aboutsummaryrefslogtreecommitdiff
path: root/src/threading.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-01-01 15:06:57 +0000
committergingerBill <bill@gingerbill.org>2023-01-01 15:06:57 +0000
commit20d451396d68d749b6c7ce762bc14e44f219e299 (patch)
tree7e5d1091a6970922b732aedfcba57cc0458fedc9 /src/threading.cpp
parent60d0390ef8ceabb0567ee1ba968fdaf2024d34bf (diff)
Begin work on futex-ifying the threading primitives
Diffstat (limited to 'src/threading.cpp')
-rw-r--r--src/threading.cpp172
1 files changed, 133 insertions, 39 deletions
diff --git a/src/threading.cpp b/src/threading.cpp
index cb3150c2a..646c0e93b 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -41,11 +41,12 @@ struct Thread {
struct ThreadPool *pool;
};
-typedef std::atomic<int32_t> Futex;
-typedef volatile int32_t Footex;
+typedef std::atomic<i32> Futex;
+typedef volatile i32 Footex;
gb_internal void futex_wait(Futex *addr, Footex val);
gb_internal void futex_signal(Futex *addr);
+gb_internal void futex_broadcast(Futex *addr);
gb_internal void mutex_init (BlockingMutex *m);
gb_internal void mutex_destroy (BlockingMutex *m);
@@ -117,6 +118,82 @@ struct MutexGuard {
#define MUTEX_GUARD(m) MutexGuard GB_DEFER_3(_mutex_guard_){m}
+struct RecursiveMutex {
+ Futex owner;
+ i32 recursion;
+};
+gb_internal void mutex_init(RecursiveMutex *m) {
+
+}
+gb_internal void mutex_destroy(RecursiveMutex *m) {
+
+}
+gb_internal void mutex_lock(RecursiveMutex *m) {
+ Futex tid = cast(i32)thread_current_id();
+ for (;;) {
+ i32 prev_owner = 0;
+ m->owner.compare_exchange_strong(prev_owner, tid, std::memory_order_acquire, std::memory_order_acquire);
+ if (prev_owner == 0 || prev_owner == tid) {
+ m->recursion++;
+ // inside the lock
+ return;
+ }
+ futex_wait(&m->owner, prev_owner);
+ }
+}
+gb_internal bool mutex_try_lock(RecursiveMutex *m) {
+ Futex tid = cast(i32)thread_current_id();
+ i32 prev_owner = 0;
+ m->owner.compare_exchange_strong(prev_owner, tid, std::memory_order_acquire, std::memory_order_acquire);
+ if (prev_owner == 0 || prev_owner == tid) {
+ m->recursion++;
+ // inside the lock
+ return true;
+ }
+ return false;
+}
+gb_internal void mutex_unlock(RecursiveMutex *m) {
+ m->recursion--;
+ if (m->recursion != 0) {
+ return;
+ }
+ m->owner.exchange(0, std::memory_order_release);
+ futex_signal(&m->owner);
+ // outside the lock
+}
+
+struct Semaphore {
+ Futex count;
+};
+
+gb_internal void semaphore_init(Semaphore *s) {
+
+}
+gb_internal void semaphore_destroy(Semaphore *s) {
+
+}
+gb_internal void semaphore_post(Semaphore *s, i32 count) {
+ s->count.fetch_add(count, std::memory_order_release);
+ if (s->count == 1) {
+ futex_signal(&s->count);
+ } else {
+ futex_broadcast(&s->count);
+ }
+}
+gb_internal void semaphore_wait(Semaphore *s) {
+ for (;;) {
+ i32 original_count = s->count.load(std::memory_order_relaxed);
+ while (original_count == 0) {
+ futex_wait(&s->count, original_count);
+ original_count = s->count;
+ }
+
+ if (!s->count.compare_exchange_strong(original_count, original_count-1, std::memory_order_acquire, std::memory_order_acquire)) {
+ return;
+ }
+ }
+}
+
#if defined(GB_SYSTEM_WINDOWS)
struct BlockingMutex {
SRWLOCK srwlock;
@@ -135,42 +212,6 @@ struct MutexGuard {
ReleaseSRWLockExclusive(&m->srwlock);
}
- struct RecursiveMutex {
- CRITICAL_SECTION win32_critical_section;
- };
- gb_internal void mutex_init(RecursiveMutex *m) {
- InitializeCriticalSection(&m->win32_critical_section);
- }
- gb_internal void mutex_destroy(RecursiveMutex *m) {
- DeleteCriticalSection(&m->win32_critical_section);
- }
- gb_internal void mutex_lock(RecursiveMutex *m) {
- EnterCriticalSection(&m->win32_critical_section);
- }
- gb_internal bool mutex_try_lock(RecursiveMutex *m) {
- return TryEnterCriticalSection(&m->win32_critical_section) != 0;
- }
- gb_internal void mutex_unlock(RecursiveMutex *m) {
- LeaveCriticalSection(&m->win32_critical_section);
- }
-
- struct Semaphore {
- void *win32_handle;
- };
-
- gb_internal void semaphore_init(Semaphore *s) {
- s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
- }
- gb_internal void semaphore_destroy(Semaphore *s) {
- CloseHandle(s->win32_handle);
- }
- gb_internal void semaphore_post(Semaphore *s, i32 count) {
- ReleaseSemaphore(s->win32_handle, count, NULL);
- }
- gb_internal void semaphore_wait(Semaphore *s) {
- WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
- }
-
struct Condition {
CONDITION_VARIABLE cond;
};
@@ -458,6 +499,18 @@ gb_internal void futex_signal(Futex *addr) {
}
}
+gb_internal void futex_broadcast(Futex *addr) {
+ for (;;) {
+ int ret = syscall(SYS_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, INT32_MAX, NULL, NULL, 0);
+ if (ret == -1) {
+ perror("Futex wake");
+ GB_PANIC("Failed in futex wake!\n");
+ } else if (ret > 0) {
+ return;
+ }
+ }
+}
+
gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) {
int ret = syscall(SYS_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, NULL, NULL, 0);
@@ -485,6 +538,10 @@ gb_internal void futex_signal(Futex *addr) {
_umtx_op(addr, UMTX_OP_WAKE, 1, 0, 0);
}
+gb_internal void futex_broadcast(Futex *addr) {
+ _umtx_op(addr, UMTX_OP_WAKE, INT32_MAX, 0, 0);
+}
+
gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) {
int ret = _umtx_op(addr, UMTX_OP_WAIT_UINT, val, 0, NULL);
@@ -523,6 +580,23 @@ gb_internal void futex_signal(Futex *addr) {
}
}
+
+gb_internal void futex_broadcast(Futex *addr) {
+ for (;;) {
+ int ret = futex((volatile uint32_t *)addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, INT32_MAX, NULL, NULL);
+ if (ret == -1) {
+ if (errno == ETIMEDOUT || errno == EINTR) {
+ continue;
+ }
+
+ perror("Futex wake");
+ GB_PANIC("futex wake fail");
+ } else if (ret == 1) {
+ return;
+ }
+ }
+}
+
gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) {
int ret = futex((volatile uint32_t *)addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, NULL, NULL);
@@ -565,9 +639,25 @@ gb_internal void futex_signal(Futex *addr) {
}
}
+gb_internal void futex_broadcast(Futex *addr) {
+ for (;;) {
+ int ret = __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, addr, 0);
+ if (ret >= 0) {
+ return;
+ }
+ if (ret == EINTR || ret == EFAULT) {
+ continue;
+ }
+ if (ret == ENOENT) {
+ return;
+ }
+ GB_PANIC("Failed in futex wake!\n");
+ }
+}
+
gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) {
- int ret = __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, addr, val, 0);
+ int ret = __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, addr, val, 0);
if (ret >= 0) {
if (*addr != val) {
return;
@@ -590,6 +680,10 @@ gb_internal void futex_signal(Futex *addr) {
WakeByAddressSingle((void *)addr);
}
+gb_internal void futex_broadcast(Futex *addr) {
+ WakeByAddressAll((void *)addr);
+}
+
gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) {
WaitOnAddress(addr, (void *)&val, sizeof(val), INFINITE);