Rev 1676 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1676 | tullio | 1 | %---------------------------------------------------------------------------- |
2 | \chapter{Examples} |
||
3 | %---------------------------------------------------------------------------- |
||
4 | |||
5 | The application of the proposed approach is presented in this |
||
6 | chapter, on three meaningful examples, by showing the code of the |
||
7 | scheduling and of the resource modules. The examples are really |
||
8 | implemented in the Kernel, so these remarks can also be used as |
||
9 | documentation. |
||
10 | |||
11 | %---------------------------------------------------------------------------- |
||
12 | \section{SIMPLEEDF (Earliest Deadline First) Scheduling Module} |
||
13 | %---------------------------------------------------------------------------- |
||
14 | |||
15 | This section describes an implementation of EDF with the following |
||
16 | characteristics: |
||
17 | |||
18 | \begin{itemize} |
||
19 | \item Support for periodic and sporadic tasks; |
||
20 | \item Support for release offsets and relative deadlines less than the period; |
||
21 | \item On-line guarantee using the utilization factor paradigm; |
||
22 | \item Temporal isolation implemented using the \texttt{CONTROL\_CAP} flag; |
||
23 | \item A number of different deadline/WCET/activation violation options. |
||
24 | \end{itemize} |
||
25 | |||
26 | Typically this module is registered at Level 0; in effect the |
||
27 | guarantee algorithm works only if the Module can use all the |
||
28 | bandwidth of the system. In order to schedule background periodic |
||
29 | tasks, a soft task model should be used with a Scheduling Module |
||
30 | like the CBS Scheduling Module. The Module described in this |
||
31 | section is contained in \texttt{modules/edf.c}. |
||
32 | |||
33 | %---------------------------------------------------------------------------- |
||
34 | \subsection{State transition diagram} |
||
35 | %---------------------------------------------------------------------------- |
||
36 | |||
37 | The state transition diagram for an EDF task is shown in Figure |
||
38 | \ref{Examples_EDF_Stati}. |
||
39 | |||
40 | \begin{figure} |
||
41 | \begin{center} |
||
42 | \includegraphics[width=1.0\columnwidth]{images/example_EDF_status.eps} |
||
43 | \end{center} |
||
44 | \label{Examples_EDF_Stati} |
||
45 | \caption{State transition diagram for an EDF task. (For simplicity, some |
||
46 | transitions have been excluded.)} |
||
47 | \end{figure} |
||
48 | |||
49 | The states whose name start with \texttt{EDF\_} are internal |
||
50 | Module statuses. The event names are reported near the arcs; in |
||
51 | particular the names of the timer events are written within |
||
52 | parentheses. The different states have the following meanings: |
||
53 | |||
54 | \begin{description} |
||
55 | \item [\texttt{FREE}]Before creation, and after destruction, the |
||
56 | task is in this state. |
||
57 | |||
58 | \item [\texttt{SLEEP}]The task waits in this state for an explicit activation. |
||
59 | |||
60 | \item [\texttt{EDF\_READY}]This is the classic ready state where the task has to |
||
61 | wait until it has the highest priority (i.e., the earliest deadline). |
||
62 | |||
63 | \item [\texttt{EXE}]This is the state when the task is executing. |
||
64 | |||
65 | \item [\texttt{EDF\_WAIT}]This is the state of a sporadic task after finishing |
||
66 | an instance, waiting for the endperiod event to arrive. |
||
67 | |||
68 | \item [\texttt{EDF\_IDLE}]This is the |
||
69 | state of a periodic task after finishing an instance, waiting for |
||
70 | the endperiod event to arrive. An activated task with a release |
||
71 | offset is also put in this state, waiting for the first period to |
||
72 | arrive. |
||
73 | |||
74 | \item [\texttt{EDF\_ZOMBIE}]This is the state where a task |
||
75 | is put when it terminates correctly. The allocated bandwidth is |
||
76 | freed when the endperiod event is fired. |
||
77 | \end{description} |
||
78 | |||
79 | %---------------------------------------------------------------------------- |
||
80 | \subsection{Level |
||
81 | descriptor} |
||
82 | %---------------------------------------------------------------------------- |
||
83 | |||
84 | The EDF Module extends the \texttt{level\_des} structure that |
||
85 | contains the interface exported by a generic Scheduling Module. |
||
86 | The extended data structure, \texttt{EDF\_level\_des,} contains |
||
87 | the following fields: |
||
88 | |||
89 | \begin{description} |
||
90 | \item [\texttt{flags}]This variable stores the flags passed to the |
||
91 | module at registration time. The following flags are defined: |
||
92 | |||
93 | \begin{description} |
||
94 | \item [\texttt{EDF\_ENABLE\_DL\_CHECK}]If set, the module will |
||
95 | keep track of task deadlines by internal deadline timers. The |
||
96 | behavior in case of a deadline overrun depends on the |
||
97 | \texttt{EDF\_ENABLE\_DL\_EXCEPTION} flag, see below. |
||
98 | |||
99 | \item |
||
100 | [\texttt{EDF\_ENABLE\_WCET\_CHECK}]If set, the module will keep |
||
101 | track of task execution times by enabling the CONTROL\_CAP flag |
||
102 | for the tasks in the generic kernel. |
||
103 | |||
104 | \item |
||
105 | [\texttt{EDF\_ENABLE\_DL\_EXCEPTION}]If set, the module will raise |
||
106 | an exception if a deadline overrun occurs. If not set, the |
||
107 | \texttt{dl\_miss} counter for the task is increased every time a |
||
108 | deadline overrun occurs. |
||
109 | |||
110 | \item |
||
111 | [\texttt{EDF\_ENABLE\_WCET\_EXCEPTION}]If set, the module will |
||
112 | raise an exception if an execution-time overrun occurs. If not |
||
113 | set, the \texttt{wcet\_miss} counter for the task is increased |
||
114 | every time an execution-time overrun occurs. |
||
115 | |||
116 | \item |
||
117 | [\texttt{EDF\_ENABLE\_ACT\_EXCEPTION}]If set, the module will |
||
118 | raise an exception if a task is activated more often than its |
||
119 | declared minimum interarrival time. If not set, the \texttt{nskip} |
||
120 | counter for the task is increased instead. |
||
121 | \end{description} |
||
122 | |||
123 | \item [\texttt{ready}]This is an \texttt{IQUEUE} variable used to |
||
124 | handle the ready queue. \item [\texttt{U}]This variable is used to |
||
125 | store the sum of the reserved bandwidth for the tasks owned by the |
||
126 | Module. \item [\texttt{tvec}]A vector of EDF task descriptors, |
||
127 | \texttt{EDF\_task\_des}, that defines a number of additional |
||
128 | variables for each task, see below. |
||
129 | \end{description} |
||
130 | |||
131 | %---------------------------------------------------------------------------- |
||
132 | \subsection{Task |
||
133 | descriptor} |
||
134 | %---------------------------------------------------------------------------- |
||
135 | |||
136 | The EDF module introduces a number of additional task variables. |
||
137 | They are collected in a \texttt{EDF\_task\_des} structure for each |
||
138 | task: |
||
139 | |||
140 | \begin{description} |
||
141 | \item [\texttt{flags}]Flags that store some additional type/status |
||
142 | information about the task. The following flags are defined: |
||
143 | |||
144 | \begin{description} |
||
145 | \item [\texttt{EDF\_FLAG\_SPORADIC}]The task is sporadic. This |
||
146 | influences some state transitions, see Figure |
||
147 | \ref{Examples_EDF_Stati}. |
||
148 | |||
149 | \item |
||
150 | [\texttt{EDF\_FLAG\_SPOR\_LATE}]The task is sporadic and has |
||
151 | experienced a period overrun. (This is only possible if the |
||
152 | EDF\_ENABLE\_DL\_EXCEPTION level flag is not set.) When finished, |
||
153 | the task should go directly to the SLEEP state. |
||
154 | \end{description} |
||
155 | |||
156 | \item [\texttt{period}]The period or minimum interarrival time of |
||
157 | the task. |
||
158 | |||
159 | \item [\texttt{rdeadline}]The relative deadline of the |
||
160 | task. Currently, only $D\leq T$ is allowed. |
||
161 | |||
162 | \item |
||
163 | [\texttt{offset}]The release offset, relative to the activation |
||
164 | time of the task. \item [\texttt{release}]This variable stores the |
||
165 | release time of the current instance. |
||
166 | |||
167 | \item |
||
168 | [\texttt{adeadline}]This variable stores the absolute deadline |
||
169 | associated with the most recent task activation. |
||
170 | |||
171 | \item |
||
172 | [\texttt{dltimer}]A handle to the task deadline timer. |
||
173 | |||
174 | \item |
||
175 | [\texttt{eop\_timer}]A handle to the task end-of-period timer. |
||
176 | |||
177 | \item [\texttt{dl\_miss}]Counter for the number of missed |
||
178 | deadlines. |
||
179 | |||
180 | \item [\texttt{wcet\_miss}]Counter for the number of |
||
181 | execution-time overruns. |
||
182 | |||
183 | \item [\texttt{act\_miss}]Counter for the |
||
184 | number of skipped activations. |
||
185 | |||
186 | \item [\texttt{nact}]The current |
||
187 | number of queued activations (periodic tasks only). |
||
188 | \end{description} |
||
189 | |||
190 | %---------------------------------------------------------------------------- |
||
191 | \subsection{Module |
||
192 | internal event handlers} |
||
193 | %---------------------------------------------------------------------------- |
||
194 | |||
195 | The module uses internal kernel events (one-shot timers) to handle |
||
196 | the release of tasks, deadline overruns, etc. When an event is |
||
197 | posted by the module, an event handler is specified, and the PID |
||
198 | of the relevant task is passed as parameter. For instance, the |
||
199 | \texttt{endperiod} event is handled by the following function: |
||
200 | |||
201 | %---------------------------------------------------------------------------- |
||
202 | \subsubsection{\texttt{static |
||
203 | void EDF\_timer\_endperiod(void *par) }} |
||
204 | %---------------------------------------------------------------------------- |
||
205 | |||
206 | The first thing to do when handling an event is to recover the |
||
207 | information about the Module that posted the event. This can be |
||
208 | done with the following statements: |
||
209 | |||
210 | \bigskip{} |
||
211 | \texttt{PID p = (PID) par;} |
||
212 | |||
213 | \texttt{EDF\_level\_des *lev =} |
||
214 | |||
215 | \begin{center}\texttt{(EDF\_level\_des |
||
216 | *)level\_table{[}proc\_table{[}p{]}.task\_level{]};}\end{center} |
||
217 | \bigskip{} |
||
218 | |||
219 | The generic kernel task fields can be referenced as |
||
220 | \texttt{proc\_table{[}p{]}.name}; the internal data of the Module |
||
221 | can be referenced as \texttt{lev-}\texttt{\emph{>}}\texttt{field}. |
||
222 | The EDF task descriptor can be referenced as |
||
223 | |||
224 | \bigskip{} |
||
225 | \texttt{EDF\_task\_des *td = \&lev->tvec{[}p{]}; } |
||
226 | \bigskip{} |
||
227 | |||
228 | and the EDF task fields can then be referenced as |
||
229 | \texttt{td-}\texttt{\emph{>}}\texttt{field}. |
||
230 | |||
231 | By studying the state transition diagram, we see that different |
||
232 | actions should be taken depending on the state of the task: |
||
233 | |||
234 | \begin{itemize} |
||
235 | \item If the task state is \texttt{EDF\_ZOMBIE,} the task is |
||
236 | inserted into the \texttt{freedesc} queue and the allocated |
||
237 | bandwidth is freed; |
||
238 | |||
239 | \item If the state is \texttt{EDF\_WAIT,} the |
||
240 | task state is set to \texttt{SLEEP}, so the sporadic task can be |
||
241 | reactivated; |
||
242 | |||
243 | \item If the state is \texttt{EDF\_IDLE} and the task |
||
244 | is periodic, it is reactivated by a call to the |
||
245 | \texttt{EDF\_intern\_release} function. This involves posting a |
||
246 | deadline event (if \texttt{EDF\_ENABLE\_DL\_CHECK} is set); |
||
247 | inserting the task in the ready queue; increasing the absolute |
||
248 | deadline; and telling the kernel that it may need to reschedule by |
||
249 | calling \texttt{event\_need\_reschedule.} |
||
250 | |||
251 | \item If the state is |
||
252 | \texttt{EDF\_IDLE} and the task is sporadic, it is marked as late. |
||
253 | \end{itemize} |
||
254 | The module also contains the following event handlers: |
||
255 | |||
256 | static void EDF\_timer\_deadline(void *par) |
||
257 | |||
258 | static void EDF\_timer\_offset(void *par) |
||
259 | |||
260 | static void EDF\_timer\_guest\_deadline(void *par) |
||
261 | |||
262 | %---------------------------------------------------------------------------- |
||
263 | \subsection{Public Functions} |
||
264 | %---------------------------------------------------------------------------- |
||
265 | |||
266 | The Module redefines the Level Calls interface. In the following |
||
267 | paragraphs the implementation of these functions is described. |
||
268 | |||
269 | All the functions of the interface receive a parameter of type |
||
270 | \texttt{LEVEL} that can be used in a way similar to the parameter |
||
271 | passed to the event functions to find all the data structures |
||
272 | needed. |
||
273 | |||
274 | %---------------------------------------------------------------------------- |
||
275 | \subsubsection{\texttt{PID |
||
276 | EDF\_public\_scheduler(LEVEL l);}} |
||
277 | %---------------------------------------------------------------------------- |
||
278 | |||
279 | This is the Module scheduler that, as all good schedulers, simply |
||
280 | returns the first task in the ready queue without extracting it. |
||
281 | |||
282 | %---------------------------------------------------------------------------- |
||
283 | \subsubsection{\texttt{int |
||
284 | EDF\_public\_guarantee(LEVEL l, bandwidth\_t *freebandwidth);}} |
||
285 | %---------------------------------------------------------------------------- |
||
286 | |||
287 | The on-line guarantee function simply verifies if there is enough |
||
288 | free bandwidth for scheduling its tasks. If so, the free bandwidth |
||
289 | is decremented by the amount used by the Module, and it returns |
||
290 | that the task set can be guaranteed. |
||
291 | |||
292 | If the guarantee is called after a task creation in the Module, it |
||
293 | can be the case that the new task, with all the other tasks |
||
294 | already guaranteed by the Module, uses a bandwidth greater than 1 |
||
295 | (note that the U field can store only numbers in the |
||
296 | {[}0\ldots{}1{]} interval). In this case, in the function |
||
297 | \texttt{EDF\_public\_create} a flag is set forcing the guarantee |
||
298 | algorithm to fail. |
||
299 | |||
300 | %---------------------------------------------------------------------------- |
||
301 | \subsubsection{\texttt{int EDF\_public\_create(LEVEL l, PID p, TASK\_MODEL *m);}} |
||
302 | %---------------------------------------------------------------------------- |
||
303 | |||
304 | The function checks if the Model passed as second parameter can be |
||
305 | handled. In this case, the Module handles all the |
||
306 | HARD\_TASK\_MODELs that have a correct \texttt{pclass} value and a |
||
307 | wcet and a period != 0. This function sets the \texttt{period}, |
||
308 | \texttt{flag}, and \texttt{wcet} internal fields of the newly |
||
309 | created task. The function sets also the \texttt{CONTROL\_CAP} |
||
310 | flag to inform the Generic Kernel that the execution time have to |
||
311 | be controlled. Finally, the function allocates the system |
||
312 | bandwidth in such a way that it can be checked by the guarantee |
||
313 | algorithm. If the bandwidth allocated for the already guaranteed |
||
314 | tasks plus the new one is greater than 1, a flag is set to signal |
||
315 | that the guarantee algorithm must fail. |
||
316 | |||
317 | %---------------------------------------------------------------------------- |
||
318 | \subsubsection{\texttt{void EDF\_public\_detach(LEVEL l, PID p);}} |
||
319 | %---------------------------------------------------------------------------- |
||
320 | |||
321 | This function simply reclaims the bandwidth used by the task |
||
322 | allocated by \texttt{EDF\_public\_create}, disabling the flag set |
||
323 | by \texttt{EDF\_public\_create} when the guarantee is impossible |
||
324 | (U>1). |
||
325 | |||
326 | %---------------------------------------------------------------------------- |
||
327 | \subsubsection{\texttt{int EDF\_public\_eligible(LEVEL l, PID p);}} |
||
328 | %---------------------------------------------------------------------------- |
||
329 | |||
330 | This function simply returns 0 because the EDF tasks are always |
||
331 | eligibles. In fact, the EDF Module does not use the guest |
||
332 | functions of another Module to handle its tasks. |
||
333 | |||
334 | %---------------------------------------------------------------------------- |
||
335 | \subsubsection{\texttt{void EDF\_public\_dispatch(LEVEL l, PID p, int nostop);}} |
||
336 | %---------------------------------------------------------------------------- |
||
337 | |||
338 | To dispatch an EDF task, the task itself must be removed from the |
||
339 | ready queue. The capacity handling (like the capacity event post) |
||
340 | is automatically done by the Generic Kernel. |
||
341 | |||
342 | %---------------------------------------------------------------------------- |
||
343 | \subsubsection{\texttt{void EDF\_public\_epilogue(LEVEL l, PID p);}} |
||
344 | %---------------------------------------------------------------------------- |
||
345 | |||
346 | The function must suspend the running task because it has been preempted or |
||
347 | because if has finished his capacity. Therefore, the first thing to be done is |
||
348 | the check of the available capacity. If it is exhausted an exception is raised |
||
349 | and the task is put into the \texttt{EDF\_WCET\_VIOLATED} \footnote{The task |
||
350 | shall not be extracted by any queue because the task was extracted by the |
||
351 | \texttt{EDF\_public\_dispatch} function.} state. |
||
352 | |||
353 | When the task has not consumed all of its capacity it is inserted |
||
354 | back into the ready queue. |
||
355 | |||
356 | %---------------------------------------------------------------------------- |
||
357 | \subsubsection{\texttt{void EDF\_public\_activate(LEVEL l, PID p, struct timespec *t);}} |
||
358 | %---------------------------------------------------------------------------- |
||
359 | |||
360 | This function simply activates the task, inserting it into the |
||
361 | ready queue. A task can be activated only if it is in the |
||
362 | \texttt{SLEEP} or in the \texttt{EDF\_WCET\_VIOLATED} state. If |
||
363 | the task is in the \texttt{EDF\_WAIT} state it means that the task |
||
364 | is a sporadic task activated too early, so an exception is raised. |
||
365 | |||
366 | The function executes the following steps: |
||
367 | |||
368 | \begin{itemize} |
||
369 | \item A suitable deadline is computed for the task; |
||
370 | |||
371 | \item The task |
||
372 | is inserted into the ready queue; |
||
373 | |||
374 | \item A deadline event is posted |
||
375 | for the task. |
||
376 | \end{itemize} |
||
377 | |||
378 | %---------------------------------------------------------------------------- |
||
379 | \subsubsection{\texttt{void EDF\_public\_unblock(LEVEL l, PID p);}} |
||
380 | %---------------------------------------------------------------------------- |
||
381 | |||
382 | The function simply inserts the task into into the ready queue. |
||
383 | The task was blocked on a synchronization by a call to the |
||
384 | function \texttt{EDF\_public\_block}. |
||
385 | |||
386 | %---------------------------------------------------------------------------- |
||
387 | \subsubsection{\texttt{void EDF\_public\_block(LEVEL l, PID p);}} |
||
388 | %---------------------------------------------------------------------------- |
||
389 | |||
390 | The function implements a synchronization block. The function |
||
391 | simply does nothing, because: |
||
392 | |||
393 | \begin{itemize} |
||
394 | \item The task was already extracted from the ready queue; |
||
395 | |||
396 | \item |
||
397 | The capacity event is handled by the Generic Kernel; |
||
398 | |||
399 | \item The |
||
400 | task state is set by the calling primitive; |
||
401 | |||
402 | \item The deadline |
||
403 | does not need modifications. |
||
404 | \end{itemize} |
||
405 | |||
406 | %---------------------------------------------------------------------------- |
||
407 | \subsubsection{\texttt{int EDF\_public\_message(LEVEL l, PID p, void *m);}} |
||
408 | %---------------------------------------------------------------------------- |
||
409 | |||
410 | This function implement only the task\_endcycle behavior, doing |
||
411 | two things: |
||
412 | |||
413 | \begin{itemize} |
||
414 | \item The \texttt{wcet} of the task is refilled, since the task |
||
415 | has finished its instance; |
||
416 | |||
417 | \item The task state is set to |
||
418 | \texttt{EDF\_IDLE} or \texttt{EDF\_WAIT}, waiting the deadline |
||
419 | arrival. |
||
420 | \end{itemize} |
||
421 | |||
422 | %---------------------------------------------------------------------------- |
||
423 | \subsubsection{\texttt{void EDF\_public\_end(LEVEL l, PID p);}} |
||
424 | %---------------------------------------------------------------------------- |
||
425 | |||
426 | The function should erase all the information about the task in |
||
427 | the data structure of the Module. It simply sets the task state to |
||
428 | \texttt{EDF\_ZOMBIE}. The deallocation of the bandwidth used by |
||
429 | the task and the freeing of the task descriptor is performed while |
||
430 | handling the deadline event. |
||
431 | |||
432 | %---------------------------------------------------------------------------- |
||
433 | \subsection{Private Functions} |
||
434 | %---------------------------------------------------------------------------- |
||
435 | |||
436 | The EDF Module can accept a JOB\_TASK\_MODEL as the Model for the |
||
437 | Guest Tasks. This Model does not provide information about the |
||
438 | time that the task will execute. This means that the EDF Module |
||
439 | does not check the execution time of the task. It must be checked |
||
440 | by the Module that inserts the tasks as guest tasks. In the |
||
441 | following paragraphs the guest calls are described. |
||
442 | |||
443 | %---------------------------------------------------------------------------- |
||
444 | \subsubsection{\texttt{int EDF\_private\_insert(LEVEL l, PID p, TASK\_MODEL *m);}} |
||
445 | %---------------------------------------------------------------------------- |
||
446 | |||
447 | This function is called by a generic Aperiodic Server Module to |
||
448 | insert a task into the EDF Module. |
||
449 | |||
450 | The function simply fills the private data structures of the EDF |
||
451 | Module with the task parameters passed through the Task Model. No |
||
452 | guarantee is done on the guest tasks (the guarantee of a guest |
||
453 | task is a responsibility of the Module that calls this function). |
||
454 | |||
455 | %---------------------------------------------------------------------------- |
||
456 | \subsubsection{\texttt{void EDF\_private\_dispatch(LEVEL l, PID p, int nostop);}} |
||
457 | %---------------------------------------------------------------------------- |
||
458 | |||
459 | This function is typically called by the \texttt{task\_dispatch} |
||
460 | Task Call of the Module that inserts the task as guest task. The |
||
461 | effect of the call is to extract a task from the ready queue, so |
||
462 | it is identical to the \texttt{task\_dispatch} Task Call. |
||
463 | |||
464 | %---------------------------------------------------------------------------- |
||
465 | \subsubsection{\texttt{void EDF\_private\_epilogue(LEVEL l, PID p);}} |
||
466 | %---------------------------------------------------------------------------- |
||
467 | |||
468 | This function is called when a task is preempted (no capacity are |
||
469 | handled by the Module). The function simply inserts the task into |
||
470 | the ready queue. |
||
471 | |||
472 | %---------------------------------------------------------------------------- |
||
473 | \subsubsection{\texttt{void EDF\_guest\_activate(LEVEL l, PID p);}} |
||
474 | %---------------------------------------------------------------------------- |
||
475 | |||
476 | This function is called when the Module that inserts the task in |
||
477 | the system through the EDF\_private\_insert wants to activate it. |
||
478 | The effect of this function is to insert the task into the ready |
||
479 | queue and to post a deadline event if the deadline miss should be |
||
480 | detected for the task (a flag that specifies if the Module should |
||
481 | generate a deadline is given in the JOB\_TASK\_MODEL. |
||
482 | |||
483 | %---------------------------------------------------------------------------- |
||
484 | \subsubsection{\texttt{void EDF\_private\_extract(LEVEL l, PID p);}} |
||
485 | %---------------------------------------------------------------------------- |
||
486 | |||
487 | This function is called by a Module when it wants to terminate a |
||
488 | task inserted as guest. This function is not called only at task |
||
489 | termination, but also when the Module has to change some |
||
490 | parameters for the task (for example, when a deadline should be |
||
491 | postponed). |
||
492 | |||
493 | The function has to erase all references to the task in the |
||
494 | private data structures of the EDF Module. Note that this function |
||
495 | can be called also when the task is not in the EXE state, so all |
||
496 | task states should be checked for a correct behavior. |
||
497 | |||
498 | %---------------------------------------------------------------------------- |
||
499 | \subsection{Additional Functions exported by the Module} |
||
500 | %---------------------------------------------------------------------------- |
||
501 | |||
502 | Finally, the EDF Module exports two functions that can be used by |
||
503 | the user. |
||
504 | |||
505 | The first function is the registration function, used to register |
||
506 | the Module into the system and to init the internal data |
||
507 | structures. |
||
508 | |||
509 | The second function, \texttt{EDF\_usedbandwidth}, can be used to |
||
510 | get the bandwidth actually used by the Module. That function needs |
||
511 | as a parameter the level at which an EDF Module is registered, so |
||
512 | all the private data structures can be read. Note that giving the |
||
513 | level of a Module in an application should not be considered a |
||
514 | violation of the independence of an Application to the Registered |
||
515 | Modules. If an application wants to know a specific data in a |
||
516 | Module, it has to know in what level the Module is Registered... |
||
517 | |||
518 | %---------------------------------------------------------------------------- |
||
519 | \section{PS (Polling Server) Scheduling Module} |
||
520 | %---------------------------------------------------------------------------- |
||
521 | |||
522 | In this Section will be described an implementation of a PS Module |
||
523 | that have the following characteristics: |
||
524 | |||
525 | \begin{itemize} |
||
526 | \item Soft Aperiodic Task support; |
||
527 | |||
528 | \item On-line guarantee using |
||
529 | the utilization factor paradigm; |
||
530 | |||
531 | \item Temporal isolation |
||
532 | implemented without the \texttt{CONTROL\_CAP} flag. |
||
533 | |||
534 | \item Feature |
||
535 | that allows to use the idle time left by the Modules registered at |
||
536 | lower level numbers; |
||
537 | |||
538 | \item Support for pending task activations; |
||
539 | |||
540 | \item Compatibility with static (RM) and dynamic (EDF) algorithms. |
||
541 | \end{itemize} |
||
542 | |||
543 | This Module implements an aperiodic server that inserts its tasks |
||
544 | into another Scheduling Module, without having any information on |
||
545 | how the Master Module is implemented. The module described in this |
||
546 | section is contained in \texttt{modules/ps}. |
||
547 | |||
548 | %---------------------------------------------------------------------------- |
||
549 | \subsection{Transition state diagram} |
||
550 | %---------------------------------------------------------------------------- |
||
551 | |||
552 | In Figure \ref{Examples_PS_Status} the state diagram of a task is |
||
553 | showed. |
||
554 | |||
555 | \begin{figure} |
||
556 | \begin{center} |
||
557 | \includegraphics[width=1.0\columnwidth]{images/example_PS_status.eps} |
||
558 | \end{center} |
||
559 | \label{Examples_PS_Status} |
||
560 | \caption{State Diagram of a Task scheduled with the PS Module.} |
||
561 | \end{figure} |
||
562 | |||
563 | |||
564 | The Module introduce only one state, \texttt{PS\_WAIT}. This is |
||
565 | the state in which a task waits to be inserted in the ``ready |
||
566 | queue''. The server queue is handled in a FIFO way. The other |
||
567 | states in which a Module will go are internal states of the Master |
||
568 | Module. |
||
569 | |||
570 | %---------------------------------------------------------------------------- |
||
571 | \subsection{Private Data structures} |
||
572 | %---------------------------------------------------------------------------- |
||
573 | |||
574 | The PS Module redefines the \texttt{level\_des} structures adding |
||
575 | some private data structures, listed below: |
||
576 | |||
577 | \begin{description} |
||
578 | \item [\texttt{nact}]This array is used to track the pending |
||
579 | activations of a task handled by the Module. Each task element has |
||
580 | a value of\texttt{-1} (if the task skips the pending activations) |
||
581 | or a value \texttt{>=0} (that is, the value of pending activations |
||
582 | for the task); |
||
583 | |||
584 | \item [\texttt{lastdline}]This field is used to |
||
585 | store the deadline used by the Polling Server; |
||
586 | |||
587 | \item |
||
588 | [\texttt{period}]This field stores the reactivation period of the |
||
589 | server; |
||
590 | |||
591 | \item [\texttt{Cs}]This field stores the Maximum capacity |
||
592 | of the server; |
||
593 | |||
594 | \item [\texttt{availCs}]This field stores the |
||
595 | computation time available for the server at a given time. The |
||
596 | capacity is updated when the task handled by the Module is |
||
597 | scheduled by the Master Module, or when a task handled by the |
||
598 | Module is dispatched following the shadow chain and the server is |
||
599 | not scheduling in background; |
||
600 | |||
601 | \item [\texttt{wait}]This field is |
||
602 | the wait queue, where the tasks wait their turn to be served by |
||
603 | the Polling Server; |
||
604 | |||
605 | item [\texttt{activated}]This field is the |
||
606 | PID of the task currently inserted into the Scheduling Module. The |
||
607 | server inserts in the Master Module maximum one Module at a time; |
||
608 | |||
609 | \item [\texttt{flags}]The flag field is used to store some |
||
610 | informations passed when the Module was registered, like for |
||
611 | example the implemented guarantee algorithm (RM or EDF). This |
||
612 | field is used also to know if the server is executing a task in |
||
613 | background; |
||
614 | |||
615 | \item [\texttt{U}]This field is used to store an |
||
616 | information of the used bandwidth by the task handled by the |
||
617 | Module. |
||
618 | |||
619 | \item [\texttt{scheduling\_level}]This field stores the |
||
620 | level of the Host Module. |
||
621 | \end{description} |
||
622 | |||
623 | %---------------------------------------------------------------------------- |
||
624 | \subsection{Internal Module Functions} |
||
625 | %---------------------------------------------------------------------------- |
||
626 | |||
627 | The PS Module needs to define some internal functions. These |
||
628 | functions are called to handle the internal events posted by the |
||
629 | Module. Many of these functions are declared \texttt{static}, so |
||
630 | they are not visible externally to the Module. |
||
631 | |||
632 | %---------------------------------------------------------------------------- |
||
633 | \subsubsection{\texttt{void PS\_activation(PS\_level\_des *lev);}} |
||
634 | %---------------------------------------------------------------------------- |
||
635 | |||
636 | This function is an inline function and it handles the activation |
||
637 | of a task into a Master Module. In particular: |
||
638 | |||
639 | \begin{itemize} |
||
640 | \item It inits a Job Task Model that will be passed to the Master |
||
641 | Module with the period and the deadline of the Polling Server; |
||
642 | |||
643 | \item It creates and activates through the guest calls the task |
||
644 | indexed by the private field \texttt{lev->activated}. |
||
645 | \end{itemize} |
||
646 | |||
647 | %---------------------------------------------------------------------------- |
||
648 | \subsubsection{\texttt{void PS\_deadline\_timer(void *a);}} |
||
649 | %---------------------------------------------------------------------------- |
||
650 | |||
651 | This function implements the periodic reactivation of the Polling |
||
652 | Server. In particular: |
||
653 | |||
654 | \begin{itemize} |
||
655 | \item a new deadline is computed and a new deadline event is |
||
656 | posted; |
||
657 | |||
658 | \item the Server capacity is reloaded to the maximum value |
||
659 | if the available capacity was positive, to a value less than the |
||
660 | maximum (a ``recharge'' (sum) is done) if negative; |
||
661 | |||
662 | \item If the |
||
663 | recharge turn the available capacity positive, a waiting task is |
||
664 | activated, or the capacity available is depleted. |
||
665 | \end{itemize} |
||
666 | |||
667 | %---------------------------------------------------------------------------- |
||
668 | \subsection{Public Functions} |
||
669 | %---------------------------------------------------------------------------- |
||
670 | |||
671 | All the functions of the interface receives a LEVEL parameter that |
||
672 | can be used in a way similar to the parameter passed to the event |
||
673 | functions to get all the private data of the Module. |
||
674 | |||
675 | %---------------------------------------------------------------------------- |
||
676 | \subsubsection{\texttt{PID PS\_level\_scheduler(LEVEL l);}} |
||
677 | %---------------------------------------------------------------------------- |
||
678 | |||
679 | This scheduler is used by the Module if the Module is registered |
||
680 | specifying that it can not use the idle time left by other |
||
681 | Modules. It always return \texttt{NIL} (meaning that the module |
||
682 | has nothing to schedule). |
||
683 | |||
684 | %---------------------------------------------------------------------------- |
||
685 | \subsubsection{\texttt{PID PS\_level\_schedulerbackground(LEVEL l);}} |
||
686 | %---------------------------------------------------------------------------- |
||
687 | |||
688 | This scheduler is used by the Module if the Module is registered |
||
689 | specifying that it can use the idle time left by other Modules. It |
||
690 | sets a flag in the \texttt{flags} field to remember that the |
||
691 | Module is scheduling a task in background, after that it returns |
||
692 | the first task in the wait queue. The scheduler is disactived in |
||
693 | case the task scheduled by the server is blocked on a |
||
694 | synchronization (look at the function \texttt{PS\_public\_block}). |
||
695 | |||
696 | %---------------------------------------------------------------------------- |
||
697 | \subsubsection{\texttt{int PS\_level\_guaranteeRM(LEVEL l, bandwidth\_t *freebandwidth);}} |
||
698 | %---------------------------------------------------------------------------- |
||
699 | |||
700 | %---------------------------------------------------------------------------- |
||
701 | \subsubsection{\texttt{int PS\_level\_guaranteeEDF(LEVEL l, bandwidth\_t *freebandwidth);}} |
||
702 | %---------------------------------------------------------------------------- |
||
703 | |||
704 | These two functions implements the internal guarantee of the |
||
705 | Module, simply decrementing when possible the available bandwidth. |
||
706 | the difference between the two functions is that the first |
||
707 | function allow to schedule until a used bandwidth of 0.69, and the |
||
708 | second one allow a scheduling limit of 1. The structure of this |
||
709 | function is similar to that of \texttt{EDF\_public\_guarantee}, |
||
710 | except that the guarantee is done on the server and not on each |
||
711 | task handled by the server.. |
||
712 | |||
713 | %---------------------------------------------------------------------------- |
||
714 | \subsection{Task Calls} |
||
715 | %---------------------------------------------------------------------------- |
||
716 | |||
717 | %---------------------------------------------------------------------------- |
||
718 | \subsubsection{\texttt{int PS\_public\_create(LEVEL l, PID p, TASK\_MODEL *m);}} |
||
719 | %---------------------------------------------------------------------------- |
||
720 | |||
721 | This functions checks if the Task Model passed can be handled by |
||
722 | the Module. The Module simply handles all the Soft Task Models |
||
723 | that specify a periodicity equal to APERIODIC, ignoring each |
||
724 | additional parameters. This function sets the \texttt{nact} field |
||
725 | on the new task according to the requirements of the task model. |
||
726 | The function does not set the flag \texttt{CONTROL\_CAP}. |
||
727 | |||
728 | %---------------------------------------------------------------------------- |
||
729 | \subsubsection{\texttt{void PS\_public\_detach(LEVEL l, PID p);}} |
||
730 | %---------------------------------------------------------------------------- |
||
731 | |||
732 | This function does nothing, because in the |
||
733 | \texttt{PS\_public\_create} function no dynamic data structures |
||
734 | were allocated, and because the tasks served by do not require |
||
735 | individual guarantee (the guarantee is done for the whole Server). |
||
736 | |||
737 | %---------------------------------------------------------------------------- |
||
738 | \subsubsection{\texttt{int PS\_public\_eligible(LEVEL l, PID p);}} |
||
739 | %---------------------------------------------------------------------------- |
||
740 | |||
741 | The function always returns 0 because the PS tasks are always |
||
742 | eligible. |
||
743 | |||
744 | %---------------------------------------------------------------------------- |
||
745 | \subsubsection{\texttt{void PS\_public\_dispatch(LEVEL l, PID p, int nostop);}} |
||
746 | %---------------------------------------------------------------------------- |
||
747 | |||
748 | A task can be dispatched if it is in the wait queue or if it is |
||
749 | inserted into the Master Module. |
||
750 | |||
751 | In the first case the task is extracted from the \texttt{wait} |
||
752 | queue, in the latter case the private function |
||
753 | \texttt{private\_dispatch} is called to signal to the Master |
||
754 | Module to dispatch the task. |
||
755 | |||
756 | Then, a capacity event is generated (only if the parameter |
||
757 | \texttt{nostop} is \texttt{0} (the parameter is 0 if there is no |
||
758 | substitution due to the shadow chain mechanism). The capacity |
||
759 | event is created using the \texttt{cap\_timer} field. In this way |
||
760 | the event will be removed by the Generic Kernel. |
||
761 | |||
762 | %---------------------------------------------------------------------------- |
||
763 | \subsubsection{\texttt{void PS\_public\_epilogue(LEVEL l, PID p);}} |
||
764 | %---------------------------------------------------------------------------- |
||
765 | |||
766 | This function implements the suspension of the running task due to |
||
767 | a preemption or a capacity exhaustion. |
||
768 | |||
769 | First, the function updates the server capacity using the |
||
770 | \texttt{cap\_lasttime} and \texttt{schedule\_time} variables. If |
||
771 | the server capacity is exhausted, the task that is inserted into |
||
772 | the Master Module (if the task is not scheduled in background) |
||
773 | terminates with a \texttt{private\_extract}, and then it is |
||
774 | inserted in the wait queue. |
||
775 | |||
776 | If the server capacity is not exhausted, there are two cases: if |
||
777 | the Module is scheduling a task in background, the task will be |
||
778 | inserted on the head of the wait queue, otherwise the |
||
779 | \texttt{private\_epilogue} function will be called to signal the |
||
780 | Master Module a task preemption. |
||
781 | |||
782 | %---------------------------------------------------------------------------- |
||
783 | \subsubsection{\texttt{void PS\_public\_activate(LEVEL l, PID p);}} |
||
784 | %---------------------------------------------------------------------------- |
||
785 | |||
786 | This function activates a task. If the task passed as parameter is |
||
787 | the task currently inserted in the Master Module, or if the task |
||
788 | is already inserted into the \texttt{wait} queue, the activation |
||
789 | is stored and the nact field is incremented (only if the task has |
||
790 | specified in the task model passed at its creation to save the |
||
791 | activations). |
||
792 | |||
793 | Otherwise the normal activation actions are done: |
||
794 | |||
795 | \begin{itemize} |
||
796 | \item the field \texttt{request\_time} of the task descriptor is |
||
797 | updated; \item The task is activated using the internal |
||
798 | \texttt{PS\_activation} function if there aren't tasks in the |
||
799 | Module and the server capacity is positive, otherwise the task is |
||
800 | queued into the wait queue. |
||
801 | \end{itemize} |
||
802 | |||
803 | %---------------------------------------------------------------------------- |
||
804 | \subsubsection{\texttt{void PS\_public\_block(LEVEL l, PID p);}} |
||
805 | %---------------------------------------------------------------------------- |
||
806 | |||
807 | The function should implement the synchronization blocking. The |
||
808 | function should block the whole server, calling eventually the |
||
809 | \texttt{private\_extract} guest call on the Master Module and |
||
810 | setting the \texttt{PS\_BACKGROUND\_BLOCK} flag to block every |
||
811 | background schedule. |
||
812 | |||
813 | %---------------------------------------------------------------------------- |
||
814 | \subsubsection{\texttt{void PS\_public\_unblock(LEVEL l, PID p);}} |
||
815 | %---------------------------------------------------------------------------- |
||
816 | |||
817 | The function should reactivate a blocked task. The task |
||
818 | reactivation consists of its insertion into the \texttt{wait} |
||
819 | queue and of the reset of the flags set in the |
||
820 | \texttt{public\_block} function. |
||
821 | |||
822 | %---------------------------------------------------------------------------- |
||
823 | \subsubsection{\texttt{int PS\_public\_endcycle(LEVEL l, PID p, void *m);}} |
||
824 | %---------------------------------------------------------------------------- |
||
825 | |||
826 | The function implement the task\_endcycle behavior and does the |
||
827 | following steps: |
||
828 | |||
829 | \begin{itemize} |
||
830 | |||
831 | \item The server capacity is updated, or the background scheduling |
||
832 | feature is disabled if it was active; |
||
833 | |||
834 | \item The task was extracted |
||
835 | from the Master Module through a call to the private function |
||
836 | \texttt{private\_extract}, otherwise it is extracted from the |
||
837 | \texttt{wait} queue; |
||
838 | |||
839 | \item If the task has some pending |
||
840 | activations, it is inserted at the end of the \texttt{wait} queue, |
||
841 | otherwise the task state is set to \texttt{SLEEP}. |
||
842 | |||
843 | \item If |
||
844 | possible a new task is extracted from the top of the \texttt{wait} |
||
845 | queue, through a call to the function \texttt{PS\_activation}; |
||
846 | \end{itemize} |
||
847 | |||
848 | %---------------------------------------------------------------------------- |
||
849 | \subsubsection{\texttt{void PS\_public\_end(LEVEL l, PID p);}} |
||
850 | %---------------------------------------------------------------------------- |
||
851 | |||
852 | The function directly insert the task into the \texttt{freedesc} |
||
853 | queue. |
||
854 | |||
855 | %---------------------------------------------------------------------------- |
||
856 | \subsection{Private functions} |
||
857 | %---------------------------------------------------------------------------- |
||
858 | |||
859 | The private functions are not defined (the defaults are used). |
||
860 | |||
861 | %---------------------------------------------------------------------------- |
||
862 | \subsection{Functions exported by the Module} |
||
863 | %---------------------------------------------------------------------------- |
||
864 | |||
865 | Finally, the PS Module exports two functions that can be used by |
||
866 | the user. |
||
867 | |||
868 | The first function is the registration function, used to register |
||
869 | the Module in the system and to init the internal data structures. |
||
870 | This function registers also a initialization function that posts |
||
871 | the first server deadline event. This event cannot be created in |
||
872 | the registration function because the registration function is |
||
873 | called when the OS Lib is not initialized yet. |
||
874 | |||
875 | The second function, \texttt{PS\_usedbandwidth}, can be used to |
||
876 | obtain the allocated bandwidth of the Module, and it is similar to |
||
877 | the function \texttt{EDF\_usedbandwidth}. |
||
878 | |||
879 | |||
880 | %---------------------------------------------------------------------------- |
||
881 | \section{PI (Priority Inheritance) Resource Module} |
||
882 | %---------------------------------------------------------------------------- |
||
883 | |||
884 | In this Section an implementation of the shared resource access |
||
885 | protocol Priority Inheritance (PI) \cite{Sha90} is described; it |
||
886 | has the following characteristics: |
||
887 | |||
888 | \begin{itemize} |
||
889 | \item support for the Generic Kernel mutex interface; |
||
890 | |||
891 | \item use of |
||
892 | the shadow mechanism provided by the Generic Kernel; |
||
893 | |||
894 | \item |
||
895 | independence from the data structures used internally by the |
||
896 | Scheduling Modules; |
||
897 | |||
898 | \item possibility of a static initialization |
||
899 | of the used mutexes. |
||
900 | \end{itemize} |
||
901 | |||
902 | The Module is contained in \texttt{modules/pi}. |
||
903 | |||
904 | %---------------------------------------------------------------------------- |
||
905 | \subsection{Used approach} |
||
906 | %---------------------------------------------------------------------------- |
||
907 | |||
908 | The key idea of the implementation are: |
||
909 | |||
910 | \begin{itemize} |
||
911 | \item when a task enters into a critical section locking a mutex, |
||
912 | the Module registers which is the task that owns the mutex, |
||
913 | because it is used if other tasks try to lock the mutex, and |
||
914 | because only that task can unlock it; |
||
915 | |||
916 | \item the Module registers |
||
917 | the number of mutexes that owns the tasks, to check that the task |
||
918 | does not die with some mutexes locked. |
||
919 | |||
920 | \item when a task tries to |
||
921 | block a busy mutex, its shadow pointer will be set to the blocking |
||
922 | task; |
||
923 | |||
924 | \item when a mutex is unlocked, all the task blocked by it |
||
925 | are freed, so all the blocked tasks can try to acquire the mutex |
||
926 | (the mutex will be locked by the first task blocked scheduled, |
||
927 | usually the higher priority task that was blocked); |
||
928 | \end{itemize} |
||
929 | |||
930 | %---------------------------------------------------------------------------- |
||
931 | \subsection{Private data structures} |
||
932 | %---------------------------------------------------------------------------- |
||
933 | |||
934 | The PI Module defines the structure \texttt{mutex\_resource\_des} |
||
935 | that handle the interface exported by the Resource Modules. The |
||
936 | private data structures added by the Module to the interface are |
||
937 | the following: |
||
938 | |||
939 | \begin{description} |
||
940 | \item [\texttt{nlocked}]this array stores the number of mutexes |
||
941 | that each task currently locks; |
||
942 | |||
943 | \item [\texttt{blocked}]this array |
||
944 | is used to track the blocked tasks on a mutex. Each PI mutex has a |
||
945 | pointer to the first blocked task; the other tasks are queued in |
||
946 | this structure (look at Figure\ref{Examples_PI_blocked}). The data |
||
947 | structure can be allocated locally to the Module because a task |
||
948 | can be blocked on only one |
||
949 | mutex. |
||
950 | |||
951 | \begin{figure} |
||
952 | \begin{center} |
||
953 | \includegraphics[width=1.0\columnwidth]{images/example_PI_blocked.eps} |
||
954 | \end{center} |
||
955 | \label{Examples_PI_blocked} |
||
956 | \caption{Use of the \texttt{blocked} array. The example describes a structure |
||
957 | \texttt{mutex\_t} initialized with the Priority Inheritance protocol. The field |
||
958 | \texttt{firstblocked} is the first element of the blocked task queue on a |
||
959 | specific mutex.} |
||
960 | \end{figure} |
||
961 | |||
962 | \end{description} |
||
963 | |||
964 | Each mutex handled by the Priority Inheritance protocol uses a |
||
965 | dynamically allocated internal data structure called |
||
966 | \texttt{PI\_mutex\_t}, that has the following fields: |
||
967 | |||
968 | \begin{description} |
||
969 | \item [\texttt{owner}]When the mutex is free this field is |
||
970 | \texttt{NIL}, else it is the PID of the task that locks the mutex; |
||
971 | |||
972 | \item [\texttt{nblocked}]This is the number of tasks actually |
||
973 | blocked on a mutex; |
||
974 | |||
975 | \item [\texttt{firstblocked}]When the field |
||
976 | \texttt{nblocked} is different from 0 this field is the first task |
||
977 | blocked on a mutex (the following tasks can be found following the |
||
978 | blocked list ). |
||
979 | \end{description} |
||
980 | |||
981 | Finally, to init a PI mutex, a correct parameter must be passed to |
||
982 | \texttt{mutex\_init}. That parameter must be of type |
||
983 | \texttt{PI\_mutexattr\_t} and it does not add any other parameter |
||
984 | to the default attribute. |
||
985 | |||
986 | %---------------------------------------------------------------------------- |
||
987 | \subsection{Internal and Interface Functions} |
||
988 | %---------------------------------------------------------------------------- |
||
989 | |||
990 | %---------------------------------------------------------------------------- |
||
991 | \subsubsection{\texttt{int PI\_res\_register(RLEVEL l, PID p, RES\_MODEL *r);}} |
||
992 | %---------------------------------------------------------------------------- |
||
993 | |||
994 | This function always return -1 because it will never be called by |
||
995 | the Generic Kernel (because the Module does not accept any |
||
996 | Resource Model). |
||
997 | |||
998 | %---------------------------------------------------------------------------- |
||
999 | \subsubsection{\texttt{void PI\_res\_detach(RLEVEL l, PID p);}} |
||
1000 | %---------------------------------------------------------------------------- |
||
1001 | |||
1002 | This function simply controls that the task that is still ending |
||
1003 | does not lock any mutexes. If not, an exception is raised. Such a |
||
1004 | situation is very dangerous because, when a task is died, the |
||
1005 | shadow data structures are not consistent, and this will probably |
||
1006 | cause a system crash. |
||
1007 | |||
1008 | %---------------------------------------------------------------------------- |
||
1009 | \subsubsection{\texttt{int PI\_init(RLEVEL l, mutex\_t *m, const mutexattr\_t *a);}} |
||
1010 | %---------------------------------------------------------------------------- |
||
1011 | |||
1012 | This function inits a mutex to be used with the PI Protocol. A |
||
1013 | structure of type \texttt{PI\_mutex\_t} is allocated and all the |
||
1014 | fields are initialized.. |
||
1015 | |||
1016 | |||
1017 | %---------------------------------------------------------------------------- |
||
1018 | \subsubsection{\texttt{int PI\_destroy(RLEVEL l, mutex\_t *m);}} |
||
1019 | %---------------------------------------------------------------------------- |
||
1020 | |||
1021 | This function should destroy a mutex. The mutex has to be |
||
1022 | correctly initialized and it must be free (not locked by a task). |
||
1023 | |||
1024 | %---------------------------------------------------------------------------- |
||
1025 | \subsubsection{\texttt{int PI\_lock(RLEVEL l, mutex\_t *m);}} |
||
1026 | %---------------------------------------------------------------------------- |
||
1027 | |||
1028 | This function should implement a mutex lock. First, a check is |
||
1029 | done to see if the mutex was initializated statically. In that |
||
1030 | case, the initialization of the data structures is completed. |
||
1031 | |||
1032 | At this point, a check is done to see if the task already owns the |
||
1033 | mutex. If not, a cycle is done. In the body the shadow field is |
||
1034 | set, and the system is rescheduled. The cycle is needed because |
||
1035 | when the mutex will be unlocked, all the blocked tasks will be |
||
1036 | woken up to fight for the locking of the mutex. |
||
1037 | |||
1038 | Finally, When the mutex will be found free, it is locked. |
||
1039 | |||
1040 | %---------------------------------------------------------------------------- |
||
1041 | \subsubsection{\texttt{int PI\_trylock(RLEVEL l, mutex\_t *m);}} |
||
1042 | %---------------------------------------------------------------------------- |
||
1043 | |||
1044 | This function is similar to the previous one, except that the task |
||
1045 | is never blocked if the mutex is busy. |
||
1046 | |||
1047 | %---------------------------------------------------------------------------- |
||
1048 | \subsubsection{\texttt{int PI\_unlock(RLEVEL l, mutex\_t *m);}} |
||
1049 | %---------------------------------------------------------------------------- |
||
1050 | |||
1051 | This function should free the mutex. First, a check is done to see |
||
1052 | if the task that unlocks really owns the mutex. Then, the mutex is |
||
1053 | unlocked and all the blocked tasks are woken up (the shadow field |
||
1054 | is reset to point to the blocked tasks themselves). Then, the |
||
1055 | system is rescheduled to see if a preemption should be done (the |
||
1056 | Module does not know if a preemption will occurs or not, because |
||
1057 | it does not know which are the modules registered!). |
||
1058 | |||
1059 | %---------------------------------------------------------------------------- |
||
1060 | \subsubsection{\texttt{void PI\_register\_module(void);}} |
||
1061 | %---------------------------------------------------------------------------- |
||
1062 | |||
1063 | This function will register the Module in the system. This |
||
1064 | function is very similar to the Scheduling Modules Registration |
||
1065 | function. |