static void xnsched_watchdog_handler(struct xntimer *timer) { struct xnsched *sched = xnpod_current_sched(); struct xnthread *thread = sched->curr; if (likely(xnthread_test_state(thread, XNROOT))) { xnsched_reset_watchdog(sched); return; } if (likely(++sched->wdcount < wd_timeout_arg)) return; #ifdef CONFIG_XENO_OPT_PERVASIVE if (xnthread_test_state(thread, XNSHADOW) && !xnthread_amok_p(thread)) { trace_mark(xn_nucleus, watchdog_signal, "thread %p thread_name %s", thread, xnthread_name(thread)); xnprintf("watchdog triggered -- signaling runaway thread " "'%s'\n", xnthread_name(thread)); xnthread_set_info(thread, XNAMOK | XNKICKED); xnshadow_send_sig(thread, SIGDEBUG, SIGDEBUG_WATCHDOG, 1); } else #endif /* CONFIG_XENO_OPT_PERVASIVE */ { trace_mark(xn_nucleus, watchdog, "thread %p thread_name %s", thread, xnthread_name(thread)); xnprintf("watchdog triggered -- killing runaway thread '%s'\n", xnthread_name(thread)); xnpod_delete_thread(thread); } xnsched_reset_watchdog(sched); }
void xntimer_adjust_all_aperiodic(xnsticks_t delta) { unsigned cpu, nr_cpus; xnqueue_t adjq; initq(&adjq); delta = xnarch_ns_to_tsc(delta); for (cpu = 0, nr_cpus = xnarch_num_online_cpus(); cpu < nr_cpus; cpu++) { xnsched_t *sched = xnpod_sched_slot(cpu); xntimerq_t *q = &sched->timerqueue; xnholder_t *adjholder; xntimerh_t *holder; xntimerq_it_t it; for (holder = xntimerq_it_begin(q, &it); holder; holder = xntimerq_it_next(q, &it, holder)) { xntimer_t *timer = aplink2timer(holder); if (testbits(timer->status, XNTIMER_REALTIME)) { inith(&timer->adjlink); appendq(&adjq, &timer->adjlink); } } while ((adjholder = getq(&adjq))) { xntimer_t *timer = adjlink2timer(adjholder); xntimer_dequeue_aperiodic(timer); xntimer_adjust_aperiodic(timer, delta); } if (sched != xnpod_current_sched()) xntimer_next_remote_shot(sched); else xntimer_next_local_shot(sched); } }
int xntimer_start_aperiodic(xntimer_t *timer, xnticks_t value, xnticks_t interval, xntmode_t mode) { xnticks_t date, now; trace_mark(xn_nucleus, timer_start, "timer %p base %s value %Lu interval %Lu mode %u", timer, xntimer_base(timer)->name, value, interval, mode); if (!testbits(timer->status, XNTIMER_DEQUEUED)) xntimer_dequeue_aperiodic(timer); now = xnarch_get_cpu_tsc(); __clrbits(timer->status, XNTIMER_REALTIME | XNTIMER_FIRED | XNTIMER_PERIODIC); switch (mode) { case XN_RELATIVE: if ((xnsticks_t)value < 0) return -ETIMEDOUT; date = xnarch_ns_to_tsc(value) + now; break; case XN_REALTIME: __setbits(timer->status, XNTIMER_REALTIME); value -= nktbase.wallclock_offset; /* fall through */ default: /* XN_ABSOLUTE || XN_REALTIME */ date = xnarch_ns_to_tsc(value); if ((xnsticks_t)(date - now) <= 0) return -ETIMEDOUT; break; } xntimerh_date(&timer->aplink) = date; timer->interval = XN_INFINITE; if (interval != XN_INFINITE) { timer->interval = xnarch_ns_to_tsc(interval); timer->pexpect = date; __setbits(timer->status, XNTIMER_PERIODIC); } xntimer_enqueue_aperiodic(timer); if (xntimer_heading_p(timer)) { if (xntimer_sched(timer) != xnpod_current_sched()) xntimer_next_remote_shot(xntimer_sched(timer)); else xntimer_next_local_shot(xntimer_sched(timer)); } return 0; }
/** * Migrate a timer. * * This call migrates a timer to another cpu. In order to avoid pathological * cases, it must be called from the CPU to which @a timer is currently * attached. * * @param timer The address of the timer object to be migrated. * * @param sched The address of the destination CPU xnsched_t structure. * * @retval -EINVAL if @a timer is queued on another CPU than current ; * @retval 0 otherwise. * */ int xntimer_migrate(xntimer_t *timer, xnsched_t *sched) { int err = 0; int queued; spl_t s; trace_mark(xn_nucleus, timer_migrate, "timer %p cpu %d", timer, (int)xnsched_cpu(sched)); xnlock_get_irqsave(&nklock, s); if (sched == timer->sched) goto unlock_and_exit; queued = !testbits(timer->status, XNTIMER_DEQUEUED); /* Avoid the pathological case where the timer interrupt did not occur yet for the current date on the timer source CPU, whereas we are trying to migrate it to a CPU where the timer interrupt already occured. This would not be a problem in aperiodic mode. */ if (queued) { if (timer->sched != xnpod_current_sched()) { err = -EINVAL; goto unlock_and_exit; } #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC timer->base->ops->stop_timer(timer); #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */ xntimer_stop_aperiodic(timer); #endif /* !CONFIG_XENO_OPT_TIMING_PERIODIC */ } timer->sched = sched; if (queued) #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC timer->base->ops->move_timer(timer); #else /* !CONFIG_XENO_OPT_TIMING_PERIODIC */ xntimer_move_aperiodic(timer); #endif /* !CONFIG_XENO_OPT_TIMING_PERIODIC */ unlock_and_exit: xnlock_put_irqrestore(&nklock, s); return err; }
void xntimer_stop_aperiodic(xntimer_t *timer) { int heading; trace_mark(xn_nucleus, timer_stop, "timer %p", timer); heading = xntimer_heading_p(timer); xntimer_dequeue_aperiodic(timer); /* If we removed the heading timer, reprogram the next shot if any. If the timer was running on another CPU, let it tick. */ if (heading && xntimer_sched(timer) == xnpod_current_sched()) xntimer_next_local_shot(xntimer_sched(timer)); }
void xnintr_clock_handler(void) { struct xnsched *sched = xnpod_current_sched(); xnstat_exectime_t *prev; prev = xnstat_exectime_switch(sched, &nkclock.stat[xnsched_cpu(sched)].account); xnstat_counter_inc(&nkclock.stat[xnsched_cpu(sched)].hits); trace_mark(xn_nucleus, irq_enter, "irq %u", XNARCH_TIMER_IRQ); trace_mark(xn_nucleus, tbase_tick, "base %s", nktbase.name); ++sched->inesting; __setbits(sched->lflags, XNINIRQ); xnlock_get(&nklock); xntimer_tick_aperiodic(); xnlock_put(&nklock); xnstat_exectime_switch(sched, prev); if (--sched->inesting == 0) { __clrbits(sched->lflags, XNINIRQ); xnpod_schedule(); sched = xnpod_current_sched(); } /* * If the clock interrupt preempted a real-time thread, any * transition to the root thread has already triggered a host * tick propagation from xnpod_schedule(), so at this point, * we only need to propagate the host tick in case the * interrupt preempted the root thread. */ if (testbits(sched->lflags, XNHTICK) && xnthread_test_state(sched->curr, XNROOT)) xnintr_host_tick(sched); trace_mark(xn_nucleus, irq_exit, "irq %u", XNARCH_TIMER_IRQ); }
void __xntimer_init(xntimer_t *timer, xntbase_t *base, void (*handler) (xntimer_t *timer)) { /* CAUTION: Setup from xntimer_init() must not depend on the periodic/aperiodic timing mode. */ xntimerh_init(&timer->aplink); xntimerh_date(&timer->aplink) = XN_INFINITE; #ifdef CONFIG_XENO_OPT_TIMING_PERIODIC timer->base = base; xntlholder_init(&timer->plink); xntlholder_date(&timer->plink) = XN_INFINITE; #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */ xntimer_set_priority(timer, XNTIMER_STDPRIO); timer->status = XNTIMER_DEQUEUED; timer->handler = handler; timer->interval = 0; timer->sched = xnpod_current_sched(); #ifdef CONFIG_XENO_OPT_STATS { spl_t s; if (!xnpod_current_thread() || xnpod_shadow_p()) snprintf(timer->name, XNOBJECT_NAME_LEN, "%d/%s", current->pid, current->comm); else xnobject_copy_name(timer->name, xnpod_current_thread()->name); inith(&timer->tblink); xnstat_counter_set(&timer->scheduled, 0); xnstat_counter_set(&timer->fired, 0); xnlock_get_irqsave(&nklock, s); appendq(&base->timerq, &timer->tblink); base->timerq_rev++; xnlock_put_irqrestore(&nklock, s); } #endif /* CONFIG_XENO_OPT_TIMING_PERIODIC */ xnarch_init_display_context(timer); }
void xntimer_tick_periodic_inner(xntslave_t *slave) { xnsched_t *sched = xnpod_current_sched(); xntbase_t *base = &slave->base; xntlholder_t *holder; xnqueue_t *timerq; xntimer_t *timer; /* * Update the periodic clocks keeping the things strictly * monotonous (this routine is run on every cpu, but only CPU * XNTIMER_KEEPER_ID should do this). */ if (sched == xnpod_sched_slot(XNTIMER_KEEPER_ID)) ++base->jiffies; timerq = &slave->cascade[xnsched_cpu(sched)].wheel[base->jiffies & XNTIMER_WHEELMASK]; while ((holder = xntlist_head(timerq)) != NULL) { timer = plink2timer(holder); if ((xnsticks_t) (xntlholder_date(&timer->plink) - base->jiffies) > 0) break; trace_mark(xn_nucleus, timer_expire, "timer %p", timer); xntimer_dequeue_periodic(timer); xnstat_counter_inc(&timer->fired); timer->handler(timer); if (!xntimer_reload_p(timer)) continue; __setbits(timer->status, XNTIMER_FIRED); xntlholder_date(&timer->plink) = base->jiffies + timer->interval; xntimer_enqueue_periodic(timer); } xnsched_tick(sched->curr, base); /* Do time-slicing if required. */ }
struct xnsched *xnsched_finish_unlocked_switch(struct xnsched *sched) { struct xnthread *last; spl_t s; xnlock_get_irqsave(&nklock, s); #ifdef CONFIG_SMP /* If current thread migrated while suspended */ sched = xnpod_current_sched(); #endif /* CONFIG_SMP */ last = sched->last; __clrbits(sched->status, XNSWLOCK); /* Detect a thread which called xnpod_migrate_thread */ if (last->sched != sched) { xnsched_putback(last); xnthread_clear_state(last, XNMIGRATE); } if (xnthread_test_state(last, XNZOMBIE)) { /* * There are two cases where sched->last has the zombie * bit: * - either it had it before the context switch, the hooks * have been executed and sched->zombie is last; * - or it has been killed while the nklocked was unlocked * during the context switch, in which case we must run the * hooks, and we do it now. */ if (sched->zombie != last) xnsched_zombie_hooks(last); } return sched; }
void xntimer_tick_aperiodic(void) { xnsched_t *sched = xnpod_current_sched(); xntimerq_t *timerq = &sched->timerqueue; xntimerh_t *holder; xntimer_t *timer; xnsticks_t delta; xnticks_t now; /* * Optimisation: any local timer reprogramming triggered by * invoked timer handlers can wait until we leave the tick * handler. Use this status flag as hint to * xntimer_start_aperiodic. */ __setbits(sched->status, XNINTCK); now = xnarch_get_cpu_tsc(); while ((holder = xntimerq_head(timerq)) != NULL) { timer = aplink2timer(holder); /* * If the delay to the next shot is greater than the * intrinsic latency value, we may stop scanning the * timer queue there, since timeout dates are ordered * by increasing values. */ delta = (xnsticks_t)(xntimerh_date(&timer->aplink) - now); if (delta > (xnsticks_t)nklatency) break; trace_mark(xn_nucleus, timer_expire, "timer %p", timer); xntimer_dequeue_aperiodic(timer); xnstat_counter_inc(&timer->fired); if (likely(timer != &sched->htimer)) { if (likely(!testbits(nktbase.status, XNTBLCK) || testbits(timer->status, XNTIMER_NOBLCK))) { timer->handler(timer); now = xnarch_get_cpu_tsc(); /* * If the elapsed timer has no reload * value, or was re-enqueued or killed * by the timeout handler: don't not * re-enqueue it for the next shot. */ if (!xntimer_reload_p(timer)) continue; __setbits(timer->status, XNTIMER_FIRED); } else if (likely(!testbits(timer->status, XNTIMER_PERIODIC))) { /* * Postpone the next tick to a * reasonable date in the future, * waiting for the timebase to be * unlocked at some point. */ xntimerh_date(&timer->aplink) = xntimerh_date(&sched->htimer.aplink); continue; } } else { /* * By postponing the propagation of the * low-priority host tick to the interrupt * epilogue (see xnintr_irq_handler()), we * save some I-cache, which translates into * precious microsecs on low-end hw. */ __setbits(sched->status, XNHTICK); __clrbits(sched->status, XNHDEFER); if (!testbits(timer->status, XNTIMER_PERIODIC)) continue; } do { xntimerh_date(&timer->aplink) += timer->interval; } while (xntimerh_date(&timer->aplink) < now + nklatency); xntimer_enqueue_aperiodic(timer); } __clrbits(sched->status, XNINTCK); xntimer_next_local_shot(sched); }
/* * Low-level interrupt handler dispatching non-shared ISRs -- Called with * interrupts off. */ static void xnintr_irq_handler(unsigned irq, void *cookie) { struct xnsched *sched = xnpod_current_sched(); xnstat_exectime_t *prev; struct xnintr *intr; xnticks_t start; int s; prev = xnstat_exectime_get_current(sched); start = xnstat_exectime_now(); trace_mark(xn_nucleus, irq_enter, "irq %u", irq); ++sched->inesting; __setbits(sched->lflags, XNINIRQ); xnlock_get(&xnirqs[irq].lock); #ifdef CONFIG_SMP /* * In SMP case, we have to reload the cookie under the per-IRQ * lock to avoid racing with xnintr_detach. However, we * assume that no CPU migration will occur while running the * interrupt service routine, so the scheduler pointer will * remain valid throughout this function. */ intr = xnarch_get_irq_cookie(irq); if (unlikely(!intr)) { s = 0; goto unlock_and_exit; } #else /* cookie always valid, attach/detach happens with IRQs disabled */ intr = cookie; #endif s = intr->isr(intr); if (unlikely(s == XN_ISR_NONE)) { if (++intr->unhandled == XNINTR_MAX_UNHANDLED) { xnlogerr("%s: IRQ%d not handled. Disabling IRQ " "line.\n", __FUNCTION__, irq); s |= XN_ISR_NOENABLE; } } else { xnstat_counter_inc(&intr->stat[xnsched_cpu(sched)].hits); xnstat_exectime_lazy_switch(sched, &intr->stat[xnsched_cpu(sched)].account, start); intr->unhandled = 0; } #ifdef CONFIG_SMP unlock_and_exit: #endif xnlock_put(&xnirqs[irq].lock); if (s & XN_ISR_PROPAGATE) xnarch_chain_irq(irq); else if (!(s & XN_ISR_NOENABLE)) xnarch_end_irq(irq); xnstat_exectime_switch(sched, prev); if (--sched->inesting == 0) { __clrbits(sched->lflags, XNINIRQ); xnpod_schedule(); } trace_mark(xn_nucleus, irq_exit, "irq %u", irq); }
/* * Low-level interrupt handler dispatching the user-defined ISRs for * shared edge-triggered interrupts -- Called with interrupts off. */ static void xnintr_edge_shirq_handler(unsigned irq, void *cookie) { const int MAX_EDGEIRQ_COUNTER = 128; struct xnsched *sched = xnpod_current_sched(); xnintr_irq_t *shirq = &xnirqs[irq]; int s = 0, counter = 0, ret, code; struct xnintr *intr, *end = NULL; xnstat_exectime_t *prev; xnticks_t start; prev = xnstat_exectime_get_current(sched); start = xnstat_exectime_now(); trace_mark(xn_nucleus, irq_enter, "irq %u", irq); ++sched->inesting; __setbits(sched->lflags, XNINIRQ); xnlock_get(&shirq->lock); intr = shirq->handlers; while (intr != end) { xnstat_exectime_switch(sched, &intr->stat[xnsched_cpu(sched)].account); /* * NOTE: We assume that no CPU migration will occur * while running the interrupt service routine. */ ret = intr->isr(intr); code = ret & ~XN_ISR_BITMASK; s |= ret; if (code == XN_ISR_HANDLED) { end = NULL; xnstat_counter_inc( &intr->stat[xnsched_cpu(sched)].hits); xnstat_exectime_lazy_switch(sched, &intr->stat[xnsched_cpu(sched)].account, start); start = xnstat_exectime_now(); } else if (end == NULL) end = intr; if (counter++ > MAX_EDGEIRQ_COUNTER) break; if (!(intr = intr->next)) intr = shirq->handlers; } xnlock_put(&shirq->lock); if (counter > MAX_EDGEIRQ_COUNTER) xnlogerr ("xnintr_edge_shirq_handler() : failed to get the IRQ%d line free.\n", irq); if (unlikely(s == XN_ISR_NONE)) { if (++shirq->unhandled == XNINTR_MAX_UNHANDLED) { xnlogerr("%s: IRQ%d not handled. Disabling IRQ " "line.\n", __FUNCTION__, irq); s |= XN_ISR_NOENABLE; } } else shirq->unhandled = 0; if (s & XN_ISR_PROPAGATE) xnarch_chain_irq(irq); else if (!(s & XN_ISR_NOENABLE)) xnarch_end_irq(irq); xnstat_exectime_switch(sched, prev); if (--sched->inesting == 0) { __clrbits(sched->lflags, XNINIRQ); xnpod_schedule(); } trace_mark(xn_nucleus, irq_exit, "irq %u", irq); }
/* * Low-level interrupt handler dispatching the user-defined ISRs for * shared interrupts -- Called with interrupts off. */ static void xnintr_shirq_handler(unsigned irq, void *cookie) { struct xnsched *sched = xnpod_current_sched(); xnintr_irq_t *shirq = &xnirqs[irq]; xnstat_exectime_t *prev; xnticks_t start; xnintr_t *intr; int s = 0, ret; prev = xnstat_exectime_get_current(sched); start = xnstat_exectime_now(); trace_mark(xn_nucleus, irq_enter, "irq %u", irq); ++sched->inesting; __setbits(sched->status, XNINIRQ); xnlock_get(&shirq->lock); intr = shirq->handlers; while (intr) { /* * NOTE: We assume that no CPU migration will occur * while running the interrupt service routine. */ ret = intr->isr(intr); s |= ret; if (ret & XN_ISR_HANDLED) { xnstat_counter_inc( &intr->stat[xnsched_cpu(sched)].hits); xnstat_exectime_lazy_switch(sched, &intr->stat[xnsched_cpu(sched)].account, start); start = xnstat_exectime_now(); } intr = intr->next; } xnlock_put(&shirq->lock); if (unlikely(s == XN_ISR_NONE)) { if (++shirq->unhandled == XNINTR_MAX_UNHANDLED) { xnlogerr("%s: IRQ%d not handled. Disabling IRQ " "line.\n", __FUNCTION__, irq); s |= XN_ISR_NOENABLE; } } else shirq->unhandled = 0; if (s & XN_ISR_PROPAGATE) xnarch_chain_irq(irq); else if (!(s & XN_ISR_NOENABLE)) xnarch_end_irq(irq); if (--sched->inesting == 0) { __clrbits(sched->status, XNINIRQ); xnpod_schedule(); } trace_mark(xn_nucleus, irq_exit, "irq %u", irq); xnstat_exectime_switch(sched, prev); }