diff options
-rw-r--r-- | readme.txt | 9 | ||||
-rw-r--r-- | src/chinit.c | 3 | ||||
-rw-r--r-- | src/chlists.c | 19 | ||||
-rw-r--r-- | src/chmtx.c | 34 | ||||
-rw-r--r-- | src/chschd.c | 21 | ||||
-rw-r--r-- | src/include/inline.h | 10 | ||||
-rw-r--r-- | src/include/lists.h | 1 | ||||
-rw-r--r-- | src/include/scheduler.h | 1 |
8 files changed, 48 insertions, 50 deletions
diff --git a/readme.txt b/readme.txt index 632e65c2d..df08d43da 100644 --- a/readme.txt +++ b/readme.txt @@ -50,9 +50,14 @@ AVR-AT90CANx-GCC - Port on AVR AT90CAN128, not complete yet. various mechanisms and the correct use cases.
- RT Semaphores subsystem removed, the Mutexes implements a better solution
for the same problem.
+- Fixed a bug in the round robin scheduling mode, see the bug tracker for
+ details and a fix for previous versions.
- More performance improvements to the scheduler, see the remarks into the
- chSchWakeupS() function source. The benchmark suite reports a 6% increase
- in the context switch performance.
+ chSchWakeupS() function source. This change makes the ready list insertion
+ time in many cases constant (not influenced by the number of ready threads).
+ The worst case is always proportional to the number of threads in the ready
+ list but the normal case is much more often constant than linear. See the
+ new benchmarks added to the test suite.
- Added mutexes test cases and new benchmarks to the test suite.
- Modified the test suite in order to have each test case to have the same
alignment enforced on functions. This is done to reduce MAM/Cache alignment
diff --git a/src/chinit.c b/src/chinit.c index e57c0614e..06ee2fc9b 100644 --- a/src/chinit.c +++ b/src/chinit.c @@ -66,7 +66,8 @@ void chSysInit(void) { */
void chSysTimerHandlerI(void) {
- rlist.r_preempt--;
+ if (rlist.r_preempt > 0)
+ rlist.r_preempt--;
#ifdef CH_USE_SYSTEMTIME
rlist.r_stime++;
#endif
diff --git a/src/chlists.c b/src/chlists.c index 7994f8ac6..37db948b2 100644 --- a/src/chlists.c +++ b/src/chlists.c @@ -18,13 +18,30 @@ */
/**
- * @addtogroup Messages
+ * @addtogroup Threads
* @{
*/
#include <ch.h>
#ifndef CH_OPTIMIZE_SPEED
/*
+ * Inserts a thread into a priority ordered queue.
+ * @param tp the pointer to the thread to be inserted in the list
+ * @param tqp the pointer to the threads list header
+ * @note the insertion is done by scanning the list from the highest priority
+ * toward the lowest
+ */
+void prio_insert(Thread *tp, ThreadsQueue *tqp) {
+
+ Thread *cp = tqp->p_next;
+ while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio))
+ cp = cp->p_next;
+ /* Insertion on p_prev.*/
+ tp->p_prev = (tp->p_next = cp)->p_prev;
+ tp->p_prev->p_next = cp->p_prev = tp;
+}
+
+/*
* Inserts a thread into a FIFO queue.
* @param tp the pointer to the thread to be inserted in the list
* @param tqp the pointer to the threads list header
diff --git a/src/chmtx.c b/src/chmtx.c index 822789270..9037621bb 100644 --- a/src/chmtx.c +++ b/src/chmtx.c @@ -36,25 +36,6 @@ void chMtxInit(Mutex *mp) { mp->m_owner = NULL;
}
-/*
- * Inserts a thread into a list ordering it by priority.
- * @param tp the pointer to the thread to be inserted in the list
- * @param tqp the pointer to the threads list header
- */
-#ifdef CH_OPTIMIZE_SPEED
-static INLINE void prio_enq(Thread *tp, ThreadsQueue *tqp) {
-#else
-static void prio_enq(Thread *tp, ThreadsQueue *tqp) {
-#endif
-
- Thread *cp = tqp->p_next;
- while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio))
- cp = cp->p_next;
- /* Insertion on p_prev.*/
- tp->p_prev = (tp->p_next = cp)->p_prev;
- tp->p_prev->p_next = cp->p_prev = tp;
-}
-
/**
* Locks the specified mutex.
* @param mp pointer to the \p Mutex structure
@@ -86,7 +67,7 @@ void chMtxLockS(Mutex *mp) { tp->p_prio = currp->p_prio;
switch (tp->p_state) {
case PRWTMTX:
- prio_enq(dequeue(tp), &tp->p_mtxp->m_queue);
+ prio_insert(dequeue(tp), &tp->p_mtxp->m_queue);
tp = tp->p_mtxp->m_owner;
continue;
case PRREADY:
@@ -97,7 +78,7 @@ void chMtxLockS(Mutex *mp) { /*
* Goes to sleep on the mutex.
*/
- prio_enq(currp, &mp->m_queue);
+ prio_insert(currp, &mp->m_queue);
currp->p_mtxp = mp;
chSchGoSleepS(PRWTMTX);
chDbgAssert(mp->m_owner == NULL, "chmtx.c, chMtxLockS()");
@@ -189,15 +170,8 @@ void chMtxUnlockS(void) { newprio = mp->m_queue.p_next->p_prio;
mp = mp->m_next;
}
- if (currp->p_prio == newprio)
- chSchWakeupS(tp, RDY_OK);
- else {
- /* Note, changing priority and use chSchWakeupS() is wrong because the
- internal optimization, see the chSchWakeupS() notes.*/
- currp->p_prio = newprio;
- chSchReadyI(tp, RDY_OK);
- chSchRescheduleS();
- }
+ currp->p_prio = newprio;
+ chSchWakeupS(tp, RDY_OK);
}
}
diff --git a/src/chschd.c b/src/chschd.c index 78efa57f7..78f051bf8 100644 --- a/src/chschd.c +++ b/src/chschd.c @@ -35,7 +35,7 @@ ReadyList rlist; void chSchInit(void) {
fifo_init(&rlist.r_queue);
- rlist.r_prio = ABSPRIO;
+// rlist.r_prio = ABSPRIO;
rlist.r_preempt = CH_TIME_QUANTUM;
#ifdef CH_USE_SYSTEMTIME
rlist.r_stime = 0;
@@ -58,15 +58,10 @@ INLINE void chSchReadyI(Thread *tp, t_msg msg) { #else
void chSchReadyI(Thread *tp, t_msg msg) {
#endif
- Thread *cp = rlist.r_queue.p_prev;
tp->p_state = PRREADY;
tp->p_rdymsg = msg;
- while (cp->p_prio < tp->p_prio)
- cp = cp->p_prev;
- /* Insertion on p_next.*/
- tp->p_next = (tp->p_prev = cp)->p_next;
- tp->p_next->p_prev = cp->p_next = tp;
+ prio_insert(tp, &rlist.r_queue);
}
/**
@@ -104,8 +99,6 @@ void chSchGoSleepS(t_tstate newstate) { * @note The function is not meant to be used in the user code directly.
* @note It is equivalent to a \p chSchReadyI() followed by a
* \p chSchRescheduleS() but much more efficient.
- * @note The function assumes that the invoking thread is the highest priority
- * thread, so you can't use it to change priority and reschedule.
*/
void chSchWakeupS(Thread *ntp, t_msg msg) {
@@ -113,15 +106,13 @@ void chSchWakeupS(Thread *ntp, t_msg msg) { chSchReadyI(ntp, msg);
else {
Thread *otp = currp;
- /* Optimization, assumes that the invoking thread has the highest priority
- which is always true unless the priority was willingly changed.
- This assumption allows us to place the thread always on top of the
- ready list without have to scan it, free lunch.*/
+ /* Note, does a prio_insert() instead of a chSchReadyI() because of the
+ relative priority between the two threads, prio_insert() scans the
+ list starting from the highest priority end downward.*/
/* chSchReadyI(otp, RDY_OK);*/
otp->p_state = PRREADY;
otp->p_rdymsg = RDY_OK;
- otp->p_next = (otp->p_prev = (Thread *)&rlist.r_queue)->p_next;
- otp->p_next->p_prev = rlist.r_queue.p_next = otp;
+ prio_insert(otp, &rlist.r_queue);
(currp = ntp)->p_state = PRCURR;
ntp->p_rdymsg = msg;
rlist.r_preempt = CH_TIME_QUANTUM;
diff --git a/src/include/inline.h b/src/include/inline.h index 1982fd075..85de20f3f 100644 --- a/src/include/inline.h +++ b/src/include/inline.h @@ -26,6 +26,16 @@ * this is true for GCC, not sure about other compilers.
*/
#ifdef CH_OPTIMIZE_SPEED
+static INLINE void prio_insert(Thread *tp, ThreadsQueue *tqp) {
+
+ Thread *cp = tqp->p_next;
+ while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio))
+ cp = cp->p_next;
+ /* Insertion on p_prev.*/
+ tp->p_prev = (tp->p_next = cp)->p_prev;
+ tp->p_prev->p_next = cp->p_prev = tp;
+}
+
static INLINE void fifo_insert(Thread *tp, ThreadsQueue *tqp) {
tp->p_prev = (tp->p_next = (Thread *)tqp)->p_prev;
diff --git a/src/include/lists.h b/src/include/lists.h index 043538457..2a8f20e82 100644 --- a/src/include/lists.h +++ b/src/include/lists.h @@ -59,6 +59,7 @@ typedef struct { #ifdef __cplusplus
extern "C" {
#endif
+ void prio_insert(Thread *tp, ThreadsQueue *tqp);
void fifo_insert(Thread *tp, ThreadsQueue *tqp);
Thread *fifo_remove(ThreadsQueue *tqp);
Thread *dequeue(Thread *tp);
diff --git a/src/include/scheduler.h b/src/include/scheduler.h index 183e3af79..565b75ccb 100644 --- a/src/include/scheduler.h +++ b/src/include/scheduler.h @@ -39,7 +39,6 @@ */
typedef struct {
ThreadsQueue r_queue;
- t_prio r_prio;
t_cnt r_preempt;
#ifndef CH_CURRP_REGISTER_CACHE
Thread *r_current;
|