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."
This commit is contained in:
parent
7853570651
commit
75acc9ca1c
|
@ -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 */
|
/* Helper for sys */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -1259,14 +1314,8 @@ static PyObject * import_submodule Py_PROTO((PyObject *mod,
|
||||||
|
|
||||||
/* The Magnum Opus of dotted-name import :-) */
|
/* The Magnum Opus of dotted-name import :-) */
|
||||||
|
|
||||||
/* XXX TO DO:
|
static PyObject *
|
||||||
- Remember misses in package directories so package submodules
|
import_module_ex(name, globals, locals, fromlist)
|
||||||
that all import the same toplevel module don't keep hitting on the
|
|
||||||
package directory first
|
|
||||||
*/
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
PyImport_ImportModuleEx(name, globals, locals, fromlist)
|
|
||||||
char *name;
|
char *name;
|
||||||
PyObject *globals;
|
PyObject *globals;
|
||||||
PyObject *locals;
|
PyObject *locals;
|
||||||
|
@ -1315,6 +1364,20 @@ PyImport_ImportModuleEx(name, globals, locals, fromlist)
|
||||||
return tail;
|
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 *
|
static PyObject *
|
||||||
get_parent(globals, buf, p_buflen)
|
get_parent(globals, buf, p_buflen)
|
||||||
PyObject *globals;
|
PyObject *globals;
|
||||||
|
|
Loading…
Reference in New Issue