Subversion Repositories shark

Rev

Rev 1676 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1676 tullio 1
%----------------------------------------------------------------------------
2
\chapter{The Generic Kernel Internals}
3
%----------------------------------------------------------------------------
4
 
5
In this chapter some information are given on the implementation
6
of the Generic Kernel. The objective of this chapter is to give
7
the user enought information about the internal of the kernel to
8
allow an analysis of the source code. The code described in this
9
chapter is contained into the \texttt{kernel} directory.
10
 
11
%----------------------------------------------------------------------------
12
\section{System Tasks and User Tasks}
13
\label{Kernel_TaskUtente}
14
%----------------------------------------------------------------------------
15
 
16
The Generic Kernel classifies the tasks in the system using two
17
flags of the control field of the task descriptor. The Programming
18
Model of the kernel is a monoprocess multithread model, so each
19
task shares a common memory without any kind of address
20
protection.
21
 
22
The two flags of interest are the \texttt{SYSTEM\_TASK} and the
23
\texttt{NO\_KILL} flags:
24
 
25
\begin{itemize}
26
\item If the \texttt{SYSTEM\_TASK} flag is set a task is a task
27
used internally by the Kernel, otherwise the task is considered an
28
user task; \item If the \texttt{NO\_KILL} flag is set a task
29
cannot be killed by a \texttt{task\_kill} or
30
\texttt{pthread\_cancel} primitive.
31
\end{itemize}
32
These two flags divide the task universe in four sets (look at
33
Figure \ref{Kernel_4Insiemi} and at Table
34
\ref{Kernel_Tab_4Insiemi}):%
35
\begin{figure}
36
\begin{center}\includegraphics[%
37
  width=8cm]{images/kernel_quattro_insiemi.eps}\end{center}
38
 
39
 
40
\caption{\label{Kernel_4Insiemi}The four sets in whitch the tasks
41
are divided; The values of the two flags \texttt{SYSTEM\_TASK}
42
(ST) and \texttt{NO\_KILL} (NK) are showed.}
43
\end{figure}
44
%
45
\begin{table}
46
\begin{center}\begin{tabular}{|c||c|c|}
47
\hline & \texttt{SYSTEM\_TASK=0}&
48
\texttt{SYSTEM\_TASK=1}\\ \hline \hline
49
\texttt{NO\_KILL=0}& User tasks& System Drivers\\
50
\hline \texttt{NO\_KILL=1}& Immortal User Tasks& System
51
Tasks\\ \hline
52
\end{tabular}\end{center}
53
 
54
 
55
\caption{\label{Kernel_Tab_4Insiemi}The four sets in whitch the
56
tasks are divided.}
57
\end{table}
58
 
59
\begin{description}
60
\item [User~Tasks]These are the tasks usually created by the user;
61
\item [Immortal~User~Tasks]These tasks are tasks that the user
62
wants to protect against uncontrolled cancellations. Usually the
63
life of these tasks is not important for the termination of the
64
system; in other words, the system can shut down also if these
65
tasks are not ended; \item [System~Drivers]These tasks are handled
66
directly by the Kernel or by some Libraries that implement some
67
important things (for example, the file system controls the hard
68
disks with tasks of this type); \item [System~Tasks]These are
69
non-critical tasks that have to be always present in the system;
70
the life of the system depends on the life of these tasks. Such a
71
task is for example the dummy task.
72
\end{description}
73
 
74
System termination can be generated automatically by the Generic Kernel or it
75
can be forced if the user calls the \texttt{exit()} function.
76
 
77
The Generic Kernel starts the system termination when all User
78
Tasks ends or when all the System Drivers ends.
79
 
80
To do the shutdown in a correct way, the libraries that are
81
implemented using the System Drivers should end in a correct way.
82
Look at Section\ref{Kernel_Inizializzazione} for more
83
informations.
84
 
85
%----------------------------------------------------------------------------
86
\section{Initialization and Termination}
87
\label{Kernel_Inizializzazione}
88
%----------------------------------------------------------------------------
89
 
90
In this section the structure of the function
91
\texttt{\_\_kernel\_init\_\_} is described in more detail. This
92
function is the function called by the OS Lib at system startup.
93
%
94
% Tool: such section does not exists.
95
%
96
% The interface between the Generic Kernel and the OS Lib is not
97
% described here but in section \ref{OSLib_SezInizializzazione}.
98
 
99
%----------------------------------------------------------------------------
100
\subsection{Interrupt Disabling}
101
%----------------------------------------------------------------------------
102
 
103
The first thing that is done in the function is the disabling of
104
the interrupts. When the system starts, the OS Lib allocs a
105
context, whose number is stored by the Generic Kernel into the
106
global variable \texttt{global\_context}. In this startup context
107
the function \texttt{\_\_kernel\_init\_\_} is called; also the
108
functions that it calls run in that context.
109
 
110
The context used by the tasks will be allocated next, with a call
111
to the OS Lib function \texttt{ll\_context\_create} (this function
112
is called by the Generic Kernel into the primitive
113
\texttt{task\_create}).
114
 
115
The interrupts will be enabled automatically at the first context
116
change.
117
 
118
%----------------------------------------------------------------------------
119
\subsection{Initialization of the Memory Management}
120
%----------------------------------------------------------------------------
121
 
122
After disabling the interrupts, the dynamic memory manager can be
123
initialized. It must be the first thing that is initialized
124
because dynamic memory is used extensively in all the Kernel (and
125
the first place where it is used is the Module Registration).
126
 
127
%----------------------------------------------------------------------------
128
\subsection{Initialization of the static data structures}
129
%----------------------------------------------------------------------------
130
 
131
The next step in the in the Kernel startup is the initialization
132
of the staticdata structures. In particular, it will be
133
initialized:
134
 
135
\begin{itemize}
136
\item The task descriptor and the task-specific data; \item The
137
free descriptor queue; \item The arrays that contains the pointers
138
to the Module descriptors; \item The tata structures used to
139
implement POSIX signals; \item The data structures used to call
140
the init functions posted through the function
141
\texttt{sys\_atrunlevel}.
142
\end{itemize}
143
 
144
%----------------------------------------------------------------------------
145
\subsection{Resgistration of the Modules in the system}
146
\label{Kernel_kernel_register_levels}
147
%----------------------------------------------------------------------------
148
 
149
At this point, the system has the interrupts disabled and all
150
static data structures initialized. Now, the Generic kernel needs
151
to know what is the real Module configuration in the system. To
152
handle that, the following function is called:
153
 
154
\bigskip{}
155
\begin{center}\texttt{TIME
156
\_\_kernel\_register\_levels\_\_(void {*}arg)}\end{center}
157
\bigskip{}
158
 
159
That function is a user defined function that must call the
160
registration functions of the Scheduling Modules and of the
161
Resource Modules.
162
 
163
It has a parameter that contains a pointer to a \texttt{multiboot}
164
structure,that can be used to know some information about the
165
system and about the command line
166
arguments.%
167
\footnote{The function \texttt{\_\_compute\_args\_\_} described in
168
the file \texttt{include/kernel/func.h} can be
169
used.%
170
} . These informations can be useful to modify the Module
171
registration dinamically at run time.
172
 
173
The value returned by the function is the system tick that the
174
system will use for the periodic timer initialization. If the
175
value returned is 0 the generic kernel will use the one-shot timer
176
instead
177
%
178
% Tool: such section does not exists.
179
%
180
% (look at Section \ref{OSLib_Inizializzazione})
181
.
182
 
183
To simplify the developing of the applications, the kernel
184
distribution contains some init examples in the directory
185
\texttt{kernel/init}.
186
 
187
In the initialization function only these functions can be used:
188
 
189
\begin{itemize}
190
\item The functions that alloc and free the dynamic memory
191
(described in Section \ref{KernSupport_GestioneMemoria}); \item
192
The function \texttt{sys\_atrunlevel} that can be used to register
193
the initialization and termination functions; \item The functions
194
of the C library exported by the OS Lib; \item The functions that
195
prints some messages on the console, like for example
196
\texttt{printk} and \texttt{kern\_printf}.
197
\end{itemize}
198
\bf{The other functions of the Generic Kernel and of the OS
199
Lib can not be used}.
200
 
201
For the developers that knows the earlier versions of the Hartik
202
Kernel, the body of the startup function
203
\texttt{\_\_kernel\_register\_levels\_\_} can be thought as the
204
first part of the \texttt{main()} function (until the
205
\texttt{sys\_init()}).
206
 
207
%----------------------------------------------------------------------------
208
\subsection{OS Lib initialization}
209
%----------------------------------------------------------------------------
210
 
211
At this point all the data structures are initialized, so the
212
system can go in multitasking mode calling the OS Lib's
213
\texttt{ll\_init} and \texttt{event\_init} functions.
214
 
215
%----------------------------------------------------------------------------
216
\subsection{Initialization functions call}
217
\label{Kernel_Runlevel_init}
218
%----------------------------------------------------------------------------
219
 
220
At this point the system has only one valid context (the
221
\texttt{global\_context}); there aren't any tasks yet (because
222
nobody could create them before).
223
 
224
To end the initialization part the Generic Kernel calls the
225
initialization functions registered by the Modules registered in
226
the system. Because the OS Lib is initialized, all the function
227
exported by it can be called. Moreover, the primitives
228
\texttt{task\_create} and \texttt{task\_activate} can be called.
229
 
230
The initialization functions can be used by the Scheduling Modules
231
to create a startup task set. Tipically the startup task set is
232
composed by two tasks: the \texttt{dummy} task (usually created by
233
the \texttt{dummy} Scheduling Module
234
%
235
\footnote{This module simply ends the Scheduling Module levels, in
236
a way that there will be always a task to
237
schedule.%
238
}) and the task that has the function \texttt{\_\_init\_\_} as
239
body (that task is usually created by the Round Robin
240
(\texttt{RR}) Scheduling Module). This choice is the tipical
241
situation used in most cases, but is not mandatory. The only thing
242
really important is that there must be a task to schedule after
243
this step.
244
 
245
The function \texttt{\_\_init\_\_} is usually contained into the
246
initialization files, just after the \texttt{\_\_kernel\_register}
247
\texttt{\_levels\_\_} function. That function is the body of the
248
first task that is executed in the system. The actions done by
249
that function are tipically two:
250
 
251
\begin{itemize}
252
\item the initialization of some devices and libraries that use
253
some system primitives (for example, the semaphores) and for this
254
reason they must be initialized into a context of a {}``real''
255
task (and not in the \texttt{global\_context} where the
256
initialization functions are called). Examples of these libraries
257
are for example the communication ports, and the keyboard and
258
mouse drivers (all these libraries uses the semaphores); \item the
259
call to the \texttt{main()} function (in this way the Applications
260
can be writed using the straight C
261
standard)%
262
\footnote{The function \texttt{\_\_call\_main\_\_} described in
263
the file \texttt{include/kernel/func.h} can be
264
used.%
265
}.
266
\end{itemize}
267
For the developers that knows the earlier versions of the Hartik
268
Kernel, the body of the \texttt{\_\_init\_\_} function can be
269
thought as the part of the \texttt{main()} function (from the
270
\texttt{sys\_init} to the \texttt{sys\_end()}).
271
 
272
Per quanti fossero familiari con le versioni precedenti del
273
Kernel, il corpo della funzione \texttt{\_\_init\_\_} corrisponde
274
più o meno alla parte della funzione \texttt{main()} compresa tra
275
la \texttt{sys\_init} (esclusa) e la \texttt{sys\_end} finale
276
(esclusa).
277
 
278
%----------------------------------------------------------------------------
279
\subsection{First context change}
280
%----------------------------------------------------------------------------
281
 
282
Now, the data structures are initialized, and the first tasks are
283
created. At this point the Generic Kernel simply schedule the
284
first task and dispatch it.
285
 
286
When the first task is scheduled the global context is also saved.
287
Because the global context is not a context of a task, the system
288
will never schedule again the global context until all the user
289
task are finished.
290
 
291
The system will change the context to the global context also when
292
the \texttt{sys\_end} or the \texttt{sys\_abort} functions are
293
called to shut down the system. Note that the function
294
\texttt{ll\_abort} does not change the context to the global
295
context, but it simply change to a safe stack and shut down the OS
296
Lib, without shutting down the Generic Kernel correctly.
297
 
298
%----------------------------------------------------------------------------
299
\subsection{The shutdown functions}
300
%----------------------------------------------------------------------------
301
 
302
When the last user task ends, or when the \texttt{sys\_end}, or
303
\texttt{sys\_abort} function are called, the current context
304
changes to the global context.
305
 
306
At this point the system has to do some operations to shut down
307
the system in a correct
308
way%
309
\footnote{For example, if the File System is used maybe there will
310
be some data that have to be written on the
311
disks%
312
}.
313
 
314
The operations that have to be called depends on the registered
315
Modules, so the Generic Kernel allows to set, using the function
316
\texttt{sys\_atrunlevel}, a set of functions to be called at this
317
time.
318
 
319
Usually these functions activates some recovery tasks that will
320
shut down correctly the system. These function should be small,
321
because just after the calls the system will be scheduled again to
322
allow the libraries to shut down using the newly activated
323
threads.
324
 
325
If the shutdown functions are too long and uses a lot of computation time, thete
326
can be some undesirable effects that can put the system in an instable state
327
\footnote{A typical situation is that when the system is rescheduled a task that
328
used a resource miss a deadline; then the Scheduling Module disable its
329
schedulability, and the operation on the device cannot end, and with it all the
330
system!}.
331
 
332
%----------------------------------------------------------------------------
333
\subsection{Termination request for all user tasks}
334
%----------------------------------------------------------------------------
335
 
336
To speed-up the system termination, the system tries to kill all
337
the user tasks. Because the cancellation is usually deferred (as
338
told by the POSIX standard), this should not cause the
339
instantaneous dead of all tasks when the system returns in
340
multitasking mode.
341
 
342
%----------------------------------------------------------------------------
343
\subsection{Second context change}
344
%----------------------------------------------------------------------------
345
 
346
To shut down correctly the system the scheduler must be called
347
again. For the secon time the system exits from the global
348
context. The system usually evolve as follows:
349
 
350
\begin{itemize}
351
\item The user tasks should die (slowly\ldots{}); \item The
352
shutdown function should give some information to the system tasks
353
so they can finish their work and end.
354
\end{itemize}
355
The system will return to the global context when all system tasks
356
will end or the \texttt{sys\_abort} will be called. The
357
\texttt{sys\_end} function does not have any effect in this phase.
358
 
359
%----------------------------------------------------------------------------
360
\subsection{Exit functions called before OS Lib termination}
361
%----------------------------------------------------------------------------
362
 
363
When all the tasks end or the \texttt{sys\_abort} is called the
364
execution returns to the global context. At this point the
365
functions registered through the \texttt{sys\_atrunlevel} function
366
with the parameter \texttt{RUNLEVEL\_BEFORE\_EXIT} are called.
367
 
368
The mission of these functions is to terminate the cleaning of the
369
system (for example, it may be useful to set the display in text
370
mode if the application uses the graphic modes).
371
 
372
%----------------------------------------------------------------------------
373
\subsection{Termination of the OS Lib}
374
%----------------------------------------------------------------------------
375
 
376
At this point the system can end its work. For this reason the
377
function \texttt{ll\_end} is called; this function frees all the
378
data structures allocated with the \texttt{ll\_init}. After this
379
call only the function specified in the Section
380
\ref{Kernel_kernel_register_levels} can be called.
381
 
382
%----------------------------------------------------------------------------
383
\subsection{Exit functions called after OS Lib termination}
384
%----------------------------------------------------------------------------
385
 
386
Finally, the Kernel calls the last functions registered with the
387
\texttt{sys\_atrunlevel}, that tipically prints some nice messages
388
or simply reboot the computer.
389
 
390
%----------------------------------------------------------------------------
391
\section{Task creation and on-line guarantee}
392
\label{Kernel_Garanzia}
393
%----------------------------------------------------------------------------
394
 
395
The Generic Kernel primitive that creates and guarantees a new
396
task is called \texttt{task\_createn}. The prototype of that
397
function is the following (the code of the primitive is contained
398
in the file \texttt{kernel/create.c}):
399
 
400
\bigskip{}
401
\noindent \texttt{PID task\_createn(char {*}name, TASK
402
({*}body)(), TASK\_MODEL {*}m, \ldots{});}
403
\bigskip{}
404
 
405
\noindent The parameter passed with that function are the
406
following:
407
 
408
\begin{description}
409
\item [\texttt{name}]Symbolic name for the task, used for
410
statistical pourposes; \item [\texttt{body}]Pointer to the first
411
instruction of the task; \item [\texttt{m}]Pointer to a Task Model
412
for the new task to be created \item [\texttt{\ldots{}}]List of
413
Resource Model pointers terminated with a \texttt{NULL} pointer.
414
\end{description}
415
The primitive returns the descriptor number associated to the
416
newly created task, or \texttt{NIL} if the task cannot be created
417
in the system. In the latter case the variable \texttt{errno} is
418
set to a value that explain the typology of the
419
error%
420
\footnote{The error codes are listed in the file
421
\texttt{include/bits/errno.h}.%
422
}.
423
 
424
There is also a redefinition of the primitive called
425
\texttt{task\_create} that accept only one Resource Module instead
426
of {}``\ldots{}''. This redefinition may be useful because usually
427
only a few tasks need more than one Resource Model.
428
 
429
The step followed to create and guarantee correctly a new task are
430
described in the following paragraphs.
431
 
432
The first thing to do is to find a unused task descriptor.
433
Tipically the free descriptors are queued in the \texttt{freedesc}
434
queue. During the selection the tasks that are into the freedesc
435
queue but that waits a synchronization with a \texttt{task\_join}
436
primitive are discarded (look at Section \ref{Kernel_Join}).
437
 
438
At this point the descriptor chosen is removed from the freedesc
439
queue and initialized with some default values.
440
 
441
Then, a Scheduling Module that can handle the Task Model passed as
442
parameter have to be found. The research is done starting from
443
level 0 and calling the \texttt{public\_create} function. When a
444
correct Module is found the task is created into that module.
445
 
446
The next step in task creation is the handling of the Resource
447
Models passed. This initialization is done calling the
448
\texttt{res\_register} function on the Resource Modules registered
449
in the system.
450
 
451
At this point all system components are informed of the Quality of
452
Service required by the new task, and the on-line guarantee can
453
start. The guarantee algorithm cannot be called before registering
454
the Resource Models because in general {}``hybrid'' Modules can be
455
developed (for example, a Module can register itself as Scheduling
456
Module and Resource Module, using the two descriptors...).
457
 
458
Finally, if the task can be guaranteed, the stack memory for the
459
task is allocated (only if needed), the task context is created
460
using the OS Lib function \texttt{ll\_context\_create}), the
461
creation event is registered for the tracer and the task is
462
counted into the user or system task counter.
463
 
464
If one of these steps fail, the system will be put in the state
465
preceding the call of the primitive (the functions
466
\texttt{public\_detach} and \texttt{res\_detach} are also called).
467
 
468
Looking at the on-line system guarantee, the generic kernel
469
supports a distributed guarantee on all the Scheduling Modules
470
based on the utilization factor paradigm. The system will call the
471
\texttt{public\_guarantee} function starting from level 0, and
472
passing each time the free bandwidth left by the upper levels.
473
This algorithm is implemented in the \texttt{guarantee()} function
474
stored in the file \texttt{kernel/kern.c}. That function returns
475
-1 if the task set cannot be guaranteed, 0 otherwise.
476
 
477
This approach allows the implementation in a simple way the
478
on-line guarantee of many algorithms. However, this approach is
479
not suitable to implement more complex algorithms, like for
480
example the Deferrable Server guarantee, the TB{*} \cite{But97}
481
guarantee and others. in these cases two strategies can be used:
482
 
483
\begin{itemize}
484
\item All the system tasks are guarantee off-line, so the
485
guarantee procedure can be disabled at run-time. \item All the
486
algorithms that need a guarantee are developed in a single
487
Sheduling Module, placed at level 0. In this way it can control
488
all the system bandwidth, and a guarantee can be done because the
489
Module knows all the data needed. However, in this way all
490
advantages of the Modularity is lost.
491
\end{itemize}
492
 
493
%----------------------------------------------------------------------------
494
\section{Task activation}
495
\label{Kernel_Attivazione}
496
%----------------------------------------------------------------------------
497
 
498
The Generic Kernel, unlike the POSIX standard, decouple the task
499
creation and guarantee and the task activation. This is done
500
because in literature many proofs are given for tasks that are
501
activated at the start of the major cycle. Also, the guarantee
502
function can be heavy and long, unlike the activation that is
503
typically shorter.
504
 
505
The primitives provided by the generic kernel to activate a task
506
are two:
507
 
508
\begin{description}
509
\item [\texttt{task\_activate}]Activation of a single
510
task%
511
\footnote{This primitive can be called also into an OS Lib event
512
and into the global\_context (in other words, in the function
513
posted with the primitive
514
\texttt{sys\_atrunlevel}).%
515
}; \item [\texttt{group\_activate}]Activation of a group of tasks
516
in an atomic
517
way%
518
\footnote{The system is rescheduled only one time, so it can
519
speed-up the activation of a lot of
520
tasks.%
521
}.
522
\end{description}
523
The Generic kernel provides a mechanism that allow to freeze task
524
activations. That mechanism is inserted in the generic kernel to
525
allow the modular implementation of some shared resource protocols
526
like SRP or similar.
527
 
528
This mechanism use the task descripror control field flag
529
\texttt{FREEZE\_ACTIVATION}, that stores the freeze state of the
530
activations, and use the task descripror field
531
\texttt{frozen\_activations}, that stores the number of freed
532
activations for the Generic Kernel.
533
 
534
These primitives are also defined:
535
 
536
\begin{description}
537
\item [\texttt{task\_block\_activation}]blocks explicit task
538
activations and activates its counting. The function usually
539
returns 0, or -1 if the task index is not correct. \item
540
[\texttt{task\_unblock\_activation}]enables explicit task
541
activations. it returns -1 if the task had the
542
\texttt{FREEZE\_ACTIVATION} field disabled, or the number of
543
freezed activations. If there were freezed activations, the
544
primitive does not the activations.
545
\end{description}
546
The prototypes presenyted in this Section are showed in Figura
547
\ref{Kernel_Fig_activate} and they are stored in the files file
548
\texttt{kernel/activate.c} and
549
\texttt{kernel/blkact.c}.%
550
\begin{figure}
551
\begin{center} \fbox{\tt{ \begin{minipage}{6cm} \begin{tabbing}
552
123\=123\=123\=\kill
553
int task\_activate(PID p);\\
554
int group\_activate(WORD g);\\
555
int task\_block\_activation(PID p);\\
556
int task\_unblock\_activation(PID p);\\
557
\end{tabbing} \end{minipage} }} \end{center}
558
\label{Kernel_Fig_activate}
559
\caption{Prototypes of the actiovation
560
functions.}
561
\end{figure}
562
 
563
%----------------------------------------------------------------------------
564
\section{The Scheduler}
565
\label{Kernel_Scheduler}
566
%----------------------------------------------------------------------------
567
 
568
The steps that the Generic Kernel does when the system is
569
rescheduled are three:
570
 
571
\begin{itemize}
572
\item If when the system is rescheduled a task is running, the end
573
of the slice must be called for that
574
task%
575
\footnote{A task slice is the time interval in that starts when
576
the running task is dispatched and end when the system is
577
scheduled
578
again.%
579
}; \item Then, a new task to run must be found (scheduling); \item
580
Finally, the chosen task must be run (dispatching).
581
\end{itemize}
582
These steps are implemented into the system primitives and in the
583
\texttt{scheduler()} function stored in the file
584
\texttt{kernel/kern.c}. In the following section the three points
585
are showed in detail.
586
 
587
%----------------------------------------------------------------------------
588
\subsection{Current slice end for the running task}
589
%----------------------------------------------------------------------------
590
 
591
To specify which are the actions to do at the end of a slice of
592
the running task, the reason af the slice end must be known.
593
Depending on the behaviour of the end of the slice, different
594
actions should be made.
595
 
596
For this reason the Generic Kernel provides different functions
597
that terminates a slice. The cases in that a slice must be ended
598
are the following (into parenthesis the related Task Calls are
599
listed):
600
 
601
\begin{enumerate}
602
\item A new task becomes active in the system, so the Generic
603
Kernel wants to check if a preemption (\texttt{public\_epilogue})
604
must be done. This situation can happen in a lot of situations,
605
like for example:
606
 
607
\begin{itemize}
608
\item a new task is activated with a \texttt{task\_activate} or
609
\texttt{group\_activate} primitive; \item a resource or a mutex is
610
freed, so a task blocked on it is unblocked; \item a periodic task
611
is reactivated at the beginning of its period; \item a System
612
Driver is activated because an intrettupt is arrived;
613
\end{itemize}
614
\item The running task finishes its available capacity
615
(\texttt{public\_epilogue}); \item The running task blocks itself
616
on a synchronization primitive (\texttt{public\_block}); \item The
617
running task ends its instance and it suspend itself with a
618
\texttt{task\_endcycle} primitive (\texttt{public\_message});
619
\item The running task ends or it is killed by a
620
\texttt{task\_kill} or \texttt{pthread\_cancel} primitive
621
(\texttt{public\_end});
622
\end{enumerate}
623
In general the funcions sequence that have to be called is the
624
following:
625
 
626
\begin{enumerate}
627
\item The current time is read into the global variable
628
\texttt{schedule\_time}%
629
\footnote{That variable is used as temporal reference for the
630
scheduling time. Note that the Generic kernel does not separe the
631
CPU time passed executing user code and system code; all the CPU
632
time is assigned to the user
633
task.%
634
}; \item The length of the current terminated slice is computed
635
using the variables \texttt{schedule\_time} and
636
\texttt{cap\_lasttime}; \item The computation time of the current
637
slice is accounted to the task (look at Section \ref{Kernel_Jet});
638
\item The capacity event (if one is pending) is erased; \item The
639
Scheduling Module function that handles the termination of the
640
slice for the task is called..
641
\end{enumerate}
642
To simplify the writing of the primitives the following approach
643
is implemented: because the preemption rescheduling is the most
644
common situation, the sequence given before that terminates with a
645
call to \texttt{public\_epilogue} is included as prologue in the
646
\texttt{scheduler()} function. That prologue is not executed if
647
the variables \texttt{exec} and \texttt{exec\_shadow} have a
648
\texttt{NIL} (\texttt{-1}) value when the function is called.
649
 
650
%----------------------------------------------------------------------------
651
\subsection{Scheduling}
652
%----------------------------------------------------------------------------
653
 
654
When the previous slice is terminated a new task to schedule must
655
be chosen. The generic scheduling algorithm starts from the
656
Scheduling Module at level 0, calling the function
657
\texttt{public\_scheduler}, and going through the levels when a
658
Module does not have any task to schedule. The Generic Kernel
659
assumes that there is always a task to
660
schedule%
661
\footnote{To have always a task to schedule a Scheduling Module
662
called \texttt{dummy} is provided that always guarantees the
663
existence of a task to
664
schedule.%
665
}.
666
 
667
When a task to schedule is found, the function
668
\texttt{public\_eligible} is called to verify if the task chosen
669
by the scheduler is correct. If the task is not correct, the
670
generic scheduling algorithm restarts from the level that gave the
671
wrong task before
672
%
673
% Tool: such section does not exists.
674
%
675
% (look at Section \ref{SchedModules_TaskCalls})
676
.
677
 
678
%----------------------------------------------------------------------------
679
\subsection{Dispatching}
680
%----------------------------------------------------------------------------
681
 
682
To find the task that should be executed really another step has
683
to be done: the shadow chain of the scheduled task must be
684
followed
685
%
686
% Tool: such section does not exists.
687
%
688
% (look at Section \ref{ArchDetail_prot_ris_condiv})
689
. When
690
the tail of that chain is found, the function
691
\texttt{public\_dispatch} is called on that task.
692
 
693
Finally, if the task has the \texttt{CONTROL\_CAP} bit of the task
694
descriptor control field set, a capacity event is posted.
695
 
696
%----------------------------------------------------------------------------
697
\section{Execution Time statistics}
698
\label{Kernel_Jet}
699
%----------------------------------------------------------------------------
700
 
701
The Generic Kernel supports the accounting of the task execution
702
times. This is useful because the behaviour of many algorithm
703
proposed in the literature depends widely on the accuracy with
704
that the task capacities are managed.
705
 
706
To enable the Generic Kernel to account the execution time of a
707
task, the user should use the provided macros for the Task Models
708
(look at Section \ref{Modelli_TASK_MODEL}). These macros modifies
709
the \texttt{JET\_ENABLE} flag into the \texttt{control} field of
710
the task descriptor.
711
 
712
The Generic Kernel can store some data about a task. In
713
particular, the mean and the maximum execution time of a task and
714
the time consumed by the current instance and of the last
715
\texttt{JET\_TABLE\_DIM} instances.
716
 
717
The prototypes of the Generic Kernel functions are described in
718
Figure\ref{Kernel_Fig_Jet}.%
719
\begin{figure}
720
\begin{center} \fbox{\tt{ \begin{minipage}{6cm} \begin{tabbing}
721
123\=123\=123\=\kill
722
int jet\_getstat(PID p, TIME *sum, TIME *max,\\
723
\>\>int *n, TIME *curr);\\
724
 int jet\_delstat(PID p); \\
725
 int jet\_gettable(PID p, TIME *table, int n);\\
726
 void jet\_update\_slice(TIME t);\\
727
 void jet\_update\_endcycle();
728
 \end{tabbing} \end{minipage} }} \end{center}
729
 
730
\label{Kernel_Fig_Jet}
731
\caption{Primitives for execution time handling and correlated functions used
732
internally by the Generic Kernel.}
733
\end{figure}
734
 
735
In the following paragraphs these functions are described:
736
 
737
\begin{description}
738
\item [\texttt{jet\_getstat}]This primitive returns some
739
statistical informations; in particular, the informations are
740
stored into the following parameters:
741
 
742
\begin{description}
743
\item [\texttt{sum}]is the task total execution time since it was
744
created or since the last call to the \texttt{jet\_delstat}
745
function; \item [\texttt{max}]is the maximum time used by a task
746
instance since it was created or since the last call to the
747
\texttt{jet\_delstat} function; \item [\texttt{n}]is the number of
748
terminated instances which sum and max refers to; \item
749
[\texttt{curr}]is the total execution time of the current
750
instance.
751
\end{description}
752
if a parameter is passed as NULL the information is not returned.
753
The function returns 0 if the PID passed is correct, \texttt{-1}
754
if the PID passed does not correspond to a valid PID or the task
755
does not have the \texttt{JET\_ENABLE} bit set.
756
 
757
\item [\texttt{jet\_delstat}]The primitive voids the actual task
758
execution time data mantained by the Generic Kernel. The function
759
returns 0 if the PID passed is correct, \texttt{-1} if the PID
760
passed does not correspond to a valid PID or the task does not
761
have the \texttt{JET\_ENABLE} bit set. \item
762
[\texttt{jet\_gettable}]The primitive returns the last n execution
763
times of the task passed as parameter. If the parameter n is less
764
than 0, it returns only the last values stored since the last call
765
to \texttt{jet\_gettable}. If the value is greater than 0, the
766
function returns the last \texttt{min(n,~JET\_TABLE\_DIM)} values
767
registered. The return value is \texttt{-1} if the task passed as
768
parameter does not exist or the task does not have the
769
\texttt{JET\_ENABLE} bit set, otherwise the number of values
770
stored into the array is returned. The table passed as parameter
771
should store at least \texttt{JET\_TABLE\_DIM} elements.
772
\end{description}
773
The function used into the Generic Kernel implementation are the
774
following:
775
 
776
\begin{description}
777
\item [\texttt{jet\_update\_slice}]updates the current slice of
778
the running task (pointed by the \texttt{exec\_shadow} field) by t
779
microseconds; \item [\texttt{jet\_update\_endcycle}]updates the
780
execution time of the last instance. When this function is called
781
the last instance is just terminated.
782
\end{description}
783
 
784
%----------------------------------------------------------------------------
785
\section{Cancellation}
786
\label{Kernel_Cancellazione}
787
%----------------------------------------------------------------------------
788
 
789
The POSIX standard provides some mechanisms to enable and disable
790
the cancellation, and to set the cancellation as deferred or
791
asynchronous.
792
 
793
For more informations about the cancellation functions look to the
794
POSIX standard.
795
%
796
% Tool: table does not exist.
797
%
798
% In Table \ref{Posix_Tab_Funzioni} there are some
799
% primitives that are very similar to these of the standard.
800
 
801
The biggest problems in implementing task cancellation into the
802
Generic Kernel are the following:
803
 
804
\begin{itemize}
805
\item The kernel does not have a private stack, and works simply
806
disabling the interrupts into the contexts of the tasks in the
807
system; \item The cancellation functions for a tasks should be
808
called into the stack of the task, so it is not possible to kill
809
another task immediately without changing context; \item The
810
Generic Kernel should abstract from the cancellation points
811
present in the system, because in general it is not possible to
812
handle all the internal structures introduced by a particular
813
cancellation point.
814
\end{itemize}
815
The solution to these problems is proposed in the following
816
Sections.
817
 
818
%----------------------------------------------------------------------------
819
\subsection{The task\_makefree function}
820
%----------------------------------------------------------------------------
821
 
822
When a task die the flow control of a task is switched to the
823
\texttt{task\_makefree} function. This function have to call all
824
the cancellation points function, and the key destructors.
825
 
826
The function can be called into the cancellation points (the
827
\texttt{task\_testcancel} function is called, look at the file
828
\texttt{kernel/cancel.c}), and at task termination (look at the
829
\texttt{task\_create\_stub} in the file \texttt{kernel/create.c}),
830
and each time a task is scheduled (to test asynchronous
831
cancellation).
832
 
833
The function does the following steps:
834
 
835
\begin{itemize}
836
\item It checks if someone is waiting for the task termination
837
(with a \texttt{task\_join} primitive); \item It verifies if the
838
task that is terminating is actually using a resource handled with
839
the shadow mechanism (if so an exception is raised); \item It
840
calls some cleanup functions; \item It calls the thread specific
841
data destructors; \item It frees the
842
context%
843
\footnote{Note that the freed context is the running context. this
844
is not a problem because the \texttt{task\_makefree} is executed
845
with the interrupts disabled, and nobody can use the free memory
846
areas
847
freed.%
848
}and the allocated memory for the stack; \item It calls the
849
\texttt{public\_end} on the Scheduling Module that owns the task,
850
and the \texttt{res\_detach} function on the Resource Modules
851
registered in the system; \item It verifies if the end of the task
852
should cause the whole system termination (look at Section
853
\ref{Kernel_TaskUtente}).
854
\end{itemize}
855
 
856
%----------------------------------------------------------------------------
857
\subsection{Cancellation point registration}
858
%----------------------------------------------------------------------------
859
 
860
The last problem to solve is the independence of the Generic
861
Kernel from the Cancellation Points. The objective of the
862
cancellation point registration is to write the code for a
863
cancellation point without modify the primitives that effectively
864
kill a task. The implementations can be depicted with these
865
points:
866
 
867
\begin{itemize}
868
\item The blocking of a task on a cancellation point is
869
implemented through the \texttt{public\_block} function; \item The
870
task state of a blocked task on a cancellation point is modified
871
to a value visible by the Generic Kernel (usually these names
872
starts with the prefix WAIT\_); \item The functions that
873
implements the cancellation points register themselves at their
874
first execution calling the \texttt{register\_cancellation\_point}
875
primitive (this function is defined in the file
876
\texttt{kernel/kill.c}). The primitive accepts a function pointer
877
that returns 1 if the task passed as parameter is blocked on the
878
cancellation point handled by the function. \item First, the
879
function that should kill a task sets the \texttt{KILL\_REQUEST}
880
flag of the control field of the task descriptor; then, it calls
881
the registered cancellation point functions to check if a task is
882
blocked on a cancellation point. If so, the registered function
883
reactivates the blocked task calling the \texttt{public\_unblock}
884
function. \item The architecture of a cancellation point should
885
guarantee that when a task is woken up a check is made to see if a
886
task is killed. If so, the function internally calls the primitive
887
\texttt{task\_testcancel} to kill the task.
888
\end{itemize}
889
 
890
%----------------------------------------------------------------------------
891
\subsection{Cleanups and Thread Specific Data}
892
\label{Kernel_Cleanups}
893
\label{Kernel_pthread_keys}
894
%----------------------------------------------------------------------------
895
 
896
The POSIX standard provides two primitives,
897
\texttt{pthread\_cleanup\_push} and
898
\texttt{pthread\_cleanup\_pop}, that allows to specify functions
899
to be executed in the case a task has been killed during a section
900
of code delimited by these two functions.
901
 
902
The implementation of these two functions has been done through a
903
macro similar to that contained into the rationale of the POSIX
904
standard.
905
 
906
Their implementation is contained into the files
907
\texttt{include/pthread.h} and \texttt{include/kernel/func.h}.
908
 
909
The Generic kernel provides also the support for the Thread
910
Specific Data of the POSIX Standard. The implementation of these
911
primitives is not complex and can be found in the file
912
\texttt{kernel/keys.c}.
913
 
914
%----------------------------------------------------------------------------
915
\section{Signals}
916
\label{Kernel_Segnali}
917
%----------------------------------------------------------------------------
918
 
919
The Generic kernel provides a POSIX signal implementation derived
920
from the Flux OSKit \cite{Bry97}.
921
 
922
Two aspects need to be described:
923
 
924
\begin{itemize}
925
\item the implementation of the signal interruptable functions:
926
 
927
 
928
To implement these function a registration call is provided in a
929
way similar to the cancellation points. Each time a signal is
930
generated, a check is done to see if some task is blocked on a
931
signal interruptable function. The registration function is called
932
\texttt{register\_interruptable\_point} and it is contained into
933
the file \texttt{kernel/signal.c;}
934
 
935
\item the correct delivery of the signals:
936
 
937
 
938
a function called \texttt{kern\_deliver\_pending\_signals}
939
(defined in the file \texttt{kernel/signal.c}) is provided; this
940
function is called into the macro that changes context (the macro
941
\texttt{kern\_context\_load}, defined into the file
942
\texttt{include/kernel/func.h}). That function is usually called
943
after a context change, so when a task is rescheduled the pending
944
signals for that task are delivered. Note that in the current
945
version if a task is preempted by a task activated in an
946
interrupt, when the task is rescheduled there will not be any
947
signal dispatching. This IS a bug, and it will be fixed in the
948
next releases of the OS Lib.
949
 
950
\end{itemize}
951
Moreover, the OS Kit signal implementation is slightly modified to
952
handle the POSIX message queues and the POSIX realtime timers.
953
 
954
%----------------------------------------------------------------------------
955
\section{Task Join}
956
\label{Kernel_Join}
957
%----------------------------------------------------------------------------
958
 
959
The POSIX standard specifies that a thread return value can be
960
read, if the task is \emph{joinable}, through a call to the
961
primitive \texttt{pthread\_join} or \texttt{task\_join}.
962
 
963
In this section the implementation of the primitive
964
\texttt{task\_join} is described, with all the modification that
965
the implementation has done on the Generic Kernel.
966
 
967
First, the information about the task type (joinable or detached)
968
is stored into the flag \texttt{TASK\_JOINABLE} of the
969
\texttt{control} field of the task descriptor.
970
 
971
Usually the POSIX threads starts in a joinable state and then they
972
can be detached. The Generic kernel follow this line when
973
implementing the \texttt{pthread\_create}, but with a difference:
974
the default attribute for the task models is
975
detached%
976
\footnote{Note that this does not impact on the standard POSIX
977
implementation, since the task\_create is a non-standard
978
function.%
979
}.
980
 
981
The \texttt{task\_join} primitive implements the POSIX primitive
982
\texttt{pthread\_join}. It is a cancellation point and it register
983
itself in the Generic kernel the first time it executes.
984
 
985
The main problem in the implementation of this primitive is that a
986
task descriptor correctly terminated can be reused until a join is
987
executed on it. The problem is that in this way the Scheduling
988
Modules should know the internal implementation of the primitive,
989
and this fact may complicate the writing of a Scheduling Module if
990
special task guarantees are implemented.
991
 
992
The implementation tries to avoid these problems in the following
993
way:
994
 
995
\begin{itemize}
996
\item The Scheduling Modules prescind from the task tipology
997
(joinable or detached) and simply inserts a task that terminates
998
in the free queue when the descriptor is no longer needed; \item
999
The \texttt{task\_makefree} checks if the task is joinable, and if
1000
it is the flag \texttt{WAIT\_FOR\_JOIN} in the control field of
1001
the task descriptor is set. In any case the context and the stack
1002
for the dead process are released; \item A call to
1003
\texttt{task\_create} that tries to alloc a task descriptor that
1004
waits for a join and whose descriptor is inserted in the freedesc
1005
queue simply discards it, setting the bit
1006
\texttt{DESCRIPTOR\_DISCARDED}, in the \texttt{control} field of
1007
the task descriptor. \item A call to \texttt{task\_join} on a task
1008
that is already terminated, inserted in the freedesc queue and
1009
discarded by the primitive \texttt{task\_create}, inserts the
1010
descriptor in the \texttt{freedesc} queue.
1011
\end{itemize}
1012
This way allow the Scheduling Modules to abstract and remain
1013
independent from the implementation of the join primitive.
1014
 
1015
%----------------------------------------------------------------------------
1016
\section{Pause and Nanosleep}
1017
\label{Kernel_nanosleep}
1018
%----------------------------------------------------------------------------
1019
 
1020
The Generic Kernel supports a set of primitives to implement a
1021
task suspension. The differences between them are the following:
1022
 
1023
\begin{description}
1024
\item [\texttt{sleep}]This primitive suspend the execution task
1025
for a number of seconds. The task can be woken up by a signal
1026
delivery; \item [\texttt{pause}]This function suspends the task
1027
until a signal is delivered to it; \item [\texttt{nanosleep}]This
1028
function suspends the running task for a minimum time passed as
1029
parameter. The task can be woken up by the dispatch of a signal,
1030
in that case the residual time is returned.
1031
\end{description}
1032
 
1033
%----------------------------------------------------------------------------
1034
\section{Mutex and condition variables}
1035
%----------------------------------------------------------------------------
1036
 
1037
The Generic kernel provides a set of functions that are similar in
1038
the interface with the correspondents POSIX functions that handles
1039
mutexes and condition variables.
1040
 
1041
The extensions to the interface of the Resource Modules described
1042
in the previous chapter are used by these primitives to handle
1043
different shared resource access protocols in a general way.
1044
 
1045
Le estensioni apportate all'interfaccia dei Moduli di Gestione
1046
delle Risorse descritte nella sezione precedente vengono
1047
utilizzate da tali primitive per gestire i vari protocolli di
1048
accesso a risorse condivise in modo trasparente.
1049
 
1050
In particular, the proposed interfaces are the following (for a
1051
better description look at the POSIX standard):
1052
 
1053
%----------------------------------------------------------------------------
1054
\subsubsection{\texttt{int mutex\_init(mutex\_t {*}mutex, const mutexattr\_t {*}attr);}}
1055
%----------------------------------------------------------------------------
1056
 
1057
This primitive can be used to init a task descriptor. The attr
1058
parameter should be correctly initialized before the call. It can
1059
not be NULL.
1060
 
1061
%----------------------------------------------------------------------------
1062
\subsubsection{\texttt{int mutex\_destroy(mutex\_t {*}mutex);}}
1063
%----------------------------------------------------------------------------
1064
 
1065
This function dealloc a mutex.
1066
 
1067
%----------------------------------------------------------------------------
1068
\subsubsection{\texttt{int mutex\_lock(mutex\_t {*}mutex);}}
1069
%----------------------------------------------------------------------------
1070
 
1071
This function implements a blocking wait.
1072
 
1073
%----------------------------------------------------------------------------
1074
\subsubsection{\texttt{int mutex\_trylock(mutex\_t {*}mutex);}}
1075
%----------------------------------------------------------------------------
1076
 
1077
This function implements a non blocking wait.
1078
 
1079
%----------------------------------------------------------------------------
1080
\subsubsection{\texttt{int mutex\_unlock(mutex\_t {*}mutex);}}
1081
%----------------------------------------------------------------------------
1082
 
1083
This functions unlocks a mutex.
1084
 
1085
%----------------------------------------------------------------------------
1086
\subsubsection{\texttt{int cond\_init(cond\_t {*}cond);}}
1087
%----------------------------------------------------------------------------
1088
 
1089
This function initializes a condition variable.
1090
 
1091
%----------------------------------------------------------------------------
1092
\subsubsection{\texttt{int cond\_destroy(cond\_t {*}cond);}}
1093
%----------------------------------------------------------------------------
1094
 
1095
This function destroys a condition variable.
1096
 
1097
%----------------------------------------------------------------------------
1098
\subsubsection{\texttt{int cond\_signal(cond\_t {*}cond);}}
1099
%----------------------------------------------------------------------------
1100
 
1101
This function signals on a condition variable. Only one task is
1102
unblocked.
1103
 
1104
%----------------------------------------------------------------------------
1105
\subsubsection{\texttt{int cond\_broadcast(cond\_t {*}cond);}}
1106
%----------------------------------------------------------------------------
1107
 
1108
This function signals on a condition variables, unblocking all the
1109
task blocked on the condition variable.
1110
 
1111
%----------------------------------------------------------------------------
1112
\subsubsection{\texttt{int cond\_wait(cond\_t {*}cond, mutex\_t {*}mutex);}}
1113
%----------------------------------------------------------------------------
1114
 
1115
%----------------------------------------------------------------------------
1116
\subsubsection{\texttt{int cond\_timedwait(cond\_t {*}cond, mutex\_t {*}mutex, }}
1117
%----------------------------------------------------------------------------
1118
 
1119
%----------------------------------------------------------------------------
1120
\subsubsection{\texttt{const struct timespec {*}abstime);}}
1121
%----------------------------------------------------------------------------
1122
 
1123
The task that exec this primitive blocks and the mutex passed as
1124
parameter is unlocked to be required when the task restarts. There
1125
are two versions of the primitive, and one has a timeout to limit
1126
blocking times. These functions are cancellation points. If a
1127
cancellation request is generated for a task blocked on a
1128
condition variable, the task will end after reaquiring the mutex.
1129
This implies that each call have to be protected by cleanup
1130
functions that should free the mutex in a correct way.
1131
 
1132
%----------------------------------------------------------------------------
1133
\section{Other primitives}
1134
\label{Kernel_Altreprimitive}
1135
%----------------------------------------------------------------------------
1136
 
1137
In this section a set of other primitives are shortly described.
1138
They are implemented in the source files contained into the kernel
1139
directory.
1140
 
1141
%----------------------------------------------------------------------------
1142
\subsubsection{\texttt{void task\_endcycle(void);}}
1143
%----------------------------------------------------------------------------
1144
 
1145
This primitive terminates the current instance of a task (look at
1146
Section \ref{SchedModules_Lifecycle}).
1147
 
1148
%----------------------------------------------------------------------------
1149
\subsubsection{\texttt{void task\_abort(void);}}
1150
%----------------------------------------------------------------------------
1151
 
1152
This primitive ends the task.
1153
 
1154
%----------------------------------------------------------------------------
1155
\subsubsection{\texttt{void group\_kill(WORD g);}}
1156
%----------------------------------------------------------------------------
1157
 
1158
This primitive send a kill request to all the tasks that have the
1159
group g.
1160
 
1161
%----------------------------------------------------------------------------
1162
\subsubsection{\texttt{TIME sys\_time(struct timespec {*}t);}}
1163
%----------------------------------------------------------------------------
1164
 
1165
This primitive can be used into the applications to read the
1166
system time. Its behaviour is equal to the \texttt{ll\_gettime}
1167
but it is executed with interrupt disabled.