Rev 1108 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Paolo Gai <pj@gandalf.sssup.it>
* Massimiliano Giorgi <massy@gandalf.sssup.it>
* Luca Abeni <luca@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: cash.c,v 1.4 2003-01-07 17:10:16 pj Exp $
File: $File$
Revision: $Revision: 1.4 $
Last update: $Date: 2003-01-07 17:10:16 $
------------
This file contains the aperiodic server CBS (Total Bandwidth Server)
Read CBS.h for further details.
**/
/*
* 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 WARRANTY; without even the implied warranty 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 "cash.h"
#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>
/*+ Status used in the level +*/
#define CBSGHD_IDLE APER_STATUS_BASE /*+ waiting the activation +*/
#define CBSGHD_ZOMBIE APER_STATUS_BASE+1 /*+ waiting the period end +*/
/* structure of an element of the capacity queue */
struct cap_queue {
int cap;
struct timespec dead;
struct cap_queue *next;
};
/*+ the level redefinition for the CBS_HD level +*/
typedef struct {
level_des l; /*+ the standard level descriptor +*/
/* The wcet are stored in the task descriptor, but we need
an array for the deadlines. We can't use the timespec_priority
field because it is used by the master level!!!...
Notice that however the use of the timespec_priority field
does not cause any problem... */
struct timespec cbsghd_dline[MAX_PROC]; /*+ CBSGHD deadlines +*/
TIME period[MAX_PROC]; /*+ CBSGHD activation period +*/
TIME maxperiod[MAX_PROC]; /*+ maximum period of each elastic task +*/
int cremaining[MAX_PROC]; /*+ instance remaining computation time +*/
TIME act_period[MAX_PROC]; /*+ actual period of each elastic task: it
must be less than maxperiod!!! +*/
struct timespec request_time[MAX_PROC]; /* used for the response time */
TIME last_response_time[MAX_PROC]; /* response time of the last instance */
TIME cnormal[MAX_PROC]; /*+ CBSGHD normal computation time +*/
struct timespec reactivation_time[MAX_PROC];
/*+ the time at witch the reactivation timer is post +*/
int reactivation_timer[MAX_PROC];
/*+ the recativation timer +*/
struct cap_queue *queue; /* pointer to the spare capacity queue */
int flags; /*+ the init flags... +*/
bandwidth_t U; /*+ the used bandwidth by the server +*/
int idle; /* the idle flag... */
struct timespec start_idle; /*gives the start time of the last idle period */
LEVEL scheduling_level;
} CBSGHD_level_des;
/* insert a capacity in the queue capacity ordering by deadline */
static int c_insert(struct timespec dead, int cap, struct cap_queue **que,
PID p)
{
struct cap_queue *prev, *n, *new;
prev = NULL;
n = *que;
while ((n != NULL) &&
!TIMESPEC_A_LT_B(&dead, &n->dead)) {
prev = n;
n = n->next;
}
new = (struct cap_queue *)kern_alloc(sizeof(struct cap_queue));
if (new == NULL) {
kern_printf("\nNew cash_queue element failed\n");
kern_raise(XINVALID_TASK, p);
return -1;
}
new->next = NULL;
new->cap = cap;
new->dead = dead;
if (prev != NULL)
prev->next = new;
else
*que = new;
if (n != NULL)
new->next = n;
return 0;
}
/* extract the first element from the capacity queue */
static int c_extractfirst(struct cap_queue **que)
{
struct cap_queue *p = *que;
if (*que == NULL) return(-1);
*que = (*que)->next;
kern_free(p, sizeof(struct cap_queue));
return(1);
}
/* read data of the first element from the capacity queue */
static void c_readfirst(struct timespec *d, int *c, struct cap_queue *que)
{
*d = que->dead;
*c = que->cap;
}
/* write data of the first element from the capacity queue */
static void c_writefirst(struct timespec dead, int cap, struct cap_queue *que)
{
que->dead = dead;
que->cap = cap;
}
static void CBSGHD_activation(CBSGHD_level_des *lev,
PID p,
struct timespec *acttime)
{
JOB_TASK_MODEL job;
/* This rule is used when we recharge the budget at initial task activation
and each time a new task instance must be activated */
if (TIMESPEC_A_GT_B(acttime, &lev->cbsghd_dline[p])) {
/* we modify the deadline ... */
TIMESPEC_ASSIGN(&lev->cbsghd_dline[p], acttime);
}
lev->act_period[p] = 0;
if (proc_table[p].avail_time > 0)
proc_table[p].avail_time = 0;
/* there is a while because if the wcet is << than the system tick
we need to postpone the deadline many times */
while (proc_table[p].avail_time <= 0) {
/* A spare capacity is inserted in the capacity queue!! */
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbsghd_dline[p]);
lev->act_period[p] += lev->period[p];
c_insert(lev->cbsghd_dline[p], lev->cnormal[p], &lev->queue, p);
/* it exploits available capacities from the capacity queue */
while (proc_table[p].avail_time < (int)lev->cnormal[p] &&
lev->queue != NULL) {
struct timespec dead;
int cap, delta;
delta = lev->cnormal[p] - proc_table[p].avail_time;
c_readfirst(&dead, &cap, lev->queue);
if (!TIMESPEC_A_GT_B(&dead, &lev->cbsghd_dline[p])) {
if (cap > delta) {
proc_table[p].avail_time += delta;
c_writefirst(dead, cap - delta, lev->queue);
}
else {
proc_table[p].avail_time += cap;
c_extractfirst(&lev->queue);
}
}
else
break;
}
}
lev->cremaining[p] = proc_table[p].wcet - proc_table[p].avail_time;
#ifdef TESTG
if (starttime && p == 3) {
oldx = x;
x = ((lev->cbsghd_dline[p].tv_sec*1000000+lev->cbsghd_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
// kern_printf("(a%d)",lev->cbsghd_dline[p].tv_sec*1000000+lev->cbsghd_dline[p].tv_nsec/1000);
if (oldx > x) sys_end();
if (x<640)
grx_plot(x, 15, 8);
}
#endif
/* and, finally, we reinsert the task in the master level */
job_task_default_model(job, lev->cbsghd_dline[p]);
job_task_def_yesexc(job);
level_table[ lev->scheduling_level ]->
private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
}
/* this is the periodic reactivation of the task... */
static void CBSGHD_timer_reactivate(void *par)
{
PID p = (PID) par;
CBSGHD_level_des *lev;
lev = (CBSGHD_level_des *)level_table[proc_table[p].task_level];
if (proc_table[p].status == CBSGHD_IDLE) {
/* the task has finished the current activation and must be
reactivated */
/* request_time represents the time of the last instance release!! */
TIMESPEC_ASSIGN(&lev->request_time[p], &lev->reactivation_time[p]);
/* If idle=1, then we have to discharge the capacities stored in
the capacity queue up to the length of the idle interval */
if (lev->idle == 1) {
TIME interval;
struct timespec delta;
lev->idle = 0;
SUBTIMESPEC(&lev->request_time[p], &lev->start_idle, &delta);
/* length of the idle interval expressed in usec! */
interval = TIMESPEC2NANOSEC(&delta) / 1000;
/* it discharge the available capacities from the capacity queue */
while (interval > 0 && lev->queue != NULL) {
struct timespec dead;
int cap;
c_readfirst(&dead, &cap, lev->queue);
if (cap > interval) {
c_writefirst(dead, cap - interval, lev->queue);
interval = 0;
}
else {
interval -= cap;
c_extractfirst(&lev->queue);
}
}
}
CBSGHD_activation(lev,p,&lev->reactivation_time[p]);
/* check the constraint on the maximum period permitted... */
if (lev->act_period[p] > lev->maxperiod[p]) {
kern_printf("Deadline miss(timer_react.! process:%d act_period:%lu maxperiod:%lu\n",
p, lev->act_period[p], lev->maxperiod[p]);
kern_raise(XDEADLINE_MISS,p);
}
/* Set the reactivation timer */
TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbsghd_dline[p]);
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBSGHD_timer_reactivate,
(void *)p);
event_need_reschedule();
}
else {
/* this situation cannot occur */
kern_printf("Trying to reactivate a task which is not IDLE!!!/n");
kern_raise(XINVALID_TASK,p);
}
}
static void CBSGHD_avail_time_check(CBSGHD_level_des *lev, PID p)
{
/*+ if the capacity became negative the remaining computation time
is diminuished.... +*/
/* if (p==4)
kern_printf("(old dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
if (proc_table[p].avail_time < 0)
lev->cremaining[p] += proc_table[p].avail_time;
if (lev->cremaining[p] <= 0) {
kern_printf("Task:%d WCET violation \n", p);
kern_raise(XWCET_VIOLATION, p);
ll_abort(666);
}
/* there is a while because if the wcet is << than the system tick
we need to postpone the deadline many times */
while (proc_table[p].avail_time <= 0) {
/* it exploits available capacities from the capacity queue */
while (proc_table[p].avail_time < lev->cremaining[p]
&& lev->queue != NULL) {
struct timespec dead;
int cap, delta;
delta = lev->cremaining[p] - proc_table[p].avail_time;
c_readfirst(&dead, &cap, lev->queue);
if (!TIMESPEC_A_GT_B(&dead, &lev->cbsghd_dline[p])) {
if (cap > delta) {
proc_table[p].avail_time += delta;
c_writefirst(dead, cap - delta, lev->queue);
}
else {
proc_table[p].avail_time += cap;
c_extractfirst(&lev->queue);
}
}
else
break;
}
/* if (p==5 && proc_table[p].avail_time <= 0 &&
lev->cremaining[p] > lev->cnormal[p])
kern_printf("(inter dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
/* The remaining computation time is modified according
to the new budget! */
if (proc_table[p].avail_time > 0)
lev->cremaining[p] -= proc_table[p].avail_time;
else {
/* the CBSGHD rule for recharging the capacity: */
if (lev->cremaining[p] > lev->cnormal[p]) {
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbsghd_dline[p]);
lev->act_period[p] += lev->period[p];
/* A spare capacity is inserted in the capacity queue!! */
c_insert(lev->cbsghd_dline[p], lev->cnormal[p], &lev->queue, p);
}
else {
TIME t;
t = (lev->cremaining[p] * lev->period[p]) / lev->cnormal[p];
ADDUSEC2TIMESPEC(t, &lev->cbsghd_dline[p]);
lev->act_period[p] += t;
/* A spare capacity is inserted in the capacity queue!! */
c_insert(lev->cbsghd_dline[p], lev->cremaining[p], &lev->queue, p);
}
}
}
/* if (p==4)
kern_printf("n dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
/* check the constraint on the maximum period permitted... */
if (lev->act_period[p] > lev->maxperiod[p]) {
/*kern_printf("n dead:%d av_time:%d crem:%d)\n",
lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000, proc_table[p].avail_time,
lev->cremaining[p]); */
kern_printf("Deadline miss(av.time_check! process:%d act_period:%lu maxperiod:%lu\n",
p, lev->act_period[p], lev->maxperiod[p]);
kern_raise(XDEADLINE_MISS,p);
}
if (TIMESPEC_A_LT_B(&lev->reactivation_time[p], &lev->cbsghd_dline[p])) {
/* we delete the reactivation timer */
kern_event_delete(lev->reactivation_timer[p]);
/* repost the event at the next instance deadline... */
lev->reactivation_time[p] = lev->cbsghd_dline[p];
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBSGHD_timer_reactivate,
(void *)p);
}
#ifdef TESTG
if (starttime && p == 3) {
oldx = x;
x = ((lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
// kern_printf("(e%d avail%d)",lev->cbsghd_dline[p].tv_sec*1000000+
lev->cbsghd_dline[p].tv_nsec/1000,proc_table[p].avail_time);
if (oldx > x) sys_end();
if (x<640)
grx_plot(x, 15, 2);
}
#endif
}
/*+ this function is called when a killed or ended task reach the
period end +*/
static void CBSGHD_timer_zombie(void *par)
{
PID p = (PID) par;
CBSGHD_level_des *lev;
lev = (CBSGHD_level_des *)level_table[proc_table[p].task_level];
/* we finally put the task in the FREE status */
proc_table[p].status = FREE;
iq_insertfirst(p,&freedesc);
/* and free the allocated bandwidth */
lev->U -= (MAX_BANDWIDTH/lev->period[p]) * lev->cnormal[p];
}
static PID CBSGHD_public_scheduler(LEVEL l)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
/* it stores the actual time and set the IDLE flag in order to handle
the capacity queue discharging!!! */
lev->idle = 1;
kern_gettime(&lev->start_idle);
/* the CBSGHD don't schedule anything...
it's an EDF level or similar that do it! */
return NIL;
}
/* The on-line guarantee is enabled only if the appropriate flag is set... */
static int CBSGHD_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
if (lev->flags & CBSGHD_FAILED_GUARANTEE) {
*freebandwidth = 0;
//kern_printf("guarantee :garanzia fallita!!!!!!\n");
return 0;
}
else if (*freebandwidth >= lev->U) {
*freebandwidth -= lev->U;
return 1;
}
else {
//kern_printf("guarantee :garanzia fallita per mancanza di banda!!!!!!\n");
//kern_printf("freeband: %d request band: %d", *freebandwidth, lev->U);
return 0;
}
}
static int CBSGHD_public_create(LEVEL l, PID p, TASK_MODEL *m)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
ELASTIC_HARD_TASK_MODEL *s;
bandwidth_t b1, b2;
if (m->pclass != ELASTIC_HARD_PCLASS) return -1;
if (m->level != 0 && m->level != l) return -1;
s = (ELASTIC_HARD_TASK_MODEL *)m;
/* kern_printf("accept :ELASTIC TASK found!!!!!!\n"); */
b1 = (MAX_BANDWIDTH / s->period) * s->cnormal;
b2 = (MAX_BANDWIDTH / s->maxperiod) * s->wcet;
if (!(s->wcet && s->cnormal && s->period && s->maxperiod &&
s->wcet >= s->cnormal && b1 >= b2) )
return -1;
/* kern_printf("period: %d maxperiod: %d cnormal: %d wcet: %d, b1: %d b2:
%d\n", s->period, s->maxperiod, s->cnormal, s->wcet, b1, b2); */
/* now we know that m is a valid model */
/* Enable wcet check */
proc_table[p].avail_time = 0;
proc_table[p].wcet = s->wcet;
proc_table[p].control |= CONTROL_CAP;
lev->period[p] = s->period;
lev->maxperiod[p] = s->maxperiod;
lev->cnormal[p] = s->cnormal;
NULL_TIMESPEC(&lev->cbsghd_dline[p]);
NULL_TIMESPEC(&lev->request_time[p]);
/* update the bandwidth... */
if (lev->flags & CBSGHD_ENABLE_GUARANTEE) {
bandwidth_t b;
b = (MAX_BANDWIDTH / s->period) * s->cnormal;
/* really update lev->U, checking an overflow... */
if (MAX_BANDWIDTH - lev->U > b)
lev->U += b;
else
/* The task can NOT be guaranteed (U>MAX_BANDWIDTH)...
(see EDF.c) */
lev->flags |= CBSGHD_FAILED_GUARANTEE;
}
return 0; /* OK, also if the task cannot be guaranteed... */
}
static void CBSGHD_public_detach(LEVEL l, PID p)
{
/* the CBSGHD level doesn't introduce any dinamic allocated new field.
we have only to reset the NO_GUARANTEE FIELD and decrement the allocated
bandwidth */
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
if (lev->flags & CBSGHD_FAILED_GUARANTEE)
lev->flags &= ~CBSGHD_FAILED_GUARANTEE;
else
lev->U -= (MAX_BANDWIDTH / lev->period[p]) * lev->cnormal[p];
}
static void CBSGHD_public_dispatch(LEVEL l, PID p, int nostop)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
level_table[ lev->scheduling_level ]->
private_dispatch(lev->scheduling_level,p,nostop);
}
static void CBSGHD_public_epilogue(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
JOB_TASK_MODEL job;
/* check if the budget is finished... */
if ( proc_table[p].avail_time <= 0) {
/* we kill the current activation */
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level, p);
/* we modify the deadline */
CBSGHD_avail_time_check(lev, p);
/* and, finally, we reinsert the task in the master level */
job_task_default_model(job, lev->cbsghd_dline[p]);
job_task_def_yesexc(job);
level_table[ lev->scheduling_level ]->
private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
// kern_printf("epil : dl %d per %d p %d |\n",
// lev->cbsghd_dline[p].tv_nsec/1000,lev->period[p],p);
}
else
/* the task has been preempted. it returns into the ready queue by
calling the guest_epilogue... */
level_table[ lev->scheduling_level ]->
private_epilogue(lev->scheduling_level,p);
}
static void CBSGHD_public_activate(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
kern_gettime(&lev->request_time[p]);
/* If idle=1, then we have to discharge the capacities stored in
the capacity queue up to the length of the idle interval */
if (lev->idle == 1) {
TIME interval;
struct timespec delta;
lev->idle = 0;
SUBTIMESPEC(&lev->request_time[p], &lev->start_idle, &delta);
/* length of the idle interval expressed in usec! */
interval = TIMESPEC2NANOSEC(&delta) / 1000;
/* it discharge the available capacities from the capacity queue */
while (interval > 0 && lev->queue != NULL) {
struct timespec dead;
int cap;
c_readfirst(&dead, &cap, lev->queue);
if (cap > interval) {
c_writefirst(dead, cap - interval, lev->queue);
interval = 0;
}
else {
interval -= cap;
c_extractfirst(&lev->queue);
}
}
}
CBSGHD_activation(lev, p, &lev->request_time[p]);
/* check the constraint on the maximum period permitted... */
if (lev->act_period[p] > lev->maxperiod[p]) {
kern_printf("Deadline miss(task_activ.! process:%d act_period:%lu maxperiod:%lu\n",
p, lev->act_period[p], lev->maxperiod[p]);
kern_raise(XDEADLINE_MISS,p);
}
/* Set the reactivation timer */
TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbsghd_dline[p]);
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBSGHD_timer_reactivate,
(void *)p);
// kern_printf("act : %d %d |",lev->cbsghd_dline[p].tv_nsec/1000,p);
}
static void CBSGHD_public_unblock(LEVEL l, PID p)
{
printk("CBSGHD_task_insert\n");
kern_raise(XINVALID_TASK,p);
}
static void CBSGHD_public_block(LEVEL l, PID p)
{
printk("CBSGHD_task_extract\n");
kern_raise(XINVALID_TASK,p);
}
static int CBSGHD_public_message(LEVEL l, PID p, void *m)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
struct timespec act_time, res;
/* It computes the response time of the current instance... */
kern_gettime(&act_time);
SUBTIMESPEC(&act_time, &lev->request_time[p], &res);
/* response time expressed in usec! */
lev->last_response_time[p] = TIMESPEC2NANOSEC(&res) / 1000;
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level,p);
/* A spare capacity is inserted in the capacity queue!! */
if (proc_table[p].avail_time > 0) {
c_insert(lev->cbsghd_dline[p], proc_table[p].avail_time, &lev->queue, p);
proc_table[p].avail_time = 0;
}
proc_table[p].status = CBSGHD_IDLE;
jet_update_endcycle(); /* Update the Jet data... */
trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */
return 0;
}
static void CBSGHD_public_end(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
/* check if the capacity became negative... */
/* there is a while because if the wcet is << than the system tick
we need to postpone the deadline many times */
while (proc_table[p].avail_time < 0) {
/* the CBSGHD rule for recharging the capacity */
proc_table[p].avail_time += lev->cnormal[p];
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbsghd_dline[p]);
}
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level,p);
/* we delete the reactivation timer */
kern_event_delete(lev->reactivation_timer[p]);
lev->reactivation_timer[p] = -1;
/* Finally, we post the zombie event. when the end period is reached,
the task descriptor and banwidth are freed */
proc_table[p].status = CBSGHD_ZOMBIE;
lev->reactivation_timer[p] = kern_event_post(&lev->cbsghd_dline[p],
CBSGHD_timer_zombie,
(void *)p);
}
/* Registration functions */
/*+ Registration function:
int flags the init flags ... see CBS.h +*/
LEVEL CBSGHD_register_level(int flags, LEVEL master)
{
LEVEL l; /* the level that we register */
CBSGHD_level_des *lev; /* for readableness only */
PID i; /* a counter */
printk("CBSGHD_register_level\n");
/* request an entry in the level_table */
l = level_alloc_descriptor(sizeof(CBSGHD_level_des));
lev = (CBSGHD_level_des *)level_table[l];
printk(" lev=%d\n",(int)lev);
/* fill the standard descriptor */
lev->l.public_scheduler = CBSGHD_public_scheduler;
if (flags & CBSGHD_ENABLE_GUARANTEE)
lev->l.public_guarantee = CBSGHD_public_guarantee;
else
lev->l.public_guarantee = NULL;
lev->l.public_create = CBSGHD_public_create;
lev->l.public_detach = CBSGHD_public_detach;
lev->l.public_end = CBSGHD_public_end;
lev->l.public_dispatch = CBSGHD_public_dispatch;
lev->l.public_epilogue = CBSGHD_public_epilogue;
lev->l.public_activate = CBSGHD_public_activate;
lev->l.public_unblock = CBSGHD_public_unblock;
lev->l.public_block = CBSGHD_public_block;
lev->l.public_message = CBSGHD_public_message;
/* fill the CBSGHD descriptor part */
for (i=0; i<MAX_PROC; i++) {
NULL_TIMESPEC(&lev->cbsghd_dline[i]);
lev->period[i] = 0;
NULL_TIMESPEC(&lev->request_time[i]);
lev->last_response_time[i] = 0;
NULL_TIMESPEC(&lev->reactivation_time[i]);
lev->reactivation_timer[i] = -1;
}
lev->U = 0;
lev->idle = 0;
lev->queue = NULL;
lev->scheduling_level = master;
lev->flags = flags & 0x07;
return l;
}
int CBSGHD_get_response_time(LEVEL l, PID p)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
return lev->last_response_time[p];
}
bandwidth_t CBSGHD_usedbandwidth(LEVEL l)
{
CBSGHD_level_des *lev = (CBSGHD_level_des *)(level_table[l]);
return lev->U;
}