[Python-checkins] r59678 - in python/trunk: Doc/c-api/utilities.rst Include/import.h Include/py_curses.h Mac/Modules/MacOS.c Misc/NEWS Modules/_ctypes/callbacks.c Modules/_cursesmodule.c Modules/cjkcodecs/cjkcodecs.h Modules/datetimemodule.c Modules/gcmodule.c Modules/parsermodule.c Modules/posixmodule.c Modules/socketmodule.h Modules/timemodule.c Modules/zipimport.c Objects/unicodeobject.c Python/errors.c Python/import.c Python/mactoolboxglue.c

christian.heimes python-checkins at python.org
Thu Jan 3 23:16:33 CET 2008


Author: christian.heimes
Date: Thu Jan  3 23:16:32 2008
New Revision: 59678

Modified:
   python/trunk/Doc/c-api/utilities.rst
   python/trunk/Include/import.h
   python/trunk/Include/py_curses.h
   python/trunk/Mac/Modules/MacOS.c
   python/trunk/Misc/NEWS
   python/trunk/Modules/_ctypes/callbacks.c
   python/trunk/Modules/_cursesmodule.c
   python/trunk/Modules/cjkcodecs/cjkcodecs.h
   python/trunk/Modules/datetimemodule.c
   python/trunk/Modules/gcmodule.c
   python/trunk/Modules/parsermodule.c
   python/trunk/Modules/posixmodule.c
   python/trunk/Modules/socketmodule.h
   python/trunk/Modules/timemodule.c
   python/trunk/Modules/zipimport.c
   python/trunk/Objects/unicodeobject.c
   python/trunk/Python/errors.c
   python/trunk/Python/import.c
   python/trunk/Python/mactoolboxglue.c
Log:
Modified PyImport_Import and PyImport_ImportModule to always use absolute imports by calling __import__ with an explicit level of 0
Added a new API function PyImport_ImportModuleNoBlock. It solves the problem with dead locks when mixing threads and imports

Modified: python/trunk/Doc/c-api/utilities.rst
==============================================================================
--- python/trunk/Doc/c-api/utilities.rst	(original)
+++ python/trunk/Doc/c-api/utilities.rst	Thu Jan  3 23:16:32 2008
@@ -183,7 +183,8 @@
       single: __all__ (package variable)
 
    This is a simplified interface to :cfunc:`PyImport_ImportModuleEx` below,
-   leaving the *globals* and *locals* arguments set to *NULL*.  When the *name*
+   leaving the *globals* and *locals* arguments set to *NULL* and *level* set
+   to 0.  When the *name*
    argument contains a dot (when it specifies a submodule of a package), the
    *fromlist* argument is set to the list ``['*']`` so that the return value is the
    named module rather than the top-level package containing it as would otherwise
@@ -198,9 +199,28 @@
    .. versionchanged:: 2.4
       failing imports remove incomplete module objects.
 
+   .. versionchanged:: 2.6
+      always use absolute imports
+
    .. index:: single: modules (in module sys)
 
 
+.. cfunction:: PyObject* PyImport_ImportModuleNoBlock(const char *name)
+
+   .. index::
+      single: `cfunc:PyImport_ImportModule`
+
+   This version of `cfunc:PyImport_ImportModule` does not block. It's intended
+   to be used in C function which import other modules to execute a function.
+   The import may block if another thread holds the import lock. The function
+  `cfunc:PyImport_ImportModuleNoBlock` doesn't block. It first tries to fetch
+   the module from sys.modules and falls back to `cfunc:PyImport_ImportModule`
+   unless the the lock is hold. In the latter case the function raises an
+   ImportError.
+
+   .. versionadded:: 2.6
+
+
 .. cfunction:: PyObject* PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
 
    .. index:: builtin: __import__
@@ -218,6 +238,24 @@
    .. versionchanged:: 2.4
       failing imports remove incomplete module objects.
 
+   .. versionchanged:: 2.6
+      The function is an alias for `cfunc:PyImport_ImportModuleLevel` with
+      -1 as level, meaning relative import.
+
+
+.. cfunction:: PyObject* PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level)
+
+   Import a module.  This is best described by referring to the built-in Python
+   function :func:`__import__`, as the standard :func:`__import__` function calls
+   this function directly.
+
+   The return value is a new reference to the imported module or top-level package,
+   or *NULL* with an exception set on failure.  Like for :func:`__import__`,
+   the return value when a submodule of a package was requested is normally the
+   top-level package, unless a non-empty *fromlist* was given.
+
+   ..versionadded:: 2.5
+
 
 .. cfunction:: PyObject* PyImport_Import(PyObject *name)
 
@@ -230,6 +268,9 @@
    current globals.  This means that the import is done using whatever import hooks
    are installed in the current environment, e.g. by :mod:`rexec` or :mod:`ihooks`.
 
+   .. versionchanged:: 2.6
+      always use absolute imports
+
 
 .. cfunction:: PyObject* PyImport_ReloadModule(PyObject *m)
 

Modified: python/trunk/Include/import.h
==============================================================================
--- python/trunk/Include/import.h	(original)
+++ python/trunk/Include/import.h	Thu Jan  3 23:16:32 2008
@@ -14,13 +14,10 @@
 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_ImportModuleNoBlock(const char *);
 PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name,
 	PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
 
-/* For DLL compatibility */
-#undef PyImport_ImportModuleEx
-PyAPI_FUNC(PyObject *) PyImport_ImportModuleEx(
-	char *name, PyObject *globals, PyObject *locals, PyObject *fromlist);
 #define PyImport_ImportModuleEx(n, g, l, f) \
 	PyImport_ImportModuleLevel(n, g, l, f, -1)
 

Modified: python/trunk/Include/py_curses.h
==============================================================================
--- python/trunk/Include/py_curses.h	(original)
+++ python/trunk/Include/py_curses.h	Thu Jan  3 23:16:32 2008
@@ -90,7 +90,7 @@
 
 #define import_curses() \
 { \
-  PyObject *module = PyImport_ImportModule("_curses"); \
+  PyObject *module = PyImport_ImportModuleNoBlock("_curses"); \
   if (module != NULL) { \
     PyObject *module_dict = PyModule_GetDict(module); \
     PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \

Modified: python/trunk/Mac/Modules/MacOS.c
==============================================================================
--- python/trunk/Mac/Modules/MacOS.c	(original)
+++ python/trunk/Mac/Modules/MacOS.c	Thu Jan  3 23:16:32 2008
@@ -357,7 +357,7 @@
 		PyObject *m, *rv;
 		errors_loaded = 1;
 		
-		m = PyImport_ImportModule("macresource");
+		m = PyImport_ImportModuleNoBlock("macresource");
 		if (!m) {
 			if (Py_VerboseFlag)
 				PyErr_Print();

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Thu Jan  3 23:16:32 2008
@@ -14,25 +14,10 @@
 
 - Issue #1640: Added math.isinf() and math.isnan() functions.
 
-- Issue #1726: Remove Python/atof.c from PCBuild/pythoncore.vcproj
-
-- Removed PCbuild8/ directory and added a new build directory for VS 2005
-  based on the VS 2008 build directory to PC/VS8.0. The script 
-  PCbuild/vs8to9.py was added to sync changes from PCbuild to PC/VS8.0.
-
-- Moved PCbuild/ directory for VS 2003 to PC/VS7.1 and renamed PCBuild9/
-  directory to PCBuild/.
-
-- Issue #1629: Renamed Py_Size, Py_Type and Py_Refcnt to Py_SIZE, Py_TYPE
-  and Py_REFCNT.
-
 - Issue #1635: Platform independent creation and representation of NaN
   and INF. float("nan"), float("inf") and float("-inf") now work on every
   platform with IEEE 754 semantics.
 
-- Added case insensitive comparsion methods ``PyOS_stricmp(char*, char*)``
-  and ``PyOS_strnicmp(char*, char*, Py_ssize_t)``.
-
 - Compiler now generates simpler and faster code for dictionary literals.
   The oparg for BUILD_MAP now indicates an estimated dictionary size.
   There is a new opcode, STORE_MAP, for adding entries to the dictionary.
@@ -1165,6 +1150,15 @@
 Build
 -----
 
+- Issue #1726: Remove Python/atof.c from PCBuild/pythoncore.vcproj
+
+- Removed PCbuild8/ directory and added a new build directory for VS 2005
+  based on the VS 2008 build directory to PC/VS8.0. The script 
+  PCbuild/vs8to9.py was added to sync changes from PCbuild to PC/VS8.0.
+
+- Moved PCbuild/ directory for VS 2003 to PC/VS7.1 and renamed PCBuild9/
+  directory to PCBuild/.
+
 - Bug #1699: Define _BSD_SOURCE only on OpenBSD.
 
 - Bug #1608: use -fwrapv when GCC supports it.  This is important,
@@ -1225,6 +1219,18 @@
 C API
 -----
 
+- Added a new API function ``PyImport_ImportModuleNoBlock``.
+
+- ``PyImport_Import`` and ``PyImport_ImportModule`` now always do absolute
+  imports. In earlier versions they might have used relative imports under
+  some conditions.
+
+- Issue #1629: Renamed Py_Size, Py_Type and Py_Refcnt to Py_SIZE, Py_TYPE
+  and Py_REFCNT.
+
+- Added case insensitive comparsion methods ``PyOS_stricmp(char*, char*)``
+  and ``PyOS_strnicmp(char*, char*, Py_ssize_t)``.
+
 - Bug #1542693: remove semi-colon at end of PyImport_ImportModuleEx macro
   so it can be used as an expression.
 

Modified: python/trunk/Modules/_ctypes/callbacks.c
==============================================================================
--- python/trunk/Modules/_ctypes/callbacks.c	(original)
+++ python/trunk/Modules/_ctypes/callbacks.c	Thu Jan  3 23:16:32 2008
@@ -370,7 +370,7 @@
 	if (context == NULL)
 		context = PyString_FromString("_ctypes.DllGetClassObject");
 
-	mod = PyImport_ImportModule("ctypes");
+	mod = PyImport_ImportModuleNoBlock("ctypes");
 	if (!mod) {
 		PyErr_WriteUnraisable(context ? context : Py_None);
 		/* There has been a warning before about this already */
@@ -449,7 +449,7 @@
 	if (context == NULL)
 		context = PyString_FromString("_ctypes.DllCanUnloadNow");
 
-	mod = PyImport_ImportModule("ctypes");
+	mod = PyImport_ImportModuleNoBlock("ctypes");
 	if (!mod) {
 /*		OutputDebugString("Could not import ctypes"); */
 		/* We assume that this error can only occur when shutting

Modified: python/trunk/Modules/_cursesmodule.c
==============================================================================
--- python/trunk/Modules/_cursesmodule.c	(original)
+++ python/trunk/Modules/_cursesmodule.c	Thu Jan  3 23:16:32 2008
@@ -2255,7 +2255,7 @@
 update_lines_cols(void)
 {
   PyObject *o;
-  PyObject *m = PyImport_ImportModule("curses");
+  PyObject *m = PyImport_ImportModuleNoBlock("curses");
 
   if (!m)
     return 0;

Modified: python/trunk/Modules/cjkcodecs/cjkcodecs.h
==============================================================================
--- python/trunk/Modules/cjkcodecs/cjkcodecs.h	(original)
+++ python/trunk/Modules/cjkcodecs/cjkcodecs.h	Thu Jan  3 23:16:32 2008
@@ -245,7 +245,7 @@
 	static PyObject *cofunc = NULL;
 
 	if (cofunc == NULL) {
-		PyObject *mod = PyImport_ImportModule("_multibytecodec");
+		PyObject *mod = PyImport_ImportModuleNoBlock("_multibytecodec");
 		if (mod == NULL)
 			return NULL;
 		cofunc = PyObject_GetAttrString(mod, "__create_codec");

Modified: python/trunk/Modules/datetimemodule.c
==============================================================================
--- python/trunk/Modules/datetimemodule.c	(original)
+++ python/trunk/Modules/datetimemodule.c	Thu Jan  3 23:16:32 2008
@@ -1305,7 +1305,7 @@
 	if (_PyString_Resize(&newfmt, usednew) < 0)
 		goto Done;
 	{
-		PyObject *time = PyImport_ImportModule("time");
+		PyObject *time = PyImport_ImportModuleNoBlock("time");
 		if (time == NULL)
 			goto Done;
 		result = PyObject_CallMethod(time, "strftime", "OO",
@@ -1353,7 +1353,7 @@
 time_time(void)
 {
 	PyObject *result = NULL;
-	PyObject *time = PyImport_ImportModule("time");
+	PyObject *time = PyImport_ImportModuleNoBlock("time");
 
 	if (time != NULL) {
 		result = PyObject_CallMethod(time, "time", "()");
@@ -1371,7 +1371,7 @@
 	PyObject *time;
 	PyObject *result = NULL;
 
-	time = PyImport_ImportModule("time");
+	time = PyImport_ImportModuleNoBlock("time");
 	if (time != NULL) {
 		result = PyObject_CallMethod(time, "struct_time",
 					     "((iiiiiiiii))",
@@ -3827,7 +3827,7 @@
 	if (!PyArg_ParseTuple(args, "ss:strptime", &string, &format))
 		return NULL;
 
-	if ((module = PyImport_ImportModule("time")) == NULL)
+	if ((module = PyImport_ImportModuleNoBlock("time")) == NULL)
 		return NULL;
 	obj = PyObject_CallMethod(module, "strptime", "ss", string, format);
 	Py_DECREF(module);

Modified: python/trunk/Modules/gcmodule.c
==============================================================================
--- python/trunk/Modules/gcmodule.c	(original)
+++ python/trunk/Modules/gcmodule.c	Thu Jan  3 23:16:32 2008
@@ -1236,7 +1236,7 @@
 	 * the import and triggers an assertion.
 	 */
 	if (tmod == NULL) {
-		tmod = PyImport_ImportModule("time");
+		tmod = PyImport_ImportModuleNoBlock("time");
 		if (tmod == NULL)
 			PyErr_Clear();
 	}

Modified: python/trunk/Modules/parsermodule.c
==============================================================================
--- python/trunk/Modules/parsermodule.c	(original)
+++ python/trunk/Modules/parsermodule.c	Thu Jan  3 23:16:32 2008
@@ -3269,7 +3269,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_ImportModuleNoBlock("copy_reg");
     if (copyreg != NULL) {
         PyObject *func, *pickler;
 

Modified: python/trunk/Modules/posixmodule.c
==============================================================================
--- python/trunk/Modules/posixmodule.c	(original)
+++ python/trunk/Modules/posixmodule.c	Thu Jan  3 23:16:32 2008
@@ -5651,7 +5651,7 @@
 		return posix_error();
 
 	if (struct_rusage == NULL) {
-		PyObject *m = PyImport_ImportModule("resource");
+		PyObject *m = PyImport_ImportModuleNoBlock("resource");
 		if (m == NULL)
 			return NULL;
 		struct_rusage = PyObject_GetAttrString(m, "struct_rusage");

Modified: python/trunk/Modules/socketmodule.h
==============================================================================
--- python/trunk/Modules/socketmodule.h	(original)
+++ python/trunk/Modules/socketmodule.h	Thu Jan  3 23:16:32 2008
@@ -222,7 +222,7 @@
 	void *api;
 
 	DPRINTF("Importing the %s C API...\n", apimodule);
-	mod = PyImport_ImportModule(apimodule);
+	mod = PyImport_ImportModuleNoBlock(apimodule);
 	if (mod == NULL)
 		goto onError;
 	DPRINTF(" %s package found\n", apimodule);

Modified: python/trunk/Modules/timemodule.c
==============================================================================
--- python/trunk/Modules/timemodule.c	(original)
+++ python/trunk/Modules/timemodule.c	Thu Jan  3 23:16:32 2008
@@ -515,7 +515,7 @@
 static PyObject *
 time_strptime(PyObject *self, PyObject *args)
 {
-    PyObject *strptime_module = PyImport_ImportModule("_strptime");
+    PyObject *strptime_module = PyImport_ImportModuleNoBlock("_strptime");
     PyObject *strptime_result;
 
     if (!strptime_module)
@@ -627,7 +627,7 @@
 {
 	PyObject* m;
 
-	m = PyImport_ImportModule("time");
+	m = PyImport_ImportModuleNoBlock("time");
 	if (m == NULL) {
 	    return NULL;
 	}

Modified: python/trunk/Modules/zipimport.c
==============================================================================
--- python/trunk/Modules/zipimport.c	(original)
+++ python/trunk/Modules/zipimport.c	Thu Jan  3 23:16:32 2008
@@ -776,7 +776,7 @@
 			   let's avoid a stack overflow. */
 			return NULL;
 		importing_zlib = 1;
-		zlib = PyImport_ImportModule("zlib");	/* import zlib */
+		zlib = PyImport_ImportModuleNoBlock("zlib");
 		importing_zlib = 0;
 		if (zlib != NULL) {
 			decompress = PyObject_GetAttrString(zlib,

Modified: python/trunk/Objects/unicodeobject.c
==============================================================================
--- python/trunk/Objects/unicodeobject.c	(original)
+++ python/trunk/Objects/unicodeobject.c	Thu Jan  3 23:16:32 2008
@@ -2216,7 +2216,7 @@
             if (ucnhash_CAPI == NULL) {
                 /* load the unicode data module */
                 PyObject *m, *api;
-                m = PyImport_ImportModule("unicodedata");
+                m = PyImport_ImportModuleNoBlock("unicodedata");
                 if (m == NULL)
                     goto ucnhashError;
                 api = PyObject_GetAttrString(m, "ucnhash_CAPI");

Modified: python/trunk/Python/errors.c
==============================================================================
--- python/trunk/Python/errors.c	(original)
+++ python/trunk/Python/errors.c	Thu Jan  3 23:16:32 2008
@@ -690,7 +690,7 @@
 {
 	PyObject *mod, *dict, *func = NULL;
 
-	mod = PyImport_ImportModule("warnings");
+	mod = PyImport_ImportModuleNoBlock("warnings");
 	if (mod != NULL) {
 		dict = PyModule_GetDict(mod);
 		func = PyDict_GetItemString(dict, "warn_explicit");

Modified: python/trunk/Python/import.c
==============================================================================
--- python/trunk/Python/import.c	(original)
+++ python/trunk/Python/import.c	Thu Jan  3 23:16:32 2008
@@ -1985,6 +1985,53 @@
 	return result;
 }
 
+/* Import a module without blocking
+ *
+ * At first it tries to fetch the module from sys.modules. If the module was
+ * never loaded before it loads it with PyImport_ImportModule() unless another
+ * thread holds the import lock. In the latter case the function raises an
+ * ImportError instead of blocking.
+ *
+ * Returns the module object with incremented ref count.
+ */
+PyObject *
+PyImport_ImportModuleNoBlock(const char *name)
+{
+	PyObject *result;
+	PyObject *modules;
+	long me;
+
+	/* Try to get the module from sys.modules[name] */
+	modules = PyImport_GetModuleDict();
+	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);
@@ -2054,26 +2101,6 @@
 	return tail;
 }
 
-/* For DLL compatibility */
-#undef PyImport_ImportModuleEx
-PyObject *
-PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals,
-			PyObject *fromlist)
-{
-	PyObject *result;
-	lock_import();
-	result = import_module_level(name, globals, locals, fromlist, -1);
-	if (unlock_import() < 0) {
-		Py_XDECREF(result);
-		PyErr_SetString(PyExc_RuntimeError,
-				"not holding the import lock");
-		return NULL;
-	}
-	return result;
-}
-#define PyImport_ImportModuleEx(n, g, l, f) \
-	PyImport_ImportModuleLevel(n, g, l, f, -1);
-
 PyObject *
 PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals,
 			 PyObject *fromlist, int level)
@@ -2646,9 +2673,10 @@
 	if (import == NULL)
 		goto err;
 
-	/* Call the __import__ function with the proper argument list */
-	r = PyObject_CallFunctionObjArgs(import, module_name, globals,
-					 globals, silly_list, NULL);
+	/* Call the __import__ function with the proper argument list
+	 * Always use absolute import here. */
+	r = PyObject_CallFunction(import, "OOOOi", module_name, globals,
+				  globals, silly_list, 0, NULL);
 
   err:
 	Py_XDECREF(globals);

Modified: python/trunk/Python/mactoolboxglue.c
==============================================================================
--- python/trunk/Python/mactoolboxglue.c	(original)
+++ python/trunk/Python/mactoolboxglue.c	Thu Jan  3 23:16:32 2008
@@ -36,7 +36,7 @@
 	PyObject *m;
 	PyObject *rv;
 
-	m = PyImport_ImportModule("MacOS");
+	m = PyImport_ImportModuleNoBlock("MacOS");
 	if (!m) {
 		if (Py_VerboseFlag)
 			PyErr_Print();


More information about the Python-checkins mailing list