diff options
-rw-r--r-- | Lib/tempfile.py | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 417b749..51e43b0 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -17,6 +17,30 @@ def gettempdir(): global tempdir if tempdir is not None: return tempdir + + # _gettempdir_inner deduces whether a candidate temp dir is usable by + # trying to create a file in it, and write to it. If that succeeds, + # great, it closes the file and unlinks it. There's a race, though: + # the *name* of the test file it tries is the same across all threads + # under most OSes (Linux is an exception), and letting multiple threads + # all try to open, write to, close, and unlink a single file can cause + # a variety of bogus errors (e.g., you cannot unlink a file under + # Windows if anyone has it open, and two threads cannot create the + # same file in O_EXCL mode under Unix). The simplest cure is to serialize + # calls to _gettempdir_inner. This isn't a real expense, because the + # first thread to succeed sets the global tempdir, and all subsequent + # calls to gettempdir() reuse that without trying _gettempdir_inner. + _tempdir_lock.acquire() + try: + return _gettempdir_inner() + finally: + _tempdir_lock.release() + +def _gettempdir_inner(): + """Function to calculate the directory to use.""" + global tempdir + if tempdir is not None: + return tempdir try: pwd = os.getcwd() except (AttributeError, os.error): @@ -179,8 +203,8 @@ def TemporaryFile(mode='w+b', bufsize=-1, suffix=""): # 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". +# Note that the only names that survive this next block of code +# are "_counter" and "_tempdir_lock". class _ThreadSafeCounter: def __init__(self, mutex, initialvalue=0): @@ -209,10 +233,12 @@ except ImportError: release = acquire _counter = _ThreadSafeCounter(_DummyMutex()) + _tempdir_lock = _DummyMutes() del _DummyMutex else: _counter = _ThreadSafeCounter(thread.allocate_lock()) + _tempdir_lock = thread.allocate_lock() del thread del _ThreadSafeCounter |