]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - doc/html/ref/kernel-overview.html
Cleanup CVS ipmorted branch
[karo-tx-redboot.git] / doc / html / ref / kernel-overview.html
diff --git a/doc/html/ref/kernel-overview.html b/doc/html/ref/kernel-overview.html
deleted file mode 100644 (file)
index 576d847..0000000
+++ /dev/null
@@ -1,1066 +0,0 @@
-<!-- Copyright (C) 2003 Red Hat, Inc.                                -->
-<!-- This material may be distributed only subject to the terms      -->
-<!-- and conditions set forth in the Open Publication License, v1.0  -->
-<!-- or later (the latest version is presently available at          -->
-<!-- http://www.opencontent.org/openpub/).                           -->
-<!-- Distribution of the work or derivative of the work in any       -->
-<!-- standard (paper) book form is prohibited unless prior           -->
-<!-- permission is obtained from the copyright holder.               -->
-<HTML
-><HEAD
-><TITLE
->Kernel Overview</TITLE
-><meta name="MSSmartTagsPreventParsing" content="TRUE">
-<META
-NAME="GENERATOR"
-CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
-"><LINK
-REL="HOME"
-TITLE="eCos Reference Manual"
-HREF="ecos-ref.html"><LINK
-REL="UP"
-TITLE="The eCos Kernel"
-HREF="kernel.html"><LINK
-REL="PREVIOUS"
-TITLE="The eCos Kernel"
-HREF="kernel.html"><LINK
-REL="NEXT"
-TITLE="SMP Support"
-HREF="kernel-smp.html"></HEAD
-><BODY
-CLASS="REFENTRY"
-BGCOLOR="#FFFFFF"
-TEXT="#000000"
-LINK="#0000FF"
-VLINK="#840084"
-ALINK="#0000FF"
-><DIV
-CLASS="NAVHEADER"
-><TABLE
-SUMMARY="Header navigation table"
-WIDTH="100%"
-BORDER="0"
-CELLPADDING="0"
-CELLSPACING="0"
-><TR
-><TH
-COLSPAN="3"
-ALIGN="center"
->eCos Reference Manual</TH
-></TR
-><TR
-><TD
-WIDTH="10%"
-ALIGN="left"
-VALIGN="bottom"
-><A
-HREF="kernel.html"
-ACCESSKEY="P"
->Prev</A
-></TD
-><TD
-WIDTH="80%"
-ALIGN="center"
-VALIGN="bottom"
-></TD
-><TD
-WIDTH="10%"
-ALIGN="right"
-VALIGN="bottom"
-><A
-HREF="kernel-smp.html"
-ACCESSKEY="N"
->Next</A
-></TD
-></TR
-></TABLE
-><HR
-ALIGN="LEFT"
-WIDTH="100%"></DIV
-><H1
-><A
-NAME="KERNEL-OVERVIEW">Kernel Overview</H1
-><DIV
-CLASS="REFNAMEDIV"
-><A
-NAME="AEN56"
-></A
-><H2
->Name</H2
->Kernel&nbsp;--&nbsp;Overview of the eCos Kernel</DIV
-><DIV
-CLASS="REFSECT1"
-><A
-NAME="KERNEL-OVERVIEW-DESCRIPTION"
-></A
-><H2
->Description</H2
-><P
->The kernel is one of the key packages in all of eCos. It provides the
-core functionality needed for developing multi-threaded applications:
-      </P
-><P
-></P
-><OL
-TYPE="1"
-><LI
-><P
->The ability to create new threads in the system, either during startup
-or when the system is already running.
-        </P
-></LI
-><LI
-><P
->Control over the various threads in the system, for example
-manipulating their priorities.
-        </P
-></LI
-><LI
-><P
->A choice of schedulers, determining which thread should currently be
-running. 
-        </P
-></LI
-><LI
-><P
->A range of synchronization primitives, allowing threads to interact
-and share data safely.
-        </P
-></LI
-><LI
-><P
->Integration with the system's support for interrupts and exceptions.
-        </P
-></LI
-></OL
-><P
->In some other operating systems the kernel provides additional
-functionality. For example the kernel may also provide memory
-allocation functionality, and device drivers may be part of the kernel
-as well. This is not the case for eCos. Memory allocation is handled
-by a separate package. Similary each device driver will typically be a
-separate package. Various packages are combined and configured using
-the eCos configuration technology to meet the requirements of the
-application.
-      </P
-><P
->The eCos kernel package is optional. It is possible to write
-single-threaded applications which do not use any kernel
-functionality, for example RedBoot. Typically such applications are
-based around a central polling loop, continually checking all devices
-and taking appropriate action when I/O occurs. A small amount of
-calculation is possible every iteration, at the cost of an increased
-delay between an I/O event occurring and the polling loop detecting
-the event. When the requirements are straightforward it may well be
-easier to develop the application using a polling loop, avoiding the
-complexities of multiple threads and synchronization between threads.
-As requirements get more complicated a multi-threaded solution becomes
-more appropriate, requiring the use of the kernel. In fact some of the
-more advanced packages in eCos, for example the TCP/IP stack, use
-multi-threading internally. Therefore if the application uses any of
-those packages then the kernel becomes a required package, not an
-optional one.
-      </P
-><P
->The kernel functionality can be used in one of two ways. The kernel
-provides its own C API, with functions like
-<TT
-CLASS="FUNCTION"
->cyg_thread_create</TT
-> and
-<TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
->. These can be called directly from
-application code or from other packages. Alternatively there are a
-number of packages which provide compatibility with existing API's,
-for example POSIX threads or &micro;ITRON. These allow application
-code to call standard functions such as
-<TT
-CLASS="FUNCTION"
->pthread_create</TT
->, and those functions are
-implemented using the basic functionality provided by the eCos kernel.
-Using compatibility packages in an eCos application can make it much
-easier to reuse code developed in other environments, and to share
-code.
-      </P
-><P
->Although the different compatibility packages have similar
-requirements on the underlying kernel, for example the ability to
-create a new thread, there are differences in the exact semantics. For
-example, strict &micro;ITRON compliance requires that kernel
-timeslicing is disabled. This is achieved largely through the
-configuration technology. The kernel provides a number of
-configuration options that control the exact semantics that are
-provided, and the various compatibility packages require particular
-settings for those options. This has two important consequences.
-First, it is not usually possible to have two different compatibility
-packages in one eCos configuration because they will have conflicting
-requirements on the underlying kernel. Second, the semantics of the
-kernel's own API are only loosely defined because of the many
-configuration options. For example <TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
->
-will always attempt to lock a mutex, but various configuration options
-determine the behaviour when the mutex is already locked and there is
-a possibility of priority inversion.
-      </P
-><P
->The optional nature of the kernel package presents some complications
-for other code, especially device drivers. Wherever possible a device
-driver should work whether or not the kernel is present. However there
-are some parts of the system, especially those related to interrupt
-handling, which should be implemented differently in multi-threaded
-environments containing the eCos kernel and in single-threaded
-environments without the kernel. To cope with both scenarios the
-common HAL package provides a driver API, with functions such as
-<TT
-CLASS="FUNCTION"
->cyg_drv_interrupt_attach</TT
->. When the kernel package
-is present these driver API functions map directly on to the
-equivalent kernel functions such as
-<TT
-CLASS="FUNCTION"
->cyg_interrupt_attach</TT
->, using macros to avoid any
-overheads. When the kernel is absent the common HAL package implements
-the driver API directly, but this implementation is simpler than the
-one in the kernel because it can assume a single-threaded environment. 
-      </P
-></DIV
-><DIV
-CLASS="REFSECT1"
-><A
-NAME="KERNEL-OVERVIEW-SCHEDULERS"
-></A
-><H2
->Schedulers</H2
-><P
->When a system involves multiple threads, a scheduler is needed to
-determine which thread should currently be running. The eCos kernel
-can be configured with one of two schedulers, the bitmap scheduler and
-the multi-level queue (MLQ) scheduler. The bitmap scheduler is
-somewhat more efficient, but has a number of limitations. Most systems
-will instead use the MLQ scheduler. Other schedulers may be added in
-the future, either as extensions to the kernel package or in separate
-packages.
-      </P
-><P
->Both the bitmap and the MLQ scheduler use a simple numerical priority
-to determine which thread should be running. The number of priority
-levels is configurable via the option
-<TT
-CLASS="VARNAME"
->CYGNUM_KERNEL_SCHED_PRIORITIES</TT
->, but a typical
-system will have up to 32 priority levels. Therefore thread priorities
-will be in the range 0 to 31, with 0 being the highest priority and 31
-the lowest. Usually only the system's idle thread will run at the
-lowest priority. Thread priorities are absolute, so the kernel will
-only run a lower-priority thread if all higher-priority threads are
-currently blocked.
-      </P
-><P
->The bitmap scheduler only allows one thread per priority level, so if
-the system is configured with 32 priority levels then it is limited to
-only 32 threads &#8212; still enough for many applications. A simple
-bitmap can be used to keep track of which threads are currently
-runnable. Bitmaps can also be used to keep track of threads waiting on
-a mutex or other synchronization primitive. Identifying the
-highest-priority runnable or waiting thread involves a simple
-operation on the bitmap, and an array index operation can then be used
-to get hold of the thread data structure itself. This makes the
-bitmap scheduler fast and totally deterministic.
-      </P
-><P
->The MLQ scheduler allows multiple threads to run at the same priority.
-This means that there is no limit on the number of threads in the
-system, other than the amount of memory available. However operations
-such as finding the highest priority runnable thread are a little bit
-more expensive than for the bitmap scheduler.
-      </P
-><P
->Optionally the MLQ scheduler supports timeslicing, where the scheduler
-automatically switches from one runnable thread to another when some
-number of clock ticks have occurred. Timeslicing only comes into play
-when there are two runnable threads at the same priority and no higher
-priority runnable threads. If timeslicing is disabled then a thread
-will not be preempted by another thread of the same priority, and will
-continue running until either it explicitly yields the processor or
-until it blocks by, for example, waiting on a synchronization
-primitive. The configuration options
-<TT
-CLASS="VARNAME"
->CYGSEM_KERNEL_SCHED_TIMESLICE</TT
-> and
-<TT
-CLASS="VARNAME"
->CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS</TT
-> control
-timeslicing. The bitmap scheduler does not provide timeslicing
-support. It only allows one thread per priority level, so it is not
-possible to preempt the current thread in favour of another one with
-the same priority.
-      </P
-><P
->Another important configuration option that affects the MLQ scheduler
-is <TT
-CLASS="VARNAME"
->CYGIMP_KERNEL_SCHED_SORTED_QUEUES</TT
->. This
-determines what happens when a thread blocks, for example by waiting
-on a semaphore which has no pending events. The default behaviour of
-the system is last-in-first-out queuing. For example if several
-threads are waiting on a semaphore and an event is posted, the thread
-that gets woken up is the last one that called
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_wait</TT
->. This allows for a simple and
-fast implementation of both the queue and dequeue operations. However
-if there are several queued threads with different priorities, it may
-not be the highest priority one that gets woken up. In practice this
-is rarely a problem: usually there will be at most one thread waiting
-on a queue, or when there are several threads they will be of the same
-priority. However if the application does require strict priority
-queueing then the option
-<TT
-CLASS="VARNAME"
->CYGIMP_KERNEL_SCHED_SORTED_QUEUES</TT
-> should be
-enabled. There are disadvantages: more work is needed whenever a
-thread is queued, and the scheduler needs to be locked for this
-operation so the system's dispatch latency is worse. If the bitmap
-scheduler is used then priority queueing is automatic and does not
-involve any penalties.
-      </P
-><P
->Some kernel functionality is currently only supported with the MLQ
-scheduler, not the bitmap scheduler. This includes support for SMP
-systems, and protection against priority inversion using either mutex
-priority ceilings or priority inheritance.
-      </P
-></DIV
-><DIV
-CLASS="REFSECT1"
-><A
-NAME="KERNEL-OVERVIEW-SYNCH-PRIMITIVES"
-></A
-><H2
->Synchronization Primitives</H2
-><P
->The eCos kernel provides a number of different synchronization
-primitives: <A
-HREF="kernel-mutexes.html"
->mutexes</A
->,
-<A
-HREF="kernel-condition-variables.html"
->condition variables</A
->,
-<A
-HREF="kernel-semaphores.html"
->counting semaphores</A
->,
-<A
-HREF="kernel-mail-boxes.html"
->mail boxes</A
-> and
-<A
-HREF="kernel-flags.html"
->event flags</A
->.
-      </P
-><P
->Mutexes serve a very different purpose from the other primitives. A
-mutex allows multiple threads to share a resource safely: a thread
-locks a mutex, manipulates the shared resource, and then unlocks the
-mutex again. The other primitives are used to communicate information
-between threads, or alternatively from a DSR associated with an
-interrupt handler to a thread.
-      </P
-><P
->When a thread that has locked a mutex needs to wait for some condition
-to become true, it should use a condition variable. A condition
-variable is essentially just a place for a thread to wait, and which
-another thread, or DSR, can use to wake it up. When a thread waits on
-a condition variable it releases the mutex before waiting, and when it
-wakes up it reacquires it before proceeding. These operations are
-atomic so that synchronization race conditions cannot be introduced.
-      </P
-><P
->A counting semaphore is used to indicate that a particular event has
-occurred. A consumer thread can wait for this event to occur, and a
-producer thread or a DSR can post the event. There is a count
-associated with the semaphore so if the event occurs multiple times in
-quick succession this information is not lost, and the appropriate
-number of semaphore wait operations will succeed.
-      </P
-><P
->Mail boxes are also used to indicate that a particular event has
-occurred, and allows for one item of data to be exchanged per event.
-Typically this item of data would be a pointer to some data structure.
-Because of the need to store this extra data, mail boxes have a
-finite capacity. If a producer thread generates mail box events
-faster than they can be consumed then, to avoid overflow, it will be
-blocked until space is again available in the mail box. This means
-that mail boxes usually cannot be used by a DSR to wake up a
-thread. Instead mail boxes are typically only used between threads.
-      </P
-><P
->Event flags can be used to wait on some number of different events,
-and to signal that one or several of these events have occurred. This
-is achieved by associating bits in a bit mask with the different
-events. Unlike a counting semaphore no attempt is made to keep track
-of the number of events that have occurred, only the fact that an
-event has occurred at least once. Unlike a mail box it is not
-possible to send additional data with the event, but this does mean
-that there is no possibility of an overflow and hence event flags can
-be used between a DSR and a thread as well as between threads.
-      </P
-><P
->The eCos common HAL package provides its own device driver API which
-contains some of the above synchronization primitives. These allow
-the DSR for an interrupt handler to signal events to higher-level
-code. If the configuration includes the eCos kernel package then
-the driver API routines map directly on to the equivalent kernel
-routines, allowing interrupt handlers to interact with threads. If the
-kernel package is not included and the application consists of just a
-single thread running in polled mode then the driver API is
-implemented entirely within the common HAL, and with no need to worry
-about multiple threads the implementation can obviously be rather
-simpler. 
-      </P
-></DIV
-><DIV
-CLASS="REFSECT1"
-><A
-NAME="KERNEL-OVERVIEW-THREADS-INTERRUPTS"
-></A
-><H2
->Threads and Interrupt Handling</H2
-><P
->During normal operation the processor will be running one of the
-threads in the system. This may be an application thread, a system
-thread running inside say the TCP/IP stack, or the idle thread. From
-time to time a hardware interrupt will occur, causing control to be
-transferred briefly to an interrupt handler. When the interrupt has
-been completed the system's scheduler will decide whether to return
-control to the interrupted thread or to some other runnable thread.
-      </P
-><P
->Threads and interrupt handlers must be able to interact. If a thread
-is waiting for some I/O operation to complete, the interrupt handler
-associated with that I/O must be able to inform the thread that the
-operation has completed. This can be achieved in a number of ways. One
-very simple approach is for the interrupt handler to set a volatile
-variable. A thread can then poll continuously until this flag is set,
-possibly sleeping for a clock tick in between. Polling continuously
-means that the cpu time is not available for other activities, which
-may be acceptable for some but not all applications. Polling once
-every clock tick imposes much less overhead, but means that the thread
-may not detect that the I/O event has occurred until an entire clock
-tick has elapsed. In typical systems this could be as long as 10
-milliseconds. Such a delay might be acceptable for some applications,
-but not all.
-      </P
-><P
->A better solution would be to use one of the synchronization
-primitives. The interrupt handler could signal a condition variable,
-post to a semaphore, or use one of the other primitives. The thread
-would perform a wait operation on the same primitive. It would not
-consume any cpu cycles until the I/O event had occurred, and when the
-event does occur the thread can start running again immediately
-(subject to any higher priority threads that might also be runnable).
-      </P
-><P
->Synchronization primitives constitute shared data, so care must be
-taken to avoid problems with concurrent access. If the thread that was
-interrupted was just performing some calculations then the interrupt
-handler could manipulate the synchronization primitive quite safely.
-However if the interrupted thread happened to be inside some kernel
-call then there is a real possibility that some kernel data structure
-will be corrupted. 
-      </P
-><P
->One way of avoiding such problems would be for the kernel functions to
-disable interrupts when executing any critical region. On most
-architectures this would be simple to implement and very fast, but it
-would mean that interrupts would be disabled often and for quite a
-long time. For some applications that might not matter, but many
-embedded applications require that the interrupt handler run as soon
-as possible after the hardware interrupt has occurred. If the kernel
-relied on disabling interrupts then it would not be able to support
-such applications.
-      </P
-><P
->Instead the kernel uses a two-level approach to interrupt handling.
-Associated with every interrupt vector is an Interrupt Service Routine
-or ISR, which will run as quickly as possible so that it can service
-the hardware. However an ISR can make only a small number of kernel
-calls, mostly related to the interrupt subsystem, and it cannot make
-any call that would cause a thread to wake up. If an ISR detects that
-an I/O operation has completed and hence that a thread should be woken
-up, it can cause the associated Deferred Service Routine or DSR to
-run. A DSR is allowed to make more kernel calls, for example it can
-signal a condition variable or post to a semaphore.
-      </P
-><P
->Disabling interrupts prevents ISRs from running, but very few parts of
-the system disable interrupts and then only for short periods of time.
-The main reason for a thread to disable interrupts is to manipulate
-some state that is shared with an ISR. For example if a thread needs
-to add another buffer to a linked list of free buffers and the ISR may
-remove a buffer from this list at any time, the thread would need to
-disable interrupts for the few instructions needed to manipulate the
-list. If the hardware raises an interrupt at this time, it remains
-pending until interrupts are reenabled.
-      </P
-><P
->Analogous to interrupts being disabled or enabled, the kernel has a
-scheduler lock. The various kernel functions such as
-<TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
-> and
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_post</TT
-> will claim the scheduler lock,
-manipulate the kernel data structures, and then release the scheduler
-lock. If an interrupt results in a DSR being requested and the
-scheduler is currently locked, the DSR remains pending. When the
-scheduler lock is released any pending DSRs will run. These may post
-events to synchronization primitives, causing other higher priority
-threads to be woken up.
-      </P
-><P
->For an example, consider the following scenario. The system has a high
-priority thread A, responsible for processing some data coming from an
-external device. This device will raise an interrupt when data is
-available. There are two other threads B and C which spend their time
-performing calculations and occasionally writing results to a display
-of some sort. This display is a shared resource so a mutex is used to
-control access.
-      </P
-><P
->At a particular moment in time thread A is likely to be blocked,
-waiting on a semaphore or another synchronization primitive until data
-is available. Thread B might be running performing some calculations,
-and thread C is runnable waiting for its next timeslice. Interrupts
-are enabled, and the scheduler is unlocked because none of the threads
-are in the middle of a kernel operation. At this point the device
-raises an interrupt. The hardware transfers control to a low-level
-interrupt handler provided by eCos which works out exactly which
-interrupt occurs, and then the corresponding ISR is run. This ISR
-manipulates the hardware as appropriate, determines that there is now
-data available, and wants to wake up thread A by posting to the
-semaphore. However ISR's are not allowed to call
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_post</TT
-> directly, so instead the ISR
-requests that its associated DSR be run and returns. There are no more
-interrupts to be processed, so the kernel next checks for DSR's. One
-DSR is pending and the scheduler is currently unlocked, so the DSR can
-run immediately and post the semaphore. This will have the effect of
-making thread A runnable again, so the scheduler's data structures are
-adjusted accordingly. When the DSR returns thread B is no longer the
-highest priority runnable thread so it will be suspended, and instead
-thread A gains control over the cpu.
-      </P
-><P
->In the above example no kernel data structures were being manipulated
-at the exact moment that the interrupt happened. However that cannot
-be assumed. Suppose that thread B had finished its current set of
-calculations and wanted to write the results to the display. It would
-claim the appropriate mutex and manipulate the display. Now suppose
-that thread B was timesliced in favour of thread C, and that thread C
-also finished its calculations and wanted to write the results to the
-display. It would call <TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
->. This
-kernel call locks the scheduler, examines the current state of the
-mutex, discovers that the mutex is already owned by another thread,
-suspends the current thread, and switches control to another runnable
-thread. Another interrupt happens in the middle of this
-<TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
-> call, causing the ISR to run
-immediately. The ISR decides that thread A should be woken up so it
-requests that its DSR be run and returns back to the kernel. At this
-point there is a pending DSR, but the scheduler is still locked by the
-call to <TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
-> so the DSR cannot run
-immediately. Instead the call to <TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
->
-is allowed to continue, which at some point involves unlocking the
-scheduler. The pending DSR can now run, safely post the semaphore, and
-thus wake up thread A.
-      </P
-><P
->If the ISR had called <TT
-CLASS="FUNCTION"
->cyg_semaphore_post</TT
-> directly
-rather than leaving it to a DSR, it is likely that there would have
-been some sort of corruption of a kernel data structure. For example
-the kernel might have completely lost track of one of the threads, and
-that thread would never have run again. The two-level approach to
-interrupt handling, ISR's and DSR's, prevents such problems with no
-need to disable interrupts.
-      </P
-></DIV
-><DIV
-CLASS="REFSECT1"
-><A
-NAME="KERNEL-OVERVIEW-CONTEXTS"
-></A
-><H2
->Calling Contexts</H2
-><P
->eCos defines a number of contexts. Only certain calls are allowed from
-inside each context, for example most operations on threads or
-synchronization primitives are not allowed from ISR context. The
-different contexts are initialization, thread, ISR and DSR.
-      </P
-><P
->When eCos starts up it goes through a number of phases, including
-setting up the hardware and invoking C++ static constructors. During
-this time interrupts are disabled and the scheduler is locked. When a
-configuration includes the kernel package the final operation is a
-call to <A
-HREF="kernel-schedcontrol.html"
-><TT
-CLASS="FUNCTION"
->cyg_scheduler_start</TT
-></A
->.
-At this point interrupts are enabled, the scheduler is unlocked, and
-control is transferred to the highest priority runnable thread. If the
-configuration also includes the C library package then usually the C
-library startup package will have created a thread which will call the
-application's <TT
-CLASS="FUNCTION"
->main</TT
-> entry point.
-      </P
-><P
->Some application code can also run before the scheduler is started,
-and this code runs in initialization context. If the application is
-written partly or completely in C++ then the constructors for any
-static objects will be run. Alternatively application code can define
-a function <TT
-CLASS="FUNCTION"
->cyg_user_start</TT
-> which gets called after
-any C++ static constructors. This allows applications to be written
-entirely in C.
-      </P
-><TABLE
-BORDER="5"
-BGCOLOR="#E0E0F0"
-WIDTH="70%"
-><TR
-><TD
-><PRE
-CLASS="PROGRAMLISTING"
->void
-cyg_user_start(void)
-{
-    /* Perform application-specific initialization here */
-}
-      </PRE
-></TD
-></TR
-></TABLE
-><P
->It is not necessary for applications to provide a
-<TT
-CLASS="FUNCTION"
->cyg_user_start</TT
-> function since the system will
-provide a default implementation which does nothing.
-      </P
-><P
->Typical operations that are performed from inside static constructors
-or <TT
-CLASS="FUNCTION"
->cyg_user_start</TT
-> include creating threads,
-synchronization primitives, setting up alarms, and registering
-application-specific interrupt handlers. In fact for many applications
-all such creation operations happen at this time, using statically
-allocated data, avoiding any need for dynamic memory allocation or
-other overheads.
-      </P
-><P
->Code running in initialization context runs with interrupts disabled
-and the scheduler locked. It is not permitted to reenable interrupts
-or unlock the scheduler because the system is not guaranteed to be in
-a totally consistent state at this point. A consequence is that
-initialization code cannot use synchronization primitives such as
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_wait</TT
-> to wait for an external event.
-It is permitted to lock and unlock a mutex: there are no other threads
-running so it is guaranteed that the mutex is not yet locked, and
-therefore the lock operation will never block; this is useful when
-making library calls that may use a mutex internally.
-      </P
-><P
->At the end of the startup sequence the system will call
-<TT
-CLASS="FUNCTION"
->cyg_scheduler_start</TT
-> and the various threads will
-start running. In thread context nearly all of the kernel functions
-are available. There may be some restrictions on interrupt-related
-operations, depending on the target hardware. For example the hardware
-may require that interrupts be acknowledged in the ISR or DSR before
-control returns to thread context, in which case
-<TT
-CLASS="FILENAME"
->cyg_interrupt_acknowledge</TT
-> should not be called
-by a thread.
-      </P
-><P
->At any time the processor may receive an external interrupt, causing
-control to be transferred from the current thread. Typically a VSR
-provided by eCos will run and determine exactly which interrupt
-occurred. Then the VSR will switch to the appropriate ISR, which can
-be provided by a HAL package, a device driver, or by the application.
-During this time the system is running at ISR context, and most of the
-kernel function calls are disallowed. This includes the various
-synchronization primitives, so for example an ISR is not allowed to
-post to a semaphore to indicate that an event has happened. Usually
-the only operations that should be performed from inside an ISR are
-ones related to the interrupt subsystem itself, for example masking an
-interrupt or acknowledging that an interrupt has been processed. On
-SMP systems it is also possible to use spinlocks from ISR context.
-      </P
-><P
->When an ISR returns it can request that the corresponding DSR be run
-as soon as it is safe to do so, and that will run in DSR context. This
-context is also used for running alarm functions, and threads can
-switch temporarily to DSR context by locking the scheduler. Only
-certain kernel functions can be called from DSR context, although more
-than in ISR context. In particular it is possible to use any
-synchronization primitives which cannot block.  These include
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_post</TT
->,
-<TT
-CLASS="FILENAME"
->cyg_cond_signal</TT
->,
-<TT
-CLASS="FUNCTION"
->cyg_cond_broadcast</TT
->,
-<TT
-CLASS="FUNCTION"
->cyg_flag_setbits</TT
->, and
-<TT
-CLASS="FUNCTION"
->cyg_mbox_tryput</TT
->. It is not possible to use any
-primitives that may block such as
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_wait</TT
->,
-<TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
->, or
-<TT
-CLASS="FUNCTION"
->cyg_mbox_put</TT
->. Calling such functions from inside
-a DSR may cause the system to hang.
-      </P
-><P
->The specific documentation for the various kernel functions gives more
-details about valid contexts.
-      </P
-></DIV
-><DIV
-CLASS="REFSECT1"
-><A
-NAME="KERNEL-OVERVIEW-ERRORS"
-></A
-><H2
->Error Handling and Assertions</H2
-><P
->In many APIs each function is expected to perform some validation of
-its parameters and possibly of the current state of the system. This
-is supposed to ensure that each function is used correctly, and that
-application code is not attempting to perform a semaphore operation on
-a mutex or anything like that. If an error is detected then a suitable
-error code is returned, for example the POSIX function
-<TT
-CLASS="FUNCTION"
->pthread_mutex_lock</TT
-> can return various error codes
-including <TT
-CLASS="LITERAL"
->EINVAL</TT
-> and <TT
-CLASS="LITERAL"
->EDEADLK</TT
->.
-There are a number of problems with this approach, especially in the
-context of deeply embedded systems:
-      </P
-><P
-></P
-><OL
-TYPE="1"
-><LI
-><P
->Performing these checks inside the mutex lock and all the other
-functions requires extra cpu cycles and adds significantly to the code
-size. Even if the application is written correctly and only makes
-system function calls with sensible arguments and under the right
-conditions, these overheads still exist.
-        </P
-></LI
-><LI
-><P
->Returning an error code is only useful if the calling code detects
-these error codes and takes appropriate action. In practice the
-calling code will often ignore any errors because the programmer
-<SPAN
-CLASS="emphasis"
-><I
-CLASS="EMPHASIS"
->&#8220;knows&#8221;</I
-></SPAN
-> that the function is being
-used correctly. If the programmer is mistaken then an error condition
-may be detected and reported, but the application continues running
-anyway and is likely to fail some time later in mysterious ways.
-        </P
-></LI
-><LI
-><P
->If the calling code does always check for error codes, that adds yet
-more cpu cycles and code size overhead. 
-        </P
-></LI
-><LI
-><P
->Usually there will be no way to recover from certain errors, so if the
-application code detected an error such as <TT
-CLASS="LITERAL"
->EINVAL</TT
->
-then all it could do is abort the application somehow.
-        </P
-></LI
-></OL
-><P
->The approach taken within the eCos kernel is different. Functions such
-as <TT
-CLASS="FUNCTION"
->cyg_mutex_lock</TT
-> will not return an error code.
-Instead they contain various assertions, which can be enabled or
-disabled. During the development process assertions are normally left
-enabled, and the various kernel functions will perform parameter
-checks and other system consistency checks. If a problem is detected
-then an assertion failure will be reported and the application will be
-terminated. In a typical debug session a suitable breakpoint will have
-been installed and the developer can now examine the state of the
-system and work out exactly what is going on. Towards the end of the
-development cycle assertions will be disabled by manipulating
-configuration options within the eCos infrastructure package, and all
-assertions will be eliminated at compile-time. The assumption is that
-by this time the application code has been mostly debugged: the
-initial version of the code might have tried to perform a semaphore
-operation on a mutex, but any problems like that will have been fixed
-some time ago. This approach has a number of advantages:
-      </P
-><P
-></P
-><OL
-TYPE="1"
-><LI
-><P
->In the final application there will be no overheads for checking
-parameters and other conditions. All that code will have been
-eliminated at compile-time.
-        </P
-></LI
-><LI
-><P
->Because the final application will not suffer any overheads, it is
-reasonable for the system to do more work during the development
-process. In particular the various assertions can test for more error
-conditions and more complicated errors. When an error is detected
-it is possible to give a text message describing the error rather than
-just return an error code.
-        </P
-></LI
-><LI
-><P
->There is no need for application programmers to handle error codes
-returned by various kernel function calls. This simplifies the
-application code.
-        </P
-></LI
-><LI
-><P
->If an error is detected then an assertion failure will be reported
-immediately and the application will be halted. There is no
-possibility of an error condition being ignored because application
-code did not check for an error code.
-        </P
-></LI
-></OL
-><P
->Although none of the kernel functions return an error code, many of
-them do return a status condition. For example the function
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_timed_wait</TT
-> waits until either an
-event has been posted to a semaphore, or until a certain number of
-clock ticks have occurred. Usually the calling code will need to know
-whether the wait operation succeeded or whether a timeout occurred.
-<TT
-CLASS="FUNCTION"
->cyg_semaphore_timed_wait</TT
-> returns a boolean: a
-return value of zero or false indicates a timeout, a non-zero return
-value indicates that the wait succeeded.
-      </P
-><P
->In conventional APIs one common error conditions is lack of memory.
-For example the POSIX function <TT
-CLASS="FUNCTION"
->pthread_create</TT
->
-usually has to allocate some memory dynamically for the thread stack
-and other per-thread data. If the target hardware does not have enough
-memory to meet all demands, or more commonly if the application
-contains a memory leak, then there may not be enough memory available
-and the function call would fail. The eCos kernel avoids such problems
-by never performing any dynamic memory allocation. Instead it is the
-responsibility of the application code to provide all the memory
-required for kernel data structures and other needs. In the case of
-<TT
-CLASS="FUNCTION"
->cyg_thread_create</TT
-> this means a
-<SPAN
-CLASS="STRUCTNAME"
->cyg_thread</SPAN
-> data structure to hold the thread
-details, and a <SPAN
-CLASS="TYPE"
->char</SPAN
-> array for the thread stack.
-      </P
-><P
->In many applications this approach results in all data structures
-being allocated statically rather than dynamically. This has several
-advantages. If the application is in fact too large for the target
-hardware's memory then there will be an error at link-time rather than
-at run-time, making the problem much easier to diagnose. Static
-allocation does not involve any of the usual overheads associated with
-dynamic allocation, for example there is no need to keep track of the
-various free blocks in the system, and it may be possible to eliminate
-<TT
-CLASS="FUNCTION"
->malloc</TT
-> from the system completely. Problems such
-as fragmentation and memory leaks cannot occur if all data is
-allocated statically. However, some applications are sufficiently
-complicated that dynamic memory allocation is required, and the
-various kernel functions do not distinguish between statically and
-dynamically allocated memory. It still remains the responsibility of
-the calling code to ensure that sufficient memory is available, and
-passing null pointers to the kernel will result in assertions or
-system failure.
-      </P
-></DIV
-><DIV
-CLASS="NAVFOOTER"
-><HR
-ALIGN="LEFT"
-WIDTH="100%"><TABLE
-SUMMARY="Footer navigation table"
-WIDTH="100%"
-BORDER="0"
-CELLPADDING="0"
-CELLSPACING="0"
-><TR
-><TD
-WIDTH="33%"
-ALIGN="left"
-VALIGN="top"
-><A
-HREF="kernel.html"
-ACCESSKEY="P"
->Prev</A
-></TD
-><TD
-WIDTH="34%"
-ALIGN="center"
-VALIGN="top"
-><A
-HREF="ecos-ref.html"
-ACCESSKEY="H"
->Home</A
-></TD
-><TD
-WIDTH="33%"
-ALIGN="right"
-VALIGN="top"
-><A
-HREF="kernel-smp.html"
-ACCESSKEY="N"
->Next</A
-></TD
-></TR
-><TR
-><TD
-WIDTH="33%"
-ALIGN="left"
-VALIGN="top"
->The eCos Kernel</TD
-><TD
-WIDTH="34%"
-ALIGN="center"
-VALIGN="top"
-><A
-HREF="kernel.html"
-ACCESSKEY="U"
->Up</A
-></TD
-><TD
-WIDTH="33%"
-ALIGN="right"
-VALIGN="top"
->SMP Support</TD
-></TR
-></TABLE
-></DIV
-></BODY
-></HTML
->
\ No newline at end of file