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


Reply via email to