📄 kernel-overview.html
字号:
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 threadsrunning so it is guaranteed that the mutex is not yet locked, andtherefore the lock operation will never block; this is useful whenmaking library calls that may use a mutex internally. </P><P>At the end of the startup sequence the system will call<TTCLASS="FUNCTION">cyg_scheduler_start</TT> and the various threads willstart running. In thread context nearly all of the kernel functionsare available. There may be some restrictions on interrupt-relatedoperations, depending on the target hardware. For example the hardwaremay require that interrupts be acknowledged in the ISR or DSR beforecontrol returns to thread context, in which case<TTCLASS="FILENAME">cyg_interrupt_acknowledge</TT> should not be calledby a thread. </P><P>At any time the processor may receive an external interrupt, causingcontrol to be transferred from the current thread. Typically a VSRprovided by eCos will run and determine exactly which interruptoccurred. Then the VSR will switch to the appropriate ISR, which canbe 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 thekernel function calls are disallowed. This includes the varioussynchronization primitives, so for example an ISR is not allowed topost to a semaphore to indicate that an event has happened. Usuallythe only operations that should be performed from inside an ISR areones related to the interrupt subsystem itself, for example masking aninterrupt or acknowledging that an interrupt has been processed. OnSMP 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 runas soon as it is safe to do so, and that will run in DSR context. Thiscontext is also used for running alarm functions, and threads canswitch temporarily to DSR context by locking the scheduler. Onlycertain kernel functions can be called from DSR context, although morethan in ISR context. In particular it is possible to use anysynchronization primitives which cannot block. These include<TTCLASS="FUNCTION">cyg_semaphore_post</TT>,<TTCLASS="FILENAME">cyg_cond_signal</TT>,<TTCLASS="FUNCTION">cyg_cond_broadcast</TT>,<TTCLASS="FUNCTION">cyg_flag_setbits</TT>, and<TTCLASS="FUNCTION">cyg_mbox_tryput</TT>. It is not possible to use anyprimitives that may block such as<TTCLASS="FUNCTION">cyg_semaphore_wait</TT>,<TTCLASS="FUNCTION">cyg_mutex_lock</TT>, or<TTCLASS="FUNCTION">cyg_mbox_put</TT>. Calling such functions from insidea DSR may cause the system to hang. </P><P>The specific documentation for the various kernel functions gives moredetails about valid contexts. </P></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-OVERVIEW-ERRORS"></A><H2>Error Handling and Assertions</H2><P>In many APIs each function is expected to perform some validation ofits parameters and possibly of the current state of the system. Thisis supposed to ensure that each function is used correctly, and thatapplication code is not attempting to perform a semaphore operation ona mutex or anything like that. If an error is detected then a suitableerror code is returned, for example the POSIX function<TTCLASS="FUNCTION">pthread_mutex_lock</TT> can return various error codesincluding <TTCLASS="LITERAL">EINVAL</TT> and <TTCLASS="LITERAL">EDEADLK</TT>.There are a number of problems with this approach, especially in thecontext of deeply embedded systems: </P><P></P><OLTYPE="1"><LI><P>Performing these checks inside the mutex lock and all the otherfunctions requires extra cpu cycles and adds significantly to the codesize. Even if the application is written correctly and only makessystem function calls with sensible arguments and under the rightconditions, these overheads still exist. </P></LI><LI><P>Returning an error code is only useful if the calling code detectsthese error codes and takes appropriate action. In practice thecalling code will often ignore any errors because the programmer<SPANCLASS="emphasis"><ICLASS="EMPHASIS">“knows”</I></SPAN> that the function is beingused correctly. If the programmer is mistaken then an error conditionmay be detected and reported, but the application continues runninganyway 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 yetmore cpu cycles and code size overhead. </P></LI><LI><P>Usually there will be no way to recover from certain errors, so if theapplication code detected an error such as <TTCLASS="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 suchas <TTCLASS="FUNCTION">cyg_mutex_lock</TT> will not return an error code.Instead they contain various assertions, which can be enabled ordisabled. During the development process assertions are normally leftenabled, and the various kernel functions will perform parameterchecks and other system consistency checks. If a problem is detectedthen an assertion failure will be reported and the application will beterminated. In a typical debug session a suitable breakpoint will havebeen installed and the developer can now examine the state of thesystem and work out exactly what is going on. Towards the end of thedevelopment cycle assertions will be disabled by manipulatingconfiguration options within the eCos infrastructure package, and allassertions will be eliminated at compile-time. The assumption is thatby this time the application code has been mostly debugged: theinitial version of the code might have tried to perform a semaphoreoperation on a mutex, but any problems like that will have been fixedsome time ago. This approach has a number of advantages: </P><P></P><OLTYPE="1"><LI><P>In the final application there will be no overheads for checkingparameters and other conditions. All that code will have beeneliminated at compile-time. </P></LI><LI><P>Because the final application will not suffer any overheads, it isreasonable for the system to do more work during the developmentprocess. In particular the various assertions can test for more errorconditions and more complicated errors. When an error is detectedit is possible to give a text message describing the error rather thanjust return an error code. </P></LI><LI><P>There is no need for application programmers to handle error codesreturned by various kernel function calls. This simplifies theapplication code. </P></LI><LI><P>If an error is detected then an assertion failure will be reportedimmediately and the application will be halted. There is nopossibility of an error condition being ignored because applicationcode did not check for an error code. </P></LI></OL><P>Although none of the kernel functions return an error code, many ofthem do return a status condition. For example the function<TTCLASS="FUNCTION">cyg_semaphore_timed_wait</TT> waits until either anevent has been posted to a semaphore, or until a certain number ofclock ticks have occurred. Usually the calling code will need to knowwhether the wait operation succeeded or whether a timeout occurred.<TTCLASS="FUNCTION">cyg_semaphore_timed_wait</TT> returns a boolean: areturn value of zero or false indicates a timeout, a non-zero returnvalue indicates that the wait succeeded. </P><P>In conventional APIs one common error conditions is lack of memory.For example the POSIX function <TTCLASS="FUNCTION">pthread_create</TT>usually has to allocate some memory dynamically for the thread stackand other per-thread data. If the target hardware does not have enoughmemory to meet all demands, or more commonly if the applicationcontains a memory leak, then there may not be enough memory availableand the function call would fail. The eCos kernel avoids such problemsby never performing any dynamic memory allocation. Instead it is theresponsibility of the application code to provide all the memoryrequired for kernel data structures and other needs. In the case of<TTCLASS="FUNCTION">cyg_thread_create</TT> this means a<SPANCLASS="STRUCTNAME">cyg_thread</SPAN> data structure to hold the threaddetails, and a <SPANCLASS="TYPE">char</SPAN> array for the thread stack. </P><P>In many applications this approach results in all data structuresbeing allocated statically rather than dynamically. This has severaladvantages. If the application is in fact too large for the targethardware's memory then there will be an error at link-time rather thanat run-time, making the problem much easier to diagnose. Staticallocation does not involve any of the usual overheads associated withdynamic allocation, for example there is no need to keep track of thevarious free blocks in the system, and it may be possible to eliminate<TTCLASS="FUNCTION">malloc</TT> from the system completely. Problems suchas fragmentation and memory leaks cannot occur if all data isallocated statically. However, some applications are sufficientlycomplicated that dynamic memory allocation is required, and thevarious kernel functions do not distinguish between statically anddynamically allocated memory. It still remains the responsibility ofthe calling code to ensure that sufficient memory is available, andpassing null pointers to the kernel will result in assertions orsystem failure. </P></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="kernel.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="ecos-ref.html"ACCESSKEY="H">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="kernel-smp.html"ACCESSKEY="N">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">The eCos Kernel</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="kernel.html"ACCESSKEY="U">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">SMP Support</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -