diff options
author | Marat Dukhan <marat@fb.com> | 2018-03-24 23:21:02 -0700 |
---|---|---|
committer | Marat Dukhan <marat@fb.com> | 2018-03-24 23:21:02 -0700 |
commit | cf70aeeb83cbc1c582aca39793056904abcb1e57 (patch) | |
tree | 860516fa04782fd05a89747ce78c42163c093b49 | |
parent | 806dcca7bdd4759db446a26b2080e6cbf3307edd (diff) | |
download | cpuinfo-cf70aeeb83cbc1c582aca39793056904abcb1e57.tar.gz |
Report fatal error and abort if any cpuinfo_get_* function is called before initialization
-rw-r--r-- | CMakeLists.txt | 14 | ||||
-rwxr-xr-x | configure.py | 3 | ||||
-rw-r--r-- | src/api.c | 84 | ||||
-rw-r--r-- | src/api.h | 1 | ||||
-rw-r--r-- | src/arm/linux/init.c | 4 | ||||
-rw-r--r-- | src/arm/mach/init.c | 4 | ||||
-rw-r--r-- | src/init.c | 2 | ||||
-rw-r--r-- | src/linux/current.c | 11 | ||||
-rw-r--r-- | src/log.c | 50 | ||||
-rw-r--r-- | src/log.h | 7 | ||||
-rw-r--r-- | src/x86/linux/init.c | 4 | ||||
-rw-r--r-- | src/x86/mach/init.c | 4 | ||||
-rw-r--r-- | src/x86/windows/init.c | 4 |
13 files changed, 184 insertions, 8 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index a11695f..c94fb74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,11 @@ PROJECT(cpuinfo C CXX) # ---[ 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 @@ CPUINFO_TARGET_ENABLE_C99(cpuinfo) 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(CPUINFO_SUPPORTED_PLATFORM) 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 @@ IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_MOCK_TESTS) 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 @@ def main(args): 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"]) @@ -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 @@ uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max] = { 0 }; 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_processor* cpuinfo_get_processor(uint32_t index) { } 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_core* cpuinfo_get_core(uint32_t index) { } 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_cluster* cpuinfo_get_cluster(uint32_t index) { } 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 @@ const struct cpuinfo_package* cpuinfo_get_package(uint32_t index) { } 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_l1i_cache(uint32_t index) { } 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_l1d_cache(uint32_t index) { } 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_l2_cache(uint32_t index) { } 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_l3_cache(uint32_t index) { } 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 @@ const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_cache(uint32_t index) { } 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]; } @@ -18,6 +18,7 @@ enum cpuinfo_cache_level { 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 @@ void cpuinfo_arm_linux_init(void) { 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 @@ void cpuinfo_arm_mach_init(void) { cpuinfo_cores_count = mach_topology.cores; cpuinfo_packages_count = mach_topology.packages; + __sync_synchronize(); + + cpuinfo_is_initialized = true; + processors = NULL; cores = NULL; packages = NULL; @@ -41,7 +41,7 @@ bool CPUINFO_ABI cpuinfo_initialize(void) { #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_processor* CPUINFO_ABI cpuinfo_get_current_processor(void) } 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]; @@ -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"); @@ -48,3 +48,10 @@ __attribute__((__format__(__printf__, 1, 2))) #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 @@ void cpuinfo_x86_linux_init(void) { 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 @@ void cpuinfo_x86_mach_init(void) { 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 @@ BOOL CALLBACK cpuinfo_x86_windows_init(PINIT_ONCE init_once, PVOID parameter, PV cpuinfo_clusters_count = packages_count; cpuinfo_packages_count = packages_count; + MemoryBarrier(); + + cpuinfo_is_initialized = true; + processors = NULL; cores = NULL; clusters = NULL; |