From: Philippe Gerum <r...@xenomai.org> Allow for sending a set of event bits to the heading waiter only, instead of broadcasting them to all waiters.
This change affects the ABI, since we add a set of operation flags to the cobalt_event_sync service, to pass the new COBALT_EVENT_BCAST flag. It also affects the internal API as follows: - the new cobalt_event_broadcast() call behaves like cobalt_event_post() formerly did, which is broadcasting the event to all waiters atomically. - the new cobalt_event_signal() call implements the single-waiter delivery mode we introduce. - the former cobalt_event_post() is now a wrapper to cobalt_event_broadcast(), marked with a deprecation flag. Signed-off-by: Philippe Gerum <r...@xenomai.org> --- include/cobalt/sys/cobalt.h | 12 +++++++++++- include/cobalt/uapi/event.h | 10 +++++----- kernel/cobalt/posix/event.c | 37 +++++++++++++++---------------------- kernel/cobalt/posix/event.h | 3 ++- lib/cobalt/internal.c | 20 ++++++++++++-------- 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/include/cobalt/sys/cobalt.h b/include/cobalt/sys/cobalt.h index 46096e8801..1035a29d52 100644 --- a/include/cobalt/sys/cobalt.h +++ b/include/cobalt/sys/cobalt.h @@ -106,9 +106,19 @@ int cobalt_event_init(cobalt_event_t *event, unsigned int value, int flags); -int cobalt_event_post(cobalt_event_t *event, +int cobalt_event_signal(cobalt_event_t *event, unsigned int bits); +int cobalt_event_broadcast(cobalt_event_t *event, + unsigned int bits); + +/* Backward compatibility with 3.2.x and earlier. */ +static inline int cobalt_event_post(cobalt_event_t *event, + unsigned int bits) +{ + return cobalt_event_broadcast(event, bits); +} + int cobalt_event_wait(cobalt_event_t *event, unsigned int bits, unsigned int *bits_r, diff --git a/include/cobalt/uapi/event.h b/include/cobalt/uapi/event.h index 14ddbcf567..52b71d4e3b 100644 --- a/include/cobalt/uapi/event.h +++ b/include/cobalt/uapi/event.h @@ -22,9 +22,6 @@ struct cobalt_event_state { __u32 value; - __u32 flags; -#define COBALT_EVENT_PENDED 0x1 - __u32 nwaiters; }; struct cobalt_event; @@ -36,8 +33,11 @@ struct cobalt_event; #define COBALT_EVENT_AUTOCLEAR 0x4 /* Wait mode. */ -#define COBALT_EVENT_ALL 0x0 -#define COBALT_EVENT_ANY 0x1 +#define COBALT_EVENT_ALL 0x0 +#define COBALT_EVENT_ANY 0x1 + +/* Sync mode. */ +#define COBALT_EVENT_BCAST 0x1 struct cobalt_event_shadow { __u32 state_offset; diff --git a/kernel/cobalt/posix/event.c b/kernel/cobalt/posix/event.c index 0a1236ad73..4433e733fd 100644 --- a/kernel/cobalt/posix/event.c +++ b/kernel/cobalt/posix/event.c @@ -85,8 +85,6 @@ COBALT_SYSCALL(event_init, current, synflags = (flags & COBALT_EVENT_PRIO) ? XNSYNCH_PRIO : XNSYNCH_FIFO; xnsynch_init(&event->synch, synflags, NULL); state->value = value; - state->flags = 0; - state->nwaiters = 0; stateoff = cobalt_umm_offset(umm, state); XENO_BUG_ON(COBALT, stateoff != (__u32)stateoff); @@ -152,37 +150,31 @@ int __cobalt_event_wait(struct cobalt_event_shadow __user *u_event, goto out; } - state->flags |= COBALT_EVENT_PENDED; rbits = state->value & bits; testval = mode & COBALT_EVENT_ANY ? rbits : bits; if (rbits && rbits == testval) { if (event->flags & COBALT_EVENT_AUTOCLEAR) state->value &= ~rbits; - goto done; + goto out; } if (timeout == XN_NONBLOCK) { ret = -EWOULDBLOCK; - goto done; + goto out; } ewc.value = bits; ewc.mode = mode; xnthread_prepare_wait(&ewc.wc); - state->nwaiters++; info = xnsynch_sleep_on(&event->synch, timeout, tmode); if (info & XNRMID) { ret = -EIDRM; goto out; } - if (info & (XNBREAK|XNTIMEO)) { - state->nwaiters--; + if (info & (XNBREAK|XNTIMEO)) ret = (info & XNBREAK) ? -EINTR : -ETIMEDOUT; - } else + else rbits = ewc.value; -done: - if (!xnsynch_pended_p(&event->synch)) - state->flags &= ~COBALT_EVENT_PENDED; out: xnlock_put_irqrestore(&nklock, s); @@ -240,9 +232,10 @@ COBALT_SYSCALL(event_wait64, primary, } COBALT_SYSCALL(event_sync, current, - (struct cobalt_event_shadow __user *u_event)) + (struct cobalt_event_shadow __user *u_event, + unsigned int bits, int flags)) { - unsigned int bits, waitval, testval, consumed = 0; + unsigned int waitval, testval, consumed = 0; struct xnthread_wait_context *wc; struct cobalt_event_state *state; struct event_wait_context *ewc; @@ -262,24 +255,24 @@ COBALT_SYSCALL(event_sync, current, goto out; } - /* - * Userland has already updated the bitmask, our job is to - * wake up any thread which could be satisfied by its current - * value. - */ state = event->state; - bits = state->value; + state->value |= bits; + /* + * Wake up one or more threads satisfied by state->value, + * depending on the flags. + */ xnsynch_for_each_sleeper_safe(p, tmp, &event->synch) { wc = xnthread_get_wait_context(p); ewc = container_of(wc, struct event_wait_context, wc); - waitval = ewc->value & bits; + waitval = ewc->value & state->value; testval = ewc->mode & COBALT_EVENT_ANY ? waitval : ewc->value; if (waitval && waitval == testval) { - state->nwaiters--; ewc->value = waitval; consumed |= waitval; xnsynch_wakeup_this_sleeper(&event->synch, p); + if (!(flags & COBALT_EVENT_BCAST)) + break; } } diff --git a/kernel/cobalt/posix/event.h b/kernel/cobalt/posix/event.h index 919774c9af..85b8031b22 100644 --- a/kernel/cobalt/posix/event.h +++ b/kernel/cobalt/posix/event.h @@ -66,7 +66,8 @@ COBALT_SYSCALL_DECL(event_wait64, const struct __kernel_timespec __user *u_ts)); COBALT_SYSCALL_DECL(event_sync, - (struct cobalt_event_shadow __user *u_evtsh)); + (struct cobalt_event_shadow __user *u_evtsh, + unsigned int bits, int flags)); COBALT_SYSCALL_DECL(event_destroy, (struct cobalt_event_shadow __user *u_evtsh)); diff --git a/lib/cobalt/internal.c b/lib/cobalt/internal.c index bf1e940b71..b142b3b551 100644 --- a/lib/cobalt/internal.c +++ b/lib/cobalt/internal.c @@ -460,19 +460,23 @@ int cobalt_event_destroy(cobalt_event_t *event) return XENOMAI_SYSCALL1(sc_cobalt_event_destroy, event); } -int cobalt_event_post(cobalt_event_t *event, unsigned int bits) +static int do_sync_events(cobalt_event_t *event, + unsigned int bits, int flags) { - struct cobalt_event_state *state = get_event_state(event); - if (bits == 0) return 0; - __sync_or_and_fetch(&state->value, bits); /* full barrier. */ + return XENOMAI_SYSCALL3(sc_cobalt_event_sync, event, bits, flags); +} - if ((state->flags & COBALT_EVENT_PENDED) == 0) - return 0; +int cobalt_event_signal(cobalt_event_t *event, unsigned int bits) +{ + return do_sync_events(event, bits, 0); +} - return XENOMAI_SYSCALL1(sc_cobalt_event_sync, event); +int cobalt_event_broadcast(cobalt_event_t *event, unsigned int bits) +{ + return do_sync_events(event, bits, COBALT_EVENT_BCAST); } int cobalt_event_wait(cobalt_event_t *event, @@ -516,7 +520,7 @@ int cobalt_sem_inquire(sem_t *sem, struct cobalt_sem_info *info, pid_t *waitlist, size_t waitsz) { struct cobalt_sem_shadow *_sem = &((union cobalt_sem_union *)sem)->shadow_sem; - + return XENOMAI_SYSCALL4(sc_cobalt_sem_inquire, _sem, info, waitlist, waitsz); } -- 2.34.1