aos/kernel/schedule_rr.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

160 lines
4.3 KiB
C

/**
* \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 <kernel.h>
#include <dispatch.h>
#include <kcb.h>
#include <timer.h> // 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
}