diff --git a/docs/src/articles.dox b/docs/src/articles.dox index e9849782c..ac534a0c9 100644 --- a/docs/src/articles.dox +++ b/docs/src/articles.dox @@ -18,7 +18,7 @@ */ /** - * @page articles Articles + * @page articles Articles and Code Samples * ChibiOS/RT Articles and Code Examples: * - @subpage article_stacks * - @subpage article_mutual_exclusion @@ -29,5 +29,6 @@ * - @subpage article_timing * - @subpage article_portguide * - @subpage article_design + * - @subpage article_create_thread * . */ diff --git a/docs/src/createthread.dox b/docs/src/createthread.dox new file mode 100644 index 000000000..6ef1a61c5 --- /dev/null +++ b/docs/src/createthread.dox @@ -0,0 +1,186 @@ +/* + 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 . +*/ + +/** + * @page article_create_thread How to create a thread + * At the system startup there are already two active threads: + * - Idle thread. This thread has the lowest priority in the system so + * it runs only when the other threads in the system are sleeping. This + * threads usually switches the system in a low power mode and does nothing + * else. + * - Main thread. This thread executes your @p main() function at + * startup. The main thread is created at the @p NORMALPRIO level but it + * can change its own priority if required. It is from the main thread + * that the other threads are usually created. + * . + * There are two kind of threads in ChibiOS/RT: + * - Static Threads. This kind of threads are statically allocated in + * memory. The memory used by the thread cannot reused except for restarting + * the threads. + * - Dynamic Threads. Threads created by allocating memory from a memory + * heap or a memory pool. + * . + *

Creating a static thread

+ * In order to create a static thread a working area must be declared using + * the macro @p WORKING_AREA as shown: + * @code +static WORKING_AREA(myThreadWorkingArea, 128); + * @endcode + * This macro reserves 128 bytes of stack for the thread and space for all + * the required thread related structures. The total size and the alignment + * problems are handled inside the macro, you only need to specify the pure + * stack size.
+ * A thread can be started by invoking @p chThdCreateStatic() as shown in this + * example: + * @code + Thread *tp = chThdCreateStatic(myThreadWorkingArea, + sizeof(myThreadWorkingArea), + NORMALPRIO, /* Initial priority. */ + myThread, /* Thread function. */ + NULL); /* Thread parameter. */ + * @endcode + * Tre variable tp receives the pointer to the thread object, it is taken + * by other APIs as parameter.
+ * Now a complete example: + * @code +/* +* * My simple application. + */ + +#include + +/* +* * Working area for the LED flashing thread. + */ +static WORKING_AREA(myThreadWorkingArea, 128); + +/* +* * LED flashing thread. + */ +static msg_t myThread(void *arg) { + + while (TRUE) { + LED_ON(); + chThdSleepMilliseconds(500); + LED_OFF(); + chThdSleepMilliseconds(500); + } +} + +int main(int argc, char *argv[]) { + + /* Starting the flashing LEDs thread.*/ + (void)chThdCreateStatic(myThreadWorkingArea, sizeof(myThreadWorkingArea), + NORMALPRIO, myThread, NULL); + . + . + . +} + * @endcode + * Note that is memory allocated to myThread() is statically defined and cannot + * be reused. Static threads are ideal for safety applications because there is + * no risk of a memory allocation failure because progressive heap + * fragmentation. + * + *

Creating a dynamic thread using the heap allocator

+ * In order to create a thread from a memory heap is very easy: + * @code + Thread *tp = chThdCreateFromHeap(NULL, /* NULL = Default heap. */ + 128, /* Stack size. */ + NORMALPRIO, /* Initial priority. */ + myThread, /* Thread function. */ + NULL); /* Thread parameter. */ + * @endcode + * The memory is allocated from the spawned heap and the thread is started. + * Note that the memory is not freed when the thread terminates but when the + * thread final status (its return value) is collected by the spawning thread. + * As example: + * @code +static msg_t myThread(void *arg) { + + unsigned i = 10; + while (i > 0) { + LED_ON(); + chThdSleepMilliseconds(500); + LED_OFF(); + chThdSleepMilliseconds(500); + i--; + } + return (msg_t)i; +} + +int main(int argc, char *argv[]) { + + Thread *tp = chThdCreateFromHeap(NULL, 128, NORMALPRIO+1, myThread, NULL); + if (tp == NULL) + chSysHalt(); /* Memory exausted. */ + + /* The main thread continues its normal execution.*/ + . + . + /* +* * Now waits for the spawned thread to terminate (if it has not terminated +* * already) then gets the thread exit message (msg) and returns the +* * terminated thread memory to the heap (default system heap in this +* * example). + */ + msg_t msg = chThdWait(tp); + . + . +} + * @endcode + * + *

Creating a dynamic thread using the heap allocator

+ * A pool is a collection of equally sized memory blocks, creating a thread from + * a memry pool is very similar to the previous example but the memory of + * terminated threads is returned to the memory pool rather than to a heap: + * @code +static msg_t myThread(void *arg) { + + unsigned i = 10; + while (i > 0) { + LED_ON(); + chThdSleepMilliseconds(500); + LED_OFF(); + chThdSleepMilliseconds(500); + i--; + } + return (msg_t)i; +} + +int main(int argc, char *argv[]) { + + Thread *tp = chThdCreateFromMemoryPool(myPool, NORMALPRIO+1, myThread, NULL); + if (tp == NULL) + chSysHalt(); /* Pool empty. */ + + /* The main thread continues its normal execution.*/ + . + . + /* +* * Now waits for the spawned thread to terminate (if it has not terminated +* * already) then gets the thread exit message (msg) and returns the +* * terminated thread memory to the original memory pool. + */ + msg_t msg = chThdWait(tp); + . + . +} + * @endcode + */ diff --git a/docs/src/stacks.dox b/docs/src/stacks.dox index 6035e1277..ddb416596 100644 --- a/docs/src/stacks.dox +++ b/docs/src/stacks.dox @@ -54,7 +54,9 @@ * - 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. + * before a stack overflow happens. The halt condition is caused by + * a stack overflow when the global variable @p panic_msg is set to + * @p NULL, normally it would point to a panic message. * - @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 diff --git a/os/kernel/src/chdebug.c b/os/kernel/src/chdebug.c index f5e6bef7a..3049e03e7 100644 --- a/os/kernel/src/chdebug.c +++ b/os/kernel/src/chdebug.c @@ -62,7 +62,8 @@ void chDbgTrace(Thread *otp, Thread *ntp) { /** * @brief Pointer to the panic message. * @details This pointer is meant to be accessed through the debugger, it is - * written once and then the system is halted. + * written once and then the system is halted. This variable can be + * set to @p NULL if the halt is caused by a stack overflow. */ char *panic_msg; diff --git a/os/kernel/templates/chconf.h b/os/kernel/templates/chconf.h index 31c3c7a50..41dddd5d4 100644 --- a/os/kernel/templates/chconf.h +++ b/os/kernel/templates/chconf.h @@ -377,6 +377,8 @@ * @note The default is @p FALSE. * @note The stack check is performed in a architecture/port dependent way. It * may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. */ #if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) #define CH_DBG_ENABLE_STACK_CHECK FALSE