diff --git a/.github/workflows/reusable_proxy_lib.yml b/.github/workflows/reusable_proxy_lib.yml index 3c9067877..fbe4321d4 100644 --- a/.github/workflows/reusable_proxy_lib.yml +++ b/.github/workflows/reusable_proxy_lib.yml @@ -54,6 +54,10 @@ jobs: - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) + - name: Run "ctest --output-on-failure" without proxy library + working-directory: ${{env.BUILD_DIR}} + run: ctest --output-on-failure + - name: Run "ctest --output-on-failure" with proxy library working-directory: ${{env.BUILD_DIR}} run: LD_PRELOAD=./lib/libumf_proxy.so ctest --output-on-failure diff --git a/src/coarse/coarse.c b/src/coarse/coarse.c index a161ea575..6019a1ac7 100644 --- a/src/coarse/coarse.c +++ b/src/coarse/coarse.c @@ -22,13 +22,6 @@ #include "utils_concurrency.h" #include "utils_log.h" -#ifdef _WIN32 -UTIL_ONCE_FLAG Log_initialized = UTIL_ONCE_FLAG_INIT; -#else -void __attribute__((constructor)) coarse_init(void) { utils_log_init(); } -void __attribute__((destructor)) coarse_destroy(void) {} -#endif /* _WIN32 */ - typedef struct coarse_t { // handle of the memory provider void *provider; @@ -883,9 +876,7 @@ static umf_result_t coarse_get_stats_no_lock(coarse_t *coarse, // PUBLIC API umf_result_t coarse_new(coarse_params_t *coarse_params, coarse_t **pcoarse) { -#ifdef _WIN32 - utils_init_once(&Log_initialized, utils_log_init); -#endif /* _WIN32 */ + utils_log_init(); if (coarse_params == NULL || pcoarse == NULL) { LOG_ERR("coarse parameters or handle is missing"); diff --git a/src/proxy_lib/proxy_lib_linux.c b/src/proxy_lib/proxy_lib_linux.c index 50332b49f..c9f44ef27 100644 --- a/src/proxy_lib/proxy_lib_linux.c +++ b/src/proxy_lib/proxy_lib_linux.c @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -9,15 +9,10 @@ #include "proxy_lib.h" -// The priority 102 is used, because the constructor should be called as the second one -// (just after the first constructor of the base allocator with priority 101) -// and the destructor as the last but one (just before the last destructor -// of the base allocator with priority 101), because this library -// provides the memory allocation API. -void __attribute__((constructor(102))) proxy_lib_create(void) { +void __attribute__((constructor)) proxy_lib_create(void) { proxy_lib_create_common(); } -void __attribute__((destructor(102))) proxy_lib_destroy(void) { +void __attribute__((destructor)) proxy_lib_destroy(void) { proxy_lib_destroy_common(); } diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 17dd006ad..df8536cfb 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -14,10 +14,14 @@ #include #include #include +#include +#include #include #include +#include "utils_load_library.h" + #ifdef __cplusplus extern "C" { #endif @@ -79,6 +83,23 @@ static inline int utils_env_var_has_str(const char *envvar, const char *str) { // check if we are running in the proxy library static inline int utils_is_running_in_proxy_lib(void) { + // check if the proxy library is loaded using /proc/self/maps + FILE *fp = fopen("/proc/self/maps", "r"); + if (!fp) { + perror("Failed to open /proc/self/maps"); + return -1; + } + + char line[256]; + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, "libumf_proxy.so") != NULL) { + fclose(fp); + return 1; // Shared object is loaded + } + } + fclose(fp); + + // check if the proxy library is loaded using LD_PRELOAD return utils_env_var_get_str("LD_PRELOAD", "libumf_proxy.so") ? 1 : 0; } diff --git a/src/utils/utils_load_library.c b/src/utils/utils_load_library.c index d774fec84..3de0b3471 100644 --- a/src/utils/utils_load_library.c +++ b/src/utils/utils_load_library.c @@ -71,18 +71,31 @@ void *utils_open_library(const char *filename, int userFlags) { dlopenFlags |= RTLD_GLOBAL; } if (userFlags & UMF_UTIL_OPEN_LIBRARY_NO_LOAD) { - dlopenFlags |= RTLD_NOLOAD; + dlopenFlags = RTLD_NOLOAD | RTLD_NOW; } void *handle = dlopen(filename, dlopenFlags); if (handle == NULL) { + if (userFlags & UMF_UTIL_OPEN_LIBRARY_NO_LOAD) { + // if we are not loading the library, just return NULL if it is not + // found + LOG_DEBUG("Library %s not found, returning NULL", filename); + return NULL; + } + LOG_FATAL("dlopen(%s) failed with error: %s", filename, dlerror()); + return NULL; } + LOG_DEBUG("Opened library %s with handle %p", filename, handle); return handle; } -int utils_close_library(void *handle) { return dlclose(handle); } +int utils_close_library(void *handle) { + LOG_DEBUG("Closing library handle %p", handle); + + return dlclose(handle); +} void *utils_get_symbol_addr(void *handle, const char *symbol, const char *libname) { diff --git a/src/utils/utils_log.c b/src/utils/utils_log.c index 3c57ce033..71669c282 100644 --- a/src/utils/utils_log.c +++ b/src/utils/utils_log.c @@ -32,6 +32,10 @@ #include "utils_common.h" #include "utils_log.h" +#ifndef DISABLE_SINGLE_LOGGER +#include "utils_concurrency.h" +#endif + #define UMF_MAGIC_STR "\x00@(#) " #define UMF_PREF_STR "Intel(R) " #define UMF_PREFIX UMF_MAGIC_STR UMF_PREF_STR @@ -60,6 +64,10 @@ char const __umf_str_1__all_cmake_vars[] = #define MAX_FILE_PATH 256 #define MAX_ENV_LEN 2048 +#ifndef DISABLE_SINGLE_LOGGER +static UTIL_ONCE_FLAG initOnce = UTIL_ONCE_FLAG_INIT; +#endif + typedef struct { bool enableTimestamp; bool enablePid; @@ -247,7 +255,7 @@ void utils_plog(utils_log_level_t level, const char *func, const char *format, static const char *bool_to_str(int b) { return b ? "yes" : "no"; } -void utils_log_init(void) { +static void utils_log_init_once(void) { const char *envVar = getenv("UMF_LOG"); if (!envVar) { @@ -343,6 +351,12 @@ void utils_log_init(void) { } // this is needed for logger unit test +#ifndef DISABLE_SINGLE_LOGGER +void utils_log_init(void) { utils_init_once(&initOnce, utils_log_init_once); } +#else +void utils_log_init(void) { utils_log_init_once(); } +#endif + #ifndef DISABLE_CTL_LOGGER static umf_result_t CTL_READ_HANDLER(timestamp)(void *ctx, umf_ctl_query_source_t source, void *arg, diff --git a/test/utils/utils_log.cpp b/test/utils/utils_log.cpp index 4d1b0554e..3c7992bbc 100644 --- a/test/utils/utils_log.cpp +++ b/test/utils/utils_log.cpp @@ -97,6 +97,7 @@ int mock_strerror_windows(char *buff, size_t s, int errnum) { extern "C" { #define DISABLE_CTL_LOGGER 1 +#define DISABLE_SINGLE_LOGGER 1 const char *env_variable = ""; #define fopen(A, B) mock_fopen(A, B) #define fputs(A, B) mock_fputs(A, B) @@ -161,8 +162,8 @@ TEST_F(test, parseEnv_errors) { helper_checkConfig(&b, &loggerConfig); helper_log_init("_level:debug"); helper_checkConfig(&b, &loggerConfig); - expected_message = - "[ERROR UMF] utils_log_init: Cannot open output file - path too long\n"; + expected_message = "[ERROR UMF] utils_log_init_once: Cannot open output " + "file - path too long\n"; std::string test_env = "output:file," + std::string(300, 'x'); helper_log_init(test_env.c_str()); } @@ -247,7 +248,8 @@ TEST_F(test, parseEnv) { expect_fput_count = 1; if (expected_filename.size() > MAX_FILE_PATH) { expected_message = - "[ERROR UMF] utils_log_init: Cannot open " + "[ERROR UMF] utils_log_init_once: Cannot " + "open " "output file - path too long\n"; } }