Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,12 @@ IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_UNIT_TESTS)
TARGET_LINK_LIBRARIES(init-test PRIVATE cpuinfo gtest gtest_main)
ADD_TEST(NAME init-test COMMAND init-test)

ADD_EXECUTABLE(deinit-test test/deinit.cc)
CPUINFO_TARGET_ENABLE_CXX11(deinit-test)
CPUINFO_TARGET_RUNTIME_LIBRARY(deinit-test)
TARGET_LINK_LIBRARIES(deinit-test PRIVATE cpuinfo gtest gtest_main)
ADD_TEST(NAME deinit-test COMMAND deinit-test)

IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
ADD_EXECUTABLE(get-current-test test/get-current.cc)
CPUINFO_TARGET_ENABLE_CXX11(get-current-test)
Expand Down
3 changes: 3 additions & 0 deletions src/cpuinfo/internal-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
crvineeth97 marked this conversation as resolved.
extern CPUINFO_INTERNAL const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map;
#endif
#endif

CPUINFO_PRIVATE void cpuinfo_x86_mach_init(void);
Expand Down
98 changes: 97 additions & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <windows.h>
#elif !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)
#include <pthread.h>
#include <stdlib.h>
#endif

#include <cpuinfo.h>
Expand All @@ -14,10 +15,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) {
Expand Down Expand Up @@ -64,4 +68,96 @@ bool CPUINFO_ABI cpuinfo_initialize(void) {
return cpuinfo_is_initialized;
}

void CPUINFO_ABI cpuinfo_deinitialize(void) {}
/*
* Cleanup support for platforms where cpuinfo may be dynamically loaded/unloaded.
* ARM Linux and Emscripten are excluded because they use static storage for some
* globals (packages, L3 cache) that cannot be safely freed.
*/
#if defined(_WIN32) || defined(__CYGWIN__)
#define CPUINFO_FREE(ptr) \
do { \
if (ptr) \
HeapFree(GetProcessHeap(), 0, (void*)(ptr)); \
} while (0)
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
#define CPUINFO_FREE(ptr) free(ptr)
#endif

#if defined(_WIN32) || defined(__CYGWIN__) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)

static void cpuinfo_cleanup(void) {
if (!cpuinfo_is_initialized) {
return;
}

cpuinfo_is_initialized = false;

CPUINFO_FREE(cpuinfo_processors);
cpuinfo_processors = NULL;
cpuinfo_processors_count = 0;
Comment thread
crvineeth97 marked this conversation as resolved.
Outdated

CPUINFO_FREE(cpuinfo_cores);
cpuinfo_cores = NULL;
cpuinfo_cores_count = 0;

CPUINFO_FREE(cpuinfo_clusters);
cpuinfo_clusters = NULL;
cpuinfo_clusters_count = 0;

CPUINFO_FREE(cpuinfo_packages);
cpuinfo_packages = NULL;
cpuinfo_packages_count = 0;

/* ARM64 Windows allocates all cache levels as a single contiguous block.
* All other supported platforms allocate each level separately. */
#if CPUINFO_ARCH_ARM64 && defined(_WIN32)
CPUINFO_FREE(cpuinfo_cache[cpuinfo_cache_level_1i]);
#else
for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) {
CPUINFO_FREE(cpuinfo_cache[lvl]);
}
#endif
for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) {
cpuinfo_cache[lvl] = NULL;
cpuinfo_cache_count[lvl] = 0;
}
cpuinfo_max_cache_size = 0;

#if (CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64)
CPUINFO_FREE(cpuinfo_uarchs);
cpuinfo_uarchs = NULL;
cpuinfo_uarchs_count = 0;
#endif

#ifdef __linux__
CPUINFO_FREE(cpuinfo_linux_cpu_to_processor_map);
cpuinfo_linux_cpu_to_processor_map = NULL;

CPUINFO_FREE(cpuinfo_linux_cpu_to_core_map);
cpuinfo_linux_cpu_to_core_map = NULL;

#if (CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64)
CPUINFO_FREE(cpuinfo_linux_cpu_to_uarch_index_map);
cpuinfo_linux_cpu_to_uarch_index_map = NULL;
#endif

cpuinfo_linux_cpu_max = 0;
#endif
}

#endif

#if defined(_WIN32) || defined(__CYGWIN__)
static BOOL CALLBACK cpuinfo_deinit_once(PINIT_ONCE once, PVOID param, PVOID* ctx) {
cpuinfo_cleanup();
return TRUE;
}
#endif

void CPUINFO_ABI cpuinfo_deinitialize(void) {
#if defined(_WIN32) || defined(__CYGWIN__)
InitOnceExecuteOnce(&deinit_guard, cpuinfo_deinit_once, NULL, NULL);
#elif (defined(__linux__) && !CPUINFO_ARCH_ARM) || defined(__APPLE__) || defined(__FreeBSD__)
pthread_once(&deinit_guard, cpuinfo_cleanup);
#endif
}
3 changes: 3 additions & 0 deletions src/x86/windows/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@

/* WINE doesn't implement GetMaximumProcessorGroupCount and aborts when
* calling it */
const uint32_t max_group_count = is_wine ? 1 : (uint32_t)GetMaximumProcessorGroupCount();

Check warning on line 134 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorGroupCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo_internals.vcxproj]

Check warning on line 134 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorGroupCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo.vcxproj]

Check warning on line 134 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorGroupCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo_internals.vcxproj]

Check warning on line 134 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorGroupCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo.vcxproj]
cpuinfo_log_debug("detected %" PRIu32 " processor groups", max_group_count);

uint32_t processors_count = 0;
uint32_t* processors_per_group = (uint32_t*)CPUINFO_ALLOCA(max_group_count * sizeof(uint32_t));
for (uint32_t i = 0; i < max_group_count; i++) {
processors_per_group[i] = GetMaximumProcessorCount((WORD)i);

Check warning on line 140 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo_internals.vcxproj]

Check warning on line 140 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo.vcxproj]

Check warning on line 140 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo_internals.vcxproj]

Check warning on line 140 in src/x86/windows/init.c

View workflow job for this annotation

GitHub Actions / cmake-uwp

'GetMaximumProcessorCount' undefined; assuming extern returning int [D:\a\cpuinfo\cpuinfo\build\x64-uwp\cpuinfo.vcxproj]
cpuinfo_log_debug("detected %" PRIu32 " processors in group %" PRIu32, processors_per_group[i], i);
processors_count += processors_per_group[i];
}
Expand Down Expand Up @@ -667,5 +667,8 @@
if (l4 != NULL) {
HeapFree(heap, 0, l4);
}
if (processor_infos != NULL) {
HeapFree(heap, 0, processor_infos);
}
return TRUE;
}
87 changes: 87 additions & 0 deletions test/deinit.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <gtest/gtest.h>

#include <cpuinfo.h>

TEST(DEINITIALIZE, clears_processors) {
ASSERT_TRUE(cpuinfo_initialize());
EXPECT_NE(0, cpuinfo_get_processors_count());
EXPECT_TRUE(cpuinfo_get_processors());

cpuinfo_deinitialize();

EXPECT_EQ(0, cpuinfo_get_processors_count());
EXPECT_FALSE(cpuinfo_get_processors());
}

TEST(DEINITIALIZE, clears_cores) {
ASSERT_TRUE(cpuinfo_initialize());
EXPECT_NE(0, cpuinfo_get_cores_count());
EXPECT_TRUE(cpuinfo_get_cores());

cpuinfo_deinitialize();

EXPECT_EQ(0, cpuinfo_get_cores_count());
EXPECT_FALSE(cpuinfo_get_cores());
}

TEST(DEINITIALIZE, clears_clusters) {
ASSERT_TRUE(cpuinfo_initialize());
EXPECT_NE(0, cpuinfo_get_clusters_count());
EXPECT_TRUE(cpuinfo_get_clusters());

cpuinfo_deinitialize();

EXPECT_EQ(0, cpuinfo_get_clusters_count());
EXPECT_FALSE(cpuinfo_get_clusters());
}

TEST(DEINITIALIZE, clears_packages) {
ASSERT_TRUE(cpuinfo_initialize());
EXPECT_NE(0, cpuinfo_get_packages_count());
EXPECT_TRUE(cpuinfo_get_packages());

cpuinfo_deinitialize();

EXPECT_EQ(0, cpuinfo_get_packages_count());
EXPECT_FALSE(cpuinfo_get_packages());
}

TEST(DEINITIALIZE, clears_caches) {
ASSERT_TRUE(cpuinfo_initialize());

cpuinfo_deinitialize();

EXPECT_EQ(0, cpuinfo_get_l1i_caches_count());
EXPECT_EQ(0, cpuinfo_get_l1d_caches_count());
EXPECT_EQ(0, cpuinfo_get_l2_caches_count());
EXPECT_EQ(0, cpuinfo_get_l3_caches_count());
EXPECT_EQ(0, cpuinfo_get_l4_caches_count());
EXPECT_FALSE(cpuinfo_get_l1i_caches());
EXPECT_FALSE(cpuinfo_get_l1d_caches());
EXPECT_FALSE(cpuinfo_get_l2_caches());
EXPECT_FALSE(cpuinfo_get_l3_caches());
EXPECT_FALSE(cpuinfo_get_l4_caches());
}

TEST(DEINITIALIZE, clears_uarchs) {
ASSERT_TRUE(cpuinfo_initialize());
EXPECT_NE(0, cpuinfo_get_uarchs_count());
EXPECT_TRUE(cpuinfo_get_uarchs());

cpuinfo_deinitialize();

EXPECT_EQ(0, cpuinfo_get_uarchs_count());
EXPECT_FALSE(cpuinfo_get_uarchs());
}

TEST(DEINITIALIZE, double_deinit_is_safe) {
ASSERT_TRUE(cpuinfo_initialize());
cpuinfo_deinitialize();
cpuinfo_deinitialize();
EXPECT_EQ(0, cpuinfo_get_processors_count());
}

TEST(DEINITIALIZE, before_init_is_safe) {
cpuinfo_deinitialize();
EXPECT_EQ(0, cpuinfo_get_processors_count());
}
Loading