]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - doc/html/ref/kernel-overview.html
RedBoot TX53 Release 2012-02-15
[karo-tx-redboot.git] / doc / html / ref / kernel-overview.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 >Kernel Overview</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="The eCos Kernel"
26 HREF="kernel.html"><LINK
27 REL="NEXT"
28 TITLE="SMP Support"
29 HREF="kernel-smp.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.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-smp.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-OVERVIEW">Kernel Overview</H1
83 ><DIV
84 CLASS="REFNAMEDIV"
85 ><A
86 NAME="AEN56"
87 ></A
88 ><H2
89 >Name</H2
90 >Kernel&nbsp;--&nbsp;Overview of the eCos Kernel</DIV
91 ><DIV
92 CLASS="REFSECT1"
93 ><A
94 NAME="KERNEL-OVERVIEW-DESCRIPTION"
95 ></A
96 ><H2
97 >Description</H2
98 ><P
99 >The kernel is one of the key packages in all of eCos. It provides the
100 core functionality needed for developing multi-threaded applications:
101       </P
102 ><P
103 ></P
104 ><OL
105 TYPE="1"
106 ><LI
107 ><P
108 >The ability to create new threads in the system, either during startup
109 or when the system is already running.
110         </P
111 ></LI
112 ><LI
113 ><P
114 >Control over the various threads in the system, for example
115 manipulating their priorities.
116         </P
117 ></LI
118 ><LI
119 ><P
120 >A choice of schedulers, determining which thread should currently be
121 running. 
122         </P
123 ></LI
124 ><LI
125 ><P
126 >A range of synchronization primitives, allowing threads to interact
127 and share data safely.
128         </P
129 ></LI
130 ><LI
131 ><P
132 >Integration with the system's support for interrupts and exceptions.
133         </P
134 ></LI
135 ></OL
136 ><P
137 >In some other operating systems the kernel provides additional
138 functionality. For example the kernel may also provide memory
139 allocation functionality, and device drivers may be part of the kernel
140 as well. This is not the case for eCos. Memory allocation is handled
141 by a separate package. Similary each device driver will typically be a
142 separate package. Various packages are combined and configured using
143 the eCos configuration technology to meet the requirements of the
144 application.
145       </P
146 ><P
147 >The eCos kernel package is optional. It is possible to write
148 single-threaded applications which do not use any kernel
149 functionality, for example RedBoot. Typically such applications are
150 based around a central polling loop, continually checking all devices
151 and taking appropriate action when I/O occurs. A small amount of
152 calculation is possible every iteration, at the cost of an increased
153 delay between an I/O event occurring and the polling loop detecting
154 the event. When the requirements are straightforward it may well be
155 easier to develop the application using a polling loop, avoiding the
156 complexities of multiple threads and synchronization between threads.
157 As requirements get more complicated a multi-threaded solution becomes
158 more appropriate, requiring the use of the kernel. In fact some of the
159 more advanced packages in eCos, for example the TCP/IP stack, use
160 multi-threading internally. Therefore if the application uses any of
161 those packages then the kernel becomes a required package, not an
162 optional one.
163       </P
164 ><P
165 >The kernel functionality can be used in one of two ways. The kernel
166 provides its own C API, with functions like
167 <TT
168 CLASS="FUNCTION"
169 >cyg_thread_create</TT
170 > and
171 <TT
172 CLASS="FUNCTION"
173 >cyg_mutex_lock</TT
174 >. These can be called directly from
175 application code or from other packages. Alternatively there are a
176 number of packages which provide compatibility with existing API's,
177 for example POSIX threads or &micro;ITRON. These allow application
178 code to call standard functions such as
179 <TT
180 CLASS="FUNCTION"
181 >pthread_create</TT
182 >, and those functions are
183 implemented using the basic functionality provided by the eCos kernel.
184 Using compatibility packages in an eCos application can make it much
185 easier to reuse code developed in other environments, and to share
186 code.
187       </P
188 ><P
189 >Although the different compatibility packages have similar
190 requirements on the underlying kernel, for example the ability to
191 create a new thread, there are differences in the exact semantics. For
192 example, strict &micro;ITRON compliance requires that kernel
193 timeslicing is disabled. This is achieved largely through the
194 configuration technology. The kernel provides a number of
195 configuration options that control the exact semantics that are
196 provided, and the various compatibility packages require particular
197 settings for those options. This has two important consequences.
198 First, it is not usually possible to have two different compatibility
199 packages in one eCos configuration because they will have conflicting
200 requirements on the underlying kernel. Second, the semantics of the
201 kernel's own API are only loosely defined because of the many
202 configuration options. For example <TT
203 CLASS="FUNCTION"
204 >cyg_mutex_lock</TT
205 >
206 will always attempt to lock a mutex, but various configuration options
207 determine the behaviour when the mutex is already locked and there is
208 a possibility of priority inversion.
209       </P
210 ><P
211 >The optional nature of the kernel package presents some complications
212 for other code, especially device drivers. Wherever possible a device
213 driver should work whether or not the kernel is present. However there
214 are some parts of the system, especially those related to interrupt
215 handling, which should be implemented differently in multi-threaded
216 environments containing the eCos kernel and in single-threaded
217 environments without the kernel. To cope with both scenarios the
218 common HAL package provides a driver API, with functions such as
219 <TT
220 CLASS="FUNCTION"
221 >cyg_drv_interrupt_attach</TT
222 >. When the kernel package
223 is present these driver API functions map directly on to the
224 equivalent kernel functions such as
225 <TT
226 CLASS="FUNCTION"
227 >cyg_interrupt_attach</TT
228 >, using macros to avoid any
229 overheads. When the kernel is absent the common HAL package implements
230 the driver API directly, but this implementation is simpler than the
231 one in the kernel because it can assume a single-threaded environment. 
232       </P
233 ></DIV
234 ><DIV
235 CLASS="REFSECT1"
236 ><A
237 NAME="KERNEL-OVERVIEW-SCHEDULERS"
238 ></A
239 ><H2
240 >Schedulers</H2
241 ><P
242 >When a system involves multiple threads, a scheduler is needed to
243 determine which thread should currently be running. The eCos kernel
244 can be configured with one of two schedulers, the bitmap scheduler and
245 the multi-level queue (MLQ) scheduler. The bitmap scheduler is
246 somewhat more efficient, but has a number of limitations. Most systems
247 will instead use the MLQ scheduler. Other schedulers may be added in
248 the future, either as extensions to the kernel package or in separate
249 packages.
250       </P
251 ><P
252 >Both the bitmap and the MLQ scheduler use a simple numerical priority
253 to determine which thread should be running. The number of priority
254 levels is configurable via the option
255 <TT
256 CLASS="VARNAME"
257 >CYGNUM_KERNEL_SCHED_PRIORITIES</TT
258 >, but a typical
259 system will have up to 32 priority levels. Therefore thread priorities
260 will be in the range 0 to 31, with 0 being the highest priority and 31
261 the lowest. Usually only the system's idle thread will run at the
262 lowest priority. Thread priorities are absolute, so the kernel will
263 only run a lower-priority thread if all higher-priority threads are
264 currently blocked.
265       </P
266 ><P
267 >The bitmap scheduler only allows one thread per priority level, so if
268 the system is configured with 32 priority levels then it is limited to
269 only 32 threads &#8212; still enough for many applications. A simple
270 bitmap can be used to keep track of which threads are currently
271 runnable. Bitmaps can also be used to keep track of threads waiting on
272 a mutex or other synchronization primitive. Identifying the
273 highest-priority runnable or waiting thread involves a simple
274 operation on the bitmap, and an array index operation can then be used
275 to get hold of the thread data structure itself. This makes the
276 bitmap scheduler fast and totally deterministic.
277       </P
278 ><P
279 >The MLQ scheduler allows multiple threads to run at the same priority.
280 This means that there is no limit on the number of threads in the
281 system, other than the amount of memory available. However operations
282 such as finding the highest priority runnable thread are a little bit
283 more expensive than for the bitmap scheduler.
284       </P
285 ><P
286 >Optionally the MLQ scheduler supports timeslicing, where the scheduler
287 automatically switches from one runnable thread to another when some
288 number of clock ticks have occurred. Timeslicing only comes into play
289 when there are two runnable threads at the same priority and no higher
290 priority runnable threads. If timeslicing is disabled then a thread
291 will not be preempted by another thread of the same priority, and will
292 continue running until either it explicitly yields the processor or
293 until it blocks by, for example, waiting on a synchronization
294 primitive. The configuration options
295 <TT
296 CLASS="VARNAME"
297 >CYGSEM_KERNEL_SCHED_TIMESLICE</TT
298 > and
299 <TT
300 CLASS="VARNAME"
301 >CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS</TT
302 > control
303 timeslicing. The bitmap scheduler does not provide timeslicing
304 support. It only allows one thread per priority level, so it is not
305 possible to preempt the current thread in favour of another one with
306 the same priority.
307       </P
308 ><P
309 >Another important configuration option that affects the MLQ scheduler
310 is <TT
311 CLASS="VARNAME"
312 >CYGIMP_KERNEL_SCHED_SORTED_QUEUES</TT
313 >. This
314 determines what happens when a thread blocks, for example by waiting
315 on a semaphore which has no pending events. The default behaviour of
316 the system is last-in-first-out queuing. For example if several
317 threads are waiting on a semaphore and an event is posted, the thread
318 that gets woken up is the last one that called
319 <TT
320 CLASS="FUNCTION"
321 >cyg_semaphore_wait</TT
322 >. This allows for a simple and
323 fast implementation of both the queue and dequeue operations. However
324 if there are several queued threads with different priorities, it may
325 not be the highest priority one that gets woken up. In practice this
326 is rarely a problem: usually there will be at most one thread waiting
327 on a queue, or when there are several threads they will be of the same
328 priority. However if the application does require strict priority
329 queueing then the option
330 <TT
331 CLASS="VARNAME"
332 >CYGIMP_KERNEL_SCHED_SORTED_QUEUES</TT
333 > should be
334 enabled. There are disadvantages: more work is needed whenever a
335 thread is queued, and the scheduler needs to be locked for this
336 operation so the system's dispatch latency is worse. If the bitmap
337 scheduler is used then priority queueing is automatic and does not
338 involve any penalties.
339       </P
340 ><P
341 >Some kernel functionality is currently only supported with the MLQ
342 scheduler, not the bitmap scheduler. This includes support for SMP
343 systems, and protection against priority inversion using either mutex
344 priority ceilings or priority inheritance.
345       </P
346 ></DIV
347 ><DIV
348 CLASS="REFSECT1"
349 ><A
350 NAME="KERNEL-OVERVIEW-SYNCH-PRIMITIVES"
351 ></A
352 ><H2
353 >Synchronization Primitives</H2
354 ><P
355 >The eCos kernel provides a number of different synchronization
356 primitives: <A
357 HREF="kernel-mutexes.html"
358 >mutexes</A
359 >,
360 <A
361 HREF="kernel-condition-variables.html"
362 >condition variables</A
363 >,
364 <A
365 HREF="kernel-semaphores.html"
366 >counting semaphores</A
367 >,
368 <A
369 HREF="kernel-mail-boxes.html"
370 >mail boxes</A
371 > and
372 <A
373 HREF="kernel-flags.html"
374 >event flags</A
375 >.
376       </P
377 ><P
378 >Mutexes serve a very different purpose from the other primitives. A
379 mutex allows multiple threads to share a resource safely: a thread
380 locks a mutex, manipulates the shared resource, and then unlocks the
381 mutex again. The other primitives are used to communicate information
382 between threads, or alternatively from a DSR associated with an
383 interrupt handler to a thread.
384       </P
385 ><P
386 >When a thread that has locked a mutex needs to wait for some condition
387 to become true, it should use a condition variable. A condition
388 variable is essentially just a place for a thread to wait, and which
389 another thread, or DSR, can use to wake it up. When a thread waits on
390 a condition variable it releases the mutex before waiting, and when it
391 wakes up it reacquires it before proceeding. These operations are
392 atomic so that synchronization race conditions cannot be introduced.
393       </P
394 ><P
395 >A counting semaphore is used to indicate that a particular event has
396 occurred. A consumer thread can wait for this event to occur, and a
397 producer thread or a DSR can post the event. There is a count
398 associated with the semaphore so if the event occurs multiple times in
399 quick succession this information is not lost, and the appropriate
400 number of semaphore wait operations will succeed.
401       </P
402 ><P
403 >Mail boxes are also used to indicate that a particular event has
404 occurred, and allows for one item of data to be exchanged per event.
405 Typically this item of data would be a pointer to some data structure.
406 Because of the need to store this extra data, mail boxes have a
407 finite capacity. If a producer thread generates mail box events
408 faster than they can be consumed then, to avoid overflow, it will be
409 blocked until space is again available in the mail box. This means
410 that mail boxes usually cannot be used by a DSR to wake up a
411 thread. Instead mail boxes are typically only used between threads.
412       </P
413 ><P
414 >Event flags can be used to wait on some number of different events,
415 and to signal that one or several of these events have occurred. This
416 is achieved by associating bits in a bit mask with the different
417 events. Unlike a counting semaphore no attempt is made to keep track
418 of the number of events that have occurred, only the fact that an
419 event has occurred at least once. Unlike a mail box it is not
420 possible to send additional data with the event, but this does mean
421 that there is no possibility of an overflow and hence event flags can
422 be used between a DSR and a thread as well as between threads.
423       </P
424 ><P
425 >The eCos common HAL package provides its own device driver API which
426 contains some of the above synchronization primitives. These allow
427 the DSR for an interrupt handler to signal events to higher-level
428 code. If the configuration includes the eCos kernel package then
429 the driver API routines map directly on to the equivalent kernel
430 routines, allowing interrupt handlers to interact with threads. If the
431 kernel package is not included and the application consists of just a
432 single thread running in polled mode then the driver API is
433 implemented entirely within the common HAL, and with no need to worry
434 about multiple threads the implementation can obviously be rather
435 simpler. 
436       </P
437 ></DIV
438 ><DIV
439 CLASS="REFSECT1"
440 ><A
441 NAME="KERNEL-OVERVIEW-THREADS-INTERRUPTS"
442 ></A
443 ><H2
444 >Threads and Interrupt Handling</H2
445 ><P
446 >During normal operation the processor will be running one of the
447 threads in the system. This may be an application thread, a system
448 thread running inside say the TCP/IP stack, or the idle thread. From
449 time to time a hardware interrupt will occur, causing control to be
450 transferred briefly to an interrupt handler. When the interrupt has
451 been completed the system's scheduler will decide whether to return
452 control to the interrupted thread or to some other runnable thread.
453       </P
454 ><P
455 >Threads and interrupt handlers must be able to interact. If a thread
456 is waiting for some I/O operation to complete, the interrupt handler
457 associated with that I/O must be able to inform the thread that the
458 operation has completed. This can be achieved in a number of ways. One
459 very simple approach is for the interrupt handler to set a volatile
460 variable. A thread can then poll continuously until this flag is set,
461 possibly sleeping for a clock tick in between. Polling continuously
462 means that the cpu time is not available for other activities, which
463 may be acceptable for some but not all applications. Polling once
464 every clock tick imposes much less overhead, but means that the thread
465 may not detect that the I/O event has occurred until an entire clock
466 tick has elapsed. In typical systems this could be as long as 10
467 milliseconds. Such a delay might be acceptable for some applications,
468 but not all.
469       </P
470 ><P
471 >A better solution would be to use one of the synchronization
472 primitives. The interrupt handler could signal a condition variable,
473 post to a semaphore, or use one of the other primitives. The thread
474 would perform a wait operation on the same primitive. It would not
475 consume any cpu cycles until the I/O event had occurred, and when the
476 event does occur the thread can start running again immediately
477 (subject to any higher priority threads that might also be runnable).
478       </P
479 ><P
480 >Synchronization primitives constitute shared data, so care must be
481 taken to avoid problems with concurrent access. If the thread that was
482 interrupted was just performing some calculations then the interrupt
483 handler could manipulate the synchronization primitive quite safely.
484 However if the interrupted thread happened to be inside some kernel
485 call then there is a real possibility that some kernel data structure
486 will be corrupted. 
487       </P
488 ><P
489 >One way of avoiding such problems would be for the kernel functions to
490 disable interrupts when executing any critical region. On most
491 architectures this would be simple to implement and very fast, but it
492 would mean that interrupts would be disabled often and for quite a
493 long time. For some applications that might not matter, but many
494 embedded applications require that the interrupt handler run as soon
495 as possible after the hardware interrupt has occurred. If the kernel
496 relied on disabling interrupts then it would not be able to support
497 such applications.
498       </P
499 ><P
500 >Instead the kernel uses a two-level approach to interrupt handling.
501 Associated with every interrupt vector is an Interrupt Service Routine
502 or ISR, which will run as quickly as possible so that it can service
503 the hardware. However an ISR can make only a small number of kernel
504 calls, mostly related to the interrupt subsystem, and it cannot make
505 any call that would cause a thread to wake up. If an ISR detects that
506 an I/O operation has completed and hence that a thread should be woken
507 up, it can cause the associated Deferred Service Routine or DSR to
508 run. A DSR is allowed to make more kernel calls, for example it can
509 signal a condition variable or post to a semaphore.
510       </P
511 ><P
512 >Disabling interrupts prevents ISRs from running, but very few parts of
513 the system disable interrupts and then only for short periods of time.
514 The main reason for a thread to disable interrupts is to manipulate
515 some state that is shared with an ISR. For example if a thread needs
516 to add another buffer to a linked list of free buffers and the ISR may
517 remove a buffer from this list at any time, the thread would need to
518 disable interrupts for the few instructions needed to manipulate the
519 list. If the hardware raises an interrupt at this time, it remains
520 pending until interrupts are reenabled.
521       </P
522 ><P
523 >Analogous to interrupts being disabled or enabled, the kernel has a
524 scheduler lock. The various kernel functions such as
525 <TT
526 CLASS="FUNCTION"
527 >cyg_mutex_lock</TT
528 > and
529 <TT
530 CLASS="FUNCTION"
531 >cyg_semaphore_post</TT
532 > will claim the scheduler lock,
533 manipulate the kernel data structures, and then release the scheduler
534 lock. If an interrupt results in a DSR being requested and the
535 scheduler is currently locked, the DSR remains pending. When the
536 scheduler lock is released any pending DSRs will run. These may post
537 events to synchronization primitives, causing other higher priority
538 threads to be woken up.
539       </P
540 ><P
541 >For an example, consider the following scenario. The system has a high
542 priority thread A, responsible for processing some data coming from an
543 external device. This device will raise an interrupt when data is
544 available. There are two other threads B and C which spend their time
545 performing calculations and occasionally writing results to a display
546 of some sort. This display is a shared resource so a mutex is used to
547 control access.
548       </P
549 ><P
550 >At a particular moment in time thread A is likely to be blocked,
551 waiting on a semaphore or another synchronization primitive until data
552 is available. Thread B might be running performing some calculations,
553 and thread C is runnable waiting for its next timeslice. Interrupts
554 are enabled, and the scheduler is unlocked because none of the threads
555 are in the middle of a kernel operation. At this point the device
556 raises an interrupt. The hardware transfers control to a low-level
557 interrupt handler provided by eCos which works out exactly which
558 interrupt occurs, and then the corresponding ISR is run. This ISR
559 manipulates the hardware as appropriate, determines that there is now
560 data available, and wants to wake up thread A by posting to the
561 semaphore. However ISR's are not allowed to call
562 <TT
563 CLASS="FUNCTION"
564 >cyg_semaphore_post</TT
565 > directly, so instead the ISR
566 requests that its associated DSR be run and returns. There are no more
567 interrupts to be processed, so the kernel next checks for DSR's. One
568 DSR is pending and the scheduler is currently unlocked, so the DSR can
569 run immediately and post the semaphore. This will have the effect of
570 making thread A runnable again, so the scheduler's data structures are
571 adjusted accordingly. When the DSR returns thread B is no longer the
572 highest priority runnable thread so it will be suspended, and instead
573 thread A gains control over the cpu.
574       </P
575 ><P
576 >In the above example no kernel data structures were being manipulated
577 at the exact moment that the interrupt happened. However that cannot
578 be assumed. Suppose that thread B had finished its current set of
579 calculations and wanted to write the results to the display. It would
580 claim the appropriate mutex and manipulate the display. Now suppose
581 that thread B was timesliced in favour of thread C, and that thread C
582 also finished its calculations and wanted to write the results to the
583 display. It would call <TT
584 CLASS="FUNCTION"
585 >cyg_mutex_lock</TT
586 >. This
587 kernel call locks the scheduler, examines the current state of the
588 mutex, discovers that the mutex is already owned by another thread,
589 suspends the current thread, and switches control to another runnable
590 thread. Another interrupt happens in the middle of this
591 <TT
592 CLASS="FUNCTION"
593 >cyg_mutex_lock</TT
594 > call, causing the ISR to run
595 immediately. The ISR decides that thread A should be woken up so it
596 requests that its DSR be run and returns back to the kernel. At this
597 point there is a pending DSR, but the scheduler is still locked by the
598 call to <TT
599 CLASS="FUNCTION"
600 >cyg_mutex_lock</TT
601 > so the DSR cannot run
602 immediately. Instead the call to <TT
603 CLASS="FUNCTION"
604 >cyg_mutex_lock</TT
605 >
606 is allowed to continue, which at some point involves unlocking the
607 scheduler. The pending DSR can now run, safely post the semaphore, and
608 thus wake up thread A.
609       </P
610 ><P
611 >If the ISR had called <TT
612 CLASS="FUNCTION"
613 >cyg_semaphore_post</TT
614 > directly
615 rather than leaving it to a DSR, it is likely that there would have
616 been some sort of corruption of a kernel data structure. For example
617 the kernel might have completely lost track of one of the threads, and
618 that thread would never have run again. The two-level approach to
619 interrupt handling, ISR's and DSR's, prevents such problems with no
620 need to disable interrupts.
621       </P
622 ></DIV
623 ><DIV
624 CLASS="REFSECT1"
625 ><A
626 NAME="KERNEL-OVERVIEW-CONTEXTS"
627 ></A
628 ><H2
629 >Calling Contexts</H2
630 ><P
631 >eCos defines a number of contexts. Only certain calls are allowed from
632 inside each context, for example most operations on threads or
633 synchronization primitives are not allowed from ISR context. The
634 different contexts are initialization, thread, ISR and DSR.
635       </P
636 ><P
637 >When eCos starts up it goes through a number of phases, including
638 setting up the hardware and invoking C++ static constructors. During
639 this time interrupts are disabled and the scheduler is locked. When a
640 configuration includes the kernel package the final operation is a
641 call to <A
642 HREF="kernel-schedcontrol.html"
643 ><TT
644 CLASS="FUNCTION"
645 >cyg_scheduler_start</TT
646 ></A
647 >.
648 At this point interrupts are enabled, the scheduler is unlocked, and
649 control is transferred to the highest priority runnable thread. If the
650 configuration also includes the C library package then usually the C
651 library startup package will have created a thread which will call the
652 application's <TT
653 CLASS="FUNCTION"
654 >main</TT
655 > entry point.
656       </P
657 ><P
658 >Some application code can also run before the scheduler is started,
659 and this code runs in initialization context. If the application is
660 written partly or completely in C++ then the constructors for any
661 static objects will be run. Alternatively application code can define
662 a function <TT
663 CLASS="FUNCTION"
664 >cyg_user_start</TT
665 > which gets called after
666 any C++ static constructors. This allows applications to be written
667 entirely in C.
668       </P
669 ><TABLE
670 BORDER="5"
671 BGCOLOR="#E0E0F0"
672 WIDTH="70%"
673 ><TR
674 ><TD
675 ><PRE
676 CLASS="PROGRAMLISTING"
677 >void
678 cyg_user_start(void)
679 {
680     /* Perform application-specific initialization here */
681 }
682       </PRE
683 ></TD
684 ></TR
685 ></TABLE
686 ><P
687 >It is not necessary for applications to provide a
688 <TT
689 CLASS="FUNCTION"
690 >cyg_user_start</TT
691 > function since the system will
692 provide a default implementation which does nothing.
693       </P
694 ><P
695 >Typical operations that are performed from inside static constructors
696 or <TT
697 CLASS="FUNCTION"
698 >cyg_user_start</TT
699 > include creating threads,
700 synchronization primitives, setting up alarms, and registering
701 application-specific interrupt handlers. In fact for many applications
702 all such creation operations happen at this time, using statically
703 allocated data, avoiding any need for dynamic memory allocation or
704 other overheads.
705       </P
706 ><P
707 >Code running in initialization context runs with interrupts disabled
708 and the scheduler locked. It is not permitted to reenable interrupts
709 or unlock the scheduler because the system is not guaranteed to be in
710 a totally consistent state at this point. A consequence is that
711 initialization code cannot use synchronization primitives such as
712 <TT
713 CLASS="FUNCTION"
714 >cyg_semaphore_wait</TT
715 > to wait for an external event.
716 It is permitted to lock and unlock a mutex: there are no other threads
717 running so it is guaranteed that the mutex is not yet locked, and
718 therefore the lock operation will never block; this is useful when
719 making library calls that may use a mutex internally.
720       </P
721 ><P
722 >At the end of the startup sequence the system will call
723 <TT
724 CLASS="FUNCTION"
725 >cyg_scheduler_start</TT
726 > and the various threads will
727 start running. In thread context nearly all of the kernel functions
728 are available. There may be some restrictions on interrupt-related
729 operations, depending on the target hardware. For example the hardware
730 may require that interrupts be acknowledged in the ISR or DSR before
731 control returns to thread context, in which case
732 <TT
733 CLASS="FILENAME"
734 >cyg_interrupt_acknowledge</TT
735 > should not be called
736 by a thread.
737       </P
738 ><P
739 >At any time the processor may receive an external interrupt, causing
740 control to be transferred from the current thread. Typically a VSR
741 provided by eCos will run and determine exactly which interrupt
742 occurred. Then the VSR will switch to the appropriate ISR, which can
743 be provided by a HAL package, a device driver, or by the application.
744 During this time the system is running at ISR context, and most of the
745 kernel function calls are disallowed. This includes the various
746 synchronization primitives, so for example an ISR is not allowed to
747 post to a semaphore to indicate that an event has happened. Usually
748 the only operations that should be performed from inside an ISR are
749 ones related to the interrupt subsystem itself, for example masking an
750 interrupt or acknowledging that an interrupt has been processed. On
751 SMP systems it is also possible to use spinlocks from ISR context.
752       </P
753 ><P
754 >When an ISR returns it can request that the corresponding DSR be run
755 as soon as it is safe to do so, and that will run in DSR context. This
756 context is also used for running alarm functions, and threads can
757 switch temporarily to DSR context by locking the scheduler. Only
758 certain kernel functions can be called from DSR context, although more
759 than in ISR context. In particular it is possible to use any
760 synchronization primitives which cannot block.  These include
761 <TT
762 CLASS="FUNCTION"
763 >cyg_semaphore_post</TT
764 >,
765 <TT
766 CLASS="FILENAME"
767 >cyg_cond_signal</TT
768 >,
769 <TT
770 CLASS="FUNCTION"
771 >cyg_cond_broadcast</TT
772 >,
773 <TT
774 CLASS="FUNCTION"
775 >cyg_flag_setbits</TT
776 >, and
777 <TT
778 CLASS="FUNCTION"
779 >cyg_mbox_tryput</TT
780 >. It is not possible to use any
781 primitives that may block such as
782 <TT
783 CLASS="FUNCTION"
784 >cyg_semaphore_wait</TT
785 >,
786 <TT
787 CLASS="FUNCTION"
788 >cyg_mutex_lock</TT
789 >, or
790 <TT
791 CLASS="FUNCTION"
792 >cyg_mbox_put</TT
793 >. Calling such functions from inside
794 a DSR may cause the system to hang.
795       </P
796 ><P
797 >The specific documentation for the various kernel functions gives more
798 details about valid contexts.
799       </P
800 ></DIV
801 ><DIV
802 CLASS="REFSECT1"
803 ><A
804 NAME="KERNEL-OVERVIEW-ERRORS"
805 ></A
806 ><H2
807 >Error Handling and Assertions</H2
808 ><P
809 >In many APIs each function is expected to perform some validation of
810 its parameters and possibly of the current state of the system. This
811 is supposed to ensure that each function is used correctly, and that
812 application code is not attempting to perform a semaphore operation on
813 a mutex or anything like that. If an error is detected then a suitable
814 error code is returned, for example the POSIX function
815 <TT
816 CLASS="FUNCTION"
817 >pthread_mutex_lock</TT
818 > can return various error codes
819 including <TT
820 CLASS="LITERAL"
821 >EINVAL</TT
822 > and <TT
823 CLASS="LITERAL"
824 >EDEADLK</TT
825 >.
826 There are a number of problems with this approach, especially in the
827 context of deeply embedded systems:
828       </P
829 ><P
830 ></P
831 ><OL
832 TYPE="1"
833 ><LI
834 ><P
835 >Performing these checks inside the mutex lock and all the other
836 functions requires extra cpu cycles and adds significantly to the code
837 size. Even if the application is written correctly and only makes
838 system function calls with sensible arguments and under the right
839 conditions, these overheads still exist.
840         </P
841 ></LI
842 ><LI
843 ><P
844 >Returning an error code is only useful if the calling code detects
845 these error codes and takes appropriate action. In practice the
846 calling code will often ignore any errors because the programmer
847 <SPAN
848 CLASS="emphasis"
849 ><I
850 CLASS="EMPHASIS"
851 >&#8220;knows&#8221;</I
852 ></SPAN
853 > that the function is being
854 used correctly. If the programmer is mistaken then an error condition
855 may be detected and reported, but the application continues running
856 anyway and is likely to fail some time later in mysterious ways.
857         </P
858 ></LI
859 ><LI
860 ><P
861 >If the calling code does always check for error codes, that adds yet
862 more cpu cycles and code size overhead. 
863         </P
864 ></LI
865 ><LI
866 ><P
867 >Usually there will be no way to recover from certain errors, so if the
868 application code detected an error such as <TT
869 CLASS="LITERAL"
870 >EINVAL</TT
871 >
872 then all it could do is abort the application somehow.
873         </P
874 ></LI
875 ></OL
876 ><P
877 >The approach taken within the eCos kernel is different. Functions such
878 as <TT
879 CLASS="FUNCTION"
880 >cyg_mutex_lock</TT
881 > will not return an error code.
882 Instead they contain various assertions, which can be enabled or
883 disabled. During the development process assertions are normally left
884 enabled, and the various kernel functions will perform parameter
885 checks and other system consistency checks. If a problem is detected
886 then an assertion failure will be reported and the application will be
887 terminated. In a typical debug session a suitable breakpoint will have
888 been installed and the developer can now examine the state of the
889 system and work out exactly what is going on. Towards the end of the
890 development cycle assertions will be disabled by manipulating
891 configuration options within the eCos infrastructure package, and all
892 assertions will be eliminated at compile-time. The assumption is that
893 by this time the application code has been mostly debugged: the
894 initial version of the code might have tried to perform a semaphore
895 operation on a mutex, but any problems like that will have been fixed
896 some time ago. This approach has a number of advantages:
897       </P
898 ><P
899 ></P
900 ><OL
901 TYPE="1"
902 ><LI
903 ><P
904 >In the final application there will be no overheads for checking
905 parameters and other conditions. All that code will have been
906 eliminated at compile-time.
907         </P
908 ></LI
909 ><LI
910 ><P
911 >Because the final application will not suffer any overheads, it is
912 reasonable for the system to do more work during the development
913 process. In particular the various assertions can test for more error
914 conditions and more complicated errors. When an error is detected
915 it is possible to give a text message describing the error rather than
916 just return an error code.
917         </P
918 ></LI
919 ><LI
920 ><P
921 >There is no need for application programmers to handle error codes
922 returned by various kernel function calls. This simplifies the
923 application code.
924         </P
925 ></LI
926 ><LI
927 ><P
928 >If an error is detected then an assertion failure will be reported
929 immediately and the application will be halted. There is no
930 possibility of an error condition being ignored because application
931 code did not check for an error code.
932         </P
933 ></LI
934 ></OL
935 ><P
936 >Although none of the kernel functions return an error code, many of
937 them do return a status condition. For example the function
938 <TT
939 CLASS="FUNCTION"
940 >cyg_semaphore_timed_wait</TT
941 > waits until either an
942 event has been posted to a semaphore, or until a certain number of
943 clock ticks have occurred. Usually the calling code will need to know
944 whether the wait operation succeeded or whether a timeout occurred.
945 <TT
946 CLASS="FUNCTION"
947 >cyg_semaphore_timed_wait</TT
948 > returns a boolean: a
949 return value of zero or false indicates a timeout, a non-zero return
950 value indicates that the wait succeeded.
951       </P
952 ><P
953 >In conventional APIs one common error conditions is lack of memory.
954 For example the POSIX function <TT
955 CLASS="FUNCTION"
956 >pthread_create</TT
957 >
958 usually has to allocate some memory dynamically for the thread stack
959 and other per-thread data. If the target hardware does not have enough
960 memory to meet all demands, or more commonly if the application
961 contains a memory leak, then there may not be enough memory available
962 and the function call would fail. The eCos kernel avoids such problems
963 by never performing any dynamic memory allocation. Instead it is the
964 responsibility of the application code to provide all the memory
965 required for kernel data structures and other needs. In the case of
966 <TT
967 CLASS="FUNCTION"
968 >cyg_thread_create</TT
969 > this means a
970 <SPAN
971 CLASS="STRUCTNAME"
972 >cyg_thread</SPAN
973 > data structure to hold the thread
974 details, and a <SPAN
975 CLASS="TYPE"
976 >char</SPAN
977 > array for the thread stack.
978       </P
979 ><P
980 >In many applications this approach results in all data structures
981 being allocated statically rather than dynamically. This has several
982 advantages. If the application is in fact too large for the target
983 hardware's memory then there will be an error at link-time rather than
984 at run-time, making the problem much easier to diagnose. Static
985 allocation does not involve any of the usual overheads associated with
986 dynamic allocation, for example there is no need to keep track of the
987 various free blocks in the system, and it may be possible to eliminate
988 <TT
989 CLASS="FUNCTION"
990 >malloc</TT
991 > from the system completely. Problems such
992 as fragmentation and memory leaks cannot occur if all data is
993 allocated statically. However, some applications are sufficiently
994 complicated that dynamic memory allocation is required, and the
995 various kernel functions do not distinguish between statically and
996 dynamically allocated memory. It still remains the responsibility of
997 the calling code to ensure that sufficient memory is available, and
998 passing null pointers to the kernel will result in assertions or
999 system failure.
1000       </P
1001 ></DIV
1002 ><DIV
1003 CLASS="NAVFOOTER"
1004 ><HR
1005 ALIGN="LEFT"
1006 WIDTH="100%"><TABLE
1007 SUMMARY="Footer navigation table"
1008 WIDTH="100%"
1009 BORDER="0"
1010 CELLPADDING="0"
1011 CELLSPACING="0"
1012 ><TR
1013 ><TD
1014 WIDTH="33%"
1015 ALIGN="left"
1016 VALIGN="top"
1017 ><A
1018 HREF="kernel.html"
1019 ACCESSKEY="P"
1020 >Prev</A
1021 ></TD
1022 ><TD
1023 WIDTH="34%"
1024 ALIGN="center"
1025 VALIGN="top"
1026 ><A
1027 HREF="ecos-ref.html"
1028 ACCESSKEY="H"
1029 >Home</A
1030 ></TD
1031 ><TD
1032 WIDTH="33%"
1033 ALIGN="right"
1034 VALIGN="top"
1035 ><A
1036 HREF="kernel-smp.html"
1037 ACCESSKEY="N"
1038 >Next</A
1039 ></TD
1040 ></TR
1041 ><TR
1042 ><TD
1043 WIDTH="33%"
1044 ALIGN="left"
1045 VALIGN="top"
1046 >The eCos Kernel</TD
1047 ><TD
1048 WIDTH="34%"
1049 ALIGN="center"
1050 VALIGN="top"
1051 ><A
1052 HREF="kernel.html"
1053 ACCESSKEY="U"
1054 >Up</A
1055 ></TD
1056 ><TD
1057 WIDTH="33%"
1058 ALIGN="right"
1059 VALIGN="top"
1060 >SMP Support</TD
1061 ></TR
1062 ></TABLE
1063 ></DIV
1064 ></BODY
1065 ></HTML
1066 >