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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Sun Dec 18 22:45:53 2011 +0100

kernel/cobalt: gate lock must be held to destroy a monitor

We now require the caller of the monitor deletion service to hold the
relevant gate lock. This forcibly plugs a common race in userland APIs
based on monitors, allowing them to request a deletion atomically.

As a side effect, this reserves the monitor deletion service to
Xenomai threads, excluding regular Linux tasks. Copperplate, which is
the only and main user of Cobalt monitors does already require this
internally anyway.

---

 kernel/cobalt/monitor.c |   41 ++++++++++++++++++++++-------------------
 kernel/cobalt/syscall.c |    2 +-
 2 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/kernel/cobalt/monitor.c b/kernel/cobalt/monitor.c
index 678ea6c..e3c08ea 100644
--- a/kernel/cobalt/monitor.c
+++ b/kernel/cobalt/monitor.c
@@ -158,19 +158,20 @@ int cobalt_monitor_enter(struct cobalt_monitor_shadow 
__user *u_monsh)
 }
 
 /* nklock held, irqs off */
-static int cobalt_monitor_wakeup(struct cobalt_monitor *mon)
+static void cobalt_monitor_wakeup(struct cobalt_monitor *mon)
 {
        struct cobalt_monitor_data *datp = mon->data;
-       int resched = 0, bcast;
        struct xnthread *p;
        struct xnholder *h;
        pthread_t tid;
+       int bcast;
 
        /*
         * Having the GRANT signal pending does not necessarily mean
         * that somebody is actually waiting for it, so we have to
         * check both conditions below.
         */
+       bcast = (datp->flags & COBALT_MONITOR_BROADCAST) != 0;
        if ((datp->flags & COBALT_MONITOR_GRANTED) == 0 ||
            emptyq_p(&mon->waiters))
                goto drain;
@@ -185,7 +186,6 @@ static int cobalt_monitor_wakeup(struct cobalt_monitor *mon)
         * syscall for exiting the monitor if nobody else is waiting
         * at the gate.
         */
-       bcast = (datp->flags & COBALT_MONITOR_BROADCAST) != 0;
        h = getheadq(&mon->waiters);
        while (h) {
                tid = container_of(h, struct cobalt_thread, monitor_link);
@@ -203,30 +203,25 @@ static int cobalt_monitor_wakeup(struct cobalt_monitor 
*mon)
                                                    &p->plink);
                        removeq(&mon->waiters, &tid->monitor_link);
                        tid->monitor_queued = 0;
-                       resched = 1;
                }
        }
 drain:
        /*
         * Unblock threads waiting for a drain event if that signal is
-        * pending, either one or all, depending on the broadcast bit.
+        * pending, either one or all, depending on the broadcast
+        * flag.
         */
        if ((datp->flags & COBALT_MONITOR_DRAINED) != 0 &&
            xnsynch_pended_p(&mon->drain)) {
-               if (datp->flags & COBALT_MONITOR_BROADCAST)
-                       resched |= xnsynch_flush(&mon->drain, 0)
-                               == XNSYNCH_RESCHED;
+               if (bcast)
+                       xnsynch_flush(&mon->drain, 0);
                else
-                       resched |= xnsynch_wakeup_one_sleeper(&mon->drain)
-                               != NULL;
+                       xnsynch_wakeup_one_sleeper(&mon->drain);
        }
 
-       if (resched &&
-           emptyq_p(&mon->waiters) &&
+       if (emptyq_p(&mon->waiters) &&
            !xnsynch_pended_p(&mon->drain))
-               mon->data->flags &= ~COBALT_MONITOR_PENDED;
-
-       return resched;
+               datp->flags &= ~COBALT_MONITOR_PENDED;
 }
 
 int cobalt_monitor_wait(struct cobalt_monitor_shadow __user *u_monsh,
@@ -234,8 +229,8 @@ int cobalt_monitor_wait(struct cobalt_monitor_shadow __user 
*u_monsh,
                        int __user *u_ret)
 {
        pthread_t cur = cobalt_current_thread();
-       struct cobalt_monitor_data *datp;
        struct cobalt_monitor *mon = NULL;
+       struct cobalt_monitor_data *datp;
        xnticks_t timeout = XN_INFINITE;
        xntmode_t tmode = XN_RELATIVE;
        int ret = 0, opret = 0;
@@ -393,6 +388,7 @@ static void cobalt_monitor_destroy_inner(struct 
cobalt_monitor *mon,
 
 int cobalt_monitor_destroy(struct cobalt_monitor_shadow __user *u_monsh)
 {
+       struct xnthread *cur = xnpod_current_thread();
        struct cobalt_monitor *mon = NULL;
        int ret = 0;
        spl_t s;
@@ -407,13 +403,20 @@ int cobalt_monitor_destroy(struct cobalt_monitor_shadow 
__user *u_monsh)
                goto fail;
        }
 
-       if (xnsynch_fast_owner_check(mon->gate.fastlock, XN_NO_HANDLE) ||
-           xnsynch_pended_p(&mon->drain) ||
-           !emptyq_p(&mon->waiters)) {
+       if (xnsynch_pended_p(&mon->drain) || !emptyq_p(&mon->waiters)) {
                ret = -EBUSY;
                goto fail;
        }
 
+       /*
+        * A monitor must be destroyed by the thread currently holding
+        * its gate lock.
+        */
+       if (xnsynch_owner_check(&mon->gate, cur)) {
+               ret = -EPERM;
+               goto fail;
+       }
+
        xnlock_put_irqrestore(&nklock, s);
 
        cobalt_monitor_destroy_inner(mon, mon->owningq);
diff --git a/kernel/cobalt/syscall.c b/kernel/cobalt/syscall.c
index 4420f23..7b89eb1 100644
--- a/kernel/cobalt/syscall.c
+++ b/kernel/cobalt/syscall.c
@@ -296,7 +296,7 @@ static struct xnsysent __systab[] = {
        SKINCALL_DEF(sc_cobalt_sched_minprio, cobalt_sched_min_prio, any),
        SKINCALL_DEF(sc_cobalt_sched_maxprio, cobalt_sched_max_prio, any),
        SKINCALL_DEF(sc_cobalt_monitor_init, cobalt_monitor_init, any),
-       SKINCALL_DEF(sc_cobalt_monitor_destroy, cobalt_monitor_destroy, any),
+       SKINCALL_DEF(sc_cobalt_monitor_destroy, cobalt_monitor_destroy, 
primary),
        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, 
nonrestartable),


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

Reply via email to