1 |
28 |
unneback |
<!-- 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 -- 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 µ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 µ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 — 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 |
|
|
>“knows”</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 |
|
|
>
|