|
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 |
|
|
0 commit comments