Module: xenomai-forge Branch: master Commit: c0574d09b0614cb383ec2a9657c3933de5cb89a3 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=c0574d09b0614cb383ec2a9657c3933de5cb89a3
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/init.c | 2 - kernel/cobalt/posix/process.h | 7 +- kernel/cobalt/posix/syscall.c | 9 +- kernel/cobalt/posix/timer.c | 209 ++++++++++++++++++++++------------------- kernel/cobalt/posix/timer.h | 19 +--- 5 files changed, 127 insertions(+), 119 deletions(-) diff --git a/kernel/cobalt/posix/init.c b/kernel/cobalt/posix/init.c index 02e0b08..e5395d9 100644 --- a/kernel/cobalt/posix/init.c +++ b/kernel/cobalt/posix/init.c @@ -65,7 +65,6 @@ void cobalt_cleanup(void) { cobalt_syscall_cleanup(); cobalt_nsem_pkg_cleanup(); - cobalt_timer_pkg_cleanup(); cobalt_monitor_pkg_cleanup(); cobalt_event_pkg_cleanup(); cobalt_signal_pkg_cleanup(); @@ -98,7 +97,6 @@ int __init cobalt_init(void) cobalt_mq_pkg_init(); cobalt_event_pkg_init(); cobalt_monitor_pkg_init(); - cobalt_timer_pkg_init(); INIT_LIST_HEAD(&cobalt_global_kqueues.threadq); cobalt_time_slice = CONFIG_XENO_OPT_RR_QUANTUM * 1000; diff --git a/kernel/cobalt/posix/process.h b/kernel/cobalt/posix/process.h index 42f3afd..0a4e722 100644 --- a/kernel/cobalt/posix/process.h +++ b/kernel/cobalt/posix/process.h @@ -19,6 +19,7 @@ #define _COBALT_POSIX_PROCESS_H #include <linux/list.h> +#include <linux/bitmap.h> #include <cobalt/kernel/ppd.h> struct cobalt_kqueues { @@ -26,17 +27,21 @@ struct cobalt_kqueues { struct list_head mutexq; struct list_head semq; struct list_head threadq; - struct list_head timerq; struct list_head monitorq; struct list_head eventq; }; +struct cobalt_timer; struct cobalt_process { struct cobalt_kqueues kqueues; struct list_head uqds; struct list_head usems; struct xnshadow_ppd ppd; struct list_head sigwaiters; + + /* timers */ + DECLARE_BITMAP(timers_map, CONFIG_XENO_OPT_NRTIMERS); + struct cobalt_timer *timers[CONFIG_XENO_OPT_NRTIMERS]; }; extern struct cobalt_kqueues cobalt_global_kqueues; diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c index 3848b9a..b89c331 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -53,13 +53,14 @@ 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->uqds); INIT_LIST_HEAD(&cc->usems); INIT_LIST_HEAD(&cc->sigwaiters); + bitmap_fill(cc->timers_map, CONFIG_XENO_OPT_NRTIMERS); + return &cc->ppd; } @@ -71,8 +72,8 @@ static void cobalt_process_detach(struct xnshadow_ppd *ppd) cobalt_sem_usems_cleanup(cc); cobalt_mq_uqds_cleanup(cc); + cobalt_timers_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); @@ -136,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 17d7063..6c5994f 100644 --- a/kernel/cobalt/posix/timer.c +++ b/kernel/cobalt/posix/timer.c @@ -30,10 +30,6 @@ #include "timer.h" #include "clock.h" -struct cobalt_timer *cobalt_timer_pool; - -static struct list_head timer_freeq; - void cobalt_timer_handler(struct xntimer *xntimer) { struct cobalt_timer *timer; @@ -100,6 +96,32 @@ timer_init(struct cobalt_timer *timer, return target; } +static inline int timer_alloc_id(struct cobalt_process *cc) +{ + unsigned id; + + id = find_first_bit(cc->timers_map, CONFIG_XENO_OPT_NRTIMERS); + if (id == CONFIG_XENO_OPT_NRTIMERS) + return -EAGAIN; + + clear_bit(id, cc->timers_map); + return id; +} + +static inline void timer_free_id(struct cobalt_process *cc, int id) +{ + set_bit(id, cc->timers_map); +} + +struct cobalt_timer * +cobalt_timer_by_id(struct cobalt_process *cc, timer_t timer_id) +{ + if (test_bit(timer_id, cc->timers_map)) + return NULL; + + return cc->timers[timer_id]; +} + /** * Create a timer object. * @@ -146,33 +168,33 @@ static inline int timer_create(clockid_t clockid, const struct sigevent *__restrict__ evp, timer_t * __restrict__ timerid) { + struct cobalt_process *cc; 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; - } + cc = cobalt_process_context(); + if (cc == 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; } } @@ -180,24 +202,34 @@ 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(cc); + 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; + cc->timers[timer_id] = timer; + timer->id = timer_id; xnlock_put_irqrestore(&nklock, s); *timerid = timer_id; @@ -206,42 +238,43 @@ 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)); + p->timers[cobalt_timer_id(timer)] = NULL; } static inline int timer_delete(timer_t timerid) { + struct cobalt_process *cc; struct cobalt_timer *timer; int ret = 0; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; + cc = cobalt_process_context(); + if (cc == 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(cc, 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 @@ -259,7 +292,12 @@ timer_delete(timer_t timerid) else ret = 0; - timer_cleanup(timer); + timer_cleanup(cc, timer); + xnlock_put_irqrestore(&nklock, s); + kfree(timer); + + return ret; + out: xnlock_put_irqrestore(&nklock, s); @@ -342,7 +380,7 @@ static inline int timer_set(struct cobalt_timer *timer, int flags, } static inline void -timer_deliver_late(timer_t timerid) +timer_deliver_late(struct cobalt_process *cc, timer_t timerid) { struct cobalt_timer *timer; spl_t s; @@ -352,9 +390,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(cc, timerid); + if (timer) cobalt_timer_handler(&timer->timerbase); xnlock_put_irqrestore(&nklock, s); @@ -415,18 +452,17 @@ timer_settime(timer_t timerid, int flags, struct itimerspec *__restrict__ ovalue) { struct cobalt_timer *timer; + struct cobalt_process *cc; int ret; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; + cc = cobalt_process_context(); + XENO_BUGON(COBALT, cc == NULL); 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(cc, timerid); + if (timer == NULL) { ret = -EINVAL; goto out; } @@ -443,7 +479,7 @@ timer_settime(timer_t timerid, int flags, * break the atomic section temporarily. */ xnlock_put_irqrestore(&nklock, s); - timer_deliver_late(timerid); + timer_deliver_late(cc, timerid); return 0; } out: @@ -482,17 +518,17 @@ out: static inline int timer_gettime(timer_t timerid, struct itimerspec *value) { struct cobalt_timer *timer; + struct cobalt_process *cc; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; + cc = cobalt_process_context(); + if (cc == NULL) + return -EPERM; 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(cc, timerid); + if (timer == NULL) goto fail; timer_gettimeout(timer, value); @@ -576,20 +612,18 @@ int cobalt_timer_gettime(timer_t tm, struct itimerspec __user *u_val) int cobalt_timer_getoverrun(timer_t timerid) { struct cobalt_timer *timer; + struct cobalt_process *cc; int overruns; spl_t s; - if (timerid >= CONFIG_XENO_OPT_NRTIMERS) - return -EINVAL; + cc = cobalt_process_context(); + if (cc == NULL) + return -EPERM; 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(cc, timerid); + if (timer == NULL) goto fail; overruns = timer->overruns; @@ -608,9 +642,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(cobalt_process_context(), timerid); + if (timer == NULL) /* Killed before ultimate delivery, who cares then? */ return 0; @@ -626,54 +659,34 @@ int cobalt_timer_deliver(timer_t timerid) /* nklocked, IRQs off. */ return timer->overruns; } -void cobalt_timerq_cleanup(struct cobalt_kqueues *q) +void cobalt_timers_cleanup(struct cobalt_process *p) { - struct cobalt_timer *timer, *tmp; + struct cobalt_timer *timer; + unsigned id; spl_t s; int ret; xnlock_get_irqsave(&nklock, s); - if (list_empty(&q->timerq)) + if (find_first_zero_bit(p->timers_map, CONFIG_XENO_OPT_NRTIMERS) == + CONFIG_XENO_OPT_NRTIMERS) goto out; - list_for_each_entry_safe(timer, tmp, &q->timerq, link) { + for (id = 0; id < ARRAY_SIZE(p->timers); id++) { + timer = cobalt_timer_by_id(p, id); + if (timer == NULL) + continue; + 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); } 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; -} - -void cobalt_timer_pkg_cleanup(void) -{ - cobalt_timerq_cleanup(&cobalt_global_kqueues); - free_pages_exact(cobalt_timer_pool, __TMPOOL_SIZE); -} - /*@}*/ diff --git a/kernel/cobalt/posix/timer.h b/kernel/cobalt/posix/timer.h index 5b361c9..999f414 100644 --- a/kernel/cobalt/posix/timer.h +++ b/kernel/cobalt/posix/timer.h @@ -28,12 +28,11 @@ struct cobalt_kqueues; struct cobalt_timer { struct xntimer timerbase; + timer_t id; int overruns; - struct list_head link; clockid_t clockid; pid_t target; struct cobalt_sigpending sigp; - struct cobalt_kqueues *owningq; struct cobalt_extref extref; }; @@ -54,23 +53,15 @@ int cobalt_timer_getoverrun(timer_t tm); int cobalt_timer_deliver(timer_t timerid); -void cobalt_timerq_cleanup(struct cobalt_kqueues *q); - -int cobalt_timer_pkg_init(void); - -void cobalt_timer_pkg_cleanup(void); - -extern struct cobalt_timer *cobalt_timer_pool; +void cobalt_timers_cleanup(struct cobalt_process *p); static inline timer_t cobalt_timer_id(const struct cobalt_timer *timer) { - return (timer_t)(timer - cobalt_timer_pool); + return timer->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 cobalt_process *p, timer_t timer_id); void cobalt_timer_handler(struct xntimer *xntimer); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git