Update threading.cpp

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