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