diff options
author | Guido van Rossum <guido@python.org> | 1998-03-03 22:26:50 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1998-03-03 22:26:50 (GMT) |
commit | 75acc9ca1c2415717951ac11347714563894b325 (patch) | |
tree | fa149a3c9fa6a1b26cfa2f3382a4676122ab4475 | |
parent | 78535706517b3e6bf0c2e594e3c53dbed10c016e (diff) | |
download | cpython-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."
-rw-r--r-- | Python/import.c | 79 |
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; |