]> granicus.if.org Git - python/commitdiff
Modified PyImport_Import and PyImport_ImportModule to always use absolute imports...
authorChristian Heimes <christian@cheimes.de>
Thu, 3 Jan 2008 22:16:32 +0000 (22:16 +0000)
committerChristian Heimes <christian@cheimes.de>
Thu, 3 Jan 2008 22:16:32 +0000 (22:16 +0000)
Added a new API function PyImport_ImportModuleNoBlock. It solves the problem with dead locks when mixing threads and imports

19 files changed:
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

index eab33a32e09ab2ca2c9fce47f7400fe1a181b6ad..d9e85b0da95a442b874d1f2b489638cd02e8d092 100644 (file)
@@ -183,7 +183,8 @@ Importing Modules
       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 @@ Importing Modules
    .. 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 @@ Importing Modules
    .. 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 @@ Importing Modules
    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)
 
index af9f3394b13d51a73092acd5d53a258cdc280566..05ad7f008a0091d79d1fb468a3fe1995097fa1d8 100644 (file)
@@ -14,13 +14,10 @@ PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleEx(
 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)
 
index b045a595a28de71e900e7204a3b2149d8749bc38..f38f76543b150c25bdb9930178f42d06a9acfd1c 100644 (file)
@@ -90,7 +90,7 @@ static void **PyCurses_API;
 
 #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"); \
index 4eabb3951d912c7033f336ca246f22ae69ccbb29..3fe6e0dbe39fafc2b93cf1b336673abc6a85a060 100644 (file)
@@ -357,7 +357,7 @@ MacOS_GetErrorString(PyObject *self, PyObject *args)
                PyObject *m, *rv;
                errors_loaded = 1;
                
-               m = PyImport_ImportModule("macresource");
+               m = PyImport_ImportModuleNoBlock("macresource");
                if (!m) {
                        if (Py_VerboseFlag)
                                PyErr_Print();
index 95845b6e6a33bfc90747a9416c48c8a86366ca22..ee0bec2966b33555a0540a2c7f3a1b183ce6edf1 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -14,25 +14,10 @@ Core and builtins
 
 - 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 @@ Tools/Demos
 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 @@ Build
 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.
 
index 18af288ce26a0158035394cefdf699a9b5213494..5362584d50eeb69af563a61a42e2a7d27c043c8b 100644 (file)
@@ -370,7 +370,7 @@ long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
        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 @@ long Call_CanUnloadNow(void)
        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
index e7c4bc170a2927ff00e3b066204ee0b776f8aa32..a805b2d05fb57c4d0e331df46c1ee77dd959aea4 100644 (file)
@@ -2255,7 +2255,7 @@ static int
 update_lines_cols(void)
 {
   PyObject *o;
-  PyObject *m = PyImport_ImportModule("curses");
+  PyObject *m = PyImport_ImportModuleNoBlock("curses");
 
   if (!m)
     return 0;
index 71c54f093fc96a24ef11f8fb3fa57453d5e64c56..4005bcfe3453e13ca2def6ad1641a8bdf7f0b84e 100644 (file)
@@ -245,7 +245,7 @@ getmultibytecodec(void)
        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");
index b94812b19d79f4740c6713669060a67ece44127e..83e547eb2e200c11c9c74c0b2e69a1dbe5bb1ee8 100644 (file)
@@ -1305,7 +1305,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
        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 @@ static PyObject *
 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 @@ build_struct_time(int y, int m, int d, int hh, int mm, int ss, int dstflag)
        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 @@ datetime_strptime(PyObject *cls, PyObject *args)
        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);
index 0edf52365c18379be643dd6d3de22c314307a791..522cc89c50615c71c28aaf8f462b862562058c9e 100644 (file)
@@ -1236,7 +1236,7 @@ initgc(void)
         * the import and triggers an assertion.
         */
        if (tmod == NULL) {
-               tmod = PyImport_ImportModule("time");
+               tmod = PyImport_ImportModuleNoBlock("time");
                if (tmod == NULL)
                        PyErr_Clear();
        }
index 6c4a6ad6db2e1d5b1edb76f27eb5d96a952f372c..5764c24b8a454932d43d43de763370742046868a 100644 (file)
@@ -3269,7 +3269,7 @@ initparser(void)
      * 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;
 
index 85725f4bf5f3b0a4704a34aea5b845718f9ac3fa..696df0dca47f36e2be44d011ae73977c8a5b06a3 100644 (file)
@@ -5651,7 +5651,7 @@ wait_helper(int pid, int status, struct rusage *ru)
                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");
index a4382abd91d31d680c1d3cb715ae0e125c8e67bb..fb9ec67a510f7c468297708217ddcd8fae78dad5 100644 (file)
@@ -222,7 +222,7 @@ int PySocketModule_ImportModuleAndAPI(void)
        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);
index 842ce94f09d0c1e51773e1f55eaff3a32ac1edb0..5b4d21031fcea0ef4e186b66c5179d9b53b56915 100644 (file)
@@ -515,7 +515,7 @@ is not present, current time as returned by localtime() is used.");
 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 @@ time_tzset(PyObject *self, PyObject *unused)
 {
        PyObject* m;
 
-       m = PyImport_ImportModule("time");
+       m = PyImport_ImportModuleNoBlock("time");
        if (m == NULL) {
            return NULL;
        }
index fe5e1b0f7d017fa88b61ef4c9779913d4730973f..dec6091b6637d6aa8a69de92ff17a2560cc1dc03 100644 (file)
@@ -776,7 +776,7 @@ get_decompress_func(void)
                           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,
index 4241fe90062e6dbefbd7917df5755f725d3190f6..e3fc71ab5f00cceddd3e891ac70effd28f79d187 100644 (file)
@@ -2216,7 +2216,7 @@ PyObject *PyUnicode_DecodeUnicodeEscape(const char *s,
             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");
index 63acf3306654581d53f1decb95c8c3edead1c5b2..1c29160924ab4a955c832556339a103673d4a2f9 100644 (file)
@@ -690,7 +690,7 @@ PyErr_WarnExplicit(PyObject *category, const char *message,
 {
        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");
index bcae9b2eed14d985bf0a71a8e080db31b8201cb5..e191bd576a82f77424c603f55fb933f03fd16bb2 100644 (file)
@@ -1985,6 +1985,53 @@ PyImport_ImportModule(const char *name)
        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 @@ import_module_level(char *name, PyObject *globals, PyObject *locals,
        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 @@ PyImport_Import(PyObject *module_name)
        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);
index 26a13083f367913358df95273d975bbf6fd452d3..8ad0d6d1c3b221527bcb59bbcf0b198126e0aff1 100644 (file)
@@ -36,7 +36,7 @@ PyMac_StrError(int err)
        PyObject *m;
        PyObject *rv;
 
-       m = PyImport_ImportModule("MacOS");
+       m = PyImport_ImportModuleNoBlock("MacOS");
        if (!m) {
                if (Py_VerboseFlag)
                        PyErr_Print();