|
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"
|
@@ -912,172 +914,192 @@ extensions_lock_release(void)
|
912 | 914 | dictionary, to avoid loading shared libraries twice.
|
913 | 915 | */
|
914 | 916 |
|
| 917 | +static void * |
| 918 | +hashtable_key_from_2_strings(PyObject *str1, PyObject *str2, const char sep) |
| 919 | +{ |
| 920 | + Py_ssize_t str1_len, str2_len; |
| 921 | + const char *str1_data = PyUnicode_AsUTF8AndSize(str1, &str1_len); |
| 922 | + const char *str2_data = PyUnicode_AsUTF8AndSize(str2, &str2_len); |
| 923 | + if (str1_data == NULL || str2_data == NULL) { |
| 924 | + return NULL; |
| 925 | + } |
| 926 | + /* Make sure sep and the NULL byte won't cause an overflow. */ |
| 927 | + assert(SIZE_MAX - str1_len - str2_len > 2); |
| 928 | + size_t size = str1_len + 1 + str2_len + 1; |
| 929 | + |
| 930 | + char *key = PyMem_RawMalloc(size); |
| 931 | + if (key == NULL) { |
| 932 | + PyErr_NoMemory(); |
| 933 | + return NULL; |
| 934 | + } |
| 935 | + |
| 936 | + strncpy(key, str1_data, str1_len); |
| 937 | + key[str1_len] = sep; |
| 938 | + strncpy(key + str1_len + 1, str2_data, str2_len + 1); |
| 939 | + assert(strlen(key) == size - 1); |
| 940 | + return key; |
| 941 | +} |
| 942 | + |
| 943 | +static Py_uhash_t |
| 944 | +hashtable_hash_str(const void *key) |
| 945 | +{ |
| 946 | + return _Py_HashBytes(key, strlen((const char *)key)); |
| 947 | +} |
| 948 | + |
| 949 | +static int |
| 950 | +hashtable_compare_str(const void *key1, const void *key2) |
| 951 | +{ |
| 952 | + return strcmp((const char *)key1, (const char *)key2) == 0; |
| 953 | +} |
| 954 | + |
915 | 955 | static void
|
916 |
| -_extensions_cache_init(void) |
| 956 | +hashtable_destroy_str(void *ptr) |
917 | 957 | {
|
918 |
| - /* The runtime (i.e. main interpreter) must be initializing, |
919 |
| - so we don't need to worry about the lock. */ |
920 |
| - _PyThreadState_InitDetached(&EXTENSIONS.main_tstate, |
921 |
| - _PyInterpreterState_Main()); |
| 958 | + PyMem_RawFree(ptr); |
922 | 959 | }
|
923 | 960 |
|
| 961 | +#define HTSEP ':' |
| 962 | + |
924 | 963 | static PyModuleDef *
|
925 | 964 | _extensions_cache_get(PyObject *filename, PyObject *name)
|
926 | 965 | {
|
927 | 966 | PyModuleDef *def = NULL;
|
| 967 | + void *key = NULL; |
928 | 968 | extensions_lock_acquire();
|
929 | 969 |
|
930 |
| - PyObject *key = PyTuple_Pack(2, filename, name); |
931 |
| - if (key == NULL) { |
| 970 | + if (EXTENSIONS.hashtable == NULL) { |
932 | 971 | goto finally;
|
933 | 972 | }
|
934 | 973 |
|
935 |
| - PyObject *extensions = EXTENSIONS.dict; |
936 |
| - if (extensions == NULL) { |
| 974 | + key = hashtable_key_from_2_strings(filename, name, HTSEP); |
| 975 | + if (key == NULL) { |
| 976 | + goto finally; |
| 977 | + } |
| 978 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( |
| 979 | + EXTENSIONS.hashtable, key); |
| 980 | + if (entry == NULL) { |
937 | 981 | goto finally;
|
938 | 982 | }
|
939 |
| - def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); |
| 983 | + def = (PyModuleDef *)entry->value; |
940 | 984 |
|
941 | 985 | finally:
|
942 |
| - Py_XDECREF(key); |
943 | 986 | extensions_lock_release();
|
| 987 | + if (key != NULL) { |
| 988 | + PyMem_RawFree(key); |
| 989 | + } |
944 | 990 | return def;
|
945 | 991 | }
|
946 | 992 |
|
947 | 993 | static int
|
948 | 994 | _extensions_cache_set(PyObject *filename, PyObject *name, PyModuleDef *def)
|
949 | 995 | {
|
950 | 996 | int res = -1;
|
951 |
| - PyThreadState *oldts = NULL; |
952 | 997 | extensions_lock_acquire();
|
953 | 998 |
|
954 |
| - /* Swap to the main interpreter, if necessary. This matters if |
955 |
| - the dict hasn't been created yet or if the item isn't in the |
956 |
| - dict yet. In both cases we must ensure the relevant objects |
957 |
| - are created using the main interpreter. */ |
958 |
| - PyThreadState *main_tstate = &EXTENSIONS.main_tstate; |
959 |
| - PyInterpreterState *interp = _PyInterpreterState_GET(); |
960 |
| - if (!_Py_IsMainInterpreter(interp)) { |
961 |
| - _PyThreadState_BindDetached(main_tstate); |
962 |
| - oldts = _PyThreadState_Swap(interp->runtime, main_tstate); |
963 |
| - assert(!_Py_IsMainInterpreter(oldts->interp)); |
964 |
| - |
965 |
| - /* Make sure the name and filename objects are owned |
966 |
| - by the main interpreter. */ |
967 |
| - name = PyUnicode_InternFromString(PyUnicode_AsUTF8(name)); |
968 |
| - assert(name != NULL); |
969 |
| - filename = PyUnicode_InternFromString(PyUnicode_AsUTF8(filename)); |
970 |
| - assert(filename != NULL); |
| 999 | + if (EXTENSIONS.hashtable == NULL) { |
| 1000 | + _Py_hashtable_allocator_t alloc = {PyMem_RawMalloc, PyMem_RawFree}; |
| 1001 | + EXTENSIONS.hashtable = _Py_hashtable_new_full( |
| 1002 | + hashtable_hash_str, |
| 1003 | + hashtable_compare_str, |
| 1004 | + hashtable_destroy_str, // key |
| 1005 | + /* There's no need to decref the def since it's immortal. */ |
| 1006 | + NULL, // value |
| 1007 | + &alloc |
| 1008 | + ); |
| 1009 | + if (EXTENSIONS.hashtable == NULL) { |
| 1010 | + PyErr_NoMemory(); |
| 1011 | + goto finally; |
| 1012 | + } |
971 | 1013 | }
|
972 | 1014 |
|
973 |
| - PyObject *key = PyTuple_Pack(2, filename, name); |
| 1015 | + void *key = hashtable_key_from_2_strings(filename, name, HTSEP); |
974 | 1016 | if (key == NULL) {
|
975 | 1017 | goto finally;
|
976 | 1018 | }
|
977 | 1019 |
|
978 |
| - PyObject *extensions = EXTENSIONS.dict; |
979 |
| - if (extensions == NULL) { |
980 |
| - extensions = PyDict_New(); |
981 |
| - if (extensions == NULL) { |
| 1020 | + int already_set = 0; |
| 1021 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( |
| 1022 | + EXTENSIONS.hashtable, key); |
| 1023 | + if (entry == NULL) { |
| 1024 | + if (_Py_hashtable_set(EXTENSIONS.hashtable, key, def) < 0) { |
| 1025 | + PyMem_RawFree(key); |
| 1026 | + PyErr_NoMemory(); |
982 | 1027 | goto finally;
|
983 | 1028 | }
|
984 |
| - EXTENSIONS.dict = extensions; |
985 |
| - } |
986 |
| - |
987 |
| - PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); |
988 |
| - if (PyErr_Occurred()) { |
989 |
| - goto finally; |
990 | 1029 | }
|
991 |
| - else if (actual != NULL) { |
992 |
| - /* We expect it to be static, so it must be the same pointer. */ |
993 |
| - assert(def == actual); |
994 |
| - res = 0; |
995 |
| - goto finally; |
| 1030 | + else { |
| 1031 | + if (entry->value == NULL) { |
| 1032 | + entry->value = def; |
| 1033 | + } |
| 1034 | + else { |
| 1035 | + /* We expect it to be static, so it must be the same pointer. */ |
| 1036 | + assert((PyModuleDef *)entry->value == def); |
| 1037 | + already_set = 1; |
| 1038 | + } |
| 1039 | + PyMem_RawFree(key); |
996 | 1040 | }
|
997 |
| - |
998 |
| - /* This might trigger a resize, which is why we must switch |
999 |
| - to the main interpreter. */ |
1000 |
| - res = PyDict_SetItem(extensions, key, (PyObject *)def); |
1001 |
| - if (res < 0) { |
1002 |
| - res = -1; |
1003 |
| - goto finally; |
| 1041 | + if (!already_set) { |
| 1042 | + /* We assume that all module defs are statically allocated |
| 1043 | + and will never be freed. Otherwise, we would incref here. */ |
| 1044 | + _Py_SetImmortal(def); |
1004 | 1045 | }
|
1005 | 1046 | res = 0;
|
1006 | 1047 |
|
1007 | 1048 | finally:
|
1008 |
| - Py_XDECREF(key); |
1009 |
| - if (oldts != NULL) { |
1010 |
| - _PyThreadState_Swap(interp->runtime, oldts); |
1011 |
| - _PyThreadState_UnbindDetached(main_tstate); |
1012 |
| - Py_DECREF(name); |
1013 |
| - Py_DECREF(filename); |
1014 |
| - } |
1015 | 1049 | extensions_lock_release();
|
1016 | 1050 | return res;
|
1017 | 1051 | }
|
1018 | 1052 |
|
1019 |
| -static int |
| 1053 | +static void |
1020 | 1054 | _extensions_cache_delete(PyObject *filename, PyObject *name)
|
1021 | 1055 | {
|
1022 |
| - int res = -1; |
1023 |
| - PyThreadState *oldts = NULL; |
| 1056 | + void *key = NULL; |
1024 | 1057 | extensions_lock_acquire();
|
1025 | 1058 |
|
1026 |
| - PyObject *key = PyTuple_Pack(2, filename, name); |
1027 |
| - if (key == NULL) { |
| 1059 | + if (EXTENSIONS.hashtable == NULL) { |
| 1060 | + /* It was never added. */ |
1028 | 1061 | goto finally;
|
1029 | 1062 | }
|
1030 | 1063 |
|
1031 |
| - PyObject *extensions = EXTENSIONS.dict; |
1032 |
| - if (extensions == NULL) { |
1033 |
| - res = 0; |
| 1064 | + key = hashtable_key_from_2_strings(filename, name, HTSEP); |
| 1065 | + if (key == NULL) { |
1034 | 1066 | goto finally;
|
1035 | 1067 | }
|
1036 | 1068 |
|
1037 |
| - PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); |
1038 |
| - if (PyErr_Occurred()) { |
| 1069 | + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( |
| 1070 | + EXTENSIONS.hashtable, key); |
| 1071 | + if (entry == NULL) { |
| 1072 | + /* It was never added. */ |
1039 | 1073 | goto finally;
|
1040 | 1074 | }
|
1041 |
| - else if (actual == NULL) { |
1042 |
| - /* It was already removed or never added. */ |
1043 |
| - res = 0; |
| 1075 | + if (entry->value == NULL) { |
| 1076 | + /* It was already removed. */ |
1044 | 1077 | goto finally;
|
1045 | 1078 | }
|
1046 |
| - |
1047 |
| - /* Swap to the main interpreter, if necessary. */ |
1048 |
| - PyThreadState *main_tstate = &EXTENSIONS.main_tstate; |
1049 |
| - PyInterpreterState *interp = _PyInterpreterState_GET(); |
1050 |
| - if (!_Py_IsMainInterpreter(interp)) { |
1051 |
| - _PyThreadState_BindDetached(main_tstate); |
1052 |
| - oldts = _PyThreadState_Swap(interp->runtime, main_tstate); |
1053 |
| - assert(!_Py_IsMainInterpreter(oldts->interp)); |
1054 |
| - } |
1055 |
| - |
1056 |
| - if (PyDict_DelItem(extensions, key) < 0) { |
1057 |
| - goto finally; |
1058 |
| - } |
1059 |
| - res = 0; |
| 1079 | + /* If we hadn't made the stored defs immortal, we would decref here. |
| 1080 | + However, this decref would be problematic if the module def were |
| 1081 | + dynamically allocated, it were the last ref, and this function |
| 1082 | + were called with an interpreter other than the def's owner. */ |
| 1083 | + entry->value = NULL; |
1060 | 1084 |
|
1061 | 1085 | finally:
|
1062 |
| - if (oldts != NULL) { |
1063 |
| - _PyThreadState_Swap(interp->runtime, oldts); |
1064 |
| - _PyThreadState_UnbindDetached(main_tstate); |
1065 |
| - } |
1066 |
| - Py_XDECREF(key); |
1067 | 1086 | extensions_lock_release();
|
1068 |
| - return res; |
| 1087 | + if (key != NULL) { |
| 1088 | + PyMem_RawFree(key); |
| 1089 | + } |
1069 | 1090 | }
|
1070 | 1091 |
|
1071 | 1092 | static void
|
1072 | 1093 | _extensions_cache_clear_all(void)
|
1073 | 1094 | {
|
1074 | 1095 | /* The runtime (i.e. main interpreter) must be finalizing,
|
1075 | 1096 | so we don't need to worry about the lock. */
|
1076 |
| - // XXX assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); |
1077 |
| - Py_CLEAR(EXTENSIONS.dict); |
1078 |
| - _PyThreadState_ClearDetached(&EXTENSIONS.main_tstate); |
| 1097 | + _Py_hashtable_destroy(EXTENSIONS.hashtable); |
| 1098 | + EXTENSIONS.hashtable = NULL; |
1079 | 1099 | }
|
1080 | 1100 |
|
| 1101 | +#undef HTSEP |
| 1102 | + |
1081 | 1103 |
|
1082 | 1104 | static bool
|
1083 | 1105 | check_multi_interp_extensions(PyInterpreterState *interp)
|
@@ -1238,6 +1260,8 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
|
1238 | 1260 | PyObject *m_copy = def->m_base.m_copy;
|
1239 | 1261 | /* Module does not support repeated initialization */
|
1240 | 1262 | if (m_copy == NULL) {
|
| 1263 | + /* It might be a core module (e.g. sys & builtins), |
| 1264 | + for which we don't set m_copy. */ |
1241 | 1265 | m_copy = get_core_module_dict(tstate->interp, name, filename);
|
1242 | 1266 | if (m_copy == NULL) {
|
1243 | 1267 | return NULL;
|
@@ -1307,9 +1331,7 @@ clear_singlephase_extension(PyInterpreterState *interp,
|
1307 | 1331 | }
|
1308 | 1332 |
|
1309 | 1333 | /* Clear the cached module def. */
|
1310 |
| - if (_extensions_cache_delete(filename, name) < 0) { |
1311 |
| - return -1; |
1312 |
| - } |
| 1334 | + _extensions_cache_delete(filename, name); |
1313 | 1335 |
|
1314 | 1336 | return 0;
|
1315 | 1337 | }
|
@@ -3059,6 +3081,8 @@ void
|
3059 | 3081 | _PyImport_Fini(void)
|
3060 | 3082 | {
|
3061 | 3083 | /* Destroy the database used by _PyImport_{Fixup,Find}Extension */
|
| 3084 | + // XXX Should we actually leave them (mostly) intact, since we don't |
| 3085 | + // ever dlclose() the module files? |
3062 | 3086 | _extensions_cache_clear_all();
|
3063 | 3087 |
|
3064 | 3088 | /* Use the same memory allocator as _PyImport_Init(). */
|
@@ -3096,10 +3120,6 @@ _PyImport_Fini2(void)
|
3096 | 3120 | PyStatus
|
3097 | 3121 | _PyImport_InitCore(PyThreadState *tstate, PyObject *sysmod, int importlib)
|
3098 | 3122 | {
|
3099 |
| - if (_Py_IsMainInterpreter(tstate->interp)) { |
3100 |
| - _extensions_cache_init(); |
3101 |
| - } |
3102 |
| - |
3103 | 3123 | // XXX Initialize here: interp->modules and interp->import_func.
|
3104 | 3124 | // XXX Initialize here: sys.modules and sys.meta_path.
|
3105 | 3125 |
|
|
0 commit comments