diff Python/import.c @ 27852:4b75a0b76857 legacy-trunk

Provide access to the import lock, fixing SF bug #580952. This is mostly from SF patch #683257, but I had to change unlock_import() to return an error value to avoid fatal error. Should this be backported? The patch requested this, but it's a new feature.
author Guido van Rossum <guido@python.org>
date Wed, 12 Feb 2003 21:46:11 +0000
parents afd1dc62e354
children 5620b0786271
line wrap: on
line diff
--- a/Python/import.c	Wed Feb 12 20:48:22 2003 +0000
+++ b/Python/import.c	Wed Feb 12 21:46:11 2003 +0000
@@ -252,7 +252,8 @@
 		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 @@
 	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 @@
 #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 @@
 	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 @@
 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 @@
 	{"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},