Compare commits

...

1 Commits
main ... event

Author SHA1 Message Date
Chris Copeland d800eae484
add event 2024-04-28 12:30:08 -07:00
6 changed files with 210 additions and 1 deletions

View File

@ -2,6 +2,7 @@ Import("env")
env.Program("donate.c")
env.Program("empty.c")
env.Program("event.c")
env.Program("fair.c")
env.Program("float.c")
env.Program("mutex.c")

37
examples/event.c Normal file
View File

@ -0,0 +1,37 @@
#include <rt/assert.h>
#include <rt/event.h>
#include <rt/task.h>
#include <rt/trap.h>
static const int n = 10;
static RT_EVENT(event);
static void setter(void)
{
rt_task_drop_privilege();
for (int i = 0; i < n; ++i)
{
rt_task_sleep(5);
rt_event_set(&event, 1);
}
}
static void waiter(void)
{
rt_task_drop_privilege();
uint32_t bits;
for (int i = 0; i < n; ++i)
{
bits = rt_event_timedwait(&event, 1, 10);
rt_assert((bits & 1) != 0, "wait timed out");
}
bits = rt_event_timedwait(&event, 1, 10);
rt_assert((bits & 1) == 0, "wait didn't time out");
rt_trap();
}
RT_TASK(setter, RT_STACK_MIN, 1);
RT_TASK(waiter, RT_STACK_MIN, 1);

41
include/rt/event.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include <rt/atomic.h>
#include <rt/cond.h>
#include <rt/mutex.h>
struct rt_event;
uint32_t rt_event_clear(struct rt_event *, uint32_t);
uint32_t rt_event_get(const struct rt_event *);
uint32_t rt_event_set(struct rt_event *, uint32_t);
uint32_t rt_event_wait(struct rt_event *, uint32_t);
uint32_t rt_event_wait_all(struct rt_event *, uint32_t);
uint32_t rt_event_trywait(struct rt_event *, uint32_t);
uint32_t rt_event_trywait_all(struct rt_event *, uint32_t);
uint32_t rt_event_timedwait(struct rt_event *, uint32_t, unsigned long ticks);
uint32_t rt_event_timedwait_all(struct rt_event *, uint32_t,
unsigned long ticks);
struct rt_event
{
rt_atomic_uint32_t bits;
struct rt_mutex mutex;
struct rt_cond cond;
};
#define RT_EVENT_INIT(name) \
{ \
.bits = UINT32_C(0), .mutex = RT_MUTEX_INIT(name.mutex), \
.cond = RT_COND_INIT(name.cond), \
}
#define RT_EVENT(name) struct rt_event name = RT_EVENT_INIT(name)

View File

@ -5,6 +5,7 @@ librt = env.StaticLibrary(
source=[
"assert.c",
"barrier.c",
"event.c",
"cond.c",
"list.c",
"mutex.c",

129
src/event.c Normal file
View File

@ -0,0 +1,129 @@
#include <rt/event.h>
#include <rt/tick.h>
static inline bool match_any(uint32_t bits, uint32_t wait)
{
return ((bits & wait) != UINT32_C(0));
}
static inline bool match_all(uint32_t bits, uint32_t wait)
{
return ((bits & wait) == wait);
}
uint32_t rt_event_clear(struct rt_event *event, uint32_t clear)
{
return rt_atomic_fetch_and(&event->bits, ~clear, RT_ATOMIC_ACQ_REL);
}
uint32_t rt_event_get(const struct rt_event *event)
{
return rt_atomic_load(&event->bits, RT_ATOMIC_ACQUIRE);
}
uint32_t rt_event_set(struct rt_event *event, uint32_t set)
{
const uint32_t oldbits =
rt_atomic_fetch_or(&event->bits, set, RT_ATOMIC_RELEASE);
rt_cond_broadcast(&event->cond);
return oldbits;
}
uint32_t rt_event_wait(struct rt_event *event, uint32_t wait)
{
uint32_t bits = rt_event_trywait(event, wait);
if (match_any(bits, wait))
{
return bits;
}
rt_mutex_lock(&event->mutex);
while (!match_any(bits = rt_event_trywait(event, wait), wait))
{
rt_cond_wait(&event->cond, &event->mutex);
}
rt_mutex_unlock(&event->mutex);
return bits;
}
uint32_t rt_event_trywait(struct rt_event *event, uint32_t wait)
{
uint32_t bits = rt_atomic_load(&event->bits, RT_ATOMIC_RELAXED);
while (match_any(bits, wait) &&
!rt_atomic_compare_exchange_weak(&event->bits, &bits, bits & ~wait,
RT_ATOMIC_ACQUIRE,
RT_ATOMIC_RELAXED))
{
}
return bits;
}
uint32_t rt_event_timedwait(struct rt_event *event, uint32_t wait,
unsigned long ticks)
{
unsigned long start_tick = rt_tick_count();
uint32_t bits = rt_event_trywait(event, wait);
if (match_any(bits, wait) || !rt_mutex_timedlock(&event->mutex, ticks))
{
return bits;
}
while (!match_any(bits = rt_event_trywait(event, wait), wait))
{
rt_tick_elapse(&ticks, &start_tick);
if (!rt_cond_timedwait(&event->cond, &event->mutex, ticks))
{
return bits;
}
}
rt_mutex_unlock(&event->mutex);
return bits;
}
uint32_t rt_event_wait_all(struct rt_event *event, uint32_t wait)
{
uint32_t bits = rt_event_trywait_all(event, wait);
if (match_all(bits, wait))
{
return bits;
}
rt_mutex_lock(&event->mutex);
while (!match_all(bits = rt_event_trywait_all(event, wait), wait))
{
rt_cond_wait(&event->cond, &event->mutex);
}
rt_mutex_unlock(&event->mutex);
return bits;
}
uint32_t rt_event_trywait_all(struct rt_event *event, uint32_t wait)
{
uint32_t bits = rt_atomic_load(&event->bits, RT_ATOMIC_RELAXED);
while (match_all(bits, wait) &&
!rt_atomic_compare_exchange_weak(&event->bits, &bits, bits & ~wait,
RT_ATOMIC_ACQUIRE,
RT_ATOMIC_RELAXED))
{
}
return bits;
}
uint32_t rt_event_timedwait_all(struct rt_event *event, uint32_t wait,
unsigned long ticks)
{
unsigned long start_tick = rt_tick_count();
uint32_t bits = rt_event_trywait_all(event, wait);
if (match_all(bits, wait) || !rt_mutex_timedlock(&event->mutex, ticks))
{
return bits;
}
while (!match_all(bits = rt_event_trywait_all(event, wait), wait))
{
rt_tick_elapse(&ticks, &start_tick);
if (!rt_cond_timedwait(&event->cond, &event->mutex, ticks))
{
return bits;
}
}
rt_mutex_unlock(&event->mutex);
return bits;
}

View File

@ -7,7 +7,7 @@ scons -j $(nproc)
trap 'if [ "$?" != "0" ]; then echo "test failed!"; fi' EXIT
examples=(
donate empty float mutex notify once queue rwlock sem simple tls
donate empty event float mutex notify once queue rwlock sem simple tls
water/barrier water/cond water/sem cycle/mutex cycle/notify cycle/queue
cycle/sem cycle/sleep cycle/yield cxx/mutex cxx/notify cxx/once cxx/queue
cxx/rwlock cxx/sem cxx/water/barrier cxx/water/cond cxx/water/sem