This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
stellar-stellar/infra/utils_internal.h

369 lines
8.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "stellar/utils.h"
#include "toml.h"
#include "log_internal.h"
#define RX_BURST_MAX 32
#define MAX_THREAD_NUM 256 // limit by snowflake
#define SYNC_STAT_INTERVAL_MS 1 // TODO
#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)
/*
* 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);
if (arr == NULL)
{
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