mirror of
https://github.com/Jous99/F4MP.git
synced 2026-01-13 00:40:53 +01:00
76 lines
2 KiB
C
76 lines
2 KiB
C
|
|
// 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
|