Provide access to the import lock, fixing SF bug #580952. This is

mostly from SF patch #683257, but I had to change unlock_import() to
return an error value to avoid fatal error.

Should this be backported?  The patch requested this, but it's a new
feature.
This commit is contained in:
Guido van Rossum 2003-02-12 21:46:11 +00:00
parent 47710656e5
commit c4f4ca91e1
2 changed files with 59 additions and 7 deletions

View File

@ -10,7 +10,7 @@ What's New in Python 2.3 alpha 2?
*Release date: XX-XXX-2003*
Core and builtins
----------------
-----------------
- Through a bytecode optimizer bug (and I bet you didn't even know
Python *had* a bytecode optimizer :-), "unsigned" hex/oct constants
@ -75,6 +75,12 @@ Core and builtins
Extension modules
-----------------
- The imp module now has ways to acquire and release the "import
lock": imp.acquire_lock() and imp.release_lock(). Note: this is a
reentrant lock, so releasing the lock only truly releases it when
this is the last release_lock() call. You can check with
imp.lock_held(). (SF bug #580952 and patch #683257.)
- Fix some bugs in the parser module. SF bug #678518.
- Thanks to Scott David Daniels, a subtle bug in how the zlib

View File

@ -252,7 +252,8 @@ lock_import(void)
import_lock_level++;
return;
}
if (import_lock_thread != -1 || !PyThread_acquire_lock(import_lock, 0)) {
if (import_lock_thread != -1 || !PyThread_acquire_lock(import_lock, 0))
{
PyThreadState *tstate = PyEval_SaveThread();
PyThread_acquire_lock(import_lock, 1);
PyEval_RestoreThread(tstate);
@ -261,25 +262,26 @@ lock_import(void)
import_lock_level = 1;
}
static void
static int
unlock_import(void)
{
long me = PyThread_get_thread_ident();
if (me == -1)
return; /* Too bad */
return 0; /* Too bad */
if (import_lock_thread != me)
Py_FatalError("unlock_import: not holding the import lock");
return -1;
import_lock_level--;
if (import_lock_level == 0) {
import_lock_thread = -1;
PyThread_release_lock(import_lock);
}
return 1;
}
#else
#define lock_import()
#define unlock_import()
#define unlock_import() 0
#endif
@ -295,6 +297,32 @@ imp_lock_held(PyObject *self, PyObject *args)
#endif
}
static PyObject *
imp_acquire_lock(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":acquire_lock"))
return NULL;
#ifdef WITH_THREAD
lock_import();
#endif
return Py_None;
}
static PyObject *
imp_release_lock(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":release_lock"))
return NULL;
#ifdef WITH_THREAD
if (unlock_import() < 0) {
PyErr_SetString(PyExc_RuntimeError,
"not holding the import lock");
return NULL;
}
#endif
return Py_None;
}
/* Helper for sys */
PyObject *
@ -1970,7 +1998,12 @@ PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals,
PyObject *result;
lock_import();
result = import_module_ex(name, globals, locals, fromlist);
unlock_import();
if (unlock_import() < 0) {
Py_XDECREF(result);
PyErr_SetString(PyExc_RuntimeError,
"not holding the import lock");
return NULL;
}
return result;
}
@ -2743,6 +2776,17 @@ PyDoc_STRVAR(doc_lock_held,
Return 1 if the import lock is currently held.\n\
On platforms without threads, return 0.");
PyDoc_STRVAR(doc_acquire_lock,
"acquire_lock() -> None\n\
Acquires the interpreter's import lock for the current thread. This lock
should be used by import hooks to ensure thread-safety when importing modules.
On platforms without threads, this function does nothing.");
PyDoc_STRVAR(doc_release_lock,
"release_lock() -> None\n\
Release the interpreter's import lock.\n\
On platforms without threads, this function does nothing.");
static PyMethodDef imp_methods[] = {
{"find_module", imp_find_module, METH_VARARGS, doc_find_module},
{"get_magic", imp_get_magic, METH_VARARGS, doc_get_magic},
@ -2750,6 +2794,8 @@ static PyMethodDef imp_methods[] = {
{"load_module", imp_load_module, METH_VARARGS, doc_load_module},
{"new_module", imp_new_module, METH_VARARGS, doc_new_module},
{"lock_held", imp_lock_held, METH_VARARGS, doc_lock_held},
{"acquire_lock", imp_acquire_lock, METH_VARARGS, doc_acquire_lock},
{"release_lock", imp_release_lock, METH_VARARGS, doc_release_lock},
/* The rest are obsolete */
{"get_frozen_object", imp_get_frozen_object, METH_VARARGS},
{"init_builtin", imp_init_builtin, METH_VARARGS},