Update threading.cpp

This commit is contained in:
avanspector
2024-03-01 00:41:28 +01:00
parent 290ada7f90
commit d4d9f55556

View File

@@ -840,86 +840,131 @@ gb_internal void futex_wait(Futex *f, Footex val) {
#include <pthread.h>
#include <atomic>
struct _Spinlock {
std::atomic_flag state;
void init() {
state.clear();
}
void lock() {
while (state.test_and_set(std::memory_order_acquire)) {
#if defined(GB_CPU_X86)
_mm_pause();
#else
(void)0; // spin...
#endif
}
}
void unlock() {
state.clear(std::memory_order_release);
}
};
struct Futex_Waitq;
struct Futex_Wait_Node {
struct Futex_Waiter {
_Spinlock lock;
pthread_t thread;
Futex *futex;
Futex_Wait_Node *prev, *next;
Futex_Waitq *waitq;
Futex_Waiter *prev, *next;
};
struct Futex_Wait_Queue {
std::atomic_flag spinlock;
Futex_Wait_Node list;
struct Futex_Waitq {
_Spinlock lock;
Futex_Waiter list;
void lock() {
while (spinlock.test_and_set(std::memory_order_acquire)) {
; // spin...
}
}
void unlock() {
spinlock.clear(std::memory_order_release);
void init() {
auto head = &list;
head->prev = head->next = head;
}
};
// FIXME: This approach may scale badly in the future,
// possible solution - hash map (leads to deadlocks now).
Futex_Wait_Queue g_waitq = {
.spinlock = ATOMIC_FLAG_INIT,
Futex_Waitq g_waitq = {
.lock = ATOMIC_FLAG_INIT,
.list = {
.prev = &g_waitq.list,
.next = &g_waitq.list,
},
};
Futex_Wait_Queue *get_wait_queue(Futex *f) {
Futex_Waitq *get_waitq(Futex *f) {
// Future hash map method...
return &g_waitq;
}
void futex_signal(Futex *f) {
auto waitq = get_wait_queue(f);
auto waitq = get_waitq(f);
waitq->lock();
waitq->lock.lock();
auto head = &waitq->list;
for (auto waiter = head->next; waiter != head; waiter = waiter->next) {
if (waiter->futex == f) {
pthread_kill(waiter->thread, SIGCONT);
break;
}
if (waiter->futex != f) {
continue;
}
waitq->lock.unlock();
pthread_kill(waiter->thread, SIGCONT);
return;
}
waitq->unlock();
waitq->lock.unlock();
}
void futex_broadcast(Futex *f) {
auto waitq = get_wait_queue(f);
auto waitq = get_waitq(f);
waitq->lock();
waitq->lock.lock();
auto head = &waitq->list;
for (auto waiter = head->next; waiter != head; waiter = waiter->next) {
if (waiter->futex == f) {
if (waiter->futex != f) {
continue;
}
if (waiter->next == head) {
waitq->lock.unlock();
pthread_kill(waiter->thread, SIGCONT);
}
return;
} else {
pthread_kill(waiter->thread, SIGCONT);
}
}
waitq->unlock();
waitq->lock.unlock();
}
void futex_wait(Futex *f, Footex val) {
auto waitq = get_wait_queue(f);
waitq->lock();
auto head = &waitq->list;
Futex_Wait_Node waiter;
Futex_Waiter waiter;
waiter.thread = pthread_self();
waiter.futex = f;
waiter.prev = head;
waiter.next = head->next;
auto waitq = get_waitq(f);
while (waitq->lock.state.test_and_set(std::memory_order_acquire)) {
if (f->load(std::memory_order_relaxed) != val) {
return;
}
#if defined(GB_CPU_X86)
_mm_pause();
#else
(void)0; // spin...
#endif
}
waiter.waitq = waitq;
waiter.lock.init();
waiter.lock.lock();
auto head = &waitq->list;
waiter.prev = head->prev;
waiter.next = head;
waiter.prev->next = &waiter;
waiter.next->prev = &waiter;
waiter.prev->next = &waiter;
waiter.next->prev = &waiter;
@@ -928,12 +973,25 @@ void futex_wait(Futex *f, Footex val) {
sigemptyset(&mask);
sigaddset(&mask, SIGCONT);
pthread_sigmask(SIG_BLOCK, &mask, &old_mask);
if (*f == val) {
waitq->unlock();
int sig;
sigwait(&mask, &sig);
waitq->lock();
if (f->load(std::memory_order_relaxed) == val) {
waiter.lock.unlock();
waitq->lock.unlock();
int sig;
sigwait(&mask, &sig);
waitq->lock.lock();
waiter.lock.lock();
while (waitq != waiter.waitq) {
auto req = waiter.waitq;
waiter.lock.unlock();
waitq->lock.unlock();
waitq = req;
waitq->lock.lock();
waiter.lock.lock();
}
}
waiter.prev->next = waiter.next;
@@ -941,7 +999,8 @@ void futex_wait(Futex *f, Footex val) {
pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
waitq->unlock();
waiter.lock.unlock();
waitq->lock.unlock();
}
#endif