mirror of
https://github.com/python/cpython.git
synced 2025-07-28 05:34:31 +00:00
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
This commit is contained in:
parent
0a83d79268
commit
000a074c95
19 changed files with 135 additions and 63 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"); \
|
||||
|
|
|
@ -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();
|
||||
|
|
36
Misc/NEWS
36
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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue