F4MP/f4mp_originalcode/thirdparty/zpl/code/source/threading/sync.c

76 lines
2 KiB
C
Raw Normal View History

// file: source/threading/sync.c
#ifdef ZPL_EDITOR
#include <zpl.h>
#endif
ZPL_BEGIN_C_DECLS
void zpl_sync_init(zpl_sync *s) {
zpl_zero_item(s);
zpl_mutex_init(&s->mutex);
zpl_mutex_init(&s->start);
zpl_semaphore_init(&s->release);
}
void zpl_sync_destroy(zpl_sync *s) {
if (s->waiting) {
ZPL_PANIC("Cannot destroy while threads are waiting!");
}
zpl_mutex_destroy(&s->mutex);
zpl_mutex_destroy(&s->start);
zpl_semaphore_destroy(&s->release);
}
void zpl_sync_set_target(zpl_sync *s, zpl_i32 count) {
zpl_mutex_lock(&s->start);
zpl_mutex_lock(&s->mutex);
ZPL_ASSERT(s->target == 0);
s->target = count;
s->current = 0;
s->waiting = 0;
zpl_mutex_unlock(&s->mutex);
}
void zpl_sync_release(zpl_sync *s) {
if (s->waiting) {
zpl_semaphore_release(&s->release);
} else {
s->target = 0;
zpl_mutex_unlock(&s->start);
}
}
zpl_i32 zpl_sync_reach(zpl_sync *s) {
zpl_i32 n;
zpl_mutex_lock(&s->mutex);
ZPL_ASSERT(s->current < s->target);
n = ++s->current; // NOTE: Record this value to avoid possible race if `return s->current` was done
if (s->current == s->target)
zpl_sync_release(s);
zpl_mutex_unlock(&s->mutex);
return n;
}
void zpl_sync_reach_and_wait(zpl_sync *s) {
zpl_mutex_lock(&s->mutex);
ZPL_ASSERT(s->current < s->target);
s->current++;
if (s->current == s->target) {
zpl_sync_release(s);
zpl_mutex_unlock(&s->mutex);
} else {
s->waiting++; // NOTE: Waiting, so one more waiter
zpl_mutex_unlock(&s->mutex); // NOTE: Release the mutex to other threads
zpl_semaphore_wait(&s->release); // NOTE: Wait for merge completion
zpl_mutex_lock(&s->mutex); // NOTE: On merge completion, lock mutex
s->waiting--; // NOTE: Done waiting
zpl_sync_release(s); // NOTE: Restart the next waiter
zpl_mutex_unlock(&s->mutex);
}
}
ZPL_END_C_DECLS