aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/ch.txt24
-rw-r--r--docs/src/atomic.dox10
-rw-r--r--docs/src/timing.dox42
-rw-r--r--src/chschd.c8
-rw-r--r--src/chthreads.c20
-rw-r--r--src/include/threads.h1
-rw-r--r--test/testsem.c1
7 files changed, 73 insertions, 33 deletions
diff --git a/docs/ch.txt b/docs/ch.txt
index 0ae4eb61b..74436d6b5 100644
--- a/docs/ch.txt
+++ b/docs/ch.txt
@@ -192,7 +192,28 @@
*
* @section thread_states Threads States
* The image shows how threads can change their state in ChibiOS/RT.<br>
- * @image html states.png
+ * @dot
+ digraph example {
+ /*rankdir="LR";*/
+ node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
+ start [label="Start", style="bold"];
+ run [label="Running"];
+ ready [label="Ready"];
+ suspend [label="Suspended"];
+ sleep [label="Sleeping"];
+ stop [label="Stop", style="bold"];
+ start -> suspend [label="chThdInit()", fontname=Helvetica, fontsize=8, constraint=false];
+ start -> run [label="chThdCreate()", fontname=Helvetica, fontsize=8];
+ start -> ready [label="chThdCreate()", fontname=Helvetica, fontsize=8];
+ run -> ready [dir="both", label="Reschedulation", fontname=Helvetica, fontsize=8];
+ suspend -> run [label="chThdResume()", fontname=Helvetica, fontsize=8];
+ suspend -> ready [label="chThdResume()", fontname=Helvetica, fontsize=8];
+ run -> sleep [label="chSchGoSleepS()", fontname=Helvetica, fontsize=8];
+ sleep -> run [label="chSchWakepS()", fontname=Helvetica, fontsize=8];
+ sleep -> ready [label="chSchWakepS()", fontname=Helvetica, fontsize=8];
+ run -> stop [label="chThdExit()", fontname=Helvetica, fontsize=8];
+ }
+ * @enddot
*
* @section priority Priority Levels
* Priorities in ChibiOS/RT are a contiguous numerical range but the initial
@@ -246,6 +267,7 @@
* - @subpage article_atomic
* - @subpage article_saveram
* - @subpage article_interrupts
+ * - @subpage article_timing
*/
/** @} */
diff --git a/docs/src/atomic.dox b/docs/src/atomic.dox
index 22601d8d9..144d6bca0 100644
--- a/docs/src/atomic.dox
+++ b/docs/src/atomic.dox
@@ -12,17 +12,13 @@
chSemSignalI(&sem1);
chSemSignalI(&sem2);
- if (tp != NULL) {
- chThdResumeI(tp);
- tp = NULL;
- }
chSchRescheduleS();
chSysUnlock();
* @endcode
- * The above example performs a signal operation on two semaphores, optionally
- * resumes a thread, and performs a final reschedulation. The three operations
- * are performed atomically.<br>
+ * The above example performs a signal operation on two semaphores and
+ * performs a final reschedulation. The two operations are performed
+ * atomically.<br>
* An hypotetical @p chSemSignalSignalWait() operation could be implemented as
* follow:
* @code
diff --git a/docs/src/timing.dox b/docs/src/timing.dox
new file mode 100644
index 000000000..e38fcb74c
--- /dev/null
+++ b/docs/src/timing.dox
@@ -0,0 +1,42 @@
+/**
+ * @page article_timing Reliable timings using Threads
+ * @{
+ * One common task is to have threads do something at regular, scheduled,
+ * intervals.
+ * An obvious solution is to write something like this:
+ * @code
+msg_t my_thread(void *param) {
+
+ while (TRUE) {
+ do_something();
+ chThdSleepMilliseconds(1000); /* Fixed interval */
+ }
+}
+ * @endcode
+ * This example works well assuming that @p do_something() execution time is
+ * well below the system tick period and that @p my_thread() is not preempted
+ * by other threads inserting long intervals.<br>
+ * If the above conditions are not satisfied you may have @p do_something()
+ * executed at irregular intevals, as example:<br><br>
+ * T0...T0+1000...T0+2002...T0+3002...T0+4005...etc.<br><br>
+ * Also note that the error increases over time and this kind of behavior can
+ * lead anomalies really hard to debug.
+ * <h2>A better solution</h2>
+ * It is possible to rewrite the above code using absolute deadlines rather
+ * than fixed intervals:
+ * @code
+msg_t my_thread(void *param) {
+
+ systick_t time = chSysGetTime(); /* T0 */
+ while (TRUE) {
+ time += MS2ST(1000); /* Next deadline */
+ do_something();
+ chThdSleepUntil(time);
+ }
+}
+ * @endcode
+ * Using this code @p do_something() will always be executed at an absolute
+ * deadline time and the error will not accumulate over time regardless of
+ * the execution time and delays inserted by other threads.
+ */
+/** @} */
diff --git a/src/chschd.c b/src/chschd.c
index e568ac64a..cc89682a8 100644
--- a/src/chschd.c
+++ b/src/chschd.c
@@ -102,11 +102,13 @@ static void wakeup(void *p) {
#ifdef CH_USE_SEMAPHORES
case PRWTSEM:
chSemFastSignalI(tp->p_wtsemp);
- /* Falls into, intentional.*/
+ /* Falls into, intentional. */
#endif
case PRWTCOND:
- chSchReadyI(dequeue(tp))->p_rdymsg = RDY_TIMEOUT;
- break;
+ case PRWTMTX:
+ /* States requiring dequeuing. */
+ dequeue(tp);
+ /* Falls into, intentional. */
default:
chSchReadyI(tp)->p_rdymsg = RDY_TIMEOUT;
}
diff --git a/src/chthreads.c b/src/chthreads.c
index 355687423..28d969e46 100644
--- a/src/chthreads.c
+++ b/src/chthreads.c
@@ -215,26 +215,6 @@ void chThdSetPriority(tprio_t newprio) {
}
/**
- * @brief Suspends the invoking thread.
- *
- * @param tpp pointer to a @p Thread pointer, the @p Thread pointer is set
- * to point to the suspended process before it enters the
- * @p PRSUSPENDED state. The variable pointed by this parameter
- * must be set to @p NULL on entry.
- * @note The resume operation is meant to be executed into an interrupt or timer
- * handler. The handler is also responsible to clear the variable pointed
- * by @p tpp after invoking @p chThdResumeI().
- */
-void chThdSuspend(Thread **tpp) {
-
- chSysLock();
- chDbgAssert(*tpp == NULL, "chthreads.c, chThdSuspend()");
- *tpp = currp;
- chSchGoSleepS(PRSUSPENDED);
- chSysUnlock();
-}
-
-/**
* @brief Resumes a suspended thread.
*
* @param tp the pointer to the thread
diff --git a/src/include/threads.h b/src/include/threads.h
index 68f7f9bb9..5ca7dd0ce 100644
--- a/src/include/threads.h
+++ b/src/include/threads.h
@@ -183,7 +183,6 @@ extern "C" {
#endif
void chThdSetPriority(tprio_t newprio);
Thread *chThdResume(Thread *tp);
- void chThdSuspend(Thread **tpp);
void chThdTerminate(Thread *tp);
void chThdSleep(systime_t time);
void chThdSleepUntil(systime_t time);
diff --git a/test/testsem.c b/test/testsem.c
index c9361a0bb..1ec0a7a13 100644
--- a/test/testsem.c
+++ b/test/testsem.c
@@ -94,7 +94,6 @@ static void sem2_execute(void) {
test_assert(isempty(&sem1.s_queue), "queue not empty");
test_assert(&sem1.s_cnt != 0, "counter not zero");
}
- test_assert(chSemGetCounter(&sem1) == 0, "non zero counter");
test_assert_sequence("ABCDE");
test_assert_time_window(target_time, target_time + ALLOWED_DELAY);
}