summaryrefslogtreecommitdiffstats
path: root/Python/import.c
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2012-05-17 16:55:59 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2012-05-17 16:55:59 (GMT)
commitea3eb88bcaef775c8f2bbe310053f9990a8c9ea7 (patch)
tree9461ae28e833a95a79cc4811df68435bf0e00fc3 /Python/import.c
parent5cec9d2ae57da6fb5c424bb297ddb67902393b2d (diff)
downloadcpython-ea3eb88bcaef775c8f2bbe310053f9990a8c9ea7.zip
cpython-ea3eb88bcaef775c8f2bbe310053f9990a8c9ea7.tar.gz
cpython-ea3eb88bcaef775c8f2bbe310053f9990a8c9ea7.tar.bz2
Issue #9260: A finer-grained import lock.
Most of the import sequence now uses per-module locks rather than the global import lock, eliminating well-known issues with threads and imports.
Diffstat (limited to 'Python/import.c')
-rw-r--r--Python/import.c88
1 files changed, 41 insertions, 47 deletions
diff --git a/Python/import.c b/Python/import.c
index a8b1aa3..ab6ff86 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -1370,47 +1370,7 @@ PyImport_ImportModule(const char *name)
PyObject *
PyImport_ImportModuleNoBlock(const char *name)
{
- PyObject *nameobj, *modules, *result;
-#ifdef WITH_THREAD
- long me;
-#endif
-
- /* Try to get the module from sys.modules[name] */
- modules = PyImport_GetModuleDict();
- if (modules == NULL)
- return NULL;
-
- nameobj = PyUnicode_FromString(name);
- if (nameobj == NULL)
- return NULL;
- result = PyDict_GetItem(modules, nameobj);
- if (result != NULL) {
- Py_DECREF(nameobj);
- Py_INCREF(result);
- return result;
- }
- PyErr_Clear();
-#ifdef WITH_THREAD
- /* 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 */
- result = PyImport_Import(nameobj);
- }
- else {
- PyErr_Format(PyExc_ImportError,
- "Failed to import %R because the import lock"
- "is held by another thread.",
- nameobj);
- result = NULL;
- }
-#else
- result = PyImport_Import(nameobj);
-#endif
- Py_DECREF(nameobj);
- return result;
+ return PyImport_ImportModule(name);
}
@@ -1420,11 +1380,13 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
int level)
{
_Py_IDENTIFIER(__import__);
+ _Py_IDENTIFIER(__initializing__);
_Py_IDENTIFIER(__package__);
_Py_IDENTIFIER(__path__);
_Py_IDENTIFIER(__name__);
_Py_IDENTIFIER(_find_and_load);
_Py_IDENTIFIER(_handle_fromlist);
+ _Py_IDENTIFIER(_lock_unlock_module);
_Py_static_string(single_dot, ".");
PyObject *abs_name = NULL;
PyObject *builtins_import = NULL;
@@ -1607,16 +1569,48 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
goto error_with_unlock;
}
else if (mod != NULL) {
+ PyObject *value;
+ int initializing = 0;
+
Py_INCREF(mod);
+ /* Only call _bootstrap._lock_unlock_module() if __initializing__ is true. */
+ value = _PyObject_GetAttrId(mod, &PyId___initializing__);
+ if (value == NULL)
+ PyErr_Clear();
+ else {
+ initializing = PyObject_IsTrue(value);
+ Py_DECREF(value);
+ if (initializing == -1)
+ PyErr_Clear();
+ }
+ if (initializing > 0) {
+ /* _bootstrap._lock_unlock_module() releases the import lock */
+ value = _PyObject_CallMethodObjIdArgs(interp->importlib,
+ &PyId__lock_unlock_module, abs_name,
+ NULL);
+ if (value == NULL)
+ goto error;
+ Py_DECREF(value);
+ }
+ else {
+#ifdef WITH_THREAD
+ if (_PyImport_ReleaseLock() < 0) {
+ PyErr_SetString(PyExc_RuntimeError, "not holding the import lock");
+ goto error;
+ }
+#endif
+ }
}
else {
+ /* _bootstrap._find_and_load() releases the import lock */
mod = _PyObject_CallMethodObjIdArgs(interp->importlib,
&PyId__find_and_load, abs_name,
builtins_import, NULL);
if (mod == NULL) {
- goto error_with_unlock;
+ goto error;
}
}
+ /* From now on we don't hold the import lock anymore. */
if (PyObject_Not(fromlist)) {
if (level == 0 || PyUnicode_GET_LENGTH(name) > 0) {
@@ -1625,12 +1619,12 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
if (borrowed_dot == NULL) {
- goto error_with_unlock;
+ goto error;
}
partition = PyUnicode_Partition(name, borrowed_dot);
if (partition == NULL) {
- goto error_with_unlock;
+ goto error;
}
if (PyUnicode_GET_LENGTH(PyTuple_GET_ITEM(partition, 1)) == 0) {
@@ -1638,7 +1632,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
Py_DECREF(partition);
final_mod = mod;
Py_INCREF(mod);
- goto exit_with_unlock;
+ goto error;
}
front = PyTuple_GET_ITEM(partition, 0);
@@ -1657,7 +1651,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
abs_name_len - cut_off);
Py_DECREF(front);
if (to_return == NULL) {
- goto error_with_unlock;
+ goto error;
}
final_mod = PyDict_GetItem(interp->modules, to_return);
@@ -1683,8 +1677,8 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
fromlist, builtins_import,
NULL);
}
+ goto error;
- exit_with_unlock:
error_with_unlock:
#ifdef WITH_THREAD
if (_PyImport_ReleaseLock() < 0) {