0,0 → 1,529 |
/* |
* Project: S.Ha.R.K. |
* |
* Coordinators: |
* Giorgio Buttazzo <giorgio@sssup.it> |
* Paolo Gai <pj@gandalf.sssup.it> |
* |
* Authors : |
* Trimarchi Michael <trimarchi@gandalf.sssup.it> |
* (see the web pages for full authors list) |
* |
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy) |
* |
* http://www.sssup.it |
* http://retis.sssup.it |
* http://shark.sssup.it |
*/ |
|
/** |
------------ |
CVS : $Id: posixstar.c,v 1.1 2003-06-18 08:13:02 trimarchi Exp $ |
|
File: $File$ |
Revision: $Revision: 1.1 $ |
Last update: $Date: 2003-06-18 08:13:02 $ |
------------ |
|
This file contains the scheduling module compatible with POSIX |
specifications |
|
Read posixstar.h for further details. |
|
RR tasks have the CONTROL_CAP bit set |
|
**/ |
|
/* |
* Copyright (C) 2000 Paolo Gai |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARR2ANTY; without even the implied waRR2anty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* |
*/ |
|
|
#include <ll/stdio.h> |
#include <ll/string.h> |
#include <kernel/model.h> |
#include <kernel/descr.h> |
#include <kernel/var.h> |
#include <kernel/func.h> |
#include <kernel/trace.h> |
#include "posixstar.h" |
#include "cbsstar.h" |
//#define POSIXSTAR_DEBUG |
/*+ Status used in the level +*/ |
#define POSIXSTAR_READY MODULE_STATUS_BASE |
|
/*+ the level redefinition for the Round Robin level +*/ |
typedef struct { |
level_des l; /*+ the standard level descriptor +*/ |
|
int nact[MAX_PROC]; /*+ number of pending activations +*/ |
|
int priority[MAX_PROC]; /*+ priority of each task +*/ |
|
IQUEUE *ready; /*+ the ready queue array +*/ |
|
int slice; /*+ the level's time slice +*/ |
|
// the multiboot is not usefull for this module |
// struct multiboot_info *multiboot; /*+ used if the level have to insert |
// the main task +*/ |
int maxpriority; /*+ the priority are from 0 to maxpriority |
(i.e 0 to 31) +*/ |
|
int yielding; /*+ equal to 1 when a sched_yield is called +*/ |
|
int budget; |
|
PID activated; |
int scheduling_level; |
|
} POSIXSTAR_level_des; |
|
/* the private scheduler choice a task and insert in cbsstar module */ |
/* This is not efficient but very fair :-) |
The need of all this stuff is because if a task execute a long time |
due to (shadow!) priority inheritance, then the task shall go to the |
tail of the queue many times... */ |
|
static void POSIXSTAR_private_scheduler(POSIXSTAR_level_des * lev) |
{ |
/* the old posix scheduler select the private job for CBS */ |
PID p=NIL; |
|
int prio; |
|
prio = lev->maxpriority; |
|
for (;;) { |
p = iq_query_first(&lev->ready[prio]); |
if (p == NIL) { |
if (prio) { |
prio--; |
continue; |
} |
else { |
p=NIL; |
break; |
} |
} |
//if (p != NIL && (proc_table[p].control & CONTROL_CAP)) |
// kern_printf("CC SET %d",p); |
|
//kern_printf("task %d", p); |
|
if ((proc_table[p].control & CONTROL_CAP) && |
(proc_table[p].avail_time <= 0)) { |
proc_table[p].avail_time += proc_table[p].wcet; |
//kern_printf("RR policy"); |
iq_extract(p,&lev->ready[prio]); |
iq_insertlast(p,&lev->ready[prio]); |
} |
else { |
break; |
} |
} |
|
if (p!=lev->activated) { |
if (lev->activated != NIL ) { |
level_table[ lev->scheduling_level ]-> |
private_extract(lev->scheduling_level, lev->activated); |
//kern_printf("CBS ext %d", lev->activated); |
} |
lev->activated = p; |
|
if (p != NIL) { |
BUDGET_TASK_MODEL b; |
budget_task_default_model(b, lev->budget); |
// viene inserito nel CBS |
//#ifdef POSIXSTAR_DEBUG |
//kern_printf("CBS Ins %d",p); |
//#endif |
level_table[ lev->scheduling_level ]-> |
private_insert(lev->scheduling_level, p, (TASK_MODEL *)&b); |
} |
} |
} |
|
static int POSIXSTAR_public_eligible(LEVEL l, PID p) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
if (p==lev->activated) { |
//kern_printf("eli %d", p); |
|
return level_table[ lev->scheduling_level ]-> |
private_eligible(lev->scheduling_level,p); |
} |
return 0; |
} |
|
|
static int POSIXSTAR_public_create(LEVEL l, PID p, TASK_MODEL *m) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
NRT_TASK_MODEL *nrt; |
|
if (m->pclass != NRT_PCLASS) return -1; |
if (m->level != 0 && m->level != l) return -1; |
|
nrt = (NRT_TASK_MODEL *)m; |
|
/* the task state is set at SLEEP by the general task_create */ |
|
/* I used the wcet field because using wcet can account if a task |
consume more than the timeslice... */ |
|
if (nrt->inherit == NRT_INHERIT_SCHED && |
proc_table[exec_shadow].task_level == l) { |
/* We inherit the scheduling properties if the scheduling level |
*is* the same */ |
lev->priority[p] = lev->priority[exec_shadow]; |
|
proc_table[p].avail_time = proc_table[exec_shadow].avail_time; |
proc_table[p].wcet = proc_table[exec_shadow].wcet; |
|
proc_table[p].control = (proc_table[p].control & ~CONTROL_CAP) | |
(proc_table[exec_shadow].control & CONTROL_CAP); |
|
lev->nact[p] = (lev->nact[exec_shadow] == -1) ? -1 : 0; |
} |
else { |
if (nrt->weight<=lev->maxpriority) |
lev->priority[p] = nrt->weight; |
else lev->priority[p]=lev->maxpriority; |
|
if (nrt->slice) { |
proc_table[p].avail_time = nrt->slice; |
proc_table[p].wcet = nrt->slice; |
} |
else { |
proc_table[p].avail_time = lev->slice; |
proc_table[p].wcet = lev->slice; |
} |
|
if (nrt->policy == NRT_RR_POLICY) { |
proc_table[p].control |= CONTROL_CAP; |
//kern_printf("CCAP set:%d",p); |
|
} |
if (nrt->arrivals == SAVE_ARRIVALS) |
lev->nact[p] = 0; |
else |
lev->nact[p] = -1; |
} |
|
return 0; /* OK */ |
} |
|
static void POSIXSTAR_public_dispatch(LEVEL l, PID p, int nostop) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
|
//#ifdef POSIXSTAR_DEBUG |
//kern_printf("PDisp:%d(%d)",p, lev->activated); |
//#endif |
|
/* the task state is set EXE by the scheduler() |
we extract the task from the ready queue |
NB: we can't assume that p is the first task in the queue!!! */ |
//iq_extract(p, &lev->ready[lev->priority[p]]); |
if (p==lev->activated) { |
level_table[lev->scheduling_level]->private_dispatch(lev->scheduling_level, p, nostop); |
} |
} |
|
static void POSIXSTAR_public_epilogue(LEVEL l, PID p) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
//#ifdef POSIXSTAR_DEBUG |
//kern_printf("PEpic:%d(%d)",p, lev->activated); |
//#endif |
if (p==lev->activated) { |
if (lev->yielding) { |
lev->yielding = 0; |
iq_extract(p,&lev->ready[lev->priority[p]]); |
iq_insertlast(p,&lev->ready[lev->priority[p]]); |
} |
/* check if the slice is finished and insert the task in the coPOSIXect |
qqueue position */ |
else if (proc_table[p].control & CONTROL_CAP && |
proc_table[p].avail_time <= 0) { |
|
//proc_table[p].avail_time += proc_table[p].wcet; |
//kern_printf("avail_time %d", proc_table[p].avail_time); |
iq_extract(p,&lev->ready[lev->priority[p]]); |
iq_insertlast(p,&lev->ready[lev->priority[p]]); |
//level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p); |
//lev->activated=NIL; |
POSIXSTAR_private_scheduler(lev); |
} |
else { |
//iq_insertfirst(p,&lev->ready[lev->priority[p]]); |
level_table[lev->scheduling_level]->private_epilogue(lev->scheduling_level,p); |
} |
|
proc_table[p].status = POSIXSTAR_READY; |
|
} |
} |
|
static void POSIXSTAR_internal_activate(POSIXSTAR_level_des *lev, PID p) |
{ |
|
/* Insert task in the correct position */ |
proc_table[p].status = POSIXSTAR_READY; |
iq_insertlast(p,&lev->ready[lev->priority[p]]); |
|
} |
|
|
static void POSIXSTAR_public_activate(LEVEL l, PID p) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
|
/* Test if we are trying to activate a non sleeping task */ |
/* save activation (only if needed...) */ |
if (proc_table[p].status != SLEEP) { |
if (lev->nact[p] != -1) |
lev->nact[p]++; |
return; |
} |
#ifdef POSIXSTAR_DEBUG |
kern_printf("PA:%d",p); |
#endif |
POSIXSTAR_internal_activate(lev, p); |
POSIXSTAR_private_scheduler(lev); |
|
} |
|
|
static void POSIXSTAR_public_unblock(LEVEL l, PID p) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
|
/* Similar to POSIX_task_activate, but we don't check in what state |
the task is */ |
|
/* Insert task in the coPOSIXect position */ |
proc_table[p].status = POSIXSTAR_READY; |
iq_insertlast(p,&lev->ready[lev->priority[p]]); |
POSIXSTAR_private_scheduler(lev); |
} |
|
static void POSIXSTAR_public_block(LEVEL l, PID p) |
{ |
/* Extract the running task from the level |
. we have already extract it from the ready queue at the dispatch time. |
. the capacity event have to be removed by the generic kernel |
. the wcet don't need modification... |
. the state of the task is set by the calling function |
|
So, we do nothing!!! |
*/ |
|
//#ifdef POSIXSTAR_DEBUG |
//kern_printf("PB:%d", p); |
//#endif |
} |
|
static int POSIXSTAR_public_message(LEVEL l, PID p, void *m) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
|
if (lev->nact[p] > 0) { |
/* continue!!!! */ |
lev->nact[p]--; |
iq_insertfirst(p,&lev->ready[lev->priority[p]]); |
proc_table[p].status = POSIXSTAR_READY; |
} |
else { |
proc_table[p].status = SLEEP; |
|
} |
//#ifdef POSIXSTAR_DEBUG |
//kern_printf("PM:%d",p); |
//#endif |
//jet_update_endcycle(); /* Update the Jet data... */ |
//trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */ |
POSIXSTAR_private_scheduler(lev); |
return 0; |
} |
|
static void POSIXSTAR_public_end(LEVEL l, PID p) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
#ifdef POSIXSTAR_DEBUG |
kern_printf("PEnd:%d", p); |
#endif |
lev->nact[p] = -1; |
|
/* then, we insert the task in the free queue */ |
proc_table[p].status = FREE; |
iq_priority_insert(p,NULL); |
POSIXSTAR_private_scheduler(lev); |
} |
|
/* Registration functions */ |
|
/*+ Registration function: |
TIME slice the slice for the Round Robin queue |
struct multiboot_info *mb used if createmain specified +*/ |
LEVEL POSIXSTAR_register_level(int budget, int master, TIME slice, |
int prioritylevels) |
{ |
LEVEL l; /* the level that we register */ |
POSIXSTAR_level_des *lev; /* for readableness only */ |
PID i; /* a counter */ |
int x; /* a counter */ |
|
printk("POSIXSTAR_register_level\n"); |
|
l = level_alloc_descriptor(sizeof(POSIXSTAR_level_des)); |
|
lev = (POSIXSTAR_level_des *)level_table[l]; |
|
printk(" lev=%d\n",(int)lev); |
|
/* fill the standard descriptor */ |
/* |
lev->l.private_insert = NULL; |
lev->l.private_extract = NULL; |
lev->l.private_dispatch = NULL; |
lev->l.private_epilogue = NULL; |
*/ |
|
//lev->l.public_scheduler = NULL; |
lev->l.public_create = POSIXSTAR_public_create; |
lev->l.public_end = POSIXSTAR_public_end; |
lev->l.public_dispatch = POSIXSTAR_public_dispatch; |
lev->l.public_epilogue = POSIXSTAR_public_epilogue; |
lev->l.public_activate = POSIXSTAR_public_activate; |
lev->l.public_unblock = POSIXSTAR_public_unblock; |
lev->l.public_block = POSIXSTAR_public_block; |
lev->l.public_message = POSIXSTAR_public_message; |
lev->l.public_eligible = POSIXSTAR_public_eligible; |
|
/* fill the POSIX descriptor part */ |
for (i = 0; i < MAX_PROC; i++) |
lev->nact[i] = -1; |
|
lev->maxpriority = prioritylevels -1; |
|
lev->ready = (IQUEUE *)kern_alloc(sizeof(IQUEUE) * prioritylevels); |
|
for (x = 0; x < prioritylevels; x++) |
iq_init(&lev->ready[x], NULL, 0); |
|
if (slice < POSIXSTAR_MINIMUM_SLICE) slice = POSIXSTAR_MINIMUM_SLICE; |
if (slice > POSIXSTAR_MAXIMUM_SLICE) slice = POSIXSTAR_MAXIMUM_SLICE; |
lev->slice = slice; |
lev->activated=NIL; |
lev->budget = budget; |
lev->scheduling_level = master; |
//lev->multiboot = mb; |
|
//if (createmain) |
// sys_atrunlevel(POSIXSTAR_call_main,(void *) l, RUNLEVEL_INIT); |
|
return l; |
} |
|
/*+ this function forces the running task to go to his queue tail; |
(it works only on the POSIX level) +*/ |
int POSIXSTAR_sched_yield(LEVEL l) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
|
if (proc_table[exec_shadow].task_level != l) |
return -1; |
|
proc_table[exec_shadow].context = kern_context_save(); |
lev->yielding = 1; |
scheduler(); |
kern_context_load(proc_table[exec_shadow].context); |
return 0; |
} |
|
/*+ this function returns the maximum level allowed for the POSIX level +*/ |
int POSIXSTAR_get_priority_max(LEVEL l) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
return lev->maxpriority; |
} |
|
/*+ this function returns the default timeslice for the POSIX level +*/ |
int POSIXSTAR_rr_get_interval(LEVEL l) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
return lev->slice; |
} |
|
/*+ this functions returns some paramaters of a task; |
policy must be NRT_RR_POLICY or NRT_FIFO_POLICY; |
priority must be in the range [0..prioritylevels] |
returns ENOSYS or ESRCH if there are problems +*/ |
int POSIXSTAR_getschedparam(LEVEL l, PID p, int *policy, int *priority) |
{ |
if (p<0 || p>= MAX_PROC || proc_table[p].status == FREE) |
return ESRCH; |
|
if (proc_table[p].task_level != l) |
return ENOSYS; |
|
if (proc_table[p].control & CONTROL_CAP) |
*policy = NRT_RR_POLICY; |
else |
*policy = NRT_FIFO_POLICY; |
|
*priority = ((POSIXSTAR_level_des *)(level_table[l]))->priority[p]; |
|
return 0; |
} |
|
/*+ this functions sets paramaters of a task +*/ |
int POSIXSTAR_setschedparam(LEVEL l, PID p, int policy, int priority) |
{ |
POSIXSTAR_level_des *lev = (POSIXSTAR_level_des *)(level_table[l]); |
|
if (p<0 || p>= MAX_PROC || proc_table[p].status == FREE) |
return ESRCH; |
|
if (proc_table[p].task_level != l) |
return ENOSYS; |
|
if (policy == SCHED_RR) |
proc_table[p].control |= CONTROL_CAP; |
else if (policy == SCHED_FIFO) |
proc_table[p].control &= ~CONTROL_CAP; |
else |
return EINVAL; |
|
if (lev->priority[p] != priority) { |
if (proc_table[p].status == POSIXSTAR_READY) { |
iq_extract(p,&lev->ready[lev->priority[p]]); |
lev->priority[p] = priority; |
iq_insertlast(p,&lev->ready[priority]); |
} |
else |
lev->priority[p] = priority; |
} |
|
return 0; |
} |
|
|
|