#include #include #include #include #include #include #include #include #include #include "param.h" #include "debug.h" namespace sccl { /** * 获取当前用户的主目录路径 * * @return 返回指向用户主目录路径的指针,如果获取失败则返回NULL */ const char* userHomeDir() { struct passwd* pwUser = getpwuid(getuid()); return pwUser == NULL ? NULL : pwUser->pw_dir; } /** * @brief 从指定文件中读取环境变量并设置到系统环境 * * 该函数读取指定格式的配置文件,每行格式为"VAR=VALUE", * 忽略以#开头的注释行,并将解析出的环境变量设置到当前进程环境。 * * @param fileName 环境变量配置文件路径 */ void setEnvFile(const char* fileName) { FILE* file = fopen(fileName, "r"); if(file == NULL) return; char* line = NULL; char envVar[1024]; char envValue[1024]; size_t n = 0; ssize_t read; while((read = getline(&line, &n, file)) != -1) { if(line[0] == '#') continue; if(line[read - 1] == '\n') line[read - 1] = '\0'; int s = 0; // Env Var Size while(line[s] != '\0' && line[s] != '=') s++; if(line[s] == '\0') continue; strncpy(envVar, line, std::min(1023, s)); envVar[std::min(1023, s)] = '\0'; s++; strncpy(envValue, line + s, 1023); envValue[1023] = '\0'; setenv(envVar, envValue, 0); // printf("%s : %s->%s\n", fileName, envVar, envValue); } if(line) free(line); fclose(file); } /** * 初始化环境配置函数 * * 该函数用于加载SCCL配置文件,按照以下顺序查找: * 1. 首先检查环境变量"SCCL_CONF_FILE"指定的文件 * 2. 其次查找用户主目录下的".sccl.conf"文件 * 3. 最后尝试加载系统默认的"/etc/sccl.conf"文件 * * 每个找到的配置文件都会被通过setEnvFile函数加载 */ static void initEnvFunc() { char confFilePath[1024]; const char* userFile = getenv("SCCL_CONF_FILE"); if(userFile && strlen(userFile) > 0) { snprintf(confFilePath, sizeof(confFilePath), "%s", userFile); setEnvFile(confFilePath); } else { const char* userDir = userHomeDir(); if(userDir) { snprintf(confFilePath, sizeof(confFilePath), "%s/.sccl.conf", userDir); setEnvFile(confFilePath); } } snprintf(confFilePath, sizeof(confFilePath), "/etc/sccl.conf"); setEnvFile(confFilePath); return; } /** * 初始化环境变量(线程安全) * * 使用pthread_once确保initEnvFunc仅被调用一次 * 适用于多线程环境下环境变量的初始化 */ void initEnv() { static pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once(&once, initEnvFunc); return; } /** * @brief 加载环境变量参数并缓存 * * 该函数用于从环境变量中读取整型参数值,并进行缓存以避免重复读取。 * 如果环境变量未设置或解析失败,则使用默认值。 * * @param env 环境变量名 * @param deftVal 默认值 * @param uninitialized 未初始化标记值 * @param cache 用于缓存参数值的指针 * * @note 该函数是线程安全的,使用互斥锁保护缓存操作 */ void scclLoadParam(char const* env, int64_t deftVal, int64_t uninitialized, int64_t* cache) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex); if(__atomic_load_n(cache, __ATOMIC_RELAXED) == uninitialized) { const char* str = scclGetEnv(env); int64_t value = deftVal; if(str && strlen(str) > 0) { errno = 0; value = strtoll(str, nullptr, 0); if(errno) { value = deftVal; INFO(SCCL_LOG_CODEALL, "Invalid value %s for %s, using default %lld.", str, env, (long long)deftVal); } else { INFO(SCCL_LOG_TRANSPORT, "%s set by environment to %lld.", env, (long long)value); } } __atomic_store_n(cache, value, __ATOMIC_RELAXED); } pthread_mutex_unlock(&mutex); return; } /** * 获取环境变量的值 * * @param name 环境变量名称 * @return 环境变量的值,如果未找到则返回NULL * * @note 该函数会先初始化环境变量 */ const char* scclGetEnv(const char* name) { initEnv(); return getenv(name); } #define SCCL_THREAD_NAMELEN 16 SCCL_PARAM(SetThreadName, "SET_THREAD_NAME", 0); /** * @brief 设置指定线程的名称 * * 该函数使用GNU扩展的pthread_setname_np来设置线程名称。名称通过可变参数格式化字符串生成, * 最大长度为SCCL_THREAD_NAMELEN。仅在启用了_GNU_SOURCE宏且scclParamSetThreadName()返回1时生效。 * * @param thread 要设置名称的线程句柄 * @param fmt 格式化字符串,用于生成线程名称 * @param ... 可变参数,用于格式化字符串 */ void scclSetThreadName(pthread_t thread, const char* fmt, ...) { // pthread_setname_np 是 GNU 的非标准扩展 // 需要以下特性测试宏 #ifdef _GNU_SOURCE // 检查是否启用了设置线程名称的功能,如果未启用则直接返回 if(scclParamSetThreadName() != 1) return; // 定义一个足够长的字符数组用于存储线程名 char threadName[SCCL_THREAD_NAMELEN]; // 声明可变参数列表变量 va_list vargs; // 初始化可变参数列表 va_start(vargs, fmt); // 使用可变参数和格式化字符串生成线程名,并写入 threadName 数组 vsnprintf(threadName, SCCL_THREAD_NAMELEN, fmt, vargs); // 结束可变参数列表的使用 va_end(vargs); // 使用 pthread_setname_np 设置线程名称 pthread_setname_np(thread, threadName); #endif } } // namespace sccl