Module: xenomai-forge Branch: next Commit: c822813401d76c784c39a2caf814781b4caece58 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=c822813401d76c784c39a2caf814781b4caece58
Author: Philippe Gerum <r...@xenomai.org> Date: Mon Jun 16 18:39:10 2014 +0200 copperplate/threadobj: rebase periodic wait over timer+sigwaitinfo --- include/cobalt/boilerplate/signal.h | 1 + include/copperplate/threadobj.h | 3 +- include/mercury/boilerplate/signal.h | 1 + lib/alchemy/task.c | 7 -- lib/copperplate/threadobj.c | 160 +++++++++++++++++----------------- 5 files changed, 82 insertions(+), 90 deletions(-) diff --git a/include/cobalt/boilerplate/signal.h b/include/cobalt/boilerplate/signal.h index f1d691f..40c6c78 100644 --- a/include/cobalt/boilerplate/signal.h +++ b/include/cobalt/boilerplate/signal.h @@ -24,6 +24,7 @@ #define __SIGRSVD(n) (SIGRTMIN + 8 + (n)) #define SIGAGENT __SIGRSVD(0) /* Request to remote agent */ +#define SIGPERIOD __SIGRSVD(1) /* Periodic signal */ /* Generates private signal numbers for clients, up to SIGRTMAX. */ #define __SIGPRIV(n) __SIGRSVD(8 + (n)) diff --git a/include/copperplate/threadobj.h b/include/copperplate/threadobj.h index a8e049f..e7b610d 100644 --- a/include/copperplate/threadobj.h +++ b/include/copperplate/threadobj.h @@ -83,8 +83,6 @@ struct threadobj_corespec { int policy_unlocked; struct sched_param_ex schedparam_unlocked; timer_t rr_timer; - struct timespec wakeup; - ticks_t period; /** Timeout reported by sysregd. */ struct timespec timeout; }; @@ -178,6 +176,7 @@ struct threadobj { int wait_prio; void *wait_union; size_t wait_size; + timer_t periodic_timer; struct threadobj_corespec core; struct timespec tslice; diff --git a/include/mercury/boilerplate/signal.h b/include/mercury/boilerplate/signal.h index 05bba14..0405481 100644 --- a/include/mercury/boilerplate/signal.h +++ b/include/mercury/boilerplate/signal.h @@ -32,6 +32,7 @@ #define SIGRELS __SIGRSVD(2) /* Syscall abort */ #define SIGRRB __SIGRSVD(3) /* Round-robin event */ #define SIGAGENT __SIGRSVD(4) /* Request to remote agent */ +#define SIGPERIOD __SIGRSVD(5) /* Periodic signal */ /* Generates private signal numbers for clients, up to SIGRTMAX. */ #define __SIGPRIV(n) __SIGRSVD(8 + (n)) diff --git a/lib/alchemy/task.c b/lib/alchemy/task.c index e8b5f40..12621dc 100644 --- a/lib/alchemy/task.c +++ b/lib/alchemy/task.c @@ -840,13 +840,6 @@ int rt_task_set_periodic(RT_TASK *task, RTIME idate, RTIME period) if (tcb == NULL) goto out; - /* - * XXX: we enforce locality since Cobalt wants this for - * pthread_make_periodic_np(), although Mercury would accept - * remote threads. This seems an acceptable limitation - * compared to introducing a new Cobalt API for supporting a - * somewhat weird feature. - */ if (!threadobj_local_p(&tcb->thobj)) { ret = -EINVAL; goto out; diff --git a/lib/copperplate/threadobj.c b/lib/copperplate/threadobj.c index c9b4d8a..28cd9d5 100644 --- a/lib/copperplate/threadobj.c +++ b/lib/copperplate/threadobj.c @@ -56,6 +56,8 @@ static int request_setschedparam(struct threadobj *thobj, int policy, static int request_cancel(struct threadobj *thobj); +static sigset_t sigperiod_set; + static int threadobj_agent_prio; int threadobj_high_prio; @@ -448,21 +450,6 @@ static inline void disable_rr_corespec(struct threadobj *thobj) /* thobj->lock h /* nop */ } -int threadobj_set_periodic(struct threadobj *thobj, - const struct timespec *__restrict__ idate, - const struct timespec *__restrict__ period) -{ /* thobj->lock held */ - __threadobj_check_locked(thobj); - - return -pthread_make_periodic_np(thobj->ptid, - CLOCK_COPPERPLATE, idate, period); -} - -int threadobj_wait_period(unsigned long *overruns_r) -{ - return -pthread_wait_np(overruns_r); -} - int threadobj_stat(struct threadobj *thobj, struct threadobj_stat *p) /* thobj->lock held */ { struct cobalt_threadstat stat; @@ -536,7 +523,7 @@ static void suspend_sighandler(int sig) sleep_suspended(); } -static void resume_sighandler(int sig) +static void nop_sighandler(int sig) { /* nop */ } @@ -568,8 +555,9 @@ static inline void pkg_init_corespec(void) sigaction(SIGRRB, &sa, NULL); sa.sa_handler = suspend_sighandler; sigaction(SIGSUSP, &sa, NULL); - sa.sa_handler = resume_sighandler; + sa.sa_handler = nop_sighandler; sigaction(SIGRESM, &sa, NULL); + sigaction(SIGPERIOD, &sa, NULL); } static inline int threadobj_init_corespec(struct threadobj *thobj) @@ -616,13 +604,15 @@ static inline int threadobj_setup_corespec(struct threadobj *thobj) * - we must process the suspension signal on behalf of the * target thread, as we want that thread to block upon * receipt. + * + * In addition, we block the periodic signal, which we only + * want to receive from within threadobj_wait_period(). */ sigemptyset(&set); sigaddset(&set, SIGRESM); + sigaddset(&set, SIGPERIOD); pthread_sigmask(SIG_BLOCK, &set, NULL); - thobj->core.period = 0; - /* * Create the per-thread round-robin timer. */ @@ -834,68 +824,6 @@ static void disable_rr_corespec(struct threadobj *thobj) /* thobj->lock held */ timer_settime(thobj->core.rr_timer, 0, &value, NULL); } -int threadobj_set_periodic(struct threadobj *thobj, - const struct timespec *__restrict__ idate, - const struct timespec *__restrict__ period) -{ /* thobj->lock held */ - struct timespec now, wakeup; - - __threadobj_check_locked(thobj); - - clock_gettime(CLOCK_COPPERPLATE, &now); - - if (idate->tv_sec || idate->tv_nsec) { - if (timespec_before(idate, &now)) - return -ETIMEDOUT; - wakeup = *idate; - } else - wakeup = now; - - timespec_add(&thobj->core.wakeup, &wakeup, period); - thobj->core.period = timespec_scalar(period); - - return 0; -} - -int threadobj_wait_period(unsigned long *overruns_r) -{ - struct threadobj *current = threadobj_current(); - struct timespec now, delta, wakeup; - unsigned long overruns = 0; - ticks_t d, period; - int ret; - - period = current->core.period; - if (period == 0) - return -EWOULDBLOCK; - - wakeup = current->core.wakeup; - ret = threadobj_sleep(&wakeup); - if (ret) - return ret; - - /* Check whether we had an overrun. */ - - clock_gettime(CLOCK_COPPERPLATE, &now); - - timespec_sub(&delta, &now, &wakeup); - d = timespec_scalar(&delta); - if (d >= period) { - overruns = d / period; - timespec_adds(¤t->core.wakeup, &wakeup, - overruns * (period + 1)); - } else - timespec_adds(¤t->core.wakeup, &wakeup, period); - - if (overruns) - ret = -ETIMEDOUT; - - if (overruns_r) - *overruns_r = overruns; - - return ret; -} - int threadobj_stat(struct threadobj *thobj, struct threadobj_stat *stat) /* thobj->lock held */ { @@ -1037,6 +965,7 @@ int threadobj_init(struct threadobj *thobj, thobj->cnode = __node_id; thobj->pid = 0; thobj->cancel_sem = NULL; + thobj->periodic_timer = NULL; /* * CAUTION: wait_union and wait_size have been set in @@ -1075,6 +1004,8 @@ static void uninit_thread(struct threadobj *thobj) static void destroy_thread(struct threadobj *thobj) { threadobj_cleanup_corespec(thobj); + if (thobj->periodic_timer) + __RT(timer_delete(thobj->periodic_timer)); uninit_thread(thobj); } @@ -1484,6 +1415,72 @@ int threadobj_sleep(const struct timespec *ts) return -ret; } +int threadobj_set_periodic(struct threadobj *thobj, + const struct timespec *__restrict__ idate, + const struct timespec *__restrict__ period) +{ /* thobj->lock held */ + struct itimerspec its; + struct sigevent sev; + int ret; + + __threadobj_check_locked(thobj); + + if (thobj->periodic_timer == NULL) { + memset(&sev, 0, sizeof(sev)); + sev.sigev_signo = SIGPERIOD; + sev.sigev_notify = SIGEV_SIGNAL|SIGEV_THREAD_ID; + sev.sigev_notify_thread_id = threadobj_get_pid(thobj); + ret = __RT(timer_create(CLOCK_COPPERPLATE, &sev, + &thobj->periodic_timer)); + if (ret) + return __bt(-errno); + } + + if (period == NULL) { + /* Maybe a oneshot specification. */ + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + } else + its.it_interval = *period; + + if (idate == NULL) { + /* Maybe a start now or stop specification. */ + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 0; + ret = __RT(timer_settime(thobj->periodic_timer, 0, + &its, NULL)); + } else { + its.it_value = *idate; + ret = __RT(timer_settime(thobj->periodic_timer, TIMER_ABSTIME, + &its, NULL)); + } + + if (ret) + return __bt(-errno); + + return 0; +} + +int threadobj_wait_period(unsigned long *overruns_r) +{ + siginfo_t si; + int sig; + + for (;;) { + sig = __RT(sigwaitinfo(&sigperiod_set, &si)); + if (sig == SIGPERIOD) + break; + if (errno == EINTR) + return -EINTR; + panic("cannot wait for next period, %s", symerror(-errno)); + } + + if (overruns_r) + *overruns_r = si.si_overrun; + + return 0; +} + void threadobj_spin(ticks_t ns) { ticks_t end; @@ -1603,6 +1600,7 @@ int threadobj_pkg_init(void) threadobj_irq_prio = __RT(sched_get_priority_max(SCHED_CORE)); threadobj_high_prio = threadobj_irq_prio - 1; threadobj_agent_prio = threadobj_high_prio; + sigaddset(&sigperiod_set, SIGPERIOD); pkg_init_corespec(); start_agent(); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git