diff --git a/src/arm/linux/init.c b/src/arm/linux/init.c index 1bf0014d..53e9a43d 100644 --- a/src/arm/linux/init.c +++ b/src/arm/linux/init.c @@ -1001,3 +1001,43 @@ void cpuinfo_arm_linux_init(void) { free(linux_cpu_to_core_map); free(linux_cpu_to_uarch_index_map); } + +void cpuinfo_arm_linux_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + /* cpuinfo_packages points to static storage (&package) — do not free */ + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + free(cpuinfo_uarchs); + cpuinfo_uarchs = NULL; + cpuinfo_uarchs_count = 0; + + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + free(cpuinfo_cache[lvl]); + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + free(cpuinfo_linux_cpu_to_processor_map); + cpuinfo_linux_cpu_to_processor_map = NULL; + + free(cpuinfo_linux_cpu_to_core_map); + cpuinfo_linux_cpu_to_core_map = NULL; + + free((void*)cpuinfo_linux_cpu_to_uarch_index_map); + cpuinfo_linux_cpu_to_uarch_index_map = NULL; + + cpuinfo_linux_cpu_max = 0; +} diff --git a/src/arm/mach/init.c b/src/arm/mach/init.c index 11de4ae3..eac431f7 100644 --- a/src/arm/mach/init.c +++ b/src/arm/mach/init.c @@ -755,3 +755,32 @@ void cpuinfo_arm_mach_init(void) { free(l2); free(l3); } + +void cpuinfo_arm_mach_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + free(cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + free(cpuinfo_uarchs); + cpuinfo_uarchs = NULL; + cpuinfo_uarchs_count = 0; + + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + free(cpuinfo_cache[lvl]); + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; +} diff --git a/src/arm/windows/init-by-logical-sys-info.c b/src/arm/windows/init-by-logical-sys-info.c index 815ecb77..2e44f8aa 100644 --- a/src/arm/windows/init-by-logical-sys-info.c +++ b/src/arm/windows/init-by-logical-sys-info.c @@ -372,6 +372,40 @@ bool cpu_info_init_by_logical_sys_info(const struct woa_chip_info* chip_info, co return result; } +BOOL CALLBACK cpuinfo_arm_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context) { + HANDLE heap = GetProcessHeap(); + + HeapFree(heap, 0, cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + HeapFree(heap, 0, cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + HeapFree(heap, 0, cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + HeapFree(heap, 0, cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + HeapFree(heap, 0, cpuinfo_uarchs); + cpuinfo_uarchs = NULL; + cpuinfo_uarchs_count = 0; + + /* Caches are allocated as a single contiguous block starting at l1i */ + HeapFree(heap, 0, cpuinfo_cache[cpuinfo_cache_level_1i]); + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + return TRUE; +} + static uint32_t count_logical_processors(const uint32_t max_group_count, uint32_t* global_proc_index_per_group) { uint32_t nr_of_processors = 0; diff --git a/src/cpuinfo/internal-api.h b/src/cpuinfo/internal-api.h index d84b26a8..9c158887 100644 --- a/src/cpuinfo/internal-api.h +++ b/src/cpuinfo/internal-api.h @@ -45,6 +45,9 @@ extern CPUINFO_INTERNAL struct cpuinfo_uarch_info cpuinfo_global_uarch; extern CPUINFO_INTERNAL uint32_t cpuinfo_linux_cpu_max; extern CPUINFO_INTERNAL const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map; extern CPUINFO_INTERNAL const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map; +#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 +extern CPUINFO_INTERNAL const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map; +#endif #endif CPUINFO_PRIVATE void cpuinfo_x86_mach_init(void); @@ -62,6 +65,23 @@ CPUINFO_PRIVATE void cpuinfo_arm_linux_init(void); CPUINFO_PRIVATE void cpuinfo_riscv_linux_init(void); CPUINFO_PRIVATE void cpuinfo_emscripten_init(void); +/* Platform-specific deinitialization functions. + * Each frees the globals allocated by its corresponding init function. */ +CPUINFO_PRIVATE void cpuinfo_x86_mach_deinit(void); +CPUINFO_PRIVATE void cpuinfo_x86_linux_deinit(void); +CPUINFO_PRIVATE void cpuinfo_x86_freebsd_deinit(void); +#if defined(_WIN32) || defined(__CYGWIN__) +#if CPUINFO_ARCH_ARM64 +CPUINFO_PRIVATE BOOL CALLBACK cpuinfo_arm_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context); +#else +CPUINFO_PRIVATE BOOL CALLBACK cpuinfo_x86_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context); +#endif +#endif +CPUINFO_PRIVATE void cpuinfo_arm_mach_deinit(void); +CPUINFO_PRIVATE void cpuinfo_arm_linux_deinit(void); +CPUINFO_PRIVATE void cpuinfo_riscv_linux_deinit(void); +CPUINFO_PRIVATE void cpuinfo_emscripten_deinit(void); + CPUINFO_PRIVATE uint32_t cpuinfo_compute_max_cache_size(const struct cpuinfo_processor* processor); typedef void (*cpuinfo_processor_callback)(uint32_t); diff --git a/src/emscripten/init.c b/src/emscripten/init.c index c2393243..6c8210f2 100644 --- a/src/emscripten/init.c +++ b/src/emscripten/init.c @@ -286,3 +286,35 @@ void cpuinfo_emscripten_init(void) { free(l1d); free(l2); } + +void cpuinfo_emscripten_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + /* cpuinfo_packages points to static storage (&static_package) — do not free */ + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + /* L1i, L1d, L2 are dynamically allocated; L3 may point to static + * storage (&static_x86_l3) so only free levels that were calloc'd */ + free(cpuinfo_cache[cpuinfo_cache_level_1i]); + free(cpuinfo_cache[cpuinfo_cache_level_1d]); + free(cpuinfo_cache[cpuinfo_cache_level_2]); + /* cpuinfo_cache[cpuinfo_cache_level_3] may be &static_x86_l3 — do not free */ + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + cpuinfo_global_uarch = (struct cpuinfo_uarch_info){0}; +} diff --git a/src/init.c b/src/init.c index 81d5721c..e4b684bd 100644 --- a/src/init.c +++ b/src/init.c @@ -14,10 +14,13 @@ #if defined(_WIN32) || defined(__CYGWIN__) static INIT_ONCE init_guard = INIT_ONCE_STATIC_INIT; +static INIT_ONCE deinit_guard = INIT_ONCE_STATIC_INIT; #elif !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__) static pthread_once_t init_guard = PTHREAD_ONCE_INIT; +static pthread_once_t deinit_guard = PTHREAD_ONCE_INIT; #else static bool init_guard = false; +static bool deinit_guard = false; #endif bool CPUINFO_ABI cpuinfo_initialize(void) { @@ -64,4 +67,52 @@ bool CPUINFO_ABI cpuinfo_initialize(void) { return cpuinfo_is_initialized; } -void CPUINFO_ABI cpuinfo_deinitialize(void) {} +void CPUINFO_ABI cpuinfo_deinitialize(void) { + if (!cpuinfo_is_initialized) { + return; + } + cpuinfo_is_initialized = false; +#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64 +#if defined(__MACH__) && defined(__APPLE__) + pthread_once(&deinit_guard, &cpuinfo_x86_mach_deinit); +#elif defined(__FreeBSD__) + pthread_once(&deinit_guard, &cpuinfo_x86_freebsd_deinit); +#elif defined(__linux__) + pthread_once(&deinit_guard, &cpuinfo_x86_linux_deinit); +#elif defined(_WIN32) || defined(__CYGWIN__) + InitOnceExecuteOnce(&deinit_guard, &cpuinfo_x86_windows_deinit, NULL, NULL); +#endif +#elif CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 +#if defined(__linux__) + pthread_once(&deinit_guard, &cpuinfo_arm_linux_deinit); +#elif defined(__MACH__) && defined(__APPLE__) + pthread_once(&deinit_guard, &cpuinfo_arm_mach_deinit); +#elif defined(_WIN32) + InitOnceExecuteOnce(&deinit_guard, &cpuinfo_arm_windows_deinit, NULL, NULL); +#endif +#elif CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 +#if defined(__linux__) + pthread_once(&deinit_guard, &cpuinfo_riscv_linux_deinit); +#endif +#elif CPUINFO_ARCH_ASMJS || CPUINFO_ARCH_WASM || CPUINFO_ARCH_WASMSIMD +#if defined(__EMSCRIPTEN_PTHREADS__) + pthread_once(&deinit_guard, &cpuinfo_emscripten_deinit); +#else + if (!deinit_guard) { + cpuinfo_emscripten_deinit(); + } + deinit_guard = true; +#endif +#endif + /* Reset guards to allow re-initialization */ +#if defined(_WIN32) || defined(__CYGWIN__) + init_guard = INIT_ONCE_STATIC_INIT; + deinit_guard = INIT_ONCE_STATIC_INIT; +#elif !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__) + init_guard = PTHREAD_ONCE_INIT; + deinit_guard = PTHREAD_ONCE_INIT; +#else + init_guard = false; + deinit_guard = false; +#endif +} diff --git a/src/riscv/linux/init.c b/src/riscv/linux/init.c index 45168c7e..3da8c3ff 100644 --- a/src/riscv/linux/init.c +++ b/src/riscv/linux/init.c @@ -618,3 +618,36 @@ void cpuinfo_riscv_linux_init(void) { free(linux_cpu_to_core_map); free(linux_cpu_to_uarch_index_map); } + +void cpuinfo_riscv_linux_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + free(cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + free(cpuinfo_uarchs); + cpuinfo_uarchs = NULL; + cpuinfo_uarchs_count = 0; + + free(cpuinfo_linux_cpu_to_processor_map); + cpuinfo_linux_cpu_to_processor_map = NULL; + + free(cpuinfo_linux_cpu_to_core_map); + cpuinfo_linux_cpu_to_core_map = NULL; + + free((void*)cpuinfo_linux_cpu_to_uarch_index_map); + cpuinfo_linux_cpu_to_uarch_index_map = NULL; + + cpuinfo_linux_cpu_max = 0; +} diff --git a/src/x86/freebsd/init.c b/src/x86/freebsd/init.c index 797fa24b..ba30a5d9 100644 --- a/src/x86/freebsd/init.c +++ b/src/x86/freebsd/init.c @@ -396,3 +396,30 @@ void cpuinfo_x86_freebsd_init(void) { free(l3); free(l4); } + +void cpuinfo_x86_freebsd_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + free(cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + free(cpuinfo_cache[lvl]); + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + cpuinfo_global_uarch = (struct cpuinfo_uarch_info){0}; +} diff --git a/src/x86/linux/init.c b/src/x86/linux/init.c index d2b2d475..5f6dd6a5 100644 --- a/src/x86/linux/init.c +++ b/src/x86/linux/init.c @@ -676,3 +676,38 @@ void cpuinfo_x86_linux_init(void) { free(linux_cpu_to_processor_map); free(linux_cpu_to_core_map); } + +void cpuinfo_x86_linux_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + free(cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + free(cpuinfo_cache[lvl]); + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + free(cpuinfo_linux_cpu_to_processor_map); + cpuinfo_linux_cpu_to_processor_map = NULL; + + free(cpuinfo_linux_cpu_to_core_map); + cpuinfo_linux_cpu_to_core_map = NULL; + + cpuinfo_linux_cpu_max = 0; + + cpuinfo_global_uarch = (struct cpuinfo_uarch_info){0}; +} \ No newline at end of file diff --git a/src/x86/mach/init.c b/src/x86/mach/init.c index b8ea6047..321f8879 100644 --- a/src/x86/mach/init.c +++ b/src/x86/mach/init.c @@ -378,3 +378,30 @@ void cpuinfo_x86_mach_init(void) { free(l3); free(l4); } + +void cpuinfo_x86_mach_deinit(void) { + free(cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + free(cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + free(cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + free(cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + free(cpuinfo_cache[lvl]); + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + cpuinfo_global_uarch = (struct cpuinfo_uarch_info){0}; +} \ No newline at end of file diff --git a/src/x86/windows/init.c b/src/x86/windows/init.c index d2332802..7b97d114 100644 --- a/src/x86/windows/init.c +++ b/src/x86/windows/init.c @@ -667,5 +667,39 @@ BOOL CALLBACK cpuinfo_x86_windows_init(PINIT_ONCE init_once, PVOID parameter, PV if (l4 != NULL) { HeapFree(heap, 0, l4); } + if (processor_infos != NULL) { + HeapFree(heap, 0, processor_infos); + } + return TRUE; +} + +BOOL CALLBACK cpuinfo_x86_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context) { + HANDLE heap = GetProcessHeap(); + + HeapFree(heap, 0, cpuinfo_processors); + cpuinfo_processors = NULL; + cpuinfo_processors_count = 0; + + HeapFree(heap, 0, cpuinfo_cores); + cpuinfo_cores = NULL; + cpuinfo_cores_count = 0; + + HeapFree(heap, 0, cpuinfo_clusters); + cpuinfo_clusters = NULL; + cpuinfo_clusters_count = 0; + + HeapFree(heap, 0, cpuinfo_packages); + cpuinfo_packages = NULL; + cpuinfo_packages_count = 0; + + for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) { + HeapFree(heap, 0, cpuinfo_cache[lvl]); + cpuinfo_cache[lvl] = NULL; + cpuinfo_cache_count[lvl] = 0; + } + cpuinfo_max_cache_size = 0; + + cpuinfo_global_uarch = (struct cpuinfo_uarch_info){0}; + return TRUE; }