From 0a8bbe0ac3a45f2ff3975d4de07332b25649ba9f Mon Sep 17 00:00:00 2001 From: steven-na Date: Thu, 13 Aug 2026 14:01:01 -0700 Subject: Simple logging, started on threadpool --- src/deque.h | 2 +- src/log.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/log.h | 35 ++++++++++++++++++++++ src/threadpool.c | 10 +++++++ src/threadpool.h | 32 +++++++++++++++++++++ src/unity.c | 1 + 6 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 src/log.c create mode 100644 src/log.h create mode 100644 src/threadpool.c create mode 100644 src/threadpool.h (limited to 'src') diff --git a/src/deque.h b/src/deque.h index 0f7d13a..e254bfb 100644 --- a/src/deque.h +++ b/src/deque.h @@ -26,7 +26,7 @@ ez_deque_t *ez_deque_create(smrt_arena_t *arena, u64 elem_size, u64 size); // Returns deque backed memory. Copy if needed. void * ez_deque_pop(ez_deque_t *q); -// Thread-safe deque (SPMC) +// Thread-safe deque (MPMC) // Does not own queue typedef struct { ez_deque_t * queue; diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..2d7eaa2 --- /dev/null +++ b/src/log.c @@ -0,0 +1,88 @@ +#include "log.h" + +#include +#include +#include + +static struct { + log_LockProc lock_proc; + LogLevelE lvl; + b32 quiet; + FILE *log_file; +} L; + +static const char *level_strings[] = { + "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" +}; + +#ifndef LOG_NO_COLOR +static const char *level_colors[] = { + "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" +}; +#endif + +const char *log_get_level() { + return level_strings[L.lvl]; +} + +void log_set_level(LogLevelE lvl) { + L.lvl = lvl; +} + +void log_set_quiet(b32 quiet) { + L.quiet = quiet; +} + +void log_set_lock(log_LockProc proc) { + L.lock_proc = proc; +} + +void log_set_fp(FILE *log_file) { + L.log_file = log_file; +} + +static inline void lock() { if (L.lock_proc) L.lock_proc( true); } +static inline void unlock() { if (L.lock_proc) L.lock_proc(false); } + +static inline void write_to_file(LogLevelE lvl, const char *src_file, u64 src_line, const char *fmt, struct tm* time, va_list va) { + if (!L.log_file) { return; } + char time_str[64]; + time_str[strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", time)] = '\0'; + + fprintf(L.log_file, "%s %-5s%s:%lu ", time_str, level_strings[lvl], src_file, src_line); + vfprintf(L.log_file, fmt, va); + fprintf(L.log_file, "\n"); +} + +void log_log(LogLevelE lvl, const char *src_file, u64 src_line, const char *fmt, ...) { + lock(); + + va_list va; + va_list fva; + va_start(va, fmt); + va_copy(fva, va); + va_end(va); + + time_t t = time(NULL); + struct tm* time = localtime(&t); + + if (L.quiet || lvl < L.lvl) { goto skip; } + + char time_str[16]; + time_str[strftime(time_str, sizeof(time_str), "%H:%M:%S", time)] = '\0'; + +#ifndef LOG_NO_COLOR + fprintf(stdout, "%s %s%-5s\x1b[0m\x1b[90m%s:%lu:\x1b[0m ", + time_str, level_colors[lvl], level_strings[lvl], src_file, src_line); +#else + fprintf(stdout, "%s %-5s %s:%lu: ", + time_str, level_strings[L.lvl], src_file, src_line); +#endif /* ifndef LOG_NO_COLOR */ + + vfprintf(stdout, fmt, va); + fprintf(stdout, "\n"); + +skip: + write_to_file(lvl, src_file, src_line, fmt, time, fva); + unlock(); +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..eedb182 --- /dev/null +++ b/src/log.h @@ -0,0 +1,35 @@ +// Based on: https://github.com/rxi/log.c/ + +#pragma once + +#include "common.h" + +#include +#include + +typedef void (*log_LockProc)(b32 should_lock); + +typedef enum { + LogLevelTrace = 0, + LogLevelDebug = 1, + LogLevelInfo = 2, + LogLevelWarn = 3, + LogLevelError = 4, + LogLevelFatal = 5, +} LogLevelE; + +#define log_trace(...) log_log(LogLevelTrace, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LogLevelDebug, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LogLevelInfo, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LogLevelWarn, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LogLevelError, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LogLevelFatal, __FILE__, __LINE__, __VA_ARGS__) + +const char *log_get_level(); + +void log_set_level(LogLevelE lvl); +void log_set_quiet(b32 quiet); +void log_set_lock(log_LockProc proc); +void log_set_fp(FILE *log_file); + +void log_log(LogLevelE lvl, const char *src_file, u64 src_line, const char *fmt, ...); diff --git a/src/threadpool.c b/src/threadpool.c new file mode 100644 index 0000000..3b1168c --- /dev/null +++ b/src/threadpool.c @@ -0,0 +1,10 @@ +#include "common.h" +#include "threadpool.h" +#include "smrt_arena.h" +#include "deque.h" + +typedef struct { + tp_job_proc proc; + void *args; +} tp_job_t; + diff --git a/src/threadpool.h b/src/threadpool.h new file mode 100644 index 0000000..121d803 --- /dev/null +++ b/src/threadpool.h @@ -0,0 +1,32 @@ +#pragma once + +#include "common.h" +#include "deque.h" +#include "smrt_arena.h" + +#include +#include + +typedef void (*tp_job_proc)(void *args); + +typedef struct { + u64 num_threads; + pthread_t *threads; + + sem_t threads_running; + ts_deque_t jobs; +} thread_pool_t; + +// Job queue will be allocated on the arena. +thread_pool_t tp_create(smrt_arena_t * arena , + u64 max_jobs , + u64 num_threads); + +i32 tp_destroy(thread_pool_t tp); + +i32 tp_push_job(thread_pool_t tp , + tp_job_proc job , + void *args); + +// Wait for all threads to finish +void tp_wait(thread_pool_t tp); diff --git a/src/unity.c b/src/unity.c index a1273be..69dd9d1 100644 --- a/src/unity.c +++ b/src/unity.c @@ -27,4 +27,5 @@ #include "dft.c" // Misc +#include "log.c" #include "version.c" -- cgit v1.2.3