aboutsummaryrefslogtreecommitdiff
path: root/src/threading.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/threading.cpp')
-rw-r--r--src/threading.cpp160
1 files changed, 88 insertions, 72 deletions
diff --git a/src/threading.cpp b/src/threading.cpp
index 646c0e93b..7dd1247e7 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -234,95 +234,111 @@ gb_internal void semaphore_wait(Semaphore *s) {
}
#else
+ enum Internal_Mutex_State : i32 {
+ Internal_Mutex_State_Unlocked = 0,
+ Internal_Mutex_State_Locked = 1,
+ Internal_Mutex_State_Waiting = 2,
+ };
+
struct BlockingMutex {
- pthread_mutex_t pthread_mutex;
+ i32 state_;
+
+ Futex &state() {
+ return *(Futex *)&this->state_;
+ }
+ Futex const &state() const {
+ return *(Futex const *)&this->state_;
+ }
};
- gb_internal void mutex_init(BlockingMutex *m) {
- pthread_mutex_init(&m->pthread_mutex, nullptr);
- }
- gb_internal void mutex_destroy(BlockingMutex *m) {
- pthread_mutex_destroy(&m->pthread_mutex);
+
+ gb_internal void mutex_init(BlockingMutex *m) {};
+ gb_internal void mutex_destroy(BlockingMutex *m) {};
+
+ gb_no_inline gb_internal void mutex_lock_slow(BlockingMutex *m, i32 curr_state) {
+ i32 new_state = curr_state;
+ for (i32 spin = 0; spin < 100; spin++) {
+ i32 state = Internal_Mutex_State_Unlocked;
+ bool ok = m->state().compare_exchange_weak(state, new_state, std::memory_order_acquire, std::memory_order_consume);
+ if (ok) {
+ return;
+ }
+ if (state == Internal_Mutex_State_Waiting) {
+ break;
+ }
+ for (i32 i = gb_min(spin+1, 32); i > 0; i--) {
+ yield_thread();
+ }
+ }
+
+ // Set just in case 100 iterations did not do it
+ new_state = Internal_Mutex_State_Waiting;
+
+ for (;;) {
+ if (m->state().exchange(Internal_Mutex_State_Waiting, std::memory_order_acquire) == Internal_Mutex_State_Unlocked) {
+ return;
+ }
+ futex_wait(&m->state(), new_state);
+ yield_thread();
+ }
}
+
gb_internal void mutex_lock(BlockingMutex *m) {
- pthread_mutex_lock(&m->pthread_mutex);
+ i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire);
+ if (v != Internal_Mutex_State_Unlocked) {
+ mutex_lock_slow(m, v);
+ }
}
gb_internal bool mutex_try_lock(BlockingMutex *m) {
- return pthread_mutex_trylock(&m->pthread_mutex) == 0;
+ i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire);
+ return v == Internal_Mutex_State_Unlocked;
}
- gb_internal void mutex_unlock(BlockingMutex *m) {
- pthread_mutex_unlock(&m->pthread_mutex);
+
+ gb_no_inline gb_internal void mutex_unlock_slow(BlockingMutex *m) {
+ futex_signal(&m->state());
}
- struct RecursiveMutex {
- pthread_mutex_t pthread_mutex;
- pthread_mutexattr_t pthread_mutexattr;
- };
- gb_internal void mutex_init(RecursiveMutex *m) {
- pthread_mutexattr_init(&m->pthread_mutexattr);
- pthread_mutexattr_settype(&m->pthread_mutexattr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&m->pthread_mutex, &m->pthread_mutexattr);
- }
- gb_internal void mutex_destroy(RecursiveMutex *m) {
- pthread_mutex_destroy(&m->pthread_mutex);
- }
- gb_internal void mutex_lock(RecursiveMutex *m) {
- pthread_mutex_lock(&m->pthread_mutex);
- }
- gb_internal bool mutex_try_lock(RecursiveMutex *m) {
- return pthread_mutex_trylock(&m->pthread_mutex) == 0;
- }
- gb_internal void mutex_unlock(RecursiveMutex *m) {
- pthread_mutex_unlock(&m->pthread_mutex);
- }
-
- #if defined(GB_SYSTEM_OSX)
- struct Semaphore {
- semaphore_t osx_handle;
- };
-
- gb_internal void semaphore_init (Semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
- gb_internal void semaphore_destroy(Semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); }
- gb_internal void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); }
- gb_internal void semaphore_wait (Semaphore *s) { semaphore_wait(s->osx_handle); }
- #elif defined(GB_SYSTEM_UNIX)
- struct Semaphore {
- sem_t unix_handle;
- };
-
- gb_internal void semaphore_init (Semaphore *s) { sem_init(&s->unix_handle, 0, 0); }
- gb_internal void semaphore_destroy(Semaphore *s) { sem_destroy(&s->unix_handle); }
- gb_internal void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) sem_post(&s->unix_handle); }
- void semaphore_wait (Semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); }
- #else
- #error Implement Semaphore for this platform
- #endif
-
+ gb_internal void mutex_unlock(BlockingMutex *m) {
+ i32 v = m->state().exchange(Internal_Mutex_State_Unlocked, std::memory_order_release);
+ switch (v) {
+ case Internal_Mutex_State_Unlocked:
+ GB_PANIC("Unreachable");
+ break;
+ case Internal_Mutex_State_Locked:
+ // Okay
+ break;
+ case Internal_Mutex_State_Waiting:
+ mutex_unlock_slow(m);
+ break;
+ }
+ }
struct Condition {
- pthread_cond_t pthread_cond;
+ i32 state_;
+
+ Futex &state() {
+ return *(Futex *)&this->state_;
+ }
+ Futex const &state() const {
+ return *(Futex const *)&this->state_;
+ }
};
-
- gb_internal void condition_init(Condition *c) {
- pthread_cond_init(&c->pthread_cond, NULL);
- }
- gb_internal void condition_destroy(Condition *c) {
- pthread_cond_destroy(&c->pthread_cond);
- }
+
+ gb_internal void condition_init(Condition *c) {}
+ gb_internal void condition_destroy(Condition *c) {}
+
gb_internal void condition_broadcast(Condition *c) {
- pthread_cond_broadcast(&c->pthread_cond);
+ c->state().fetch_add(1, std::memory_order_release);
+ futex_broadcast(&c->state());
}
gb_internal void condition_signal(Condition *c) {
- pthread_cond_signal(&c->pthread_cond);
+ c->state().fetch_add(1, std::memory_order_release);
+ futex_signal(&c->state());
}
gb_internal void condition_wait(Condition *c, BlockingMutex *m) {
- pthread_cond_wait(&c->pthread_cond, &m->pthread_mutex);
- }
- gb_internal void condition_wait_with_timeout(Condition *c, BlockingMutex *m, u32 timeout_in_ms) {
- struct timespec abstime = {};
- abstime.tv_sec = timeout_in_ms/1000;
- abstime.tv_nsec = cast(long)(timeout_in_ms%1000)*1e6;
- pthread_cond_timedwait(&c->pthread_cond, &m->pthread_mutex, &abstime);
-
+ i32 state = c->state().load(std::memory_order_relaxed);
+ mutex_unlock(m);
+ futex_wait(&c->state(), state);
+ mutex_lock(m);
}
#endif