Subversion Repositories shark

Rev

Rev 45 | Rev 353 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   (see the web pages for full authors list)
11
 *
12
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
13
 *
14
 * http://www.sssup.it
15
 * http://retis.sssup.it
16
 * http://shark.sssup.it
17
 */
18
 
19
/**
20
 ------------
157 pj 21
 CVS :        $Id: kern.c,v 1.5 2003-05-01 19:40:53 pj Exp $
2 pj 22
 
23
 File:        $File$
157 pj 24
 Revision:    $Revision: 1.5 $
25
 Last update: $Date: 2003-05-01 19:40:53 $
2 pj 26
 ------------
27
 
28
 This file contains:
29
 
30
 - the kernel system variables
31
 
32
 - the errno functions
33
 
34
 - the scheduler, capacity timer, and grarantee
35
 
36
 - the sys_abort, sys_end, sys_gettime
37
 
38
 
39
**/
40
 
41
/*
42
 * Copyright (C) 2000 Paolo Gai
43
 *
44
 * This program is free software; you can redistribute it and/or modify
45
 * it under the terms of the GNU General Public License as published by
46
 * the Free Software Foundation; either version 2 of the License, or
47
 * (at your option) any later version.
48
 *
49
 * This program is distributed in the hope that it will be useful,
50
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
51
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
52
 * GNU General Public License for more details.
53
 *
54
 * You should have received a copy of the GNU General Public License
55
 * along with this program; if not, write to the Free Software
56
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
57
 *
58
 */
59
 
60
#include <stdarg.h>
61
#include <ll/ll.h>
62
#include <ll/stdlib.h>
63
#include <ll/stdio.h>
64
#include <ll/string.h>
65
#include <kernel/config.h>
66
#include <kernel/model.h>
67
#include <kernel/const.h>
68
#include <sys/types.h>
69
#include <kernel/types.h>
70
#include <kernel/descr.h>
71
#include <errno.h>
72
#include <kernel/var.h>
73
#include <kernel/func.h>
74
#include <kernel/trace.h>
75
 
76
/*----------------------------------------------------------------------*/
77
/* Kernel System variables                                              */
78
/*----------------------------------------------------------------------*/
79
 
80
int global_errnumber;   /*+ Errno used in system initialization  +*/
81
CONTEXT global_context; /*+ Context used during initialization;
82
                            It references also a safe stack      +*/
83
 
84
int task_counter;       /*+ Application task counter. It represent
85
                            the number of Application tasks in the
86
                            system. When all Application Tasks end,
87
                            also the system ends.                +*/
88
 
89
int system_counter;     /*+ System task counter. It represent
90
                            the number of System tasks in the
91
                            system with the NO_KILL flag reset.
92
                            When all Application Tasks end,
93
                            the system waits for the end of the
94
                            system tasks and then it ends.       +*/
95
 
96
PID exec;               /*+ Task advised by the scheduler        +*/
97
PID exec_shadow;        /*+ Currently executing task             +*/
98
 
29 pj 99
IQUEUE freedesc;        /*+ Free descriptor handled as a queue   +*/
2 pj 100
 
101
DWORD sys_tick;         /*+ System tick (in usec)                +*/
102
struct timespec schedule_time;
103
                        /*+ Timer read at each call to schedule()+*/
104
 
105
int   cap_timer;        /*+ the capacity event posted when the
106
                            task starts                          +*/
107
struct timespec cap_lasttime;
108
                        /*+ the time at whitch the capacity
109
                            event is posted. Normally, it is
110
                            equal to schedule_time               +*/
111
 
112
 
113
 
114
DWORD sched_levels;     /*+ Schedule levels active in the system +*/
115
DWORD res_levels;       /*+ Resource levels active in the system +*/
116
 
117
/*+ Process descriptor table +*/
118
proc_des proc_table[MAX_PROC];
119
 
38 pj 120
/* Scheduling modules descriptor table */
121
/* ------------------------------------------------------------------------ */
122
 
123
/* the descriptor table */
2 pj 124
level_des *level_table[MAX_SCHED_LEVEL];
38 pj 125
/* ... and the size of each descriptor */
126
size_t level_size[MAX_SCHED_LEVEL];
2 pj 127
 
38 pj 128
/* an utilization counter incremented if a level is used by another module */
129
int level_used[MAX_SCHED_LEVEL];
130
/* these data structures (first, last, free, next & prev)
131
   are used to implement a double linked list of scheduling modules.
132
   That list is used by the scheduler to call the module's schedulers. */
133
int level_first; /* first module in the list */
134
int level_last;  /* last module in the list */
135
int level_free;  /* free single linked list of free module descriptors. */
136
int level_next[MAX_SCHED_LEVEL];
137
int level_prev[MAX_SCHED_LEVEL];
138
/* ------------------------------------------------------------------------ */
139
 
2 pj 140
/*+ Resource descriptor table +*/
141
resource_des *resource_table[MAX_RES_LEVEL];
142
 
143
/*+ This variable is set by the system call sys_end() or sys_abort().
144
    When a sys_end() or sys_abort is called into an event handler,
145
    we don't have to change context in the reschedule().
146
    look at kernel/event.c +*/
147
int mustexit = 0;
148
 
149
/*+ this is the system runlevel... it may be from 0 to 4:
150
 
151
    1 - running
152
    2 - shutdown
153
    3 - before halting
154
    4 - halting
155
+*/
156
int runlevel;
157
 
158
/*+ this variable is set to 1 into call_runlevel_func (look at init.c)
159
    ad it is used because the task_activate (look at activate.c) must
160
    work in a different way when the system is in the global_context +*/
161
int calling_runlevel_func;
162
 
163
 
164
/*----------------------------------------------------------------------*/
165
/* Kernel internal functions                                            */
166
/*----------------------------------------------------------------------*/
167
 
168
/*+ errno Handling: this functions returns the correct address for errno.
169
    The address returned can be either the global errno or the errno local
170
    to the execution task */
171
static int *__errnumber()
172
{
173
  if (exec_shadow == -1)
174
    return &global_errnumber;
175
  else
176
    return &(proc_table[exec_shadow].errnumber);
177
}
178
 
179
/*+ this is the capacity timer. it fires when the running task has expired
180
    his time contained in the avail_time field. The event is tipically
181
    posted in the scheduler() after the task_dispatch. The task_dispatch
182
    can modify the avail_time field to reach his scheduling purposes.
183
    The wcet field is NOT used in the Generic kernel. it is initialized at
184
    init time to 0. +*/
185
void capacity_timer(void *arg)
186
{
187
  /* the capacity event is served, so at the epilogue we
188
     don't have to erase it */
189
  cap_timer = NIL;
190
 
191
//  kern_printf("cap%d ",exec_shadow);
192
 
193
  /* When we reschedule, the call to task_epilogue check the slice and
194
     put the task in the queue's tail */
195
  event_need_reschedule();
196
}
197
 
198
/*+
199
  Generic Scheduler:
200
  This function select the next task that should be executed.
201
  The selection is made calling the level schedulers.
202
  It assume that THERE IS a task that can be scheduled in one
203
  level.
204
 
205
  The general scheduler:
206
  - first, it checks for interrupts.
207
  - then, it calls the epilogue of the task pointed in exec_shadow
208
  - after that, it calls the level schedulers
209
  - then it sets exec and it follows the shadow chain
210
  - finally it calls task_dispatch for the new task (the shadow!!!),
211
    saying if exec != exec_shadow
212
 
213
+*/
214
void scheduler(void)
215
{
216
  LEVEL l;    /* a counter                                     */
217
  struct timespec ty; /* a dummy used for time computation     */
218
 
219
  PID p;      /* p is the task chosen by the level scheduler   */
220
  int ok;     /* 1 only if the task chosen by the level scheduler
221
                 is eligible (normally, it is; but in some server
222
                 it is not always true (i.e., CBS))            */
223
 
224
  PID old_exec_shadow;
225
 
226
  if ( (exec_shadow != -1 &&
227
       (proc_table[exec_shadow].control & NO_PREEMPT) ) )
228
    return;
229
 
38 pj 230
  //  kern_printf("(!");
231
 
2 pj 232
  /*
233
  exec_shadow = exec = -1 only if the scheduler is called from:
234
   . task_endcycle
235
   . task_kill
236
   . task_extract
237
   . task_sleep
238
   . task_delay
239
  and from the system startup routines.
240
 
241
  Normally, the scheduler is called with exec & co != -1...
242
 
243
  if exec & co. is set to -1 before calling scheduler(), the following
244
  stuffs have to be executed before the call
245
  - get the schedule_time
246
  - account the capacity if necessary
247
  - call an epilogue
248
  */
249
 
38 pj 250
  /* then, we call the epilogue. the epilogue tipically checks the
251
     avail_time field... */
2 pj 252
  if (exec_shadow != -1) {
38 pj 253
    kern_epilogue_macro();
2 pj 254
 
255
    l = proc_table[exec_shadow].task_level;
38 pj 256
    level_table[l]->public_epilogue(l,exec_shadow);
2 pj 257
  }
258
 
38 pj 259
  //  kern_printf("[");
260
 
261
  l = level_first;
2 pj 262
  for(;;) {
263
    do {
38 pj 264
      p = level_table[l]->public_scheduler(l);
265
      //      kern_printf("p=%d",p);
2 pj 266
      if (p != NIL)
267
        ok = level_table[ proc_table[p].task_level ]->
38 pj 268
          public_eligible(proc_table[p].task_level,p);
2 pj 269
      else
270
        ok = 0;
38 pj 271
      //      kern_printf(" ok=%d",ok);      
2 pj 272
    } while (ok < 0); /* repeat the level scheduler if the task isn't
273
                         eligible... (ex. in the aperiodic servers...) */
274
    if (p != NIL) break;
275
 
38 pj 276
    l = level_next[l];  /* THERE MUST BE a level with a task to schedule */
277
    //    kern_printf(" l=%d",l);      
2 pj 278
  };
279
 
38 pj 280
  //  kern_printf("]");
281
 
2 pj 282
  /* tracer stuff */
283
  //trc_logevent(exec,TRC_SCHEDULE,NULL,0);
284
 
285
  /* we follow the shadow chain */
286
  old_exec_shadow=exec_shadow;
287
  exec_shadow = exec = p;
288
  while (exec_shadow != proc_table[exec_shadow].shadow)
289
    exec_shadow = proc_table[exec_shadow].shadow;
290
 
291
  /* tracer stuff */
292
  //trc_logevent(exec_shadow,TRC_DISPATCH,NULL,0);
293
  if (old_exec_shadow!=exec_shadow)
294
    trc_logevent(TRC_SCHEDULE,&exec_shadow);
38 pj 295
  //    kern_printf("[%i->%i]",old_exec_shadow,exec_shadow);
2 pj 296
 
297
  /* we control the correctness of the shadows when we kill */
298
  proc_table[exec_shadow].status = EXE;
299
 
38 pj 300
  //  kern_printf("(d%d)",exec_shadow);
2 pj 301
  l = proc_table[exec_shadow].task_level;
38 pj 302
  level_table[l]->public_dispatch(l, exec_shadow, exec!=exec_shadow);
2 pj 303
 
38 pj 304
  //  kern_printf("*");
305
 
2 pj 306
  /* Finally,we post the capacity event, BUT
307
     . only if the task require that
308
     . only if exec==exec_shadow (if a task is blocked we don't want
309
       to check the capacity!!!) */
310
  if ((proc_table[exec_shadow].control & CONTROL_CAP)
311
      && exec==exec_shadow) {
312
    TIMESPEC_ASSIGN(&ty, &schedule_time);
313
    ADDUSEC2TIMESPEC(proc_table[exec_shadow].avail_time,&ty);
38 pj 314
    //    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);
2 pj 315
    cap_timer = kern_event_post(&ty, capacity_timer, NULL);
316
  }
317
  /* set the time at witch the task is scheduled */
318
  TIMESPEC_ASSIGN(&cap_lasttime, &schedule_time);
319
 
38 pj 320
  //  kern_printf("(s%d)",exec_shadow);
2 pj 321
}
322
 
323
 
324
/*+
325
  Guarantee:
326
  This function guarantees the system: it calls the
327
  level_guarantee of each level that have that function != NULL
328
 
329
  The guarantee is based on a utilization factor basis.
330
  We mantain only a DWORD. num has to be interpreted as num/MAX_DWORD
331
  free bandwidth.
332
+*/
333
int guarantee()
334
{
335
  bandwidth_t num=MAX_BANDWIDTH;
336
  int l;
337
 
38 pj 338
  for (l =0; l<MAX_SCHED_LEVEL && level_table[l]->public_guarantee; l++)
339
    if (!level_table[l]->public_guarantee(l,&num))
2 pj 340
      return -1;
341
 
342
  return 0; /* OK */
343
}
344
 
345
/*----------------------------------------------------------------------*/
346
/* Context switch handling functions                                    */
347
/*----------------------------------------------------------------------*/
348
/* this function is called every time a context change occurs,
349
   when a task is preempted by an event called into an IRQ */
350
void kern_after_dispatch()
351
{
352
  /* every time a task wakes up from an IRQ, it has to check for async
353
     cancellation */
354
  check_killed_async();
355
 
356
  /* Then, look for pending signal delivery */
357
  kern_deliver_pending_signals();
358
}
359
 
360
/*----------------------------------------------------------------------*/
157 pj 361
/* Abort strings                                                        */
362
/*----------------------------------------------------------------------*/
363
 
364
const char *const _sys_abrtlist[] = {
365
  "zero - no error",
366
  "OSLib exception",
367
  "generic unhandled signal raised",
368
  "error in signal_init",
369
  "default exception handler code",
370
  "ARP table full"
371
};
372
 
373
/*----------------------------------------------------------------------*/
2 pj 374
/* Kernel main system functions                                         */
375
/*----------------------------------------------------------------------*/
376
 
377
extern int trc_systemevents(trc_event_t *evt, int event, void *ptr);
378
 
379
/*+
380
  This function initialize
381
  - the virtual machine (timer, interrupt, mem)
382
  the system's structures (queues, tables) , & the two task main &
383
  dummy, that are always present
384
+*/
45 pj 385
void __kernel_init__(/* struct multiboot_info *multiboot */ void)
2 pj 386
{
387
  int i,j;                                              /* counters */
388
 
389
  struct ll_initparms parms;                          /* for the VM */
390
 
391
//  extern void C8042_restore(void);              /* an exit function */
392
  int aborting;          /* it is set if we are aborting the system */
393
 
45 pj 394
  struct multiboot_info *multiboot=mbi_address();
2 pj 395
 
396
 
397
 
398
  /*
399
   * Runlevel 0: kernel startup
400
   *
401
   *
402
   */
403
 
38 pj 404
  runlevel = RUNLEVEL_STARTUP;
2 pj 405
 
406
  /* The kernel startup MUST proceed with int disabled!    */
407
  kern_cli();
408
 
409
  /* First we initialize the memory allocator, because it is needed by
410
     __kernel_register_levels__     */
411
  kern_mem_init(multiboot);
412
 
413
  /* Clear the task descriptors */
414
  for (i = 0; i < MAX_PROC; i++) {
415
     proc_table[i].task_level   = -1;
416
     proc_table[i].stack        = NULL;
417
     proc_table[i].name[0]      = 0;
418
     proc_table[i].status       = FREE;
419
     proc_table[i].pclass       = 0;
420
     proc_table[i].group        = 0;
421
     proc_table[i].stacksize    = 0;
422
     proc_table[i].control      = 0;
423
     proc_table[i].frozen_activations = 0;
424
     proc_table[i].sigmask      = 0;
425
     proc_table[i].sigpending   = 0;
426
     proc_table[i].avail_time   = 0;
427
     proc_table[i].shadow       = i;
428
     proc_table[i].cleanup_stack= NULL;
429
     proc_table[i].errnumber    = 0;
29 pj 430
     //proc_table[i].priority     = 0;
431
     //NULL_TIMESPEC(&proc_table[i].timespec_priority);
2 pj 432
     proc_table[i].delay_timer  = -1;
433
     proc_table[i].wcet         = -1;
434
 
435
     proc_table[i].jet_tvalid   = 0;
436
     proc_table[i].jet_curr     = 0;
437
     proc_table[i].jet_max      = 0;
438
     proc_table[i].jet_sum      = 0;
439
     proc_table[i].jet_n        = 0;
440
     for (j=0; j<JET_TABLE_DIM; j++)
441
        proc_table[i].jet_table[j] = 0;
442
 
443
     proc_table[i].waiting_for_me = NIL;
444
     proc_table[i].return_value   = NULL;
445
 
446
     for (j=0; j<PTHREAD_KEYS_MAX; j++)
447
       proc_table[i].keys[j] = NULL;
448
  }
449
 
29 pj 450
  /* set up the free descriptor queue */
451
  //  for (i = 0; i < MAX_PROC-1; i++) proc_table[i].next = i+1;
452
  //  proc_table[MAX_PROC-1].next = NIL;
453
  //  for (i = MAX_PROC-1; i > 0; i--) proc_table[i].prev = i-1;
454
  //  proc_table[0].prev = NIL;
455
  //  freedesc = 0;
456
  iq_init(&freedesc, NULL, 0);
457
  for (i = 0; i < MAX_PROC; i++)
458
    iq_insertlast(i,&freedesc);
459
 
2 pj 460
  /* Set up the varius stuff */
461
  global_errnumber = 0;
462
  task_counter     = 0;
463
  system_counter   = 0;
464
  exec             = -1;
465
  exec_shadow      = -1;
466
  cap_timer        = -1;
467
  NULL_TIMESPEC(&cap_lasttime);
468
  sched_levels     = 0;  /* They are not registered yet... */
469
  res_levels       = 0;
470
  calling_runlevel_func = 0;
471
 
472
  /* Clear the key-specific data */
473
  task_specific_data_init();
474
 
475
  /* Clear exit and init functions */
476
  runlevel_init();
477
 
478
  /* Init VM layer (Interrupts, levels & memory management)           */
479
  /* for old exception handling, use excirq_init() */
480
  signals_init();
38 pj 481
  set_default_exception_handler();
2 pj 482
 
38 pj 483
  /* Clear scheduling modules registration data */
484
  levels_init();
485
 
2 pj 486
  sys_tick = __kernel_register_levels__(multiboot);
487
 
488
  /* tracer stuff */
489
  /*
490
  trc_register_eventclass(TRC_CLASS_SYSTEM,
491
                          TRC_SYSTEMNUMBER,
492
                          trc_systemevents);
493
  */
494
 
495
  /* test on system tick */
496
  if (sys_tick>=55000)  {
497
     printk("The system tick must be less than 55 mSec!");
498
     l1_exit(0);
499
  }
500
 
501
  /* OSLib initialization */
502
  if (sys_tick)
503
    parms.mode = LL_PERIODIC;
504
  else
505
    parms.mode = LL_ONESHOT; // one shot!!!
506
 
507
  parms.tick = sys_tick;
508
 
509
  /*
38 pj 510
   * Runlevel INIT: Let's go!!!!
2 pj 511
   *
512
   *
513
   */
514
 
515
  runlevel = RUNLEVEL_INIT;
516
 
517
  ll_init();
518
  event_init(&parms);
519
  seterrnumber(__errnumber);
520
  event_setprologue(event_resetepilogue);
521
  event_setlasthandler(kern_after_dispatch);
522
 
523
  /* call the init functions */
524
  call_runlevel_func(RUNLEVEL_INIT, 0);
525
 
38 pj 526
 
527
 
528
 
529
  /*
530
   * Runlevel RUNNING: Hoping that all works fine ;-)
531
   *
532
   *
533
   */
534
 
535
  runlevel = RUNLEVEL_RUNNING;
536
 
2 pj 537
  /* reset keyboard after exit */
538
//  sys_atexit((void(*)(void *))C8042_restore,NULL,AFTER_EXIT);
539
 
540
  /* tracer stuff */
541
  trc_resume();
542
 
543
  /* exec and exec_shadow are already = -1 */
38 pj 544
  kern_gettime(&schedule_time);
2 pj 545
  scheduler();
546
  global_context = ll_context_from(); /* It will be used by sys_end */
547
  ll_context_to(proc_table[exec_shadow].context);
548
 
549
  /*
550
   *
551
   * Now the system starts!!!
552
   * (hoping that someone has created some task(s) )
553
   * The function returns only at system end...
554
   *
555
   */
556
 
557
 
558
  /*
38 pj 559
   * Runlevel SHUTDOWN: Shutting down the system... :-(
2 pj 560
   *
561
   *
562
   */
563
 
564
  event_setlasthandler(NULL);
565
 
566
  // ll_abort(666); 
567
  /* tracer stuff */
568
  trc_suspend();
569
 
570
  runlevel = RUNLEVEL_SHUTDOWN;
571
 
572
  /* 1 when the error code is != 0 */
573
  aborting = global_errnumber > 0;
574
 
38 pj 575
  //kern_printf("after  - system_counter=%d, task_counter = %d\n", system_counter,task_counter); 
2 pj 576
 
577
  call_runlevel_func(RUNLEVEL_SHUTDOWN, aborting);
578
 
38 pj 579
  //kern_printf("before - system_counter=%d, task_counter = %d\n", system_counter,task_counter);
2 pj 580
 
581
  if (system_counter) {
582
    /* To shutdown the kernel correctly, we have to wait that all the SYSTEM
583
       tasks that are killable will die...
584
 
585
       We don't mess about the user task... we only kill them and reschedule
586
       The only thing important is that the system tasks shut down correctly.
587
       We do nothing for user tasks that remain active (because, for example,
588
       they have the cancelability set to deferred) when the system goes to
589
       runlevel 3 */
38 pj 590
    //kern_printf("Û%lu",kern_gettime(NULL));
2 pj 591
    kill_user_tasks();
38 pj 592
    //kern_printf("Û%lu",kern_gettime(NULL)); 
2 pj 593
 
594
    /* we have to go again in multitasking mode!!! */
595
    mustexit = 0;
596
 
597
    /* exec and exec_shadow are already = -1 */
38 pj 598
    kern_gettime(&schedule_time);
2 pj 599
    global_context = ll_context_from(); /* It will be used by sys_end */
600
    scheduler();
601
 
602
    event_setlasthandler(kern_after_dispatch);
603
    ll_context_to(proc_table[exec_shadow].context);
604
    event_setlasthandler(NULL);
605
  }
606
 
607
 
608
 
609
 
610
  /*
38 pj 611
   * Runlevel BEFORE_EXIT: Before Halting the system
2 pj 612
   *
613
   *
614
   */
615
 
616
  runlevel = RUNLEVEL_BEFORE_EXIT;
617
 
618
 
619
  /* the field global_errnumber is
620
     =0  if the system normally ends
621
     !=0 if an abort is issued
622
  */
623
 
624
  //kern_printf("Chiamo exit Functions\n"); 
625
 
626
  call_runlevel_func(RUNLEVEL_BEFORE_EXIT, aborting);
627
 
628
  //kern_printf("Dopo exit Functions\n"); 
629
 
630
  /* Shut down the VM layer */
631
  ll_end();
632
 
633
 
634
  /*
38 pj 635
   * Runlevel AFTER_EXIT: After halting...
2 pj 636
   *
637
   *
638
   */
639
 
640
  runlevel = RUNLEVEL_AFTER_EXIT;
641
 
642
  //kern_printf("prima before Functions\n"); 
643
 
644
  call_runlevel_func(RUNLEVEL_AFTER_EXIT, 0);
645
 
646
  //kern_printf("dopo before Functions\n"); 
647
  kern_cli();
648
  if (global_errnumber) {
649
    /* vm_abort called */
157 pj 650
    kern_printf("Abort detected\nCode : %u (%s)\n",global_errnumber,
651
                global_errnumber<=LAST_ABORT_NUMBER ? _sys_abrtlist[global_errnumber] : "no description" );
2 pj 652
    l1_exit(-1);
653
  }
654
 
655
  l1_exit(0); // System terminated normally
656
 
657
}
658
 
38 pj 659
/* IMPORTANT!!!
660
   I'm almost sure the shutdown procedure does not work into interrupts. */
2 pj 661
void internal_sys_end(int i)
662
{
663
  LEVEL l;    /* a counter                                     */
38 pj 664
 
665
  /* if something goes wron during the real mode */
666
  if (runlevel==RUNLEVEL_STARTUP || runlevel==RUNLEVEL_AFTER_EXIT)
667
    l1_exit(i);
2 pj 668
 
669
  //kern_printf("mustexit=%d",mustexit);
38 pj 670
  if (mustexit)
671
    return;
2 pj 672
 
38 pj 673
  mustexit = 1;
2 pj 674
 
38 pj 675
  global_errnumber = i;
676
 
677
 
678
  if (!ll_ActiveInt()) {
679
    proc_table[exec_shadow].context = kern_context_save();
680
 
2 pj 681
    if (exec_shadow != -1) {
38 pj 682
      kern_gettime(&schedule_time);
683
 
684
      kern_epilogue_macro();
685
 
2 pj 686
      /* then, we call the epilogue. the epilogue tipically checks the
38 pj 687
         avail_time field... */
2 pj 688
      l = proc_table[exec_shadow].task_level;
38 pj 689
      level_table[l]->public_epilogue(l,exec_shadow);
690
 
2 pj 691
      exec_shadow = exec = -1;
692
    }
38 pj 693
    kern_context_load(global_context);
694
  }
2 pj 695
 
38 pj 696
  if (ll_ActiveInt()) {
697
    ll_context_to(global_context);
698
    /* The context change will be done when all the interrupts end!!! */
2 pj 699
  }
38 pj 700
 
2 pj 701
  //kern_printf("fine sysend");
702
 
703
  /* the control reach this line only if we call sys_end() into an event
704
     handler (for example, if the event raises an exception with
705
     SA_USEFAST active and the exception calls sys_end() ) */
706
}
707
 
708
 
38 pj 709
/*
710
   Close the system & return to HOST OS.
711
   Can be called from tasks and from ISRS
712
 
713
 
714
*/
715
void sys_abort(int err)
2 pj 716
{
717
  SYS_FLAGS f;
718
 
719
  f = kern_fsave();
38 pj 720
  internal_sys_end(err);
2 pj 721
  kern_frestore(f);
722
}
723
 
38 pj 724
void sys_end(void)
2 pj 725
{
38 pj 726
  sys_abort(0);
2 pj 727
}
728
 
729
void _exit(int status)
730
{
38 pj 731
  sys_abort(status);
2 pj 732
}
733
 
734
 
735
 
736
/* this function is never called... used for the OSLib */
737
void sys_abort_tail(int code)
738
{
739
 //DUMMY!!!!
740
}
741
 
742
 
743
 
744
/*+ this primitive returns the time read from the system timer +*/
745
TIME sys_gettime(struct timespec *t)
746
{
747
  SYS_FLAGS f;
748
  TIME x;
749
 
750
  f = kern_fsave();
38 pj 751
  x = kern_gettime(t);
2 pj 752
  kern_frestore(f);
753
 
754
  return x;
755
}
756
 
757