summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1998-03-03 22:26:50 (GMT)
committerGuido van Rossum <guido@python.org>1998-03-03 22:26:50 (GMT)
commit75acc9ca1c2415717951ac11347714563894b325 (patch)
treefa149a3c9fa6a1b26cfa2f3382a4676122ab4475 /Python
parent78535706517b3e6bf0c2e594e3c53dbed10c016e (diff)
downloadcpython-75acc9ca1c2415717951ac11347714563894b325.zip
cpython-75acc9ca1c2415717951ac11347714563894b325.tar.gz
cpython-75acc9ca1c2415717951ac11347714563894b325.tar.bz2
Add a single Python-wide (!) lock on import. Only one thread at a
time can be in PyImport_ImportModuleEx(). Recursive calls from the same thread are okay. Potential problems: - The lock should really be part of the interpreter state rather than global, but that would require modifying more files, and I first want to figure out whether this works at all. - One could argue that the lock should be per module -- however that would be complicated to implement. We would have to have a linked list of locks per module name, *or* invent a new object type to represent a lock, so we can store the locks in the module or in a separate dictionary. Both seem unwarranted. The one situation where this can cause problems is when loading a module takes a long time, e.g. when the module's initialization code interacts with the user -- during that time, no other threads can run. I say, "too bad."
Diffstat (limited to 'Python')
-rw-r--r--Python/import.c79
1 files changed, 71 insertions, 8 deletions
diff --git a/Python/import.c b/Python/import.c
index 3aa110c..ef82439 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -113,6 +113,61 @@ _PyImport_Fini()
}
+/* Locking primitives to prevent parallel imports of the same module
+ in different threads to return with a partially loaded module.
+ These calls are serialized by the global interpreter lock. */
+
+#ifdef WITH_THREAD
+
+#include "thread.h"
+
+static type_lock import_lock = 0;
+static long import_lock_thread = -1;
+static int import_lock_level = 0;
+
+static void
+lock_import()
+{
+ long me = get_thread_ident();
+ if (me == -1)
+ return; /* Too bad */
+ if (import_lock == NULL)
+ import_lock = allocate_lock();
+ if (import_lock_thread == me) {
+ import_lock_level++;
+ return;
+ }
+ if (import_lock_thread != -1 || !acquire_lock(import_lock, 0)) {
+ PyThreadState *tstate = PyEval_SaveThread();
+ acquire_lock(import_lock, 1);
+ PyEval_RestoreThread(tstate);
+ }
+ import_lock_thread = me;
+ import_lock_level = 1;
+}
+
+static void
+unlock_import()
+{
+ long me = get_thread_ident();
+ if (me == -1)
+ return; /* Too bad */
+ if (import_lock_thread != me)
+ Py_FatalError("unlock_import: not holding the import lock");
+ import_lock_level--;
+ if (import_lock_level == 0) {
+ import_lock_thread = -1;
+ release_lock(import_lock);
+ }
+}
+
+#else
+
+#define lock_import()
+#define unlock_import()
+
+#endif
+
/* Helper for sys */
PyObject *
@@ -1259,14 +1314,8 @@ static PyObject * import_submodule Py_PROTO((PyObject *mod,
/* The Magnum Opus of dotted-name import :-) */
-/* XXX TO DO:
- - Remember misses in package directories so package submodules
- that all import the same toplevel module don't keep hitting on the
- package directory first
-*/
-
-PyObject *
-PyImport_ImportModuleEx(name, globals, locals, fromlist)
+static PyObject *
+import_module_ex(name, globals, locals, fromlist)
char *name;
PyObject *globals;
PyObject *locals;
@@ -1315,6 +1364,20 @@ PyImport_ImportModuleEx(name, globals, locals, fromlist)
return tail;
}
+PyObject *
+PyImport_ImportModuleEx(name, globals, locals, fromlist)
+ char *name;
+ PyObject *globals;
+ PyObject *locals;
+ PyObject *fromlist;
+{
+ PyObject *result;
+ lock_import();
+ result = import_module_ex(name, globals, lock_import, fromlist);
+ unlock_import();
+ return result;
+}
+
static PyObject *
get_parent(globals, buf, p_buflen)
PyObject *globals;