]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - doc/html/ref/kernel-mutexes.html
RedBoot TX53 Release 2012-02-15
[karo-tx-redboot.git] / doc / html / ref / kernel-mutexes.html
1 <!-- Copyright (C) 2003 Red Hat, Inc.                                -->
2 <!-- This material may be distributed only subject to the terms      -->
3 <!-- and conditions set forth in the Open Publication License, v1.0  -->
4 <!-- or later (the latest version is presently available at          -->
5 <!-- http://www.opencontent.org/openpub/).                           -->
6 <!-- Distribution of the work or derivative of the work in any       -->
7 <!-- standard (paper) book form is prohibited unless prior           -->
8 <!-- permission is obtained from the copyright holder.               -->
9 <HTML
10 ><HEAD
11 ><TITLE
12 >Mutexes</TITLE
13 ><meta name="MSSmartTagsPreventParsing" content="TRUE">
14 <META
15 NAME="GENERATOR"
16 CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
17 "><LINK
18 REL="HOME"
19 TITLE="eCos Reference Manual"
20 HREF="ecos-ref.html"><LINK
21 REL="UP"
22 TITLE="The eCos Kernel"
23 HREF="kernel.html"><LINK
24 REL="PREVIOUS"
25 TITLE="Alarms"
26 HREF="kernel-alarms.html"><LINK
27 REL="NEXT"
28 TITLE="Condition Variables"
29 HREF="kernel-condition-variables.html"></HEAD
30 ><BODY
31 CLASS="REFENTRY"
32 BGCOLOR="#FFFFFF"
33 TEXT="#000000"
34 LINK="#0000FF"
35 VLINK="#840084"
36 ALINK="#0000FF"
37 ><DIV
38 CLASS="NAVHEADER"
39 ><TABLE
40 SUMMARY="Header navigation table"
41 WIDTH="100%"
42 BORDER="0"
43 CELLPADDING="0"
44 CELLSPACING="0"
45 ><TR
46 ><TH
47 COLSPAN="3"
48 ALIGN="center"
49 >eCos Reference Manual</TH
50 ></TR
51 ><TR
52 ><TD
53 WIDTH="10%"
54 ALIGN="left"
55 VALIGN="bottom"
56 ><A
57 HREF="kernel-alarms.html"
58 ACCESSKEY="P"
59 >Prev</A
60 ></TD
61 ><TD
62 WIDTH="80%"
63 ALIGN="center"
64 VALIGN="bottom"
65 ></TD
66 ><TD
67 WIDTH="10%"
68 ALIGN="right"
69 VALIGN="bottom"
70 ><A
71 HREF="kernel-condition-variables.html"
72 ACCESSKEY="N"
73 >Next</A
74 ></TD
75 ></TR
76 ></TABLE
77 ><HR
78 ALIGN="LEFT"
79 WIDTH="100%"></DIV
80 ><H1
81 ><A
82 NAME="KERNEL-MUTEXES">Mutexes</H1
83 ><DIV
84 CLASS="REFNAMEDIV"
85 ><A
86 NAME="AEN1098"
87 ></A
88 ><H2
89 >Name</H2
90 >cyg_mutex_init, cyg_mutex_destroy, cyg_mutex_lock, cyg_mutex_trylock, cyg_mutex_unlock, cyg_mutex_release, cyg_mutex_set_ceiling, cyg_mutex_set_protocol&nbsp;--&nbsp;Synchronization primitive</DIV
91 ><DIV
92 CLASS="REFSYNOPSISDIV"
93 ><A
94 NAME="AEN1108"><H2
95 >Synopsis</H2
96 ><DIV
97 CLASS="FUNCSYNOPSIS"
98 ><A
99 NAME="AEN1109"><P
100 ></P
101 ><TABLE
102 BORDER="5"
103 BGCOLOR="#E0E0F0"
104 WIDTH="70%"
105 ><TR
106 ><TD
107 ><PRE
108 CLASS="FUNCSYNOPSISINFO"
109 >#include &lt;cyg/kernel/kapi.h&gt;
110         </PRE
111 ></TD
112 ></TR
113 ></TABLE
114 ><P
115 ><CODE
116 ><CODE
117 CLASS="FUNCDEF"
118 >void cyg_mutex_init</CODE
119 >(cyg_mutex_t* mutex);</CODE
120 ></P
121 ><P
122 ><CODE
123 ><CODE
124 CLASS="FUNCDEF"
125 >void cyg_mutex_destroy</CODE
126 >(cyg_mutex_t* mutex);</CODE
127 ></P
128 ><P
129 ><CODE
130 ><CODE
131 CLASS="FUNCDEF"
132 >cyg_bool_t cyg_mutex_lock</CODE
133 >(cyg_mutex_t* mutex);</CODE
134 ></P
135 ><P
136 ><CODE
137 ><CODE
138 CLASS="FUNCDEF"
139 >cyg_bool_t cyg_mutex_trylock</CODE
140 >(cyg_mutex_t* mutex);</CODE
141 ></P
142 ><P
143 ><CODE
144 ><CODE
145 CLASS="FUNCDEF"
146 >void cyg_mutex_unlock</CODE
147 >(cyg_mutex_t* mutex);</CODE
148 ></P
149 ><P
150 ><CODE
151 ><CODE
152 CLASS="FUNCDEF"
153 >void cyg_mutex_release</CODE
154 >(cyg_mutex_t* mutex);</CODE
155 ></P
156 ><P
157 ><CODE
158 ><CODE
159 CLASS="FUNCDEF"
160 >void cyg_mutex_set_ceiling</CODE
161 >(cyg_mutex_t* mutex, cyg_priority_t priority);</CODE
162 ></P
163 ><P
164 ><CODE
165 ><CODE
166 CLASS="FUNCDEF"
167 >void cyg_mutex_set_protocol</CODE
168 >(cyg_mutex_t* mutex, enum cyg_mutex_protocol protocol/);</CODE
169 ></P
170 ><P
171 ></P
172 ></DIV
173 ></DIV
174 ><DIV
175 CLASS="REFSECT1"
176 ><A
177 NAME="KERNEL-MUTEXES-DESCRIPTION"
178 ></A
179 ><H2
180 >Description</H2
181 ><P
182 >The purpose of mutexes is to let threads share resources safely. If
183 two or more threads attempt to manipulate a data structure with no
184 locking between them then the system may run for quite some time
185 without apparent problems, but sooner or later the data structure will
186 become inconsistent and the application will start behaving strangely
187 and is quite likely to crash. The same can apply even when
188 manipulating a single variable or some other resource. For example,
189 consider:
190       </P
191 ><TABLE
192 BORDER="5"
193 BGCOLOR="#E0E0F0"
194 WIDTH="70%"
195 ><TR
196 ><TD
197 ><PRE
198 CLASS="PROGRAMLISTING"
199 >static volatile int counter = 0;
200
201 void
202 process_event(void)
203 {
204     &#8230;
205
206     counter++;
207 }</PRE
208 ></TD
209 ></TR
210 ></TABLE
211 ><P
212 >Assume that after a certain period of time <TT
213 CLASS="VARNAME"
214 >counter</TT
215 >
216 has a value of 42, and two threads A and B running at the same
217 priority call <TT
218 CLASS="FUNCTION"
219 >process_event</TT
220 >. Typically thread A
221 will read the value of <TT
222 CLASS="VARNAME"
223 >counter</TT
224 > into a register,
225 increment this register to 43, and write this updated value back to
226 memory. Thread B will do the same, so usually
227 <TT
228 CLASS="VARNAME"
229 >counter</TT
230 > will end up with a value of 44. However if
231 thread A is timesliced after reading the old value 42 but before
232 writing back 43, thread B will still read back the old value and will
233 also write back 43. The net result is that the counter only gets
234 incremented once, not twice, which depending on the application may
235 prove disastrous.
236       </P
237 ><P
238 >Sections of code like the above which involve manipulating shared data
239 are generally known as critical regions. Code should claim a lock
240 before entering a critical region and release the lock when leaving.
241 Mutexes provide an appropriate synchronization primitive for this.
242       </P
243 ><TABLE
244 BORDER="5"
245 BGCOLOR="#E0E0F0"
246 WIDTH="70%"
247 ><TR
248 ><TD
249 ><PRE
250 CLASS="PROGRAMLISTING"
251 >static volatile int counter = 0;
252 static cyg_mutex_t  lock;
253
254 void
255 process_event(void)
256 {
257     &#8230;
258
259     cyg_mutex_lock(&amp;lock);
260     counter++;
261     cyg_mutex_unlock(&amp;lock);
262 }
263       </PRE
264 ></TD
265 ></TR
266 ></TABLE
267 ><P
268 >A mutex must be initialized before it can be used, by calling
269 <TT
270 CLASS="FUNCTION"
271 >cyg_mutex_init</TT
272 >. This takes a pointer to a
273 <SPAN
274 CLASS="STRUCTNAME"
275 >cyg_mutex_t</SPAN
276 > data structure which is typically
277 statically allocated, and may be part of a larger data structure. If a
278 mutex is no longer required and there are no threads waiting on it
279 then <TT
280 CLASS="FUNCTION"
281 >cyg_mutex_destroy</TT
282 > can be used.
283       </P
284 ><P
285 >The main functions for using a mutex are
286 <TT
287 CLASS="FUNCTION"
288 >cyg_mutex_lock</TT
289 > and
290 <TT
291 CLASS="FUNCTION"
292 >cyg_mutex_unlock</TT
293 >. In normal operation
294 <TT
295 CLASS="FUNCTION"
296 >cyg_mutex_lock</TT
297 > will return success after claiming
298 the mutex lock, blocking if another thread currently owns the mutex.
299 However the lock operation may fail if other code calls
300 <TT
301 CLASS="FUNCTION"
302 >cyg_mutex_release</TT
303 > or
304 <TT
305 CLASS="FUNCTION"
306 >cyg_thread_release</TT
307 >, so if these functions may get
308 used then it is important to check the return value. The current owner
309 of a mutex should call <TT
310 CLASS="FUNCTION"
311 >cyg_mutex_unlock</TT
312 > when a
313 lock is no longer required. This operation must be performed by the
314 owner, not by another thread.
315       </P
316 ><P
317 ><TT
318 CLASS="FUNCTION"
319 >cyg_mutex_trylock</TT
320 > is a variant of
321 <TT
322 CLASS="FUNCTION"
323 >cyg_mutex_lock</TT
324 > that will always return
325 immediately, returning success or failure as appropriate. This
326 function is rarely useful. Typical code locks a mutex just before
327 entering a critical region, so if the lock cannot be claimed then
328 there may be nothing else for the current thread to do. Use of this
329 function may also cause a form of priority inversion if the owner
330 owner runs at a lower priority, because the priority inheritance code
331 will not be triggered. Instead the current thread continues running,
332 preventing the owner from getting any cpu time, completing the
333 critical region, and releasing the mutex.
334       </P
335 ><P
336 ><TT
337 CLASS="FUNCTION"
338 >cyg_mutex_release</TT
339 > can be used to wake up all
340 threads that are currently blocked inside a call to
341 <TT
342 CLASS="FUNCTION"
343 >cyg_mutex_lock</TT
344 > for a specific mutex. These lock
345 calls will return failure. The current mutex owner is not affected.
346       </P
347 ></DIV
348 ><DIV
349 CLASS="REFSECT1"
350 ><A
351 NAME="KERNEL-MUTEXES-PRIORITY-INVERSION"
352 ></A
353 ><H2
354 >Priority Inversion</H2
355 ><P
356 >The use of mutexes gives rise to a problem known as priority
357 inversion. In a typical scenario this requires three threads A, B, and
358 C, running at high, medium and low priority respectively. Thread A and
359 thread B are temporarily blocked waiting for some event, so thread C
360 gets a chance to run, needs to enter a critical region, and locks
361 a mutex. At this point threads A and B are woken up - the exact order
362 does not matter. Thread A needs to claim the same mutex but has to
363 wait until C has left the critical region and can release the mutex.
364 Meanwhile thread B works on something completely different and can
365 continue running without problems. Because thread C is running a lower
366 priority than B it will not get a chance to run until B blocks for
367 some reason, and hence thread A cannot run either. The overall effect
368 is that a high-priority thread A cannot proceed because of a lower
369 priority thread B, and priority inversion has occurred.
370       </P
371 ><P
372 >In simple applications it may be possible to arrange the code such
373 that priority inversion cannot occur, for example by ensuring that a
374 given mutex is never shared by threads running at different priority
375 levels. However this may not always be possible even at the
376 application level. In addition mutexes may be used internally by
377 underlying code, for example the memory allocation package, so careful
378 analysis of the whole system would be needed to be sure that priority
379 inversion cannot occur. Instead it is common practice to use one of
380 two techniques: priority ceilings and priority inheritance.
381       </P
382 ><P
383 >Priority ceilings involve associating a priority with each mutex.
384 Usually this will match the highest priority thread that will ever
385 lock the mutex. When a thread running at a lower priority makes a
386 successful call to <TT
387 CLASS="FUNCTION"
388 >cyg_mutex_lock</TT
389 > or
390 <TT
391 CLASS="FUNCTION"
392 >cyg_mutex_trylock</TT
393 > its priority will be boosted to
394 that of the mutex. For example, given the previous example the
395 priority associated with the mutex would be that of thread A, so for
396 as long as it owns the mutex thread C will run in preference to thread
397 B. When C releases the mutex its priority drops to the normal value
398 again, allowing A to run and claim the mutex. Setting the
399 priority for a mutex involves a call to
400 <TT
401 CLASS="FUNCTION"
402 >cyg_mutex_set_ceiling</TT
403 >, which is typically called
404 during initialization. It is possible to change the ceiling
405 dynamically but this will only affect subsequent lock operations, not
406 the current owner of the mutex.
407       </P
408 ><P
409 >Priority ceilings are very suitable for simple applications, where for
410 every thread in the system it is possible to work out which mutexes
411 will be accessed. For more complicated applications this may prove
412 difficult, especially if thread priorities change at run-time. An
413 additional problem occurs for any mutexes outside the application, for
414 example used internally within eCos packages. A typical eCos package
415 will be unaware of the details of the various threads in the system,
416 so it will have no way of setting suitable ceilings for its internal
417 mutexes. If those mutexes are not exported to application code then 
418 using priority ceilings may not be viable. The kernel does provide a
419 configuration option
420 <TT
421 CLASS="VARNAME"
422 >CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY</TT
423 >
424 that can be used to set the default priority ceiling for all mutexes,
425 which may prove sufficient.
426       </P
427 ><P
428 >The alternative approach is to use priority inheritance: if a thread
429 calls <TT
430 CLASS="FUNCTION"
431 >cyg_mutex_lock</TT
432 > for a mutex that it
433 currently owned by a lower-priority thread, then the owner will have
434 its priority raised to that of the current thread. Often this is more
435 efficient than priority ceilings because priority boosting only
436 happens when necessary, not for every lock operation, and the required
437 priority is determined at run-time rather than by static analysis.
438 However there are complications when multiple threads running at
439 different priorities try to lock a single mutex, or when the current
440 owner of a mutex then tries to lock additional mutexes, and this makes
441 the implementation significantly more complicated than priority
442 ceilings. 
443       </P
444 ><P
445 >There are a number of configuration options associated with priority
446 inversion. First, if after careful analysis it is known that priority
447 inversion cannot arise then the component
448 <TT
449 CLASS="FUNCTION"
450 >CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL</TT
451 >
452 can be disabled. More commonly this component will be enabled, and one
453 of either
454 <TT
455 CLASS="VARNAME"
456 >CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT</TT
457 >
458 or
459 <TT
460 CLASS="VARNAME"
461 >CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING</TT
462 >
463 will be selected, so that one of the two protocols is available for
464 all mutexes. It is possible to select multiple protocols, so that some
465 mutexes can have priority ceilings while others use priority
466 inheritance or no priority inversion protection at all. Obviously this
467 flexibility will add to the code size and to the cost of mutex
468 operations. The default for all mutexes will be controlled by
469 <TT
470 CLASS="VARNAME"
471 >CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT</TT
472 >,
473 and can be changed at run-time using
474 <TT
475 CLASS="FUNCTION"
476 >cyg_mutex_set_protocol</TT
477 >. 
478       </P
479 ><P
480 >Priority inversion problems can also occur with other synchronization
481 primitives such as semaphores. For example there could be a situation
482 where a high-priority thread A is waiting on a semaphore, a
483 low-priority thread C needs to do just a little bit more work before
484 posting the semaphore, but a medium priority thread B is running and
485 preventing C from making progress. However a semaphore does not have
486 the concept of an owner, so there is no way for the system to know
487 that it is thread C which would next post to the semaphore. Hence
488 there is no way for the system to boost the priority of C
489 automatically and prevent the priority inversion. Instead situations
490 like this have to be detected by application developers and
491 appropriate precautions have to be taken, for example making sure that
492 all the threads run at suitable priorities at all times.
493       </P
494 ><DIV
495 CLASS="WARNING"
496 ><P
497 ></P
498 ><TABLE
499 CLASS="WARNING"
500 BORDER="1"
501 WIDTH="100%"
502 ><TR
503 ><TD
504 ALIGN="CENTER"
505 ><B
506 >Warning</B
507 ></TD
508 ></TR
509 ><TR
510 ><TD
511 ALIGN="LEFT"
512 ><P
513 >The current implementation of priority inheritance within the eCos
514 kernel does not handle certain exceptional circumstances completely
515 correctly. Problems will only arise if a thread owns one mutex,
516 then attempts to claim another mutex, and there are other threads
517 attempting to lock these same mutexes. Although the system will
518 continue running, the current owners of the various mutexes involved
519 may not run at the priority they should. This situation never arises
520 in typical code because a mutex will only be locked for a small
521 critical region, and there is no need to manipulate other shared resources
522 inside this region. A more complicated implementation of priority
523 inheritance is possible but would add significant overhead and certain
524 operations would no longer be deterministic.
525       </P
526 ></TD
527 ></TR
528 ></TABLE
529 ></DIV
530 ><DIV
531 CLASS="WARNING"
532 ><P
533 ></P
534 ><TABLE
535 CLASS="WARNING"
536 BORDER="1"
537 WIDTH="100%"
538 ><TR
539 ><TD
540 ALIGN="CENTER"
541 ><B
542 >Warning</B
543 ></TD
544 ></TR
545 ><TR
546 ><TD
547 ALIGN="LEFT"
548 ><P
549 >Support for priority ceilings and priority inheritance is not
550 implemented for all schedulers. In particular neither priority
551 ceilings nor priority inheritance are currently available for the
552 bitmap scheduler.
553       </P
554 ></TD
555 ></TR
556 ></TABLE
557 ></DIV
558 ></DIV
559 ><DIV
560 CLASS="REFSECT1"
561 ><A
562 NAME="KERNEL-MUTEXES-ALTERNATIVES"
563 ></A
564 ><H2
565 >Alternatives</H2
566 ><P
567 >In nearly all circumstances, if two or more threads need to share some
568 data then protecting this data with a mutex is the correct thing to
569 do. Mutexes are the only primitive that combine a locking mechanism
570 and protection against priority inversion problems. However this
571 functionality is achieved at a cost, and in exceptional circumstances
572 such as an application's most critical inner loop it may be desirable
573 to use some other means of locking.
574       </P
575 ><P
576 >When a critical region is very very small it is possible to lock the
577 scheduler, thus ensuring that no other thread can run until the
578 scheduler is unlocked again. This is achieved with calls to <A
579 HREF="kernel-schedcontrol.html"
580 ><TT
581 CLASS="FUNCTION"
582 >cyg_scheduler_lock</TT
583 ></A
584 >
585 and <TT
586 CLASS="FUNCTION"
587 >cyg_scheduler_unlock</TT
588 >. If the critical region
589 is sufficiently small then this can actually improve both performance
590 and dispatch latency because <TT
591 CLASS="FUNCTION"
592 >cyg_mutex_lock</TT
593 > also
594 locks the scheduler for a brief period of time. This approach will not
595 work on SMP systems because another thread may already be running on a
596 different processor and accessing the critical region.
597       </P
598 ><P
599 >Another way of avoiding the use of mutexes is to make sure that all
600 threads that access a particular critical region run at the same
601 priority and configure the system with timeslicing disabled
602 (<TT
603 CLASS="VARNAME"
604 >CYGSEM_KERNEL_SCHED_TIMESLICE</TT
605 >). Without
606 timeslicing a thread can only be preempted by a higher-priority one,
607 or if it performs some operation that can block. This approach
608 requires that none of the operations in the critical region can block,
609 so for example it is not legal to call
610 <TT
611 CLASS="FUNCTION"
612 >cyg_semaphore_wait</TT
613 >. It is also vulnerable to
614 any changes in the configuration or to the various thread priorities:
615 any such changes may now have unexpected side effects. It will not
616 work on SMP systems.
617       </P
618 ></DIV
619 ><DIV
620 CLASS="REFSECT1"
621 ><A
622 NAME="KERNEL-MUTEXES-RECURSIVE"
623 ></A
624 ><H2
625 >Recursive Mutexes</H2
626 ><P
627 >The implementation of mutexes within the eCos kernel does not support
628 recursive locks. If a thread has locked a mutex and then attempts to
629 lock the mutex again, typically as a result of some recursive call in
630 a complicated call graph, then either an assertion failure will be
631 reported or the thread will deadlock. This behaviour is deliberate.
632 When a thread has just locked a mutex associated with some data
633 structure, it can assume that that data structure is in a consistent
634 state. Before unlocking the mutex again it must ensure that the data
635 structure is again in a consistent state. Recursive mutexes allow a
636 thread to make arbitrary changes to a data structure, then in a
637 recursive call lock the mutex again while the data structure is still
638 inconsistent. The net result is that code can no longer make any
639 assumptions about data structure consistency, which defeats the
640 purpose of using mutexes.
641       </P
642 ></DIV
643 ><DIV
644 CLASS="REFSECT1"
645 ><A
646 NAME="KERNEL-MUTEXES-CONTEXT"
647 ></A
648 ><H2
649 >Valid contexts</H2
650 ><P
651 ><TT
652 CLASS="FUNCTION"
653 >cyg_mutex_init</TT
654 >,
655 <TT
656 CLASS="FUNCTION"
657 >cyg_mutex_set_ceiling</TT
658 > and
659 <TT
660 CLASS="FUNCTION"
661 >cyg_mutex_set_protocol</TT
662 > are normally called during
663 initialization but may also be called from thread context. The
664 remaining functions should only be called from thread context. Mutexes
665 serve as a mutual exclusion mechanism between threads, and cannot be
666 used to synchronize between threads and the interrupt handling
667 subsystem. If a critical region is shared between a thread and a DSR
668 then it must be protected using <A
669 HREF="kernel-schedcontrol.html"
670 ><TT
671 CLASS="FUNCTION"
672 >cyg_scheduler_lock</TT
673 ></A
674 >
675 and <TT
676 CLASS="FUNCTION"
677 >cyg_scheduler_unlock</TT
678 >. If a critical region is
679 shared between a thread and an ISR, it must be protected by disabling
680 or masking interrupts. Obviously these operations must be used with
681 care because they can affect dispatch and interrupt latencies.
682       </P
683 ></DIV
684 ><DIV
685 CLASS="NAVFOOTER"
686 ><HR
687 ALIGN="LEFT"
688 WIDTH="100%"><TABLE
689 SUMMARY="Footer navigation table"
690 WIDTH="100%"
691 BORDER="0"
692 CELLPADDING="0"
693 CELLSPACING="0"
694 ><TR
695 ><TD
696 WIDTH="33%"
697 ALIGN="left"
698 VALIGN="top"
699 ><A
700 HREF="kernel-alarms.html"
701 ACCESSKEY="P"
702 >Prev</A
703 ></TD
704 ><TD
705 WIDTH="34%"
706 ALIGN="center"
707 VALIGN="top"
708 ><A
709 HREF="ecos-ref.html"
710 ACCESSKEY="H"
711 >Home</A
712 ></TD
713 ><TD
714 WIDTH="33%"
715 ALIGN="right"
716 VALIGN="top"
717 ><A
718 HREF="kernel-condition-variables.html"
719 ACCESSKEY="N"
720 >Next</A
721 ></TD
722 ></TR
723 ><TR
724 ><TD
725 WIDTH="33%"
726 ALIGN="left"
727 VALIGN="top"
728 >Alarms</TD
729 ><TD
730 WIDTH="34%"
731 ALIGN="center"
732 VALIGN="top"
733 ><A
734 HREF="kernel.html"
735 ACCESSKEY="U"
736 >Up</A
737 ></TD
738 ><TD
739 WIDTH="33%"
740 ALIGN="right"
741 VALIGN="top"
742 >Condition Variables</TD
743 ></TR
744 ></TABLE
745 ></DIV
746 ></BODY
747 ></HTML
748 >