fiber wait wip
This commit is contained in:
parent
d47b951b82
commit
40dcdb40dc
@ -1382,7 +1382,14 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg)
|
|||||||
while (!G.evictor_scheduler_shutdown) {
|
while (!G.evictor_scheduler_shutdown) {
|
||||||
sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, job_counter);
|
sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, job_counter);
|
||||||
sys_counter_wait(job_counter);
|
sys_counter_wait(job_counter);
|
||||||
|
/* FIXME: Enable this */
|
||||||
|
#if 0
|
||||||
sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
|
sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
|
||||||
|
#else
|
||||||
|
sys_mutex_unlock(&evictor_lock);
|
||||||
|
sys_sleep(SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
|
||||||
|
evictor_lock = sys_mutex_lock_e(G.evictor_scheduler_mutex);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&evictor_lock);
|
sys_mutex_unlock(&evictor_lock);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -388,8 +388,6 @@ void sys_assert_locked_e_or_s(struct sys_lock *lock, struct sys_mutex *mutex);
|
|||||||
struct sys_condition_variable *sys_condition_variable_alloc(void);
|
struct sys_condition_variable *sys_condition_variable_alloc(void);
|
||||||
void sys_condition_variable_release(struct sys_condition_variable *sys_cv);
|
void sys_condition_variable_release(struct sys_condition_variable *sys_cv);
|
||||||
void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock);
|
void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock);
|
||||||
void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, struct sys_lock *lock, f64 seconds);
|
|
||||||
void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 count);
|
|
||||||
void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv);
|
void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
257
src/sys_win32.c
257
src/sys_win32.c
@ -35,25 +35,13 @@
|
|||||||
#define FIBER_STACK_SIZE MEGABYTE(4)
|
#define FIBER_STACK_SIZE MEGABYTE(4)
|
||||||
|
|
||||||
struct win32_mutex {
|
struct win32_mutex {
|
||||||
SRWLOCK srwlock;
|
volatile LONG state; /* Lower 30 bits = reader count, bit 30 = writer waiting, bit 31 = writer held */
|
||||||
struct win32_mutex *next_free;
|
struct win32_mutex *next_free;
|
||||||
|
|
||||||
#if PROFILING_LOCKS
|
|
||||||
__proflock_ctx(profiling_ctx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if RTC
|
|
||||||
u64 owner_tid;
|
|
||||||
struct atomic_i64 count;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct win32_condition_variable {
|
struct win32_condition_variable {
|
||||||
CONDITION_VARIABLE condition_variable;
|
struct atomic_u64 wake_gen;
|
||||||
struct win32_condition_variable *next_free;
|
struct win32_condition_variable *next_free;
|
||||||
#if RTC
|
|
||||||
struct atomic_i64 num_yielders;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct win32_thread {
|
struct win32_thread {
|
||||||
@ -393,7 +381,7 @@ GLOBAL struct {
|
|||||||
|
|
||||||
|
|
||||||
INTERNAL struct fiber *fiber_from_id(i32 id);
|
INTERNAL struct fiber *fiber_from_id(i32 id);
|
||||||
INTERNAL void fiber_yield(struct fiber *fiber, struct fiber *parent_fiber, struct yield_param *param);
|
INTERNAL void fiber_yield(struct fiber *fiber, struct fiber *parent_fiber);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -416,7 +404,8 @@ INTERNAL void fiber_yield(struct fiber *fiber, struct fiber *parent_fiber, struc
|
|||||||
|
|
||||||
void sys_wait(void *addr, void *cmp, u32 size)
|
void sys_wait(void *addr, void *cmp, u32 size)
|
||||||
{
|
{
|
||||||
#if 1
|
__prof;
|
||||||
|
#if 0
|
||||||
WaitOnAddress(addr, cmp, size, INFINITE);
|
WaitOnAddress(addr, cmp, size, INFINITE);
|
||||||
#else
|
#else
|
||||||
struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
|
struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
|
||||||
@ -425,7 +414,7 @@ void sys_wait(void *addr, void *cmp, u32 size)
|
|||||||
if (parent_fiber_id > 0) {
|
if (parent_fiber_id > 0) {
|
||||||
#if 1
|
#if 1
|
||||||
/* Yield if job fiber */
|
/* Yield if job fiber */
|
||||||
struct yield_param param = {
|
*fiber->yield_param = (struct yield_param) {
|
||||||
.kind = YIELD_KIND_WAIT,
|
.kind = YIELD_KIND_WAIT,
|
||||||
.wait = {
|
.wait = {
|
||||||
.addr = addr,
|
.addr = addr,
|
||||||
@ -433,7 +422,8 @@ void sys_wait(void *addr, void *cmp, u32 size)
|
|||||||
.size = size
|
.size = size
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fiber_yield(fiber, fiber_from_id(parent_fiber_id), ¶m);
|
struct fiber *parent_fiber = fiber_from_id(parent_fiber_id);
|
||||||
|
fiber_yield(fiber, parent_fiber);
|
||||||
#else
|
#else
|
||||||
while (MEMEQ(addr, cmp, size)) {
|
while (MEMEQ(addr, cmp, size)) {
|
||||||
ix_pause();
|
ix_pause();
|
||||||
@ -447,7 +437,7 @@ void sys_wait(void *addr, void *cmp, u32 size)
|
|||||||
|
|
||||||
void sys_wake_all(void *addr)
|
void sys_wake_all(void *addr)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 1
|
||||||
u64 wait_bin_index = (u64)addr % NUM_WAIT_BINS;
|
u64 wait_bin_index = (u64)addr % NUM_WAIT_BINS;
|
||||||
struct wait_bin *bin = &G.wait_bins[wait_bin_index];
|
struct wait_bin *bin = &G.wait_bins[wait_bin_index];
|
||||||
|
|
||||||
@ -472,7 +462,7 @@ void sys_wake_all(void *addr)
|
|||||||
for (struct yielder *yielder = wait_list->first_yielder; yielder; yielder = yielder->next) {
|
for (struct yielder *yielder = wait_list->first_yielder; yielder; yielder = yielder->next) {
|
||||||
enum job_queue_kind queue_kind = yielder->job_queue_kind;
|
enum job_queue_kind queue_kind = yielder->job_queue_kind;
|
||||||
i32 index = queue_counts[queue_kind]++;
|
i32 index = queue_counts[queue_kind]++;
|
||||||
struct yielder **array = queue_yielder_arrays[index];
|
struct yielder **array = queue_yielder_arrays[queue_kind];
|
||||||
array[index] = yielder;
|
array[index] = yielder;
|
||||||
}
|
}
|
||||||
/* Push jobs */
|
/* Push jobs */
|
||||||
@ -511,11 +501,17 @@ void sys_wake_all(void *addr)
|
|||||||
atomic_i32_fetch_set(&queue->lock, 0);
|
atomic_i32_fetch_set(&queue->lock, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Free yielders */
|
||||||
|
wait_list->last_yielder->next = wait_list->first_free_yielder;
|
||||||
|
wait_list->first_free_yielder = wait_list->first_yielder;
|
||||||
|
wait_list->first_yielder = NULL;
|
||||||
|
wait_list->last_yielder = NULL;
|
||||||
|
wait_list->num_yielders = 0;
|
||||||
}
|
}
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomic_i32_fetch_set(&bin->lock, 1);
|
atomic_i32_fetch_set(&bin->lock, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Wake blocking waiters */
|
/* Wake blocking waiters */
|
||||||
@ -692,7 +688,7 @@ i32 sys_current_fiber_id(void)
|
|||||||
return (i32)(i64)GetFiberData();
|
return (i32)(i64)GetFiberData();
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void fiber_yield(struct fiber *fiber, struct fiber *parent_fiber, struct yield_param *param)
|
INTERNAL void fiber_yield(struct fiber *fiber, struct fiber *parent_fiber)
|
||||||
{
|
{
|
||||||
ASSERT(fiber->id == sys_current_fiber_id());
|
ASSERT(fiber->id == sys_current_fiber_id());
|
||||||
ASSERT(parent_fiber->id == fiber->parent_id);
|
ASSERT(parent_fiber->id == fiber->parent_id);
|
||||||
@ -701,7 +697,6 @@ INTERNAL void fiber_yield(struct fiber *fiber, struct fiber *parent_fiber, struc
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
__prof_fiber_leave;
|
__prof_fiber_leave;
|
||||||
fiber->yield_param = param;
|
|
||||||
SwitchToFiber(parent_fiber->addr);
|
SwitchToFiber(parent_fiber->addr);
|
||||||
__prof_fiber_enter(fiber->name_cstr, PROF_THREAD_GROUP_FIBERS + fiber->id);
|
__prof_fiber_enter(fiber->name_cstr, PROF_THREAD_GROUP_FIBERS + fiber->id);
|
||||||
}
|
}
|
||||||
@ -714,8 +709,8 @@ void sys_yield(void)
|
|||||||
i32 parent_id = fiber->parent_id;
|
i32 parent_id = fiber->parent_id;
|
||||||
if (parent_id > 0) { /* Top level fibers should not yield */
|
if (parent_id > 0) { /* Top level fibers should not yield */
|
||||||
struct fiber *parent_fiber = fiber_from_id(parent_id);
|
struct fiber *parent_fiber = fiber_from_id(parent_id);
|
||||||
struct yield_param param = { .kind = YIELD_KIND_COOPERATIVE };
|
fiber->yield_param->kind = YIELD_KIND_COOPERATIVE;
|
||||||
fiber_yield(fiber, parent_fiber, ¶m);
|
fiber_yield(fiber, parent_fiber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -764,26 +759,24 @@ INTERNAL void job_fiber_entry(void *id_ptr)
|
|||||||
{
|
{
|
||||||
i32 id = (i32)(i64)id_ptr;
|
i32 id = (i32)(i64)id_ptr;
|
||||||
struct fiber *fiber = fiber_from_id(id);
|
struct fiber *fiber = fiber_from_id(id);
|
||||||
struct yield_param yield = ZI;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
__prof_fiber_enter(fiber->name_cstr, PROF_THREAD_GROUP_FIBERS + fiber->id);
|
__prof_fiber_enter(fiber->name_cstr, PROF_THREAD_GROUP_FIBERS + fiber->id);
|
||||||
i32 parent_id = fiber->parent_id;
|
|
||||||
struct fiber *parent_fiber = fiber_from_id(parent_id);
|
|
||||||
void *parent_fiber_addr = parent_fiber->addr;
|
|
||||||
/* Run job */
|
/* Run job */
|
||||||
{
|
{
|
||||||
__profscope(Run job);
|
__profscope(Run job);
|
||||||
yield.kind = YIELD_KIND_NONE;
|
fiber->yield_param->kind = YIELD_KIND_NONE;
|
||||||
fiber->yield_param = &yield;
|
|
||||||
struct sys_job_data data = ZI;
|
struct sys_job_data data = ZI;
|
||||||
data.id = fiber->job_id;
|
data.id = fiber->job_id;
|
||||||
data.sig = fiber->job_sig;
|
data.sig = fiber->job_sig;
|
||||||
fiber->job_func(data);
|
fiber->job_func(data);
|
||||||
yield.kind = YIELD_KIND_DONE;
|
fiber->yield_param->kind = YIELD_KIND_DONE;
|
||||||
fiber->yield_param = &yield;
|
|
||||||
}
|
}
|
||||||
__prof_fiber_leave;
|
__prof_fiber_leave;
|
||||||
SwitchToFiber(parent_fiber_addr);
|
{
|
||||||
|
i32 parent_id = fiber->parent_id;
|
||||||
|
struct fiber *parent_fiber = fiber_from_id(parent_id);
|
||||||
|
SwitchToFiber(parent_fiber->addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,6 +786,7 @@ INTERNAL void job_fiber_entry(void *id_ptr)
|
|||||||
|
|
||||||
INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
||||||
{
|
{
|
||||||
|
__prof;
|
||||||
struct worker_ctx *ctx = worker_ctx_arg;
|
struct worker_ctx *ctx = worker_ctx_arg;
|
||||||
(UNUSED)ctx;
|
(UNUSED)ctx;
|
||||||
|
|
||||||
@ -881,36 +875,38 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
|||||||
if (!job_fiber) {
|
if (!job_fiber) {
|
||||||
job_fiber = fiber_alloc(FIBER_KIND_JOB_WORKER);
|
job_fiber = fiber_alloc(FIBER_KIND_JOB_WORKER);
|
||||||
}
|
}
|
||||||
|
struct yield_param yield = ZI;
|
||||||
job_fiber->job_func = job_func;
|
job_fiber->job_func = job_func;
|
||||||
job_fiber->job_sig = job_sig;
|
job_fiber->job_sig = job_sig;
|
||||||
job_fiber->job_id = job_id;
|
job_fiber->job_id = job_id;
|
||||||
job_fiber->job_priority = job_priority;
|
job_fiber->job_priority = job_priority;
|
||||||
job_fiber->parent_id = worker_fiber_id;
|
job_fiber->parent_id = worker_fiber_id;
|
||||||
|
job_fiber->yield_param = &yield;
|
||||||
b32 done = false;
|
b32 done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
SwitchToFiber(job_fiber->addr);
|
SwitchToFiber(job_fiber->addr);
|
||||||
struct yield_param *yield_param = job_fiber->yield_param;
|
switch (yield.kind) {
|
||||||
enum yield_kind yield_kind = yield_param ? yield_param->kind : YIELD_KIND_NONE;
|
|
||||||
switch (yield_kind) {
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
/* Invalid yield kind */
|
/* Invalid yield kind */
|
||||||
sys_panic(LIT("Invalid fiber yield"));
|
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||||
|
sys_panic(string_format(scratch.arena, LIT("Invalid fiber yield kind \"%F\""), FMT_SINT(yield.kind)));
|
||||||
|
scratch_end(scratch);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case YIELD_KIND_WAIT:
|
case YIELD_KIND_WAIT:
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
void *wait_addr = yield_param->wait.addr;
|
void *wait_addr = yield.wait.addr;
|
||||||
void *wait_cmp = yield_param->wait.cmp;
|
void *wait_cmp = yield.wait.cmp;
|
||||||
u32 wait_size = yield_param->wait.size;
|
u32 wait_size = yield.wait.size;
|
||||||
|
|
||||||
u64 wait_bin_index = (u64)wait_addr % NUM_WAIT_BINS;
|
u64 wait_bin_index = (u64)wait_addr % NUM_WAIT_BINS;
|
||||||
struct wait_bin *bin = &G.wait_bins[wait_bin_index];
|
struct wait_bin *bin = &G.wait_bins[wait_bin_index];
|
||||||
|
|
||||||
while (atomic_i32_fetch_test_set(&bin->lock, 0, 1) != 0) ix_pause();
|
while (atomic_i32_fetch_test_set(&bin->lock, 0, 1) != 0) ix_pause();
|
||||||
{
|
{
|
||||||
if (!MEMEQ(wait_addr, wait_cmp, wait_size)) {
|
if (MEMEQ(wait_addr, wait_cmp, wait_size)) {
|
||||||
/* Search addr wait list in bin */
|
/* Search addr wait list in bin */
|
||||||
struct wait_list *wait_list = NULL;
|
struct wait_list *wait_list = NULL;
|
||||||
for (struct wait_list *tmp = bin->first_wait_list; tmp && !wait_list; tmp = tmp->next_in_bin) {
|
for (struct wait_list *tmp = bin->first_wait_list; tmp && !wait_list; tmp = tmp->next_in_bin) {
|
||||||
@ -978,7 +974,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
|||||||
atomic_i32_fetch_set(&bin->lock, 0);
|
atomic_i32_fetch_set(&bin->lock, 0);
|
||||||
#else
|
#else
|
||||||
(UNUSED)job_queue_kind;
|
(UNUSED)job_queue_kind;
|
||||||
ASSERT(false);
|
//ASSERT(false);
|
||||||
#endif
|
#endif
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -993,13 +989,6 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
__profscope(Worker wait);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL SYS_THREAD_DEF(test_entry, _)
|
INTERNAL SYS_THREAD_DEF(test_entry, _)
|
||||||
@ -2515,17 +2504,7 @@ void sys_window_cursor_disable_clip(struct sys_window *sys_window)
|
|||||||
|
|
||||||
INTERNAL void win32_mutex_init(struct win32_mutex *m)
|
INTERNAL void win32_mutex_init(struct win32_mutex *m)
|
||||||
{
|
{
|
||||||
#if PROFILING_LOCKS
|
|
||||||
__proflock_ctx(profiling_ctx) = m->profiling_ctx;
|
|
||||||
#endif
|
|
||||||
MEMZERO_STRUCT(m);
|
MEMZERO_STRUCT(m);
|
||||||
m->srwlock = (SRWLOCK)SRWLOCK_INIT;
|
|
||||||
#if PROFILING_LOCKS
|
|
||||||
if (!profiling_ctx) {
|
|
||||||
__proflock_alloc(profiling_ctx);
|
|
||||||
}
|
|
||||||
m->profiling_ctx = profiling_ctx;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sys_mutex *sys_mutex_alloc(void)
|
struct sys_mutex *sys_mutex_alloc(void)
|
||||||
@ -2550,7 +2529,6 @@ void sys_mutex_release(struct sys_mutex *mutex)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct win32_mutex *m = (struct win32_mutex *)mutex;
|
struct win32_mutex *m = (struct win32_mutex *)mutex;
|
||||||
ASSERT(atomic_i64_fetch(&m->count) == 0); /* Mutex should be unlocked */
|
|
||||||
{
|
{
|
||||||
struct sys_lock lock = sys_mutex_lock_e(G.mutexes_mutex);
|
struct sys_lock lock = sys_mutex_lock_e(G.mutexes_mutex);
|
||||||
m->next_free = G.first_free_mutex;
|
m->next_free = G.first_free_mutex;
|
||||||
@ -2562,13 +2540,22 @@ void sys_mutex_release(struct sys_mutex *mutex)
|
|||||||
struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
|
struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
|
||||||
{
|
{
|
||||||
struct win32_mutex *m = (struct win32_mutex *)mutex;
|
struct win32_mutex *m = (struct win32_mutex *)mutex;
|
||||||
__proflock_before_exclusive_lock(m->profiling_ctx);
|
{
|
||||||
AcquireSRWLockExclusive((SRWLOCK *)&m->srwlock);
|
while (true) {
|
||||||
__proflock_after_exclusive_lock(m->profiling_ctx);
|
//LONG expected = 0;
|
||||||
#if RTC
|
if (InterlockedCompareExchange(&m->state, 0x80000000, 0) == 0) {
|
||||||
m->owner_tid = (u64)GetCurrentThreadId();
|
break; /* Acquired exclusive */
|
||||||
atomic_i64_fetch_add(&m->count, 1);
|
} else {
|
||||||
#endif
|
/* Set writer pending */
|
||||||
|
LONG old;
|
||||||
|
do {
|
||||||
|
old = m->state;
|
||||||
|
if (old & 0x40000000) break; /* Already pending */
|
||||||
|
} while (InterlockedCompareExchange(&m->state, old | 0x40000000, old) != old);
|
||||||
|
sys_wait((void *)&m->state, (void *)&old, sizeof(old));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
struct sys_lock lock = ZI;
|
struct sys_lock lock = ZI;
|
||||||
lock.exclusive = true;
|
lock.exclusive = true;
|
||||||
lock.mutex = mutex;
|
lock.mutex = mutex;
|
||||||
@ -2578,12 +2565,19 @@ struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
|
|||||||
struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
|
struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
|
||||||
{
|
{
|
||||||
struct win32_mutex *m = (struct win32_mutex *)mutex;
|
struct win32_mutex *m = (struct win32_mutex *)mutex;
|
||||||
__proflock_before_shared_lock(m->profiling_ctx);
|
{
|
||||||
AcquireSRWLockShared((SRWLOCK *)&m->srwlock);
|
while (true) {
|
||||||
__proflock_after_shared_lock(m->profiling_ctx);
|
LONG old = m->state;
|
||||||
#if RTC
|
/* If writer not held or pending */
|
||||||
atomic_i64_fetch_add(&m->count, 1);
|
if ((old & 0xC0000000) == 0) {
|
||||||
#endif
|
if (InterlockedCompareExchange(&m->state, old + 1, old) == old) {
|
||||||
|
break; /* Acquired shared */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sys_wait((void *)&m->state, &old, sizeof(old));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
struct sys_lock lock = ZI;
|
struct sys_lock lock = ZI;
|
||||||
lock.mutex = mutex;
|
lock.mutex = mutex;
|
||||||
return lock;
|
return lock;
|
||||||
@ -2592,16 +2586,15 @@ struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
|
|||||||
void sys_mutex_unlock(struct sys_lock *lock)
|
void sys_mutex_unlock(struct sys_lock *lock)
|
||||||
{
|
{
|
||||||
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
|
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
|
||||||
#if RTC
|
|
||||||
atomic_i64_fetch_add(&m->count, -1);
|
|
||||||
m->owner_tid = 0;
|
|
||||||
#endif
|
|
||||||
if (lock->exclusive) {
|
if (lock->exclusive) {
|
||||||
ReleaseSRWLockExclusive((SRWLOCK *)&m->srwlock);
|
//LONG old = m->state;
|
||||||
__proflock_after_exclusive_unlock(m->profiling_ctx);
|
InterlockedExchange(&m->state, 0); /* Clear all bits */
|
||||||
|
sys_wake_all((void *)&m->state);
|
||||||
} else {
|
} else {
|
||||||
ReleaseSRWLockShared((SRWLOCK *)&m->srwlock);
|
LONG old = InterlockedDecrement(&m->state);
|
||||||
__proflock_after_shared_unlock(m->profiling_ctx);
|
if (old == 1) {
|
||||||
|
sys_wake_all((void *)&m->state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(lock);
|
MEMZERO_STRUCT(lock);
|
||||||
}
|
}
|
||||||
@ -2633,14 +2626,11 @@ INTERNAL struct win32_condition_variable *win32_condition_variable_alloc(void)
|
|||||||
cv = G.first_free_condition_variable;
|
cv = G.first_free_condition_variable;
|
||||||
G.first_free_condition_variable = cv->next_free;
|
G.first_free_condition_variable = cv->next_free;
|
||||||
} else {
|
} else {
|
||||||
cv = arena_push(G.condition_variables_arena, struct win32_condition_variable);
|
cv = arena_push_no_zero(G.condition_variables_arena, struct win32_condition_variable);
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&lock);
|
sys_mutex_unlock(&lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMZERO_STRUCT(cv);
|
MEMZERO_STRUCT(cv);
|
||||||
InitializeConditionVariable(&cv->condition_variable);
|
|
||||||
|
|
||||||
return cv;
|
return cv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2663,105 +2653,36 @@ void sys_condition_variable_release(struct sys_condition_variable *sys_cv)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
||||||
/* Condition variable must not have any sleepers (signal before releasing) */
|
|
||||||
ASSERT(atomic_i64_fetch(&cv->num_yielders) == 0);
|
|
||||||
win32_condition_variable_release(cv);
|
win32_condition_variable_release(cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock)
|
void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock)
|
||||||
{
|
{
|
||||||
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
||||||
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
|
struct sys_mutex *mutex = lock->mutex;
|
||||||
b32 exclusive = lock->exclusive;
|
b32 exclusive = lock->exclusive;
|
||||||
#if RTC
|
u64 old_wake_gen = atomic_u64_fetch(&cv->wake_gen);
|
||||||
atomic_i64_fetch_add(&cv->num_yielders, 1);
|
u64 wake_gen = old_wake_gen;
|
||||||
if (exclusive) {
|
|
||||||
m->owner_tid = 0;
|
|
||||||
}
|
|
||||||
atomic_i64_fetch_add(&m->count, -1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* TODO: Correct profiling of internal condition variable sleep / wait mutex state */
|
|
||||||
if (exclusive) {
|
|
||||||
__proflock_after_exclusive_unlock(m->profiling_ctx);
|
|
||||||
} else {
|
|
||||||
__proflock_after_shared_unlock(m->profiling_ctx);
|
|
||||||
}
|
|
||||||
SleepConditionVariableSRW(&cv->condition_variable, (SRWLOCK *)&m->srwlock, INFINITE, exclusive ? 0 : CONDITION_VARIABLE_LOCKMODE_SHARED);
|
|
||||||
if (exclusive) {
|
|
||||||
__proflock_before_exclusive_lock(m->profiling_ctx);
|
|
||||||
__proflock_after_exclusive_lock(m->profiling_ctx);
|
|
||||||
} else {
|
|
||||||
__proflock_before_shared_lock(m->profiling_ctx);
|
|
||||||
__proflock_after_shared_lock(m->profiling_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if RTC
|
|
||||||
atomic_i64_fetch_add(&m->count, 1);
|
|
||||||
if (exclusive) {
|
|
||||||
m->owner_tid = (u64)GetCurrentThreadId();
|
|
||||||
}
|
|
||||||
atomic_i64_fetch_add(&cv->num_yielders, -1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, struct sys_lock *lock, f64 seconds)
|
|
||||||
{
|
{
|
||||||
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
sys_mutex_unlock(lock);
|
||||||
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
|
do {
|
||||||
b32 exclusive = lock->exclusive;
|
sys_wait(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen));
|
||||||
#if RTC
|
wake_gen = atomic_u64_fetch(&cv->wake_gen);
|
||||||
atomic_i64_fetch_add(&cv->num_yielders, 1);
|
} while (wake_gen == old_wake_gen);
|
||||||
|
sys_wake_all(&cv->wake_gen);
|
||||||
if (exclusive) {
|
if (exclusive) {
|
||||||
m->owner_tid = 0;
|
*lock = sys_mutex_lock_e(mutex);
|
||||||
}
|
|
||||||
atomic_i64_fetch_add(&m->count, -1);
|
|
||||||
#endif
|
|
||||||
u32 ms = (u32)math_round_to_int((f32)seconds * 1000.f);
|
|
||||||
|
|
||||||
/* TODO: Correct profiling of internal condition variable sleep / wait mutex state */
|
|
||||||
if (exclusive) {
|
|
||||||
__proflock_after_exclusive_unlock(m->profiling_ctx);
|
|
||||||
} else {
|
} else {
|
||||||
__proflock_after_shared_unlock(m->profiling_ctx);
|
*lock = sys_mutex_lock_s(mutex);
|
||||||
}
|
}
|
||||||
SleepConditionVariableSRW(&cv->condition_variable, (SRWLOCK *)&m->srwlock, ms, exclusive ? 0 : CONDITION_VARIABLE_LOCKMODE_SHARED);
|
|
||||||
if (exclusive) {
|
|
||||||
__proflock_before_exclusive_lock(m->profiling_ctx);
|
|
||||||
__proflock_after_exclusive_lock(m->profiling_ctx);
|
|
||||||
} else {
|
|
||||||
__proflock_before_shared_lock(m->profiling_ctx);
|
|
||||||
__proflock_after_shared_lock(m->profiling_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if RTC
|
|
||||||
atomic_i64_fetch_add(&m->count, 1);
|
|
||||||
if (exclusive) {
|
|
||||||
m->owner_tid = (u64)GetCurrentThreadId();
|
|
||||||
}
|
|
||||||
atomic_i64_fetch_add(&cv->num_yielders, -1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 count)
|
|
||||||
{
|
|
||||||
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
|
||||||
/* Windows will wake all waiters if many single-wakes occur anyway, so we
|
|
||||||
* might as well wake all ourselves.
|
|
||||||
* https://devblogs.microsoft.com/oldnewthing/20180201-00/?p=97946 */
|
|
||||||
if (count <= 24) {
|
|
||||||
for (u32 i = 0; i < count; ++i) {
|
|
||||||
WakeConditionVariable(&cv->condition_variable);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WakeAllConditionVariable(&cv->condition_variable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv)
|
void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv)
|
||||||
{
|
{
|
||||||
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
|
||||||
WakeAllConditionVariable(&cv->condition_variable);
|
atomic_u64_fetch_add_u64(&cv->wake_gen, 1);
|
||||||
|
sys_wake_all(&cv->wake_gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user