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

Reply via email to