18,11 → 18,11 |
|
/** |
------------ |
CVS : $Id: kern.c,v 1.1.1.1 2002-03-29 14:12:51 pj Exp $ |
CVS : $Id: kern.c,v 1.3 2003-01-07 17:07:49 pj Exp $ |
|
File: $File$ |
Revision: $Revision: 1.1.1.1 $ |
Last update: $Date: 2002-03-29 14:12:51 $ |
Revision: $Revision: 1.3 $ |
Last update: $Date: 2003-01-07 17:07:49 $ |
------------ |
|
This file contains: |
96,7 → 96,7 |
PID exec; /*+ Task advised by the scheduler +*/ |
PID exec_shadow; /*+ Currently executing task +*/ |
|
QUEUE freedesc; /*+ Free descriptor handled as a queue +*/ |
IQUEUE freedesc; /*+ Free descriptor handled as a queue +*/ |
|
DWORD sys_tick; /*+ System tick (in usec) +*/ |
struct timespec schedule_time; |
117,9 → 117,26 |
/*+ Process descriptor table +*/ |
proc_des proc_table[MAX_PROC]; |
|
/*+ Level descriptor table +*/ |
/* Scheduling modules descriptor table */ |
/* ------------------------------------------------------------------------ */ |
|
/* the descriptor table */ |
level_des *level_table[MAX_SCHED_LEVEL]; |
/* ... and the size of each descriptor */ |
size_t level_size[MAX_SCHED_LEVEL]; |
|
/* an utilization counter incremented if a level is used by another module */ |
int level_used[MAX_SCHED_LEVEL]; |
/* these data structures (first, last, free, next & prev) |
are used to implement a double linked list of scheduling modules. |
That list is used by the scheduler to call the module's schedulers. */ |
int level_first; /* first module in the list */ |
int level_last; /* last module in the list */ |
int level_free; /* free single linked list of free module descriptors. */ |
int level_next[MAX_SCHED_LEVEL]; |
int level_prev[MAX_SCHED_LEVEL]; |
/* ------------------------------------------------------------------------ */ |
|
/*+ Resource descriptor table +*/ |
resource_des *resource_table[MAX_RES_LEVEL]; |
|
197,7 → 214,6 |
void scheduler(void) |
{ |
LEVEL l; /* a counter */ |
TIME tx; /* a dummy used for time computation */ |
struct timespec ty; /* a dummy used for time computation */ |
|
PID p; /* p is the task chosen by the level scheduler */ |
211,6 → 227,8 |
(proc_table[exec_shadow].control & NO_PREEMPT) ) ) |
return; |
|
// kern_printf("(!"); |
|
/* |
exec_shadow = exec = -1 only if the scheduler is called from: |
. task_endcycle |
229,48 → 247,38 |
- call an epilogue |
*/ |
|
/* then, we call the epilogue. the epilogue tipically checks the |
avail_time field... */ |
if (exec_shadow != -1) { |
// ok is set 4 debug :-( |
ok = ll_gettime(TIME_EXACT, &schedule_time); |
// kern_printf("(%d sched s%d ns%d)", ok, schedule_time.tv_sec, schedule_time.tv_nsec); |
kern_epilogue_macro(); |
|
/* manage the capacity event */ |
SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty); |
tx = TIMESPEC2USEC(&ty); |
proc_table[exec_shadow].avail_time -= tx; |
jet_update_slice(tx); |
|
/* if the event didn't fire before, we delete it. */ |
if (cap_timer != NIL) { |
event_delete(cap_timer); |
cap_timer = NIL; |
} |
|
/* then, we call the epilogue. the epilogue tipically checks the |
avail_time field... */ |
|
// kern_printf("(e%d)",exec_shadow); |
|
l = proc_table[exec_shadow].task_level; |
level_table[l]->task_epilogue(l,exec_shadow); |
level_table[l]->public_epilogue(l,exec_shadow); |
} |
|
l = 0; |
// kern_printf("["); |
|
l = level_first; |
for(;;) { |
do { |
p = level_table[l]->level_scheduler(l); |
p = level_table[l]->public_scheduler(l); |
// kern_printf("p=%d",p); |
if (p != NIL) |
ok = level_table[ proc_table[p].task_level ]-> |
task_eligible(proc_table[p].task_level,p); |
public_eligible(proc_table[p].task_level,p); |
else |
ok = 0; |
// kern_printf(" ok=%d",ok); |
} while (ok < 0); /* repeat the level scheduler if the task isn't |
eligible... (ex. in the aperiodic servers...) */ |
if (p != NIL) break; |
|
l++; /* THERE MUST BE a level with a task to schedule */ |
l = level_next[l]; /* THERE MUST BE a level with a task to schedule */ |
// kern_printf(" l=%d",l); |
}; |
|
// kern_printf("]"); |
|
/* tracer stuff */ |
//trc_logevent(exec,TRC_SCHEDULE,NULL,0); |
|
284,15 → 292,17 |
//trc_logevent(exec_shadow,TRC_DISPATCH,NULL,0); |
if (old_exec_shadow!=exec_shadow) |
trc_logevent(TRC_SCHEDULE,&exec_shadow); |
// kern_printf("[%i->%i]",old_exec_shadow,exec_shadow); |
// kern_printf("[%i->%i]",old_exec_shadow,exec_shadow); |
|
/* we control the correctness of the shadows when we kill */ |
proc_table[exec_shadow].status = EXE; |
|
//kern_printf("(d%d)",exec_shadow); |
// kern_printf("(d%d)",exec_shadow); |
l = proc_table[exec_shadow].task_level; |
level_table[l]->task_dispatch(l, exec_shadow, exec!=exec_shadow); |
level_table[l]->public_dispatch(l, exec_shadow, exec!=exec_shadow); |
|
// kern_printf("*"); |
|
/* Finally,we post the capacity event, BUT |
. only if the task require that |
. only if exec==exec_shadow (if a task is blocked we don't want |
301,13 → 311,13 |
&& exec==exec_shadow) { |
TIMESPEC_ASSIGN(&ty, &schedule_time); |
ADDUSEC2TIMESPEC(proc_table[exec_shadow].avail_time,&ty); |
// kern_printf("³s%d ns%d sched s%d ns%d³",ty.tv_sec,ty.tv_nsec, schedule_time.tv_sec, schedule_time.tv_nsec); |
// kern_printf("³s%d ns%d sched s%d ns%d³",ty.tv_sec,ty.tv_nsec, schedule_time.tv_sec, schedule_time.tv_nsec); |
cap_timer = kern_event_post(&ty, capacity_timer, NULL); |
} |
/* set the time at witch the task is scheduled */ |
TIMESPEC_ASSIGN(&cap_lasttime, &schedule_time); |
|
//if (runlevel != 1) kern_printf("(s%d)",exec_shadow); |
// kern_printf("(s%d)",exec_shadow); |
} |
|
|
325,8 → 335,8 |
bandwidth_t num=MAX_BANDWIDTH; |
int l; |
|
for (l =0; l<MAX_SCHED_LEVEL && level_table[l]->level_guarantee; l++) |
if (!level_table[l]->level_guarantee(l,&num)) |
for (l =0; l<MAX_SCHED_LEVEL && level_table[l]->public_guarantee; l++) |
if (!level_table[l]->public_guarantee(l,&num)) |
return -1; |
|
return 0; /* OK */ |
378,7 → 388,7 |
* |
*/ |
|
runlevel = 0; |
runlevel = RUNLEVEL_STARTUP; |
|
/* The kernel startup MUST proceed with int disabled! */ |
kern_cli(); |
400,13 → 410,12 |
proc_table[i].frozen_activations = 0; |
proc_table[i].sigmask = 0; |
proc_table[i].sigpending = 0; |
NULL_TIMESPEC(&proc_table[i].request_time); |
proc_table[i].avail_time = 0; |
proc_table[i].shadow = i; |
proc_table[i].cleanup_stack= NULL; |
proc_table[i].errnumber = 0; |
proc_table[i].priority = 0; |
NULL_TIMESPEC(&proc_table[i].timespec_priority); |
//proc_table[i].priority = 0; |
//NULL_TIMESPEC(&proc_table[i].timespec_priority); |
proc_table[i].delay_timer = -1; |
proc_table[i].wcet = -1; |
|
424,12 → 433,17 |
for (j=0; j<PTHREAD_KEYS_MAX; j++) |
proc_table[i].keys[j] = NULL; |
} |
for (i = 0; i < MAX_PROC-1; i++) proc_table[i].next = i+1; |
proc_table[MAX_PROC-1].next = NIL; |
for (i = MAX_PROC-1; i > 0; i--) proc_table[i].prev = i-1; |
proc_table[0].prev = NIL; |
freedesc = 0; |
|
/* set up the free descriptor queue */ |
// for (i = 0; i < MAX_PROC-1; i++) proc_table[i].next = i+1; |
// proc_table[MAX_PROC-1].next = NIL; |
// for (i = MAX_PROC-1; i > 0; i--) proc_table[i].prev = i-1; |
// proc_table[0].prev = NIL; |
// freedesc = 0; |
iq_init(&freedesc, NULL, 0); |
for (i = 0; i < MAX_PROC; i++) |
iq_insertlast(i,&freedesc); |
|
/* Set up the varius stuff */ |
global_errnumber = 0; |
task_counter = 0; |
451,7 → 465,11 |
/* Init VM layer (Interrupts, levels & memory management) */ |
/* for old exception handling, use excirq_init() */ |
signals_init(); |
set_default_exception_handler(); |
|
/* Clear scheduling modules registration data */ |
levels_init(); |
|
sys_tick = __kernel_register_levels__(multiboot); |
|
/* tracer stuff */ |
476,7 → 494,7 |
parms.tick = sys_tick; |
|
/* |
* Runlevel 1: Let's go!!!! |
* Runlevel INIT: Let's go!!!! |
* |
* |
*/ |
492,6 → 510,17 |
/* call the init functions */ |
call_runlevel_func(RUNLEVEL_INIT, 0); |
|
|
|
|
/* |
* Runlevel RUNNING: Hoping that all works fine ;-) |
* |
* |
*/ |
|
runlevel = RUNLEVEL_RUNNING; |
|
/* reset keyboard after exit */ |
// sys_atexit((void(*)(void *))C8042_restore,NULL,AFTER_EXIT); |
|
499,7 → 528,7 |
trc_resume(); |
|
/* exec and exec_shadow are already = -1 */ |
ll_gettime(TIME_EXACT, &schedule_time); |
kern_gettime(&schedule_time); |
scheduler(); |
global_context = ll_context_from(); /* It will be used by sys_end */ |
ll_context_to(proc_table[exec_shadow].context); |
514,7 → 543,7 |
|
|
/* |
* Runlevel 2: Shutting down the system... :-( |
* Runlevel SHUTDOWN: Shutting down the system... :-( |
* |
* |
*/ |
530,13 → 559,11 |
/* 1 when the error code is != 0 */ |
aborting = global_errnumber > 0; |
|
//kern_printf("after - system_counter=%d, task_counter = %d\n", |
// system_counter,task_counter); |
//kern_printf("after - system_counter=%d, task_counter = %d\n", system_counter,task_counter); |
|
call_runlevel_func(RUNLEVEL_SHUTDOWN, aborting); |
|
//kern_printf("before - system_counter=%d, task_counter = %d\n", |
// system_counter,task_counter); |
//kern_printf("before - system_counter=%d, task_counter = %d\n", system_counter,task_counter); |
|
if (system_counter) { |
/* To shutdown the kernel correctly, we have to wait that all the SYSTEM |
547,15 → 574,15 |
We do nothing for user tasks that remain active (because, for example, |
they have the cancelability set to deferred) when the system goes to |
runlevel 3 */ |
//kern_printf("Û%lu",ll_gettime(TIME_EXACT,NULL)); |
//kern_printf("Û%lu",kern_gettime(NULL)); |
kill_user_tasks(); |
//kern_printf("Û%lu",ll_gettime(TIME_EXACT,NULL)); |
//kern_printf("Û%lu",kern_gettime(NULL)); |
|
/* we have to go again in multitasking mode!!! */ |
mustexit = 0; |
|
/* exec and exec_shadow are already = -1 */ |
ll_gettime(TIME_EXACT, &schedule_time); |
kern_gettime(&schedule_time); |
global_context = ll_context_from(); /* It will be used by sys_end */ |
scheduler(); |
|
568,7 → 595,7 |
|
|
/* |
* Runlevel 3: Before Halting the system |
* Runlevel BEFORE_EXIT: Before Halting the system |
* |
* |
*/ |
592,7 → 619,7 |
|
|
/* |
* Runlevel 4: After halting... |
* Runlevel AFTER_EXIT: After halting... |
* |
* |
*/ |
615,47 → 642,48 |
|
} |
|
/* IMPORTANT!!! |
I'm almost sure the shutdown procedure does not work into interrupts. */ |
void internal_sys_end(int i) |
{ |
LEVEL l; /* a counter */ |
TIME tx; /* a dummy used for time computation */ |
struct timespec ty; /* a dummy used for time computation */ |
|
/* if something goes wron during the real mode */ |
if (runlevel==RUNLEVEL_STARTUP || runlevel==RUNLEVEL_AFTER_EXIT) |
l1_exit(i); |
|
//kern_printf("mustexit=%d",mustexit); |
if (!mustexit) { |
if (!ll_ActiveInt()) |
proc_table[exec_shadow].context = kern_context_save(); |
|
global_errnumber = i; |
if (mustexit) |
return; |
|
mustexit = 1; |
mustexit = 1; |
|
global_errnumber = i; |
|
|
if (!ll_ActiveInt()) { |
proc_table[exec_shadow].context = kern_context_save(); |
|
if (exec_shadow != -1) { |
ll_gettime(TIME_EXACT, &schedule_time); |
/* manage the capacity event */ |
SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty); |
tx = TIMESPEC2USEC(&ty); |
proc_table[exec_shadow].avail_time -= tx; |
jet_update_slice(tx); |
/* if the event didn't fire before, we delete it. */ |
if (cap_timer != NIL) { |
event_delete(cap_timer); |
cap_timer = NIL; |
} |
|
kern_gettime(&schedule_time); |
|
kern_epilogue_macro(); |
|
/* then, we call the epilogue. the epilogue tipically checks the |
avail_time field... */ |
avail_time field... */ |
l = proc_table[exec_shadow].task_level; |
level_table[l]->task_epilogue(l,exec_shadow); |
|
level_table[l]->public_epilogue(l,exec_shadow); |
|
exec_shadow = exec = -1; |
} |
kern_context_load(global_context); |
} |
|
if (ll_ActiveInt()) |
ll_context_to(global_context); |
else |
kern_context_load(global_context); |
if (ll_ActiveInt()) { |
ll_context_to(global_context); |
/* The context change will be done when all the interrupts end!!! */ |
} |
|
//kern_printf("fine sysend"); |
|
/* the control reach this line only if we call sys_end() into an event |
664,64 → 692,29 |
} |
|
|
/*+ Close the system & return to HOST OS. |
Can be called from all the tasks... |
The first time it is called it jumps to the global context |
The second time it jumps only if there are no system task remaining |
The error code passed is 0... (it is saved on the first call!!!) +*/ |
void sys_end(void) |
/* |
Close the system & return to HOST OS. |
Can be called from tasks and from ISRS |
|
|
*/ |
void sys_abort(int err) |
{ |
SYS_FLAGS f; |
|
/* the sys_end change the context to the global context. |
when the first time is called, it simply kills all the users tasks |
and waits the system tasks to end... */ |
|
/*kern_printf("°sys_end %d°",exec_shadow);*/ |
/*return;*/ |
f = kern_fsave(); |
if (runlevel != RUNLEVEL_INIT && system_counter) { |
kern_frestore(f); |
return; |
} |
|
internal_sys_end(0); |
internal_sys_end(err); |
kern_frestore(f); |
} |
|
/*+ Close the system & return to HOST OS. |
Can be called from all the tasks... |
The first time it is called it works as the sys_end |
The second time it jumps every time |
The error code passed is 0... +*/ |
void sys_abort(int err) |
void sys_end(void) |
{ |
/* the sys_end change the context to the global context. |
when the first time is called, it simply kills all the users tasks |
and waits the system tasks to end... */ |
|
internal_sys_end(err); |
sys_abort(0); |
} |
|
/*+ equal to sys_end! +*/ |
void _exit(int status) |
{ |
SYS_FLAGS f; |
|
/* the sys_end change the context to the global context. |
when the first time is called, it simply kills all the users tasks |
and waits the system tasks to end... */ |
|
/*kern_printf("°sys_end %d°",exec_shadow);*/ |
/*return;*/ |
f = kern_fsave(); |
if (runlevel != RUNLEVEL_INIT && system_counter) { |
kern_frestore(f); |
return; |
} |
|
internal_sys_end(status); |
kern_frestore(f); |
sys_abort(status); |
} |
|
|
741,7 → 734,7 |
TIME x; |
|
f = kern_fsave(); |
x = ll_gettime(TIME_EXACT,t); |
x = kern_gettime(t); |
kern_frestore(f); |
|
return x; |