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. |