|
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