git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@802 35acf78f-673a-0410-8e92-d51de3d6d3f4
parent
d425f2ec12
commit
e9274448e9
|
@ -21,6 +21,7 @@
|
|||
* @page articles Articles
|
||||
* @{
|
||||
* ChibiOS/RT Articles and Code Examples:
|
||||
* - @subpage article_stacks
|
||||
* - @subpage article_mutual_exclusion
|
||||
* - @subpage article_atomic
|
||||
* - @subpage article_saveram
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS/RT.
|
||||
|
||||
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS/RT is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page article_stacks Stacks and stack sizes
|
||||
* @{
|
||||
* In a RTOS like ChibiOS/RT there are several dedicated stacks, each stack
|
||||
* has a dedicated RAM space that must have a correctly sized assigned area.
|
||||
* <h2>The stacks</h2>
|
||||
* There are several stacks in the systems, some are always present, some
|
||||
* others are present only in some architectures:
|
||||
* - <b>Main stack</b>, this stack is used by the @p main() function and the
|
||||
* thread that execute it. It is not a normal thread stack because it is
|
||||
* initialized in the startup code and its size is defined in a port
|
||||
* dependent way. Details are in the various ports documentation.
|
||||
* - <b>Interrupt Stack</b>, some architectures have a dedicated interrupt
|
||||
* stack. This is an important feature in a multithreaded environment,
|
||||
* without a dedicated interrupt stack each thread has to reserve
|
||||
* enough space, for interrupts servicing, within its own stack. This space,
|
||||
* multiplied by the total threads number, can be a significant RAM waste.
|
||||
* - <b>Thread Stack</b>, each thread has a dedicated stack for its own
|
||||
* execution and context switch.
|
||||
* - <b>Other Stacks</b>, some architectures (ARM) can have other stacks but
|
||||
* the OS does not directly use any of them.
|
||||
* .
|
||||
* <h2>Risks</h2>
|
||||
* The most critical thing when writing an embedded multithreaded application
|
||||
* is to determine the correct stack size for main, threads and, when present,
|
||||
* interrupts.<br>
|
||||
* Assign too much space to a stack wastes RAM, assign too little space
|
||||
* leads to crashes or, worst scenario, hard to track instability.
|
||||
*
|
||||
* <h2>Assign the correct size</h2>
|
||||
* You may try to examine the asm listings in order to calculate the exact
|
||||
* stack requirements but this requires much time, experience and patience.<br>
|
||||
* An alternative way is to use an interactive method. Follow this procedure
|
||||
* for each thread in the system:
|
||||
* - Enable the following debug options in the kernel:
|
||||
* - @p CH_DBG_ENABLE_STACK_CHECK, this enables a stack check before any
|
||||
* context switch. This option halts the system in @p chSysHalt() just
|
||||
* before a stack overflow happens.
|
||||
* - @p CH_DBG_FILL_THREADS, this option fills the threads working area
|
||||
* with an easily recognizable pattern (0x55).
|
||||
* - Assign a large and safe size to the thread stack, as example 256 bytes
|
||||
* on 32 MCUs, 128 bytes on 8/16 bit MCUs. This is almost always too much
|
||||
* for simple threads.
|
||||
* - Run the application, if the application crashes or halts then increase
|
||||
* the stack size and repeat (you know how to use the debugger right?).
|
||||
* - Let the application run and make sure to trigger the thread in a way to
|
||||
* make it follow most or all its code paths. If the application crashes or
|
||||
* halts then increase the stack size and repeat.
|
||||
* - Stop the application using the debugger and examine the thread working
|
||||
* area (you know what a map file is, right?). You can see that the thread
|
||||
* stack overwrote the fill pattern (0x55) from the top of the working area
|
||||
* downward. You can estimate the excess stack by counting the untouched
|
||||
* locations.
|
||||
* - Trim down the stack size and repeat until the application still runs
|
||||
* correctly and you have a decent margin in the stack.
|
||||
* - Repeat for all the thread classes in the system.
|
||||
* - Turn off the debug options.
|
||||
* - Done.
|
||||
* .
|
||||
* <h2>Final Notes</h2>
|
||||
* Some useful info:
|
||||
* - Stack overflows are the most common source of problems during development,
|
||||
* when in trouble with crashes or anomalous behaviors always first verify
|
||||
* stack sizes.
|
||||
* - The required stack size can, and very often does change when changing
|
||||
* compiler vendor, compiler version, compiler options, code type (ARM
|
||||
* or THUMB as example).
|
||||
* - Code compiled in THUMB mode uses more stack space compared to the
|
||||
* same code compiled in ARM mode. In GCC this is related to lack of tail
|
||||
* calls optimizations in THUMB mode, this is probably true also in other
|
||||
* compilers.
|
||||
* - Speed optimized code often requires less stack space compared to space
|
||||
* optimized code. Be careful when changing optimizations.
|
||||
* - The interrupts space overhead on the thread stacks (@p INT_REQUIRED_STACK
|
||||
* defined in @p chcore.h) is included in the total working area size
|
||||
* by the system macros @p THD_WA_SIZE() and @p WORKING_AREA().<br>
|
||||
* The correct way to reserve space into the thread stacks for interrupts
|
||||
* processing is to override the @p INT_REQUIRED_STACK default value.
|
||||
* Architectures with a dedicated interrupt stack do not require changes
|
||||
* to this value. Resizing of the global interrupt stack may be required
|
||||
* instead.
|
||||
* - Often is a good idea to have some extra space in stacks unless you
|
||||
* are really starved on RAM. Anyway optimize stack space at the very
|
||||
* end of your development cycle.
|
||||
* .
|
||||
*/
|
||||
/** @} */
|
|
@ -0,0 +1,85 @@
|
|||
I/O Channels
|
||||
|
||||
- Channels are specific for I/O operations, however, a channel can hide a
|
||||
complex IPC operation.
|
||||
- Channels are N-sized not necessarily byte-sized.
|
||||
- Channels support timeout.
|
||||
- The IOChannel structure hides a virtualized implementation using a VMT.
|
||||
- The APIs are macros that hide the VMT.
|
||||
- Channels must support events, at least 3 events are predefined:
|
||||
0 - Incoming data event.
|
||||
1 - Output queue empty.
|
||||
2 - I/O Status Change (at least one status flag was pended).
|
||||
X - More events can be defined and are channel specific.
|
||||
- Read/write functions are non blocking and can transfer no data if the
|
||||
buffers are empty/full.
|
||||
- Zero sized read and writes simply returns zero, nothing is queued.
|
||||
|
||||
/**
|
||||
* @brief Returns the channel data unit size.
|
||||
* @details The channel data unit size is characteristic of the channel and
|
||||
* cannot be modified.
|
||||
* @param[in] iop pointer to an IOChannel structure
|
||||
* @return The channel data unit size in bytes.
|
||||
*/
|
||||
size_t chIOGetWidth(const IOChannel *iop);
|
||||
|
||||
/**
|
||||
* @brief Returns the event sources associated to the channel.
|
||||
* @details A channel can have associated event sources. The event sources are
|
||||
* identified by a numerical identifier, the following identifiers
|
||||
* are predefined:
|
||||
* - CH_IO_EVT_INPUT signaled when some data is queued in the input buffer.
|
||||
* - CH_IO_EVT_OUTPUT signaled when the output buffer is emptied.
|
||||
* - CH_IO_EVT_STATUS signaled when a channel related condition happens.
|
||||
*
|
||||
* @param[in] iop pointer to an IOChannel structure
|
||||
* @param[in] n the numerical identifier.
|
||||
* @return A pointer to the @p EventSource structure associated to the numerical
|
||||
* identifier.
|
||||
* @retval NULL there is no event source associated to the specified
|
||||
* identifier.
|
||||
*/
|
||||
EventSource *chIOGetEventSource(const IOChannel *iop, ioevtsrc_t n);
|
||||
|
||||
/**
|
||||
* @brief Returns the channel status flags.
|
||||
* @details The channel status flags are returned and cleared.
|
||||
*
|
||||
* @param[in] iop pointer to an IOChannel structure
|
||||
* @return The status flags.
|
||||
* @retval 0 no flags pending.
|
||||
*/
|
||||
iosts_t chIOGetAndClearStatus(IOChannel *iop);
|
||||
|
||||
/**
|
||||
* @brief Asynchronous read.
|
||||
* @details This function reads up to @p n data units into the specified
|
||||
* buffer without blocking. If there is no data into the input queue
|
||||
* then the function returns immediatly.
|
||||
*
|
||||
* @param[in] iop pointer to an IOChannel structure
|
||||
* @param[out] buf the buffer where to copy the input data
|
||||
* @param[in] n the maximum number of data units to transfer
|
||||
* @return The actual data units number read.
|
||||
* @retval 0 the input queue is empty, no data transfer was performed.
|
||||
*/
|
||||
size_t chIORead(IOChannel *iop, void *buf, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Asynchronous write.
|
||||
* @details This function writes up to @p n data units from the specified
|
||||
* buffer without blocking. If there is no space into the output queue
|
||||
* then the function returns immediatly.
|
||||
*
|
||||
* @param[in] iop pointer to an IOChannel structure
|
||||
* @param[out] buf the buffer with the data to be written
|
||||
* @param[in] n the maximum number of data units to transfer
|
||||
* @return The actual data units number written.
|
||||
* @retval 0 the output queue is full, no data transfer was performed.
|
||||
*/
|
||||
size_t chIOWrite(IOChannel *iop, const void *buf, size_t n);
|
||||
|
||||
bool_t chIOWaitInput(IOChannel *iop, systime_t timeout);
|
||||
|
||||
bool_t chIOWaitOutput(IOChannel *iop, systime_t timeout);
|
|
@ -176,7 +176,7 @@ struct context {
|
|||
* "touching" them.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE() { \
|
||||
asm ("" : : : "r18", "r19", "r20", "r21", "r22", "r23", "r24", \
|
||||
asm ("" : : : "r18", "r19", "r20", "r21", "r22", "r23", "r24", \
|
||||
"r25", "r26", "r27", "r30", "r31"); \
|
||||
}
|
||||
|
||||
|
|
|
@ -59,10 +59,10 @@ Thread *init_thread(Thread *tp, tprio_t prio) {
|
|||
}
|
||||
|
||||
#if CH_DBG_FILL_THREADS
|
||||
static void memfill(uint8_t *p, uint32_t n, uint8_t v) {
|
||||
static void memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
|
||||
|
||||
while (n)
|
||||
*p++ = v, n--;
|
||||
while (startp < endp)
|
||||
*startp++ = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -95,7 +95,12 @@ Thread *chThdInit(void *workspace, size_t wsize,
|
|||
(prio <= HIGHPRIO) && (pf != NULL),
|
||||
"chThdInit");
|
||||
#if CH_DBG_FILL_THREADS
|
||||
memfill(workspace, wsize, MEM_FILL_PATTERN);
|
||||
memfill(workspace,
|
||||
(uint8_t)workspace + sizeof(Thread),
|
||||
THREAD_FILL_VALUE);
|
||||
memfill((uint8_t)workspace + sizeof(Thread),
|
||||
(uint8_t)workspace + wsize
|
||||
STACK_FILL_VALUE);
|
||||
#endif
|
||||
SETUP_CONTEXT(workspace, wsize, pf, arg);
|
||||
return init_thread(tp, prio);
|
||||
|
|
|
@ -35,10 +35,21 @@
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @brief Fill value for threads working area in debug mode.
|
||||
* @brief Fill value for thread stack area in debug mode.
|
||||
*/
|
||||
#ifndef MEM_FILL_PATTERN
|
||||
#define MEM_FILL_PATTERN 0x55
|
||||
#ifndef STACK_FILL_VALUE
|
||||
#define STACK_FILL_VALUE 0x55
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Fill value for thread area in debug mode.
|
||||
* @note The chosen default value is 0xFF in order to make evident which
|
||||
* thread fields were not initialized when inspecting the memory with
|
||||
* a debugger. A uninitialized field is not an error in itself but it
|
||||
* better to know it.
|
||||
*/
|
||||
#ifndef THREAD_FILL_VALUE
|
||||
#define THREAD_FILL_VALUE 0xFF
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
11
todo.txt
11
todo.txt
|
@ -17,11 +17,17 @@ After 1.0.0:
|
|||
* Add checks to all APIs.
|
||||
* Stack checks option.
|
||||
* Threads profiling option.
|
||||
- Registers clearing on thread start.
|
||||
* Idle loop hook macro.
|
||||
* Switch the configuration options to TRUE/FALSE rather than def/undef.
|
||||
* Remove port_puts() from all the ports.
|
||||
- Stack sizes article into the documentation.
|
||||
- Find out and document main stack settings in MSP430 and AVR runtimes.
|
||||
|
||||
After 1.2.0:
|
||||
X Abstract I/O channels rather than just serial ports.
|
||||
- Move the serial drivers implementations in library. Better keep the core
|
||||
as compact as possible.
|
||||
- Threads Pools manager in the library.
|
||||
- New chThdCreate() that takes just two parameters, a pointer to a thread
|
||||
descriptor and the tread parameter. It could wrap the current variants
|
||||
|
@ -30,11 +36,8 @@ After 1.2.0:
|
|||
- OSEK-style simple tasks within the idle thread.
|
||||
? Think to something for threads restart.
|
||||
? Multiple heaps, disjoint heaps, heaps in heaps.
|
||||
- Abstract I/O channels rather than just serial ports.
|
||||
- Move the serial drivers implementations in library al keep the I/O channel
|
||||
interface as part of the kernel. Better keep the core as compact as
|
||||
possible.
|
||||
- Update C++ wrapper (Heap, Pools, Mailboxes and any new feature).
|
||||
- Think about making threads return void.
|
||||
|
||||
Ideas for 2.x.x:
|
||||
- Reference counter for threads, concept of detached threads, threads
|
||||
|
|
Loading…
Reference in New Issue