replace semaphore usage w/ condition variable
This commit is contained in:
parent
e3830fccae
commit
925ef5a482
@ -257,7 +257,7 @@ INTERNAL struct sheet init_sheet_from_ase_result(struct arena *arena, struct ase
|
|||||||
return sheet;
|
return sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void node_load(struct cache_node *n, struct sheet_tag tag)
|
INTERNAL void sheet_load(struct cache_node *n, struct sheet_tag tag)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
@ -428,7 +428,7 @@ INTERNAL struct sheet *sheet_from_tag_internal(struct sheet_scope *scope, struct
|
|||||||
} else if (state == CACHE_NODE_STATE_NONE) {
|
} else if (state == CACHE_NODE_STATE_NONE) {
|
||||||
if (atomic_u32_eval_compare_exchange(&n->state, CACHE_NODE_STATE_NONE, CACHE_NODE_STATE_QUEUED) == CACHE_NODE_STATE_NONE) {
|
if (atomic_u32_eval_compare_exchange(&n->state, CACHE_NODE_STATE_NONE, CACHE_NODE_STATE_QUEUED) == CACHE_NODE_STATE_NONE) {
|
||||||
if (await) {
|
if (await) {
|
||||||
node_load(n, tag);
|
sheet_load(n, tag);
|
||||||
res = &n->sheet;
|
res = &n->sheet;
|
||||||
} else {
|
} else {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|||||||
22
src/sys.h
22
src/sys.h
@ -302,11 +302,6 @@ struct sys_mutex {
|
|||||||
u64 handle;
|
u64 handle;
|
||||||
#if RTC
|
#if RTC
|
||||||
u64 owner_tid;
|
u64 owner_tid;
|
||||||
# if OS_WINDOWS
|
|
||||||
wchar_t *owner_name;
|
|
||||||
# else
|
|
||||||
char *owner_name;
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -358,7 +353,7 @@ void sys_rw_mutex_assert_locked_exclusive(struct sys_rw_mutex *mutex);
|
|||||||
struct sys_condition_variable {
|
struct sys_condition_variable {
|
||||||
u64 handle;
|
u64 handle;
|
||||||
#if RTC
|
#if RTC
|
||||||
struct atomic_i64 num_sleepers;
|
struct atomic_i64 num_waiters;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -367,20 +362,7 @@ void sys_condition_variable_release(struct sys_condition_variable *cv);
|
|||||||
void sys_condition_variable_wait(struct sys_condition_variable *cv, struct sys_mutex *mutex);
|
void sys_condition_variable_wait(struct sys_condition_variable *cv, struct sys_mutex *mutex);
|
||||||
void sys_condition_variable_wait_time(struct sys_condition_variable *cv, struct sys_mutex *mutex, f64 seconds);
|
void sys_condition_variable_wait_time(struct sys_condition_variable *cv, struct sys_mutex *mutex, f64 seconds);
|
||||||
void sys_condition_variable_signal(struct sys_condition_variable *cv);
|
void sys_condition_variable_signal(struct sys_condition_variable *cv);
|
||||||
|
void sys_condition_variable_broadcast(struct sys_condition_variable *cv);
|
||||||
/* ========================== *
|
|
||||||
* Semaphore
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct sys_semaphore {
|
|
||||||
u64 handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sys_semaphore sys_semaphore_alloc(u32 max_count);
|
|
||||||
void sys_semaphore_release(struct sys_semaphore *semaphore);
|
|
||||||
void sys_semaphore_wait(struct sys_semaphore *semaphore);
|
|
||||||
void sys_semaphore_wait_timed(struct sys_semaphore *semaphore, f64 seconds);
|
|
||||||
void sys_semaphore_signal(struct sys_semaphore *semaphore, u32 count);
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Thread local storage
|
* Thread local storage
|
||||||
|
|||||||
@ -1251,7 +1251,6 @@ void sys_mutex_lock(struct sys_mutex *mutex)
|
|||||||
AcquireSRWLockExclusive((SRWLOCK *)&mutex->handle);
|
AcquireSRWLockExclusive((SRWLOCK *)&mutex->handle);
|
||||||
#if RTC
|
#if RTC
|
||||||
mutex->owner_tid = (u64)GetCurrentThreadId();
|
mutex->owner_tid = (u64)GetCurrentThreadId();
|
||||||
GetThreadDescription(GetCurrentThread(), &mutex->owner_name);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1259,7 +1258,6 @@ void sys_mutex_unlock(struct sys_mutex *mutex)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
#if RTC
|
#if RTC
|
||||||
mutex->owner_name = L"None";
|
|
||||||
mutex->owner_tid = 0;
|
mutex->owner_tid = 0;
|
||||||
#endif
|
#endif
|
||||||
ReleaseSRWLockExclusive((SRWLOCK *)&mutex->handle);
|
ReleaseSRWLockExclusive((SRWLOCK *)&mutex->handle);
|
||||||
@ -1393,7 +1391,7 @@ void sys_condition_variable_release(struct sys_condition_variable *cv)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
/* Condition variable must not have any sleepers (signal before releasing) */
|
/* Condition variable must not have any sleepers (signal before releasing) */
|
||||||
ASSERT(atomic_i64_eval(&cv->num_sleepers) == 0);
|
ASSERT(atomic_i64_eval(&cv->num_waiters) == 0);
|
||||||
win32_condition_variable_release((struct win32_condition_variable *)cv->handle);
|
win32_condition_variable_release((struct win32_condition_variable *)cv->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1401,11 +1399,13 @@ void sys_condition_variable_wait(struct sys_condition_variable *cv, struct sys_m
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
#if RTC
|
#if RTC
|
||||||
atomic_i64_inc_eval(&cv->num_sleepers);
|
atomic_i64_inc_eval(&cv->num_waiters);
|
||||||
|
mutex->owner_tid = 0;
|
||||||
#endif
|
#endif
|
||||||
SleepConditionVariableSRW((PCONDITION_VARIABLE)cv->handle, (SRWLOCK *)&mutex->handle, INFINITE, 0);
|
SleepConditionVariableSRW((PCONDITION_VARIABLE)cv->handle, (SRWLOCK *)&mutex->handle, INFINITE, 0);
|
||||||
#if RTC
|
#if RTC
|
||||||
atomic_i64_dec_eval(&cv->num_sleepers);
|
mutex->owner_tid = (u64)GetCurrentThreadId();
|
||||||
|
atomic_i64_dec_eval(&cv->num_waiters);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1413,61 +1413,29 @@ void sys_condition_variable_wait_time(struct sys_condition_variable *cv, struct
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
#if RTC
|
#if RTC
|
||||||
atomic_i64_inc_eval(&cv->num_sleepers);
|
atomic_i64_inc_eval(&cv->num_waiters);
|
||||||
|
mutex->owner_tid = 0;
|
||||||
#endif
|
#endif
|
||||||
u32 ms = (u32)math_round_to_int((f32)seconds * 1000.f);
|
u32 ms = (u32)math_round_to_int((f32)seconds * 1000.f);
|
||||||
SleepConditionVariableSRW((PCONDITION_VARIABLE)cv->handle, (SRWLOCK *)&mutex->handle, ms, 0);
|
SleepConditionVariableSRW((PCONDITION_VARIABLE)cv->handle, (SRWLOCK *)&mutex->handle, ms, 0);
|
||||||
#if RTC
|
#if RTC
|
||||||
atomic_i64_dec_eval(&cv->num_sleepers);
|
mutex->owner_tid = (u64)GetCurrentThreadId();
|
||||||
|
atomic_i64_dec_eval(&cv->num_waiters);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_condition_variable_signal(struct sys_condition_variable *cv)
|
void sys_condition_variable_signal(struct sys_condition_variable *cv)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
WakeConditionVariable((PCONDITION_VARIABLE)cv->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_condition_variable_broadcast(struct sys_condition_variable *cv)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
WakeAllConditionVariable((PCONDITION_VARIABLE)cv->handle);
|
WakeAllConditionVariable((PCONDITION_VARIABLE)cv->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Semaphore
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
/* TODO: Use similar allocation scheme to mutex & condition var for speed? */
|
|
||||||
|
|
||||||
struct sys_semaphore sys_semaphore_alloc(u32 max_count)
|
|
||||||
{
|
|
||||||
struct sys_semaphore semaphore = {
|
|
||||||
.handle = (u64)CreateSemaphoreEx(0, 0, max_count, NULL, 0, SEMAPHORE_ALL_ACCESS)
|
|
||||||
};
|
|
||||||
return semaphore;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_release(struct sys_semaphore *semaphore)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
CloseHandle((HANDLE)semaphore->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_wait(struct sys_semaphore *semaphore)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
WaitForSingleObjectEx((HANDLE)semaphore->handle, INFINITE, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_wait_timed(struct sys_semaphore *semaphore, f64 seconds)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
u32 ms = max_u32(1, math_round_to_int((f32)(seconds * 1000.0)));
|
|
||||||
WaitForSingleObjectEx((HANDLE)semaphore->handle, ms, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_signal(struct sys_semaphore *semaphore, u32 count)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
/* FIXME: Implicit mutex release means mutex debug owner info becomes invalid? */
|
|
||||||
ReleaseSemaphore((HANDLE)semaphore->handle, count, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Thread local storage
|
* Thread local storage
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -153,7 +153,7 @@ INLINE void sync_flag_set(struct sync_flag *sf)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
if (atomic_i32_eval_compare_exchange(&sf->flag, 0, 1) == 0) {
|
if (atomic_i32_eval_compare_exchange(&sf->flag, 0, 1) == 0) {
|
||||||
sys_condition_variable_signal(&sf->cv);
|
sys_condition_variable_broadcast(&sf->cv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
41
src/work.c
41
src/work.c
@ -69,10 +69,10 @@ struct work_task {
|
|||||||
GLOBAL struct {
|
GLOBAL struct {
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
|
|
||||||
|
b32 workers_shutdown;
|
||||||
struct sys_mutex mutex;
|
struct sys_mutex mutex;
|
||||||
struct sys_semaphore semaphore;
|
struct sys_condition_variable cv;
|
||||||
|
|
||||||
struct atomic_i32 workers_shutdown;
|
|
||||||
u32 worker_count;
|
u32 worker_count;
|
||||||
u32 idle_worker_count;
|
u32 idle_worker_count;
|
||||||
struct worker *worker_head;
|
struct worker *worker_head;
|
||||||
@ -116,13 +116,12 @@ struct work_startup_receipt work_startup(u32 num_worker_threads)
|
|||||||
|
|
||||||
G.arena = arena_alloc(GIGABYTE(64));
|
G.arena = arena_alloc(GIGABYTE(64));
|
||||||
G.mutex = sys_mutex_alloc();
|
G.mutex = sys_mutex_alloc();
|
||||||
G.semaphore = sys_semaphore_alloc(num_worker_threads);
|
G.cv = sys_condition_variable_alloc();
|
||||||
G.worker_count = num_worker_threads;
|
G.worker_count = num_worker_threads;
|
||||||
G.idle_worker_count = num_worker_threads;
|
G.idle_worker_count = num_worker_threads;
|
||||||
app_register_exit_callback(&work_shutdown);
|
app_register_exit_callback(&work_shutdown);
|
||||||
|
|
||||||
/* Initialize threads */
|
/* Initialize threads */
|
||||||
{
|
|
||||||
sys_mutex_lock(&G.mutex);
|
sys_mutex_lock(&G.mutex);
|
||||||
{
|
{
|
||||||
struct worker *prev = NULL;
|
struct worker *prev = NULL;
|
||||||
@ -142,7 +141,6 @@ struct work_startup_receipt work_startup(u32 num_worker_threads)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&G.mutex);
|
sys_mutex_unlock(&G.mutex);
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
|
|
||||||
@ -152,8 +150,12 @@ struct work_startup_receipt work_startup(u32 num_worker_threads)
|
|||||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(work_shutdown)
|
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(work_shutdown)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
atomic_i32_eval_exchange(&G.workers_shutdown, true);
|
sys_mutex_lock(&G.mutex);
|
||||||
sys_semaphore_signal(&G.semaphore, G.worker_count);
|
{
|
||||||
|
G.workers_shutdown = true;
|
||||||
|
sys_condition_variable_broadcast(&G.cv);
|
||||||
|
}
|
||||||
|
sys_mutex_unlock(&G.mutex);
|
||||||
for (struct worker *worker = G.worker_head; (worker = worker->next);) {
|
for (struct worker *worker = G.worker_head; (worker = worker->next);) {
|
||||||
sys_thread_wait_release(&worker->thread);
|
sys_thread_wait_release(&worker->thread);
|
||||||
}
|
}
|
||||||
@ -271,7 +273,9 @@ INTERNAL void work_schedule_assume_locked(struct work *work)
|
|||||||
G.scheduled_work_priority_tails[priority] = work;
|
G.scheduled_work_priority_tails[priority] = work;
|
||||||
|
|
||||||
WRITE_BARRIER();
|
WRITE_BARRIER();
|
||||||
sys_semaphore_signal(&G.semaphore, min_u32(work->tasks_incomplete, G.worker_count));
|
for (u64 i = 0; i < work->tasks_incomplete; ++i) {
|
||||||
|
sys_condition_variable_signal(&G.cv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void work_unschedule_assume_locked(struct work *work)
|
INTERNAL void work_unschedule_assume_locked(struct work *work)
|
||||||
@ -352,7 +356,7 @@ INTERNAL b32 work_exec_single_task_maybe_release_assume_locked(struct work *work
|
|||||||
if (work->tasks_incomplete == 0) {
|
if (work->tasks_incomplete == 0) {
|
||||||
/* Signal finished */
|
/* Signal finished */
|
||||||
work->status = WORK_STATUS_DONE;
|
work->status = WORK_STATUS_DONE;
|
||||||
sys_condition_variable_signal(&work->condition_variable_finished);
|
sys_condition_variable_broadcast(&work->condition_variable_finished);
|
||||||
|
|
||||||
/* Release */
|
/* Release */
|
||||||
work_release_assume_locked(work);
|
work_release_assume_locked(work);
|
||||||
@ -387,12 +391,20 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(worker_thread_entry_point, thread_data)
|
|||||||
.is_worker = true
|
.is_worker = true
|
||||||
};
|
};
|
||||||
|
|
||||||
while (!atomic_i32_eval(&G.workers_shutdown)) {
|
while (true) {
|
||||||
sys_semaphore_wait_timed(&G.semaphore, 0.500); /* Timed to poll G.shutdown */
|
|
||||||
while (G.scheduled_work_head) {
|
|
||||||
/* Do work from top */
|
|
||||||
sys_mutex_lock(&G.mutex);
|
sys_mutex_lock(&G.mutex);
|
||||||
{
|
{
|
||||||
|
/* Check for exit */
|
||||||
|
if (G.workers_shutdown) {
|
||||||
|
sys_mutex_unlock(&G.mutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait */
|
||||||
|
sys_condition_variable_wait(&G.cv, &G.mutex);
|
||||||
|
|
||||||
|
/* Do work from top */
|
||||||
|
while (G.scheduled_work_head) {
|
||||||
struct work *work = G.scheduled_work_head;
|
struct work *work = G.scheduled_work_head;
|
||||||
if (work) {
|
if (work) {
|
||||||
__profscope(work_pool_task);
|
__profscope(work_pool_task);
|
||||||
@ -401,8 +413,9 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(worker_thread_entry_point, thread_data)
|
|||||||
++G.idle_worker_count;
|
++G.idle_worker_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&G.mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sys_mutex_unlock(&G.mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user