#pragma once #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include "toml.h" #include "log_internal.h" #define RX_BURST_MAX 32 #define MAX_THREAD_NUM 256 // limit by snowflake #define ATOMIC_INC(x) __atomic_fetch_add(x, 1, __ATOMIC_RELAXED) #define ATOMIC_DEC(x) __atomic_fetch_sub(x, 1, __ATOMIC_RELAXED) #define ATOMIC_READ(x) __atomic_load_n(x, __ATOMIC_RELAXED) #define ATOMIC_ZERO(x) __atomic_fetch_and(x, 0, __ATOMIC_RELAXED) #define ATOMIC_ADD(x, y) __atomic_fetch_add(x, y, __ATOMIC_RELAXED) #define ATOMIC_SET(x, y) __atomic_store_n(x, y, __ATOMIC_RELAXED) #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define likely(expr) __builtin_expect((expr), 1) #define unlikely(expr) __builtin_expect((expr), 0) /* * The maximum number of seconds that can be stored in the time_t value is 2147483647 –- a little over 68 years. * * struct timespec * { * time_t tv_sec; // seconds * long tv_nsec; // nanoseconds * }; * * 1 s = 1000 ms * 1 ms = 1000 us * 1 us = 1000 ns */ #define TIMESPEC_TO_MSEC(ts) ((ts).tv_sec * 1000 + (ts).tv_nsec / 1000000) static inline uint64_t clock_get_real_time_ms() { struct timespec now; clock_gettime(CLOCK_REALTIME_COARSE, &now); return TIMESPEC_TO_MSEC(now); } static inline void hexdump_to_fd(int fd, uint32_t idx, const char *data, uint16_t len) { uint16_t i = 0; uint16_t used = 0; uint16_t offset = 0; #define LINE_LEN 80 char line[LINE_LEN]; /* space needed 8+16*3+3+16 == 75 */ while (offset < len) { used = snprintf(line, LINE_LEN, "%08X ", idx + offset); // hexdump for (i = 0; ((offset + i) < len) && (i < 16); i++) { if (i == 8) { used += snprintf(line + used, LINE_LEN - used, " "); } used += snprintf(line + used, LINE_LEN - used, " %02x", (data[offset + i] & 0xff)); } // padding for (; i <= 16; i++) { if (i == 8) { used += snprintf(line + used, LINE_LEN - used, " "); } used += snprintf(line + used, LINE_LEN - used, " "); } // ascii for (i = 0; (offset < len) && (i < 16); i++, offset++) { unsigned char c = data[offset]; if ((c < ' ') || (c > '~')) { c = '.'; } if (i == 8) { used += snprintf(line + used, LINE_LEN - used, " "); } used += snprintf(line + used, LINE_LEN - used, "%c", c); } dprintf(fd, "%s\n", line); } } // key: "a.b.c" static inline const char *get_toml_raw_by_hierarchical_key(toml_table_t *root, const char *key) { toml_table_t *table = root; char *saveptr; char *dup_key = strdup(key); char *token = strtok_r(dup_key, ".", &saveptr); while (token != NULL) { table = toml_table_in(table, token); if (table == NULL) { free(dup_key); return NULL; } if (strchr(saveptr, '.') == NULL) { const char *val = toml_raw_in(table, saveptr); free(dup_key); return val; } token = strtok_r(NULL, ".", &saveptr); } free(dup_key); return toml_raw_in(root, key); } static inline toml_array_t *get_toml_array_by_hierarchical_key(toml_table_t *root, const char *key) { toml_table_t *table = root; char *saveptr; char *dup_key = strdup(key); char *token = strtok_r(dup_key, ".", &saveptr); while (token != NULL) { table = toml_table_in(table, token); if (table == NULL) { free(dup_key); return NULL; } if (strchr(saveptr, '.') == NULL) { toml_array_t *arr = toml_array_in(table, saveptr); free(dup_key); return arr; } token = strtok_r(NULL, ".", &saveptr); } free(dup_key); return toml_array_in(root, key); } static inline int load_toml_integer_config(const char *toml_file, const char *key, uint64_t *val, uint64_t min, uint64_t max) { int ret = -1; char errbuf[200]; const char *ptr = NULL; FILE *fp = NULL; toml_table_t *root = NULL; fp = fopen(toml_file, "r"); if (fp == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno)); return -1; } root = toml_parse_file(fp, errbuf, sizeof(errbuf)); if (root == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf); goto error_out; } ptr = get_toml_raw_by_hierarchical_key(root, key); if (ptr == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key); goto error_out; } *val = atoll(ptr); if ((*val) < min || (*val) > max) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "invalid %s: %lu, supported range: [%lu, %lu]", key, *val, min, max); goto error_out; } ret = 0; error_out: if (root != NULL) { toml_free(root); } if (fp) { fclose(fp); } return ret; } static inline int load_toml_double_config(const char *toml_file, const char *key, double *val, double min, double max) { int ret = -1; char errbuf[200]; const char *ptr = NULL; FILE *fp = NULL; toml_table_t *root = NULL; fp = fopen(toml_file, "r"); if (fp == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno)); return -1; } root = toml_parse_file(fp, errbuf, sizeof(errbuf)); if (root == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf); goto error_out; } ptr = get_toml_raw_by_hierarchical_key(root, key); if (ptr == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key); goto error_out; } *val = atof(ptr); if ((*val) < min || (*val) > max) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "invalid %s: %f, supported range: [%f, %f]", key, *val, min, max); goto error_out; } ret = 0; error_out: if (root != NULL) { toml_free(root); } if (fp) { fclose(fp); } return ret; } static inline int load_toml_str_config(const char *toml_file, const char *key, char *val) { int ret = -1; char errbuf[200]; const char *ptr = NULL; FILE *fp = NULL; toml_table_t *root = NULL; fp = fopen(toml_file, "r"); if (fp == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno)); return -1; } root = toml_parse_file(fp, errbuf, sizeof(errbuf)); if (root == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf); goto error_out; } ptr = get_toml_raw_by_hierarchical_key(root, key); if (ptr == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key); goto error_out; } memcpy(val, ptr + 1, strlen(ptr) - 2); ret = 0; error_out: if (root != NULL) { toml_free(root); } if (fp) { fclose(fp); } return ret; } static inline int load_toml_array_config(const char *toml_file, const char *key, uint64_t val[], uint64_t size) { int ret = 0; char errbuf[200]; const char *ptr = NULL; toml_array_t *arr = NULL; FILE *fp = NULL; toml_table_t *root = NULL; uint64_t loop = 0; fp = fopen(toml_file, "r"); if (fp == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s open failed, %s", toml_file, strerror(errno)); return -1; } root = toml_parse_file(fp, errbuf, sizeof(errbuf)); if (root == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file %s parse failed, %s", toml_file, errbuf); goto error_out; } arr = get_toml_array_by_hierarchical_key(root, key); { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s", key); goto error_out; } loop = MIN((uint64_t)toml_array_nelem(arr), size); for (uint64_t i = 0; i < loop; i++) { ptr = toml_raw_at(arr, i); if (ptr == NULL) { STELLAR_LOG_ERROR(__thread_local_logger, "config", "config file missing %s[%d]", key, i); goto error_out; } val[i] = atoll(ptr); } ret = loop; error_out: if (root != NULL) { toml_free(root); } if (fp) { fclose(fp); } return ret; } #ifdef __cplusplus } #endif