Subversion Repositories shark

Rev

Rev 29 | Rev 45 | 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
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
 
22
/**
23
 ------------
38 pj 24
 CVS :        $Id: func.h,v 1.3 2003-01-07 17:12:19 pj Exp $
2 pj 25
 
26
 File:        $File$
38 pj 27
 Revision:    $Revision: 1.3 $
28
 Last update: $Date: 2003-01-07 17:12:19 $
2 pj 29
 ------------
30
 
31
Kernel functions:
32
 
33
- Debug stuff
34
 
35
- Primitives called at initialization time
36
 
37
- Kernel global functions (scheduler, queues)
38
 
39
- Kernel VM hooks
40
 
41
- IRQ, errors & exception handling
42
 
43
- System management primitives
44
 
45
- Jet management primitives
46
 
47
- Task management primitives
48
 
49
- Mutex primitives
50
 
51
**/
52
 
53
/*
54
 * Copyright (C) 2000 Paolo Gai
55
 *
56
 * This program is free software; you can redistribute it and/or modify
57
 * it under the terms of the GNU General Public License as published by
58
 * the Free Software Foundation; either version 2 of the License, or
59
 * (at your option) any later version.
60
 *
61
 * This program is distributed in the hope that it will be useful,
62
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
63
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
64
 * GNU General Public License for more details.
65
 *
66
 * You should have received a copy of the GNU General Public License
67
 * along with this program; if not, write to the Free Software
68
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
69
 *
70
 */
71
 
72
#ifndef __KERNEL_FUNC_H__
73
#define __KERNEL_FUNC_H__
74
 
75
#include <ll/ll.h>
76
#include <ll/stdio.h>
77
#include <kernel/types.h>
78
#include <kernel/model.h>
79
#include <kernel/mem.h>
80
#include <signal.h>
81
#include <kernel/var.h>
82
#include <errno.h>
83
 
84
 
85
/*---------------------------------------------------------------------*/
86
/* Debug stuff                                                         */
87
/*---------------------------------------------------------------------*/
88
 
89
/* if a source use printk() it should include log.h not func.h */
90
#include <kernel/log.h>
91
 
92
/*---------------------------------------------------------------------*/
93
/* Kernel global functions: initialization & termination...            */
94
/*---------------------------------------------------------------------*/
95
 
96
/*+ this function is called by __kernel_init__.
97
    It register the modules in the system at init time +*/
98
TIME __kernel_register_levels__(void *arg);
99
 
100
/*+ This function returns a level_des **. the value returned shall be
38 pj 101
    used to register a level module.
2 pj 102
 
38 pj 103
    The function is usually called at module registration time.  The
104
    function can also be called when the system is already started, to
105
    allow the implementation of dynamic module registration.  
106
 
107
    The argument must be the size of the data block that have to be allocated
108
 
109
    The function returns the number of the descriptor allocated for the module
110
    or -1 in case there are no free descriptors.
111
 
112
    The function also reserves a descriptor with size s, initialized
113
    with default function pointers.
114
 
115
+*/
116
LEVEL level_alloc_descriptor(size_t s);
117
 
118
/*+ This function release a level descriptor previously allocated using
119
  level_alloc_descriptor().
120
 
121
  The function returns 0 if the level has been freed, or -1 if someone is
122
  using it, -2 if the level has never been registered.
123
 
124
+*/
125
int level_free_descriptor(LEVEL l);
126
 
127
/* Call this if you want to say that your module is using module l
128
   (e.g., for calling its private functions) */
129
int level_use_descriptor(LEVEL l);
130
 
131
/* Call this when you no more need the module l */
132
int level_unuse_descriptor(LEVEL l);
133
 
2 pj 134
/*+ This function returns a resource_des **. the value returned shall be
135
    used to register a resource module. The function shall be called only at
136
    module registration time. It assume that the system is not yet
137
    initialized, so we shall not call sys_abort...                     +*/
138
RLEVEL resource_alloc_descriptor();
139
 
140
/*+ This function compute the command line parameters from the multiboot_info
141
    NOTE: this function modify the multiboot struct, so this function and
142
    __call_main__ are mutually exclusives!!! +*/
143
void __compute_args__(struct multiboot_info *mbi, int *_argc, char **_argv);
144
 
145
/*+ This function calls the standard C main() function, with a
146
    parameter list up to 100 parameters                        +*/
147
int __call_main__(struct multiboot_info *mb);
148
 
149
/*+ This task initialize the system and calls the main() with
150
    __call_mail__ .
151
    It should be created by a level registered in the system by
152
    __kernel_register_levels__ +*/
153
TASK __init__(void *arg);
154
 
155
/*+ Use this function to post your own exit operations
156
    (when uses some defines contained in const.h) +*/
157
int sys_atrunlevel(void (*func_code)(void *),void *parm, BYTE when);
158
 
159
/*---------------------------------------------------------------------*/
29 pj 160
/* Kernel global functions: scheduler,                                 */
2 pj 161
/*---------------------------------------------------------------------*/
162
 
163
/*+ This is the generic scheduler.
164
    The scheduler calls the appropriates level schedulers and then
165
    dispatch the task chosen. +*/
166
void scheduler(void);
167
 
168
/*+ called in the events to force the system to execute the scheduler at
169
    the end of an event list +*/
170
void event_need_reschedule();
171
 
172
void task_makefree(void *ret);
173
void check_killed_async(void);
174
 
175
int guarantee();
176
 
38 pj 177
void levels_init(void); /* see init.c */
178
 
2 pj 179
void runlevel_init();
180
void call_runlevel_func(int runlevel, int aborting);
181
 
182
// in kill.c
183
void kill_user_tasks();
184
 
185
void event_resetepilogue();
186
 
187
 
188
void call_task_specific_data_destructors();
189
void task_specific_data_init();
190
 
191
// in kill.c
192
void register_cancellation_point(int (*func)(PID p, void *arg), void *arg);
193
 
194
// in signal.c
195
void register_interruptable_point(int (*func)(PID p, void *arg), void *arg);
196
 
197
 
198
/*---------------------------------------------------------------------*/
199
/* Kernel VM hooks                                                     */
200
/*---------------------------------------------------------------------*/
201
 
202
/* this hooks redefines the VM functions to use them into the kernel...
203
 
204
   the only VM functions called directly from the kernel are VM_init and
205
   VM_end
206
*/
207
 
208
/* Context management routines */
209
#define kern_context_create    ll_context_create
210
#define kern_context_delete    ll_context_delete
211
 
212
extern __inline__ CONTEXT kern_context_save()
213
{
214
  cli();
215
  return ll_context_from();
216
}
217
 
218
/*+ this functions are called every time a context is changed +*/
219
void kern_after_dispatch(void);
220
 
221
/* Warning: if modified, modify also:
222
   - task_join
223
   - cond_wait
224
   - cond_timedwait
225
   - internal_sem_wait
226
*/
227
extern __inline__ void kern_context_load(c)
228
{
229
  ll_context_to(c);
230
  kern_after_dispatch();
231
  sti();
232
}
233
 
234
 
235
/* Interrupt enabling/disabling */
236
#define kern_cli          cli
237
#define kern_sti          sti
238
 
239
/* Interrupt enabling/disabling with flag save */
240
#define kern_fsave        ll_fsave
241
#define kern_frestore     ll_frestore
242
 
243
/* interrupt handling */
244
#define kern_irq_unmask   VM_irq_unmask
245
#define kern_irq_mask     VM_irq_mask
246
 
247
extern __inline__ int kern_event_post(const struct timespec *time,
248
                                      void (*handler)(void *p),
249
                                      void *par)
250
{
251
  int e;
252
  e = event_post(*time,handler,par);
253
 
254
  if (e == -1)
255
    kern_raise(XNOMORE_EVENTS,exec_shadow);
256
 
257
  return e;
258
}
259
 
38 pj 260
#define kern_event_delete event_delete
261
 
2 pj 262
/*+ the default capacity timer used by the kernel... +*/
263
void capacity_timer(void *arg);
264
 
265
 
266
#define kern_printf message
267
 
38 pj 268
extern __inline__ TIME kern_gettime(struct timespec *t)
269
{
270
  return ll_gettime(TIME_EXACT, t);
271
}
272
 
273
 
274
 
2 pj 275
/*---------------------------------------------------------------------*/
38 pj 276
/* Kernel global functions: IRQ handling                               */
2 pj 277
/*---------------------------------------------------------------------*/
278
 
279
/*+ Interrupt handler installation +*/
280
int handler_set(int no, void (*fast)(int), PID pi);
281
 
282
/*+ Interrupt handler removal      +*/
283
int handler_remove(int no);
284
 
285
 
286
/*---------------------------------------------------------------------*/
287
/* System management primitives                                        */
288
/*---------------------------------------------------------------------*/
289
 
290
/*+ Close the system & return to HOST OS.
291
    Can be called from all the tasks...
292
    The first time it is called it jumps to the global context
293
    The second time it jumps only if there are no system task remaining
294
    The error code passed is 0... (it is saved on the first call!!!) +*/
295
void sys_end(void);
296
 
297
/*+ Close the system & return to HOST OS.
298
    Can be called from all the tasks...
299
    The first time it is called it works as the sys_end
300
    The second time it jumps every time
301
    The error code passed is 0... +*/
302
void sys_abort(int err);
303
 
304
/* The system implements also exit and _exit as a redefinition of sys_end
305
   This is not the correct behaviour, and should be fixed.
306
   The definitions for these functions are in kernel/kern.c
307
*/
308
 
309
/*+ Print a message then call sys_abort(333).
310
    Can be called from all the tasks...  +*/
311
void sys_panic(const char * fmt, ...) __attribute__ ((format (printf, 1, 2)));
312
 
313
/*+ prints an error message (see perror.c) +*/
314
void perror (const char *s);
315
 
316
/*+ this primitive returns the time read from the system timer +*/
317
TIME sys_gettime(struct timespec *t);
318
 
319
/*---------------------------------------------------------------------*/
320
/* Jet management primitives                                           */
321
/*---------------------------------------------------------------------*/
322
 
323
/*+ This primitive returns the maximum execution time and the total
324
    execution time from the task_create or the last jet_delstat
325
    It returns also the number of instances to use to calculate the mean
326
    time and the current job execution time.
327
    The value returned is 0 if all ok, -1 if the PID is not correct or
328
    the task doesn't have the JET_ENABLE bit set.
329
+*/
330
int jet_getstat(PID p, TIME *sum, TIME *max, int *n, TIME *curr);
331
 
332
/*+ This primitive reset to 0 the maximum execution time and the mean
333
    execution time of the task p, and reset to 0 all the entries in
334
    jet_table.
335
    The value returned is 0 if all ok, -1 if the PID is not correct or
336
    the task doesn't have the JET_ENABLE bit set.                     +*/
337
int jet_delstat(PID p);
338
 
339
/*+ This primitive returns the last n values of the task execution time
340
    recorded after the last call to jet_gettable or jet_delstat.
341
    If n is
342
    <0 it will be set only the last values inserted in the table
343
       since the last call of jet_gettable.
344
    >0 it will be set up to JET_TABLE_DIM datas.
345
 
346
    The value returned is -1 if the PID is not correct or
347
    the task doesn't have the JET_ENABLE bit set, otherwise it returns the
348
    number of values set in the parameter table.
349
    (can be from 0 to JET_TABLE_DIM-1)
350
+*/
351
int jet_gettable(PID p, TIME *table, int n);
352
 
353
/*+ This function updates the jet information. +*/
354
void jet_update_slice(TIME t);
355
 
356
/*+ This function updates the jet information at the task end period
357
    it is called in task_endcycle and task_sleep +*/
358
void jet_update_endcycle();
359
 
360
/*---------------------------------------------------------------------*/
38 pj 361
/* Internal Macros                                                     */
362
/*---------------------------------------------------------------------*/
363
 
364
extern __inline__ void kern_epilogue_macro(void)
365
{
366
  TIME tx;    /* a dummy used for time computation             */
367
  struct timespec ty; /* a dummy used for time computation     */
368
 
369
  kern_gettime(&schedule_time);
370
 
371
  /* manage the capacity event */
372
  SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
373
  tx = TIMESPEC2USEC(&ty);
374
  proc_table[exec_shadow].avail_time -= tx;
375
  jet_update_slice(tx);
376
 
377
  /* if the event didn't fire before, we delete it. */
378
  if (cap_timer != NIL) {
379
    kern_event_delete(cap_timer);
380
    cap_timer = NIL;
381
  }
382
}
383
 
384
/* This function is called by the kernel into kern.c to register a default
385
   exception handler */
386
int set_default_exception_handler(void);
387
 
388
/*---------------------------------------------------------------------*/
2 pj 389
/* Task management primitives                                          */
390
/*---------------------------------------------------------------------*/
391
 
392
 
393
/*+ This primitive:
394
    - Reserve a task descriptor
395
    - Create the task based on the task model passed
396
    - Initialize the resources used by the task
397
    - Guarantees the task set
398
+*/
399
PID task_createn(char *name,      /*+ the symbolic name of the task +*/
400
                 TASK (*body)(),  /*+ a pointer to the task body    +*/
401
                 TASK_MODEL *m,   /*+ the task model                +*/
402
                                  /*+ the resources models, a list  +*/
403
                 ...);            /*+ of models terminated by NULL  +*/
404
 
405
 
406
/*+ a redefinition of task_createn +*/
407
extern __inline PID task_create(char *name, TASK (*body)(),
408
                                void *m, void *r)
409
{
410
   return task_createn(name, body, (TASK_MODEL *)m, (RES_MODEL *)r, NULL);
411
}
412
 
413
 
414
/* This function allow to create a set of tasks without guarantee.
415
   It must be called with interrupts disabled and it must be used with
416
   group_create_accept and group_create_reject.
417
 
418
   This function allocates a task descriptor and fills it.
419
   After that, the guarantee() function should be called to check for task(s)
420
   admission.
421
   Next, each task created with group_create must be accepted with a call to
422
   group_create_accept() or rejected with a call to group_create_reject.
423
 
424
   The function returns the PID of the allocated descriptor, or NIL(-1)
425
   if the descriptor cannot be allocated or some problems arises the creation.
426
   If -1 is returned, errno is set to a value that represent the error:
427
      ENO_AVAIL_TASK       -> no free descriptors available
428
      ENO_AVAIL_SCHEDLEVEL -> there were no scheduling modules that can handle
429
                              the TASK_MODEL *m passed as parameter
430
      ETASK_CREATE         -> there was an error during the creation of the
431
                              task into the scheduling module
432
      ENO_AVAIL_RESLEVEL   -> there were no resource modules that can handle
433
                              one of the RES_MODEL * passed as parameter
434
*/
435
PID group_create(char *name,
436
                 TASK (*body)(),
437
                 TASK_MODEL *m,
438
                 ...);
439
 
440
 
441
/*
442
  This function should be called when a task created with group_create
443
  is successfully guaranteed and accepted in the system.
444
  This function finish the creation process allocating the last resources
445
  for the task (i.e., the stack and the context).
446
  it returns:
447
 
448
  -1 if something goes wrong. In this case, THE TASK IS AUTOMATICALLY REJECTED
449
     AND THE GROUP_CREATE_REJECT MUST NOT BE CALLED.
450
     errno is set to a value that explains the problem occurred:
451
 
452
     ENO_AVAIL_STACK_MEM -> No stack memory available for the task
453
     ENO_AVAIL_TSS       -> No context available for the task (This is a
454
                            CRITICAL error, and usually never happens...)
455
*/
456
int group_create_accept(PID i, TASK_MODEL *m);
457
 
458
/*
459
  This function should be called when a task created with group_create
460
  can not be successfully guaranteed.
461
  This function reject the task from the system.
462
  You cannot use the PID of a rejected task after this call.
463
*/
464
void group_create_reject(PID i);
465
 
466
/*+
467
  It blocks all explicit activation of a task made with task_activate and
468
  group_activate. These activations are registered in an internal counter,
469
  returned by task_unblock_activation.
470
  it returns 0 if all ok, or -1 otherwise. errno is set accordingly.
471
+*/
472
int task_block_activation(PID p);
473
 
474
/*+
475
  It unblocks all explicit activations of a task, and returns the number of
476
  "frozen" activations. It not call the task_activate!!!!
477
  it returns -1 if an error occurs. errno is set accordingly.
478
+*/
479
int task_unblock_activation(PID p);
480
 
481
 
482
/*+ Activate a task specified via pid returned from task_create +*/
483
int task_activate(PID pid);
484
 
485
/*+ Kill a task specified via pid returned from task_create +*/
486
int task_kill(PID pid);
487
 
488
/*+
489
  This primitive autokills the excuting task; it was used to avoid
490
  that returning from a task cause a jmp to an unpredictable location.
491
 
492
  Now it is obsolete, the task_create_stub do all the works.
493
 
494
  It is used by the Posix layer to implement pthread_exit
495
+*/
496
void task_abort(void *returnvalue);
497
 
498
/*+ Creates a cancellation point in the calling task +*/
499
void task_testcancel(void);
500
 
501
/*+ Set the cancellation state of the task +*/
502
int task_setcancelstate(int state, int *oldstate);
503
 
504
/*+ Set the cancellation type of the task +*/
505
int task_setcanceltype(int type, int *oldtype);
506
 
507
/*+ this function suspends execution of the calling task until the target
508
    task terminates, unless the target task has already terminated.
509
    It works like the pthread_join +*/
510
int task_join(PID p, void **value);
511
 
512
/*+ this function set the detach state of a task to joinable. This function
513
    is not present in Posix standard...
514
    returns ESRCH if p is non correct +*/
515
int task_joinable(PID p);
516
 
517
/*+ this function set the detach state of a task to detached. This function
518
    works as the posix's pthread_detach
519
    returns EINVAL if p can't be joined (or currently a task has done a
520
    join on it (condition not provided in posix)
521
    ESRCH if p is not correct +*/
522
int task_unjoinable(PID p);
523
 
524
/*+ Disable the preemption mechanism on the task.
525
    This primitive is very dangerous!!!!         +*/
526
void task_nopreempt(void);
527
 
528
/*+ Enable the preemption mechanism on the task. +*/
529
void task_preempt(void);
530
 
38 pj 531
/*+ sends a message to the scheduling module that is handling the task +*/
532
int task_message(void *m, int reschedule);
533
 
2 pj 534
/*+ This function signals to the kernel that the current istance of
535
    the task (periodic or aperiodic) is ended; so the task can be
536
    suspended until it is activated again. Pending activations may be saved
537
    depending on the task model +*/
38 pj 538
extern __inline__ void task_endcycle(void)
539
{
540
  task_message(NULL, 1);
541
}
2 pj 542
 
543
/*+ This primitives refers the group id which is supplied
544
    by the application, not by the kernel                 +*/
545
int group_activate(WORD g);
546
int group_kill(WORD g);
547
 
548
 
549
/*---------------------------------------------------------------------*/
550
/* Mutex primitives                                                    */
551
/*---------------------------------------------------------------------*/
552
 
553
/* This primitives manages a mutex in the system.
554
   The behavior of the functions is similar to the POSIX ones. */
555
 
556
 
557
/*+ Alloc a mutex descriptor +*/
558
int mutex_init(mutex_t *mutex, const mutexattr_t *attr);
559
 
560
/*+ Free a mutex descriptor  +*/
561
int mutex_destroy(mutex_t *mutex);
562
 
563
/*+ Block wait               +*/
564
int mutex_lock(mutex_t *mutex);
565
 
566
/*+ Non-block wait           +*/
567
int mutex_trylock(mutex_t *mutex);
568
 
569
/*+ unlock primitive +*/
570
int mutex_unlock(mutex_t *mutex);
571
 
572
/*---------------------------------------------------------------------*/
573
/* Condition variables                                                 */
574
/*---------------------------------------------------------------------*/
575
 
576
/*+ Initialization of the condition variable +*/
577
int cond_init(cond_t *cond);
578
 
579
/*+ free a condition variable descriptor +*/
580
int cond_destroy(cond_t *cond);
581
 
582
/*+ signal on a condition variable, it unlocks only one task +*/
583
int cond_signal(cond_t *cond);
584
 
585
/*+ broadcast on a condition variable, it unlocks all the blocked tasks +*/
586
int cond_broadcast(cond_t *cond);
587
 
588
/*+ wait on a condition variable +*/
589
int cond_wait(cond_t *cond, mutex_t *mutex);
590
 
591
/*+ wait on a condition variable (with timer) +*/
592
int cond_timedwait(cond_t *cond, mutex_t *mutex,
593
                   const struct timespec *abstime);
594
 
595
/*---------------------------------------------------------------------*/
596
/* Task specific data primitives                                       */
597
/*---------------------------------------------------------------------*/
598
 
599
/* they are similar to the POSIX standard */
600
 
601
int task_key_create(task_key_t *key, void (*destructor)(void *));
602
void *task_getspecific(task_key_t key);
603
int task_setspecific(task_key_t key, const void *value);
604
int task_key_delete(task_key_t key);
605
 
606
/*---------------------------------------------------------------------*/
607
/* Task cancellation handlers                                          */
608
/*---------------------------------------------------------------------*/
609
 
610
/*+ push the specified cancellation cleanup handler routine onto
611
    the cancellation cleanup stack
612
void task_cleanup_push(void (*routine)(void *), void *arg); +*/
613
#define task_cleanup_push(rtn,arg) { \
614
        struct _task_handler_rec __cleanup_handler, **__head; \
615
        __cleanup_handler.f = rtn; \
616
        __cleanup_handler.a = arg; \
617
        __head = task_getspecific(0); \
618
        __cleanup_handler.next = *__head; \
619
        *__head = &__cleanup_handler;
620
 
621
/*+
622
    removes the routine at the top of the cancellation cleanup stack
623
    of the calling thread
624
void task_cleanup_pop(int execute); +*/
625
#define task_cleanup_pop(ex) \
626
        *__head = __cleanup_handler.next; \
627
        if (ex) (*__cleanup_handler.f) (__cleanup_handler.a); \
628
}
629
 
630
#endif /* __FUNC_H__ */