Rev 676 |
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 :
* Giacomo Guidi <giacomo@gandalf.sssup.it>
* Mauro Marinoni
* Anton Cervin
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
/*
* 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/model.h>
#include <kernel/descr.h>
#include <kernel/var.h>
#include <kernel/func.h>
#include <stdlib.h>
#include <modules/elastic.h>
#include <tracer.h>
#define ELASTIC_EMPTY_SLOT 0
#define ELASTIC_PRESENT 1
#define ELASTIC_SAVE_ARRIVALS 2
#define ELASTIC_DEBUG
typedef struct {
struct timespec dline
;
TIME Tmin
;
TIME Tmax
;
TIME period
;
TIME wcet
;
bandwidth_t Up
;
int kelastic
;
int beta
;
int nact
;
int flags
;
int arrivals
;
} ELASTIC_task_descr
;
typedef struct {
level_des l
; /*+ the standard level descriptor +*/
bandwidth_t U
; /*+ the used bandwidth by the server +*/
ELASTIC_task_descr
*elist
;
LEVEL scheduling_level
;
LEVEL current_level
;
int flags
;
} ELASTIC_level_des
;
static int ELASTIC_recompute
(ELASTIC_level_des
*lev
) {
PID i
;
for (i
=0; i
<MAX_PROC
; i
++) {
if (lev
->elist
[i
].
flags & ELASTIC_PRESENT
)
lev
->elist
[i
].
period = lev
->elist
[i
].
Tmax;
}
return 0;
}
static int ELASTIC_check_guarantie
(ELASTIC_level_des
*lev
) {
return 0;
}
static void ELASTIC_activation
(ELASTIC_level_des
*lev
,
PID p
,
struct timespec
*acttime
)
{
JOB_TASK_MODEL job
;
/* Job deadline */
TIMESPEC_ASSIGN
(&(lev
->elist
[p
].
dline),acttime
);
ADDUSEC2TIMESPEC
(lev
->elist
[p
].
period,&(lev
->elist
[p
].
dline));
/* Job insertion */
job_task_default_model
(job
, lev
->elist
[p
].
dline);
level_table
[ lev
->scheduling_level
]->
private_insert
(lev
->scheduling_level
, p
, (TASK_MODEL
*)&job
);
}
static void ELASTIC_timer_act
(void *arg
) {
PID p
= (PID
)(arg
);
ELASTIC_level_des
*lev
;
struct timespec acttime
;
kern_gettime
(&acttime
);
lev
= (ELASTIC_level_des
*)level_table
[proc_table
[p
].
task_level];
ELASTIC_activation
(lev
, p
, &acttime
);
}
/* The on-line guarantee is enabled only if the appropriate flag is set... */
static int ELASTIC_public_guarantee
(LEVEL l
, bandwidth_t
*freebandwidth
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
return 0;
}
static int ELASTIC_public_create
(LEVEL l
, PID p
, TASK_MODEL
*m
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
ELASTIC_TASK_MODEL
*elastic
;
if (m
->pclass
!= ELASTIC_PCLASS
) return -1;
if (m
->level
!= 0 && m
->level
!= l
) return -1;
elastic
= (ELASTIC_TASK_MODEL
*)m
;
if (elastic
->wcet
== 0) return -1;
if (elastic
->Tmin
> elastic
->Tmax
) return -1;
if (elastic
->Tmax
== 0) return -1;
lev
->elist
[p
].
flags |= ELASTIC_PRESENT
;
NULL_TIMESPEC
(&(lev
->elist
[p
].
dline));
lev
->elist
[p
].
Tmin = elastic
->Tmin
;
lev
->elist
[p
].
Tmax = elastic
->Tmax
;
lev
->elist
[p
].
wcet = elastic
->wcet
;
lev
->elist
[p
].
kelastic = elastic
->kelastic
;
lev
->elist
[p
].
beta = elastic
->beta
;
if (lev
->flags
& ELASTIC_ENABLE_GUARANTEE
)
if (ELASTIC_check_guarantie
(lev
) != 0) {
lev
->elist
[p
].
flags = ELASTIC_EMPTY_SLOT
;
return -1;
}
ELASTIC_recompute
(lev
);
if (lev
->elist
[p
].
period == 0) {
lev
->elist
[p
].
flags = ELASTIC_EMPTY_SLOT
;
return -1;
}
proc_table
[p
].
avail_time = elastic
->wcet
;
proc_table
[p
].
wcet = elastic
->wcet
;
proc_table
[p
].
control |= CONTROL_CAP
;
if (elastic
->arrivals
== SAVE_ARRIVALS
)
lev
->elist
[p
].
arrivals |= ELASTIC_SAVE_ARRIVALS
;
return 0; /* OK, also if the task cannot be guaranteed... */
}
static void ELASTIC_public_detach
(LEVEL l
, PID p
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
}
static int ELASTIC_public_eligible
(LEVEL l
, PID p
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
return 0;
}
static void ELASTIC_public_dispatch
(LEVEL l
, PID p
, int nostop
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
level_table
[ lev
->scheduling_level
]->
private_dispatch
(lev
->scheduling_level
,p
,nostop
);
}
static void ELASTIC_public_epilogue
(LEVEL l
, PID p
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
/* check if the wcet is finished... */
if (proc_table
[p
].
avail_time <= 0) {
TRACER_LOGEVENT
(FTrace_EVT_task_wcet_violation
,(unsigned short int)proc_table
[p
].
context,0);
kern_raise
(XWCET_VIOLATION
,p
);
}
level_table
[ lev
->scheduling_level
]->
private_epilogue
(lev
->scheduling_level
,p
);
}
static void ELASTIC_public_activate
(LEVEL l
, PID p
, struct timespec
*t
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
#ifdef ELASTIC_DEBUG
printk
("(ELASTIC:Act:%d)", p
);
#endif
/* check if we are not in the SLEEP state */
if (proc_table
[p
].
status != SLEEP
) {
if (lev
->elist
[p
].
arrivals & ELASTIC_SAVE_ARRIVALS
) {
/* skip the sporadic job, but increase a counter */
#ifdef ELASTIC_DEBUG
printk
("(ELASTIC:SaveAct:%d)", p
);
#endif
lev
->elist
[p
].
nact++;
}
return;
}
ELASTIC_activation
(lev
,p
,t
);
/* Next activation */
kern_event_post
(&(lev
->elist
[p
].
dline), ELASTIC_timer_act
, (void *)(p
));
}
static void ELASTIC_public_unblock
(LEVEL l
, PID p
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
struct timespec acttime
;
kern_gettime
(&acttime
);
ELASTIC_activation
(lev
,p
,&acttime
);
}
static void ELASTIC_public_block
(LEVEL l
, PID p
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
level_table
[ lev
->scheduling_level
]->
private_extract
(lev
->scheduling_level
,p
);
}
static int ELASTIC_public_message
(LEVEL l
, PID p
, void *m
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
struct timespec acttime
;
switch((long)(m
)) {
case (long)(NULL
):
level_table
[ lev
->scheduling_level
]->
private_extract
(lev
->scheduling_level
,p
);
if (lev
->elist
[p
].
nact > 0) {
lev
->elist
[p
].
nact--;
kern_gettime
(&acttime
);
ELASTIC_activation
(lev
,p
,&acttime
);
}
jet_update_endcycle
(); /* Update the Jet data... */
TRACER_LOGEVENT
(FTrace_EVT_task_end_cycle
,(unsigned short int)proc_table
[p
].
context,(unsigned int)l
);
break;
case 1:
level_table
[ lev
->scheduling_level
]->
private_extract
(lev
->scheduling_level
,p
);
proc_table
[p
].
status = SLEEP
;
TRACER_LOGEVENT
(FTrace_EVT_task_disable
,(unsigned short int)proc_table
[p
].
context,(unsigned int)l
);
break;
}
return 0;
}
static void ELASTIC_public_end
(LEVEL l
, PID p
)
{
ELASTIC_level_des
*lev
= (ELASTIC_level_des
*)(level_table
[l
]);
level_table
[ lev
->scheduling_level
]->
private_extract
(lev
->scheduling_level
,p
);
}
/*+ Registration function +*/
LEVEL ELASTIC_register_level
(int flags
, LEVEL master
)
{
LEVEL l
; /* the level that we register */
ELASTIC_level_des
*lev
; /* for readableness only */
PID i
;
printk
("ELASTIC_register_level\n");
/* request an entry in the level_table */
l
= level_alloc_descriptor
(sizeof(ELASTIC_level_des
));
lev
= (ELASTIC_level_des
*)level_table
[l
];
/* fill the standard descriptor */
if (flags
& ELASTIC_ENABLE_GUARANTEE
)
lev
->l.
public_guarantee = ELASTIC_public_guarantee
;
else
lev
->l.
public_guarantee = NULL
;
lev
->l.
public_create = ELASTIC_public_create
;
lev
->l.
public_detach = ELASTIC_public_detach
;
lev
->l.
public_end = ELASTIC_public_end
;
lev
->l.
public_eligible = ELASTIC_public_eligible
;
lev
->l.
public_dispatch = ELASTIC_public_dispatch
;
lev
->l.
public_epilogue = ELASTIC_public_epilogue
;
lev
->l.
public_activate = ELASTIC_public_activate
;
lev
->l.
public_unblock = ELASTIC_public_unblock
;
lev
->l.
public_block = ELASTIC_public_block
;
lev
->l.
public_message = ELASTIC_public_message
;
lev
->elist
= malloc(MAX_PROC
* sizeof(ELASTIC_task_descr
));
if (lev
->elist
== NULL
) {
printk
("ELASTIC: Error allocating elastic task decriptor table\n");
sys_end
();
}
/* fill the ELASTIC task descriptor part */
for (i
=0; i
<MAX_PROC
; i
++) {
NULL_TIMESPEC
(&(lev
->elist
[i
].
dline));
lev
->elist
[i
].
Tmin = 0;
lev
->elist
[i
].
Tmax = 0;
lev
->elist
[i
].
period = 0;
lev
->elist
[i
].
wcet = 0;
lev
->elist
[i
].
Up = 0;
lev
->elist
[i
].
kelastic = 0;
lev
->elist
[i
].
beta = 0;
lev
->elist
[i
].
nact = 0;
lev
->elist
[i
].
arrivals = SKIP_ARRIVALS
;
lev
->elist
[i
].
flags = ELASTIC_EMPTY_SLOT
;
}
lev
->U
= 0;
lev
->scheduling_level
= master
;
lev
->current_level
= l
;
lev
->flags
= flags
;
return l
;
}