Module: xenomai-gch Branch: for-forge Commit: 80fee42db6a174edc3d1368d59d393ee8256e9e3 URL: http://git.xenomai.org/?p=xenomai-gch.git;a=commit;h=80fee42db6a174edc3d1368d59d393ee8256e9e3
Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org> Date: Sun Dec 29 00:28:47 2013 +0100 cobalt/timer: make timer_id per-process instead of global --- kernel/cobalt/posix/process.h | 7 +- kernel/cobalt/posix/syscall.c | 11 ++- kernel/cobalt/posix/timer.c | 204 +++++++++++++++++++++++------------------ kernel/cobalt/posix/timer.h | 14 +-- 4 files changed, 134 insertions(+), 102 deletions(-) diff --git a/kernel/cobalt/posix/process.h b/kernel/cobalt/posix/process.h index c19920d..6239b1d 100644 --- a/kernel/cobalt/posix/process.h +++ b/kernel/cobalt/posix/process.h @@ -20,13 +20,13 @@ #include <linux/list.h> #include <cobalt/kernel/ppd.h> +#include <asm/bitsperlong.h> struct cobalt_kqueues { struct list_head condq; struct list_head mutexq; struct list_head semq; struct list_head threadq; - struct list_head timerq; struct list_head monitorq; struct list_head eventq; }; @@ -36,6 +36,11 @@ struct cobalt_process { struct list_head usems; struct xnshadow_ppd ppd; struct list_head sigwaiters; + + /* timers */ + unsigned long timers_himap; + unsigned long timers_lomap[BITS_PER_LONG]; + struct list_head timerq; }; extern struct cobalt_kqueues cobalt_global_kqueues; diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c index 6603d94..82c8ae0 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -55,12 +55,15 @@ static struct xnshadow_ppd *cobalt_process_attach(void) INIT_LIST_HEAD(&cc->kqueues.mutexq); INIT_LIST_HEAD(&cc->kqueues.semq); INIT_LIST_HEAD(&cc->kqueues.threadq); - INIT_LIST_HEAD(&cc->kqueues.timerq); INIT_LIST_HEAD(&cc->kqueues.monitorq); INIT_LIST_HEAD(&cc->kqueues.eventq); + INIT_LIST_HEAD(&cc->timerq); INIT_LIST_HEAD(&cc->usems); INIT_LIST_HEAD(&cc->sigwaiters); + cc->timers_himap = ~0UL; + memset(&cc->timers_lomap, 0xff, sizeof(cc->timers_lomap)); + return &cc->ppd; } @@ -71,8 +74,8 @@ static void cobalt_process_detach(struct xnshadow_ppd *ppd) cc = container_of(ppd, struct cobalt_process, ppd); cobalt_sem_usems_cleanup(cc); + cobalt_timerq_cleanup(cc); cobalt_monitorq_cleanup(&cc->kqueues); - cobalt_timerq_cleanup(&cc->kqueues); cobalt_semq_cleanup(&cc->kqueues); cobalt_mutexq_cleanup(&cc->kqueues); cobalt_condq_cleanup(&cc->kqueues); @@ -134,8 +137,8 @@ static struct xnsyscall cobalt_syscalls[] = { SKINCALL_DEF(sc_cobalt_sigtimedwait, cobalt_sigtimedwait, primary), SKINCALL_DEF(sc_cobalt_sigpending, cobalt_sigpending, primary), SKINCALL_DEF(sc_cobalt_kill, cobalt_kill, conforming), - SKINCALL_DEF(sc_cobalt_timer_create, cobalt_timer_create, any), - SKINCALL_DEF(sc_cobalt_timer_delete, cobalt_timer_delete, any), + SKINCALL_DEF(sc_cobalt_timer_create, cobalt_timer_create, lostage), + SKINCALL_DEF(sc_cobalt_timer_delete, cobalt_timer_delete, lostage), SKINCALL_DEF(sc_cobalt_timer_settime, cobalt_timer_settime, primary), SKINCALL_DEF(sc_cobalt_timer_gettime, cobalt_timer_gettime, any), SKINCALL_DEF(sc_cobalt_timer_getoverrun, cobalt_timer_getoverrun, any), diff --git a/kernel/cobalt/posix/timer.c b/kernel/cobalt/posix/timer.c index 18dcb29..1628bba 100644 --- a/kernel/cobalt/posix/timer.c +++ b/kernel/cobalt/posix/timer.c @@ -24,14 +24,13 @@ #include <linux/module.h> #include <linux/cred.h> #include <linux/err.h> +#include <cobalt/kernel/id_table.h> #include "internal.h" #include "thread.h" #include "timer.h" #include "clock.h" -struct cobalt_timer *cobalt_timer_pool; - -static struct list_head timer_freeq; +static struct xnid_table timer_table; void cobalt_timer_handler(struct xntimer *xntimer) { @@ -99,6 +98,44 @@ timer_init(struct cobalt_timer *timer, return target; } +static inline int timer_alloc_id(struct cobalt_process *proc) +{ + unsigned tl, th; + + th = ffs(proc->timers_himap); + if (th == 0) + return -EAGAIN; + th--; + tl = ffs(proc->timers_lomap[th]); + tl--; + proc->timers_lomap[th] &= ~(1 << tl); + if (proc->timers_lomap[th] == 0) + proc->timers_himap &= ~(1 << th); + + return th * BITS_PER_LONG + tl; +} + +static inline void timer_free_id(struct cobalt_process *proc, int id) +{ + unsigned tl, th; + + tl = id % BITS_PER_LONG; + th = id / BITS_PER_LONG; + + if (proc->timers_lomap[th] == 0) + proc->timers_himap |= (1 << th); + proc->timers_lomap[th] |= (1 << tl); +} + +struct cobalt_timer *cobalt_timer_by_id(struct mm_struct *mm, timer_t timer_id) +{ + struct xnid *i = xnid_fetch(&timer_table, mm, timer_id); + if (i == NULL) + return NULL; + + return container_of(i, struct cobalt_timer, xnid); +} + /** * Create a timer object. * @@ -145,33 +182,33 @@ static inline int timer_create(clockid_t clockid, const struct sigevent *__restrict__ evp, timer_t * __restrict__ timerid) { + struct cobalt_process *proc; struct cobalt_thread *target; struct cobalt_timer *timer; int signo, ret = -EINVAL; timer_t timer_id; spl_t s; - xnlock_get_irqsave(&nklock, s); - - if (list_empty(&timer_freeq)) { - ret = -EAGAIN; - goto unlock_and_error; - } + proc = cobalt_process_context(); + if (proc == NULL) + return -EPERM; + timer = kmalloc(sizeof(*timer), GFP_KERNEL); + if (timer == NULL) + return -ENOMEM; + /* We may bail out early, don't unlink yet. */ - timer = list_first_entry(&timer_freeq, struct cobalt_timer, link); - timer_id = (timer_t)(timer - cobalt_timer_pool); - if (evp == NULL) { - timer->sigp.si.si_int = timer_id; signo = SIGALRM; } else { if (evp->sigev_notify == SIGEV_NONE) signo = 0; /* Don't notify. */ else { signo = evp->sigev_signo; - if (signo < 1 || signo > _NSIG) - goto unlock_and_error; + if (signo < 1 || signo > _NSIG) { + ret = -EINVAL; + goto err_free_timer; + } timer->sigp.si.si_value = evp->sigev_value; } } @@ -179,24 +216,39 @@ static inline int timer_create(clockid_t clockid, timer->sigp.si.si_signo = signo; timer->sigp.si.si_errno = 0; timer->sigp.si.si_code = SI_TIMER; - timer->sigp.si.si_tid = timer_id; timer->sigp.si.si_overrun = 0; INIT_LIST_HEAD(&timer->sigp.next); timer->clockid = clockid; timer->overruns = 0; target = timer_init(timer, evp); - if (target == NULL) - goto unlock_and_error; + if (target == NULL) { + ret = -EINVAL; + goto err_free_timer; + } if (IS_ERR(target)) { ret = PTR_ERR(target); - goto unlock_and_error; + goto err_free_timer; } timer->target = xnthread_host_pid(&target->threadbase); - timer->owningq = cobalt_kqueues(0); - list_del(&timer->link); - list_add_tail(&timer->link, &cobalt_kqueues(0)->timerq); + + xnlock_get_irqsave(&nklock, s); + ret = timer_alloc_id(proc); + if (ret < 0) + goto unlock_and_error; + + timer_id = ret; + if (evp == NULL) + timer->sigp.si.si_int = timer_id; + timer->sigp.si.si_tid = timer_id; + ret = xnid_enter(&timer_table, &timer->xnid, current->mm, timer_id); + if (ret < 0) { + timer_free_id(proc, timer_id); + goto unlock_and_error; + } + + list_add_tail(&timer->link, &proc->timerq); xnlock_put_irqrestore(&nklock, s); *timerid = timer_id; @@ -205,42 +257,44 @@ static inline int timer_create(clockid_t clockid, unlock_and_error: xnlock_put_irqrestore(&nklock, s); + + err_free_timer: + kfree(timer); return ret; } -static void timer_cleanup(struct cobalt_timer *timer) +static void timer_cleanup(struct cobalt_process *p, struct cobalt_timer *timer) { xntimer_destroy(&timer->timerbase); - list_del(&timer->link); - if (!list_empty(&timer->sigp.next)) list_del(&timer->sigp.next); - list_add(&timer->link, &timer_freeq); /* Favour earliest reuse. */ + timer_free_id(p, cobalt_timer_id(timer)); + xnid_remove(&timer_table, &timer->xnid); + list_del(&timer->link); } static inline int timer_delete(timer_t timerid) { + struct cobalt_process *proc; struct cobalt_timer *timer; int ret = 0; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; + proc = cobalt_process_context(); + if (proc == NULL) + return -EPERM; xnlock_get_irqsave(&nklock, s); - timer = cobalt_timer_pool + timerid; - - if (!xntimer_active_p(&timer->timerbase) || - timer->owningq != cobalt_kqueues(0)) { - ret = -EINVAL; - goto out; + timer = cobalt_timer_by_id(current->mm, timerid); + if (timer == NULL) { + xnlock_put_irqrestore(&nklock, s); + return -EINVAL; } - /* * If an extension runs and actually handles the deletion, we * should not call the timer_cleanup extension handler for @@ -258,7 +312,12 @@ timer_delete(timer_t timerid) else ret = 0; - timer_cleanup(timer); + timer_cleanup(proc, timer); + xnlock_put_irqrestore(&nklock, s); + kfree(timer); + + return ret; + out: xnlock_put_irqrestore(&nklock, s); @@ -370,9 +429,8 @@ timer_deliver_late(timer_t timerid) * We dropped the lock shortly, revalidate the timer handle in * case a deletion slipped in. */ - timer = cobalt_timer_pool + timerid; - - if (xntimer_active_p(&timer->timerbase)) + timer = cobalt_timer_by_id(current->mm, timerid); + if (timer) cobalt_timer_handler(&timer->timerbase); xnlock_put_irqrestore(&nklock, s); @@ -436,15 +494,10 @@ timer_settime(timer_t timerid, int flags, int ret; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; - xnlock_get_irqsave(&nklock, s); - timer = cobalt_timer_pool + timerid; - - if (!xntimer_active_p(&timer->timerbase) || - timer->owningq != cobalt_kqueues(0)) { + timer = cobalt_timer_by_id(current->mm, timerid); + if (timer == NULL) { ret = -EINVAL; goto out; } @@ -502,15 +555,10 @@ static inline int timer_gettime(timer_t timerid, struct itimerspec *value) struct cobalt_timer *timer; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; - xnlock_get_irqsave(&nklock, s); - timer = cobalt_timer_pool + timerid; - - if (!xntimer_active_p(&timer->timerbase) || - timer->owningq != cobalt_kqueues(0)) + timer = cobalt_timer_by_id(current->mm, timerid); + if (timer == NULL) goto fail; timer_gettimeout(timer, value); @@ -597,17 +645,10 @@ int cobalt_timer_getoverrun(timer_t timerid) int overruns; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; - xnlock_get_irqsave(&nklock, s); - timer = cobalt_timer_pool + timerid; - - if (!xntimer_active_p(&timer->timerbase)) - goto fail; - - if (timer->owningq != cobalt_kqueues(0)) + timer = cobalt_timer_by_id(current->mm, timerid); + if (timer == NULL) goto fail; overruns = timer->overruns; @@ -626,9 +667,8 @@ int cobalt_timer_deliver(timer_t timerid) /* nklocked, IRQs off. */ struct cobalt_timer *timer; xnticks_t now; - timer = cobalt_timer_pool + timerid; - - if (!xntimer_active_p(&timer->timerbase)) + timer = cobalt_timer_by_id(current->mm, timerid); + if (timer == NULL) /* Killed before ultimate delivery, who cares then? */ return 0; @@ -644,7 +684,7 @@ int cobalt_timer_deliver(timer_t timerid) /* nklocked, IRQs off. */ return timer->overruns; } -void cobalt_timerq_cleanup(struct cobalt_kqueues *q) +void cobalt_timerq_cleanup(struct cobalt_process *p) { struct cobalt_timer *timer, *tmp; spl_t s; @@ -652,16 +692,19 @@ void cobalt_timerq_cleanup(struct cobalt_kqueues *q) xnlock_get_irqsave(&nklock, s); - if (list_empty(&q->timerq)) + if (list_empty(&p->timerq)) goto out; - list_for_each_entry_safe(timer, tmp, &q->timerq, link) { + list_for_each_entry_safe(timer, tmp, &p->timerq, link) { +#if XENO_DEBUG(COBALT) + unsigned id = cobalt_timer_id(timer); +#endif /* XENO_DEBUG(COBALT) */ cobalt_call_extension(timer_cleanup, &timer->extref, ret); - timer_cleanup(timer); + timer_cleanup(p, timer); xnlock_put_irqrestore(&nklock, s); + kfree(timer); #if XENO_DEBUG(COBALT) - printk(XENO_INFO "deleting Cobalt timer %u\n", - (unsigned int)(timer - cobalt_timer_pool)); + printk(XENO_INFO "deleting Cobalt timer %u\n", id); #endif /* XENO_DEBUG(COBALT) */ xnlock_get_irqsave(&nklock, s); } @@ -669,29 +712,14 @@ out: xnlock_put_irqrestore(&nklock, s); } -#define __TMPOOL_SIZE (sizeof(struct cobalt_timer) * CONFIG_XENO_OPT_NRTIMERS) - int cobalt_timer_pkg_init(void) { - int n; - - cobalt_timer_pool = alloc_pages_exact(__TMPOOL_SIZE, GFP_KERNEL); - if (cobalt_timer_pool == NULL) - return -ENOMEM; - - INIT_LIST_HEAD(&timer_freeq); - INIT_LIST_HEAD(&cobalt_global_kqueues.timerq); - - for (n = 0; n < CONFIG_XENO_OPT_NRTIMERS; n++) - list_add_tail(&cobalt_timer_pool[n].link, &timer_freeq); - - return 0; + return xnid_table_init(&timer_table, CONFIG_XENO_OPT_NRTIMERS); } void cobalt_timer_pkg_cleanup(void) { - cobalt_timerq_cleanup(&cobalt_global_kqueues); - free_pages_exact(cobalt_timer_pool, __TMPOOL_SIZE); + xnid_table_cleanup(&timer_table); } /*@}*/ diff --git a/kernel/cobalt/posix/timer.h b/kernel/cobalt/posix/timer.h index b9ff95a..a78defc 100644 --- a/kernel/cobalt/posix/timer.h +++ b/kernel/cobalt/posix/timer.h @@ -22,6 +22,7 @@ #include <linux/time.h> #include <linux/list.h> #include <cobalt/kernel/timer.h> +#include <cobalt/kernel/id_table.h> #include "signal.h" struct cobalt_thread; @@ -30,11 +31,11 @@ struct cobalt_kqueues; struct cobalt_timer { struct xntimer timerbase; int overruns; + struct xnid xnid; struct list_head link; clockid_t clockid; pid_t target; struct cobalt_sigpending sigp; - struct cobalt_kqueues *owningq; struct cobalt_extref extref; }; @@ -55,23 +56,18 @@ int cobalt_timer_getoverrun(timer_t tm); int cobalt_timer_deliver(timer_t timerid); -void cobalt_timerq_cleanup(struct cobalt_kqueues *q); +void cobalt_timerq_cleanup(struct cobalt_process *p); int cobalt_timer_pkg_init(void); void cobalt_timer_pkg_cleanup(void); -extern struct cobalt_timer *cobalt_timer_pool; - static inline timer_t cobalt_timer_id(const struct cobalt_timer *timer) { - return (timer_t)(timer - cobalt_timer_pool); + return (timer_t)timer->xnid.id; } -static inline struct cobalt_timer *cobalt_timer_by_id(timer_t timer_id) -{ - return &cobalt_timer_pool[(unsigned int)timer_id]; -} +struct cobalt_timer *cobalt_timer_by_id(struct mm_struct *mm, timer_t timer_id); void cobalt_xntimer_gettime(struct xntimer *__restrict__ timer, struct itimerspec *__restrict__ value); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git