/** * \file * \brief DCB wakeup queue management */ /* * Copyright (c) 2011, ETH Zurich. * All rights reserved. * * This file is distributed under the terms in the attached LICENSE file. * If you do not find this file, copies can be found by writing to: * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. */ #include #include #include // kcb_current->wakeup_queue_head #include // update_wakeup_timer() #include #include /* wrapper to change the head, and update the next wakeup tick */ void wakeup_set_queue_head(struct dcb *h) { kcb_current->wakeup_queue_head = h; #ifdef CONFIG_ONESHOT_TIMER // we changed the first dcb in the wakeup queue, which means // that we need to update the next tick value systime_t next_wakeup = h ? h->wakeup_time : TIMER_INF; update_wakeup_timer(next_wakeup); #endif } static inline void set_queue_head(struct dcb *h) { wakeup_set_queue_head(h); } void wakeup_remove(struct dcb *dcb) { if (dcb->wakeup_time != 0) { if (dcb->wakeup_prev == NULL) { assert(kcb_current->wakeup_queue_head == dcb); set_queue_head(dcb->wakeup_next); } else { assert(dcb->wakeup_prev->wakeup_next == dcb); dcb->wakeup_prev->wakeup_next = dcb->wakeup_next; } if (dcb->wakeup_next != NULL) { assert(dcb->wakeup_next->wakeup_prev == dcb); dcb->wakeup_next->wakeup_prev = dcb->wakeup_prev; } dcb->wakeup_prev = dcb->wakeup_next = NULL; } // No-Op if not in queue... } /// Set the wakeup time for the given DCB void wakeup_set(struct dcb *dcb, systime_t waketime) { assert(dcb != NULL); // if we're already enqueued, remove first wakeup_remove(dcb); dcb->wakeup_time = waketime; for (struct dcb *d = kcb_current->wakeup_queue_head, *p = NULL; ; p = d, d = d->wakeup_next) { if (d == NULL || d->wakeup_time > waketime) { if (p == NULL) { // insert at head assert(d == kcb_current->wakeup_queue_head); dcb->wakeup_prev = NULL; dcb->wakeup_next = d; if (d != NULL) { d->wakeup_prev = dcb; } set_queue_head(dcb); } else { dcb->wakeup_next = d; dcb->wakeup_prev = p; p->wakeup_next = dcb; if (d != NULL) { d->wakeup_prev = dcb; } } break; } } } /// Check for wakeups, given the current time void wakeup_check(systime_t now) { struct dcb *d = kcb_current->wakeup_queue_head, *next = NULL; for (; d != NULL && d->wakeup_time <= now; d = next) { next = d->wakeup_next; d->wakeup_time = 0; d->wakeup_prev = d->wakeup_next = NULL; make_runnable(d); schedule_now(d); } if (d != NULL) { d->wakeup_prev = NULL; } set_queue_head(d); } bool wakeup_is_pending(void) { return kcb_current->wakeup_queue_head != NULL; }