Rev 1676 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1676 | tullio | 1 | %---------------------------------------------------------------------------- |
2 | \chapter{Kernel Internals} |
||
3 | %---------------------------------------------------------------------------- |
||
4 | |||
5 | Since the Generic Kernel does not implement any memory protection, |
||
6 | all the Modules have access to the internal data structures used |
||
7 | for scheduling. Although the Modules could modify these data |
||
8 | structures, typically they do not need to do so. |
||
9 | |||
10 | %---------------------------------------------------------------------------- |
||
11 | \section{Kernel types} |
||
12 | %---------------------------------------------------------------------------- |
||
13 | |||
14 | The Generic Kernel defines a set of primitive data types, that are |
||
15 | briefly described below: |
||
16 | |||
17 | \begin{description} |
||
18 | \item [PID]This type is used to contain a task index. It is an |
||
19 | integer pointing to an entry of the task descriptor table. This |
||
20 | type can have values in the range {[}0...MAXPROC-1{]}, plus an |
||
21 | invalid value, NIL (that is, -1). |
||
22 | |||
23 | \item [IQUEUE]This type is used to implement the task queues typically used in |
||
24 | scheduling operations. For more information see Section \ref{KernSupport_Code}. |
||
25 | |||
26 | \item [TASK]This type is simply a |
||
27 | redefinition of the \texttt{void {*}} type and it can be used for |
||
28 | readiness ad the returned value in the task function declaration. |
||
29 | |||
30 | \item [LEVEL,~RLEVEL]They are used to index the Module descriptor |
||
31 | Tables. They are integers and they point to a particular entry. |
||
32 | The values of these types are |
||
33 | {[}0...\texttt{MAX\_SCHED\_LEVEL-1}{]} for the \texttt{LEVEL} type |
||
34 | and {[}0...\texttt{MAX\_RES\_LEVEL}{]} for the \texttt{RLEVEL} |
||
35 | type. |
||
36 | |||
37 | \item [bandwidth\_t]This type is used to store a real number |
||
38 | in the range {[}0,1{]}. It is a 32 bit unsigned integer and its |
||
39 | value is interpreted as $\frac{x}{MAX\_ BANDWIDTH}$. |
||
40 | |||
41 | \item |
||
42 | [task\_key\_t]This is an integer type and it is used as an index |
||
43 | for task specific data (similar to POSIX's Thread Specific Data). |
||
44 | \end{description} |
||
45 | |||
46 | %---------------------------------------------------------------------------- |
||
47 | \section{Descriptors} |
||
48 | %---------------------------------------------------------------------------- |
||
49 | |||
50 | In this section we present all the descriptors defined in the |
||
51 | Generic Kernel. If not specified, these data structures are |
||
52 | defined in the \texttt{include/kernel/descr.h} file and they are |
||
53 | used (usually as arrays) in the \texttt{kernel/kern.c} file. |
||
54 | |||
55 | %---------------------------------------------------------------------------- |
||
56 | \subsection{Task Descriptor} |
||
57 | \label{KernSupport_Task_descriptor} |
||
58 | %---------------------------------------------------------------------------- |
||
59 | |||
60 | The \texttt{proc\_des} structures used to define task control blocks |
||
61 | \footnote{The name of this structure is derived from the previous versions of |
||
62 | Hartik. However, it is a \textit{task} descriptor and not a \textit{process} |
||
63 | descriptor.}. In the following paragraphs the fields of the task descriptor are |
||
64 | described \footnote{The following fields have been removed from the structure in |
||
65 | the last releases: request\_time, priority, timespec\_priority, prev, next.}. |
||
66 | |||
67 | \begin{description} |
||
68 | \item [DWORD~task\_ID]Progressive number assigned to a task at its |
||
69 | creation. |
||
70 | |||
71 | \item [LEVEL~task\_level]This field points to the Module |
||
72 | that owns the task. The Generic kernel uses this field to redirect |
||
73 | the calls to the Module owning the task. |
||
74 | |||
75 | \item |
||
76 | [CONTEXT~context]This field contains an index in the OS Lib |
||
77 | context array that handles the context of a task. |
||
78 | |||
79 | \item |
||
80 | [BYTE~{*}stack]This field is a pointer to the memory used as a |
||
81 | task stack. |
||
82 | |||
83 | \item [TASK~(*body)()]This field is the pointer to |
||
84 | the first instruction of a task body, and it is used at |
||
85 | initialization time. |
||
86 | |||
87 | \item [char~name[MAX\_TASKNAME]]This is a |
||
88 | symbolic name, whose length is defined by the |
||
89 | \texttt{MAX\_TASKNAME} constant. |
||
90 | |||
91 | \item [WORD~status]This is the |
||
92 | task status. |
||
93 | |||
94 | \item [WORD~pclass]This field is the Class code of |
||
95 | the Task Model used during task creation. It can be used by |
||
96 | Modules to know the typology of the task (useful if the task |
||
97 | supports many types of Models; see |
||
98 | % |
||
99 | % Tool: such section does not exists. |
||
100 | % |
||
101 | %Section |
||
102 | %\ref{SchedModules_LevelCalls}, |
||
103 | \texttt{level\_accept\_task\_model} |
||
104 | %function) |
||
105 | . |
||
106 | |||
107 | \item [WORD~group]This is the task group. The value 0 |
||
108 | is used to index a single task. This field is not used as a GID in |
||
109 | classical Unix systems but is used to kill or activate a group of |
||
110 | tasks in an atomic way. |
||
111 | |||
112 | \item [WORD~stacksize]Stack dimension (in |
||
113 | bytes). |
||
114 | |||
115 | \item [DWORD~control]Task Status flags. A description of |
||
116 | the bits in this field is reported in |
||
117 | Section\ref{Modelli_TASK_MODEL}. |
||
118 | |||
119 | \item |
||
120 | [int~frozen\_activations]Number of frozen activations. Useful only |
||
121 | if the \texttt{FREEZE\_ACTIVATION} flag of the \texttt{control} |
||
122 | field is active (see Section \ref{Kernel_Attivazione}). |
||
123 | |||
124 | \item |
||
125 | [int~sigmask]This is the blocked signal task mask (see |
||
126 | \texttt{kernel/signal.c} and also \cite{POSIX1003.1}). |
||
127 | |||
128 | \item |
||
129 | [int~sigpending]This is the pending signal task mask (see |
||
130 | \texttt{kernel/signal.c} and also \cite{POSIX1003.1}). |
||
131 | |||
132 | \item |
||
133 | [int~sigwaiting]This is the mask of the signals on which a task is |
||
134 | waiting, blocked on a \texttt{sigwait} primitive (or similar). |
||
135 | |||
136 | \item [int~avail\_time]This field contains the remaining |
||
137 | computation time of a task (see Section |
||
138 | \ref{KernSupport_Capacita}). |
||
139 | |||
140 | \item [PID~shadow]This is the shadow |
||
141 | pointer (see Section \ref{oview_Shadows}). |
||
142 | |||
143 | \item |
||
144 | [struct~\_task\_handler\_rec~{*}cleanup\_stack]Pointer to the |
||
145 | first element of the cleanup stack. |
||
146 | |||
147 | \item [int~errnumber]This is |
||
148 | an error number local to the running task. The symbol |
||
149 | \texttt{errno} defined into the C standard is implemented as a |
||
150 | macro that refers to this field of the running task. |
||
151 | |||
152 | \item |
||
153 | [TIME~jet\_table{[}JET\_TABLE\_DIM{]}]This table contains the |
||
154 | computation times consumed by the last JET\_TABLE\_DIM instances |
||
155 | of the task. The table is handled as a circular buffer. |
||
156 | |||
157 | \item |
||
158 | [int~jet\_tvalid]This is the number of valid items in the |
||
159 | \texttt{jet\_table} table. |
||
160 | |||
161 | \item [int~jet\_curr]This is the |
||
162 | current element in the \texttt{jet\_table} table. |
||
163 | |||
164 | \item |
||
165 | [TIME~jet\_max]This field contains the maximum time (in |
||
166 | microseconds) consumed by a task, among all its instances. |
||
167 | |||
168 | \item |
||
169 | [TIME~jet\_sum]This field accumulates the execution times (in |
||
170 | microseconds) of all task instances from the start of the task (or |
||
171 | from the last call to \texttt{jet\_delstat}). This field, together |
||
172 | with the \texttt{jet\_n} field, is used to compute the mean |
||
173 | execution time of a task instance. |
||
174 | |||
175 | \item [TIME~jet\_n]This field contains the number of instances involved in the |
||
176 | computation of \texttt{jet\_sum}. |
||
177 | |||
178 | \item [PID~waiting\_for\_me]This field contains |
||
179 | the identifier of the task which is currently blocked for a |
||
180 | \texttt{task\_join} on the current task. The field value is NIL if |
||
181 | no task is blocked for a join on it. |
||
182 | |||
183 | \item |
||
184 | [void~{*}return\_value]This is the value returned by a task when |
||
185 | it dies. This value is memorized if the task is joinable, waiting |
||
186 | for someone to synchronize on it with a join. |
||
187 | |||
188 | \item |
||
189 | [void~{*}keys{[}PTHREAD\_KEYS\_MAX{]}]This array contains the task |
||
190 | specific data. |
||
191 | |||
192 | \item |
||
193 | [struct~condition\_struct~{*}cond\_waiting]This field is NULL or |
||
194 | it points to the condition variable on which the task is |
||
195 | blocked \footnote{This field is present because if a task is killed during |
||
196 | a block on a condition wait, the POSIX standard requires that the |
||
197 | task reacquires the mutex linked to that condition before it |
||
198 | dies.}. |
||
199 | |||
200 | \item [int~delay\_timer]This field is used in the |
||
201 | implementation of the blocking primitives with timeout. Usually |
||
202 | this field contains the OS Lib index of the event created for the |
||
203 | wake-up. |
||
204 | |||
205 | \item [int~wcet]This field can be used by Modules to |
||
206 | store some temporal information. It is generally used in |
||
207 | conjunction with the \texttt{avail\_time} field. |
||
208 | \end{description} |
||
209 | |||
210 | %---------------------------------------------------------------------------- |
||
211 | \subsection{Level descriptor} |
||
212 | \label{KernSupport_Level_Descriptor} |
||
213 | %---------------------------------------------------------------------------- |
||
214 | |||
215 | In this Section we describe the fields contained in the |
||
216 | \texttt{level\_des} structure, that implements the Scheduling |
||
217 | Module Descriptor. These Modules will fill the proposed interface, |
||
218 | defining also all the interface functions. If a Module does not |
||
219 | implement an interface function, it redefines that function in a |
||
220 | way that it will raise an exception if called. The fields defined |
||
221 | for the \texttt{level\_des} structure are the following: |
||
222 | |||
223 | \begin{description} |
||
224 | \item [Private~Functions,~Public~Functions]The rest of the interface is made of |
||
225 | a set of function pointers that implements the \emph{virtual} functions of the |
||
226 | Scheduling Modules. That functions are described in the Chapter |
||
227 | \ref{CapSchedulingModules}. All that functions have as first parameter a LEVEL |
||
228 | field that can be used to find the Module Descriptor and then the private |
||
229 | structures of that Modules \footnote{The behaviour of the LEVEL parameter passed |
||
230 | to that function is the same of the hidden paramether \emph{this} of many Object |
||
231 | Oriented languages.}. |
||
232 | \end{description} |
||
233 | |||
234 | %---------------------------------------------------------------------------- |
||
235 | \subsection{Resource module descriptor} |
||
236 | \label{KernSupport_Descrittore_GestioneRisorse} |
||
237 | %---------------------------------------------------------------------------- |
||
238 | |||
239 | In this Section we describe the fields contained in the |
||
240 | \texttt{resource\_des} structure, which implements the Resource |
||
241 | Module Descriptor. These Modules will fill the proposed interface, |
||
242 | defining all the required functions. If a Module does not |
||
243 | implement an interface function, it redefines that function in a |
||
244 | way that it will raise an exception if it is called. The fields |
||
245 | defined for the \texttt{resource\_des} structure are the |
||
246 | following: |
||
247 | |||
248 | \begin{description} |
||
249 | \item [char~res\_name{[}MAX\_MODULENAME{]}]This filed contains a |
||
250 | symbolic Name of the Module, for statistical purposes. The file |
||
251 | \texttt{include/modules/codes.h} contains the name of the Modules |
||
252 | distributed with the Kernel. \item [WORD~res\_code]This field |
||
253 | contains a numeric identifier that identifies a Module in an |
||
254 | unique way. The codes of the Modules distributed with the kernel |
||
255 | are written in the file \texttt{include/modules/codes.h}. \item |
||
256 | [BYTE~res\_version]This is a version number for the Module. The |
||
257 | version numbers of the Modules distributed with the Kernel are |
||
258 | reported in the file \texttt{include/modules/codes.h}. \item |
||
259 | [int~rtype]This field is used to identify the extended interface |
||
260 | implemented by a Resource Module. This field is necessary to |
||
261 | implement some primitives that use a particular extended |
||
262 | interface, that need to know which of the resource modules |
||
263 | registered in the kernel have a particular extension. \item |
||
264 | [Resource~Calls]The rest of the interface is made of a set of |
||
265 | function pointers that implement the \emph{virtual} functions of |
||
266 | the Resource Modules. These functions are described in Chapter |
||
267 | \ref{CapModuliRisorsa}. All these functions have as first |
||
268 | parameter a RLEVEL field that can be used as the similar parameter |
||
269 | of the Scheduling Module virtual functions. |
||
270 | \end{description} |
||
271 | |||
272 | %---------------------------------------------------------------------------- |
||
273 | \section{System states} |
||
274 | %---------------------------------------------------------------------------- |
||
275 | |||
276 | As mentioned in Section \ref{oview_Status} the concept of task |
||
277 | state has a local meaning, and it is stored in the \texttt{status} |
||
278 | field of its task descriptor. |
||
279 | |||
280 | The values that the status field can have are divided in four |
||
281 | intervals, described in Table \ref{KernSupport_Tab_StatusCodes}. |
||
282 | |||
283 | \begin{table} |
||
284 | \begin{center} |
||
285 | \begin{tabular}{|p{4cm}|p{9cm}|} |
||
286 | \hline |
||
287 | Interval reserved to & Codes\\ \hline \hline |
||
288 | |||
289 | Generic Kernel & {[}0...\texttt{MODULE\_STATUS\_BASE}-1{]} \\ \hline |
||
290 | Scheduling Algorithm \foreignlanguage{english}{} & {[}\texttt{MODULE\_STATUS\_BASE} |
||
291 | ...\texttt{APER\_STATUS\_BASE}-1{]}\\ \hline |
||
292 | |||
293 | Aperiodic Servers \foreignlanguage{english}{} & {[}\texttt{APER\_STATUS\_BASE} |
||
294 | ...\texttt{LIB\_STATUS\_BASE}-1{]}\\ \hline |
||
295 | |||
296 | Others (Resource Handling, libraries, etc.) \foreignlanguage{english}{} & |
||
297 | \texttt{>= LIB\_STATUS\_BASE}\\ \hline |
||
298 | \end{tabular} |
||
299 | \end{center} |
||
300 | \caption{Partitioning of the codes for the status field of the task descriptor.} |
||
301 | \label{KernSupport_Tab_StatusCodes} |
||
302 | \end{table} |
||
303 | |||
304 | Each Module Should use the codes in the correct range of values. |
||
305 | |||
306 | This approach allows to handle many Module configurations. The |
||
307 | fact that two Scheduling Modules use the same status code for |
||
308 | different meanings is not a problem, because the codes are used |
||
309 | internally to the Modules. |
||
310 | |||
311 | %---------------------------------------------------------------------------- |
||
312 | \section{Kernel Global Variables} |
||
313 | \label{KernSupport_Variabili} |
||
314 | %---------------------------------------------------------------------------- |
||
315 | |||
316 | The following global variables are defined in the Generic Kernel |
||
317 | and can be used by the Modules. |
||
318 | |||
319 | \begin{description} |
||
320 | |||
321 | \item [proc\_des~proc\_table{[}{]}]This variable is the task descriptor array. |
||
322 | Not all the entries of this array are used. The descriptor really allocated are |
||
323 | handled by the \texttt{task\_create} primitive. |
||
324 | |||
325 | \item [level\_des~{*}level\_table{[}{]}]This variable is the array that |
||
326 | memorizes a set of \emph{pointers} to the Scheduling Modules |
||
327 | Descriptors. When a Module registers itself into the Kernel, an |
||
328 | entry of this array is allocated, and it points to an |
||
329 | \emph{extension} of the \texttt{level\_des} descriptor type. In an |
||
330 | object oriented interpretation it can be thought as a polymorphic |
||
331 | Module array (see Section \ref{Modelli_MetodologiaOOP}). |
||
332 | |||
333 | \item [resource\_des~{*}resource\_table{[}{]}]This variable memorizes an |
||
334 | array of pointers to extension of the resource\_des structure. For |
||
335 | this variable the same comments for the level\_table apply. |
||
336 | |||
337 | \item [PID~exec]This variable contains the task returned by the |
||
338 | Scheduling Module scheduling operation. Typically this variable is |
||
339 | used only into the \texttt{scheduler()} function of the Generic |
||
340 | Kernel. This variable cannot be modified, it can only be read and |
||
341 | checked with the field \texttt{exec\_shadow}. This variable has |
||
342 | the value \texttt{NIL} (-1) when a primitive blocks the running |
||
343 | task, and the scheduler is not yet called. This variable |
||
344 | \emph{does not} point to the running task. Use |
||
345 | \texttt{exec\_shadow} instead! |
||
346 | |||
347 | \item [PID~exec\_shadow]This variable points to the running task. It can be |
||
348 | different from the value contained into \texttt{exec} because of the Shadow |
||
349 | mechanism (see Section \ref{oview_Shadows}). This variable cannot be modified, |
||
350 | it can only be read and check with the field \texttt{exec}. This variable has |
||
351 | the value \texttt{NIL} (-1) when a primitive blocks the running task, and the |
||
352 | scheduler is not yet called. When a reference to the running task is needed, |
||
353 | this variable has to be used. |
||
354 | |||
355 | \item [int~cap\_timer]This variable is different from -1 only if the Generic |
||
356 | Kernel or a Module created a capacity event. This variable can be used by the |
||
357 | Scheduling Modules that do not utilize the \texttt{CONTROL\_CAP flag} for their |
||
358 | tasks (see Section \ref{KernSupport_Capacita}). |
||
359 | |||
360 | \item [struct~timespec~schedule\_time]This variable contains the system time in |
||
361 | which the scheduler was called the last time. The first thing the Kernel |
||
362 | function \texttt{scheduler()} does is the setting of that variable. This |
||
363 | variable is also used as finish time for an execution time interval. |
||
364 | |||
365 | \item [struct~timespec~cap\_lasttime]This variable is a copy of the |
||
366 | \texttt{schedule\_time} variable, done at each call of the \texttt{scheduler()} |
||
367 | function. The value of that variable is used as the start time of the last |
||
368 | interval executed by a task. It is used to implement the time accounting. |
||
369 | |||
370 | \item [DWORD~res\_levels]This variable is the number of resource |
||
371 | module level descriptors allocated. It is modified only by the |
||
372 | \texttt{resource\_alloc\_descriptor} function |
||
373 | % |
||
374 | % Tool: such section does not exists. |
||
375 | % |
||
376 | % (see Section \ref{SchedModules_RegFunctions}) |
||
377 | . |
||
378 | |||
379 | \item [int~task\_counter]This variable is a variable that counts the number of |
||
380 | User tasks actually present into the system (see Section |
||
381 | \ref{Kernel_Inizializzazione}). |
||
382 | |||
383 | \item [int~system\_counter]This |
||
384 | variable is a variable that counts the number of System tasks |
||
385 | actually present into the system (see Section |
||
386 | \ref{Kernel_Inizializzazione}). |
||
387 | |||
388 | % |
||
389 | % Tool: no more sys_end nor sys_abort. Check this in the code! |
||
390 | % |
||
391 | % \item [int~mustexit]This variable |
||
392 | % is used by the system primitives \texttt{sys\_end} and |
||
393 | % \texttt{sys\_abort} to block the context changes into the event |
||
394 | % handlers. |
||
395 | |||
396 | \item [int~calling\_runlevel\_func]This variable is a |
||
397 | flag. It is set to 1 when the system executes some system |
||
398 | functions (registered through the \texttt{sys\_atrunlevel()} |
||
399 | function). This flag influence the \texttt{task\_activate} |
||
400 | primitive, because that primitive has to do different stuffs |
||
401 | depending on the value of that variable (see the code of the |
||
402 | primitive in the file \texttt{kernel/activate.c}). |
||
403 | |||
404 | \item |
||
405 | [IQUEUE~freedesc]This variable is the free task descriptor queue. |
||
406 | It is handled by the Kernel and must be used by a Scheduling |
||
407 | Module into the call \texttt{task\_end} call to free a task |
||
408 | descriptor of a task terminated correctly. |
||
409 | |||
410 | \item |
||
411 | [TIME~sys\_tick]If the OS Lib is initialized with the \textit{one |
||
412 | shot timer} the variable contains the system tick (in |
||
413 | microseconds). Otherwise, the one-shot timer is used, and this |
||
414 | variable has a value of \texttt{0}. |
||
415 | \end{description} |
||
416 | |||
417 | %---------------------------------------------------------------------------- |
||
418 | \section{Temporal protection} |
||
419 | \label{KernSupport_Capacita} |
||
420 | %---------------------------------------------------------------------------- |
||
421 | |||
422 | The Generic Kernel supports task temporal protection through a set |
||
423 | of procedures and data structures that may be used by the |
||
424 | Scheduling Modules. The generic Kernel does force to use its own |
||
425 | functions, so a Module can define itself a policy to ensure |
||
426 | temporal protection. In this Section the proposed functions to |
||
427 | implement the temporal protection are described. |
||
428 | |||
429 | The Generic Kernel handles the time capacity of the tasks in the |
||
430 | system using the creation and the deletion of a specific OS Lib |
||
431 | event that simply reschedules the system. The end of the capacity |
||
432 | is seen by the Modules as a normal epilogue done in the case of a |
||
433 | preemption. |
||
434 | |||
435 | The timer event is created when a task is dispatched, and it is |
||
436 | deleted by all the primitives that may cause preemption. In an |
||
437 | instant there is at least one capacity event pending, that is the |
||
438 | event of the running task. |
||
439 | |||
440 | The Generic Kernel defines for each task the bit |
||
441 | \texttt{CONTROL\_CAP} that is memorized into the field |
||
442 | \texttt{control} of the task descriptor. That bit is set by the |
||
443 | Scheduling Modules to require for a task the creation of the |
||
444 | capacity event at dispatch time. |
||
445 | |||
446 | The Scheduling Modules have also to check the capacity exhaustion |
||
447 | each time a task is descheduled. |
||
448 | |||
449 | Capacities are handled using the following variables provided by |
||
450 | the Kernel: |
||
451 | |||
452 | \begin{itemize} |
||
453 | |||
454 | \item The \texttt{wcet} field of the task descriptor usually memorizes a |
||
455 | characteristic time for a task (i.e., it is used to store a worst-case execution |
||
456 | time or a mean execution time). It is included in the task descriptor to avoid |
||
457 | the allocation of such an information for all the modules. It is \emph{not} used |
||
458 | by the Generic Kernel. |
||
459 | |||
460 | \item The \texttt{avail\_time} field of the task descriptor is used to handle |
||
461 | the available execution time for a task. The capacity event generated by the |
||
462 | Generic Kernel at dispatch time has an activation time that is equal to |
||
463 | \texttt{schedule\_time + avail\_time}. The field is updated by the generic |
||
464 | kernel each time a task is descheduled, decrementing the slice just executed by |
||
465 | the task. |
||
466 | |||
467 | \item The \texttt{cap\_timer} field is used by the Generic Kernel to know |
||
468 | whether a capacity event is or not pending. If the field is equal to -1, there |
||
469 | are no events, otherwise the value is the index of the capacity event. If the |
||
470 | field is not equal to -1 the Generic kernel will delete automatically the event |
||
471 | each time the system is rescheduled. The Generic Kernel does not check who has |
||
472 | created the event pointed by \texttt{cap\_timer}, so a Scheduling Module that |
||
473 | not use the flag \texttt{CONTROL\_CAP} can create a capacity event and put his |
||
474 | index into \texttt{cap\_timer}, avoiding the removal of the event directly in |
||
475 | the code of the Module. |
||
476 | |||
477 | \item The \texttt{cap\_lasttime} field contains the time of the previous |
||
478 | reschedule of the system. The accounting of the computation times is done from |
||
479 | the difference between \texttt{schedule\_time} and \texttt{cap\_lasttime}. The |
||
480 | time used by the Kernel primitives is accounted in the running task. |
||
481 | |||
482 | \end{itemize} |
||
483 | |||
484 | The functions called by the capacity event have only to reschedule |
||
485 | the system. The Scheduling Modules that have to generate |
||
486 | themselves the capacity event can store their events in the |
||
487 | \texttt{cap\_timer} filed if they want an event to be removed at |
||
488 | each preemption. The events can call the Generic Kernel Function |
||
489 | called \texttt{capacity\_timer} (it does not accept any |
||
490 | parameter). |
||
491 | |||
492 | %---------------------------------------------------------------------------- |
||
493 | \subsection{Negative capacities} |
||
494 | %---------------------------------------------------------------------------- |
||
495 | |||
496 | The contents of the \texttt{avail\_time} field can be negative. |
||
497 | This fact, theoretically impossible, can happen for two reasons: |
||
498 | |||
499 | \begin{itemize} |
||
500 | \item first, the OS LIb event handler can not guarantee the |
||
501 | delivery of a capacity event at exact time (a small delay of some |
||
502 | microseconds may occur). So, a capacity event may be delivered |
||
503 | after the capacity is exhausted, so that the task capacity becomes |
||
504 | negative. We can suppose that negatives values are smaller than |
||
505 | the usual time for the tasks; \item second, because the shadow |
||
506 | mechanism can execute a task that has finished his budget; that |
||
507 | task will not be descheduled until the shadow of the higher |
||
508 | priority task points to it. This behavior is correct because we |
||
509 | want that the blocking task will ends its critical section to |
||
510 | limit the blocking time of the higher priority tasks. This |
||
511 | approach is supported by some theoretical results (see |
||
512 | \cite{Gha95}). |
||
513 | \end{itemize} |
||
514 | |||
515 | Scheduling modules can use two strategies to cope with the problem |
||
516 | given by negative capacities. |
||
517 | |||
518 | The first solution is to recharges the capacity with an amount |
||
519 | equal to $Q_{s}$; if the capacity is still negative, the task will |
||
520 | {}``loose a turn''. This solution is good for algorithms that |
||
521 | provide a periodic replenishment (like for example Round Robin, |
||
522 | Polling Server or Deferrable Server) but not for algorithms like |
||
523 | Sporadic Server or Constant Bandwidth Server, where the |
||
524 | replenishment is due to the capacity usage (in these algorithms |
||
525 | the server would not become active). |
||
526 | |||
527 | The second solution is to replenish the budget up to $Q_{s}$; this |
||
528 | solution is good for all types of algorithms, but we have to |
||
529 | consider that the server utilization factor becomes |
||
530 | $\frac{Q_{s}+\Delta}{T_{s}}$. |
||
531 | |||
532 | %---------------------------------------------------------------------------- |
||
533 | \section{Utility functions} |
||
534 | %---------------------------------------------------------------------------- |
||
535 | |||
536 | This section contains a set of utility functions that can be used |
||
537 | to simplify the writing of the Modules. Often these functions are |
||
538 | simple redefinitions of the OS Lib functions. Use these functions |
||
539 | instead of those provided by the OS Lib. |
||
540 | |||
541 | %---------------------------------------------------------------------------- |
||
542 | \subsection{Event Handling} |
||
543 | \label{KernSupport_GestioneEventi} |
||
544 | %---------------------------------------------------------------------------- |
||
545 | |||
546 | The Generic Kernel uses the Generic kernel event handling provided |
||
547 | by the OS Lib. The following functions should be used (see |
||
548 | \texttt{include/kernel/func.h}): |
||
549 | |||
550 | \begin{itemize} |
||
551 | \item \texttt{kern\_event\_post} can be used to post an event. The |
||
552 | redefinition adds a check on the index, raising an exception if |
||
553 | the OS Lib event queue is full. \item \texttt{kern\_event\_delete} |
||
554 | can be used to remove an OSLIB event. The unique parameter of the |
||
555 | funcion is the eveni ID returned by the kern\_event\_post |
||
556 | function. \item \texttt{event\_need\_reschedule}, with no |
||
557 | parameters. It has to be called into the event handlers that have |
||
558 | to reschedule the system. The Modules never have to call the |
||
559 | schedule function into event handlers. |
||
560 | \end{itemize} |
||
561 | |||
562 | %---------------------------------------------------------------------------- |
||
563 | \subsection{Exception Handling} |
||
564 | %---------------------------------------------------------------------------- |
||
565 | |||
566 | The Generic Kernel exception handling is based on the real-time |
||
567 | signal interface of the POSIX standard. In particular, the |
||
568 | exceptions are implemented with the signal number 9, SIGHEXC, that |
||
569 | typically writes a message to the console and ends the system. |
||
570 | |||
571 | The function to use to raise an exception is: \begin{center} |
||
572 | \fbox{\tt{ void kern\_raise(int n, PID p); }} \end{center} |
||
573 | |||
574 | As a result of this function call, a real-time signal is enqueued |
||
575 | into the system and the n parameter is passed into the field |
||
576 | \texttt{si\_value} of the structure \texttt{siginfo\_t} passed as |
||
577 | a parameter to the signal handler. |
||
578 | |||
579 | %---------------------------------------------------------------------------- |
||
580 | \subsection{Memory Management} |
||
581 | \label{KernSupport_GestioneMemoria} |
||
582 | %---------------------------------------------------------------------------- |
||
583 | |||
584 | The Generic kernel provides a memory allocator based on Flux |
||
585 | OS-Kit LMM\cite{Bry97}. The LMM is in the \texttt{kernel/mem} |
||
586 | directory; the functions defined in this subsection are in the |
||
587 | file \texttt{kernel/mem.c}. These functions must be called with |
||
588 | interrupt disabled. |
||
589 | |||
590 | The allocator divides the memory into three regions that can be |
||
591 | specified with some \#defines into the flag parameter of some |
||
592 | functions: |
||
593 | |||
594 | \begin{itemize} |
||
595 | \item Memory addresses below 1 Mb (flag field set to |
||
596 | \texttt{MEMORY\_UNDER\_1M}) \item Memory addresses from 1 Mb to 16 |
||
597 | Mb (flag field set to \texttt{MEMORY\_FROM\_1M\_TO\_16M}) \item |
||
598 | Memory addresses below 16 Mb (flag field set to |
||
599 | \texttt{MEMORY\_UNDER\_16M}) \item Memory addresses over 16 Mb |
||
600 | (flag field set to \texttt{0}) |
||
601 | \end{itemize} |
||
602 | |||
603 | Memory management functions are described below (see also Figure |
||
604 | \ref{KernSupport_mem_functions}): |
||
605 | |||
606 | \begin{figure} |
||
607 | \begin{center} |
||
608 | \begin{minipage}{6cm} |
||
609 | \begin{verbatim} |
||
610 | void *kern_alloc(DWORD s); |
||
611 | void *kern_alloc_aligned(size_t size, lmm_flags_t flags, |
||
612 | int align_bits, DWORD align_ofs); |
||
613 | void *kern_alloc_gen(size_t size, lmm_flags_t flags, |
||
614 | int align_bits, DWORD align_ofs, |
||
615 | DWORD bounds_min, DWORD bounds_max); |
||
616 | void kern_free(void *block, size_t size); |
||
617 | void *kern_alloc_page(lmm_flags_t flags); |
||
618 | void kern_free_page(void *block); |
||
619 | void *DOS_alloc(DWORD size); |
||
620 | void DOS_free(void *ptr, DWORD size); |
||
621 | \end{verbatim} |
||
622 | \end{minipage} |
||
623 | \end{center} |
||
624 | \label{KernSupport_mem_functions} |
||
625 | \caption{Memory allocation functions.} |
||
626 | \end{figure} |
||
627 | |||
628 | \begin{description} |
||
629 | \item [\texttt{kern\_alloc}]This function allocates a memory block |
||
630 | of s bytes returning a \texttt{void~{*}}. All the addresses given |
||
631 | are supposed to be good for the block. The function returns |
||
632 | \texttt{NULL} if there is not a free memory block with the |
||
633 | required size. \item [\texttt{kern\_alloc\_aligned}]This functions |
||
634 | allocates an aligned memory block. The first \texttt{align\_bits} |
||
635 | of the block must be equal to the lowest \texttt{align\_bits} of |
||
636 | \texttt{align\_ofs}. In other words, \texttt{align\_bits} |
||
637 | specifies an alignment as a power of 2, whereas |
||
638 | \texttt{align\_ofs} is a natural offset. The function returns |
||
639 | \texttt{NULL} if there is not a block with the required |
||
640 | characteristics. \item [\texttt{kern\_alloc\_gen}]This function |
||
641 | allocates an aligned memory block in a way similar to |
||
642 | \texttt{kern\_alloc\_aligned}, with the additional condition that |
||
643 | the block must be found within the addresses \texttt{bounds\_min} |
||
644 | and \texttt{bounds\_max}. \item [\texttt{kern\_free}]This function |
||
645 | will free a block allocated with one of the previous functions. |
||
646 | Note that this function requires the dimension of the block to |
||
647 | allocate. \item [\texttt{kern\_alloc\_page}]This function |
||
648 | allocates an aligned page of memory (4 Kb). \item |
||
649 | [\texttt{kern\_free\_page}]This function frees a page allocated |
||
650 | with the \texttt{kern\_alloc\_page} function. \item |
||
651 | [\texttt{DOS\_alloc,~DOS\_free}]These functions allocate memory |
||
652 | under the first Mb. |
||
653 | \end{description} |
||
654 | |||
655 | %---------------------------------------------------------------------------- |
||
656 | \subsection{Context switch} |
||
657 | %---------------------------------------------------------------------------- |
||
658 | |||
659 | The creation and the deletion of a context in the Generic Kernel |
||
660 | is made using the OS Lib functions, properly renamed into |
||
661 | \texttt{kern\_context\_create} and \texttt{kern\_context\_delete}. |
||
662 | |||
663 | To change context, the Generic Kernel provides two functions, |
||
664 | \texttt{kern\_context\_save} and \texttt{kern\_context\_load}. |
||
665 | First function can be used to start a kernel primitive (disabling |
||
666 | interrupts, whereas the second can be used to enable the |
||
667 | interrupts, change the context using the OS Lib functions, |
||
668 | dispatch pending signals and test for asynchronous cancellation. |
||
669 | Note that currently the kernel primitives run on the same stack of |
||
670 | the caller thread, and the primitives are simply called disabling |
||
671 | the interrupts. |
||
672 | |||
673 | These functions must never be called into the standard interface |
||
674 | of the scheduling modules. When a OS Lib event need to reschedule |
||
675 | the system because there is a preemption, the function |
||
676 | \texttt{event\_need\_reschedule} must be called instead. |
||
677 | |||
678 | The functions described in this paragraph are into the |
||
679 | \texttt{include/kernel/func.h} file. |
||
680 | |||
681 | %---------------------------------------------------------------------------- |
||
682 | \subsection{Queues, arrays and pointers} |
||
683 | \label{KernSupport_Code} |
||
684 | %---------------------------------------------------------------------------- |
||
685 | |||
686 | To simplify the use of the internal Kernel references, the |
||
687 | following approach is used: |
||
688 | |||
689 | \begin{itemize} |
||
690 | \item Whenever possible, the descriptor arrays are statically |
||
691 | allocated. \item Each descriptor is identified by an integer which |
||
692 | represents the index in the descriptor array (e.g. PID, LEVEL, |
||
693 | RLEVEL). |
||
694 | \end{itemize} |
||
695 | |||
696 | To handle task queues, the Generic Kernel provides some utility |
||
697 | functions which can speed up the Module writing; however a module |
||
698 | can use its own functions to enqueue tasks. |
||
699 | |||
700 | The implemented functions do not use any fields of the task |
||
701 | descriptor; they are implemented with a double linked list. The |
||
702 | prototypes of the functions for queue management are shown in |
||
703 | Figure \ref{KernSupport_queue_functions}. They are into the file |
||
704 | \texttt{kernel/iqueue.c}, and \texttt{include/kernel/iqueue.h}, |
||
705 | described below. |
||
706 | |||
707 | \begin{figure} |
||
708 | \texttt{\#define IQUEUE\_NO\_PRIORITY 1} |
||
709 | \texttt{\#define IQUEUE\_NO\_TIMESPEC 2} |
||
710 | \texttt{struct IQUEUE\_shared \{ } |
||
711 | \texttt{~~PID prev{[}MAX\_PROC{]}; } |
||
712 | \texttt{~~PID next{[}MAX\_PROC{]}; } |
||
713 | \texttt{~~struct timespec {*}timespec\_priority; } |
||
714 | \texttt{~~DWORD {*}priority; } |
||
715 | \texttt{\};} |
||
716 | \texttt{typedef struct \{ } |
||
717 | \texttt{~~PID first; } |
||
718 | \texttt{~~PID last; } |
||
719 | \texttt{~~struct IQUEUE\_shared {*}s; } |
||
720 | \texttt{\} IQUEUE; } |
||
721 | \texttt{~} |
||
722 | \texttt{void iq\_init (IQUEUE {*}q, IQUEUE {*}share, int flags);} |
||
723 | \texttt{void iq\_priority\_insert (PID p, IQUEUE {*}q); } |
||
724 | \texttt{void iq\_timespec\_insert (PID p, IQUEUE {*}q); } |
||
725 | \texttt{void iq\_insertfirst (PID p, IQUEUE {*}q); } |
||
726 | \texttt{void iq\_insertlast (PID p, IQUEUE {*}q);} |
||
727 | \texttt{void iq\_extract (PID p, IQUEUE {*}q); } |
||
728 | \texttt{PID iq\_getfirst ( IQUEUE {*}q); } |
||
729 | \texttt{PID iq\_getlast ( IQUEUE {*}q); } |
||
730 | \texttt{PID iq\_query\_first(IQUEUE {*}q);} |
||
731 | \texttt{PID iq\_query\_last(IQUEUE {*}q);} |
||
732 | \texttt{struct timespec {*}iq\_query\_timespec(PID p, IQUEUE |
||
733 | {*}q);} |
||
734 | \texttt{DWORD {*}iq\_query\_priority (PID p, IQUEUE {*}q);} |
||
735 | \texttt{PID iq\_query\_next (PID p, IQUEUE {*}q);} |
||
736 | \texttt{PID iq\_query\_prev (PID p, IQUEUE {*}q);} |
||
737 | \texttt{int iq\_isempty (IQUEUE {*}q);} |
||
738 | \caption{Prototypes of the task queue handling functions.} |
||
739 | \label{KernSupport_queue_functions} |
||
740 | \end{figure} |
||
741 | |||
742 | |||
743 | Basically, an IQUEUE has an \char`\"{}I\char`\"{}nternal prev/next |
||
744 | structure, that may be shared between one or more queue. Of |
||
745 | course, the user MUST guarantee that the same task will not be |
||
746 | inserted in two IQUEUEs that share the same prev/next buffer. |
||
747 | |||
748 | Internal queue initialization: |
||
749 | |||
750 | \begin{description} |
||
751 | \item [share~=~\&x]the internal data structure of the IQUEUE x is |
||
752 | used to enqueue the tasks. \item [\texttt{share~=~NULL}]an |
||
753 | internal data structure to handle prev/next pairs is dynamically |
||
754 | allocated (The amount of memory that is allocated can be reduced |
||
755 | using the flags). \item [flags]can be used to reduce the memory |
||
756 | usage of an IQUEUE when \texttt{share=NULL}: |
||
757 | |||
758 | \begin{description} |
||
759 | \item [\texttt{IQUEUE\_NO\_PRIORITY}]the iqueue do not provide |
||
760 | internally a priority field \item |
||
761 | [\texttt{IQUEUE\_NO\_TIMESPEC}]the iqueue do not provide |
||
762 | internally a timespec field |
||
763 | \end{description} |
||
764 | |||
765 | note that, if these flags are used, the corresponding insert |
||
766 | functions will not work!. The default value for the flags is, of |
||
767 | course, 0. |
||
768 | |||
769 | \end{description} |
||
770 | The queue insertion is made by the following functions: |
||
771 | |||
772 | \begin{description} |
||
773 | \item [iq\_insert]insertion based on the \texttt{priority} field. |
||
774 | \item [iq\_timespec\_insert]same as above but use the |
||
775 | \texttt{timespec\_priority} field \item [iq\_insertfirst]insert in |
||
776 | the first position of the queue \item [iq\_insertlast]insert in |
||
777 | the last position of the queue |
||
778 | \end{description} |
||
779 | |||
780 | The queue extraction functions: basically extracts a task p from |
||
781 | the queue q. There are three versions of the function: |
||
782 | |||
783 | \begin{description} |
||
784 | \item [iq\_extract]extracts given a task p (that must be inserted |
||
785 | in the queue); \item [iq\_getfirst]extracts the first task in the |
||
786 | queue, NIL if the queue is empty; \item [iq\_getlast]extracts the |
||
787 | last task in the queue, NIL if the queue is empty; |
||
788 | \end{description} |
||
789 | |||
790 | Seven queue query functions are also provided. The first two |
||
791 | functions (query first/last) return the first and the last task in |
||
792 | the queue, NIL if the queue is empty. The second two functions |
||
793 | (query priority/timespec) can be used to get/set the priority or |
||
794 | the timespec field used when queuing. The third two functions |
||
795 | (query next/prev) can be used to scan the queue elements. The last |
||
796 | function can be used to test if a queue is empty. |
||
797 | |||
798 | %---------------------------------------------------------------------------- |
||
799 | \subsection{Initialization functions} |
||
800 | %---------------------------------------------------------------------------- |
||
801 | |||
802 | The Generic Kernel supports the specification of the functions to |
||
803 | be called at system initialization and termination (see Section |
||
804 | \ref{Kernel_Inizializzazione}). These functions can be registered |
||
805 | through the following system primitive: |
||
806 | |||
807 | \begin{center} |
||
808 | \fbox{\tt{ |
||
809 | \texttt{int sys\_atrunlevel(void ({*}f)(void {*}),void {*}p, BYTE when); |
||
810 | }}} |
||
811 | \end{center} |
||
812 | |||
813 | The parameters for that function are: |
||
814 | |||
815 | \begin{description} |
||
816 | |||
817 | \item [\texttt{f}]the function to be registered; |
||
818 | |||
819 | \item [\texttt{p}]the parameter to be passed to function \texttt{f} when the |
||
820 | function will be called; |
||
821 | |||
822 | \item [\texttt{when}]is the situation in witch that function will be called. The |
||
823 | correct values are the following: |
||
824 | |||
825 | \begin{description} |
||
826 | |||
827 | \item [\texttt{RUNLEVEL\_INIT}]The function will be called after Module |
||
828 | registration, when the system is just entered in multitasking mode but no thread |
||
829 | executed yet; |
||
830 | |||
831 | \item [\texttt{RUNLEVEL\_SHUTDOWN}]The function will be called after a call to |
||
832 | \texttt{sys\_abort} or \texttt{sys\_end}; The system is still in multitasking |
||
833 | mode; |
||
834 | |||
835 | \item [\texttt{RUNLEVEL\_BEFORE\_EXIT}]The function will be called when the |
||
836 | Kernel exits from multitasking mode; |
||
837 | |||
838 | \item [\texttt{RUNLEVEL\_AFTER\_EXIT}]The function is called before the system |
||
839 | hangs (or returns to the host OS, if the proprietary extender is used). |
||
840 | |||
841 | \end{description} |
||
842 | |||
843 | It is also possible to specify with an OR operator a flag |
||
844 | \texttt{NO\_AT\_ABORT} that disables the call to the functions if |
||
845 | the system is exiting with a \texttt{sys\_abort} function. |
||
846 | \end{description} |
||
847 | |||
848 | You can post at most \texttt{MAX\_RUNLEVEL\_FUNC} functions. |
||
849 | |||
850 | %---------------------------------------------------------------------------- |
||
851 | \subsection{Interrupt disabling, printf and system termination} |
||
852 | %---------------------------------------------------------------------------- |
||
853 | |||
854 | The Generic Kernel redefines the following OS Lib functions (see |
||
855 | the \texttt{include/kernel/func.h} file): |
||
856 | |||
857 | \begin{description} |
||
858 | \item [\texttt{cli}]renamed in \texttt{kern\_cli} \item |
||
859 | [\texttt{sti}]renamed in \texttt{kern\_sti} \item |
||
860 | [\texttt{ll\_fsave}]renamed in \texttt{kern\_fsave} \item |
||
861 | [\texttt{ll\_frestore}]renamed in \texttt{kern\_frestore}. |
||
862 | \end{description} |
||
863 | |||
864 | To display some messages to the console, the Generic Kernel |
||
865 | provides two functions called \texttt{printk} and |
||
866 | \texttt{kern\_printf}. These functions are similar to the standard |
||
867 | C \texttt{printf} function, except that they write directly to the |
||
868 | console. The \texttt{printk} function allows to specify a kind of |
||
869 | ``importance'' for the message that the function displays. For |
||
870 | more information look at the file \texttt{include/kernel/func.h} |
||
871 | and \texttt{include/kernel/log.h}. |
||
872 | |||
873 | Finally, a clean system termination can be obtained through the \texttt{exit} |
||
874 | primitive. For more information look at the file \texttt{include/kernel/func.h} |
||
875 | and read Section \ref{Kernel_Inizializzazione}. |