atomic log level read

This commit is contained in:
tezc 2021-02-09 19:12:15 +03:00
parent 8eff74a4f4
commit 4ac9d8691b
3 changed files with 40 additions and 8 deletions

View File

@ -1,6 +1,6 @@
### Overview ### Overview
Common data structures utilities for C. Common data structures and utilities for C.
Each folder is independent and contains a header and a source file. Each folder is independent and contains a header and a source file.
There is no build for libraries, just copy *.h *.c files into your project. There is no build for libraries, just copy *.h *.c files into your project.
@ -37,6 +37,8 @@ CI runs on Linux, MacOS, FreeBSD and Windows with gcc, clang and msvc.
| **[uri](uri)** | A basic uri parser | | **[uri](uri)** | A basic uri parser |
### Test ### Test
[![codecov](https://codecov.io/gh/tezc/sc/branch/master/graph/badge.svg?token=O8ZHQ0XZ30)](https://codecov.io/gh/tezc/sc)
Although I use on Linux mostly, CI runs with Although I use on Linux mostly, CI runs with
@ -61,7 +63,7 @@ cmake .. -DSANITIZER=address && make && make check
mkdir build; cd build; mkdir build; cd build;
cmake .. -DSANITIZER=undefined && make && make check cmake .. -DSANITIZER=undefined && make && make check
#coverage #coverage, requires GCC.
mkdir build; cd build; mkdir build; cd build;
cmake .. -DCMAKE_BUILD_TYPE=Coverage; make; make coverage cmake .. -DCMAKE_BUILD_TYPE=Coverage; make; make coverage

View File

@ -5,7 +5,7 @@
- Log destination can be stdout, file and user callback. - Log destination can be stdout, file and user callback.
- You can pass logs to all destinations at the same time. - You can pass logs to all destinations at the same time.
- Log files are rotated. - Log files are rotated.
- Thread-safe. - Thread-safe, requires pthread.
### Usage ### Usage

View File

@ -43,8 +43,22 @@
#endif #endif
#endif #endif
thread_local char sc_name[32] = "Thread"; #if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_ATOMIC__
#define SC_ATOMIC
#include <stdatomic.h>
#define sc_atomic _Atomic
#define sc_atomic_store(var, val) \
(atomic_store_explicit(var, val, memory_order_relaxed))
#define sc_atomic_load(var) \
(atomic_load_explicit(var, memory_order_relaxed))
#else
#define sc_atomic
#define sc_atomic_store(var, val) ((*(var)) = (val))
#define sc_atomic_load(var) (*(var))
#endif
thread_local char sc_name[32] = "Thread";
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
@ -135,7 +149,7 @@ struct sc_log
size_t file_size; size_t file_size;
struct sc_log_mutex mtx; struct sc_log_mutex mtx;
enum sc_log_level level; sc_atomic enum sc_log_level level;
bool to_stdout; bool to_stdout;
@ -151,7 +165,7 @@ int sc_log_init(void)
sc_log = (struct sc_log){0}; sc_log = (struct sc_log){0};
sc_log.level = SC_LOG_INFO; sc_atomic_store(&sc_log.level, SC_LOG_INFO);
sc_log.to_stdout = true; sc_log.to_stdout = true;
rc = sc_log_mutex_init(&sc_log.mtx); rc = sc_log_mutex_init(&sc_log.mtx);
@ -200,14 +214,17 @@ static int sc_strcasecmp(const char *a, const char *b)
int sc_log_set_level(const char *str) int sc_log_set_level(const char *str)
{ {
size_t count = sizeof(sc_log_levels) / sizeof(struct sc_log_level_pair); size_t count = sizeof(sc_log_levels) / sizeof(sc_log_levels[0]);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
if (sc_strcasecmp(str, sc_log_levels[i].str) == 0) { if (sc_strcasecmp(str, sc_log_levels[i].str) == 0) {
#ifdef SC_ATOMIC
sc_atomic_store(&sc_log.level, sc_log_levels[i].id);
#else
sc_log_mutex_lock(&sc_log.mtx); sc_log_mutex_lock(&sc_log.mtx);
sc_log.level = sc_log_levels[i].id; sc_log.level = sc_log_levels[i].id;
sc_log_mutex_unlock(&sc_log.mtx); sc_log_mutex_unlock(&sc_log.mtx);
#endif
return 0; return 0;
} }
} }
@ -348,12 +365,25 @@ int sc_log_log(enum sc_log_level level, const char *fmt, ...)
int rc = 0; int rc = 0;
va_list va; va_list va;
// Use relaxed atomics to avoid locking cost, e.g DEBUG logs when
// level=INFO will get away without any synchronization on most platforms.
#ifdef SC_ATOMIC
enum sc_log_level curr;
curr = sc_atomic_load(&sc_log.level);
if (level < curr) {
return 0;
}
#endif
sc_log_mutex_lock(&sc_log.mtx); sc_log_mutex_lock(&sc_log.mtx);
#ifndef SC_ATOMIC
if (level < sc_log.level) { if (level < sc_log.level) {
sc_log_mutex_unlock(&sc_log.mtx); sc_log_mutex_unlock(&sc_log.mtx);
return 0; return 0;
} }
#endif
if (sc_log.to_stdout) { if (sc_log.to_stdout) {
va_start(va, fmt); va_start(va, fmt);