aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/ch.txt13
-rw-r--r--docs/src/articles.dox3
-rw-r--r--docs/src/goals.dox88
-rw-r--r--docs/src/mutualexcl.dox213
-rw-r--r--readme.txt2
-rw-r--r--src/chthreads.c21
-rw-r--r--src/include/threads.h2
7 files changed, 323 insertions, 19 deletions
diff --git a/docs/ch.txt b/docs/ch.txt
index 57cb502dc..2bf0721ec 100644
--- a/docs/ch.txt
+++ b/docs/ch.txt
@@ -46,16 +46,10 @@
* - 128 priority levels.
* - Multiple threads at the same priority level allowed.
* - Round robin scheduling for threads at the same priority level.
- * - Unlimited number of threads.
- * - Unlimited number of virtual timers.
- * - Unlimited number of semaphores.
- * - Unlimited number of mutexes.
- * - Unlimited number of condvars.
- * - Unlimited number of event sources.
- * - Unlimited number of messages in queue.
- * - Unlimited number of I/O queues.
+ * - Offers threads, virtual timers, semaphores, mutexes, condvars,
+ * event flags, messages, I/O queues.
* - No static setup at compile time, there is no need to configure a maximum
- * number of all the above resources.
+ * number of all the above objects.
* - No *need* for a memory allocator, all the kernel structures are static
* and declaratively allocated.
* - Threads, Semaphores, Event Sources, Virtual Timers creation/deletion at
@@ -73,6 +67,7 @@
* .
* <h2>Related pages</h2>
* - @subpage lic_faq
+ * - @subpage goals
* - @subpage concepts
* - @subpage articles
* .
diff --git a/docs/src/articles.dox b/docs/src/articles.dox
index a14a7285b..590efdda7 100644
--- a/docs/src/articles.dox
+++ b/docs/src/articles.dox
@@ -21,12 +21,13 @@
* @page articles Articles
* @{
* ChibiOS/RT Articles and Code Examples:
- * - @subpage article_portguide
+ * - @subpage article_mutual_exclusion
* - @subpage article_atomic
* - @subpage article_saveram
* - @subpage article_interrupts
* - @subpage article_jitter
* - @subpage article_timing
+ * - @subpage article_portguide
* .
*/
/** @} */
diff --git a/docs/src/goals.dox b/docs/src/goals.dox
new file mode 100644
index 000000000..4df7eaba7
--- /dev/null
+++ b/docs/src/goals.dox
@@ -0,0 +1,88 @@
+/*
+ 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 goals Project Goals
+ * @{
+ * <h2>Another RTOS?</h2>
+ * The first question to be answered is: there was really the need for YET
+ * ANOTHER RTOS?<br>
+ * My answer is yes because various reasons:
+ * - The ChibiOS/RT ancestor was created more than 15 years ago and while it
+ * had far less features than the current product it was complete and
+ * functioning. ChibiOS/RT is just a new (and silly) name given to
+ * something created when there were not many free RTOSes around (actually
+ * none, at least none in my knowledge, there was no widespread Internet
+ * at that time).
+ * - When, after a while, I needed a RTOS again, none of the existing FOSS
+ * projects met my expectations or my ideas of how a RTOS should be, not
+ * even close (see below). I decided that work on that old project was
+ * a better idea that contribute to, or fork, something else.
+ * - I wanted another toy.
+ * .
+ * <h2>Why is it different?</h2>
+ * In itself it implements ideas already seen in other projects but never
+ * all together in a single FOSS project. There are some basic choices in
+ * ChibiOS/RT (mostly derived by its ancestor):
+ *
+ * <h3>Static design</h3>
+ * Everything in the kernel is static, nowhere memory is allocated or freed,
+ * there are two allocator subsystems but those are options and not part of
+ * core OS. Safety is something you design in, not something you can add later.
+ *
+ * <h3>No fixed size tables or structures</h3>
+ * No tables to configure, no arrays that can be filled and overflow at
+ * runtime. Everything without practical upper bounds (except for resource
+ * limits and numerical upper bounds of course).
+ *
+ * <h3>No error conditions and no error checks</h3>
+ * All the API should not have error conditions, all the previous points are
+ * finalized to this objective. Everything you can invoke in the kernel is
+ * designed to not fail unless you pass garbage as parameters, stray pointers
+ * or such. Also the APIs are not slowed down by error checks, error checks
+ * exists but only when the debug switch is activated.<br>
+ * All the static core APIs always succeed if correct parameters are passed.
+ *
+ * <h3>Very simple APIs</h3>
+ * Every API should have the parameters you would expect for that function, no
+ * more no less. Each API should do a single thing with no options.
+ *
+ * <h3>Damn fast and compact</h3>
+ * Note first "fast" then "compact", the focus is on speed and execution
+ * efficiency rather than code size. This does not mean it is large, the OS
+ * with all the subsystems activated is well below 8KiB (32bit ARM code, the
+ * least space efficient) and can shrink down below 2KiB. It would be
+ * possible to make something smaller but:
+ * -# It would be pointless, it @a is already small.
+ * -# I would not sacrifice efficiency or features in order to save few bytes.
+ * .
+ * About the "fast" part, it is able to start/wait/exit more than <b>200,000
+ * threads per second</b> on a 72MHz STM32 (Cortex-M3). The Context Switch just
+ * takes <b>2.3 microseconds</b> on the same STM32. The numbers are not
+ * pulled out of thin air, it is the output of the included test suite.
+ *
+ * <h3>Tests and metrics</h3>
+ * I think it is nice to know how an OS is tested and how it performs before
+ * committing to use it. Test results on all the supported platforms and
+ * performance metrics are included in each ChibiOS/RT release. The test
+ * code is released as well, all the included demos are capable of executing
+ * the test suite and the OS benchmarks.
+ */
+/** @} */
+ \ No newline at end of file
diff --git a/docs/src/mutualexcl.dox b/docs/src/mutualexcl.dox
new file mode 100644
index 000000000..367618d5d
--- /dev/null
+++ b/docs/src/mutualexcl.dox
@@ -0,0 +1,213 @@
+/*
+ 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_mutual_exclusion Mutual Exclusion guide
+ * @{
+ * The most common problem when writing multithreaded code is the
+ * synchronization on the shared resources/services.<br>
+ * ChibiOS/RT offers a rich variety of mechanisms that apparently solve the
+ * same problem. I wrote apparently because each mechanism has its pro and
+ * cons.
+ * This article will introduce the various mechanisms and the explain the
+ * right scenarios for each one.
+ *
+ * <h2>Basics</h2>
+ * Some of the concepts mentioned in this article can be found in the
+ * following Wikipedia articles:
+ * - <a href="http://en.wikipedia.org/wiki/Mutual_exclusion" target="_blank">
+ * Mutual Exclusion</a>
+ * - <a href="http://en.wikipedia.org/wiki/Priority_inversion" target="_blank">
+ * Priority Inversion</a>
+ * - <a href="http://en.wikipedia.org/wiki/Priority_inheritance"
+ * target="_blank">Priority Inheritance</a>
+ * - <a href="http://en.wikipedia.org/wiki/Priority_ceiling" target="_blank">
+ * Priority Ceiling</a>
+ * .
+ * <h2>Mutual exclusion by System Locks</h2>
+ * This is the lowest level mechanism, the system is locked by invoking the
+ * @p chSysLock() API and then unlocked by invoking @p chSysUnlock().<br>
+ * The implementation is architecture dependent but it is guaranteed to, at
+ * least, disable the interrupt sources with hardware priority below or equal
+ * the kernel level.
+ *
+ * <h3>Advantages</h3>
+ * - It is the lightest as execution time, often a lock or unlock becomes just a
+ * single inlined assembler instruction.
+ * - It ensures mutual exclusion among threads but also interrupt handling code.
+ * - The implementation would ensure mutual exclusion even on multicore
+ * architectures where multiple hardware threads are present.
+ * .
+ * <h3>Disadvantages</h3>
+ * - Disabling interrupts for a long period of time can deteriorate the overall
+ * system response time and/or introduce jitter.
+ * .
+ * <h3>When use Locks</h3>
+ * - When mutual exclusion with interrupt handlers is required.
+ * - When the operation within the lock zone is very simple and has finite
+ * time.
+ * .
+ * <h3>Example</h3>
+ * @code
+ * ...
+ * chSysLock();
+ * /* Protected code */
+ * chSysUnlock();
+ * ...
+ * @endcode
+ *
+ * <h2>Mutual exclusion by Semaphores</h2>
+ * In ChibiOS/RT the counting semaphores are mainly meant as a
+ * synchronization mechanism between interrupt handlers and high level code
+ * running at thread level. Usually a thread waits on a semaphore that is
+ * signaled asynchronously by an interrupt handler.<br>
+ * The semaphores can, however, be used as simple mutexes by initializing
+ * counter to one.
+ *
+ * <h3>Advantages</h3>
+ * - The semaphores code is "already there" if you use the I/O queues and
+ * you don't want to enable the mutexes too because space constraints.
+ * - Semaphores are lighter than mutexes because their queues are FIFO
+ * ordered and do not have any overhead caused by the priority inheritance
+ * algorithm.
+ * - A semaphore takes less RAM than a mutex (12 vs 16 bytes on 32 bit
+ * architectures).
+ * .
+ * <h3>Disadvantages</h3>
+ * - Semaphore queues are FIFO ordered by default, an option exist to make
+ * them priority ordered but this can impact I/O performance because
+ * semaphores are used in I/O queues.
+ * - Semaphores do not implement the priority inheritance algorithm so the
+ * priority inversion problem is not mitigated.
+ * .
+ * <h3>When use Semaphores</h3>
+ * - When you don't need queuing by priority nor the priority inheritance
+ * algorithm.
+ * - When RAM/ROM space is scarce.
+ * .
+ * <h3>Example</h3>
+ * @code
+ * static Semaphore sem; /* Semaphore declaration */
+ * ...
+ * chSemInit(&sem, 1); /* Semaphore initialization before use */
+ * ...
+ * chSemWait(&sem);
+ * /* Protected code */
+ * chSemSignal(&sem);
+ * ...
+ * @endcode
+ *
+ * <h2>Mutual exclusion by Mutexes</h2>
+ * The mutexes, also known as binary semaphores (we choose to not use this
+ * terminology to avoid confusion with counting semaphores), are the mechanism
+ * intended as general solution for the mutual exclusion problem.
+ *
+ * <h3>Advantages</h3>
+ * - Mutexes implement the Priority Inheritance algorithm that is an important
+ * tool in reducing jitter and improve overall system response time (it is
+ * not a magic solution, just a tool for the system designer).
+ * .
+ * <h3>Disadvantages</h3>
+ * - Heaviest among all the possible choices. The Priority Inheritance method
+ * is efficiently implemented but nothing is more efficient than no code at
+ * all.
+ * .
+ * <h3>When use Mutexes</h3>
+ * - When you are designing a very complex system with hard realtime
+ * requirements.
+ * .
+ * <h3>Example</h3>
+ * @code
+ * static Mutex mtx; /* Mutex declaration */
+ * ...
+ * chMtxInit(&mtx); /* Mutex initialization before use */
+ * ...
+ * chMtxLock(&mtx);
+ * /* Protected code */
+ * chMtxUnlock();
+ * ...
+ * @endcode
+ *
+ * <h2>Mutual exclusion by priority boost</h2>
+ * Another way to implement mutual exclusion is to boost the thread priority
+ * to a level higher than all of the threads competing for a certain resource.
+ * This solution effectively implements an Immediate Priority Ceiling
+ * algorithm.
+ *
+ * <h3>Advantages</h3>
+ * - Almost free as code size, you need no semaphores nor mutexes.
+ * - No RAM overhead.
+ * - Fast execution, priority change is a quick operation under ChibiOS/RT.
+ * - The priority ceiling protocol that can help mitigate the Priority
+ * Inversion problem.
+ * .
+ * <h3>Disadvantages</h3>
+ * - Makes the design more complicated because priorities must be assigned to
+ * not just threads but also assigned to the resources to be protected.
+ * - Locking a resource affects all the threads with lower priority even if
+ * not interested to the resource.
+ * - All the threads that can access the resource must have lower priority
+ * than the resource itself.
+ * - The mechanism is not easy to understand in the code unless it is clearly
+ * documented.
+ * - This method does not work in on multicore architectures where multiple
+ * hardware threads are present.
+ * - Only useful in very simple applications.
+ * .
+ * <h3>Example</h3>
+ * @code
+ * /* Priority assigned to the resource, threads must have lower
+ * priority than this.*/
+ * #define AAA_RESOURCE_PRIORITY NORMALPRIO+10
+ * ...
+ * /* Locks the resources AAA.*/
+ * tprio_t aaa_old_prio = chThdSetPriority(AAA_RESOURCE_PRIORITY);
+ * /* Accessing resource AAA */
+ * chThdSetPriority(aaa_old_prio); /* Unlocks AAA.*/
+ * ...
+ * @endcode
+ *
+ * <h2>Mutual exclusion by message passing</h2>
+ * Another method is to make a single dedicated thread execute the critical
+ * code and make it work as a messages server. The other threads can request
+ * the service to the server by sending a properly formatted message and
+ * then wait for the answer with the result.<br>
+ * This method is very useful when integrating into the system components not
+ * designed to be reentrant or to be executed in a multithreaded environment,
+ * as example a 3rd part file system or a networking protocol stack.
+ *
+ * <h3>Advantages</h3>
+ * - It is possible to encapsulate very complex logic without worry about
+ * about concurrent accesses.
+ * - If the encapsulate code uses a large stack area only the server thread
+ * have to allocate enough RAM, the client threads save RAM by just
+ * requesting the service to the server.
+ * - Clean system architecture.
+ * - This method also implements a form of Priority Ceiling. The ceiling is
+ * the priority of the server thread itself.
+ * .
+ * <h3>Disadvantages</h3>
+ * - More complex implementation, a protocol must be created between clients
+ * and server.
+ * - Two context switches are required for each request to the server (but
+ * ChibiOSRT is very efficient at that).
+ * - Requires a dedicated thread.
+ * .
+ */
+/** @} */
diff --git a/readme.txt b/readme.txt
index 307e98c29..1026c34dc 100644
--- a/readme.txt
+++ b/readme.txt
@@ -108,6 +108,8 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
registers usage now the kernel is much smaller, faster and most OS APIs
use less RAM in stack frames (note, this is an ARM7 thumb mode specific
optimization).
+- CHANGE: Now the API chThdSetPriority() returns the old priority instead
+ of void.
- CHANGE: Modified the signature of the chMsgSendWithEvent() API, it now uses
a more efficient event signaling method.
- CHANGE: Removed the field p_tid from the Thread structure and the related
diff --git a/src/chthreads.c b/src/chthreads.c
index 5b80687d6..58f2b46d5 100644
--- a/src/chthreads.c
+++ b/src/chthreads.c
@@ -189,29 +189,34 @@ Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS */
/**
- * @brief Changes the running thread priority then reschedules if necessary.
+ * @brief Changes the running thread priority level then reschedules if
+ * necessary.
*
- * @param newprio the new priority of the running thread
+ * @param newprio the new priority level of the running thread
+ * @return The old priority level.
+ * @note The function returns the real thread priority regardless of the
+ * actual priority that could be higher than the real priority because
+ * the priority inheritance mechanism.
*/
-void chThdSetPriority(tprio_t newprio) {
+tprio_t chThdSetPriority(tprio_t newprio) {
+ tprio_t oldprio;
chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()");
chSysLock();
#if CH_USE_MUTEXES
- if (currp->p_prio != currp->p_realprio) {
- if (newprio > currp->p_prio)
- currp->p_prio = newprio;
- }
- else
+ oldprio = currp->p_realprio;
+ if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio))
currp->p_prio = newprio;
currp->p_realprio = newprio;
#else
+ oldprio = currp->p_prio;
currp->p_prio = newprio;
#endif
chSchRescheduleS();
chSysUnlock();
+ return oldprio;
}
/**
diff --git a/src/include/threads.h b/src/include/threads.h
index 3c279bf3c..29ed7f21f 100644
--- a/src/include/threads.h
+++ b/src/include/threads.h
@@ -172,7 +172,7 @@ extern "C" {
Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
tfunc_t pf, void *arg);
#endif
- void chThdSetPriority(tprio_t newprio);
+ tprio_t chThdSetPriority(tprio_t newprio);
Thread *chThdResume(Thread *tp);
void chThdTerminate(Thread *tp);
void chThdSleep(systime_t time);