Rev 1676 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1676 | tullio | 1 | %---------------------------------------------------------------------------- |
2 | \chapter{Synchronization and communication} |
||
3 | %---------------------------------------------------------------------------- |
||
4 | |||
5 | This chapter describes the task's interaction capabilities provided by the |
||
6 | S.Ha.R.K. kernel. In order to improve the programming flexibility without |
||
7 | jeopardizing the hard tasks' a priori guarantee, the kernel implements different |
||
8 | mechanisms. |
||
9 | |||
10 | In general, hard tasks should not use system calls that can cause an unbounded |
||
11 | (or unknown) blocking time, since they can jeopardize the system schedulability. |
||
12 | |||
13 | \begin{figure} |
||
14 | \begin{center}\includegraphics{over.eps}\end{center} |
||
15 | \caption{EDF Scheduling - Overload due to a task\_delay().} |
||
16 | \label{fg:semaf-over} |
||
17 | \end{figure} |
||
18 | |||
19 | For example, consider Figure~\ref{fg:semaf-over}: in this case there are two |
||
20 | periodic tasks, $\tau_{1}$ (execution time $C_{1}=5$ and period $T_{1}=15$) and |
||
21 | $\tau_{2}$ (execution time $C_{2}=2$ and period $T_{2}=4$). Since the total |
||
22 | utilization factor is $U=1/2+1/3=5/6<1$, the system is schedulable by EDF, but |
||
23 | if $\tau_{1}$ blocks for $8$ time units at time $t=4$, $\tau_{2}$ misses a |
||
24 | deadline at time $t=16$. |
||
25 | |||
26 | For efficiency reasons, the system does not perform any check to avoid the use |
||
27 | of blocking primitives in hard tasks; so this aspect is left to the programmer |
||
28 | responsibility. |
||
29 | |||
30 | %---------------------------------------------------------------------------- |
||
31 | \section{POSIX Semaphores} |
||
32 | %---------------------------------------------------------------------------- |
||
33 | |||
34 | The primitives described in this Section covers the semaphore mechanism |
||
35 | interface that can be used by the S.Ha.R.K. applications. The semaphore |
||
36 | interface directly follows the POSIX semaphore interface; the S.Ha.R.K. Kernel |
||
37 | add also some other primitives that allows to increment/decrement the semaphore |
||
38 | counter by more than one unit at a time. |
||
39 | |||
40 | These primitives can be used both for synchronization and mutual exclusion. It |
||
41 | is worth noting that the traditional semaphore mechanism can cause unbounded |
||
42 | \emph{priority inversion}, so it is not suitable for hard real-time tasks. |
||
43 | Concerning the synchronization, we note that the guarantee mechanism does not |
||
44 | take synchronization into account; therefore the programmer should avoid to |
||
45 | explicitly synchronize hard tasks by means of blocking primitives. It is instead |
||
46 | possible to use a weak synchronization between hard real-time tasks, realized |
||
47 | through non-blocking semaphores. |
||
48 | |||
49 | Only \texttt{SEM\_NSEMS\_MAX} semaphores can be created in the system. If an |
||
50 | application needs to use the POSIX semaphores, it have to add the call to the |
||
51 | function |
||
52 | |||
53 | \texttt{void SEM\_register\_module(void);} |
||
54 | |||
55 | into the \texttt{\_\_kernel\_register\_levels\_\_} function of the |
||
56 | initialization file (see Volume III - S.Ha.R.K. Modules). |
||
57 | |||
58 | In this section will be briefly described the POSIX semaphore interface |
||
59 | \footnote{This section only described unnamed semaphores. The interface for |
||
60 | named semaphores is also provided, althoutgh it does not use a file system but |
||
61 | resolve the names internally (as allowed by the POSIX 1003.13 PSE51 profile).}. |
||
62 | For a complete reference see the POSIX standard (the Linux manpage also works |
||
63 | well). |
||
64 | |||
65 | %---------------------------------------------------------------------------- |
||
66 | \begin{intest} |
||
67 | SEM\_INIT\index{sem\_init()} |
||
68 | \end{intest} |
||
69 | |||
70 | \begin{description} |
||
71 | |||
72 | \item [\textbf{int sem\_init(sem\_t {*}sem, int pshared, unsigned int value);}] |
||
73 | |||
74 | \item [\textbf{Description:}] It is used to initialize a semaphore referred by |
||
75 | sem. The value of the initialized semaphore is \texttt{value}. The pshared |
||
76 | argument is ignored. After the call to the primitive, the sem value can bve used |
||
77 | to refer the semaphore. |
||
78 | |||
79 | \item [\textbf{Return value:}] on successful completion, the function |
||
80 | initializes the semaphore in sem and returns 0. Otherwise, it returns -1 and |
||
81 | \texttt{errno} is set according to the POSIX standard. |
||
82 | |||
83 | \item [\textbf{See also}:] sem\_wait(), sem\_trywait, sem\_post(), |
||
84 | sem\_destroy(). |
||
85 | |||
86 | \end{description} |
||
87 | |||
88 | \begin{description} |
||
89 | \item \texttt{[Example]} |
||
90 | \end{description} |
||
91 | |||
92 | \begin{verbatim} |
||
93 | sem_t mutex; |
||
94 | |||
95 | TASK demo(void *arg) { |
||
96 | ... |
||
97 | |||
98 | /* The task enters a critical section protected by a mutex semaphore */ |
||
99 | sem_wait(&mutex); |
||
100 | <critical section> |
||
101 | sem_post(&mutex); |
||
102 | ... |
||
103 | } |
||
104 | |||
105 | int main(int argc, char**argv) { |
||
106 | ... |
||
107 | sem_init(&mutex, 0, 1); |
||
108 | ... |
||
109 | } |
||
110 | \end{verbatim} |
||
111 | |||
112 | %---------------------------------------------------------------------------- |
||
113 | \begin{intest} |
||
114 | SEM\_DESTROY\index{sem\_destroy()} |
||
115 | \end{intest} |
||
116 | |||
117 | \begin{description} |
||
118 | |||
119 | \item [\textbf{int sem\_destroy(sem\_t {*}sem);}] |
||
120 | |||
121 | \item [\textbf{Description:}] It is used to destroy the semaphore indicated by |
||
122 | sem. Only a semaphore that was created using sem\_init() may be destroyed using |
||
123 | sem\_destroy(). \textbf{Warning}: This system call does not check if the |
||
124 | semaphore queue is empty or not, and does not awake tasks blocked on the |
||
125 | semaphore. The programmer has to make sure that \texttt{s} is free before |
||
126 | destroying it. |
||
127 | |||
128 | \item [\textbf{Return value}:] on successful completion, the function destroys |
||
129 | the sem semaphore and returns 0. Otherwise, it returns -1 and \texttt{errno} is |
||
130 | set according to the POSIX standard. |
||
131 | |||
132 | \item [\textbf{See also}:] sem\_init(). |
||
133 | |||
134 | \end{description} |
||
135 | |||
136 | %---------------------------------------------------------------------------- |
||
137 | \begin{intest} |
||
138 | SEM\_WAIT\index{sem\_wait()} and SEM\_TRYWAIT\index{sem\_trywait()} |
||
139 | \end{intest} |
||
140 | |||
141 | \begin{description} |
||
142 | |||
143 | \item [\textbf{int sem\_wait(sem\_t {*}sem);}] |
||
144 | |||
145 | \item [\textbf{int sem\_trywait(sem\_t {*}sem);}] |
||
146 | |||
147 | \item [\textbf{Description:}] is used to lock the semaphore referenced by |
||
148 | \texttt{sem}. If the semaphore value is currently zero, then the calling task |
||
149 | shall not return from the call to \texttt{sem\_wait}() until it either locks the |
||
150 | semaphore. \texttt{sem\_trywait} locks the semaphore referenced by \texttt{sem} |
||
151 | only if the semaphore is currently not locked; that is, if the semaphore value |
||
152 | is currently positive. Otherwise, it does not lock the semaphore. |
||
153 | \texttt{sem\_wait} is a cancellation point. |
||
154 | |||
155 | \item [\textbf{Return value:}] on successful completion the functions return 0. |
||
156 | Otherwise, they return -1 and \texttt{errno} is set according to the POSIX |
||
157 | standard. |
||
158 | |||
159 | \item [\textbf{See also}:] sem\_post(). |
||
160 | |||
161 | \end{description} |
||
162 | |||
163 | %---------------------------------------------------------------------------- |
||
164 | \begin{intest} |
||
165 | SEM\_XWAIT\index{sem\_wait()} |
||
166 | \end{intest} |
||
167 | |||
168 | \begin{description} |
||
169 | |||
170 | \item [\textbf{BYTE sem\_xwait(sem\_t {*}s, int n, int wait);}] |
||
171 | |||
172 | \item [Description:]\texttt{sem\_xwait()} is a non-portable extension to the |
||
173 | POSIX semaphores that decreases the semaphore counter by \texttt{n}. If the |
||
174 | counter is greater than or equal to \texttt{n} and there are no tasks blocked on |
||
175 | semaphore \texttt{s}, the counter is decreased by \texttt{n} and |
||
176 | \texttt{sem\_xwait} returns 0, otherwise the system call's behavior depends on |
||
177 | the \texttt{b} parameter. If \texttt{wait} is \texttt{BLOCK}, the calling task |
||
178 | blocks on the semaphore, if \texttt{wait} is \texttt{NON\_BLOCK} |
||
179 | \texttt{sem\_xwait} returns -1, errno is set to EAGAIN and the calling task does |
||
180 | not block. The semaphore queue is ordered using a FIFO strategy, in order to |
||
181 | avoid starvation. Hard tasks should not use blocking system calls, so it is |
||
182 | suggested to use \texttt{sem\_trywait()/xwait()} (only with \texttt{b = |
||
183 | NON\_BLOCK}). \texttt{sem\_xwait} is a cancellation point. |
||
184 | |||
185 | \item [\textbf{Return value:}] on successful completion, the function returns 0. |
||
186 | Otherwise, it returns -1 and \texttt{errno} is set according to the POSIX |
||
187 | standard. |
||
188 | |||
189 | \item [\textbf{See also}:] sem\_wait(), sem\_trywait(), sem\_post(). |
||
190 | |||
191 | \end{description} |
||
192 | |||
193 | \begin{description} |
||
194 | \item [\textbf{Example:}] |
||
195 | \end{description} |
||
196 | |||
197 | \begin{verbatim} |
||
198 | sem_t sync; |
||
199 | |||
200 | TASK demo(void *arg) { |
||
201 | ... |
||
202 | /* The demo task synchronizes itself */ |
||
203 | /* with the wake task, waiting */ |
||
204 | /* for 5 signals on the sync semaphore */ |
||
205 | sem_xwait(&sync, 5, BLOCK); |
||
206 | ... |
||
207 | } |
||
208 | |||
209 | TASK wake(void *arg) { |
||
210 | while (1) { |
||
211 | ... |
||
212 | sem_xsignal(sync, 1); |
||
213 | ... |
||
214 | task_endcycle(); |
||
215 | } |
||
216 | } |
||
217 | |||
218 | void main(void) { |
||
219 | ... |
||
220 | sem_init(&sync, 0, 0); |
||
221 | ... |
||
222 | } |
||
223 | \end{verbatim} |
||
224 | |||
225 | %---------------------------------------------------------------------------- |
||
226 | \begin{intest} |
||
227 | SEM\_POST\index{sem\_post()} |
||
228 | \end{intest} |
||
229 | |||
230 | \begin{description} |
||
231 | |||
232 | \item [\textbf{int sem\_post(sem\_t {*}sem);}] |
||
233 | |||
234 | \item [\textbf{Description:}]It unlocks the semaphore referenced by sem by |
||
235 | performing the semaphore unlock operation on that semaphore. If the semaphore |
||
236 | queue is not empty and the first task in the queue requests a feasible counter |
||
237 | decrement, it can be awaken. The task is put in the ready queue and the |
||
238 | scheduler is invoked: for this reason this system call can cause a preemption. |
||
239 | The semaphore queue is a FIFO queue: tasks are awoken in a FIFO order according |
||
240 | to resource availability. |
||
241 | |||
242 | \item [\textbf{Return value:}] on successful completion, the function destroys |
||
243 | the sem semaphore and returns 0. Otherwise, it returns -1 and \texttt{errno} is |
||
244 | set according to the POSIX standard. |
||
245 | |||
246 | \item [\textbf{See also}:] sem\_wait(), sem\_trywait(). |
||
247 | |||
248 | \end{description} |
||
249 | |||
250 | %---------------------------------------------------------------------------- |
||
251 | \begin{intest} |
||
252 | SEM\_XPOST\index{sem\_xpost()} |
||
253 | \end{intest} |
||
254 | |||
255 | \begin{description} |
||
256 | |||
257 | \item [\textbf{int sem\_xpost(sem\_t {*}s, int n);}] |
||
258 | |||
259 | \item [\textbf{Description:}]\texttt{sem\_xpost()} is a non-portable extension |
||
260 | to the POSIX semaphores that implements the classical signal primitive on |
||
261 | semaphore \texttt{s}, increasing the counter by \texttt{n}. If the semaphore |
||
262 | queue is not empty and the first task in the queue requests a feasible counter |
||
263 | decrement, it can be awaken. The task is put in the \texttt{READY} queue and the |
||
264 | scheduler is invoked: for this reason this system call can cause a preemption. |
||
265 | The semaphore queue is a FIFO queue: tasks are awoken in a FIFO order according |
||
266 | to resource availability. |
||
267 | |||
268 | \item [\textbf{Return value:}] on successful completion, the function destroys |
||
269 | the sem semaphore and returns 0. Otherwise, it returns -1 and \texttt{errno} is |
||
270 | set according to the POSIX standard. |
||
271 | |||
272 | \item [\textbf{See also}:] \texttt{sem\_init(), sem\_wait(), sem\_destroy()}. |
||
273 | |||
274 | \item [Example:]see \texttt{sem\_wait()}. |
||
275 | |||
276 | \end{description} |
||
277 | |||
278 | %---------------------------------------------------------------------------- |
||
279 | \begin{intest} |
||
280 | SEM\_GETVALUE\index{sem\_getvalue()} |
||
281 | \end{intest} |
||
282 | |||
283 | \begin{description} |
||
284 | |||
285 | \item [\textbf{int sem\_getvalue(sem\_t {*}sem, int {*}sval);}] |
||
286 | |||
287 | \item [\textbf{Description:}]\texttt{sem\_getvalue()} updates the location |
||
288 | referenced by the sval argument to have the value of the semaphore referenced by |
||
289 | sem without affecting the state of the semaphore. If sem is locked the value |
||
290 | returned by sem\_getvalue is a negative number whose absolute value represents |
||
291 | the number of processes waiting for the semaphore at some unspecified time |
||
292 | during the call. |
||
293 | |||
294 | \item [\textbf{Return value:}] on successful completion, the function destroys |
||
295 | the sem semaphore and returns 0. Otherwise, it returns -1 and \texttt{errno} is |
||
296 | set according to the POSIX standard. |
||
297 | |||
298 | \item [\textbf{See also}:] \texttt{sem\_init(), sem\_wait(), sem\_destroy()}. |
||
299 | |||
300 | \end{description} |
||
301 | |||
302 | %---------------------------------------------------------------------------- |
||
303 | \section{Internal Semaphores} |
||
304 | %---------------------------------------------------------------------------- |
||
305 | |||
306 | When developing a complex driver of the kernel, a designer usually needs to |
||
307 | manage a lot of shared resources that have to be accessed in mutual exclusion, |
||
308 | and needs also a lot of synchronization points that are not cancellation points. |
||
309 | For these pourposes the POSIX semaphores are not good because they are limited |
||
310 | in number and they are cancellation points. |
||
311 | |||
312 | For this pourpose the S.Ha.R.K. Kernel provides a sort of lightweight semaphores |
||
313 | called \emph{internal} semaphores, that fulfill the designer needs \footnote{The |
||
314 | existence of two type of semaphores is not new in Kernel development; For |
||
315 | example, the Linux Kernel differentiate the semaphores used by the applications |
||
316 | and the semaphors used by the Kernel.}: they are not cancellation points and |
||
317 | there is no limit on the number of semaphores that can be created in a system |
||
318 | \footnote{Only 8 bytes are taken for each internal semaphore. In some sense the |
||
319 | internal semaphores are similar to the POSIX mutexes...}. The interface of the |
||
320 | Internal semaphores is very similar to POSIX semaphore interface. |
||
321 | |||
322 | To use the Internal Semaphores, you don't need to call any registration function |
||
323 | at kernel startup time. |
||
324 | |||
325 | %---------------------------------------------------------------------------- |
||
326 | \begin{intest} |
||
327 | INTERNAL\_SEM\_INIT\index{internal\_sem\_init()} |
||
328 | \end{intest} |
||
329 | |||
330 | \begin{description} |
||
331 | |||
332 | \item [\textbf{void internal\_sem\_init(internal\_sem\_t {*}s, int value);}] |
||
333 | |||
334 | \item [\textbf{Description:}]It initializes the internal semaphore \texttt{s} |
||
335 | with a specified \texttt{value}. |
||
336 | |||
337 | \end{description} |
||
338 | |||
339 | %---------------------------------------------------------------------------- |
||
340 | \begin{intest} |
||
341 | INTERNAL\_SEM\_WAIT\index{internal\_sem\_wait()} |
||
342 | \end{intest} |
||
343 | |||
344 | \begin{description} |
||
345 | |||
346 | \item [\textbf{void internal\_sem\_wait(internal\_sem\_t {*}s);}] |
||
347 | |||
348 | \item [\textbf{Description:}]It implements a blocking wait. the semaphore |
||
349 | counter is decremented by one. |
||
350 | |||
351 | \end{description} |
||
352 | |||
353 | %---------------------------------------------------------------------------- |
||
354 | \begin{intest} |
||
355 | INTERNAL\_SEM\_TRYWAIT\index{internal\_sem\_trywait()} |
||
356 | \end{intest} |
||
357 | |||
358 | \begin{description} |
||
359 | |||
360 | \item [\textbf{int internal\_sem\_trywait(internal\_sem\_t {*}s);}] |
||
361 | |||
362 | \item [\textbf{Description:}]It implements a non-blocking wait. It returns 0 if |
||
363 | the counter is decremented, -1 if not. |
||
364 | |||
365 | \end{description} |
||
366 | |||
367 | %---------------------------------------------------------------------------- |
||
368 | \begin{intest} |
||
369 | INTERNAL\_SEM\_POST\index{internal\_sem\_post()} |
||
370 | \end{intest} |
||
371 | |||
372 | \begin{description} |
||
373 | |||
374 | \item [\textbf{void internal\_sem\_post(internal\_sem\_t {*}s);}] |
||
375 | |||
376 | \item [\textbf{Description:}]It implements a post operation. |
||
377 | |||
378 | \end{description} |
||
379 | |||
380 | %---------------------------------------------------------------------------- |
||
381 | \begin{intest} |
||
382 | INTERNAL\_SEM\_GETVALUE\index{internal\_sem\_getvalue()} |
||
383 | \end{intest} |
||
384 | |||
385 | \begin{description} |
||
386 | |||
387 | \item [\textbf{int internal\_sem\_getvalue(internal\_sem\_t {*}s);}] |
||
388 | |||
389 | \item [\textbf{Description:}]It returns a value greater or equal 0 if there are |
||
390 | no tasks blocked on s, -1 otherwise. |
||
391 | |||
392 | \end{description} |
||
393 | |||
394 | %---------------------------------------------------------------------------- |
||
395 | \section{Mutexes and Condition Variables} |
||
396 | %---------------------------------------------------------------------------- |
||
397 | |||
398 | The primitives described in this section allows the user to define and use |
||
399 | \emph{mutexes} and \emph{condition variables}. A mutex can be thought as a |
||
400 | binary semaphore initialized to 1. In that way, a critical section can be |
||
401 | specified using the \emph{mutex\_lock} and \emph{mutex\_unlock} primitives. |
||
402 | Moreover, using condition variables a task can block itself waiting for an |
||
403 | event. |
||
404 | |||
405 | The provided implementation extends the POSIX standard mutex functions |
||
406 | implementing protocols like Stack Resource Policy and Non Preemptive |
||
407 | Protocol, that are not part of the standard. To do that, the mutex |
||
408 | initialization interface is different from the standard to allow the |
||
409 | specification of the various policies. In any case, the standard interface |
||
410 | is provided based on the extended interface. |
||
411 | |||
412 | %---------------------------------------------------------------------------- |
||
413 | \subsection{Mutex attributes} |
||
414 | %---------------------------------------------------------------------------- |
||
415 | |||
416 | A mutex can be used to implement critical sections that uses different |
||
417 | policies (for example, the Priority Inheritance, Priority Ceiling |
||
418 | or Stack Resource Policy protocol). The S.Ha.R.K. Kernel provides |
||
419 | a set of structures derived from the basic structure mutexattr\_t |
||
420 | \footnote{Similar to the pthread\_mutexattr\_t structures of the POSIX |
||
421 | standard.} that allow to handle the specification of different policies. |
||
422 | |||
423 | The mutex attributes are different foe every policy, that is implemented |
||
424 | by a Resouce Module. To see the the description of the mutex attributes |
||
425 | for every policy, look at the S.Ha.R.K. Modules Manual. |
||
426 | |||
427 | %---------------------------------------------------------------------------- |
||
428 | \subsection{Functions} |
||
429 | %---------------------------------------------------------------------------- |
||
430 | |||
431 | This subsection describes the functions that handle mutexes and condition |
||
432 | variables. |
||
433 | |||
434 | %---------------------------------------------------------------------------- |
||
435 | \begin{intest} |
||
436 | MUTEX\_INIT\index{mutex\_init()} |
||
437 | \end{intest} |
||
438 | |||
439 | \begin{description} |
||
440 | |||
441 | \item [\textbf{int mutex\_init(mutex\_t {*}mutex, const mutexattr\_t {*}attr);}] |
||
442 | |||
443 | \item [\textbf{Description:}]The mutex\_init function inituializes the mutex |
||
444 | referenced by \emph{mutex} with attributes specified by \emph{attr}. \emph{attr} |
||
445 | shall be not equal NULL. Upon successful initialization, the state |
||
446 | of the mutex becomes initialized and unlocked. |
||
447 | |||
448 | \item [\textbf{Return value:}] on successful completion the functions return |
||
449 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
450 | the POSIX standard. |
||
451 | |||
452 | \item [\textbf{See also}:] mutex\_destroy(). |
||
453 | |||
454 | \end{description} |
||
455 | |||
456 | %---------------------------------------------------------------------------- |
||
457 | \begin{intest} |
||
458 | MUTEX\_DESTROY\index{mutex\_destroy()} |
||
459 | \end{intest} |
||
460 | |||
461 | \begin{description} |
||
462 | |||
463 | \item [\textbf{int mutex\_destroy(mutex\_t {*}mutex);}] |
||
464 | |||
465 | \item [\textbf{Description:}]The mutex\_destroy function destroys the mutex |
||
466 | object |
||
467 | referenced by mutex. It is safe to destroy an initialize mutex that |
||
468 | is unlocked. |
||
469 | |||
470 | \item [\textbf{Return value:}] on successful completion the functions return |
||
471 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
472 | the POSIX standard. |
||
473 | |||
474 | \item [\textbf{See also}:] mutex\_init(). |
||
475 | |||
476 | \end{description} |
||
477 | |||
478 | %---------------------------------------------------------------------------- |
||
479 | \begin{intest} |
||
480 | MUTEX\_LOCK\index{mutex\_lock()} |
||
481 | \end{intest} |
||
482 | |||
483 | \begin{description} |
||
484 | |||
485 | \item [\textbf{int mutex\_lock(mutex\_t {*}mutex);}] |
||
486 | |||
487 | \item [\textbf{Description:}]The mutex\_lock function locks an unlocked mutex. |
||
488 | If |
||
489 | the mutex is already locked , the calling thread waits until the mutex |
||
490 | becomes available. the behaviour of the function may change depending |
||
491 | on the particular policy passed with the mutexattr\_t parameter at |
||
492 | mutex initialization. The function is \emph{not} a cancellation point. |
||
493 | |||
494 | \item [\textbf{Return value:}] on successful completion the functions return |
||
495 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
496 | the POSIX standard. |
||
497 | |||
498 | \end{description} |
||
499 | |||
500 | \pagebreak |
||
501 | |||
502 | %---------------------------------------------------------------------------- |
||
503 | \begin{intest} |
||
504 | MUTEX\_TRYLOCK\index{mutex\_trylock()} |
||
505 | \end{intest} |
||
506 | |||
507 | \begin{description} |
||
508 | |||
509 | \item [\textbf{int mutex\_lock(mutex\_t {*}mutex);}] |
||
510 | |||
511 | \item [\textbf{Description:}]The mutex\_trylock function is identycal to |
||
512 | mutex\_lock |
||
513 | except that if the mutex us locked when the function is called, the |
||
514 | calling task does not block but returns -1 and an errno value of EBUSY, |
||
515 | as specified by the POSIX standard. |
||
516 | |||
517 | \item [\textbf{Return value:}] on successful completion the functions return |
||
518 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
519 | the POSIX standard. |
||
520 | |||
521 | \end{description} |
||
522 | |||
523 | %---------------------------------------------------------------------------- |
||
524 | \begin{intest} |
||
525 | MUTEX\_UNLOCK\index{mutex\_unlock()} |
||
526 | \end{intest} |
||
527 | |||
528 | \begin{description} |
||
529 | |||
530 | \item [\textbf{int mutex\_unlock(mutex\_t {*}mutex);}] |
||
531 | |||
532 | \item [\textbf{Description:}]The mutex\_unlock function is called by the owner |
||
533 | of |
||
534 | the mutex object to release it. If there are thread blocked on the |
||
535 | mutex object referenced by mutex when mutex\_lock is called, the mutex |
||
536 | becomes available, and the task that will acquire the mutex depends |
||
537 | on the policy with that the mutex was initialized. |
||
538 | |||
539 | \item [\textbf{Return value:}] on successful completion the functions return |
||
540 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
541 | the POSIX standard. |
||
542 | |||
543 | \end{description} |
||
544 | |||
545 | %---------------------------------------------------------------------------- |
||
546 | \begin{intest} |
||
547 | COND\_INIT\index{cond\_init()} |
||
548 | \end{intest} |
||
549 | |||
550 | \begin{description} |
||
551 | |||
552 | \item [\textbf{int cond\_init(cond\_t {*}cond);}] |
||
553 | |||
554 | \item [\textbf{Description:}]The function initializes the condition variable |
||
555 | referenced |
||
556 | by cond. |
||
557 | |||
558 | \item [\textbf{Return value:}] on successful completion the functions return |
||
559 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
560 | the POSIX standard. |
||
561 | |||
562 | \end{description} |
||
563 | |||
564 | %---------------------------------------------------------------------------- |
||
565 | \begin{intest} |
||
566 | COND\_DESTROY\index{cond\_destroy()} |
||
567 | \end{intest} |
||
568 | |||
569 | \begin{description} |
||
570 | |||
571 | \item [\textbf{int cond\_destroy(cond\_t {*}cond);}] |
||
572 | |||
573 | \item [\textbf{Description:}]The function destroys the given condition variable |
||
574 | specified by cond. |
||
575 | |||
576 | \item [\textbf{Return value:}] on successful completion the functions return |
||
577 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
578 | the POSIX standard. |
||
579 | |||
580 | \end{description} |
||
581 | |||
582 | %---------------------------------------------------------------------------- |
||
583 | \begin{intest} |
||
584 | COND\_SIGNAL\index{cond\_signal()} and COND\_BROADCAST\index{cond\_broadcast()} |
||
585 | \end{intest} |
||
586 | |||
587 | \begin{description} |
||
588 | |||
589 | \item [\textbf{int cond\_signal(cond\_t {*}cond);}] |
||
590 | |||
591 | \item [\textbf{int cond\_broadcast(cond\_t {*}cond);}] |
||
592 | |||
593 | \item [\textbf{Description:}]The function cond\_signal unblocks at least one of |
||
594 | the threads that are blocked on the specified condition variable cond. |
||
595 | The function cond\_broadcast unblocks all threads currently blocked |
||
596 | on the specified condition variable cond. These functions have no |
||
597 | effect if there are no threads currently blocked on cond. |
||
598 | |||
599 | \item [\textbf{Return value:}] on successful completion the functions return |
||
600 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
601 | the POSIX standard. |
||
602 | |||
603 | \end{description} |
||
604 | |||
605 | %---------------------------------------------------------------------------- |
||
606 | \begin{intest} |
||
607 | COND\_WAIT\index{cond\_wait()} and COND\_TIMEDWAIT\index{cond\_timedwait()} |
||
608 | \end{intest} |
||
609 | |||
610 | \begin{description} |
||
611 | |||
612 | \item [\textbf{int cond\_wait(cond\_t {*}cond, mutex\_t {*}mutex);}] |
||
613 | |||
614 | \item [\textbf{int cond\_timedwait(cond\_t {*}cond, mutex\_t {*}mutex, |
||
615 | const struct timespec {*}abstime);}] |
||
616 | |||
617 | \item [\textbf{Description:}]These functions are used to block on a condition |
||
618 | variable. |
||
619 | They shall be called with \emph{mutex} locked by the calling task. |
||
620 | These functions release mutex and cause the calling task to block |
||
621 | on the condition variable cond. Upon successful return, the mutex |
||
622 | is locked and is owned by the calling task. When using condition variables, |
||
623 | there is always a Boolean predicate involving shared variables associated |
||
624 | with each condition wait that is true if the thread should proceed. |
||
625 | Spurious wakeups from the \texttt{cond\_wait} or \texttt{cond\_timedwait} |
||
626 | functions may occur. Since the return from \texttt{cond\_wait} or |
||
627 | \texttt{cond\_timedwait} does not imply anything about the value of |
||
628 | this predicate, the predicate should be re-evaluated upon each return. |
||
629 | |||
630 | The \texttt{cond\_wait} and cond\_timedwait functions are cancellation |
||
631 | points. When the cancelability enable state of a task is set to |
||
632 | \texttt{TASK\_CANCEL\_DEFERRED}, |
||
633 | a side effect of acting upon a cancellation request while in a condition |
||
634 | wait is that the mutex is (in effect) reaquired before calling the |
||
635 | first cancellation cleanup handler. To ensure a correct cancellation, |
||
636 | a cleanup function should be pushed before the \texttt{cond\_wait} |
||
637 | call (in case of cancellation it simply unlock the mutex). |
||
638 | |||
639 | The \texttt{cond\_timedwait} function is the same as the \texttt{cond\_wait} |
||
640 | function except that an error is returned if the absolute time specified |
||
641 | by abstime passes before the condition cond is signaled or broadcasted, |
||
642 | or if the absolute time specified by abstime has already been passed |
||
643 | at the time of the call. |
||
644 | |||
645 | \item [\textbf{Return value:}] on successful completion the functions return |
||
646 | 0. Otherwise, they return -1 and \texttt{errno} is set according to |
||
647 | the POSIX standard. |
||
648 | |||
649 | \end{description} |
||
650 | |||
651 | % |
||
652 | % Tool: still in use? |
||
653 | % |
||
654 | |||
655 | % %---------------------------------------------------------------------------- |
||
656 | % \section{Communication Ports \footnote{The S.Ha.R.K. communication ports are |
||
657 | % directly derived from the previous varsions of the Hartik Kernel.}} |
||
658 | % %---------------------------------------------------------------------------- |
||
659 | % |
||
660 | % S.Ha.R.K. communication ports allow tasks to exchange messages. Each |
||
661 | % port is uniquely identified by a symbolic name (i.e., a string of |
||
662 | % characters); a task willing to use this communication facility has |
||
663 | % to open the channel using the \texttt{port\_create()} call, thus becoming |
||
664 | % the owner of the resource. Any other task that wants to use this communication |
||
665 | % end-point to send or receive data needs to connect to it by using |
||
666 | % the \texttt{port\_connect()} primitive. |
||
667 | % |
||
668 | % S.Ha.R.K. offers three types of ports: |
||
669 | % |
||
670 | % \begin{itemize} |
||
671 | % |
||
672 | % \item \texttt{STREAM}: it is a one-to-one communication facility, which |
||
673 | % can be opened either by the reader or by the writer task. The task |
||
674 | % executing the \texttt{port\_create()} must specify the message size |
||
675 | % and maximum number of messages in the queue. The task executing the |
||
676 | % |
||
677 | % \texttt{port\_connect()} must only specify the size of the messages |
||
678 | % it wants to receive/send, which can be different from the one specified |
||
679 | % by the owner. For example, a task may open a port for reading messages |
||
680 | % of 4 bytes, while another task can connect to it to write one-byte |
||
681 | % messages. This mechanism turns out to be useful for character oriented |
||
682 | % device drivers which need to fill a given structure, before the message |
||
683 | % can be processed further by a higher-level task. |
||
684 | % |
||
685 | % \item \texttt{MAILBOX}: it is a many-to-one communication facility, thought |
||
686 | % for being used in classical client/server mechanisms. This kind of |
||
687 | % port can only be opened by the reader task (the server) which wants |
||
688 | % to receive data from writer tasks (the clients). Message size is fixed |
||
689 | % and defined by the reader. |
||
690 | % |
||
691 | % \item \texttt{STICK}: it is a one-to-many communication facility intended |
||
692 | % to be used for exchanging periodic state-messages, for which the most |
||
693 | % recent information is relevant. It can be opened only by the (unique) |
||
694 | % writer task and the reading tasks must connect to it. It contains |
||
695 | % just one message and any new message posted by the writer will overwrite |
||
696 | % the previous one. Messages are non-consumable: a reader task can perform |
||
697 | % many readings of a given message until the writer posts a new one. |
||
698 | % \end{itemize} |
||
699 | % |
||
700 | % The first two kinds of port implement the synchronous communication |
||
701 | % paradigm, while \texttt{STICK} ports implement an asynchronous (state-message) |
||
702 | % paradigm. It is worth noting that in order to protect the internal |
||
703 | % data structures, \texttt{STREAM} ports use semaphores for synchronizing |
||
704 | % the accesses, \texttt{STICK} ports just use a mutual exclusion semaphore, |
||
705 | % and the \texttt{MAILBOX} ports use both kinds of semaphores. |
||
706 | % |
||
707 | % For this reason, \texttt{MAILBOX} and \texttt{STICK} ports should |
||
708 | % not be used by critical tasks, whereas \texttt{STREAM} ports can be |
||
709 | % used by any task requiring a state-message non-blocking semantics. |
||
710 | % Moreover, the execution time of a transaction depends on the message |
||
711 | % size (the message is copied in/from the buffer when a send/receive |
||
712 | % is performed). The semantics associated with each port is graphically |
||
713 | % illustrated in Figure \ref{fg:port-type}. |
||
714 | % |
||
715 | % An application that uses the communication ports, must register the |
||
716 | % HARTPORT Module. Please see Volume III - S.Ha.R.K. Modules for details. |
||
717 | % |
||
718 | % \begin{figure} |
||
719 | % \begin{center}\includegraphics[width=8cm]{port.eps}\end{center} |
||
720 | % \caption{HARTIK ports.\label{fg:port-type}} |
||
721 | % \end{figure} |
||
722 | % |
||
723 | % %---------------------------------------------------------------------------- |
||
724 | % \begin{intest} |
||
725 | % PORT\_CREATE\index{port\_create()} |
||
726 | % \end{intest} |
||
727 | % |
||
728 | % \begin{description} |
||
729 | % |
||
730 | % \item [\textbf{PORT port\_create(char {*}name, int dim, int num, |
||
731 | % int type, int mode);}] |
||
732 | % |
||
733 | % \item [\textbf{Description:}]It opens the port identified by the string |
||
734 | % \texttt{name}. |
||
735 | % The argument \texttt{dim} specifies the message size in bytes, \texttt{num} |
||
736 | % specifies the queue size, \texttt{type} the port type (\texttt{STREAM}, |
||
737 | % \texttt{MAILBOX}, or \texttt{STICK}), and \texttt{mode} the access |
||
738 | % mode (\texttt{READ} or \texttt{WRITE}). |
||
739 | % |
||
740 | % \item [\textbf{Return Value:}] The primitive returns the port identifier, |
||
741 | % which identifies the connection between the port and the task, and |
||
742 | % not the port itself, which is identified through its name. A return |
||
743 | % value -1 indicates that an error is occurred. |
||
744 | % |
||
745 | % \item [\textbf{See also}:] \texttt{port\_delete(), port\_connect(), |
||
746 | % port\_disconnect(), port\_send(), port\_receive()}. |
||
747 | % |
||
748 | % \end{description} |
||
749 | % |
||
750 | % \begin{description} |
||
751 | % \item [Example:\label{pg:port-ex}] |
||
752 | % \item \texttt{TASK demo(void)} \{ |
||
753 | % \item \texttt{~~PORT p; } |
||
754 | % \item \texttt{~~char msg{[}6{]}; } |
||
755 | % \item \texttt{~~\ldots{}} |
||
756 | % \item \texttt{~~/{*} Demo task, of NRT type, opens the \char`\"{}goofy\char`\"{} |
||
757 | % port {*}/} |
||
758 | % \item \texttt{~~/{*} and sends a message of 6 bytes. {*}/} |
||
759 | % \item \texttt{~~p = port\_create(\char`\"{}goofy\char`\"{}, 6, 8, STREAM, |
||
760 | % WRITE);} |
||
761 | % \item \texttt{~~\ldots{}} |
||
762 | % \item \texttt{~~port\_send(p, msg, BLOCK); } |
||
763 | % \item \texttt{\}} |
||
764 | % \item \texttt{~} |
||
765 | % \item \texttt{TASK duro(void)} \{ |
||
766 | % \item \texttt{~~PORT q; } |
||
767 | % \item \texttt{~~char msg{[}2{]}; } |
||
768 | % \item \texttt{~~/{*} Duro task (HARD) connects to the \char`\"{}goofy\char`\"{} |
||
769 | % {*}/} |
||
770 | % \item \texttt{~~/{*} port and receives messages of 2 bytes {*}/ } |
||
771 | % \item \texttt{~~q = port\_connect(\char`\"{}goofy\char`\"{}, 2, STREAM, |
||
772 | % READ);} |
||
773 | % \item \texttt{~~while (condition) \{} |
||
774 | % \item \texttt{~~~~\ldots{}} |
||
775 | % \item \texttt{~~~~if (port\_receive(q, msg, NON\textbackslash{}\_BLOCK) \{} |
||
776 | % \item \texttt{~~~~~~<action 1>;~/{*} Ready Message! {*}/} |
||
777 | % \item \texttt{~~~~\}} |
||
778 | % \item \texttt{~~~~else \{} |
||
779 | % \item \texttt{~~~~~~<action 2>;~/{*} Message not Ready! {*}/} |
||
780 | % \item \texttt{~~~~\}} |
||
781 | % \item \texttt{~~~~\ldots{}} |
||
782 | % \item \texttt{~~~~task\_endcycle();} |
||
783 | % \item \texttt{~~\}} |
||
784 | % \item \texttt{\}} |
||
785 | % |
||
786 | % \end{description} |
||
787 | % |
||
788 | % %---------------------------------------------------------------------------- |
||
789 | % \begin{intest} |
||
790 | % PORT\_DELETE\index{port\_delete()} |
||
791 | % \end{intest} |
||
792 | % |
||
793 | % \begin{description} |
||
794 | % |
||
795 | % \item [\textbf{void port\_delete(PORT p)};] |
||
796 | % |
||
797 | % \item [\textbf{Description:}]It destroys the port identified by \texttt{p}. |
||
798 | % |
||
799 | % \item [\textbf{See also}:] \texttt{port\_create(), port\_connect(), |
||
800 | % port\_disconnect(), |
||
801 | % port\_send(), port\_receive()}. |
||
802 | % |
||
803 | % \item [\textbf{Example:}]see the example at page \pageref{pg:port-ex}. |
||
804 | % |
||
805 | % \end{description} |
||
806 | % |
||
807 | % %---------------------------------------------------------------------------- |
||
808 | % \begin{intest} |
||
809 | % PORT\_CONNECT\index{port\_connect()} |
||
810 | % \end{intest} |
||
811 | % |
||
812 | % \begin{description} |
||
813 | % |
||
814 | % \item [\textbf{PORT port\_connect(char {*}name, int dim, int type, |
||
815 | % int mode);}] |
||
816 | % |
||
817 | % \item [\textbf{Description:}]It connects the calling task to the port identified |
||
818 | % by \texttt{name}. The argument \texttt{dim} specifies the message |
||
819 | % size in bytes, \texttt{type} the port type (\texttt{STREAM}, \texttt{MAILBOX}, |
||
820 | % or \texttt{STICK}), and \texttt{mode} the access mode (\texttt{READ} |
||
821 | % or \texttt{WRITE}). If the port has not been opened by \texttt{port\_create()}, |
||
822 | % the task is blocked, waiting for port creation. To avoid synchronization |
||
823 | % delays, connection should be established only \underbar{after} opening |
||
824 | % the port. |
||
825 | % |
||
826 | % \item [\textbf{Return value:}] The function returns the port identification |
||
827 | % number in the case of successful operation; else -1 is returned. |
||
828 | % |
||
829 | % \item [\textbf{See also}:] \texttt{port\_create(), port\_delete(), |
||
830 | % port\_disconnect(), port\_send(), port\_receive()}. |
||
831 | % |
||
832 | % \end{description} |
||
833 | % |
||
834 | % %---------------------------------------------------------------------------- |
||
835 | % \begin{intest} |
||
836 | % PORT\_DISCONNECT\index{port\_disconnect()} |
||
837 | % \end{intest} |
||
838 | % |
||
839 | % \begin{description} |
||
840 | % |
||
841 | % \item [\textbf{void port\_disconnect(PORT p)};] |
||
842 | % |
||
843 | % \item [\textbf{Description:}]It closes the connection identified by \texttt{p}. |
||
844 | % |
||
845 | % \item [\textbf{See also}:] \texttt{port\_create(), port\_connect(), |
||
846 | % port\_delete(), port\_send(), port\_receive()}. |
||
847 | % |
||
848 | % \end{description} |
||
849 | % |
||
850 | % %---------------------------------------------------------------------------- |
||
851 | % \begin{intest} |
||
852 | % PORT\_SEND\index{port\_send()} |
||
853 | % \end{intest} |
||
854 | % |
||
855 | % \begin{description} |
||
856 | % |
||
857 | % \item [\textbf{int port\_send(PORT p, char {*}msg, BYTE b);}] |
||
858 | % |
||
859 | % \item [\textbf{Description:}]It sends a message pointed by \texttt{msg} to the |
||
860 | % port identified by \texttt{p}. Message dimension is defined through |
||
861 | % \texttt{port\_create()} |
||
862 | % or \texttt{port\_connect()} and cannot be dynamically changed. The |
||
863 | % argument \texttt{b} can be \texttt{BLOCK} or \texttt{NON\_BLOCK}. |
||
864 | % If \texttt{b = BLOCK} and the port queue is full, then the task is |
||
865 | % blocked until the buffer is freed. If \texttt{b = NON\_BLOCK} and |
||
866 | % the port queue is full, then the primitive returns 0 and the message |
||
867 | % is not sent. |
||
868 | % |
||
869 | % \item [\textbf{Return value:}] 1 (TRUE) if the operation can be performed, |
||
870 | % 0 otherwise. |
||
871 | % |
||
872 | % \item [\textbf{See also}:] \texttt{port\_create(), port\_connect(), |
||
873 | % port\_disconnect(), |
||
874 | % port\_send(), port\_receive()}. |
||
875 | % |
||
876 | % \item [\textbf{Example:}]see the example at page \pageref{pg:port-ex}. |
||
877 | % |
||
878 | % \end{description} |
||
879 | % |
||
880 | % %---------------------------------------------------------------------------- |
||
881 | % \begin{intest} |
||
882 | % PORT\_RECEIVE\index{port\_receive()} |
||
883 | % \end{intest} |
||
884 | % |
||
885 | % \begin{description} |
||
886 | % |
||
887 | % \item [\textbf{int port\_receive(PORT p, char {*}msg, BYTE b);}] |
||
888 | % |
||
889 | % \item [\textbf{Description:}]It receives a message from the port identified by |
||
890 | % \texttt{p} and copies it in a memory buffer pointed by \texttt{msg}. Message |
||
891 | % dimension is defined through \texttt{port\_create()} or \texttt{port\_connect()} |
||
892 | % and cannot be dynamically changed. The argument \texttt{b} can be |
||
893 | % \texttt{BLOCK} or \texttt{NON\_BLOCK}. If \texttt{b = BLOCK} and the |
||
894 | % port queue is empty, then the task is blocked until a message is available. |
||
895 | % If \texttt{b = NON\_BLOCK} and the port queue is empty, then the primitive |
||
896 | % returns 0 and no message is received. |
||
897 | % |
||
898 | % \item [\textbf{Return value:}] 1 (TRUE) if the operation can be performed, |
||
899 | % 0 otherwise. |
||
900 | % |
||
901 | % \item [\textbf{See also}:] \texttt{port\_create(), port\_connect(), |
||
902 | % port\_disconnect(), port\_send(), port\_receive()}. |
||
903 | % |
||
904 | % \item [\textbf{Example:}]see the example at page \pageref{pg:port-ex}. |
||
905 | % |
||
906 | % \end{description} |
||
907 | |||
908 | %---------------------------------------------------------------------------- |
||
909 | \section{Cyclical Asynchronous Buffers} |
||
910 | %---------------------------------------------------------------------------- |
||
911 | |||
912 | \textbf{Cyclical Asynchronous Buffers} (or CABs) represent a particular |
||
913 | mechanism purposely designed for the cooperation among periodic activities |
||
914 | with different activation rates. See \cite{But97} for implementation |
||
915 | details. |
||
916 | |||
917 | A CAB provides a one-to-many communication channel, which at any instant |
||
918 | contains the most recent message inserted into it. A message is not |
||
919 | consumed (that is, extracted) by a receiving process but is maintained |
||
920 | into the CAB structure until a new message is overwritten. As a consequence, |
||
921 | once the first message is put in a CAB, a task can never be blocked |
||
922 | during a receive operation. Similarly, since a new message overwrites |
||
923 | the old one, a sender can never be blocked. |
||
924 | |||
925 | Notice that, using such a semantics, a message can be read more than |
||
926 | once if the receiver is faster than the sender, while messages can |
||
927 | be lost if the sender is faster than the receiver. However, this is |
||
928 | not a problem in many control applications, where tasks are interested |
||
929 | only in fresh sensory data rather than in the complete message history |
||
930 | produced by a sensory acquisition task. |
||
931 | |||
932 | Notice that more tasks can simultaneously access the same buffer in |
||
933 | a CAB for reading. Also, if a task $P$ reserves a CAB for writing |
||
934 | while another task $Q$ is using that CAB, a new buffer is created, |
||
935 | so that $P$ can write its message without interfering with $Q$. |
||
936 | As $P$ finishes writing, its message becomes the most recent one |
||
937 | in that CAB. The maximum number of buffers that can be created in |
||
938 | a CAB is specified as a parameter in the \emph{cab\_create} primitive. |
||
939 | To avoid blocking, this number must be equal to the number of tasks |
||
940 | that use the CAB plus one. |
||
941 | |||
942 | CABs can be created and initialized by the \emph{cab\_create} primitive, |
||
943 | which requires the CAB name, the dimension of the message, and the |
||
944 | number of messages that the CAB may contain simultaneously. The |
||
945 | \emph{cab\_delete} |
||
946 | primitive removes a CAB from the system and releases the memory space |
||
947 | used by its data structures. |
||
948 | |||
949 | To insert a message in a CAB, a task must first reserve a buffer from |
||
950 | the CAB memory space, then copy the message into the buffer, and finally |
||
951 | put the buffer into the CAB structure, where it becomes the most recent |
||
952 | message. This is done according to the following scheme: |
||
953 | |||
954 | \vspace{5mm} \begin{tt} |
||
955 | \begin{tabbing} |
||
956 | \={b}uf\_pointer = {\textbf{cab\_reserve}}(cab\_id);\\ |
||
957 | \>\(<\)copy message in *buf\_pointer\(>\)\\ |
||
958 | \>{\textbf{cab\_putmes}}(cab\_id, buf\_pointer);\\ |
||
959 | \end{tabbing} |
||
960 | \end{tt} |
||
961 | |||
962 | \noindent Similarly, to get a message from a CAB, a task has to get |
||
963 | the pointer to the most recent message, use the data, and release |
||
964 | the pointer. This is done according to the following scheme: |
||
965 | |||
966 | \vspace{5mm} \begin{tt} |
||
967 | \begin{tabbing} |
||
968 | \={m}es\_pointer = {\textbf{cab\_getmes}}(cab\_id);\\ |
||
969 | \>\(<\)use message\(>\)\\ |
||
970 | \>{\textbf{cab\_unget}}(cab\_id, mes\_pointer); |
||
971 | \end{tabbing} |
||
972 | \end{tt} A simple example of CABs' usage is reported below. |
||
973 | |||
974 | \label{pg:cab-ex} \begin{minipage}{\columnwidth} |
||
975 | \begin{small} |
||
976 | \begin{tt} |
||
977 | \begin{verbatim} |
||
978 | CAB cc; |
||
979 | |||
980 | void main(void) { |
||
981 | SYS_PARMS parms = BASE_SYS; |
||
982 | |||
983 | /* global declaration */ |
||
984 | sys_def_tick(parms, 1, mSec); |
||
985 | sys_init(&parms); |
||
986 | |||
987 | /* The CAB named cc contains a message of */ |
||
988 | /* 5 floats and can be used by two tasks */ |
||
989 | cc = cab_create("my_cab", 5 * sizeof(float), 3); |
||
990 | task_activate(task_create("ll", read, HARD, APERIODIC, 100, NULL)); |
||
991 | task_activate(task_create("ss", write, HARD, PERIODIC, 333, NULL)); |
||
992 | ... |
||
993 | } |
||
994 | |||
995 | /*---------------------------------------------------------------------*/ |
||
996 | TASK write(void) { |
||
997 | float msg[5]; |
||
998 | char *pun; |
||
999 | ... |
||
1000 | |||
1001 | while (1) { |
||
1002 | |||
1003 | /* send a message to the `cc' cab */ |
||
1004 | pun = cab_reserve(cc); /* reserve a buffer */ |
||
1005 | memcpy(pun, msg, 5 * sizeof(float)); |
||
1006 | cab_putmes(cc, pun); /* release the buffer */ |
||
1007 | task_endcycle(); |
||
1008 | } |
||
1009 | } |
||
1010 | |||
1011 | /*---------------------------------------------------------------------*/ |
||
1012 | TASK read(void) { |
||
1013 | float msg[5]; |
||
1014 | char *pun; |
||
1015 | ... |
||
1016 | |||
1017 | while (1) { |
||
1018 | |||
1019 | /* get a message from the `cc' CAB */ |
||
1020 | pun = cab_getmes(cc); /* reserve a buffer */ |
||
1021 | memcpy(msg, pun, 5 * sizeof(float)); |
||
1022 | cab_unget(cc, pun); /* release the buffer */ |
||
1023 | task_endcycle(); |
||
1024 | } |
||
1025 | } |
||
1026 | \end{verbatim} |
||
1027 | \end{tt} |
||
1028 | \end{small} |
||
1029 | \end{minipage} |
||
1030 | |||
1031 | %---------------------------------------------------------------------------- |
||
1032 | \vspace{7mm} \begin{intest} |
||
1033 | CAB\_CREATE\index{cab\_create()} |
||
1034 | \end{intest} |
||
1035 | |||
1036 | \begin{description} |
||
1037 | |||
1038 | \item [\textbf{CAB cab\_create(char {*}name, int dim\_mes, BYTE num\_mes)}] |
||
1039 | |||
1040 | \item [\textbf{Description:}]It initializes a CAB. \texttt{name} is a pointer to |
||
1041 | an identification string (used only for debugging purposes); \texttt{dim} |
||
1042 | is the size of the messages contained in the CAB; \texttt{numbuf} |
||
1043 | is the number of buffers the CAB is composed of. Notice that such |
||
1044 | a number must be greater than or equal to the number of tasks that |
||
1045 | use the CAB plus one. |
||
1046 | |||
1047 | \item [\textbf{Return value:}] It returns the index of the created CAB. |
||
1048 | |||
1049 | \item [\textbf{See also}:] \texttt{cab\_delete(), cab\_reserve(), cab\_putmes(), |
||
1050 | cab\_getmes(), cab\_unget()}. |
||
1051 | |||
1052 | \end{description} |
||
1053 | |||
1054 | %---------------------------------------------------------------------------- |
||
1055 | \vspace{7mm} \begin{intest} |
||
1056 | CAB\_DELETE\index{cab\_delete()} |
||
1057 | \end{intest} |
||
1058 | |||
1059 | \begin{description} |
||
1060 | |||
1061 | \item [\textbf{void cab\_delete(CAB cc);}] |
||
1062 | |||
1063 | \item [\textbf{Description:}]It removes the \texttt{cc} CAB from the system, |
||
1064 | deallocating |
||
1065 | its buffers and data structures. |
||
1066 | |||
1067 | \item [\textbf{See also}:] \texttt{cab\_create(), cab\_reserve(), cab\_putmes(), |
||
1068 | cab\_getmes(), cab\_unget()}. |
||
1069 | |||
1070 | \end{description} |
||
1071 | |||
1072 | %---------------------------------------------------------------------------- |
||
1073 | \vspace{7mm} \begin{intest} |
||
1074 | CAB\_RESERVE\index{cab\_reserve()} |
||
1075 | \end{intest} |
||
1076 | |||
1077 | \begin{description} |
||
1078 | |||
1079 | \item [\textbf{char {*}cab\_reserve(CAB cc);}] |
||
1080 | |||
1081 | \item [\textbf{Description:}]it reserves a buffer belonging to the \texttt{cc} |
||
1082 | CAB and returns a pointer to it. The primitive has to be used only by |
||
1083 | writers and \emph{never} by readers. |
||
1084 | |||
1085 | \item [\textbf{Return value:}] it returns a pointer to the reserved buffer. |
||
1086 | |||
1087 | \item [\textbf{See also}:] \texttt{cab\_delete(), cab\_create(), cab\_putmes(), |
||
1088 | cab\_getmes(), cab\_unget()}. |
||
1089 | |||
1090 | \end{description} |
||
1091 | |||
1092 | \pagebreak |
||
1093 | |||
1094 | %---------------------------------------------------------------------------- |
||
1095 | \begin{intest} |
||
1096 | CAB\_PUTMES\index{cab\_putmes()} |
||
1097 | \end{intest} |
||
1098 | |||
1099 | \begin{description} |
||
1100 | |||
1101 | \item [\textbf{void cab\_putmes(CAB id, char {*}pun)}] |
||
1102 | |||
1103 | \item [\textbf{Description:}]It inserts the message pointed by \texttt{pun} into |
||
1104 | the CAB identified by \texttt{id}. This primitive must be used \emph{only} |
||
1105 | by writing tasks. |
||
1106 | |||
1107 | \item [\textbf{See also}:] \texttt{cab\_delete(), cab\_create(), cab\_reserve(), |
||
1108 | cab\_getmes(), cab\_unget()}. |
||
1109 | |||
1110 | \end{description} |
||
1111 | |||
1112 | %---------------------------------------------------------------------------- |
||
1113 | \vspace{7mm} \begin{intest} |
||
1114 | CAB\_GETMES\index{cab\_getmes()} |
||
1115 | \end{intest} |
||
1116 | |||
1117 | \begin{description} |
||
1118 | |||
1119 | \item [\textbf{char {*}cab\_getmes(CAB cc);}] |
||
1120 | |||
1121 | \item [\textbf{Description:}]It returns a pointer to the latest message written |
||
1122 | into the \texttt{cc} CAB. This primitive must be used \emph{only} |
||
1123 | by reading tasks. |
||
1124 | |||
1125 | \item [\textbf{Returned value:}] It returns a pointer to the most recent |
||
1126 | message contained in the CAB. |
||
1127 | |||
1128 | \item [\textbf{See also}:] \texttt{cab\_delete(), cab\_create(), cab\_putmes(), |
||
1129 | cab\_reserve(), cab\_unget()}. |
||
1130 | |||
1131 | \end{description} |
||
1132 | |||
1133 | %---------------------------------------------------------------------------- |
||
1134 | \vspace{7mm} \begin{intest} |
||
1135 | CAB\_UNGET\index{cab\_unget()} |
||
1136 | \end{intest} |
||
1137 | |||
1138 | \begin{description} |
||
1139 | |||
1140 | \item [\textbf{void cab\_unget(CAB cc, char {*}pun);}] |
||
1141 | |||
1142 | \item [\textbf{Description:}]it notifies the system that the buffer pointed by |
||
1143 | \texttt{pun} belonging to the \texttt{cc} CAB is no longer used by the calling |
||
1144 | task. |
||
1145 | |||
1146 | \item [\textbf{See also}:] \texttt{cab\_delete(), cab\_create(), cab\_reserve(), |
||
1147 | cab\_getmes(), cab\_putmes()}. |
||
1148 | |||
1149 | \end{description} |
||
1150 | |||
1151 | \section{POSIX Message Queues} |
||
1152 | |||
1153 | S.Ha.R.K. provides the message passing function defined in the POSIX |
||
1154 | standard. For more information, see Section 15 of the POSIX standard, |
||
1155 | Message Passing. |