| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 55ed85e commit 8ba4df9
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ | |||
| 5 | 5 | extern "C" { | |
| 6 | 6 | #endif | |
| 7 | 7 | ||
| 8 | + #include "pycore_hashtable.h" // _Py_hashtable_t | ||
| 8 | 9 | #include "pycore_time.h" // _PyTime_t | |
| 9 | 10 | ||
| 10 | 11 | extern int _PyImport_IsInitialized(PyInterpreterState *); | |
@@ -36,19 +37,15 @@ struct _import_runtime_state { | |||
| 36 | 37 | See PyInterpreterState.modules_by_index for more info. */ | |
| 37 | 38 | Py_ssize_t last_module_index; | |
| 38 | 39 | struct { | |
| 39 | - /* A thread state tied to the main interpreter, | ||
| 40 | - used exclusively for when the extensions dict is access/modified | ||
| 41 | - from an arbitrary thread. */ | ||
| 42 | - PyThreadState main_tstate; | ||
| 43 | - /* A lock to guard the dict. */ | ||
| 40 | + /* A lock to guard the cache. */ | ||
| 44 | 41 | PyThread_type_lock mutex; | |
| 45 | - /* A dict mapping (filename, name) to PyModuleDef for modules. | ||
| 42 | + /* The actual cache of (filename, name, PyModuleDef) for modules. | ||
| 46 | 43 | Only legacy (single-phase init) extension modules are added | |
| 47 | 44 | and only if they support multiple initialization (m_size >- 0) | |
| 48 | 45 | or are imported in the main interpreter. | |
| 49 | 46 | This is initialized lazily in _PyImport_FixupExtensionObject(). | |
| 50 | 47 | Modules are added there and looked up in _imp.find_extension(). */ | |
| 51 | - PyObject *dict; | ||
| 48 | + _Py_hashtable_t *hashtable; | ||
| 52 | 49 | } extensions; | |
| 53 | 50 | /* Package context -- the full module name for package imports */ | |
| 54 | 51 | const char * pkgcontext; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -125,11 +125,6 @@ extern PyThreadState * _PyThreadState_New(PyInterpreterState *interp); | |||
| 125 | 125 | extern void _PyThreadState_Bind(PyThreadState *tstate); | |
| 126 | 126 | extern void _PyThreadState_DeleteExcept(PyThreadState *tstate); | |
| 127 | 127 | ||
| 128 | - extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); | ||
| 129 | - extern void _PyThreadState_ClearDetached(PyThreadState *); | ||
| 130 | - extern void _PyThreadState_BindDetached(PyThreadState *); | ||
| 131 | - extern void _PyThreadState_UnbindDetached(PyThreadState *); | ||
| 132 | - | ||
| 133 | 128 | // Export for '_testinternalcapi' shared extension | |
| 134 | 129 | PyAPI_FUNC(PyObject*) _PyThreadState_GetDict(PyThreadState *tstate); | |
| 135 | 130 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -97,11 +97,6 @@ extern PyTypeObject _PyExc_MemoryError; | |||
| 97 | 97 | in accordance with the specification. */ \ | |
| 98 | 98 | .autoTSSkey = Py_tss_NEEDS_INIT, \ | |
| 99 | 99 | .parser = _parser_runtime_state_INIT, \ | |
| 100 | - .imports = { \ | ||
| 101 | - .extensions = { \ | ||
| 102 | - .main_tstate = _PyThreadState_INIT, \ | ||
| 103 | - }, \ | ||
| 104 | - }, \ | ||
| 105 | 100 | .ceval = { \ | |
| 106 | 101 | .perf = _PyEval_RUNTIME_PERF_INIT, \ | |
| 107 | 102 | }, \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,10 +2,12 @@ | |||
| 2 | 2 | ||
| 3 | 3 | #include "Python.h" | |
| 4 | 4 | ||
| 5 | + #include "pycore_hashtable.h" // _Py_hashtable_new_full() | ||
| 5 | 6 | #include "pycore_import.h" // _PyImport_BootstrapImp() | |
| 6 | 7 | #include "pycore_initconfig.h" // _PyStatus_OK() | |
| 7 | 8 | #include "pycore_interp.h" // struct _import_runtime_state | |
| 8 | 9 | #include "pycore_namespace.h" // _PyNamespace_Type | |
| 10 | + #include "pycore_object.h" // _Py_SetImmortal() | ||
| 9 | 11 | #include "pycore_pyerrors.h" // _PyErr_SetString() | |
| 10 | 12 | #include "pycore_pyhash.h" // _Py_KeyedHash() | |
| 11 | 13 | #include "pycore_pylifecycle.h" | |
@@ -905,172 +907,192 @@ extensions_lock_release(void) | |||
| 905 | 907 | dictionary, to avoid loading shared libraries twice. | |
| 906 | 908 | */ | |
| 907 | 909 | ||
| 910 | + static void * | ||
| 911 | + hashtable_key_from_2_strings(PyObject *str1, PyObject *str2, const char sep) | ||
| 912 | + { | ||
| 913 | + Py_ssize_t str1_len, str2_len; | ||
| 914 | + const char *str1_data = PyUnicode_AsUTF8AndSize(str1, &str1_len); | ||
| 915 | + const char *str2_data = PyUnicode_AsUTF8AndSize(str2, &str2_len); | ||
| 916 | + if (str1_data == NULL || str2_data == NULL) { | ||
| 917 | + return NULL; | ||
| 918 | + } | ||
| 919 | + /* Make sure sep and the NULL byte won't cause an overflow. */ | ||
| 920 | + assert(SIZE_MAX - str1_len - str2_len > 2); | ||
| 921 | + size_t size = str1_len + 1 + str2_len + 1; | ||
| 922 | + | ||
| 923 | + char *key = PyMem_RawMalloc(size); | ||
| 924 | + if (key == NULL) { | ||
| 925 | + PyErr_NoMemory(); | ||
| 926 | + return NULL; | ||
| 927 | + } | ||
| 928 | + | ||
| 929 | + strncpy(key, str1_data, str1_len); | ||
| 930 | + key[str1_len] = sep; | ||
| 931 | + strncpy(key + str1_len + 1, str2_data, str2_len + 1); | ||
| 932 | + assert(strlen(key) == size - 1); | ||
| 933 | + return key; | ||
| 934 | + } | ||
| 935 | + | ||
| 936 | + static Py_uhash_t | ||
| 937 | + hashtable_hash_str(const void *key) | ||
| 938 | + { | ||
| 939 | + return _Py_HashBytes(key, strlen((const char *)key)); | ||
| 940 | + } | ||
| 941 | + | ||
| 942 | + static int | ||
| 943 | + hashtable_compare_str(const void *key1, const void *key2) | ||
| 944 | + { | ||
| 945 | + return strcmp((const char *)key1, (const char *)key2) == 0; | ||
| 946 | + } | ||
| 947 | + | ||
| 908 | 948 | static void | |
| 909 | - _extensions_cache_init(void) | ||
| 949 | + hashtable_destroy_str(void *ptr) | ||
| 910 | 950 | { | |
| 911 | - /* The runtime (i.e. main interpreter) must be initializing, | ||
| 912 | - so we don't need to worry about the lock. */ | ||
| 913 | - _PyThreadState_InitDetached(&EXTENSIONS.main_tstate, | ||
| 914 | - _PyInterpreterState_Main()); | ||
| 951 | + PyMem_RawFree(ptr); | ||
| 915 | 952 | } | |
| 916 | 953 | ||
| 954 | + #define HTSEP ':' | ||
| 955 | + | ||
| 917 | 956 | static PyModuleDef * | |
| 918 | 957 | _extensions_cache_get(PyObject *filename, PyObject *name) | |
| 919 | 958 | { | |
| 920 | 959 | PyModuleDef *def = NULL; | |
| 960 | + void *key = NULL; | ||
| 921 | 961 | extensions_lock_acquire(); | |
| 922 | 962 | ||
| 923 | - PyObject *key = PyTuple_Pack(2, filename, name); | ||
| 924 | - if (key == NULL) { | ||
| 963 | + if (EXTENSIONS.hashtable == NULL) { | ||
| 925 | 964 | goto finally; | |
| 926 | 965 | } | |
| 927 | 966 | ||
| 928 | - PyObject *extensions = EXTENSIONS.dict; | ||
| 929 | - if (extensions == NULL) { | ||
| 967 | + key = hashtable_key_from_2_strings(filename, name, HTSEP); | ||
| 968 | + if (key == NULL) { | ||
| 969 | + goto finally; | ||
| 970 | + } | ||
| 971 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( | ||
| 972 | + EXTENSIONS.hashtable, key); | ||
| 973 | + if (entry == NULL) { | ||
| 930 | 974 | goto finally; | |
| 931 | 975 | } | |
| 932 | - def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); | ||
| 976 | + def = (PyModuleDef *)entry->value; | ||
| 933 | 977 | ||
| 934 | 978 | finally: | |
| 935 | - Py_XDECREF(key); | ||
| 936 | 979 | extensions_lock_release(); | |
| 980 | + if (key != NULL) { | ||
| 981 | + PyMem_RawFree(key); | ||
| 982 | + } | ||
| 937 | 983 | return def; | |
| 938 | 984 | } | |
| 939 | 985 | ||
| 940 | 986 | static int | |
| 941 | 987 | _extensions_cache_set(PyObject *filename, PyObject *name, PyModuleDef *def) | |
| 942 | 988 | { | |
| 943 | 989 | int res = -1; | |
| 944 | - PyThreadState *oldts = NULL; | ||
| 945 | 990 | extensions_lock_acquire(); | |
| 946 | 991 | ||
| 947 | - /* Swap to the main interpreter, if necessary. This matters if | ||
| 948 | - the dict hasn't been created yet or if the item isn't in the | ||
| 949 | - dict yet. In both cases we must ensure the relevant objects | ||
| 950 | - are created using the main interpreter. */ | ||
| 951 | - PyThreadState *main_tstate = &EXTENSIONS.main_tstate; | ||
| 952 | - PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| 953 | - if (!_Py_IsMainInterpreter(interp)) { | ||
| 954 | - _PyThreadState_BindDetached(main_tstate); | ||
| 955 | - oldts = _PyThreadState_Swap(interp->runtime, main_tstate); | ||
| 956 | - assert(!_Py_IsMainInterpreter(oldts->interp)); | ||
| 957 | - | ||
| 958 | - /* Make sure the name and filename objects are owned | ||
| 959 | - by the main interpreter. */ | ||
| 960 | - name = PyUnicode_InternFromString(PyUnicode_AsUTF8(name)); | ||
| 961 | - assert(name != NULL); | ||
| 962 | - filename = PyUnicode_InternFromString(PyUnicode_AsUTF8(filename)); | ||
| 963 | - assert(filename != NULL); | ||
| 992 | + if (EXTENSIONS.hashtable == NULL) { | ||
| 993 | + _Py_hashtable_allocator_t alloc = {PyMem_RawMalloc, PyMem_RawFree}; | ||
| 994 | + EXTENSIONS.hashtable = _Py_hashtable_new_full( | ||
| 995 | + hashtable_hash_str, | ||
| 996 | + hashtable_compare_str, | ||
| 997 | + hashtable_destroy_str, // key | ||
| 998 | + /* There's no need to decref the def since it's immortal. */ | ||
| 999 | + NULL, // value | ||
| 1000 | + &alloc | ||
| 1001 | + ); | ||
| 1002 | + if (EXTENSIONS.hashtable == NULL) { | ||
| 1003 | + PyErr_NoMemory(); | ||
| 1004 | + goto finally; | ||
| 1005 | + } | ||
| 964 | 1006 | } | |
| 965 | 1007 | ||
| 966 | - PyObject *key = PyTuple_Pack(2, filename, name); | ||
| 1008 | + void *key = hashtable_key_from_2_strings(filename, name, HTSEP); | ||
| 967 | 1009 | if (key == NULL) { | |
| 968 | 1010 | goto finally; | |
| 969 | 1011 | } | |
| 970 | 1012 | ||
| 971 | - PyObject *extensions = EXTENSIONS.dict; | ||
| 972 | - if (extensions == NULL) { | ||
| 973 | - extensions = PyDict_New(); | ||
| 974 | - if (extensions == NULL) { | ||
| 1013 | + int already_set = 0; | ||
| 1014 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( | ||
| 1015 | + EXTENSIONS.hashtable, key); | ||
| 1016 | + if (entry == NULL) { | ||
| 1017 | + if (_Py_hashtable_set(EXTENSIONS.hashtable, key, def) < 0) { | ||
| 1018 | + PyMem_RawFree(key); | ||
| 1019 | + PyErr_NoMemory(); | ||
| 975 | 1020 | goto finally; | |
| 976 | 1021 | } | |
| 977 | - EXTENSIONS.dict = extensions; | ||
| 978 | - } | ||
| 979 | - | ||
| 980 | - PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); | ||
| 981 | - if (PyErr_Occurred()) { | ||
| 982 | - goto finally; | ||
| 983 | 1022 | } | |
| 984 | - else if (actual != NULL) { | ||
| 985 | - /* We expect it to be static, so it must be the same pointer. */ | ||
| 986 | - assert(def == actual); | ||
| 987 | - res = 0; | ||
| 988 | - goto finally; | ||
| 1023 | + else { | ||
| 1024 | + if (entry->value == NULL) { | ||
| 1025 | + entry->value = def; | ||
| 1026 | + } | ||
| 1027 | + else { | ||
| 1028 | + /* We expect it to be static, so it must be the same pointer. */ | ||
| 1029 | + assert((PyModuleDef *)entry->value == def); | ||
| 1030 | + already_set = 1; | ||
| 1031 | + } | ||
| 1032 | + PyMem_RawFree(key); | ||
| 989 | 1033 | } | |
| 990 | - | ||
| 991 | - /* This might trigger a resize, which is why we must switch | ||
| 992 | - to the main interpreter. */ | ||
| 993 | - res = PyDict_SetItem(extensions, key, (PyObject *)def); | ||
| 994 | - if (res < 0) { | ||
| 995 | - res = -1; | ||
| 996 | - goto finally; | ||
| 1034 | + if (!already_set) { | ||
| 1035 | + /* We assume that all module defs are statically allocated | ||
| 1036 | + and will never be freed. Otherwise, we would incref here. */ | ||
| 1037 | + _Py_SetImmortal(def); | ||
| 997 | 1038 | } | |
| 998 | 1039 | res = 0; | |
| 999 | 1040 | ||
| 1000 | 1041 | finally: | |
| 1001 | - Py_XDECREF(key); | ||
| 1002 | - if (oldts != NULL) { | ||
| 1003 | - _PyThreadState_Swap(interp->runtime, oldts); | ||
| 1004 | - _PyThreadState_UnbindDetached(main_tstate); | ||
| 1005 | - Py_DECREF(name); | ||
| 1006 | - Py_DECREF(filename); | ||
| 1007 | - } | ||
| 1008 | 1042 | extensions_lock_release(); | |
| 1009 | 1043 | return res; | |
| 1010 | 1044 | } | |
| 1011 | 1045 | ||
| 1012 | - static int | ||
| 1046 | + static void | ||
| 1013 | 1047 | _extensions_cache_delete(PyObject *filename, PyObject *name) | |
| 1014 | 1048 | { | |
| 1015 | - int res = -1; | ||
| 1016 | - PyThreadState *oldts = NULL; | ||
| 1049 | + void *key = NULL; | ||
| 1017 | 1050 | extensions_lock_acquire(); | |
| 1018 | 1051 | ||
| 1019 | - PyObject *key = PyTuple_Pack(2, filename, name); | ||
| 1020 | - if (key == NULL) { | ||
| 1052 | + if (EXTENSIONS.hashtable == NULL) { | ||
| 1053 | + /* It was never added. */ | ||
| 1021 | 1054 | goto finally; | |
| 1022 | 1055 | } | |
| 1023 | 1056 | ||
| 1024 | - PyObject *extensions = EXTENSIONS.dict; | ||
| 1025 | - if (extensions == NULL) { | ||
| 1026 | - res = 0; | ||
| 1057 | + key = hashtable_key_from_2_strings(filename, name, HTSEP); | ||
| 1058 | + if (key == NULL) { | ||
| 1027 | 1059 | goto finally; | |
| 1028 | 1060 | } | |
| 1029 | 1061 | ||
| 1030 | - PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); | ||
| 1031 | - if (PyErr_Occurred()) { | ||
| 1062 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( | ||
| 1063 | + EXTENSIONS.hashtable, key); | ||
| 1064 | + if (entry == NULL) { | ||
| 1065 | + /* It was never added. */ | ||
| 1032 | 1066 | goto finally; | |
| 1033 | 1067 | } | |
| 1034 | - else if (actual == NULL) { | ||
| 1035 | - /* It was already removed or never added. */ | ||
| 1036 | - res = 0; | ||
| 1068 | + if (entry->value == NULL) { | ||
| 1069 | + /* It was already removed. */ | ||
| 1037 | 1070 | goto finally; | |
| 1038 | 1071 | } | |
| 1039 | - | ||
| 1040 | - /* Swap to the main interpreter, if necessary. */ | ||
| 1041 | - PyThreadState *main_tstate = &EXTENSIONS.main_tstate; | ||
| 1042 | - PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| 1043 | - if (!_Py_IsMainInterpreter(interp)) { | ||
| 1044 | - _PyThreadState_BindDetached(main_tstate); | ||
| 1045 | - oldts = _PyThreadState_Swap(interp->runtime, main_tstate); | ||
| 1046 | - assert(!_Py_IsMainInterpreter(oldts->interp)); | ||
| 1047 | - } | ||
| 1048 | - | ||
| 1049 | - if (PyDict_DelItem(extensions, key) < 0) { | ||
| 1050 | - goto finally; | ||
| 1051 | - } | ||
| 1052 | - res = 0; | ||
| 1072 | + /* If we hadn't made the stored defs immortal, we would decref here. | ||
| 1073 | + However, this decref would be problematic if the module def were | ||
| 1074 | + dynamically allocated, it were the last ref, and this function | ||
| 1075 | + were called with an interpreter other than the def's owner. */ | ||
| 1076 | + entry->value = NULL; | ||
| 1053 | 1077 | ||
| 1054 | 1078 | finally: | |
| 1055 | - if (oldts != NULL) { | ||
| 1056 | - _PyThreadState_Swap(interp->runtime, oldts); | ||
| 1057 | - _PyThreadState_UnbindDetached(main_tstate); | ||
| 1058 | - } | ||
| 1059 | - Py_XDECREF(key); | ||
| 1060 | 1079 | extensions_lock_release(); | |
| 1061 | - return res; | ||
| 1080 | + if (key != NULL) { | ||
| 1081 | + PyMem_RawFree(key); | ||
| 1082 | + } | ||
| 1062 | 1083 | } | |
| 1063 | 1084 | ||
| 1064 | 1085 | static void | |
| 1065 | 1086 | _extensions_cache_clear_all(void) | |
| 1066 | 1087 | { | |
| 1067 | 1088 | /* The runtime (i.e. main interpreter) must be finalizing, | |
| 1068 | 1089 | so we don't need to worry about the lock. */ | |
| 1069 | - // XXX assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); | ||
| 1070 | - Py_CLEAR(EXTENSIONS.dict); | ||
| 1071 | - _PyThreadState_ClearDetached(&EXTENSIONS.main_tstate); | ||
| 1090 | + _Py_hashtable_destroy(EXTENSIONS.hashtable); | ||
| 1091 | + EXTENSIONS.hashtable = NULL; | ||
| 1072 | 1092 | } | |
| 1073 | 1093 | ||
| 1094 | + #undef HTSEP | ||
| 1095 | + | ||
| 1074 | 1096 | ||
| 1075 | 1097 | static bool | |
| 1076 | 1098 | check_multi_interp_extensions(PyInterpreterState *interp) | |
@@ -1231,6 +1253,8 @@ import_find_extension(PyThreadState *tstate, PyObject *name, | |||
| 1231 | 1253 | PyObject *m_copy = def->m_base.m_copy; | |
| 1232 | 1254 | /* Module does not support repeated initialization */ | |
| 1233 | 1255 | if (m_copy == NULL) { | |
| 1256 | + /* It might be a core module (e.g. sys & builtins), | ||
| 1257 | + for which we don't set m_copy. */ | ||
| 1234 | 1258 | m_copy = get_core_module_dict(tstate->interp, name, filename); | |
| 1235 | 1259 | if (m_copy == NULL) { | |
| 1236 | 1260 | return NULL; | |
@@ -1300,9 +1324,7 @@ clear_singlephase_extension(PyInterpreterState *interp, | |||
| 1300 | 1324 | } | |
| 1301 | 1325 | ||
| 1302 | 1326 | /* Clear the cached module def. */ | |
| 1303 | - if (_extensions_cache_delete(filename, name) < 0) { | ||
| 1304 | - return -1; | ||
| 1305 | - } | ||
| 1327 | + _extensions_cache_delete(filename, name); | ||
| 1306 | 1328 | ||
| 1307 | 1329 | return 0; | |
| 1308 | 1330 | } | |
@@ -3051,6 +3073,8 @@ void | |||
| 3051 | 3073 | _PyImport_Fini(void) | |
| 3052 | 3074 | { | |
| 3053 | 3075 | /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ | |
| 3076 | + // XXX Should we actually leave them (mostly) intact, since we don't | ||
| 3077 | + // ever dlclose() the module files? | ||
| 3054 | 3078 | _extensions_cache_clear_all(); | |
| 3055 | 3079 | ||
| 3056 | 3080 | /* Use the same memory allocator as _PyImport_Init(). */ | |
@@ -3088,10 +3112,6 @@ _PyImport_Fini2(void) | |||
| 3088 | 3112 | PyStatus | |
| 3089 | 3113 | _PyImport_InitCore(PyThreadState *tstate, PyObject *sysmod, int importlib) | |
| 3090 | 3114 | { | |
| 3091 | - if (_Py_IsMainInterpreter(tstate->interp)) { | ||
| 3092 | - _extensions_cache_init(); | ||
| 3093 | - } | ||
| 3094 | - | ||
| 3095 | 3115 | // XXX Initialize here: interp->modules and interp->import_func. | |
| 3096 | 3116 | // XXX Initialize here: sys.modules and sys.meta_path. | |
| 3097 | 3117 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments