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