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."
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 @@
 }
 
 
+/* 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 @@
 
 /* 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 @@
 	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;