Report fatal error and abort if any cpuinfo_get_* function is called before initialization
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a11695f..c94fb74 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,11 @@
# ---[ Options.
SET(CPUINFO_LIBRARY_TYPE "default" CACHE STRING "Type of cpuinfo library (shared, static, or default) to build")
SET_PROPERTY(CACHE CPUINFO_LIBRARY_TYPE PROPERTY STRINGS default static shared)
+IF(ANDROID)
+ OPTION(CPUINFO_LOG_TO_STDIO "Log errors, warnings, and information to stdout/stderr" OFF)
+ELSE()
+ OPTION(CPUINFO_LOG_TO_STDIO "Log errors, warnings, and information to stdout/stderr" ON)
+ENDIF()
OPTION(CPUINFO_BUILD_TOOLS "Build command-line tools" ON)
OPTION(CPUINFO_BUILD_UNIT_TESTS "Build cpuinfo unit tests" ON)
OPTION(CPUINFO_BUILD_MOCK_TESTS "Build cpuinfo mock tests" ON)
@@ -199,6 +204,11 @@
SET_TARGET_PROPERTIES(cpuinfo PROPERTIES PUBLIC_HEADER include/cpuinfo.h)
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PUBLIC include)
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PRIVATE src)
+IF(CPUINFO_LOG_TO_STDIO)
+ TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_TO_STDIO=1)
+ELSE()
+ TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_TO_STDIO=0)
+ENDIF()
IF(CPUINFO_SUPPORTED_PLATFORM)
TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=1)
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
@@ -207,6 +217,9 @@
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _GNU_SOURCE=1)
ENDIF()
+ IF(CMAKE_SYSTEM_NAME STREQUAL "Android")
+ TARGET_LINK_LIBRARIES(cpuinfo PRIVATE log)
+ ENDIF()
IF(IOS)
TARGET_LINK_LIBRARIES(cpuinfo INTERFACE "-framework OpenGLES")
TARGET_LINK_LIBRARIES(cpuinfo INTERFACE "-framework Foundation")
@@ -271,6 +284,7 @@
TARGET_INCLUDE_DIRECTORIES(cpuinfo_mock BEFORE PUBLIC include)
TARGET_INCLUDE_DIRECTORIES(cpuinfo_mock BEFORE PRIVATE src)
TARGET_COMPILE_DEFINITIONS(cpuinfo_mock PUBLIC CPUINFO_MOCK=1)
+ TARGET_COMPILE_DEFINITIONS(cpuinfo_mock PRIVATE CPUINFO_LOG_TO_STDIO=1)
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
TARGET_LINK_LIBRARIES(cpuinfo_mock PUBLIC ${CMAKE_THREAD_LIBS_INIT})
ENDIF()
diff --git a/configure.py b/configure.py
index f0b2072..4a20bd1 100755
--- a/configure.py
+++ b/configure.py
@@ -14,7 +14,8 @@
macros = {
"CPUINFO_LOG_LEVEL": {"none": 0, "error": 1, "warning": 2, "info": 3, "debug": 4}[options.log_level],
- "CPUINFO_MOCK": int(options.mock)
+ "CPUINFO_LOG_TO_STDIO": int(not options.mock),
+ "CPUINFO_MOCK": int(options.mock),
}
build.export_cpath("include", ["cpuinfo.h"])
diff --git a/src/api.c b/src/api.c
index 1ffdb8c..0504a63 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2,8 +2,11 @@
#include <cpuinfo.h>
#include <api.h>
+#include <log.h>
+bool cpuinfo_is_initialized = false;
+
struct cpuinfo_processor* cpuinfo_processors = NULL;
struct cpuinfo_core* cpuinfo_cores = NULL;
struct cpuinfo_cluster* cpuinfo_clusters = NULL;
@@ -18,22 +21,37 @@
const struct cpuinfo_processor* cpuinfo_get_processors(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processors");
+ }
return cpuinfo_processors;
}
const struct cpuinfo_core* cpuinfo_get_cores(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "core");
+ }
return cpuinfo_cores;
}
const struct cpuinfo_cluster* cpuinfo_get_clusters(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "clusters");
+ }
return cpuinfo_clusters;
}
const struct cpuinfo_package* cpuinfo_get_packages(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "packages");
+ }
return cpuinfo_packages;
}
const struct cpuinfo_processor* cpuinfo_get_processor(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processor");
+ }
if (index < cpuinfo_processors_count) {
return cpuinfo_processors + index;
} else {
@@ -42,6 +60,9 @@
}
const struct cpuinfo_core* cpuinfo_get_core(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "core");
+ }
if (index < cpuinfo_cores_count) {
return cpuinfo_cores + index;
} else {
@@ -50,6 +71,9 @@
}
const struct cpuinfo_cluster* cpuinfo_get_cluster(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "cluster");
+ }
if (index < cpuinfo_clusters_count) {
return cpuinfo_clusters + index;
} else {
@@ -58,6 +82,9 @@
}
const struct cpuinfo_package* cpuinfo_get_package(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "package");
+ }
if (index < cpuinfo_packages_count) {
return cpuinfo_packages + index;
} else {
@@ -66,42 +93,72 @@
}
uint32_t cpuinfo_get_processors_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processors_count");
+ }
return cpuinfo_processors_count;
}
uint32_t cpuinfo_get_cores_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "cores_count");
+ }
return cpuinfo_cores_count;
}
uint32_t cpuinfo_get_clusters_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "clusters_count");
+ }
return cpuinfo_clusters_count;
}
uint32_t cpuinfo_get_packages_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "packages_count");
+ }
return cpuinfo_packages_count;
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1i_caches(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_caches");
+ }
return cpuinfo_cache[cpuinfo_cache_level_1i];
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1d_caches(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_caches");
+ }
return cpuinfo_cache[cpuinfo_cache_level_1d];
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l2_caches(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_caches");
+ }
return cpuinfo_cache[cpuinfo_cache_level_2];
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l3_caches(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_caches");
+ }
return cpuinfo_cache[cpuinfo_cache_level_3];
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_caches(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_caches");
+ }
return cpuinfo_cache[cpuinfo_cache_level_4];
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1i_cache(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_cache");
+ }
if (index < cpuinfo_cache_count[cpuinfo_cache_level_1i]) {
return cpuinfo_cache[cpuinfo_cache_level_1i] + index;
} else {
@@ -110,6 +167,9 @@
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1d_cache(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_cache");
+ }
if (index < cpuinfo_cache_count[cpuinfo_cache_level_1d]) {
return cpuinfo_cache[cpuinfo_cache_level_1d] + index;
} else {
@@ -118,6 +178,9 @@
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l2_cache(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_cache");
+ }
if (index < cpuinfo_cache_count[cpuinfo_cache_level_2]) {
return cpuinfo_cache[cpuinfo_cache_level_2] + index;
} else {
@@ -126,6 +189,9 @@
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l3_cache(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_cache");
+ }
if (index < cpuinfo_cache_count[cpuinfo_cache_level_3]) {
return cpuinfo_cache[cpuinfo_cache_level_3] + index;
} else {
@@ -134,6 +200,9 @@
}
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_cache(uint32_t index) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_cache");
+ }
if (index < cpuinfo_cache_count[cpuinfo_cache_level_4]) {
return cpuinfo_cache[cpuinfo_cache_level_4] + index;
} else {
@@ -142,21 +211,36 @@
}
uint32_t CPUINFO_ABI cpuinfo_get_l1i_caches_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_caches_count");
+ }
return cpuinfo_cache_count[cpuinfo_cache_level_1i];
}
uint32_t CPUINFO_ABI cpuinfo_get_l1d_caches_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_caches_count");
+ }
return cpuinfo_cache_count[cpuinfo_cache_level_1d];
}
uint32_t CPUINFO_ABI cpuinfo_get_l2_caches_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_caches_count");
+ }
return cpuinfo_cache_count[cpuinfo_cache_level_2];
}
uint32_t CPUINFO_ABI cpuinfo_get_l3_caches_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_caches_count");
+ }
return cpuinfo_cache_count[cpuinfo_cache_level_3];
}
uint32_t CPUINFO_ABI cpuinfo_get_l4_caches_count(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_caches_count");
+ }
return cpuinfo_cache_count[cpuinfo_cache_level_4];
}
diff --git a/src/api.h b/src/api.h
index 9ba406f..14463e0 100644
--- a/src/api.h
+++ b/src/api.h
@@ -18,6 +18,7 @@
cpuinfo_cache_level_max = 5,
};
+extern bool cpuinfo_is_initialized;
extern struct cpuinfo_processor* cpuinfo_processors;
extern struct cpuinfo_core* cpuinfo_cores;
extern struct cpuinfo_cluster* cpuinfo_clusters;
diff --git a/src/arm/linux/init.c b/src/arm/linux/init.c
index 197b48f..dd54668 100644
--- a/src/arm/linux/init.c
+++ b/src/arm/linux/init.c
@@ -557,6 +557,10 @@
cpuinfo_cache_count[cpuinfo_cache_level_1d] = usable_processors;
cpuinfo_cache_count[cpuinfo_cache_level_2] = l2_count;
+ __sync_synchronize();
+
+ cpuinfo_is_initialized = true;
+
linux_cpu_to_processor_map = NULL;
linux_cpu_to_core_map = NULL;
processors = NULL;
diff --git a/src/arm/mach/init.c b/src/arm/mach/init.c
index 2d8feeb..d8e0ab6 100644
--- a/src/arm/mach/init.c
+++ b/src/arm/mach/init.c
@@ -483,6 +483,10 @@
cpuinfo_cores_count = mach_topology.cores;
cpuinfo_packages_count = mach_topology.packages;
+ __sync_synchronize();
+
+ cpuinfo_is_initialized = true;
+
processors = NULL;
cores = NULL;
packages = NULL;
diff --git a/src/init.c b/src/init.c
index 45cffdc..2a30fcf 100644
--- a/src/init.c
+++ b/src/init.c
@@ -41,7 +41,7 @@
#else
cpuinfo_log_error("processor architecture is not supported in cpuinfo");
#endif
- return (cpuinfo_processors != NULL) && (cpuinfo_cores != NULL) && (cpuinfo_packages != NULL);
+ return cpuinfo_is_initialized;
}
void CPUINFO_ABI cpuinfo_deinitialize(void) {
diff --git a/src/linux/current.c b/src/linux/current.c
index d4a7f69..9d48b92 100644
--- a/src/linux/current.c
+++ b/src/linux/current.c
@@ -9,14 +9,18 @@
#include <cpuinfo.h>
#include <api.h>
+#include <log.h>
#include <linux/api.h>
-const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map;
-const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map;
+const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map = NULL;
+const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map = NULL;
const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_current_processor(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_processor");
+ }
const int cpu = sched_getcpu();
if (cpu >= 0) {
return cpuinfo_linux_cpu_to_processor_map[cpu];
@@ -26,6 +30,9 @@
}
const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_current_core(void) {
+ if (!cpuinfo_is_initialized) {
+ cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_core");
+ }
const int cpu = sched_getcpu();
if (cpu >= 0) {
return cpuinfo_linux_cpu_to_core_map[cpu];
diff --git a/src/log.c b/src/log.c
index 65fac8c..396d58c 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,17 +1,53 @@
#include <stdarg.h>
+#include <stdlib.h>
#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#endif
+#ifdef __ANDROID__
+ #include <android/log.h>
+ #define CPUINFO_LOG_TAG "cpuinfo"
+#endif
#include <log.h>
+#ifndef CPUINFO_LOG_TO_STDIO
+ #ifdef __ANDROID__
+ #define CPUINFO_LOG_TO_STDIO 0
+ #else
+ #define CPUINFO_LOG_TO_STDIO 1
+ #endif
+#endif
+
+void cpuinfo_log_fatal(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ #if defined(__ANDROID__) && !CPUINFO_LOG_TO_STDIO
+ __android_log_vprint(ANDROID_LOG_FATAL, CPUINFO_LOG_TAG, format, args);
+ #elif defined(__ANDROID__) || defined(_WIN32)
+ fprintf(stderr, "Fatal error: ");
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ #else
+ dprintf(STDERR_FILENO, "Error: ");
+ vdprintf(STDERR_FILENO, format, args);
+ dprintf(STDERR_FILENO, "\n");
+ #endif
+
+ va_end(args);
+ abort();
+}
+
#if CPUINFO_LOG_LEVEL >= CPUINFO_LOG_ERROR
void cpuinfo_log_error(const char* format, ...) {
va_list args;
va_start(args, format);
- #if defined(__ANDROID__) || defined(_WIN32)
+ #if defined(__ANDROID__) && !CPUINFO_LOG_TO_STDIO
+ __android_log_vprint(ANDROID_LOG_ERROR, CPUINFO_LOG_TAG, format, args);
+ #elif defined(__ANDROID__) || defined(_WIN32)
fprintf(stderr, "Error: ");
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
@@ -31,7 +67,9 @@
va_list args;
va_start(args, format);
- #if defined(__ANDROID__) || defined(_WIN32)
+ #if defined(__ANDROID__) && !CPUINFO_LOG_TO_STDIO
+ __android_log_vprint(ANDROID_LOG_WARN, CPUINFO_LOG_TAG, format, args);
+ #elif defined(__ANDROID__) || defined(_WIN32)
fprintf(stderr, "Warning: ");
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
@@ -51,7 +89,9 @@
va_list args;
va_start(args, format);
- #if defined(__ANDROID__) || defined(_WIN32)
+ #if defined(__ANDROID__) && !CPUINFO_LOG_TO_STDIO
+ __android_log_vprint(ANDROID_LOG_INFO, CPUINFO_LOG_TAG, format, args);
+ #elif defined(__ANDROID__) || defined(_WIN32)
printf("Note: ");
vprintf(format, args);
printf("\n");
@@ -70,7 +110,9 @@
va_list args;
va_start(args, format);
- #if defined(__ANDROID__) || defined(_WIN32)
+ #if defined(__ANDROID__) && !CPUINFO_LOG_TO_STDIO
+ __android_log_vprint(ANDROID_LOG_DEBUG, CPUINFO_LOG_TAG, format, args);
+ #elif defined(__ANDROID__) || defined(_WIN32)
printf("Debug: ");
vprintf(format, args);
printf("\n");
diff --git a/src/log.h b/src/log.h
index ccfbd03..69e4b8f 100644
--- a/src/log.h
+++ b/src/log.h
@@ -48,3 +48,10 @@
#else
static inline void cpuinfo_log_error(const char* format, ...) { }
#endif
+
+#if defined(__GNUC__)
+__attribute__((__format__(__printf__, 1, 2), __noreturn__))
+#elif defined(_MSC_VER)
+__declspec(noreturn)
+#endif
+void cpuinfo_log_fatal(const char* format, ...);
diff --git a/src/x86/linux/init.c b/src/x86/linux/init.c
index 400fb9c..fadd99c 100644
--- a/src/x86/linux/init.c
+++ b/src/x86/linux/init.c
@@ -534,6 +534,10 @@
cpuinfo_cache_count[cpuinfo_cache_level_3] = l3_count;
cpuinfo_cache_count[cpuinfo_cache_level_4] = l4_count;
+ __sync_synchronize();
+
+ cpuinfo_is_initialized = true;
+
linux_cpu_to_processor_map = NULL;
linux_cpu_to_core_map = NULL;
processors = NULL;
diff --git a/src/x86/mach/init.c b/src/x86/mach/init.c
index dc04663..a5371a5 100644
--- a/src/x86/mach/init.c
+++ b/src/x86/mach/init.c
@@ -327,6 +327,10 @@
cpuinfo_clusters_count = mach_topology.packages;
cpuinfo_packages_count = mach_topology.packages;
+ __sync_synchronize();
+
+ cpuinfo_is_initialized = true;
+
processors = NULL;
cores = NULL;
clusters = NULL;
diff --git a/src/x86/windows/init.c b/src/x86/windows/init.c
index 8866eee..d65aa6c 100644
--- a/src/x86/windows/init.c
+++ b/src/x86/windows/init.c
@@ -571,6 +571,10 @@
cpuinfo_clusters_count = packages_count;
cpuinfo_packages_count = packages_count;
+ MemoryBarrier();
+
+ cpuinfo_is_initialized = true;
+
processors = NULL;
cores = NULL;
clusters = NULL;