Add condvars and events via parking lot
This commit is contained in:
+51
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#include <zinnia/atomic.h>
|
||||
#include <zinnia/event.h>
|
||||
#include <zinnia/park.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/sched.h>
|
||||
|
||||
constexpr uint32_t EVENT_SET = (1u << 0);
|
||||
constexpr uint32_t EVENT_PARKED = (1u << 1); // At least one task might be parked on the event.
|
||||
|
||||
void event_init(struct event* event) {
|
||||
atomic_store(&event->state, 0, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
void event_set(struct event* event) {
|
||||
uint32_t old = atomic_fetch_or(&event->state, EVENT_SET, ATOMIC_RELEASE);
|
||||
if (!(old & EVENT_PARKED))
|
||||
return;
|
||||
|
||||
atomic_fetch_and(&event->state, ~EVENT_PARKED, ATOMIC_RELAXED);
|
||||
unpark_all(event, 0);
|
||||
}
|
||||
|
||||
void event_reset(struct event* event) {
|
||||
atomic_fetch_and(&event->state, ~EVENT_SET, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
bool event_is_set(struct event* event) {
|
||||
return atomic_load(&event->state, ATOMIC_ACQUIRE) & EVENT_SET;
|
||||
}
|
||||
|
||||
void event_wait(struct event* event) {
|
||||
uint32_t state = atomic_load(&event->state, ATOMIC_ACQUIRE);
|
||||
while (!(state & EVENT_SET)) {
|
||||
if (!(state & EVENT_PARKED)) {
|
||||
if (!atomic_compare_exchange_weak(
|
||||
&event->state,
|
||||
&state,
|
||||
state | EVENT_PARKED,
|
||||
ATOMIC_ACQUIRE,
|
||||
ATOMIC_ACQUIRE
|
||||
))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only sleeps if the event is not set, but parked at this point.
|
||||
park_wait(&event->state, EVENT_PARKED);
|
||||
state = atomic_load(&event->state, ATOMIC_ACQUIRE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user