summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsteven-na <noreply.github@stvnc.dev>2026-08-13 14:01:01 -0700
committersteven-na <noreply.github@stvnc.dev>2026-08-13 14:01:01 -0700
commit0a8bbe0ac3a45f2ff3975d4de07332b25649ba9f (patch)
treee3b08417e34c679b44cf81d180a02ec665193bb1
parent5f34ef597ae78199e20e82523e3e333602c01b8c (diff)
Simple logging, started on threadpool
-rw-r--r--README.md5
-rw-r--r--src/deque.h2
-rw-r--r--src/log.c88
-rw-r--r--src/log.h35
-rw-r--r--src/threadpool.c10
-rw-r--r--src/threadpool.h32
-rw-r--r--src/unity.c1
7 files changed, 172 insertions, 1 deletions
diff --git a/README.md b/README.md
index cd66aac..a6831d4 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,6 @@
# SteEZ (Steven-NA EZ library)
+
+## Todo
+- [ ] Add trace log calls, disabled with NTRACE_LOG
+- [ ] Make status return values consistent, 0 success, -1 fail, >0 info if necessary
+- [ ] Finish thread_pool
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 <stdarg.h>
+#include <stdio.h>
+#include <time.h>
+
+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 <stdio.h>
+#include <stdarg.h>
+
+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 <bits/pthreadtypes.h>
+#include <semaphore.h>
+
+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"