aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os/rt/include/chmtx.h2
-rw-r--r--os/rt/src/chmtx.c339
-rw-r--r--test/rt/testmtx.c7
3 files changed, 211 insertions, 137 deletions
diff --git a/os/rt/include/chmtx.h b/os/rt/include/chmtx.h
index a85fb84e7..30367a1ab 100644
--- a/os/rt/include/chmtx.h
+++ b/os/rt/include/chmtx.h
@@ -63,7 +63,7 @@ struct mutex {
mutex_t *m_next; /**< @brief Next @p mutex_t into an
owner-list or @p NULL. */
#if CH_CFG_USE_MUTEXES_RECURSIVE || defined(__DOXYGEN__)
- cnt_t m_taken; /**< @brief Mutex recursion counter. */
+ cnt_t m_cnt; /**< @brief Mutex recursion counter. */
#endif
};
diff --git a/os/rt/src/chmtx.c b/os/rt/src/chmtx.c
index cf0f2e7b3..45e884204 100644
--- a/os/rt/src/chmtx.c
+++ b/os/rt/src/chmtx.c
@@ -108,6 +108,9 @@ void chMtxObjectInit(mutex_t *mp) {
queue_init(&mp->m_queue);
mp->m_owner = NULL;
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ mp->m_cnt = 0;
+#endif
}
/**
@@ -145,65 +148,84 @@ void chMtxLockS(mutex_t *mp) {
/* Is the mutex already locked? */
if (mp->m_owner != NULL) {
- /* Priority inheritance protocol; explores the thread-mutex dependencies
- boosting the priority of all the affected threads to equal the priority
- of the running thread requesting the mutex.*/
- thread_t *tp = mp->m_owner;
-
- /* Does the running thread have higher priority than the mutex
- owning thread? */
- while (tp->p_prio < ctp->p_prio) {
- /* Make priority of thread tp match the running thread's priority.*/
- tp->p_prio = ctp->p_prio;
-
- /* The following states need priority queues reordering.*/
- switch (tp->p_state) {
- case CH_STATE_WTMTX:
- /* Re-enqueues the mutex owner with its new priority.*/
- queue_prio_insert(queue_dequeue(tp),
- (threads_queue_t *)tp->p_u.wtobjp);
- tp = ((mutex_t *)tp->p_u.wtobjp)->m_owner;
- continue;
-#if CH_CFG_USE_CONDVARS | \
- (CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY) | \
- (CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY)
-#if CH_CFG_USE_CONDVARS
- case CH_STATE_WTCOND:
-#endif
-#if CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY
- case CH_STATE_WTSEM:
-#endif
-#if CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY
- case CH_STATE_SNDMSGQ:
-#endif
- /* Re-enqueues tp with its new priority on the queue.*/
- queue_prio_insert(queue_dequeue(tp),
- (threads_queue_t *)tp->p_u.wtobjp);
- break;
-#endif
- case CH_STATE_READY:
-#if CH_DBG_ENABLE_ASSERTS
- /* Prevents an assertion in chSchReadyI().*/
- tp->p_state = CH_STATE_CURRENT;
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+
+ chDbgAssert(mp->m_cnt >= 1, "counter is not positive");
+
+ /* If the mutex is already owned by this thread, the counter is increased
+ and there is no need of more actions.*/
+ if (mp->m_owner == ctp)
+ mp->m_cnt++;
+ else {
#endif
- /* Re-enqueues tp with its new priority on the ready list.*/
- chSchReadyI(queue_dequeue(tp));
+ /* Priority inheritance protocol; explores the thread-mutex dependencies
+ boosting the priority of all the affected threads to equal the
+ priority of the running thread requesting the mutex.*/
+ thread_t *tp = mp->m_owner;
+
+ /* Does the running thread have higher priority than the mutex
+ owning thread? */
+ while (tp->p_prio < ctp->p_prio) {
+ /* Make priority of thread tp match the running thread's priority.*/
+ tp->p_prio = ctp->p_prio;
+
+ /* The following states need priority queues reordering.*/
+ switch (tp->p_state) {
+ case CH_STATE_WTMTX:
+ /* Re-enqueues the mutex owner with its new priority.*/
+ queue_prio_insert(queue_dequeue(tp),
+ (threads_queue_t *)tp->p_u.wtobjp);
+ tp = ((mutex_t *)tp->p_u.wtobjp)->m_owner;
+ continue;
+ #if CH_CFG_USE_CONDVARS | \
+ (CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY) | \
+ (CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY)
+ #if CH_CFG_USE_CONDVARS
+ case CH_STATE_WTCOND:
+ #endif
+ #if CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY
+ case CH_STATE_WTSEM:
+ #endif
+ #if CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY
+ case CH_STATE_SNDMSGQ:
+ #endif
+ /* Re-enqueues tp with its new priority on the queue.*/
+ queue_prio_insert(queue_dequeue(tp),
+ (threads_queue_t *)tp->p_u.wtobjp);
+ break;
+ #endif
+ case CH_STATE_READY:
+ #if CH_DBG_ENABLE_ASSERTS
+ /* Prevents an assertion in chSchReadyI().*/
+ tp->p_state = CH_STATE_CURRENT;
+ #endif
+ /* Re-enqueues tp with its new priority on the ready list.*/
+ chSchReadyI(queue_dequeue(tp));
+ break;
+ }
break;
}
- break;
- }
- /* Sleep on the mutex.*/
- queue_prio_insert(ctp, &mp->m_queue);
- ctp->p_u.wtobjp = mp;
- chSchGoSleepS(CH_STATE_WTMTX);
-
- /* It is assumed that the thread performing the unlock operation assigns
- the mutex to this thread.*/
- chDbgAssert(mp->m_owner == ctp, "not owner");
- chDbgAssert(ctp->p_mtxlist == mp, "not owned");
+ /* Sleep on the mutex.*/
+ queue_prio_insert(ctp, &mp->m_queue);
+ ctp->p_u.wtobjp = mp;
+ chSchGoSleepS(CH_STATE_WTMTX);
+
+ /* It is assumed that the thread performing the unlock operation assigns
+ the mutex to this thread.*/
+ chDbgAssert(mp->m_owner == ctp, "not owner");
+ chDbgAssert(ctp->p_mtxlist == mp, "not owned");
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ chDbgAssert(mp->m_cnt == 1, "counter is not one");
+ }
+#endif
}
else {
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ chDbgAssert(mp->m_cnt == 0, "counter is not zero");
+
+ mp->m_cnt++;
+#endif
/* It was not owned, inserted in the owned mutexes list.*/
mp->m_owner = ctp;
mp->m_next = ctp->p_mtxlist;
@@ -261,9 +283,24 @@ bool chMtxTryLockS(mutex_t *mp) {
chDbgCheckClassS();
chDbgCheck(mp != NULL);
- if (mp->m_owner != NULL)
+ if (mp->m_owner != NULL) {
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+
+ chDbgAssert(mp->m_cnt >= 1, "counter is not positive");
+
+ if (mp->m_owner == currp) {
+ mp->m_cnt++;
+ return true;
+ }
+#endif
return false;
+ }
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+
+ chDbgAssert(mp->m_cnt == 0, "counter is not zero");
+ mp->m_cnt++;
+#endif
mp->m_owner = currp;
mp->m_next = currp->p_mtxlist;
currp->p_mtxlist = mp;
@@ -284,48 +321,62 @@ void chMtxUnlock(mutex_t *mp) {
thread_t *ctp = currp;
mutex_t *lmp;
+ chDbgCheck(mp != NULL);
+
chSysLock();
chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty");
- chDbgAssert(ctp->p_mtxlist != mp, "not next in list");
chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure");
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ chDbgAssert(mp->m_cnt >= 1, "counter is not positive");
- /* Removes the top mutex from the thread's owned mutexes list and marks
- it as not owned. Note, it is assumed to be the same mutex passed as
- parameter of this function.*/
- ctp->p_mtxlist = mp->m_next;
-
- /* If a thread is waiting on the mutex then the fun part begins.*/
- if (chMtxQueueNotEmptyS(mp)) {
- thread_t *tp;
-
- /* Recalculates the optimal thread priority by scanning the owned
- mutexes list.*/
- tprio_t newprio = ctp->p_realprio;
- lmp = ctp->p_mtxlist;
- while (lmp != NULL) {
- /* If the highest priority thread waiting in the mutexes list has a
- greater priority than the current thread base priority then the final
- priority will have at least that priority.*/
- if (chMtxQueueNotEmptyS(lmp) && (lmp->m_queue.p_next->p_prio > newprio))
- newprio = lmp->m_queue.p_next->p_prio;
- lmp = lmp->m_next;
- }
+ if (--mp->m_cnt == 0) {
+#endif
+
+ chDbgAssert(ctp->p_mtxlist == mp, "not next in list");
+
+ /* Removes the top mutex from the thread's owned mutexes list and marks
+ it as not owned. Note, it is assumed to be the same mutex passed as
+ parameter of this function.*/
+ ctp->p_mtxlist = mp->m_next;
+
+ /* If a thread is waiting on the mutex then the fun part begins.*/
+ if (chMtxQueueNotEmptyS(mp)) {
+ thread_t *tp;
+
+ /* Recalculates the optimal thread priority by scanning the owned
+ mutexes list.*/
+ tprio_t newprio = ctp->p_realprio;
+ lmp = ctp->p_mtxlist;
+ while (lmp != NULL) {
+ /* If the highest priority thread waiting in the mutexes list has a
+ greater priority than the current thread base priority then the
+ final priority will have at least that priority.*/
+ if (chMtxQueueNotEmptyS(lmp) && (lmp->m_queue.p_next->p_prio > newprio))
+ newprio = lmp->m_queue.p_next->p_prio;
+ lmp = lmp->m_next;
+ }
+
+ /* Assigns to the current thread the highest priority among all the
+ waiting threads.*/
+ ctp->p_prio = newprio;
- /* Assigns to the current thread the highest priority among all the
- waiting threads.*/
- ctp->p_prio = newprio;
-
- /* Awakens the highest priority thread waiting for the unlocked mutex and
- assigns the mutex to it.*/
- tp = queue_fifo_remove(&mp->m_queue);
- mp->m_owner = tp;
- mp->m_next = tp->p_mtxlist;
- tp->p_mtxlist = mp;
- chSchWakeupS(tp, MSG_OK);
+ /* Awakens the highest priority thread waiting for the unlocked mutex and
+ assigns the mutex to it.*/
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ mp->m_cnt = 1;
+#endif
+ tp = queue_fifo_remove(&mp->m_queue);
+ mp->m_owner = tp;
+ mp->m_next = tp->p_mtxlist;
+ tp->p_mtxlist = mp;
+ chSchWakeupS(tp, MSG_OK);
+ }
+ else
+ mp->m_owner = NULL;
+#if CH_CFG_USE_MUTEXES_RECURSIVE
}
- else
- mp->m_owner = NULL;
+#endif
chSysUnlock();
}
@@ -346,46 +397,61 @@ void chMtxUnlockS(mutex_t *mp) {
thread_t *ctp = currp;
mutex_t *lmp;
+ chDbgCheckClassS();
+ chDbgCheck(mp != NULL);
+
chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty");
- chDbgAssert(ctp->p_mtxlist != mp, "not next in list");
chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure");
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ chDbgAssert(mp->m_cnt >= 1, "counter is not positive");
- /* Removes the top mutex from the thread's owned mutexes list and marks
- it as not owned. Note, it is assumed to be the same mutex passed as
- parameter of this function.*/
- ctp->p_mtxlist = mp->m_next;
-
- /* If a thread is waiting on the mutex then the fun part begins.*/
- if (chMtxQueueNotEmptyS(mp)) {
- thread_t *tp;
-
- /* Recalculates the optimal thread priority by scanning the owned
- mutexes list.*/
- tprio_t newprio = ctp->p_realprio;
- lmp = ctp->p_mtxlist;
- while (lmp != NULL) {
- /* If the highest priority thread waiting in the mutexes list has a
- greater priority than the current thread base priority then the final
- priority will have at least that priority.*/
- if (chMtxQueueNotEmptyS(lmp) && (lmp->m_queue.p_next->p_prio > newprio))
- newprio = lmp->m_queue.p_next->p_prio;
- lmp = lmp->m_next;
- }
+ if (--mp->m_cnt == 0) {
+#endif
+
+ chDbgAssert(ctp->p_mtxlist == mp, "not next in list");
+
+ /* Removes the top mutex from the thread's owned mutexes list and marks
+ it as not owned. Note, it is assumed to be the same mutex passed as
+ parameter of this function.*/
+ ctp->p_mtxlist = mp->m_next;
+
+ /* If a thread is waiting on the mutex then the fun part begins.*/
+ if (chMtxQueueNotEmptyS(mp)) {
+ thread_t *tp;
+
+ /* Recalculates the optimal thread priority by scanning the owned
+ mutexes list.*/
+ tprio_t newprio = ctp->p_realprio;
+ lmp = ctp->p_mtxlist;
+ while (lmp != NULL) {
+ /* If the highest priority thread waiting in the mutexes list has a
+ greater priority than the current thread base priority then the
+ final priority will have at least that priority.*/
+ if (chMtxQueueNotEmptyS(lmp) && (lmp->m_queue.p_next->p_prio > newprio))
+ newprio = lmp->m_queue.p_next->p_prio;
+ lmp = lmp->m_next;
+ }
+
+ /* Assigns to the current thread the highest priority among all the
+ waiting threads.*/
+ ctp->p_prio = newprio;
- /* Assigns to the current thread the highest priority among all the
- waiting threads.*/
- ctp->p_prio = newprio;
-
- /* Awakens the highest priority thread waiting for the unlocked mutex and
- assigns the mutex to it.*/
- tp = queue_fifo_remove(&mp->m_queue);
- mp->m_owner = tp;
- mp->m_next = tp->p_mtxlist;
- tp->p_mtxlist = mp;
- chSchReadyI(tp);
+ /* Awakens the highest priority thread waiting for the unlocked mutex and
+ assigns the mutex to it.*/
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ mp->m_cnt = 1;
+#endif
+ tp = queue_fifo_remove(&mp->m_queue);
+ mp->m_owner = tp;
+ mp->m_next = tp->p_mtxlist;
+ tp->p_mtxlist = mp;
+ chSchReadyI(tp);
+ }
+ else
+ mp->m_owner = NULL;
+#if CH_CFG_USE_MUTEXES_RECURSIVE
}
- else
- mp->m_owner = NULL;
+#endif
}
/**
@@ -405,17 +471,24 @@ void chMtxUnlockAll(void) {
chSysLock();
if (ctp->p_mtxlist != NULL) {
do {
- mutex_t *ump = ctp->p_mtxlist;
- ctp->p_mtxlist = ump->m_next;
- if (chMtxQueueNotEmptyS(ump)) {
- thread_t *tp = queue_fifo_remove(&ump->m_queue);
- ump->m_owner = tp;
- ump->m_next = tp->p_mtxlist;
- tp->p_mtxlist = ump;
+ mutex_t *mp = ctp->p_mtxlist;
+ ctp->p_mtxlist = mp->m_next;
+ if (chMtxQueueNotEmptyS(mp)) {
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ mp->m_cnt = 1;
+#endif
+ thread_t *tp = queue_fifo_remove(&mp->m_queue);
+ mp->m_owner = tp;
+ mp->m_next = tp->p_mtxlist;
+ tp->p_mtxlist = mp;
chSchReadyI(tp);
}
- else
- ump->m_owner = NULL;
+ else {
+#if CH_CFG_USE_MUTEXES_RECURSIVE
+ mp->m_cnt = 0;
+#endif
+ mp->m_owner = NULL;
+ }
} while (ctp->p_mtxlist != NULL);
ctp->p_prio = ctp->p_realprio;
chSchRescheduleS();
diff --git a/test/rt/testmtx.c b/test/rt/testmtx.c
index f2a3c5f5a..ccf7b9497 100644
--- a/test/rt/testmtx.c
+++ b/test/rt/testmtx.c
@@ -432,10 +432,10 @@ static void mtx5_setup(void) {
}
static void mtx5_execute(void) {
- bool b;
- tprio_t prio;
- prio = chThdGetPriorityX();
+#if !CH_CFG_USE_MUTEXES_RECURSIVE
+ bool b;
+ tprio_t prio = chThdGetPriorityX();
b = chMtxTryLock(&m1);
test_assert(1, b, "already locked");
@@ -450,6 +450,7 @@ static void mtx5_execute(void) {
test_assert(3, queue_isempty(&m1.m_queue), "queue not empty");
test_assert(4, m1.m_owner == NULL, "still owned");
test_assert(5, chThdGetPriorityX() == prio, "wrong priority level");
+#endif /* !CH_CFG_USE_MUTEXES_RECURSIVE */
chMtxLock(&m1);
chMtxUnlockAll();