Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 1633 → Rev 1632

/advdemos/trunk/cbs_ft/cbs_ft.c
0,0 → 1,811
/*
* Project: S.Ha.R.K.
*
* Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@hartik.sssup.it>
*
* Authors : Marco Caccamo and Paolo Gai
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
/**
------------
CVS : $Id: cbs_ft.c,v 1.1.1.1 2004-05-24 17:54:50 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:50 $
------------
 
This file contains the server CBS_FT
 
Read CBS_FT.h for further details.
 
**/
 
/*
* Copyright (C) 2000 Marco Caccamo and 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 "cbs_ft.h"
 
/*+ Status used in the level +*/
#define CBS_FT_IDLE APER_STATUS_BASE /*+ waiting the activation +*/
#define CBS_FT_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_FT 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 cbs_ft_dline[MAX_PROC]; /*+ CBS_FT deadlines +*/
 
TIME period[MAX_PROC]; /*+ CBS_FT activation period +*/
 
 
int maxcap[MAX_PROC]; /* amount of capacity reserved to a primary+backup
couple */
PID backup[MAX_PROC]; /* Backup task pointers, defined for primary tasks */
 
char CP[MAX_PROC]; /* checkpoint flag */
char P_or_B[MAX_PROC]; /* Type of task: PRIMARY or BACKUP */
 
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;
 
} CBS_FT_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 */
 
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 CBS_FT_activation(CBS_FT_level_des *lev,
PID p,
struct timespec *acttime)
{
JOB_TASK_MODEL job;
int capacity;
/* 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->cbs_ft_dline[p])) {
/* we modify the deadline ... */
TIMESPEC_ASSIGN(&lev->cbs_ft_dline[p], acttime);
}
 
if (proc_table[p].avail_time > 0)
proc_table[p].avail_time = 0;
 
 
/* A spare capacity is inserted in the capacity queue!! */
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_ft_dline[p]);
capacity = lev->maxcap[p] - proc_table[ lev->backup[p] ].wcet;
c_insert(lev->cbs_ft_dline[p], capacity, &lev->queue, p);
/* it exploits available capacities from the capacity queue */
while (proc_table[p].avail_time < proc_table[p].wcet &&
lev->queue != NULL) {
struct timespec dead;
int cap, delta;
delta = proc_table[p].wcet - proc_table[p].avail_time;
c_readfirst(&dead, &cap, lev->queue);
if (!TIMESPEC_A_GT_B(&dead, &lev->cbs_ft_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 the budget is still less than 0, an exception is raised */
if (proc_table[p].avail_time <= 0) {
kern_printf("\nnegative value for the budget!\n");
kern_raise(XINVALID_TASK, p);
return;
}
 
 
/*if (p==6)
kern_printf("(act_time:%d dead:%d av_time:%d)\n",
acttime->tv_sec*1000000+
acttime->tv_nsec/1000,
lev->cbs_ft_dline[p].tv_sec*1000000+
lev->cbs_ft_dline[p].tv_nsec/1000,
proc_table[p].avail_time); */
 
 
 
 
 
#ifdef TESTG
if (starttime && p == 3) {
oldx = x;
x = ((lev->cbs_ft_dline[p].tv_sec*1000000+lev->cbs_ft_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
// kern_printf("(a%d)",lev->cbs_ft_dline[p].tv_sec*1000000+lev->cbs_ft_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->cbs_ft_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 CBS_FT_timer_reactivate(void *par)
{
PID p = (PID) par;
CBS_FT_level_des *lev;
struct timespec t;
 
lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
 
if (proc_table[p].status == CBS_FT_IDLE) {
/* the task has finished the current activation and must be
reactivated */
/* request_time represents the time of the last instance release!! */
TIMESPEC_ASSIGN(&t, &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(&t, &lev->start_idle, &delta);
/* length of the idle interval expressed in usec! */
interval = TIMESPEC2NANOSEC(&delta) / 1000;
 
/* it discharges 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);
}
}
}
 
CBS_FT_activation(lev,p,&lev->reactivation_time[p]);
 
/* Set the reactivation timer */
TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_ft_dline[p]);
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBS_FT_timer_reactivate,
(void *)p);
event_need_reschedule();
}
else {
/* this situation cannot occur */
kern_printf("\nTrying to reactivate a primary task which is not IDLE!\n");
kern_raise(XINVALID_TASK,p);
}
}
 
 
 
static void CBS_FT_avail_time_check(CBS_FT_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)\n",
lev->cbs_ft_dline[p].tv_sec*1000000+
lev->cbs_ft_dline[p].tv_nsec/1000,
proc_table[p].avail_time); */
 
 
int newcap = proc_table[p].wcet / 100 * 30;
if (newcap <= 0)
newcap = proc_table[p].wcet;
/* it exploits available capacities from the capacity queue */
while (proc_table[p].avail_time < newcap
&& lev->queue != NULL) {
struct timespec dead;
int cap, delta;
delta = newcap - proc_table[p].avail_time;
c_readfirst(&dead, &cap, lev->queue);
if (!TIMESPEC_A_GT_B(&dead, &lev->cbs_ft_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==6)
kern_printf("(ATC dead:%d av_time:%d)\n",
lev->cbs_ft_dline[p].tv_sec*1000000+
lev->cbs_ft_dline[p].tv_nsec/1000,
proc_table[p].avail_time); */
 
 
/* if the budget is still empty, the backup task must be woken up.
Remind that a short chunk of primary will go ahead executing
before the task switch occurs */
if (proc_table[p].avail_time <= 0) {
lev->CP[p] = 1;
proc_table[p].avail_time += proc_table[ lev->backup[p] ].wcet;
}
 
 
/*if (p==6)
kern_printf("(ATC1 dead:%d av_time:%d)\n",
lev->cbs_ft_dline[p].tv_sec*1000000+
lev->cbs_ft_dline[p].tv_nsec/1000,
proc_table[p].avail_time); */
 
 
}
 
 
/*+ this function is called when a killed or ended task reach the
period end +*/
static void CBS_FT_timer_zombie(void *par)
{
PID p = (PID) par;
CBS_FT_level_des *lev;
 
lev = (CBS_FT_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]) * (TIME)lev->maxcap[p];
}
 
static PID CBS_FT_public_scheduler(LEVEL l)
{
CBS_FT_level_des *lev = (CBS_FT_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 CBS_FT 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 CBS_FT_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
 
if (lev->flags & CBS_FT_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 CBS_FT_public_create(LEVEL l, PID p, TASK_MODEL *m)
 
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
FT_TASK_MODEL *s;
 
if (m->pclass != FT_PCLASS) return -1;
if (m->level != 0 && m->level != l) return -1;
s = (FT_TASK_MODEL *) m;
//kern_printf("accept :FAULT TOLERANT TASK found!!!!!!\n"); */
if (!(s->type == PRIMARY && s->execP > 0 && s->budget < (int)s->period
&& s->backup != NIL)) return -1;
if (!(s->type == BACKUP && s->wcetB > 0))
return -1;
/* now we know that m is a valid model */
/* Enable budget check */
proc_table[p].control |= CONTROL_CAP;
 
proc_table[p].avail_time = 0;
NULL_TIMESPEC(&lev->cbs_ft_dline[p]);
 
 
if (s->type == PRIMARY) {
proc_table[p].wcet = (int)s->execP;
lev->period[p] = s->period;
lev->maxcap[p] = s->budget;
lev->backup[p] = s->backup;
lev->CP[p] = 0;
lev->P_or_B[p] = PRIMARY;
 
/* update the bandwidth... */
if (lev->flags & CBS_FT_ENABLE_GUARANTEE) {
bandwidth_t b;
b = (MAX_BANDWIDTH / lev->period[p]) * (TIME)lev->maxcap[p];
/* 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 |= CBS_FT_FAILED_GUARANTEE;
}
}
else {
proc_table[p].wcet = (int)s->wcetB;
lev->P_or_B[p] = BACKUP;
 
/* Backup tasks are unkillable tasks! */
proc_table[p].control |= NO_KILL;
}
return 0; /* OK, also if the task cannot be guaranteed... */
}
 
 
static void CBS_FT_public_detach(LEVEL l, PID p)
{
/* the CBS_FT level doesn't introduce any dynamic allocated new field.
we have only to reset the NO_GUARANTEE FIELD and decrement the allocated
bandwidth */
 
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
 
if (lev->flags & CBS_FT_FAILED_GUARANTEE)
lev->flags &= ~CBS_FT_FAILED_GUARANTEE;
else
lev->U -= (MAX_BANDWIDTH / lev->period[p]) * (TIME)lev->maxcap[p];
}
 
 
static void CBS_FT_public_dispatch(LEVEL l, PID p, int nostop)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
level_table[ lev->scheduling_level ]->
private_dispatch(lev->scheduling_level,p,nostop);
}
 
static void CBS_FT_public_epilogue(LEVEL l, PID p)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
 
/* check if the budget is finished... */
if (proc_table[p].avail_time <= 0) {
 
/* A backup task cannot ever exhaust its budget! */
if (lev->P_or_B[p] == BACKUP) {
kern_printf("\nBACKUP wcet violation!\n");
kern_raise(XWCET_VIOLATION,p);
/* we kill the current activation */
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level, p);
return;
}
 
/* we try to recharge the budget */
CBS_FT_avail_time_check(lev, p);
 
/* The budget must be greater than 0! */
if (proc_table[p].avail_time <= 0) {
kern_printf("\nBackup task starting with exhausted budget\n");
kern_raise(XINVALID_TASK, p);
lev->CP[p] = 0;
/* we kill the current activation */
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level, p);
return;
}
}
/* the task returns into the ready queue by
calling the guest_epilogue... */
level_table[ lev->scheduling_level ]->
private_epilogue(lev->scheduling_level,p);
}
 
 
static void CBS_FT_public_activate(LEVEL l, PID p)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
struct timespec t;
 
kern_gettime(&t);
 
if (lev->P_or_B[p] == BACKUP) {
kern_printf("\nTrying to activate a BACKUP task!\n");
kern_raise(XINVALID_TASK, p);
}
else {
/* 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(&t, &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);
}
}
}
CBS_FT_activation(lev, p, &t);
/* Set the reactivation timer */
TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_ft_dline[p]);
lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
CBS_FT_timer_reactivate,
(void *)p);
// kern_printf("act : %d %d |",lev->cbs_ft_dline[p].tv_nsec/1000,p);
}
}
 
static int CBS_FT_public_message(LEVEL l, PID p, void *m)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
 
level_table[ lev->scheduling_level ]->
private_extract(lev->scheduling_level,p);
 
proc_table[p].status = CBS_FT_IDLE;
 
if (lev->P_or_B[p] == PRIMARY) {
if (lev->CP[p]) {
JOB_TASK_MODEL job;
/* We have to start the backup task */
TIMESPEC_ASSIGN(&lev->cbs_ft_dline[ lev->backup[p] ],
&lev->cbs_ft_dline[p]);
proc_table[ lev->backup[p] ].avail_time = proc_table[p].avail_time;
lev->CP[p] = 0;
 
/* and, finally, we insert the backup task in the master level */
job_task_default_model(job, lev->cbs_ft_dline[p]);
job_task_def_yesexc(job);
level_table[ lev->scheduling_level ]->
private_insert(lev->scheduling_level, lev->backup[p],
(TASK_MODEL *)&job);
}
else {
/* A spare capacity is inserted in the capacity queue!! */
proc_table[p].avail_time += proc_table[ lev->backup[p] ].wcet;
if (proc_table[p].avail_time > 0) {
c_insert(lev->cbs_ft_dline[p], proc_table[p].avail_time,
&lev->queue, p);
proc_table[p].avail_time = 0;
}
}
}
else {
/* this branch is for backup tasks:
A spare capacity is inserted in the capacity queue!! */
if (proc_table[p].avail_time > 0) {
c_insert(lev->cbs_ft_dline[p], proc_table[p].avail_time,
&lev->queue, p);
proc_table[p].avail_time = 0;
}
}
 
jet_update_endcycle(); /* Update the Jet data... */
 
return 0;
}
 
 
static void CBS_FT_public_end(LEVEL l, PID p)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
 
/* A backup task cannot be killed, this behaviour can be modified
in a new release */
if (lev->P_or_B[p] == BACKUP) {
kern_printf("\nKilling a BACKUP task!\n");
kern_raise(XINVALID_TASK, p);
return;
}
 
/* check if the capacity becomes 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 CBS_FT rule for recharging the capacity */
proc_table[p].avail_time += lev->maxcap[p];
ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_ft_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 = CBS_FT_ZOMBIE;
lev->reactivation_timer[p] = kern_event_post(&lev->cbs_ft_dline[p],
CBS_FT_timer_zombie,
(void *)p);
}
 
/* Registration functions */
 
/*+ Registration function:
int flags the init flags ... see CBS.h +*/
LEVEL CBS_FT_register_level(int flags, LEVEL master)
{
LEVEL l; /* the level that we register */
CBS_FT_level_des *lev; /* for readableness only */
PID i; /* a counter */
 
printk("CBS_FT_register_level\n");
 
/* request an entry in the level_table */
l = level_alloc_descriptor(sizeof(CBS_FT_level_des));
 
lev = (CBS_FT_level_des *)level_table[l];
 
printk(" lev=%d\n",(int)lev);
 
/* fill the standard descriptor */
lev->l.public_scheduler = CBS_FT_public_scheduler;
 
if (flags & CBS_FT_ENABLE_GUARANTEE)
lev->l.public_guarantee = CBS_FT_public_guarantee;
else
lev->l.public_guarantee = NULL;
 
lev->l.public_create = CBS_FT_public_create;
lev->l.public_detach = CBS_FT_public_detach;
lev->l.public_end = CBS_FT_public_end;
lev->l.public_dispatch = CBS_FT_public_dispatch;
lev->l.public_epilogue = CBS_FT_public_epilogue;
lev->l.public_activate = CBS_FT_public_activate;
lev->l.public_message = CBS_FT_public_message;
 
/* fill the CBS_FT descriptor part */
for (i=0; i<MAX_PROC; i++) {
NULL_TIMESPEC(&lev->cbs_ft_dline[i]);
lev->period[i] = 0;
NULL_TIMESPEC(&lev->reactivation_time[i]);
lev->reactivation_timer[i] = -1;
lev->maxcap[i] = 0;
lev->backup[i] = NIL;
lev->CP[i] = 0;
lev->P_or_B[i] = PRIMARY;
}
 
lev->U = 0;
lev->idle = 0;
lev->queue = NULL;
lev->scheduling_level = master;
 
lev->flags = flags & 0x07;
 
return l;
}
 
 
 
bandwidth_t CBS_FT_usedbandwidth(LEVEL l)
{
CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
 
return lev->U;
}
 
 
 
void CBS_FT_Primary_Abort()
{
PID p;
CBS_FT_level_des *lev;
 
kern_cli();
p = exec_shadow;
lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
lev->CP[p] = 1;
kern_sti();
}
 
 
char CBS_FT_Checkpoint()
{
char f;
PID p;
CBS_FT_level_des *lev;
kern_cli();
p = exec_shadow;
lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
f = lev->CP[p];
kern_sti();
return f;
}
/advdemos/trunk/cbs_ft/initfile.c
0,0 → 1,112
/*
* Project: S.Ha.R.K.
*
* Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@hartik.sssup.it>
*
* Authors : Marco caccamo and Paolo Gai
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
/**
------------
CVS : $Id: initfile.c,v 1.1.1.1 2004-05-24 17:54:50 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:50 $
------------
 
This file contains the server CBS_FT
 
Read CBS_FT.h for further details.
 
**/
 
/*
* Copyright (C) 2000 Marco Caccamo and 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 "kernel/kern.h"
#include <modules/edf.h>
#include <modules/rr.h>
#include "cbs_ft.h"
#include <modules/cbs.h>
#include <modules/dummy.h>
#include <drivers/keyb.h>
#include <modules/hartport.h>
#include <modules/sem.h>
#include <modules/cabs.h>
 
/*+ system tick in us +*/
#define TICK 300
#define RRTICK 5000
 
 
TIME __kernel_register_levels__(void *arg)
{
struct multiboot_info *mb = (struct multiboot_info *)arg;
 
EDF_register_level(EDF_ENABLE_ALL);
CBS_FT_register_level(CBS_FT_ENABLE_ALL, 0);
RR_register_level(RRTICK, RR_MAIN_YES, mb);
CBS_register_level(CBS_ENABLE_ALL, 0);
dummy_register_level();
 
SEM_register_module();
CABS_register_module();
// periodic timer
return TICK;
// one-shot timer
// return 0
}
 
 
TASK __init__(void *arg)
{
struct multiboot_info *mb = (struct multiboot_info *)arg;
 
HARTPORT_init();
 
KEYB_init(NULL);
 
__call_main__(mb);
 
return (void *)0;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/advdemos/trunk/cbs_ft/cbs_ft.h
0,0 → 1,166
/*
* Project: S.Ha.R.K.
*
* Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@hartik.sssup.it>
*
* Authors : Marco Caccamo and Paolo Gai
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
/**
------------
CVS : $Id: cbs_ft.h,v 1.1.1.1 2004-05-24 17:54:50 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:50 $
------------
 
This file contains the server CBS_FT
 
Read CBS_FT.h for further details.
 
**/
 
/*
* Copyright (C) 2000 Marco Caccamo and 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
*
*/
 
#ifndef __CBS_FT__
#define __CBS_FT__
 
 
 
#include <ll/string.h>
#include <kernel/model.h>
#include <kernel/descr.h>
#include <kernel/var.h>
#include <kernel/func.h>
 
 
 
 
 
 
/*+ flags... +*/
#define CBS_FT_ENABLE_GUARANTEE 1 /*+ Task Guarantee enabled +*/
#define CBS_FT_ENABLE_ALL 1
 
#define CBS_FT_FAILED_GUARANTEE 8 /*+ used in the module, unsettable
in EDF_register_level... +*/
 
 
#define PRIMARY 1
#define BACKUP 2
#define FT_PCLASS 0x0700 // Nuova classe di task, quelli fault_tolerant
 
#define CBS_FT_LEVELNAME "CBSFT base"
#define CBS_FT_LEVEL_CODE 110
#define CBS_FT_LEVEL_VERSION 1
 
 
/* The Fault-Tolerant Task model extends the base task model
This model cannot be APERIODIC, only PERIODIC tasks are allowed.
A faut-tolerant application is composed by two different tasks (primary and
backup). The backup task is characterized by its WCET and its type (BACKUP).
The primary task must define the task period, its average execution time
(used as sort of prediction in order to recharge the budget using the
capacity cash queue!), the budget (budget / period = U that is, the
bandwidth assigned to the fault-tolerant application), its type (PRIMARY)
and finally the PID of the corresponding backup task. */
typedef struct {
TASK_MODEL t;
TIME wcetB; // WCET of the backup job (BACKUP TASK ONLY)
 
TIME execP; // average exec. time of the primary job (PRIMARY TASK ONLY)
 
TIME period; // period of the fault-tolerant task (PRIMARY TASK ONLY)
 
int budget; // amount of guaranteed capacity (PRIMARY TASK ONLY)
 
char type; // PRIMARY or BACKUP
 
PID backup; // (PRIMARY TASK ONLY)
} FT_TASK_MODEL;
 
 
#define ft_task_default_model(m) \
task_default_model((m).t,FT_PCLASS), \
(m).period = 0, \
(m).wcetB = 0, \
(m).execP = 0, \
(m).budget = 0, \
(m).type = BACKUP, \
(m).backup = NIL
 
#define ft_task_def_level(m,l) task_def_level((m).t,l)
#define ft_task_def_arg(m,a) task_def_arg((m).t,a)
#define ft_task_def_stack(m,s) task_def_stack((m).t,s)
#define ft_task_def_stackaddr(m,s) task_def_stackaddr((m).t,s)
#define ft_task_def_usemath(m) task_def_usemath((m).t)
#define ft_task_def_ctrl_jet(m) task_def_ctrl_jet((m).t)
#define ft_task_def_group(m,g) task_def_group((m).t,g)
#define ft_task_def_period(m,o) (m).period = (o)
#define ft_task_def_budget(m,o) (m).budget = (o)
#define ft_task_def_backup(m) (m).type = BACKUP
#define ft_task_def_primary(m) (m).type = PRIMARY
#define ft_task_def_backup_task(m,b) (m).backup = b
#define ft_task_def_backup_wcet(m,b) (m).wcetB = b
#define ft_task_def_primary_exec(m,b) (m).execP = b
 
/************************************************************************/
LEVEL CBS_FT_register_level(int flags, LEVEL master);
 
 
bandwidth_t CBS_FT_usedbandwidth(LEVEL l);
 
 
 
/* This function notifies to a primary task that the task itself has to
suspend its execution (the task has to suspend itself with a
task_endcycle() */
char CBS_FT_Checkpoint(void);
 
 
 
/* This function sets the checkpoint flag! hence, at the next checkpoint,
that is:
 
if (CBS_FT_Checkpoint()) {
task_endcycle();
continue;
}
 
the primary task will suspend itself switching to the backup task */
void CBS_FT_Primary_Abort(void);
 
/***************************************************************************/
 
 
 
 
#endif
/advdemos/trunk/cbs_ft/prova.c
0,0 → 1,429
/*
* Project: S.Ha.R.K.
*
* Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@hartik.sssup.it>
*
* Authors : Marco Caccamo and Paolo Gai
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
/**
------------
CVS : $Id: prova.c,v 1.1.1.1 2004-05-24 17:54:50 giacomo Exp $
 
File: $File$
Revision: $Revision: 1.1.1.1 $
Last update: $Date: 2004-05-24 17:54:50 $
------------
 
testcash.c
test for the CASH Module, directly derived from Test Number 13 (D)
 
**/
 
/*
* Copyright (C) 2000 Marco Caccamo and 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 <modules/edf.h>
#include "cbs_ft.h"
#include <math.h>
#include <stdlib.h>
 
#define ASTER_LIM 60
#define DISPLAY_MAX 15
 
#define STAT_Y 9
 
#define INPUT 0.5
 
 
 
#define MAX_STAT 10000
#define RVAL 1
#define XVAL 2
#define DVAL 3
 
 
struct statistic {
TIME r_time;
TIME ex_time;
long dead_post;
};
 
 
 
struct statistic stat[MAX_STAT];
TIME val[MAX_STAT];
 
int n_stat = 0;
 
TASK hard_aster1p(void)
{
int i;
int y = 1;
int load1,j;
 
char s[2];
 
s[0] = 'P'; s[1] = 0;
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 20000; //+ rand() % 25000;
for (j=0; j<load1; j++) {
if (CBS_FT_Checkpoint())
break;
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(1, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
 
TASK hard_aster1b(void)
{
int i;
int y = 1;
 
int load1,j;
 
char s[2];
 
s[0] = 'B'; s[1] = 0;
 
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 20000;// + rand()%4000;
for (j=0; j<load1; j++) {
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(1, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
 
TASK hard_aster2p(void)
{
int i;
int y = 3;
 
int load1,j;
 
char s[2];
 
s[0] = 'P'; s[1] = 0;
 
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 20000 + rand() % 20000;
for (j=0; j<load1; j++) {
if (CBS_FT_Checkpoint())
break;
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(5, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
TASK hard_aster2b(void)
{
int i;
int y = 3;
 
int load1,j;
 
char s[2];
 
s[0] = 'T'; s[1] = 0;
 
for (;;) {
i = 1;
while (i < ASTER_LIM) {
load1 = 20000;
for (j=0; j<load1; j++) {
puts_xy(i,y,rand()%15+1,s);
}
//kern_cli();
//stat[n_stat].r_time = CBSGHD_get_response_time(5, exec_shadow);
//jet_gettable(exec_shadow, &stat[n_stat].ex_time, 1);
//kern_sti();
//n_stat++;
task_endcycle();
puts_xy(i,y,WHITE," ");
i++;
}
}
}
 
 
TASK clock()
{
int s = 0, m = 0;
 
while(1) {
printf_xy(62,1,WHITE,"%2d:%2d",m,s);
printf_xy(62,2,WHITE,"Utot=%12u",MAX_BANDWIDTH);
printf_xy(62,3,WHITE,"Uedf=%12u",EDF_usedbandwidth(0));
printf_xy(62,4,WHITE,"Ucbs=%12u",CBS_FT_usedbandwidth(1));
task_endcycle();
if (++s > 59) {
s = 0;
m++;
}
printf_xy(62,1,WHITE,"%2d:%2d",m,s);
printf_xy(62,2,WHITE,"Utot=%12u",MAX_BANDWIDTH);
printf_xy(62,3,WHITE,"Uedf=%12u",EDF_usedbandwidth(0));
printf_xy(62,4,WHITE,"Ucbs=%12u",CBS_FT_usedbandwidth(1));
task_endcycle();
}
}
 
 
 
/* we consider the first ASTER_MAX + 2 tasks from the PID 2
and plot on the screen the elapsed times... */
TASK jetcontrol()
{
int i; /* a counter */
TIME sum, max, curr, last[5];
int nact;
int j; /* the elements set by jet_gettable */
PID p;
 
 
kern_cli();
printf_xy(0,STAT_Y,WHITE,"PID ³ Mean T.³ Max T. ³ N.A. ³ Curr. ³ Last1 ³ Last2 ³ Last3 ³ Last4 ³ Last5");
kern_sti();
 
for (;;) {
for (i=0,p=0; i<DISPLAY_MAX+5 && p<MAX_PROC; p++) {
if (jet_getstat(p, &sum, &max, &nact, &curr) == -1) continue;
 
for (j=0; j<5; j++) last[j] = 0;
jet_gettable(p, &last[0], 5);
kern_cli();
printf_xy(0,STAT_Y+i+1,WHITE,"%-3d ³ %-6ld ³ %-6ld ³ %-4d ³ %-7ld ³ %-5ld ³ %-5ld ³ %-5ld ³ %-5ld ³ %-5ld", p, sum/(nact==0 ? 1 : nact), max,
nact, curr, last[0], last[1], last[2], last[3], last[4]);
kern_sti();
i++;
}
task_endcycle();
}
}
 
 
void save_stat(struct statistic p[], int n, char *name, int type)
{
DOS_FILE *f;
int i;
char outstring[500];
for(i = 0; i < 500; i++)
outstring[i] = '0';
f = DOS_fopen(name, "w");
if (!f) {
cprintf("Cannot open %s!!!", name);
goto end1;
}
for(i = 0; i < n; i++) {
if (type == RVAL)
val[i] = p[i].r_time;
if (type == XVAL)
val[i] = p[i].ex_time;
if (type == DVAL)
val[i] = p[i].dead_post;
}
memset(outstring, 0, 300);
sprintf(outstring, "%ld \n", (long int)n);
cprintf("%s", outstring);
DOS_fwrite(outstring, 1, strlen(outstring), f);
 
for(i = 0; i < n; i++) {
memset(outstring, 0, 300);
sprintf(outstring, "%ld %lu\n", (long int)i, val[i]);
//cprintf("%s", outstring);
DOS_fwrite(outstring, 1, strlen(outstring), f);
}
DOS_fclose(f);
end1:cprintf("OK?");
}
 
 
void result_save(void *p)
{
save_stat(stat, n_stat, "stat1.tim", RVAL);
}
 
 
void fine()
{
ll_abort(666);
}
 
int main(int argc, char **argv)
{
PID p1,p2,p3, p4, p5, p6;
 
HARD_TASK_MODEL m;
FT_TASK_MODEL ftb;
FT_TASK_MODEL ftp;
// int i;
struct timespec fineprg;
 
 
//sys_atrunlevel(result_save, NULL, RUNLEVEL_AFTER_EXIT);
srand(7);
 
hard_task_default_model(m);
hard_task_def_wcet(m,500);
hard_task_def_mit(m,500000);
hard_task_def_periodic(m);
hard_task_def_group(m,1);
hard_task_def_ctrl_jet(m);
 
 
p1 = task_create("Clock",clock,&m,NULL);
if (p1 == -1) {
perror("testhd.c(main): Could not create task <Clock> ...");
sys_end();
}
 
 
hard_task_def_wcet(m,500);
hard_task_def_periodic(m);
hard_task_def_mit(m,100000);
p2 = task_create("JetControl",jetcontrol,&m,NULL);
if (p2 == -1) {
perror("testhd.c(main): Could not create task <JetControl> ...");
sys_end();
}
 
 
ft_task_default_model(ftb);
ft_task_def_usemath(ftb);
ft_task_def_backup(ftb);
ft_task_def_ctrl_jet(ftb);
ft_task_def_backup_wcet(ftb, 7000);
 
p3 = task_create("Hard_aster1b", hard_aster1b, &ftb,NULL);
if (p3 == -1) {
perror("testhd.c(main): Could not create task <aster1b> ...");
sys_end();
}
 
ft_task_default_model(ftp);
ft_task_def_usemath(ftp);
ft_task_def_ctrl_jet(ftp);
ft_task_def_group(ftp, 1);
ft_task_def_period(ftp, 50000);
ft_task_def_budget(ftp, 15000);
ft_task_def_primary_exec(ftp, 7300);
ft_task_def_primary(ftp);
ft_task_def_backup_task(ftp, p3);
p4 = task_create("Hard_aster1p", hard_aster1p, &ftp, NULL);
if (p4 == -1) {
perror("testhd.c(main): Could not create task <aster1p> ...");
sys_end();
}
 
 
ft_task_def_backup_wcet(ftb, 6700);
 
p5 = task_create("Hard_aster2b", hard_aster2b, &ftb, NULL);
if (p5 == -1) {
perror("testhd.c(main): Could not create task <aster2b> ...");
sys_end();
}
 
 
ft_task_def_period(ftp, 100000);
ft_task_def_budget(ftp, 8000);
ft_task_def_primary_exec(ftp, 11000);
ft_task_def_backup_task(ftp, p5);
p6 = task_create("Hard_aster2p", hard_aster2p, &ftp, NULL);
if (p6 == -1) {
perror("testhd.c(main): Could not create task <aster2p> ...");
sys_end();
}
 
 
printf_xy(0,STAT_Y + 15,WHITE,"Hard asteroide PID= %-3d ",p3);
printf_xy(0,STAT_Y + 17,WHITE,"Clock PID= %-3d ",p1);
printf_xy(0,STAT_Y + 18,WHITE,"JetControl PID= %-3d ",p2);
 
task_nopreempt();
fineprg.tv_sec = 10;
fineprg.tv_nsec = 0;
kern_event_post(&fineprg,fine,NULL);
group_activate(1);
return 0;
}
 
/advdemos/trunk/cbs_ft/readme.txt
0,0 → 1,6
This Example has been made by Marco Caccamo.
 
There is not a lot of documentation available, so if you have problems please
send an e-mail to Marco ( http://gandalf.sssup.it/~caccamo/ )
 
Paolo
/advdemos/trunk/cbs_ft/makefile
0,0 → 1,17
#
#
#
 
ifndef BASE
BASE=../..
endif
include $(BASE)/config/config.mk
 
PROGS= prova
 
include $(BASE)/config/example.mk
 
prova:
make -f $(SUBMAKE) APP=prova INIT= OTHEROBJS="initfile.o cbs_ft.o" OTHERINCL= SHARKOPT="__OLDCHAR__ __GRX__"