/** * \file * \brief Kernel round-robin scheduling policy */ /* * Copyright (c) 2007, 2008, 2009, 2010, 2013, 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 #include // update_sched_timer /** * \brief Scheduler policy. * * \return Next DCB to schedule or NULL if wait for interrupts. */ struct dcb *schedule(void) { // empty ring if(kcb_current->ring_current == NULL) { return NULL; } assert(kcb_current->ring_current->next != NULL); assert(kcb_current->ring_current->prev != NULL); kcb_current->ring_current = kcb_current->ring_current->next; #ifdef CONFIG_ONESHOT_TIMER update_sched_timer(kernel_now + kernel_timeslice); #endif return ring_current; } void make_runnable(struct dcb *dcb) { // Insert into schedule ring if not in there already if(dcb->prev == NULL || dcb->next == NULL) { assert(dcb->prev == NULL && dcb->next == NULL); // Ring empty if(kcb_current->ring_current == NULL) { kcb_current->ring_current = dcb; dcb->next = dcb; } // Insert after current ring position dcb->prev = kcb_current->ring_current; dcb->next = kcb_current->ring_current->next; kcb_current->ring_current->next->prev = dcb; kcb_current->ring_current->next = dcb; } } /** * \brief Remove 'dcb' from scheduler ring. * * Removes dispatcher 'dcb' from the scheduler ring. If it was not in * the ring, this function is a no-op. The postcondition for this * function is that dcb is not in the ring. * * \param dcb Pointer to DCB to remove. */ void scheduler_remove(struct dcb *dcb) { // No-op if not in scheduler ring if(dcb->prev == NULL || dcb->next == NULL) { assert(dcb->prev == NULL && dcb->next == NULL); return; } struct dcb *next = kcb_current->ring_current->next; // Remove dcb from scheduler ring dcb->prev->next = dcb->next; dcb->next->prev = dcb->prev; dcb->prev = dcb->next = NULL; // Removing ring_current if(dcb == kcb_current->ring_current) { if(dcb == next) { // Only guy in the ring kcb_current->ring_current = NULL; } else { // Advance ring_current kcb_current->ring_current = next; } } } /** * \brief Yield 'dcb' for the rest of the current timeslice. * * Re-sorts 'dcb' into the scheduler queue with its release time increased by * the timeslice period. It is an error to yield a dispatcher not in the * scheduler queue. * * \param dcb Pointer to DCB to remove. */ void scheduler_yield(struct dcb *dcb) { if(dcb->prev == NULL || dcb->next == NULL) { struct dispatcher_shared_generic *dsg = get_dispatcher_shared_generic(dcb->disp); panic("Yield of %.*s not in scheduler queue", DISP_NAME_LEN, dsg->name); } // No-op for the round-robin scheduler } void scheduler_reset_time(void) { // No-Op in RR scheduler } void scheduler_convert(void) { enum sched_state from = kcb_current->sched; switch (from) { case SCHED_RBED: { // initialize RR ring struct dcb *last = NULL; for (struct dcb *i = kcb_current->queue_head; i; i = i->next) { i->prev = last; last = i; } // at this point: we have a dll, but need to close the ring kcb_current->queue_head->prev = kcb_current->queue_tail; kcb_current->queue_tail->next = kcb_current->queue_head; break; } case SCHED_RR: // do nothing break; default: printf("don't know how to convert %d to RBED state\n", from); break; } kcb_current->ring_current = kcb_current->queue_head; for (struct dcb *i = kcb_current->ring_current; i != kcb_current->ring_current; i=i->next) { printf("dcb %p\n prev=%p\n next=%p\n", i, i->prev, i->next); } } void scheduler_restore_state(void) { // No-Op in RR scheduler }