int periodic_wake_create(spdid_t spdinv, unsigned int period) { struct thread_event *te; unsigned short int tid = cos_get_thd_id(); spdid_t spdid = cos_spd_id(); event_time_t n, t; if (period < 1) return -1; TAKE(spdid); te = te_pget(tid); if (NULL == te) BUG(); if (te->flags & TE_PERIODIC) { assert(!EMPTY_LIST(te, next, prev)); REM_LIST(te, next, prev); } assert(EMPTY_LIST(te, next, prev)); te->flags |= TE_PERIODIC; te->period = period; ticks = sched_timestamp(); te->event_expiration = n = ticks + period; assert(n > ticks); t = next_event_time(); assert(t > ticks); insert_pevent(te); if (t > n) sched_timeout(spdid, n-ticks); RELEASE(spdid); return 0; }
/** * This function is the high-level entry point for the thread-schedule * interrupt. It triggers switches to other runnable threads. */ static timeout_t alarm_handler(struct alarm* alarm) { sched_switch(cpuid()); return sched_timeout(); }
/* * FIXME: allow amnt to be specified in time units rather than ticks. */ int timed_event_block(spdid_t spdinv, unsigned int amnt) { spdid_t spdid = cos_spd_id(); struct thread_event *te; int block_time; event_time_t t; if (amnt == 0) return 0; /* * Convert from usec to ticks * * +2 here as we don't know how far through the current clock * tick we are _and_ we don't know how far into the clock tick * the wakeup time is. The sleep is supposed to be for _at * least_ amnt clock ticks, thus here we are conservative. */ //amnt = (amnt/(unsigned int)usec_per_tick) + 2; /* update: seems like +1 should be enough */ amnt++; TAKE(spdid); te = te_get(cos_get_thd_id()); if (NULL == te) BUG(); assert(EMPTY_LIST(te, next, prev)); te->thread_id = cos_get_thd_id(); te->flags &= ~TE_TIMED_OUT; te->flags |= TE_BLOCKED; ticks = sched_timestamp(); te->event_expiration = ticks + amnt; block_time = ticks; assert(te->event_expiration > ticks); t = next_event_time(); insert_event(te); assert(te->next && te->prev && !EMPTY_LIST(te, next, prev)); RELEASE(spdid); if (t != next_event_time()) sched_timeout(spdid, amnt); if (-1 == sched_block(spdid, 0)) { prints("fprr: sched block failed in timed_event_block."); } /* we better have been taking off the list! */ assert(EMPTY_LIST(te, next, prev)); if (te->flags & TE_TIMED_OUT) return TIMER_EXPIRED; /* * The event has already been removed from event list in * event_expiration by the timeout thread. * * Minus 1 here as we must report the amount of time we are * sure we waited for. As we don't know how far into the tick * we were when we slept, and how far the wakeup is into a * tick, we must account for this. */ return ((int)ticks - block_time - 1); //*usec_per_tick; /* expressed in ticks currently */ }
int __sg_sched_timeout(spdid_t spdid, unsigned long amnt) { /* printc("ser: sched_wakeup (thd %d)\n", cos_get_thd_id()); */ int ret; #ifdef LOG_MONITOR evt_enqueue(cos_get_thd_id(), spdid, cos_spd_id(), FN_SCHED_TIMEOUT, amnt, EVT_SINV); #endif ret = sched_timeout(spdid, amnt); #ifdef LOG_MONITOR evt_enqueue(cos_get_thd_id(), cos_spd_id(), spdid, FN_SCHED_TIMEOUT, amnt, EVT_SRET); #endif return ret; }
int __sg_sched_timeout(spdid_t spdid, unsigned long amnt) { /* printc("ser: sched_wakeup (thd %d)\n", cos_get_thd_id()); */ int ret; #ifdef LOG_MONITOR monevt_enqueue(cos_spd_id(), 15, 0); #endif ret = sched_timeout(spdid, amnt); #ifdef LOG_MONITOR monevt_enqueue(0, 15, 0); #endif return ret; }
/** * \brief init scheduler * \param[in] idle the initial idle thread * \return 0 on success, or a negative error code otherwise * * This initializes the scheduler. The passed thread is the idle * thread. It is added to the thread list automatically. */ int sched_init(struct tcb* idle) { assert(idle); for (size_t i = 0; i < ARRAY_NELEMS(g_current_thread); ++i) { g_current_thread[i] = idle; } for (size_t i = 0; i < ARRAY_NELEMS(g_thread); ++i) { list_init_head(g_thread + i); } alarm_init(&g_alarm, alarm_handler); int res = timer_add_alarm(&g_alarm, sched_timeout()); if (res < 0) { goto err_timer_add_alarm; } res = sched_add_thread(idle, 0); if (res < 0) { goto err_sched_add_thread; } return 0; err_sched_add_thread: timer_remove_alarm(&g_alarm); err_timer_add_alarm: for (size_t i = ARRAY_NELEMS(g_current_thread); i;) { --i; g_current_thread[i] = NULL; } return res; }
static void start_timer_thread(void) { spdid_t spdid = cos_spd_id(); unsigned int tick_freq; INIT_LIST(&events, next, prev); events.thread_id = 0; INIT_LIST(&periodic, next, prev); periodic.thread_id = 0; cos_vect_init_static(&thd_evts); cos_vect_init_static(&thd_periodic); sched_timeout_thd(spdid); tick_freq = sched_tick_freq(); assert(tick_freq == 100); ticks = sched_timestamp(); /* currently timeouts are expressed in ticks, so we don't need this */ // usec_per_tick = USEC_PER_SEC/tick_freq; cyc_per_tick = sched_cyc_per_tick(); // printc("cyc_per_tick = %lld\n", cyc_per_tick); /* When the system boots, we have no pending waits */ assert(EMPTY_LIST(&events, next, prev)); sched_block(spdid, 0); /* Wait for events, then act on expired events. Loop. */ while (1) { event_time_t next_wakeup; cos_mpd_update(); /* update mpd config given this * thread is now in this component * (no dependency if we are in the * same protection domain as the * scheduler) */ ticks = sched_timestamp(); if (sched_component_take(spdid)) { prints("fprr: scheduler lock failed!!!"); BUG(); } event_expiration(ticks); next_wakeup = next_event_time(); /* Are there no pending events??? */ if (TIMER_NO_EVENTS == next_wakeup) { if (sched_component_release(spdid)) { prints("fprr: scheduler lock release failed!!!"); BUG(); } sched_block(spdid, 0); } else { unsigned int wakeup; assert(next_wakeup > ticks); wakeup = (unsigned int)(next_wakeup - ticks); if (sched_component_release(spdid)) { prints("fprr: scheduler lock release failed!!!"); BUG(); } sched_timeout(spdid, wakeup); } } }