summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-01-12 10:02:46 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-01-12 10:02:46 (GMT)
commit1baa22aff0a9cde81e2b19b36662e7987b83356b (patch)
treeea9c661380820791d6c5b3d49aaa0d47022bdecc
parent264630e85525c5bc475204cc1aaced00ab5ec2ff (diff)
downloadcpython-1baa22aff0a9cde81e2b19b36662e7987b83356b.zip
cpython-1baa22aff0a9cde81e2b19b36662e7987b83356b.tar.gz
cpython-1baa22aff0a9cde81e2b19b36662e7987b83356b.tar.bz2
A variant of SF patch 103028 (Make tempfile.mktemp threadsafe).
Tested on Windows. Should be tested on Linux. Should also be tested on some platform without threads (I simulated that by making the "import thread" fail, but that's not the same as actually doing it!).
-rw-r--r--Lib/tempfile.py57
1 files changed, 45 insertions, 12 deletions
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 5077835..3e1e08d 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -4,16 +4,12 @@
# how to choose a temp directory or filename on MS-DOS or other
# systems so it may have to be changed...
-
import os
-
# Parameters that the caller may set to override the defaults
-
tempdir = None
template = None
-
def gettempdir():
"""Function to calculate the directory to use."""
global tempdir
@@ -92,19 +88,13 @@ def gettempprefix():
return template
-# Counter for generating unique names
-
-counter = 0
-
-
def mktemp(suffix=""):
"""User-callable function to return a unique temporary file name."""
- global counter
dir = gettempdir()
pre = gettempprefix()
while 1:
- counter = counter + 1
- file = os.path.join(dir, pre + `counter` + suffix)
+ i = _counter.get_next()
+ file = os.path.join(dir, pre + str(i) + suffix)
if not os.path.exists(file):
return file
@@ -152,3 +142,46 @@ def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
# Non-unix -- can't unlink file that's still open, use wrapper
file = open(name, mode, bufsize)
return TemporaryFileWrapper(file, name)
+
+# In order to generate unique names, mktemp() uses _counter.get_next().
+# This returns a unique integer on each call, in a threadsafe way (i.e.,
+# multiple threads will never see the same integer). The integer will
+# usually be a Python int, but if _counter.get_next() is called often
+# enough, it will become a Python long.
+# Note that the only name that survives this next block of code
+# is "_counter".
+
+class _ThreadSafeCounter:
+ def __init__(self, mutex, initialvalue=0):
+ self.mutex = mutex
+ self.i = initialvalue
+
+ def get_next(self):
+ self.mutex.acquire()
+ result = self.i
+ try:
+ newi = result + 1
+ except OverflowError:
+ newi = long(result) + 1
+ self.i = newi
+ self.mutex.release()
+ return result
+
+try:
+ import thread
+
+except ImportError:
+ class _DummyMutex:
+ def acquire(self):
+ pass
+
+ release = acquire
+
+ _counter = _ThreadSafeCounter(_DummyMutex())
+ del _DummyMutex
+
+else:
+ _counter = _ThreadSafeCounter(thread.allocate_lock())
+ del thread
+
+del _ThreadSafeCounter