Module: xenomai-forge
Branch: master
Commit: a60030948f6a04c315dad6104997471ef34f2384
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=a60030948f6a04c315dad6104997471ef34f2384

Author: Philippe Gerum <r...@xenomai.org>
Date:   Fri Dec  2 16:49:13 2011 +0100

cobalt: introduce monitor sync operations

This new set of operations sends notifications then synchronizes the
monitor state immediately afterwards, waking up all threads having
their wait condition satisfied. The gate lock is released first, then
reacquired after the issuing thread regains control.

This is the converse operation to cobalt_monitor_wait, but at the time
of notification.

---

 include/cobalt/syscall.h |    3 +-
 kernel/cobalt/monitor.c  |  140 ++++++++++++++++++++++++++++------------------
 kernel/cobalt/monitor.h  |    7 +-
 kernel/cobalt/syscall.c  |    1 +
 lib/cobalt/internal.c    |   36 ++++++++++++
 lib/cobalt/internal.h    |   10 +++
 6 files changed, 137 insertions(+), 60 deletions(-)

diff --git a/include/cobalt/syscall.h b/include/cobalt/syscall.h
index 2646fd0..c5d2cb6 100644
--- a/include/cobalt/syscall.h
+++ b/include/cobalt/syscall.h
@@ -108,7 +108,8 @@
 #define sc_cobalt_monitor_destroy       84
 #define sc_cobalt_monitor_enter         85
 #define sc_cobalt_monitor_wait          86
-#define sc_cobalt_monitor_exit          87
+#define sc_cobalt_monitor_sync          87
+#define sc_cobalt_monitor_exit          88
 
 #ifdef __KERNEL__
 
diff --git a/kernel/cobalt/monitor.c b/kernel/cobalt/monitor.c
index 7129566..2ce195c 100644
--- a/kernel/cobalt/monitor.c
+++ b/kernel/cobalt/monitor.c
@@ -157,29 +157,14 @@ int cobalt_monitor_enter(struct cobalt_monitor_shadow 
__user *u_monsh)
        return ret;
 }
 
-int cobalt_monitor_exit(struct cobalt_monitor_shadow __user *u_monsh)
+/* nklock held, irqs off */
+static int cobalt_monitor_wakeup(struct cobalt_monitor *mon)
 {
-       struct cobalt_monitor *mon = NULL;
-       struct cobalt_monitor_data *datp;
+       struct cobalt_monitor_data *datp = mon->data;
+       int resched = 0, bcast;
        struct xnthread *p;
        struct xnholder *h;
        pthread_t tid;
-       int ret = 0;
-       spl_t s;
-
-       __xn_get_user(mon, &u_monsh->monitor);
-
-       xnlock_get_irqsave(&nklock, s);
-
-       if (!cobalt_obj_active(mon, COBALT_MONITOR_MAGIC,
-                              struct cobalt_monitor)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       datp = mon->data;
-       if ((datp->flags & COBALT_MONITOR_SIGNALED) == 0)
-               goto done;
 
        if ((datp->flags & COBALT_MONITOR_GRANTED) == 0 ||
            emptyq_p(&mon->waiters))
@@ -190,14 +175,15 @@ int cobalt_monitor_exit(struct cobalt_monitor_shadow 
__user *u_monsh)
         * received it only or all of them, depending on the broadcast
         * bit.
         */
+       bcast = (datp->flags & COBALT_MONITOR_BROADCAST) != 0;
        for (h = getheadq(&mon->waiters); h; h = nextq(&mon->waiters, h)) {
                tid = container_of(h, struct cobalt_thread, monitor_link);
                p = &tid->threadbase;
-               if ((datp->flags & COBALT_MONITOR_BROADCAST) != 0 ||
-                   ((*p->u_mode & XNGRANT) &&
-                    p->wchan == &tid->monitor_synch)) {
+               if (bcast || ((*p->u_mode & XNGRANT) &&
+                             p->wchan == &tid->monitor_synch)) {
                        xnsynch_wakeup_this_sleeper(&tid->monitor_synch,
                                                    &p->plink);
+                       resched = 1;
                }
        }
 drain:
@@ -208,17 +194,14 @@ drain:
        if ((datp->flags & COBALT_MONITOR_DRAINED) != 0 &&
            !xnsynch_pended_p(&mon->drain)) {
                if (datp->flags & COBALT_MONITOR_BROADCAST)
-                       xnsynch_flush(&mon->drain, 0);
+                       resched |= xnsynch_flush(&mon->drain, 0)
+                               == XNSYNCH_RESCHED;
                else
-                       xnsynch_wakeup_one_sleeper(&mon->drain);
+                       resched |= xnsynch_wakeup_one_sleeper(&mon->drain)
+                               != NULL;
        }
-done:
-       xnsynch_release(&mon->gate);
-       xnpod_schedule();
-out:
-       xnlock_put_irqrestore(&nklock, s);
 
-       return ret;
+       return resched;
 }
 
 int cobalt_monitor_wait(struct cobalt_monitor_shadow __user *u_monsh,
@@ -256,33 +239,33 @@ int cobalt_monitor_wait(struct cobalt_monitor_shadow 
__user *u_monsh,
        xnsynch_release(&mon->gate);
 
        synch = &cur->monitor_synch;
-       if (event & COBALT_MONITOR_WAITDRAIN) {
+       if (event & COBALT_MONITOR_WAITDRAIN)
                synch = &mon->drain;
-               mon->data->flags |= COBALT_MONITOR_DRPENDED;
-       } else {
+       else {
                *cur->threadbase.u_mode &= ~XNGRANT;
                appendq(&mon->waiters, &cur->monitor_link);
-               mon->data->flags |= COBALT_MONITOR_GRPENDED;
        }
+       mon->data->flags |= COBALT_MONITOR_PENDED;
 
        info = xnsynch_sleep_on(synch, timeout, tmode);
-       if (info & XNRMID) {
+       if ((info & XNRMID) != 0 ||
+           !cobalt_obj_active(mon, COBALT_MONITOR_MAGIC,
+                              struct cobalt_monitor)) {
                ret = -EINVAL;
                goto out;
        }
 
        /*
-        * We update the GRPENDED and DRPENDED flags to inform
-        * userland about the presence of waiters, so that it may
-        * decide not to issue any syscall for exiting the monitor if
-        * there is nobody else waiting at the gate.
+        * We update the PENDED flag to inform userland about the
+        * presence of waiters, so that it may decide not to issue any
+        * syscall for exiting the monitor if there is nobody else
+        * waiting at the gate.
         */
-       if ((event & COBALT_MONITOR_WAITDRAIN) == 0) {
+       if ((event & COBALT_MONITOR_WAITDRAIN) == 0)
                removeq(&mon->waiters, &cur->monitor_link);
-               if (emptyq_p(&mon->waiters))
-                       mon->data->flags &= ~COBALT_MONITOR_GRPENDED;
-       } else if (!xnsynch_pended_p(&mon->drain))
-               mon->data->flags &= ~COBALT_MONITOR_DRPENDED;
+
+       if (emptyq_p(&mon->waiters) && !xnsynch_pended_p(&mon->drain))
+               mon->data->flags &= ~COBALT_MONITOR_PENDED;
 
        if (info & XNBREAK)
                opret = -EINTR;
@@ -298,6 +281,61 @@ out:
        return ret;
 }
 
+int cobalt_monitor_sync(struct cobalt_monitor_shadow __user *u_monsh)
+{
+       struct cobalt_monitor *mon = NULL;
+       int ret = 0;
+       spl_t s;
+
+       __xn_get_user(mon, &u_monsh->monitor);
+
+       xnlock_get_irqsave(&nklock, s);
+
+       if (!cobalt_obj_active(mon, COBALT_MONITOR_MAGIC,
+                              struct cobalt_monitor)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (mon->data->flags & COBALT_MONITOR_SIGNALED) {
+               cobalt_monitor_wakeup(mon);
+               xnsynch_release(&mon->gate);
+               xnpod_schedule();
+               ret = cobalt_monitor_enter_inner(mon);
+       }
+out:
+       xnlock_put_irqrestore(&nklock, s);
+
+       return ret;
+}
+
+int cobalt_monitor_exit(struct cobalt_monitor_shadow __user *u_monsh)
+{
+       struct cobalt_monitor *mon = NULL;
+       int ret = 0;
+       spl_t s;
+
+       __xn_get_user(mon, &u_monsh->monitor);
+
+       xnlock_get_irqsave(&nklock, s);
+
+       if (!cobalt_obj_active(mon, COBALT_MONITOR_MAGIC,
+                              struct cobalt_monitor)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (mon->data->flags & COBALT_MONITOR_SIGNALED)
+               cobalt_monitor_wakeup(mon);
+
+       xnsynch_release(&mon->gate);
+       xnpod_schedule();
+out:
+       xnlock_put_irqrestore(&nklock, s);
+
+       return ret;
+}
+
 static void cobalt_monitor_destroy_inner(struct cobalt_monitor *mon,
                                         struct cobalt_kqueues *q)
 {
@@ -334,17 +372,9 @@ int cobalt_monitor_destroy(struct cobalt_monitor_shadow 
__user *u_monsh)
                goto fail;
        }
 
-       if (xnsynch_fast_owner_check(mon->gate.fastlock, XN_NO_HANDLE)) {
-               ret = -EBUSY;
-               goto fail;
-       }
-
-       if (xnsynch_pended_p(&mon->drain)) {
-               ret = -EBUSY;
-               goto fail;
-       }
-
-       if (!emptyq_p(&mon->waiters)) {
+       if (xnsynch_fast_owner_check(mon->gate.fastlock, XN_NO_HANDLE) ||
+           xnsynch_pended_p(&mon->drain) ||
+           !emptyq_p(&mon->waiters)) {
                ret = -EBUSY;
                goto fail;
        }
diff --git a/kernel/cobalt/monitor.h b/kernel/cobalt/monitor.h
index 50e83c4..4307e63 100644
--- a/kernel/cobalt/monitor.h
+++ b/kernel/cobalt/monitor.h
@@ -27,10 +27,7 @@
 #define COBALT_MONITOR_DRAINED    0x02
 #define COBALT_MONITOR_SIGNALED   0x03 /* i.e. GRANTED or DRAINED */
 #define COBALT_MONITOR_BROADCAST  0x04
-
-#define COBALT_MONITOR_GRPENDED   0x08
-#define COBALT_MONITOR_DRPENDED   0x10
-#define COBALT_MONITOR_PENDED     0x18 /* i.e. GRPENDED or DRPENDED */
+#define COBALT_MONITOR_PENDED     0x08
 
 struct cobalt_monitor_data {
        xnarch_atomic_t owner;
@@ -59,6 +56,8 @@ int cobalt_monitor_init(struct cobalt_monitor_shadow __user 
*u_monsh,
 
 int cobalt_monitor_enter(struct cobalt_monitor_shadow __user *u_monsh);
 
+int cobalt_monitor_sync(struct cobalt_monitor_shadow __user *u_monsh);
+
 int cobalt_monitor_exit(struct cobalt_monitor_shadow __user *u_monsh);
 
 int cobalt_monitor_wait(struct cobalt_monitor_shadow __user *u_monsh,
diff --git a/kernel/cobalt/syscall.c b/kernel/cobalt/syscall.c
index 47ed075..820b004 100644
--- a/kernel/cobalt/syscall.c
+++ b/kernel/cobalt/syscall.c
@@ -1685,6 +1685,7 @@ static struct xnsysent __systab[] = {
        SKINCALL_DEF(sc_cobalt_monitor_destroy, cobalt_monitor_destroy, any),
        SKINCALL_DEF(sc_cobalt_monitor_enter, cobalt_monitor_enter, primary),
        SKINCALL_DEF(sc_cobalt_monitor_wait, cobalt_monitor_wait, 
nonrestartable),
+       SKINCALL_DEF(sc_cobalt_monitor_sync, cobalt_monitor_sync, any),
        SKINCALL_DEF(sc_cobalt_monitor_exit, cobalt_monitor_exit, 
nonrestartable),
 };
 
diff --git a/lib/cobalt/internal.c b/lib/cobalt/internal.c
index 6dd7415..a1d13d0 100644
--- a/lib/cobalt/internal.c
+++ b/lib/cobalt/internal.c
@@ -178,6 +178,15 @@ void cobalt_monitor_grant(cobalt_monitor_t *mon, unsigned 
long *u_mode)
        *u_mode |= XNGRANT;
 }
 
+int cobalt_monitor_grant_sync(cobalt_monitor_t *mon, unsigned long *u_mode)
+{
+       cobalt_monitor_grant(mon, u_mode);
+
+       return XENOMAI_SKINCALL1(__cobalt_muxid,
+                                sc_cobalt_monitor_sync,
+                                mon);
+}
+
 void cobalt_monitor_grant_all(cobalt_monitor_t *mon, unsigned long *u_mode)
 {
        struct cobalt_monitor_data *datp = get_monitor_data(mon);
@@ -185,6 +194,15 @@ void cobalt_monitor_grant_all(cobalt_monitor_t *mon, 
unsigned long *u_mode)
        datp->flags |= COBALT_MONITOR_GRANTED|COBALT_MONITOR_BROADCAST;
 }
 
+int cobalt_monitor_grant_all_sync(cobalt_monitor_t *mon, unsigned long *u_mode)
+{
+       cobalt_monitor_grant_all(mon, u_mode);
+
+       return XENOMAI_SKINCALL1(__cobalt_muxid,
+                                sc_cobalt_monitor_sync,
+                                mon);
+}
+
 void cobalt_monitor_drain(cobalt_monitor_t *mon)
 {
        struct cobalt_monitor_data *datp = get_monitor_data(mon);
@@ -192,9 +210,27 @@ void cobalt_monitor_drain(cobalt_monitor_t *mon)
        datp->flags |= COBALT_MONITOR_DRAINED;
 }
 
+int cobalt_monitor_drain_sync(cobalt_monitor_t *mon)
+{
+       cobalt_monitor_drain(mon);
+
+       return XENOMAI_SKINCALL1(__cobalt_muxid,
+                                sc_cobalt_monitor_sync,
+                                mon);
+}
+
 void cobalt_monitor_drain_all(cobalt_monitor_t *mon)
 {
        struct cobalt_monitor_data *datp = get_monitor_data(mon);
 
        datp->flags |= COBALT_MONITOR_DRAINED|COBALT_MONITOR_BROADCAST;
 }
+
+int cobalt_monitor_drain_all_sync(cobalt_monitor_t *mon)
+{
+       cobalt_monitor_drain_all(mon);
+
+       return XENOMAI_SKINCALL1(__cobalt_muxid,
+                                sc_cobalt_monitor_sync,
+                                mon);
+}
diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
index 556231a..9b37bdf 100644
--- a/lib/cobalt/internal.h
+++ b/lib/cobalt/internal.h
@@ -26,11 +26,21 @@ int cobalt_monitor_wait(cobalt_monitor_t *mon, int event,
 void cobalt_monitor_grant(cobalt_monitor_t *mon,
                          unsigned long *u_mode);
 
+int cobalt_monitor_grant_sync(cobalt_monitor_t *mon,
+                             unsigned long *u_mode);
+
 void cobalt_monitor_grant_all(cobalt_monitor_t *mon,
                              unsigned long *u_mode);
 
+int cobalt_monitor_grant_all_sync(cobalt_monitor_t *mon,
+                                 unsigned long *u_mode);
+
 void cobalt_monitor_drain(cobalt_monitor_t *mon);
 
+int cobalt_monitor_drain_sync(cobalt_monitor_t *mon);
+
 void cobalt_monitor_drain_all(cobalt_monitor_t *mon);
 
+int cobalt_monitor_drain_all_sync(cobalt_monitor_t *mon);
+
 #endif /* XENO_COBALT_INTERNAL_H */


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to