254 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* This file contains the scheduling policy for SCHED
 | 
						|
 *
 | 
						|
 * The entry points are:
 | 
						|
 *   do_noquantum:        Called on behalf of process' that run out of quantum
 | 
						|
 *   do_start_scheduling  Request from PM to start scheduling a proc
 | 
						|
 *   do_stop_scheduling   Request from PM to stop scheduling a proc
 | 
						|
 *   do_nice		  Request from PM to change the nice level on a proc
 | 
						|
 *   init_scheduling      Called from main.c to set up/prepare scheduling
 | 
						|
 */
 | 
						|
#include "sched.h"
 | 
						|
#include "schedproc.h"
 | 
						|
#include <minix/com.h>
 | 
						|
#include <machine/archtypes.h>
 | 
						|
#include "kernel/proc.h" /* for queue constants */
 | 
						|
 | 
						|
PRIVATE timer_t sched_timer;
 | 
						|
PRIVATE unsigned balance_timeout;
 | 
						|
 | 
						|
#define BALANCE_TIMEOUT	5 /* how often to balance queues in seconds */
 | 
						|
 | 
						|
FORWARD _PROTOTYPE( int schedule_process, (struct schedproc * rmp)	);
 | 
						|
FORWARD _PROTOTYPE( void balance_queues, (struct timer *tp)		);
 | 
						|
 | 
						|
#define DEFAULT_USER_TIME_SLICE 200
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_noquantum				     *
 | 
						|
 *===========================================================================*/
 | 
						|
 | 
						|
PUBLIC int do_noquantum(message *m_ptr)
 | 
						|
{
 | 
						|
	register struct schedproc *rmp;
 | 
						|
	int rv, proc_nr_n;
 | 
						|
 | 
						|
	if (sched_isokendpt(m_ptr->m_source, &proc_nr_n) != OK) {
 | 
						|
		printf("SCHED: WARNING: got an invalid endpoint in OOQ msg %u.\n",
 | 
						|
		m_ptr->m_source);
 | 
						|
		return EBADSRCDST;
 | 
						|
	}
 | 
						|
 | 
						|
	rmp = &schedproc[proc_nr_n];
 | 
						|
	if (rmp->priority < MIN_USER_Q) {
 | 
						|
		rmp->priority += 1; /* lower priority */
 | 
						|
	}
 | 
						|
 | 
						|
	if ((rv = schedule_process(rmp)) != OK) {
 | 
						|
		return rv;
 | 
						|
	}
 | 
						|
	return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_stop_scheduling			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_stop_scheduling(message *m_ptr)
 | 
						|
{
 | 
						|
	register struct schedproc *rmp;
 | 
						|
	int rv, proc_nr_n;
 | 
						|
 | 
						|
	/* Only accept stop messages from PM */
 | 
						|
	if (!is_from_pm(m_ptr))
 | 
						|
		return EPERM;
 | 
						|
 | 
						|
	if (sched_isokendpt(m_ptr->SCHEDULING_ENDPOINT, &proc_nr_n) != OK) {
 | 
						|
		printf("SCHED: WARNING: got an invalid endpoint in OOQ msg %u.\n",
 | 
						|
		m_ptr->SCHEDULING_ENDPOINT);
 | 
						|
		return EBADSRCDST;
 | 
						|
	}
 | 
						|
 | 
						|
	rmp = &schedproc[proc_nr_n];
 | 
						|
	rmp->flags = 0; /*&= ~IN_USE;*/
 | 
						|
 | 
						|
	return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_start_scheduling			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_start_scheduling(message *m_ptr)
 | 
						|
{
 | 
						|
	register struct schedproc *rmp;
 | 
						|
	int rv, proc_nr_n, parent_nr_n;
 | 
						|
 | 
						|
	/* Only accept start messages from PM */
 | 
						|
	if (!is_from_pm(m_ptr))
 | 
						|
		return EPERM;
 | 
						|
 | 
						|
	/* Resolve endpoint to proc slot. */
 | 
						|
	if ((rv = sched_isemtyendpt(m_ptr->SCHEDULING_ENDPOINT, &proc_nr_n))
 | 
						|
			!= OK) {
 | 
						|
		return rv;
 | 
						|
	}
 | 
						|
	rmp = &schedproc[proc_nr_n];
 | 
						|
 | 
						|
	/* Populate process slot */
 | 
						|
	rmp->endpoint     = m_ptr->SCHEDULING_ENDPOINT;
 | 
						|
	rmp->parent       = m_ptr->SCHEDULING_PARENT;
 | 
						|
	rmp->nice         = m_ptr->SCHEDULING_NICE;
 | 
						|
 | 
						|
	/* Find maximum priority from nice value */
 | 
						|
	rv = nice_to_priority(rmp->nice, &rmp->max_priority);
 | 
						|
	if (rv != OK)
 | 
						|
		return rv;
 | 
						|
 | 
						|
	/* Inherit current priority and time slice from parent. Since there
 | 
						|
	 * is currently only one scheduler scheduling the whole system, this
 | 
						|
	 * value is local and we assert that the parent endpoint is valid */
 | 
						|
	if (rmp->endpoint == rmp->parent) {
 | 
						|
		/* We have a special case here for init, which is the first
 | 
						|
		   process scheduled, and the parent of itself. */
 | 
						|
		rmp->priority   = USER_Q;
 | 
						|
		rmp->time_slice = DEFAULT_USER_TIME_SLICE;
 | 
						|
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		if ((rv = sched_isokendpt(m_ptr->SCHEDULING_PARENT,
 | 
						|
				&parent_nr_n)) != OK)
 | 
						|
			return rv;
 | 
						|
 | 
						|
		rmp->priority = schedproc[parent_nr_n].priority;
 | 
						|
		rmp->time_slice = schedproc[parent_nr_n].time_slice;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Take over scheduling the process. The kernel reply message populates
 | 
						|
	 * the processes current priority and its time slice */
 | 
						|
	if ((rv = sys_schedctl(rmp->endpoint)) != OK) {
 | 
						|
		printf("Sched: Error overtaking scheduling for %d, kernel said %d\n",
 | 
						|
			rmp->endpoint, rv);
 | 
						|
		return rv;
 | 
						|
	}
 | 
						|
	rmp->flags = IN_USE;
 | 
						|
 | 
						|
	/* Schedule the process, giving it some quantum */
 | 
						|
	if ((rv = schedule_process(rmp)) != OK) {
 | 
						|
		printf("Sched: Error while scheduling process, kernel replied %d\n",
 | 
						|
			rv);
 | 
						|
		return rv;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Mark ourselves as the new scheduler.
 | 
						|
	 * By default, processes are scheduled by the parents scheduler. In case
 | 
						|
	 * this scheduler would want to delegate scheduling to another
 | 
						|
	 * scheduler, it could do so and then write the endpoint of that
 | 
						|
	 * scheduler into SCHEDULING_SCHEDULER
 | 
						|
	 */
 | 
						|
 | 
						|
	m_ptr->SCHEDULING_SCHEDULER = SCHED_PROC_NR;
 | 
						|
 | 
						|
	return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_nice					     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int do_nice(message *m_ptr)
 | 
						|
{
 | 
						|
	struct schedproc *rmp;
 | 
						|
	int rv;
 | 
						|
	int proc_nr_n;
 | 
						|
	int nice;
 | 
						|
	unsigned new_q, old_q, old_max_q;
 | 
						|
	int old_nice;
 | 
						|
 | 
						|
	/* Only accept nice messages from PM */
 | 
						|
	if (!is_from_pm(m_ptr))
 | 
						|
		return EPERM;
 | 
						|
 | 
						|
	if (sched_isokendpt(m_ptr->SCHEDULING_ENDPOINT, &proc_nr_n) != OK) {
 | 
						|
		printf("SCHED: WARNING: got an invalid endpoint in OOQ msg %u.\n",
 | 
						|
		m_ptr->SCHEDULING_ENDPOINT);
 | 
						|
		return EBADSRCDST;
 | 
						|
	}
 | 
						|
 | 
						|
	rmp = &schedproc[proc_nr_n];
 | 
						|
	nice = m_ptr->SCHEDULING_NICE;
 | 
						|
 | 
						|
	if ((rv = nice_to_priority(nice, &new_q)) != OK)
 | 
						|
		return rv;
 | 
						|
 | 
						|
	/* Store old values, in case we need to roll back the changes */
 | 
						|
	old_q     = rmp->priority;
 | 
						|
	old_max_q = rmp->max_priority;
 | 
						|
	old_nice  = rmp->nice;
 | 
						|
 | 
						|
	/* Update the proc entry and reschedule the process */
 | 
						|
	rmp->max_priority = rmp->priority = new_q;
 | 
						|
	rmp->nice = nice;
 | 
						|
 | 
						|
	if ((rv = schedule_process(rmp)) != OK) {
 | 
						|
		/* Something went wrong when rescheduling the process, roll
 | 
						|
		 * back the changes to proc struct */
 | 
						|
		rmp->priority     = old_q;
 | 
						|
		rmp->max_priority = old_max_q;
 | 
						|
		rmp->nice         = old_nice;
 | 
						|
	}
 | 
						|
 | 
						|
	return rv;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				schedule_process			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PRIVATE int schedule_process(struct schedproc * rmp)
 | 
						|
{
 | 
						|
	int rv;
 | 
						|
 | 
						|
	if ((rv = sys_schedule(rmp->endpoint, rmp->priority,
 | 
						|
			rmp->time_slice)) != OK) {
 | 
						|
		printf("SCHED: An error occurred when trying to schedule %d: %d\n",
 | 
						|
		rmp->endpoint, rv);
 | 
						|
	}
 | 
						|
 | 
						|
	return rv;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				start_scheduling			     *
 | 
						|
 *===========================================================================*/
 | 
						|
 | 
						|
PUBLIC void init_scheduling(void)
 | 
						|
{
 | 
						|
	balance_timeout = BALANCE_TIMEOUT * sys_hz();
 | 
						|
	tmr_inittimer(&sched_timer);
 | 
						|
	sched_set_timer(&sched_timer, balance_timeout, balance_queues, 0);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				balance_queues				     *
 | 
						|
 *===========================================================================*/
 | 
						|
 | 
						|
/* This function in called every 100 ticks to rebalance the queues. The current
 | 
						|
 * scheduler bumps processes down one priority when ever they run out of
 | 
						|
 * quantum. This function will find all proccesses that have been bumped down,
 | 
						|
 * and pulls them back up. This default policy will soon be changed.
 | 
						|
 */
 | 
						|
PRIVATE void balance_queues(struct timer *tp)
 | 
						|
{
 | 
						|
	struct schedproc *rmp;
 | 
						|
	int proc_nr;
 | 
						|
	int rv;
 | 
						|
 | 
						|
	for (proc_nr=0, rmp=schedproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
 | 
						|
		if (rmp->flags & IN_USE) {
 | 
						|
			if (rmp->priority > rmp->max_priority) {
 | 
						|
				rmp->priority -= 1; /* increase priority */
 | 
						|
				schedule_process(rmp);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	sched_set_timer(&sched_timer, balance_timeout, balance_queues, 0);
 | 
						|
}
 |