Add condvars and events via parking lot
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/mutex.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct condvar {
|
||||
_Atomic(uint32_t) seq;
|
||||
_Atomic(uint32_t) waiters;
|
||||
};
|
||||
|
||||
void condvar_init(struct condvar* cv);
|
||||
void condvar_wait(struct condvar* cv, mutex_t* mutex);
|
||||
void condvar_signal(struct condvar* cv);
|
||||
void condvar_broadcast(struct condvar* cv);
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct event {
|
||||
_Atomic(uint32_t) state;
|
||||
};
|
||||
|
||||
void event_init(struct event* event);
|
||||
|
||||
// Sets the event and wakes all waiters.
|
||||
void event_set(struct event* event);
|
||||
|
||||
// Clears the event, so that future waiters block again.
|
||||
void event_reset(struct event* event);
|
||||
|
||||
bool event_is_set(struct event* event);
|
||||
|
||||
// Blocks until the event is set.
|
||||
void event_wait(struct event* event);
|
||||
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/atomic.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct task;
|
||||
|
||||
enum park_status {
|
||||
PARK_UNPARKED,
|
||||
PARK_INVALID,
|
||||
PARK_TIMED_OUT,
|
||||
PARK_INTERRUPTED,
|
||||
};
|
||||
|
||||
struct park_result {
|
||||
enum park_status status;
|
||||
uintptr_t token;
|
||||
};
|
||||
|
||||
enum park_flags {
|
||||
// Queue in front of waiters with the same priority.
|
||||
PARK_FRONT = 1 << 0,
|
||||
PARK_INTERRUPTIBLE = 1 << 1,
|
||||
};
|
||||
|
||||
struct park_unpark_result {
|
||||
struct task* task; // The task that is being woken up, or nullptr if there was no waiter.
|
||||
bool have_more; // Whether there are more tasks parked on the same key.
|
||||
};
|
||||
|
||||
// Parks the current task on `key` if `validate(ctx)` returns true.
|
||||
// `validate` is called with the queue for `key` locked, so it must be short and must not sleep.
|
||||
// Returns the token passed by the waker, or `PARK_INVALID` if `validate` returned false.
|
||||
// Must not be called while holding a spinlock.
|
||||
struct park_result park(const void* key, bool (*validate)(void* ctx), void* ctx, enum park_flags flags);
|
||||
|
||||
// Very similar to `park`, but with an optional `deadline_ns`.
|
||||
// If the deadline is missed, `cancelled` gets called (also optional).
|
||||
struct park_result park_timeout(
|
||||
const void* key,
|
||||
bool (*validate)(void* ctx),
|
||||
void (*cancelled)(void* ctx, bool was_last),
|
||||
void* ctx,
|
||||
enum park_flags flags,
|
||||
const uint64_t* deadline_ns
|
||||
);
|
||||
|
||||
// Wakes the first task parked on `key`.
|
||||
// `callback`, if set, is called with the queue locked before the task is woken, even if there was no waiter.
|
||||
// Its return value is passed to the woken task as the token. Without a callback, the token is 0.
|
||||
// Returns true if a task was woken.
|
||||
bool unpark_one(const void* key, uintptr_t (*callback)(void* ctx, const struct park_unpark_result* result), void* ctx);
|
||||
|
||||
// Wakes all tasks parked on `key` and passes `token` to them. Returns the amount of tasks woken.
|
||||
size_t unpark_all(const void* key, uintptr_t token);
|
||||
|
||||
// Parks the current task as long as `*addr == expected`. Returns false if the value didn't match.
|
||||
bool park_wait(atomic_uint* addr, unsigned int expected);
|
||||
|
||||
// Wakes up to `count` tasks waiting in park_wait() on `addr`. Returns the amount of tasks woken.
|
||||
size_t park_wake(atomic_uint* addr, size_t count);
|
||||
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#pragma once
|
||||
|
||||
struct task;
|
||||
|
||||
// TODO
|
||||
static inline bool signal_pending(struct task*) {
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user