Update of /cvsroot/python/python/dist/src/Lib In directory usw-pr-cvs1:/tmp/cvs-serv24830/Lib Modified Files: tempfile.py Log Message: SF bug #509805 tempfile.gettempdir not threadsafe This is an ancient race when multiple threads call gettempdir() (or anything relying on it) for the first time. Fixed x-platform via the Big Hammer of rearranging the code to serialize the first calls. Subsequent calls are as fast as before. Note that the Python test suite can't provoke this bug: it requires setting up multiple threads making the very first calls into tempfile, but the test suite uses tempfile several times before getting to test_threadedtempfile. Bugfix candidate. Index: tempfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tempfile.py,v retrieving revision 1.34 retrieving revision 1.35 diff -C2 -d -r1.34 -r1.35 *** tempfile.py 2001/12/18 23:22:01 1.34 --- tempfile.py 2002/01/28 23:11:23 1.35 *************** *** 18,21 **** --- 18,45 ---- 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() *************** *** 180,185 **** # 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: --- 204,209 ---- # usually be a Python int, but if _counter.get_next() is called often # enough, it will become a Python long. ! # Note that the only names that survive this next block of code ! # are "_counter" and "_tempdir_lock". class _ThreadSafeCounter: *************** *** 210,217 **** --- 234,243 ---- _counter = _ThreadSafeCounter(_DummyMutex()) + _tempdir_lock = _DummyMutes() del _DummyMutex else: _counter = _ThreadSafeCounter(thread.allocate_lock()) + _tempdir_lock = thread.allocate_lock() del thread
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4