summaryrefslogtreecommitdiffstats
path: root/Python/import.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/import.c')
-rw-r--r--Python/import.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/Python/import.c b/Python/import.c
index b2cefc0..f1d3d0c 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},