New submission from Christian Heimes:

The patch adds a new API method _PyImport_ImportModuleNoLock(const char
*name). It works mostly like PyImport_ImportModule except it does not
block. It tries to fetch the module from sys.modules first and falls
back to PyImport_ImportModule UNLESS the import lock is held by another
thread.

It fixes several issues related to dead locks when a thread uses a
function that imports a module but another thread holds the lock. It
doesn't require static caching of modules.

The patch is against py3k but I can backport it to 2.6.

----------
files: import_nolock.diff
messages: 58272
nosy: gvanrossum, tiran
priority: normal
severity: normal
status: open
title: Patch for new API method _PyImport_ImportModuleNoLock(char *name)
versions: Python 2.6, Python 3.0
Added file: http://bugs.python.org/file8888/import_nolock.diff

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1567>
__________________________________
Index: Python/errors.c
===================================================================
--- Python/errors.c	(Revision 59405)
+++ Python/errors.c	(Arbeitskopie)
@@ -711,7 +711,7 @@
 {
 	PyObject *mod, *dict, *func = NULL;
 
-	mod = PyImport_ImportModule("warnings");
+	mod = _PyImport_ImportModuleNoLock("warnings");
 	if (mod != NULL) {
 		dict = PyModule_GetDict(mod);
 		func = PyDict_GetItemString(dict, "warn_explicit");
Index: Python/mactoolboxglue.c
===================================================================
--- Python/mactoolboxglue.c	(Revision 59405)
+++ Python/mactoolboxglue.c	(Arbeitskopie)
@@ -36,7 +36,7 @@
 	PyObject *m;
 	PyObject *rv;
 
-	m = PyImport_ImportModule("MacOS");
+	m = _PyImport_ImportModuleNoLock("MacOS");
 	if (!m) {
 		if (Py_VerboseFlag)
 			PyErr_Print();
Index: Python/ast.c
===================================================================
--- Python/ast.c	(Revision 59405)
+++ Python/ast.c	(Arbeitskopie)
@@ -56,7 +56,7 @@
        identifier; if so, normalize to NFKC. */
     for (; *u; u++) {
 	if (*u >= 128) {
-	    PyObject *m = PyImport_ImportModule("unicodedata");
+	    PyObject *m = _PyImport_ImportModuleNoLock("unicodedata");
 	    PyObject *id2;
 	    if (!m)
 		return NULL;
Index: Python/import.c
===================================================================
--- Python/import.c	(Revision 59405)
+++ Python/import.c	(Arbeitskopie)
@@ -1895,6 +1895,53 @@
 	return result;
 }
 
+/* Import a module without blocking
+ *
+ * It tries to fetch the module from sys.modules. If the module was never
+ * loaded before it loads it with PyImport_ImportModule(), When the import
+ * lock is held by another thread it fails with an import error instead of
+ * blocking.
+ *
+ * Returns the module object with incremented ref count.
+ */
+PyObject *
+_PyImport_ImportModuleNoLock(const char *name)
+{
+	PyObject *result;
+	PyObject *modules;
+	long me;
+
+	/* Try to get the module from sys.modules[name] */
+	modules = PySys_GetObject("modules");
+	if (modules == NULL)
+		return NULL;
+
+	result = PyDict_GetItemString(modules, name);
+	if (result != NULL) {
+		Py_INCREF(result);
+		return result;
+	}
+	else {
+		PyErr_Clear();
+	}
+
+	/* check the import lock
+	   me might be -1 but I ignore the error here, the lock function
+	   takes care of the problem */
+	me = PyThread_get_thread_ident();
+	if (import_lock_thread == -1 || import_lock_thread == me) {
+		/* no thread or me is holding the lock */
+		return PyImport_ImportModule(name);
+	}
+	else {
+		PyErr_Format(PyExc_ImportError,
+			     "Failed to import %.200s because the import lock"
+			     "is held by another thread.",
+			     name);
+		return NULL;
+	}
+}
+
 /* Forward declarations for helper routines */
 static PyObject *get_parent(PyObject *globals, char *buf,
 			    Py_ssize_t *p_buflen, int level);
Index: Python/bltinmodule.c
===================================================================
--- Python/bltinmodule.c	(Revision 59405)
+++ Python/bltinmodule.c	(Arbeitskopie)
@@ -261,7 +261,7 @@
 builtin_filter(PyObject *self, PyObject *args)
 {
 	PyObject *itertools, *ifilter, *result;
-	itertools = PyImport_ImportModule("itertools");
+	itertools = _PyImport_ImportModuleNoLock("itertools");
 	if (itertools == NULL)
 		return NULL;
 	ifilter = PyObject_GetAttrString(itertools, "ifilter");
@@ -776,7 +776,7 @@
 builtin_map(PyObject *self, PyObject *args)
 {
 	PyObject *itertools, *imap, *result;
-	itertools = PyImport_ImportModule("itertools");
+	itertools = _PyImport_ImportModuleNoLock("itertools");
 	if (itertools == NULL)
 		return NULL;
 	imap = PyObject_GetAttrString(itertools, "imap");
Index: Include/py_curses.h
===================================================================
--- Include/py_curses.h	(Revision 59405)
+++ Include/py_curses.h	(Arbeitskopie)
@@ -90,7 +90,7 @@
 
 #define import_curses() \
 { \
-  PyObject *module = PyImport_ImportModule("_curses"); \
+  PyObject *module = _PyImport_ImportModuleNoLock("_curses"); \
   if (module != NULL) { \
     PyObject *module_dict = PyModule_GetDict(module); \
     PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \
Index: Include/import.h
===================================================================
--- Include/import.h	(Revision 59405)
+++ Include/import.h	(Arbeitskopie)
@@ -14,6 +14,7 @@
 PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void);
 PyAPI_FUNC(PyObject *) PyImport_AddModule(const char *name);
 PyAPI_FUNC(PyObject *) PyImport_ImportModule(const char *name);
+PyAPI_FUNC(PyObject *) _PyImport_ImportModuleNoLock(const char *);
 PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name,
 	PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
 
Index: Objects/unicodeobject.c
===================================================================
--- Objects/unicodeobject.c	(Revision 59405)
+++ Objects/unicodeobject.c	(Arbeitskopie)
@@ -2800,7 +2800,7 @@
             if (ucnhash_CAPI == NULL) {
                 /* load the unicode data module */
                 PyObject *m, *api;
-                m = PyImport_ImportModule("unicodedata");
+                m = _PyImport_ImportModuleNoLock("unicodedata");
                 if (m == NULL)
                     goto ucnhashError;
                 api = PyObject_GetAttrString(m, "ucnhash_CAPI");
Index: Objects/fileobject.c
===================================================================
--- Objects/fileobject.c	(Revision 59405)
+++ Objects/fileobject.c	(Arbeitskopie)
@@ -31,7 +31,7 @@
 {
 	PyObject *io, *stream, *nameobj = NULL;
 
-	io = PyImport_ImportModule("io");
+	io = _PyImport_ImportModuleNoLock("io");
 	if (io == NULL)
 		return NULL;
 	stream = PyObject_CallMethod(io, "open", "isisssi", fd, mode,
Index: Parser/tokenizer.c
===================================================================
--- Parser/tokenizer.c	(Revision 59405)
+++ Parser/tokenizer.c	(Arbeitskopie)
@@ -452,7 +452,7 @@
 {
 	PyObject *readline = NULL, *stream = NULL, *io = NULL;
 
-	io = PyImport_ImportModule("io");
+	io = _PyImport_ImportModuleNoLock("io");
 	if (io == NULL)
 		goto cleanup;
 
Index: Mac/Modules/MacOS.c
===================================================================
--- Mac/Modules/MacOS.c	(Revision 59405)
+++ Mac/Modules/MacOS.c	(Arbeitskopie)
@@ -356,7 +356,7 @@
 		PyObject *m, *rv;
 		errors_loaded = 1;
 		
-		m = PyImport_ImportModule("macresource");
+		m = _PyImport_ImportModuleNoLock("macresource");
 		if (!m) {
 			if (Py_VerboseFlag)
 				PyErr_Print();
Index: PC/bdist_wininst/install.c
===================================================================
--- PC/bdist_wininst/install.c	(Revision 59405)
+++ PC/bdist_wininst/install.c	(Arbeitskopie)
@@ -654,7 +654,7 @@
 	if (!Py_BuildValue || !PyArg_ParseTuple || !PyErr_Format)
 		return 1;
 
-	mod = PyImport_ImportModule("builtins");
+	mod = _PyImport_ImportModuleNoLock("builtins");
 	if (mod) {
 		int i;
 		g_PyExc_ValueError = PyObject_GetAttrString(mod, "ValueError");
Index: Modules/_ctypes/callbacks.c
===================================================================
--- Modules/_ctypes/callbacks.c	(Revision 59405)
+++ Modules/_ctypes/callbacks.c	(Arbeitskopie)
@@ -367,7 +367,7 @@
 	if (context == NULL)
 		context = PyUnicode_FromString("_ctypes.DllGetClassObject");
 
-	mod = PyImport_ImportModule("ctypes");
+	mod = _PyImport_ImportModuleNoLock("ctypes");
 	if (!mod) {
 		PyErr_WriteUnraisable(context ? context : Py_None);
 		/* There has been a warning before about this already */
@@ -446,7 +446,7 @@
 	if (context == NULL)
 		context = PyUnicode_FromString("_ctypes.DllCanUnloadNow");
 
-	mod = PyImport_ImportModule("ctypes");
+	mod = _PyImport_ImportModuleNoLock("ctypes");
 	if (!mod) {
 /*		OutputDebugString("Could not import ctypes"); */
 		/* We assume that this error can only occur when shutting
Index: Modules/datetimemodule.c
===================================================================
--- Modules/datetimemodule.c	(Revision 59405)
+++ Modules/datetimemodule.c	(Arbeitskopie)
@@ -1329,7 +1329,7 @@
 		goto Done;
 	{
 		PyObject *format;
-		PyObject *time = PyImport_ImportModule("time");
+		PyObject *time = _PyImport_ImportModuleNoLock("time");
 		if (time == NULL)
 			goto Done;
 		format = PyUnicode_FromString(PyString_AS_STRING(newfmt));
@@ -1357,7 +1357,7 @@
 time_time(void)
 {
 	PyObject *result = NULL;
-	PyObject *time = PyImport_ImportModule("time");
+	PyObject *time = _PyImport_ImportModuleNoLock("time");
 
 	if (time != NULL) {
 		result = PyObject_CallMethod(time, "time", "()");
@@ -1375,7 +1375,7 @@
 	PyObject *time;
 	PyObject *result = NULL;
 
-	time = PyImport_ImportModule("time");
+	time = _PyImport_ImportModuleNoLock("time");
 	if (time != NULL) {
 		result = PyObject_CallMethod(time, "struct_time",
 					     "((iiiiiiiii))",
@@ -3821,7 +3821,7 @@
 	if (!PyArg_ParseTuple(args, "uu:strptime", &string, &format))
 		return NULL;
 
-	if ((module = PyImport_ImportModule("time")) == NULL)
+	if ((module = _PyImport_ImportModuleNoLock("time")) == NULL)
 		return NULL;
 	obj = PyObject_CallMethod(module, "strptime", "uu", string, format);
 	Py_DECREF(module);
Index: Modules/socketmodule.h
===================================================================
--- Modules/socketmodule.h	(Revision 59405)
+++ Modules/socketmodule.h	(Arbeitskopie)
@@ -222,7 +222,7 @@
 	void *api;
 
 	DPRINTF("Importing the %s C API...\n", apimodule);
-	mod = PyImport_ImportModule(apimodule);
+	mod = _PyImport_ImportModuleNoLock(apimodule);
 	if (mod == NULL)
 		goto onError;
 	DPRINTF(" %s package found\n", apimodule);
Index: Modules/cjkcodecs/cjkcodecs.h
===================================================================
--- Modules/cjkcodecs/cjkcodecs.h	(Revision 59405)
+++ Modules/cjkcodecs/cjkcodecs.h	(Arbeitskopie)
@@ -245,7 +245,7 @@
 	static PyObject *cofunc = NULL;
 
 	if (cofunc == NULL) {
-		PyObject *mod = PyImport_ImportModule("_multibytecodec");
+		PyObject *mod = _PyImport_ImportModuleNoLock("_multibytecodec");
 		if (mod == NULL)
 			return NULL;
 		cofunc = PyObject_GetAttrString(mod, "__create_codec");
Index: Modules/_bsddb.c
===================================================================
--- Modules/_bsddb.c	(Revision 59405)
+++ Modules/_bsddb.c	(Arbeitskopie)
@@ -6002,7 +6002,7 @@
      * using one base class. */
     PyDict_SetItemString(d, "KeyError", PyExc_KeyError);
     { 
-	    PyObject *builtin_mod = PyImport_ImportModule("builtins");
+	    PyObject *builtin_mod = _PyImport_ImportModuleNoLock("builtins");
 	    PyDict_SetItemString(d, "__builtins__", builtin_mod);
     }
     PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n"
Index: Modules/zipimport.c
===================================================================
--- Modules/zipimport.c	(Revision 59405)
+++ Modules/zipimport.c	(Arbeitskopie)
@@ -766,7 +766,7 @@
 			   let's avoid a stack overflow. */
 			return NULL;
 		importing_zlib = 1;
-		zlib = PyImport_ImportModule("zlib");	/* import zlib */
+		zlib = _PyImport_ImportModuleNoLock("zlib");
 		importing_zlib = 0;
 		if (zlib != NULL) {
 			decompress = PyObject_GetAttrString(zlib,
Index: Modules/timemodule.c
===================================================================
--- Modules/timemodule.c	(Revision 59405)
+++ Modules/timemodule.c	(Arbeitskopie)
@@ -555,7 +555,7 @@
 static PyObject *
 time_strptime(PyObject *self, PyObject *args)
 {
-    PyObject *strptime_module = PyImport_ImportModule("_strptime");
+    PyObject *strptime_module = _PyImport_ImportModuleNoLock("_strptime");
     PyObject *strptime_result;
 
     if (!strptime_module)
@@ -667,7 +667,7 @@
 {
 	PyObject* m;
 
-	m = PyImport_ImportModule("time");
+	m = _PyImport_ImportModuleNoLock("time");
 	if (m == NULL) {
 	    return NULL;
 	}
Index: Modules/gcmodule.c
===================================================================
--- Modules/gcmodule.c	(Revision 59405)
+++ Modules/gcmodule.c	(Arbeitskopie)
@@ -1210,7 +1210,7 @@
 	 * the import and triggers an assertion.
 	 */
 	if (tmod == NULL) {
-		tmod = PyImport_ImportModule("time");
+		tmod = _PyImport_ImportModuleNoLock("time");
 		if (tmod == NULL)
 			PyErr_Clear();
 	}
Index: Modules/parsermodule.c
===================================================================
--- Modules/parsermodule.c	(Revision 59405)
+++ Modules/parsermodule.c	(Arbeitskopie)
@@ -3093,7 +3093,7 @@
      * If this fails, the import of this module will fail because an
      * exception will be raised here; should we clear the exception?
      */
-    copyreg = PyImport_ImportModule("copy_reg");
+    copyreg = _PyImport_ImportModuleNoLock("copy_reg");
     if (copyreg != NULL) {
         PyObject *func, *pickler;
 
Index: Modules/posixmodule.c
===================================================================
--- Modules/posixmodule.c	(Revision 59405)
+++ Modules/posixmodule.c	(Arbeitskopie)
@@ -4217,7 +4217,7 @@
 		return posix_error();
 
 	if (struct_rusage == NULL) {
-		PyObject *m = PyImport_ImportModule("resource");
+		PyObject *m = _PyImport_ImportModuleNoLock("resource");
 		if (m == NULL)
 			return NULL;
 		struct_rusage = PyObject_GetAttrString(m, "struct_rusage");
Index: Modules/_cursesmodule.c
===================================================================
--- Modules/_cursesmodule.c	(Revision 59405)
+++ Modules/_cursesmodule.c	(Arbeitskopie)
@@ -2316,7 +2316,7 @@
 update_lines_cols(void)
 {
   PyObject *o;
-  PyObject *m = PyImport_ImportModule("curses");
+  PyObject *m = _PyImport_ImportModuleNoLock("curses");
 
   if (!m)
     return 0;
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to