From e8a7fcfbf75fd3618d05419814dc22a3e647b570 Mon Sep 17 00:00:00 2001 From: Serhii Mariiekha Date: Sat, 25 Apr 2026 23:31:04 +0200 Subject: [PATCH] Add runtime platform thread primitives --- src/runtime/run_chan.c | 37 +++--- src/runtime/run_platform.h | 230 ++++++++++++++++++++++++++++++++++ src/runtime/run_runtime_api.c | 3 +- src/runtime/run_scheduler.c | 146 +++++++++++++-------- src/runtime/run_scheduler.h | 29 ++--- 5 files changed, 357 insertions(+), 88 deletions(-) create mode 100644 src/runtime/run_platform.h diff --git a/src/runtime/run_chan.c b/src/runtime/run_chan.c index 9f193af..c0ccad0 100644 --- a/src/runtime/run_chan.c +++ b/src/runtime/run_chan.c @@ -2,7 +2,6 @@ #include "run_scheduler.h" -#include #include #include #include @@ -12,7 +11,7 @@ * ======================================================================== */ struct run_chan { - pthread_mutex_t lock; + run_mutex_t lock; size_t elem_size; /* size of each element in bytes */ size_t buffer_cap; /* buffer capacity (0 = unbuffered) */ @@ -38,7 +37,7 @@ run_chan_t *run_chan_new(size_t elem_size, size_t buffer_cap) { abort(); } - pthread_mutex_init(&ch->lock, NULL); + run_mutex_init(&ch->lock); ch->elem_size = elem_size; ch->buffer_cap = buffer_cap; ch->buffer_len = 0; @@ -63,7 +62,7 @@ run_chan_t *run_chan_new(size_t elem_size, size_t buffer_cap) { void run_chan_free(run_chan_t *ch) { if (!ch) return; - pthread_mutex_destroy(&ch->lock); + run_mutex_destroy(&ch->lock); free(ch->buffer); free(ch); } @@ -79,10 +78,10 @@ void run_chan_free(run_chan_t *ch) { * ======================================================================== */ void run_chan_send(run_chan_t *ch, const void *data) { - pthread_mutex_lock(&ch->lock); + run_mutex_lock(&ch->lock); if (ch->closed) { - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); fprintf(stderr, "run: send on closed channel\n"); abort(); } @@ -92,7 +91,7 @@ void run_chan_send(run_chan_t *ch, const void *data) { run_g_t *receiver = run_g_queue_pop(&ch->recv_q); /* Direct copy: data -> receiver's waiting slot */ memcpy(receiver->chan_data_ptr, data, ch->elem_size); - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); run_g_ready(receiver); return; } @@ -103,7 +102,7 @@ void run_chan_send(run_chan_t *ch, const void *data) { memcpy(slot, data, ch->elem_size); ch->send_idx = (ch->send_idx + 1) % ch->buffer_cap; ch->buffer_len++; - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); return; } @@ -112,7 +111,7 @@ void run_chan_send(run_chan_t *ch, const void *data) { if (!g) { /* Called from main thread before scheduler is running -- * this would deadlock. */ - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); fprintf(stderr, "run: channel send would block on main thread\n"); abort(); } @@ -121,7 +120,7 @@ void run_chan_send(run_chan_t *ch, const void *data) { g->chan_data_ptr = (void *)data; /* sender's data stays in place */ g->chan_panic = false; run_g_queue_push(&ch->send_q, g); - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); run_schedule(); /* context switch to scheduler */ /* Resumed here after a receiver copies our data */ @@ -138,7 +137,7 @@ void run_chan_send(run_chan_t *ch, const void *data) { * ======================================================================== */ void run_chan_recv(run_chan_t *ch, void *data) { - pthread_mutex_lock(&ch->lock); + run_mutex_lock(&ch->lock); /* Fast path: waiting sender exists */ if (ch->send_q.len > 0) { @@ -158,7 +157,7 @@ void run_chan_recv(run_chan_t *ch, void *data) { /* Unbuffered: direct copy from sender */ memcpy(data, sender->chan_data_ptr, ch->elem_size); } - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); run_g_ready(sender); return; } @@ -169,21 +168,21 @@ void run_chan_recv(run_chan_t *ch, void *data) { memcpy(data, slot, ch->elem_size); ch->recv_idx = (ch->recv_idx + 1) % ch->buffer_cap; ch->buffer_len--; - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); return; } /* Channel is closed and empty */ if (ch->closed) { memset(data, 0, ch->elem_size); /* zero value */ - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); return; } /* Must block: buffer empty (or unbuffered with no sender) */ run_g_t *g = run_current_g(); if (!g) { - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); fprintf(stderr, "run: channel recv would block on main thread\n"); abort(); } @@ -192,7 +191,7 @@ void run_chan_recv(run_chan_t *ch, void *data) { g->chan_data_ptr = data; /* receiver provides the destination */ g->chan_panic = false; run_g_queue_push(&ch->recv_q, g); - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); run_schedule(); /* context switch to scheduler */ /* Resumed here after a sender copies data to our slot */ @@ -203,10 +202,10 @@ void run_chan_recv(run_chan_t *ch, void *data) { * ======================================================================== */ void run_chan_close(run_chan_t *ch) { - pthread_mutex_lock(&ch->lock); + run_mutex_lock(&ch->lock); if (ch->closed) { - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); fprintf(stderr, "run: close of closed channel\n"); abort(); } @@ -232,7 +231,7 @@ void run_chan_close(run_chan_t *ch) { run_g_queue_push(&wake_list, g); } - pthread_mutex_unlock(&ch->lock); + run_mutex_unlock(&ch->lock); /* Make all collected Gs runnable (outside the channel lock) */ run_g_t *g; diff --git a/src/runtime/run_platform.h b/src/runtime/run_platform.h new file mode 100644 index 0000000..fe7cc01 --- /dev/null +++ b/src/runtime/run_platform.h @@ -0,0 +1,230 @@ +#ifndef RUN_PLATFORM_H +#define RUN_PLATFORM_H + +#include +#include +#include + +#if defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include + +#define RUN_THREAD_LOCAL __declspec(thread) + +typedef HANDLE run_thread_t; +typedef SRWLOCK run_mutex_t; +typedef CONDITION_VARIABLE run_cond_t; +typedef void (*run_timer_fn)(void *); + +typedef struct { + HANDLE handle; + run_timer_fn fn; + void *arg; +} run_platform_timer_t; + +#define RUN_MUTEX_INITIALIZER SRWLOCK_INIT + +typedef void *(*run_thread_fn)(void *); + +typedef struct { + run_thread_fn fn; + void *arg; +} run_thread_start_t; + +static unsigned __stdcall run_thread_trampoline(void *arg) { + run_thread_start_t *start = (run_thread_start_t *)arg; + run_thread_fn fn = start->fn; + void *fn_arg = start->arg; + free(start); + (void)fn(fn_arg); + return 0; +} + +static VOID CALLBACK run_timer_trampoline(PVOID arg, BOOLEAN fired) { + (void)fired; + run_platform_timer_t *timer = (run_platform_timer_t *)arg; + timer->fn(timer->arg); +} + +static inline void run_mutex_init(run_mutex_t *m) { + InitializeSRWLock(m); +} + +static inline void run_mutex_destroy(run_mutex_t *m) { + (void)m; +} + +static inline void run_mutex_lock(run_mutex_t *m) { + AcquireSRWLockExclusive(m); +} + +static inline void run_mutex_unlock(run_mutex_t *m) { + ReleaseSRWLockExclusive(m); +} + +static inline void run_cond_init(run_cond_t *c) { + InitializeConditionVariable(c); +} + +static inline void run_cond_destroy(run_cond_t *c) { + (void)c; +} + +static inline void run_cond_wait(run_cond_t *c, run_mutex_t *m) { + SleepConditionVariableSRW(c, m, INFINITE, 0); +} + +static inline void run_cond_signal(run_cond_t *c) { + WakeConditionVariable(c); +} + +static inline int run_thread_create(run_thread_t *thread, run_thread_fn fn, void *arg) { + run_thread_start_t *start = (run_thread_start_t *)malloc(sizeof(run_thread_start_t)); + if (start == NULL) + return -1; + start->fn = fn; + start->arg = arg; + + uintptr_t handle = _beginthreadex(NULL, 0, run_thread_trampoline, start, 0, NULL); + if (handle == 0) { + free(start); + return -1; + } + *thread = (HANDLE)handle; + return 0; +} + +static inline void run_thread_detach(run_thread_t thread) { + CloseHandle(thread); +} + +static inline run_thread_t run_thread_self(void) { + return GetCurrentThread(); +} + +static inline uintptr_t run_thread_seed(void) { + return (uintptr_t)GetCurrentThreadId(); +} + +static inline long run_cpu_count(void) { + SYSTEM_INFO info; + GetSystemInfo(&info); + return (long)info.dwNumberOfProcessors; +} + +static inline bool run_timer_start(run_platform_timer_t *timer, uint32_t interval_us, + run_timer_fn fn, void *arg) { + timer->handle = NULL; + timer->fn = fn; + timer->arg = arg; + + DWORD interval_ms = (DWORD)((interval_us + 999u) / 1000u); + if (interval_ms == 0) + interval_ms = 1; + + return CreateTimerQueueTimer(&timer->handle, NULL, run_timer_trampoline, timer, interval_ms, + interval_ms, WT_EXECUTEDEFAULT) != 0; +} + +static inline void run_timer_stop(run_platform_timer_t *timer) { + if (timer->handle != NULL) { + DeleteTimerQueueTimer(NULL, timer->handle, INVALID_HANDLE_VALUE); + timer->handle = NULL; + } +} + +#else + +#include +#include + +#define RUN_THREAD_LOCAL __thread + +typedef pthread_t run_thread_t; +typedef pthread_mutex_t run_mutex_t; +typedef pthread_cond_t run_cond_t; +typedef void (*run_timer_fn)(void *); + +typedef struct { + int unused; +} run_platform_timer_t; + +#define RUN_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +typedef void *(*run_thread_fn)(void *); + +static inline void run_mutex_init(run_mutex_t *m) { + pthread_mutex_init(m, NULL); +} + +static inline void run_mutex_destroy(run_mutex_t *m) { + pthread_mutex_destroy(m); +} + +static inline void run_mutex_lock(run_mutex_t *m) { + pthread_mutex_lock(m); +} + +static inline void run_mutex_unlock(run_mutex_t *m) { + pthread_mutex_unlock(m); +} + +static inline void run_cond_init(run_cond_t *c) { + pthread_cond_init(c, NULL); +} + +static inline void run_cond_destroy(run_cond_t *c) { + pthread_cond_destroy(c); +} + +static inline void run_cond_wait(run_cond_t *c, run_mutex_t *m) { + pthread_cond_wait(c, m); +} + +static inline void run_cond_signal(run_cond_t *c) { + pthread_cond_signal(c); +} + +static inline int run_thread_create(run_thread_t *thread, run_thread_fn fn, void *arg) { + return pthread_create(thread, NULL, fn, arg); +} + +static inline void run_thread_detach(run_thread_t thread) { + pthread_detach(thread); +} + +static inline run_thread_t run_thread_self(void) { + return pthread_self(); +} + +static inline uintptr_t run_thread_seed(void) { + return (uintptr_t)pthread_self(); +} + +static inline long run_cpu_count(void) { + return sysconf(_SC_NPROCESSORS_ONLN); +} + +static inline bool run_timer_start(run_platform_timer_t *timer, uint32_t interval_us, + run_timer_fn fn, void *arg) { + (void)timer; + (void)interval_us; + (void)fn; + (void)arg; + return false; +} + +static inline void run_timer_stop(run_platform_timer_t *timer) { + (void)timer; +} + +#endif + +#endif diff --git a/src/runtime/run_runtime_api.c b/src/runtime/run_runtime_api.c index d86f2af..3b2d9d9 100644 --- a/src/runtime/run_runtime_api.c +++ b/src/runtime/run_runtime_api.c @@ -9,14 +9,13 @@ #include #include #include -#include #ifndef RUN_VERSION #define RUN_VERSION "0.1.0-dev" #endif int64_t run_runtime_num_cpu(void) { - long n = sysconf(_SC_NPROCESSORS_ONLN); + long n = run_cpu_count(); return n > 0 ? (int64_t)n : 1; } diff --git a/src/runtime/run_scheduler.c b/src/runtime/run_scheduler.c index 7ef9edc..9d23f29 100644 --- a/src/runtime/run_scheduler.c +++ b/src/runtime/run_scheduler.c @@ -4,15 +4,14 @@ #include "run_poller.h" #include "run_vmem.h" -#include #include #include #include #include #include -#include #if defined(__linux__) || defined(__APPLE__) +#include #include #endif @@ -41,7 +40,7 @@ * Thread-Local Storage * ======================================================================== */ -static __thread run_m_t *tls_current_m = NULL; +static RUN_THREAD_LOCAL run_m_t *tls_current_m = NULL; run_g_t *run_current_g(void) { return tls_current_m ? tls_current_m->current_g : NULL; @@ -60,21 +59,21 @@ static uint32_t num_ps = 0; /* Global run queue */ static run_g_queue_t global_queue; -static pthread_mutex_t global_queue_lock = PTHREAD_MUTEX_INITIALIZER; +static run_mutex_t global_queue_lock = RUN_MUTEX_INITIALIZER; /* Idle lists */ static uint32_t idle_p_stack[RUN_MAX_P_COUNT]; /* stack of idle P indices */ static uint32_t idle_p_count = 0; -static pthread_mutex_t idle_p_lock = PTHREAD_MUTEX_INITIALIZER; +static run_mutex_t idle_p_lock = RUN_MUTEX_INITIALIZER; /* All Ms */ static run_m_t *all_ms = NULL; static uint32_t num_ms = 0; -static pthread_mutex_t all_ms_lock = PTHREAD_MUTEX_INITIALIZER; +static run_mutex_t all_ms_lock = RUN_MUTEX_INITIALIZER; /* Idle Ms waiting to be woken */ static run_m_t *idle_m_head = NULL; -static pthread_mutex_t idle_m_lock = PTHREAD_MUTEX_INITIALIZER; +static run_mutex_t idle_m_lock = RUN_MUTEX_INITIALIZER; /* G ID counter */ static _Atomic uint64_t next_g_id = 1; @@ -95,6 +94,9 @@ static bool scheduler_initialized = false; /* Preemption timer active */ static bool preemption_timer_active = false; +#if defined(_WIN32) +static run_platform_timer_t preemption_timer; +#endif /* Signal preemption active */ static bool signal_preemption_active = false; @@ -268,6 +270,7 @@ static void run_pin_m_to_node(run_m_t *m, uint32_t node_id) { } pthread_setaffinity_np(m->thread, sizeof(cpuset), &cpuset); #elif defined(_WIN32) + (void)m; uint32_t cpu_count; const uint32_t *cpus = run_numa_cpus_on_node(node_id, &cpu_count); if (cpu_count == 0) @@ -517,14 +520,14 @@ static run_m_t *run_m_alloc(void) { abort(); } - pthread_mutex_lock(&all_ms_lock); + run_mutex_lock(&all_ms_lock); m->id = num_ms++; m->all_next = all_ms; all_ms = m; - pthread_mutex_unlock(&all_ms_lock); + run_mutex_unlock(&all_ms_lock); - pthread_mutex_init(&m->park_mutex, NULL); - pthread_cond_init(&m->park_cond, NULL); + run_mutex_init(&m->park_mutex); + run_cond_init(&m->park_cond); m->parked = false; /* Allocate g0 (scheduler goroutine) with its own stack */ @@ -548,13 +551,13 @@ static run_m_t *run_m_alloc(void) { * ======================================================================== */ static run_p_t *run_acquire_idle_p(void) { - pthread_mutex_lock(&idle_p_lock); + run_mutex_lock(&idle_p_lock); if (idle_p_count == 0) { - pthread_mutex_unlock(&idle_p_lock); + run_mutex_unlock(&idle_p_lock); return NULL; } uint32_t idx = idle_p_stack[--idle_p_count]; - pthread_mutex_unlock(&idle_p_lock); + run_mutex_unlock(&idle_p_lock); run_p_t *p = &all_ps[idx]; p->status = P_RUNNING; @@ -562,18 +565,18 @@ static run_p_t *run_acquire_idle_p(void) { } static bool run_has_idle_p(void) { - pthread_mutex_lock(&idle_p_lock); + run_mutex_lock(&idle_p_lock); bool has_idle = idle_p_count > 0; - pthread_mutex_unlock(&idle_p_lock); + run_mutex_unlock(&idle_p_lock); return has_idle; } static void run_release_p(run_p_t *p) { p->status = P_IDLE; p->bound_m = NULL; - pthread_mutex_lock(&idle_p_lock); + run_mutex_lock(&idle_p_lock); idle_p_stack[idle_p_count++] = p->id; - pthread_mutex_unlock(&idle_p_lock); + run_mutex_unlock(&idle_p_lock); } /* ======================================================================== @@ -581,22 +584,22 @@ static void run_release_p(run_p_t *p) { * ======================================================================== */ void run_global_queue_push(run_g_t *g) { - pthread_mutex_lock(&global_queue_lock); + run_mutex_lock(&global_queue_lock); run_g_queue_push(&global_queue, g); - pthread_mutex_unlock(&global_queue_lock); + run_mutex_unlock(&global_queue_lock); } run_g_t *run_global_queue_pop(void) { - pthread_mutex_lock(&global_queue_lock); + run_mutex_lock(&global_queue_lock); run_g_t *g = run_g_queue_pop(&global_queue); - pthread_mutex_unlock(&global_queue_lock); + run_mutex_unlock(&global_queue_lock); return g; } uint32_t run_global_queue_len(void) { - pthread_mutex_lock(&global_queue_lock); + run_mutex_lock(&global_queue_lock); uint32_t len = global_queue.len; - pthread_mutex_unlock(&global_queue_lock); + run_mutex_unlock(&global_queue_lock); return len; } @@ -605,12 +608,12 @@ uint32_t run_global_queue_len(void) { * ======================================================================== */ /* Simple xorshift RNG for work stealing victim selection. */ -static __thread uint32_t steal_rng_state = 0; +static RUN_THREAD_LOCAL uint32_t steal_rng_state = 0; static uint32_t run_steal_random(void) { if (steal_rng_state == 0) { /* Seed from thread ID */ - steal_rng_state = (uint32_t)(uintptr_t)pthread_self() ^ 0xDEADBEEF; + steal_rng_state = (uint32_t)run_thread_seed() ^ 0xDEADBEEF; } uint32_t x = steal_rng_state; x ^= x << 13; @@ -686,19 +689,19 @@ static void run_park_m(run_m_t *m) { (long long)run_metrics_global_queue_len(), (long long)run_metrics_local_queue_len(), (long long)run_metrics_poll_waiter_count()); } - pthread_mutex_lock(&m->park_mutex); + run_mutex_lock(&m->park_mutex); m->parked = true; /* Add to idle M list */ - pthread_mutex_lock(&idle_m_lock); + run_mutex_lock(&idle_m_lock); m->idle_next = idle_m_head; idle_m_head = m; - pthread_mutex_unlock(&idle_m_lock); + run_mutex_unlock(&idle_m_lock); while (m->parked) { - pthread_cond_wait(&m->park_cond, &m->park_mutex); + run_cond_wait(&m->park_cond, &m->park_mutex); } - pthread_mutex_unlock(&m->park_mutex); + run_mutex_unlock(&m->park_mutex); } static void run_unpark_m(run_m_t *m) { @@ -711,17 +714,17 @@ static void run_unpark_m(run_m_t *m) { (long long)run_metrics_local_queue_len(), (long long)run_metrics_poll_waiter_count()); } - pthread_mutex_lock(&m->park_mutex); + run_mutex_lock(&m->park_mutex); m->parked = false; - pthread_cond_signal(&m->park_cond); - pthread_mutex_unlock(&m->park_mutex); + run_cond_signal(&m->park_cond); + run_mutex_unlock(&m->park_mutex); } static void run_unpark_all_idle_ms(void) { - pthread_mutex_lock(&idle_m_lock); + run_mutex_lock(&idle_m_lock); run_m_t *m = idle_m_head; idle_m_head = NULL; - pthread_mutex_unlock(&idle_m_lock); + run_mutex_unlock(&idle_m_lock); while (m != NULL) { run_m_t *next = m->idle_next; @@ -733,13 +736,13 @@ static void run_unpark_all_idle_ms(void) { void run_wake_m(void) { /* Try to wake an idle M */ - pthread_mutex_lock(&idle_m_lock); + run_mutex_lock(&idle_m_lock); run_m_t *m = idle_m_head; if (m) { idle_m_head = m->idle_next; m->idle_next = NULL; } - pthread_mutex_unlock(&idle_m_lock); + run_mutex_unlock(&idle_m_lock); if (m) { /* Get an idle P for this M */ @@ -750,18 +753,18 @@ void run_wake_m(void) { run_unpark_m(m); } else { /* No idle P — put M back */ - pthread_mutex_lock(&idle_m_lock); + run_mutex_lock(&idle_m_lock); m->idle_next = idle_m_head; idle_m_head = m; - pthread_mutex_unlock(&idle_m_lock); + run_mutex_unlock(&idle_m_lock); } return; } /* No idle M — create a new one if under limit */ - pthread_mutex_lock(&all_ms_lock); + run_mutex_lock(&all_ms_lock); uint32_t current_ms = num_ms; - pthread_mutex_unlock(&all_ms_lock); + run_mutex_unlock(&all_ms_lock); if (current_ms >= RUN_MAX_M_COUNT) return; @@ -777,8 +780,12 @@ void run_wake_m(void) { new_m->current_p = p; p->bound_m = new_m; - pthread_create(&new_m->thread, NULL, run_m_thread_entry, new_m); - pthread_detach(new_m->thread); + if (run_thread_create(&new_m->thread, run_m_thread_entry, new_m) != 0) { + p->bound_m = NULL; + run_release_p(p); + return; + } + run_thread_detach(new_m->thread); } /* ======================================================================== @@ -949,7 +956,7 @@ void run_scheduler_init(void) { /* Multi-P: default to CPU count. */ { - long cpus = sysconf(_SC_NPROCESSORS_ONLN); + long cpus = run_cpu_count(); num_ps = (cpus > 0 && cpus <= RUN_MAX_P_COUNT) ? (uint32_t)cpus : 1; } const char *maxprocs_env = getenv("RUN_MAXPROCS"); @@ -981,7 +988,7 @@ void run_scheduler_init(void) { /* Create M0 wrapping the main OS thread */ run_m_t *m0 = run_m_alloc(); - m0->thread = pthread_self(); + m0->thread = run_thread_self(); m0->current_p = &all_ps[0]; all_ps[0].status = P_RUNNING; all_ps[0].bound_m = m0; @@ -1265,7 +1272,40 @@ void run_numa_pin(uint32_t node_id) { * Cooperative Preemption (#84) — Timer-based * ======================================================================== */ -#if defined(__linux__) || defined(__APPLE__) +#if defined(_WIN32) + +static void run_preempt_timer_callback(void *arg) { + (void)arg; + + run_mutex_lock(&all_ms_lock); + for (run_m_t *m = all_ms; m != NULL; m = m->all_next) { + run_g_t *g = m->current_g; + if (g && g->status == G_RUNNING) { + g->preempt = true; + } + } + run_mutex_unlock(&all_ms_lock); +} + +void run_preemption_start(void) { + if (preemption_timer_active) + return; + + if (run_timer_start(&preemption_timer, RUN_PREEMPT_INTERVAL_US, run_preempt_timer_callback, + NULL)) { + preemption_timer_active = true; + } +} + +void run_preemption_stop(void) { + if (!preemption_timer_active) + return; + + run_timer_stop(&preemption_timer); + preemption_timer_active = false; +} + +#elif defined(__linux__) || defined(__APPLE__) static void run_preempt_timer_handler(int sig) { (void)sig; @@ -1305,9 +1345,9 @@ void run_preemption_stop(void) { preemption_timer_active = false; } -#else /* Windows stub */ +#else -void run_preemption_start(void) { /* TODO: Windows timer */ } +void run_preemption_start(void) {} void run_preemption_stop(void) {} #endif @@ -1332,9 +1372,9 @@ void run_entersyscall(void) { p->bound_m = NULL; /* Put P in idle list so another M can pick it up */ - pthread_mutex_lock(&idle_p_lock); + run_mutex_lock(&idle_p_lock); idle_p_stack[idle_p_count++] = p->id; - pthread_mutex_unlock(&idle_p_lock); + run_mutex_unlock(&idle_p_lock); /* Wake an M to take over this P's work */ if (run_local_queue_len(&p->local_queue) > 0) { @@ -1462,7 +1502,7 @@ static void *run_signal_preemption_thread_entry(void *arg) { while (atomic_load_explicit(&signal_preemption_thread_running, memory_order_acquire)) { nanosleep(&interval, NULL); - pthread_mutex_lock(&all_ms_lock); + run_mutex_lock(&all_ms_lock); for (run_m_t *m = all_ms; m != NULL; m = m->all_next) { run_g_t *g = m->current_g; if (g == NULL || g->status != G_RUNNING) @@ -1471,7 +1511,7 @@ static void *run_signal_preemption_thread_entry(void *arg) { continue; pthread_kill(m->thread, SIGURG); } - pthread_mutex_unlock(&all_ms_lock); + run_mutex_unlock(&all_ms_lock); } return NULL; diff --git a/src/runtime/run_scheduler.h b/src/runtime/run_scheduler.h index 7e8a557..d3c4a6b 100644 --- a/src/runtime/run_scheduler.h +++ b/src/runtime/run_scheduler.h @@ -1,7 +1,8 @@ #ifndef RUN_SCHEDULER_H #define RUN_SCHEDULER_H -#include +#include "run_platform.h" + #include #include #include @@ -49,16 +50,16 @@ typedef struct { void *r13; void *r14; void *r15; - __declspec(align(16)) unsigned char xmm6[16]; - __declspec(align(16)) unsigned char xmm7[16]; - __declspec(align(16)) unsigned char xmm8[16]; - __declspec(align(16)) unsigned char xmm9[16]; - __declspec(align(16)) unsigned char xmm10[16]; - __declspec(align(16)) unsigned char xmm11[16]; - __declspec(align(16)) unsigned char xmm12[16]; - __declspec(align(16)) unsigned char xmm13[16]; - __declspec(align(16)) unsigned char xmm14[16]; - __declspec(align(16)) unsigned char xmm15[16]; + _Alignas(16) unsigned char xmm6[16]; + _Alignas(16) unsigned char xmm7[16]; + _Alignas(16) unsigned char xmm8[16]; + _Alignas(16) unsigned char xmm9[16]; + _Alignas(16) unsigned char xmm10[16]; + _Alignas(16) unsigned char xmm11[16]; + _Alignas(16) unsigned char xmm12[16]; + _Alignas(16) unsigned char xmm13[16]; + _Alignas(16) unsigned char xmm14[16]; + _Alignas(16) unsigned char xmm15[16]; } run_context_t; #else typedef struct { @@ -128,12 +129,12 @@ uint32_t run_local_queue_len(run_local_queue_t *q); /* ---------- M — Machine Thread ---------- */ struct run_m { uint64_t id; - pthread_t thread; + run_thread_t thread; run_g_t *current_g; run_p_t *current_p; run_g_t *g0; - pthread_mutex_t park_mutex; - pthread_cond_t park_cond; + run_mutex_t park_mutex; + run_cond_t park_cond; volatile bool parked; struct run_m *all_next; struct run_m *idle_next;