Blame |
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: slsh.c,v 1.1 2004-06-01 11:42:46 giacomo Exp $
File: $File$
Revision: $Revision: 1.1 $
Last update: $Date: 2004-06-01 11:42:46 $
------------
This file contains the scheduling module for Slot-Shifting.
Read slsh.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 "slsh.h"
#include <ll/stdio.h>
#include <ll/stdlib.h>
#include <ll/string.h>
#include <ll/math.h> /* for ceil(...) */
#include <ll/ll.h> /* for memcpy(...) */
#include <kernel/model.h>
#include <kernel/descr.h>
#include <kernel/var.h>
#include <kernel/func.h>
//#define eslsh_printf kern_printf
#define slsh_printf printk
/* Keeps information about static and guaranteed tasks */
typedef struct {
int est
;
int dabs
;
int interval
;
} SLSH_task
;
/*+ Status used in the level +*/
#define SLSH_READY MODULE_STATUS_BASE
#define SLSH_WAIT MODULE_STATUS_BASE + 1
#define SLSH_IDLE MODULE_STATUS_BASE + 2
#define SLSH_WCET_VIOLATED MODULE_STATUS_BASE + 3
/*+ defines +*/
#define MAX_INTERVALS 1000 /* 1000 intervals is max, for now */
/******+ the level redefinition for the SLOT SHIFT level +*******/
typedef struct {
level_des l
; /*+ the standard level descriptor+*/
/* task lists */
SLSH_task tasks
[MAX_PROC
]; /* est and dl's for static and guaranteed task */
IQUEUE idle_statics
; /* finished static tasks */
IQUEUE unspecified
; /* tasks with only a wcet */
/* the Intervals list */
SLSH_interval intervals
[MAX_INTERVALS
];
int current
; /* current interval */
int last
; /* last interval */
int slot
; /* slot shifting time */
TIME slot_length
; /* slothlength in real system time*/
int LCM
; /* length (in slots) of ofline schedule */
int slot_event
; /* save the event */
} SLSH_level_des
;
/* check if some tasks are ready, return 0 if ready, -1 otherwise */
static int SLSH_R
(SLSH_task
* tasks
)
{
int s
;
/* for all static tasks */
for(s
= 0; tasks
[s
].
est != -1; ++s
)
{
if(proc_table
[s
].
status == SLSH_READY
)
return 0;
}
return -1;
}
/* check if unspecified exists, return 0 if it exists, -1 otherwise */
static int SLSH_T
(IQUEUE
*unspecified
)
{
if(!iq_isempty
(unspecified
))
return 0;
else
return -1;
}
/* return the sc in an interval */
static int SLSH_sc
(SLSH_interval
* intervals
, int i
)
{
return intervals
[i
].
sc;
}
/* return a static task from current interval or a guaranted task */
static PID SLSH_staticOrGuaranteed
(SLSH_level_des
* lev
)
{
int lowest_dl
= 0; /* lowest dl found */
PID pid
= 0; /* static or guaranteed task */
int t
;
/* Decide according to EDF, go through all static & guaranteed tasks */
for(t
= 0; t
< MAX_PROC
; ++t
)
{
/* static tasks */
if(proc_table
[t
].
pclass == STATIC_PCLASS
)
{
/* static task must belong to current interval */
if(lev
->tasks
[t
].
interval == lev
->current
)
{
/* only ready tasks */
if(proc_table
[t
].
status == SLSH_READY
)
{
/* a new lower dl was found */
if(lev
->tasks
[t
].
dabs < lowest_dl
)
{
lowest_dl
= lev
->tasks
[t
].
dabs;
pid
= t
;
}
}
}
} /* guaranteed tasks */
else if(proc_table
[t
].
pclass == HARD_PCLASS
)
{
/* only ready tasks */
if(proc_table
[t
].
status == SLSH_READY
)
{
/* a new lower dl was found */
if(lev
->tasks
[t
].
dabs < lowest_dl
)
{
lowest_dl
= lev
->tasks
[t
].
dabs;
pid
= t
;
}
}
}
}/* for all tasks */
return pid
;
}
/* return a static task among the candidates, all ready statics */
static PID SLSH_candidates
(SLSH_task
* tasks
)
{
int lowest_dl
= 0;
PID pid
= -1;
int t
;
/* Use the EDL algorithm again to decide which task to run */
for(t
= 0; t
< MAX_PROC
; ++t
)
{
/* only static tasks */
if(proc_table
[t
].
pclass == STATIC_PCLASS
)
{
/* only ready tasks */
if(proc_table
[t
].
status == SLSH_READY
)
{
/* a new lower dl was found */
if(tasks
[t
].
dabs < lowest_dl
)
{
lowest_dl
= tasks
[t
].
dabs;
pid
= t
;
}
}/* all ready tasks */
}/* all static tasks */
}/* for all tasks */
return pid
;
}
/* decrease the sc in a interval by amount */
void SLSH_decSc
(SLSH_interval
* intervals
, int i
, int amount
)
{
intervals
[i
].
sc -= amount
;
}
void SLSH_incSc
(SLSH_interval
* intervals
, int i
, int amount
)
{
intervals
[i
].
sc += amount
;
}
/* swap the sc between intervals, also consider intervals with negative sc */
void SLSH_swapSc
(SLSH_interval
* intervals
, int current
, int task_interval
)
{
/* decrease the sc in the current interval */
SLSH_decSc
(intervals
, current
, 1);
/* update the other interval(s) */
if(intervals
[task_interval
].
sc < 0) /* negative sc */
{
/* special case, increase next interval sc by 1 and also current interval (borrowing) */
if(task_interval
== current
+ 1)
{
SLSH_incSc
(intervals
, task_interval
, 1);
SLSH_incSc
(intervals
, current
, 1);
}
else /* increase every interval sc that is negative between current and task_interval */
{
while(task_interval
> current
&& intervals
[task_interval
].
sc < 0)
{
SLSH_incSc
(intervals
, task_interval
, 1);
task_interval
--;
}
}
}
else /* ordinary swapping */
SLSH_incSc
(intervals
, task_interval
, 1);
}
/* The scheduler, decides which task to run. */
static PID SLSH_public_scheduler
(LEVEL l
)
{
SLSH_level_des
* lev
= (SLSH_level_des
*)(level_table
[l
]);
PID pid
;
/* The scheduler choses among static, guaranteed (hard aperiodic) and
unspecified (soft aperiodic) tasks */
/* no ready tasks and no sc, execute idle task */
if(SLSH_R
(lev
->tasks
) == 0 && SLSH_sc
(lev
->intervals
, lev
->current
) == 0)
return NIL
;
/* must execute a static from current intervall or a guaranteed task */
else if(SLSH_R
(lev
->tasks
) > 0 && SLSH_sc
(lev
->intervals
, lev
->current
) == 0)
return SLSH_staticOrGuaranteed
(lev
);
/* sc available... */
else if(SLSH_R
(lev
->tasks
) > 0 && SLSH_sc
(lev
->intervals
, lev
->current
) > 0)
{
/* If unspecified exist, execute it according to FIFO order */
if(SLSH_T
(&lev
->unspecified
) == 0)
{
SLSH_decSc
(lev
->intervals
, lev
->current
, 1); /* decrease sc by 1 */
return iq_getfirst
(&lev
->unspecified
);
}
else /* No unspecified, execute task from candidates (statics) */
{
pid
= SLSH_candidates
(lev
->tasks
);
/* sc needs to be swapped */
if(lev
->tasks
[pid
].
interval != lev
->current
)
SLSH_swapSc
(lev
->intervals
, lev
->tasks
[pid
].
interval, lev
->current
);
return pid
;
}
}
kern_printf
("(SLSH s)");
return NIL
;
}
/* not used, slot-shifting handles all guarantees itself, it handles all bandwidth */
static int SLSH_public_guarantee
(LEVEL l
, bandwidth_t
*freebandwidth
)
{
*freebandwidth
= 0;
return 1;
}
/* get the interval that x is in */
static int SLSH_getInterval
(SLSH_interval
* intervals
, int x
, int last
)
{
int i
;
/* search through the intervals */
for(i
= 0; i
<= last
; ++i
)
{
/* I is in the interval where start is smaller or equal and end is bigger */
if(intervals
[i
].
start <= x
&& x
< intervals
[i
].
end)
return i
;
}
return -1;
}
/* get the start of the interval I */
static int SLSH_intervalStart
(SLSH_interval
* intervals
, int I
)
{
return intervals
[I
].
start;
}
/* split interval I into two parts, slow because of copying. OBS!!! no check if there is
enough space in the intervals array */
static void SLSH_splitInterval
(SLSH_level_des
* lev
, int I
, int dabs
)
{
SLSH_interval left_interval
;
int i
;
lev
->last
++;
/* move every interval above and including I */
for(i
= lev
->last
; i
> I
; --i
)
memcpy(&lev
->intervals
[i
], &lev
->intervals
[i
- 1], sizeof(SLSH_interval
));
/* Left interval start, end and length */
left_interval.
start = lev
->intervals
[I
].
start;
left_interval.
end = dabs
;
left_interval.
length = left_interval.
end - left_interval.
start;
/* Right interval (uses old interval struct) start and length end remains as the old value */
lev
->intervals
[I
+ 1].
start = dabs
;
lev
->intervals
[I
+ 1].
length = lev
->intervals
[I
+ 1].
end - lev
->intervals
[I
+ 1].
start;
/* check if sc still exists in the right interval */
if(lev
->intervals
[I
+ 1].
length - lev
->intervals
[I
+ 1].
maxt > 0)
{
lev
->intervals
[I
+ 1].
sc = lev
->intervals
[I
+ 1].
length - lev
->intervals
[I
+ 1].
maxt;
left_interval.
sc = left_interval.
length; /* the whole interval is free, for now... */
}
else /* no sc in the right interval */
{
lev
->intervals
[I
+ 1].
maxt = lev
->intervals
[I
+ 1].
length;
left_interval.
sc = lev
->intervals
[I
+ 1].
sc; /* all sc in left interval */
lev
->intervals
[I
+ 1].
sc = 0;
}
/* insert the new interval */
memcpy(&lev
->intervals
[I
], &left_interval
, sizeof(SLSH_interval
));
}
/* Reduce the sc from back to front by the wcet amount, interval splitting may be neccesary */
static void SLSH_updateSc
(SLSH_level_des
* lev
, HARD_TASK_MODEL
* h
)
{
int dabs
= ceil((lev
->slot
+ h
->drel
)/lev
->slot_length
); /* absolute deadline of request */
int dabs_interval
= SLSH_getInterval
(lev
->intervals
, dabs
, lev
->last
); /* interval where dabs is */
int C
= ceil(h
->wcet
/lev
->slot_length
); /* amount of sc to reduce */
int sc
= 0;
int i
;
/* check if interval splitting is neccesary */
if(lev
->intervals
[dabs_interval
].
end != dabs
)
SLSH_splitInterval
(lev
, dabs_interval
, dabs
);
/* decrease sc in all intervals that are neccesary from dabs_interval o current */
for(i
= dabs_interval
; i
>= lev
->current
&& C
> 0; --i
)
{
if((sc
= SLSH_sc
(lev
->intervals
, i
)) >= 0) /* only decrease where sc exists */
{
if(sc
> C
) /* the last sc dec */
{
SLSH_decSc
(lev
->intervals
, i
, C
);
C
= 0;
}
else /* to little sc in this interval, decrease it to 0 */
{
C
-= SLSH_sc
(lev
->intervals
, i
);
SLSH_decSc
(lev
->intervals
, i
, SLSH_sc
(lev
->intervals
, i
));
}
}
}/* for all intervals */
}
/* the guarantee algorithm for hard aperiodic requests */
static int SLSH_guarantee
(SLSH_level_des
* lev
, HARD_TASK_MODEL
* h
)
{
int total_sc
= 0;
int temp
, i
;
int dabs
= ceil((lev
->slot
+ h
->drel
)/lev
->slot_length
); /* absolute deadline of request */
int dabs_interval
= SLSH_getInterval
(lev
->intervals
, dabs
, lev
->last
); /* interval where dabs is */
/* check if the sc up until request deadline is >= request wcet */
/* 1. the sc of the current interal */
total_sc
= SLSH_sc
(lev
->intervals
, lev
->current
);
/* 2. the sc for all whole intervals between current and the interval
with the request deadline */
for(i
= (lev
->current
) + 1; i
< dabs_interval
; ++i
)
{
if((temp
= SLSH_sc
(lev
->intervals
, i
)) > 0)
total_sc
+= temp
;
}
/* 3. the min of sc or the execution need in the last interval */
total_sc
+= min
(SLSH_sc
(lev
->intervals
, dabs_interval
),
dabs
- SLSH_intervalStart
(lev
->intervals
,
dabs_interval
));
if(total_sc
>= h
->wcet
)
{ /* update the sc in the intervals from back to front */
SLSH_updateSc
(lev
, h
);
return 0;
}
else
return -1;
}
/* check if task model is accepted and store nessecary parameters */
static int SLSH_public_create
(LEVEL l
, PID p
, TASK_MODEL
*m
)
{
SLSH_level_des
*lev
= (SLSH_level_des
*)(level_table
[l
]);
STATIC_TASK_MODEL
* s
;
HARD_TASK_MODEL
* h
;
SOFT_TASK_MODEL
* u
;
/* Check the models */
switch(m
->pclass
)
{
case STATIC_PCLASS
: /* offline scheduled tasks */
break;
case HARD_PCLASS
: /* hard aperiodic tasks */
h
= (HARD_TASK_MODEL
*) m
;
if (h
->drel
== 0 || h
->wcet
== 0) /* must be set */
return -1;
break;
case SOFT_PCLASS
: /* soft aperiodic tasks */
u
= (SOFT_TASK_MODEL
*) m
;
if(u
->wcet
== 0) /* must be set */
return -1;
break;
default:
return -1;
}
/* if the SLSH_task_create is called, then the pclass must be a
valid pclass. Slot-shifting accepts STATIC_TASK, HARD_TASK
and SOFT_TASK models with some restrictions */
/* est, dl and wcet is saved in slotlengths */
switch(m
->pclass
)
{
case STATIC_PCLASS
: /* offline scheduled tasks */
s
= (STATIC_TASK_MODEL
*) m
;
lev
->tasks
[p
].
est = ceil(s
->est
/lev
->slot_length
);
lev
->tasks
[p
].
dabs = ceil(s
->dabs
/lev
->slot_length
);
lev
->tasks
[p
].
interval = s
->interval
;
proc_table
[p
].
avail_time = s
->wcet
;
proc_table
[p
].
wcet = s
->wcet
;
break;
case HARD_PCLASS
: /* hard aperiodic tasks */
h
= (HARD_TASK_MODEL
*) m
;
if(SLSH_guarantee
(lev
, h
) == 0)
{
/* convert drel to dabs */
lev
->tasks
[p
].
dabs = ceil((lev
->slot
+ h
->drel
)/lev
->slot_length
);
proc_table
[p
].
avail_time = h
->wcet
;
proc_table
[p
].
wcet = h
->wcet
;
}
else /* task not guaranteed */
return -1;
break;
case SOFT_PCLASS
:
u
= (SOFT_TASK_MODEL
*) m
;
proc_table
[p
].
avail_time = u
->wcet
;
proc_table
[p
].
wcet = u
->wcet
;
iq_insertlast
(p
, &lev
->unspecified
); /* respect FIFO order */
break;
default: /* a task model not supported */
return -1;
}
/* enable wcet check in the kernel */
proc_table
[p
].
control |= CONTROL_CAP
;
return 0;
}
/************* The slot end event handler *************/
static void SLSH_slot_end
(void* p
)
{
SLSH_level_des
* lev
= (SLSH_level_des
*) p
;
PID pid
;
int i
;
/* increase slot "time" by 1 */
if(lev
->slot
< lev
->LCM
)
{
lev
->slot
++;
/* check if new statics are ready */
for(i
= 0; lev
->tasks
[i
].
interval != -1; ++i
)
{
if(lev
->tasks
[i
].
est <= lev
->slot
&& proc_table
[i
].
status == SLSH_WAIT
)
proc_table
[i
].
status = SLSH_READY
;
}
/* check if current (interval) needs updating */
if(lev
->current
< SLSH_getInterval
(lev
->intervals
, lev
->slot
, lev
->last
))
lev
->current
++;
}
else /* restart from the beginning of the offline schedule */
{
lev
->slot
= 0;
while((pid
= iq_getfirst
(&lev
->idle_statics
)) != NIL
)
{
if(lev
->tasks
[pid
].
est <= lev
->slot
)
proc_table
[pid
].
status = SLSH_READY
;
else
proc_table
[pid
].
status = SLSH_WAIT
;
}
}
/* call for a rescheduling, reset event flag and increase slot by 1 */
lev
->slot_event
= -1;
kern_printf
("*");
event_need_reschedule
();
}
/* when a task becomes executing (EXE status) */
static void SLSH_public_dispatch
(LEVEL l
, PID pid
, int nostop
)
{
SLSH_level_des
*lev
= (SLSH_level_des
*)(level_table
[l
]);
struct timespec t
;
/* the task state is set EXE by the scheduler()
we extract the task from the unspecified queue.
NB: we can't assume that p is the first task in the queue!!! */
if(proc_table
[pid
].
pclass == SOFT_PCLASS
)
iq_extract
(pid
, &lev
->unspecified
);
/* also start the timer for one slot length */
lev
->slot_event
= kern_event_post
(&TIME2TIMESPEC
(lev
->slot_length
, t
),
SLSH_slot_end
, (void*) lev
);
}
/* called when task is moved from EXE status */
static void SLSH_public_epilogue
(LEVEL l
, PID pid
)
{
SLSH_level_des
*lev
= (SLSH_level_des
*)(level_table
[l
]);
/* check if the wcet is finished... */
if (proc_table
[pid
].
avail_time <= 0)
{
/* if it is, raise a XWCET_VIOLATION exception */
kern_raise
(XWCET_VIOLATION
, pid
);
proc_table
[pid
].
status = SLSH_WCET_VIOLATED
;
}
else /* the end of a slot. the task returns into the ready queue... */
{
if(proc_table
[pid
].
pclass == SOFT_PCLASS
)
iq_insertfirst
(pid
,&lev
->unspecified
);
proc_table
[pid
].
status = SLSH_READY
;
}
}
/* when task go from SLEEP to SLSH_READY or SLSH_WAIT */
static void SLSH_public_activate
(LEVEL l
, PID pid
)
{
SLSH_level_des
*lev
= (SLSH_level_des
*)(level_table
[l
]);
WORD type
= proc_table
[pid
].
pclass;
/* Test if we are trying to activate a non sleeping task */
/* Ignore this; the task is already active */
if (proc_table
[pid
].
status != SLEEP
&& proc_table
[pid
].
status != SLSH_WCET_VIOLATED
)
return;
/* make task ready or waiting, dependong on slot (the time) for static tasks only*/
if(type
== STATIC_PCLASS
&& lev
->tasks
[pid
].
est <= lev
->slot
)
proc_table
[pid
].
status = SLSH_READY
;
else
proc_table
[pid
].
status = SLSH_WAIT
;
if(type
== HARD_PCLASS
)
proc_table
[pid
].
status = SLSH_READY
;
/* insert unspecified tasks in QQUEUE and make it ready */
if(type
== SOFT_PCLASS
)
{
iq_insertlast
(pid
,&lev
->unspecified
);
proc_table
[pid
].
status = SLSH_READY
;
}
}
/* when a task i returned to module from a semaphore, mutex ... */
static void SLSH_public_unblock
(LEVEL l
, PID pid
)
{
SLSH_level_des
*lev
= (SLSH_level_des
*)(level_table
[l
]);
/* change staus of task */
proc_table
[pid
].
status = SLSH_READY
;
if(proc_table
[pid
].
pclass == SOFT_PCLASS
)
iq_insertfirst
(pid
,&lev
->unspecified
);
}
/* when a semaphore, mutex ... taskes a task from module */
static void SLSH_public_block
(LEVEL l
, PID pid
)
{
/* 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
. the deadline must remain...
So, we do nothing!!!
*/
}
/* the task has finihed its wcet, kill task (dont kill static tasks) */
static void SLSH_public_end
(LEVEL l
, PID pid
)
{
SLSH_level_des
*lev
= (SLSH_level_des
*)(level_table
[l
]);
if(proc_table
[pid
].
pclass == SOFT_PCLASS
)
{
if (proc_table
[pid
].
status == SLSH_READY
)
iq_extract
(pid
, &lev
->unspecified
);
}
else if(proc_table
[pid
].
pclass == HARD_PCLASS
)
{
if (proc_table
[pid
].
status == SLSH_READY
)
lev
->tasks
[pid
].
dabs = 0;
}
/* static tasks: put them in idle QUEUE, reset status and avail_time */
else if(proc_table
[pid
].
pclass == STATIC_PCLASS
)
{
proc_table
[pid
].
avail_time = proc_table
[pid
].
wcet;
proc_table
[pid
].
status = SLSH_IDLE
;
iq_priority_insert
(pid
, &lev
->idle_statics
);
}
proc_table
[pid
].
status = FREE
;
}
/* called when a task should sleep but not execute for awhile, mabe a mode change */
//static void SLSH_task_sleep(LEVEL l, PID pid)
//{
//
// /* the task has terminated his job before it consume the wcet. All OK! */
// proc_table[pid].status = SLEEP;
//
// /* we reset the capacity counters... only for static tasks */
// if (proc_table[pid].pclass == STATIC_PCLASS)
// proc_table[pid].avail_time = proc_table[pid].wcet;
//
//}
/** Guest Functions, slot shifing accepts no guests, so all generates exceptions **/
/******* Registration functions *******/
/*+ Registration function: */
LEVEL SLSH_register_level
()
{
LEVEL l
; /* the level that we register */
SLSH_level_des
*lev
; /* for readableness only */
PID i
; /* a counter */
kern_printf
("SLSH_register_level\n");
/* request an entry in the level_table */
l
= level_alloc_descriptor
(sizeof(SLSH_level_des
));
lev
= (SLSH_level_des
*)level_table
[l
];
printk
(" lev=%d\n",(int)lev
);
/* fill the standard descriptor */
lev
->l.
public_scheduler = SLSH_public_scheduler
;
lev
->l.
public_guarantee = SLSH_public_guarantee
;
lev
->l.
public_create = SLSH_public_create
;
lev
->l.
public_end = SLSH_public_end
;
lev
->l.
public_dispatch = SLSH_public_dispatch
;
lev
->l.
public_epilogue = SLSH_public_epilogue
;
lev
->l.
public_activate = SLSH_public_activate
;
lev
->l.
public_unblock = SLSH_public_unblock
;
lev
->l.
public_block = SLSH_public_block
;
/* fill the SLSH descriptor part */
for(i
= 0; i
< MAX_PROC
; i
++)
{
lev
->tasks
[i
].
est = -1;
lev
->tasks
[i
].
dabs = 0;
lev
->tasks
[i
].
interval = -1;
}
for(i
= 0; i
< MAX_INTERVALS
; i
++)
{
lev
->intervals
[i
].
start = -1;
lev
->intervals
[i
].
end = -1;
lev
->intervals
[i
].
length = 0;
lev
->intervals
[i
].
maxt = 0;
lev
->intervals
[i
].
sc = 0;
}
lev
->current
= 0;
lev
->last
= NIL
;
lev
->slot
= 0;
lev
->slot_length
= 0;
lev
->slot_event
= -1;
return l
;
}
void SLSH_set_interval
(LEVEL l
, int start
, int end
, int maxt
)
{
SLSH_level_des
* lev
= (SLSH_level_des
*)(level_table
[l
]);
static int i
= -1;
i
++;
lev
->intervals
[i
].
start = start
;
lev
->intervals
[i
].
end = end
;
lev
->intervals
[i
].
length = end
- start
;
lev
->intervals
[i
].
maxt = maxt
;
lev
->intervals
[i
].
sc = lev
->intervals
[i
].
length - maxt
;
lev
->last
= i
;
}
void SLSH_set_variables
(LEVEL l
, TIME length
)
{
SLSH_level_des
* lev
= (SLSH_level_des
*)(level_table
[l
]);
lev
->slot_length
= length
;
}