From c4f4ca91e112a55b2fac5853718a5f05797f30b5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 12 Feb 2003 21:46:11 +0000 Subject: [PATCH] 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. --- Misc/NEWS | 8 ++++++- Python/import.c | 58 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index f1b3a8b5bcd..cfcb7aca52f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -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 diff --git a/Python/import.c b/Python/import.c index b2cefc0a7ee..f1d3d0cdf6b 100644 --- a/Python/import.c +++ b/Python/import.c @@ -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},