From 430010715e7a9af17185412273165674f3b58f20 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 16 Dec 2007 19:01:30 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@141 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- src/chmtx.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++ src/chsem.c | 129 ------------------------ src/chthreads.c | 14 ++- src/include/ch.h | 4 + src/include/mutexes.h | 66 +++++++++++++ src/include/semaphores.h | 9 +- src/include/threads.h | 26 ++--- src/templates/chconf.h | 7 +- 8 files changed, 347 insertions(+), 157 deletions(-) create mode 100644 src/chmtx.c create mode 100644 src/include/mutexes.h (limited to 'src') diff --git a/src/chmtx.c b/src/chmtx.c new file mode 100644 index 000000000..1c0055acd --- /dev/null +++ b/src/chmtx.c @@ -0,0 +1,249 @@ +/* + 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 . +*/ + +/** + * @addtogroup Mutexes + * @{ + */ + +#include + +#ifdef CH_USE_MUTEXES + +/** + * Initializes s \p Mutex structure. + * @param mp pointer to a \p Mutex structure + */ +void chMtxInit(Mutex *mp) { + + fifo_init(&mp->m_queue); + 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; +} + +/* + * 0 +++BA++------------------2+++--8++++++++++BR0---------------------------- + * 1 .......++AA++--2+++++++++BA....8..........++++++++BR8++++AR1------------- + * 2 .............++AA..............................................----++AR++ + * 8 .............................++AA........................++++++AR++...... + * + * + * 5 ++++++++++++++++++AA+....9++++++++++++++AR5------------------------------ + * 7 .....................++-------------------------------------------------- + * 9 .......................++AA.............+++++++++AR++++++++++++++++++++++ + */ + +/** + * Locks the specified mutex. + * @param mp pointer to the \p Mutex structure + */ +void chMtxLock(Mutex *mp) { + + chSysLock(); + + chMtxLockS(mp); + + chSysUnlock(); +} + +/** + * Locks the specified mutex. + * @param mp pointer to the \p Mutex structure + * @note This function must be called within a \p chSysLock() / \p chSysUnlock() + * block. + */ +void chMtxLockS(Mutex *mp) { + + if (mp->m_owner != NULL) { + /* + * Inheritance, explores the thread-mutex dependances adjusting + * the priority of all the affected threads. + */ + Thread *tp = mp->m_owner; + while (tp->p_prio < currp->p_prio) { + tp->p_prio = currp->p_prio; + switch (tp->p_state) { + case PRWTMTX: + prio_enq(dequeue(tp), &tp->p_mtxp->m_queue); + tp = tp->p_mtxp->m_owner; + continue; + case PRREADY: + chSchReadyI(dequeue(tp), RDY_OK); + } + break; + } + /* + * Goes to sleep on the mutex. + */ + prio_enq(currp, &mp->m_queue); + currp->p_mtxp = mp; + chSchGoSleepS(PRWTMTX); + chDbgAssert(mp->m_owner == NULL, "chmtx.c, chMtxLockS()"); + } + /* + * The mutex is now inserted in the owned mutexes list. + */ + mp->m_owner = currp; + mp->m_next = currp->p_mtxlist; + currp->p_mtxlist = mp; +} + +/** + * Tries to lock a mutex. This function does not have any overhead related to + * the priority inheritance mechanism because it does not try to enter a sleep + * state on the mutex. + * @param mp pointer to the \p Mutex structure + * @return \p TRUE if the mutex was successfully acquired else \p FALSE + */ +BOOL chMtxTryLock(Mutex *mp) { + + chSysLock(); + + BOOL b = chMtxTryLockS(mp); + + chSysUnlock(); + return b; +} + +/** + * Tries to lock a mutex. This function does not have any overhead related to + * the priority inheritance mechanism because it does not try to enter a sleep + * state on the mutex. + * @param mp pointer to the \p Mutex structure + * @return \p TRUE if the mutex was successfully acquired else \p FALSE + * @note This function must be called within a \p chSysLock() / \p chSysUnlock() + * block. + */ +BOOL chMtxTryLockS(Mutex *mp) { + + if (mp->m_owner != NULL) + return FALSE; + mp->m_owner = currp; + mp->m_next = currp->p_mtxlist; + currp->p_mtxlist = mp; + return TRUE; +} + +/** + * Unlocks the next owned mutex in reverse lock order. + */ +void chMtxUnlock(void) { + + chSysLock(); + + chMtxUnlockS(); + + chSysUnlock(); +} + +/** + * Unlocks the next owned mutex in reverse lock order. + * @note This function must be called within a \p chSysLock() / \p chSysUnlock() + * block. + */ +void chMtxUnlockS(void) { + + chDbgAssert((currp->p_mtxlist != NULL) && (currp->p_mtxlist->m_owner == currp), + "chmtx.c, chMtxUnlockS()"); + + /* + * Removes the top Mutex from the owned mutexes list and marks it as not owned. + */ + Mutex *mp = currp->p_mtxlist; + currp->p_mtxlist = mp->m_next; + mp->m_owner = NULL; + /* + * If a thread is waiting on the mutex then the hard part begins. + */ + if (chMtxQueueNotEmptyS(mp)) { + Thread *tp = fifo_remove(&mp->m_queue); + /* + * Recalculates the optimal thread priority by scanning the owned mutexes list. + */ + t_prio newprio = currp->p_realprio; + mp = currp->p_mtxlist; + while (mp != NULL) { + if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio)) + newprio = mp->m_queue.p_next->p_prio; + mp = mp->m_next; + } + currp->p_prio = newprio; + chSchWakeupS(tp, RDY_OK); + } +} + +/** + * Unlocks all the mutexes owned by the invoking thread, this is MUCH MORE + * efficient than releasing the mutexes one by one and not just because the + * call overhead, this function does not have any overhead related to the + * priority inheritance mechanism. + */ +void chMtxUnlockAll(void) { + + chSysLock(); + + chMtxUnlockAllS(); + + chSysUnlock(); +} + +/** + * Unlocks all the mutexes owned by the invoking thread, this is MUCH MORE + * efficient than releasing the mutexes one by one and not just because the + * call overhead, this function does not have any overhead related to the + * priority inheritance mechanism. + * @note This function must be called within a \p chSysLock() / \p chSysUnlock() + * block. + */ +void chMtxUnlockAllS(void) { + + if (currp->p_mtxlist != NULL) { + do { + Mutex *mp = currp->p_mtxlist; + currp->p_mtxlist = mp->m_next; + mp->m_owner = NULL; + if (chMtxQueueNotEmptyS(mp)) + chSchReadyI(fifo_remove(&mp->m_queue), RDY_OK); + } while (currp->p_mtxlist != NULL); + currp->p_prio = currp->p_realprio; + chSchRescheduleS(); + } +} + +#endif /* CH_USE_MUTEXES */ + +/** @} */ diff --git a/src/chsem.c b/src/chsem.c index 083e25412..8e5073248 100644 --- a/src/chsem.c +++ b/src/chsem.c @@ -225,135 +225,6 @@ void chSemSignalWait(Semaphore *sps, Semaphore *spw) { } #endif /* CH_USE_SEMSW */ -#ifdef CH_USE_RT_SEMAPHORES -/* - * 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 - * @note Usually you dont need to use this function in the user code unless - * you want to create some custom threads synchronization mechanism. - */ -static void prioenq(Thread *tp, ThreadsQueue *tqp) { - Thread *cp; - - 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; -} - -/** - * Performs a wait operation on a semaphore with priority boost. - * @param sp pointer to a \p Semaphore structure - * @note The function is available only if the \p CH_USE_RT_SEMAPHORES - * option is enabled in \p chconf.h. - */ -void chSemRaisePrioWait(Semaphore *sp) { - - chSysLock(); - - if (--sp->s_cnt < 0) { - prioenq(currp, &sp->s_queue); - currp->p_semp = sp; - chSchGoSleepS(PRWTSEM); - } - - if (!currp->p_rtcnt++) - currp->p_prio += MEPRIO; - - chSysUnlock(); -} - -/** - * Performs a signal operation on a semaphore with return to normal priority. - * @param sp pointer to a \p Semaphore structure - * @note The function is available only if the \p CH_USE_RT_SEMAPHORES - * option is enabled in \p chconf.h. - */ -void chSemLowerPrioSignal(Semaphore *sp) { - - chSysLock(); - - if (!--currp->p_rtcnt) { - currp->p_prio -= MEPRIO; - if (sp->s_cnt++ < 0) - chSchReadyI(fifo_remove(&sp->s_queue), RDY_OK); - chSchRescheduleS(); - } - else if (sp->s_cnt++ < 0) - chSchWakeupS(fifo_remove(&sp->s_queue), RDY_OK); - - chSysUnlock(); -} - -#ifdef CH_USE_SEMSW -/** - * Performs atomic signal and wait operations on two semaphores with priority - * boost. - * @param sps pointer to a \p Semaphore structure to be signaled - * @param spw pointer to a \p Semaphore structure to be wait on - * @note The function is available only if the \p CH_USE_RT_SEMAPHORES - * option is enabled in \p chconf.h. - */ -void chSemRaisePrioSignalWait(Semaphore *sps, Semaphore *spw) { - - chSysLock(); - - if (sps->s_cnt++ < 0) - chSchReadyI(fifo_remove(&sps->s_queue), RDY_OK); - - if (--spw->s_cnt < 0) { - prioenq(currp, &spw->s_queue); - currp->p_semp = spw; - chSchGoSleepS(PRWTSEM); - - if (!currp->p_rtcnt++) - currp->p_prio += MEPRIO; - } - else { - if (!currp->p_rtcnt++) - currp->p_prio += MEPRIO; - - chSchRescheduleS(); // Really needed ? - } - - chSysUnlock(); -} - -/** - * Performs atomic signal and wait operations on two semaphores with return - * to normal priority. - * @param sps pointer to a \p Semaphore structure to be signaled - * @param spw pointer to a \p Semaphore structure to be wait on - * @note The function is available only if the \p CH_USE_RT_SEMAPHORES - * option is enabled in \p chconf.h. - */ -void chSemLowerPrioSignalWait(Semaphore *sps, Semaphore *spw) { - - chSysLock(); - - if (!--currp->p_rtcnt) - currp->p_prio -= MEPRIO; - - if (sps->s_cnt++ < 0) - chSchReadyI(fifo_remove(&sps->s_queue), RDY_OK); - - if (--spw->s_cnt < 0) { - fifo_insert(currp, &spw->s_queue); // fifo_insert() because the spw is a normal sem. - currp->p_semp = spw; - chSchGoSleepS(PRWTSEM); - } - else - chSchRescheduleS(); - - chSysUnlock(); -} -#endif /* CH_USE_SEMSW */ - -#endif /* CH_USE_RT_SEMAPHORES */ - #endif /* CH_USE_SEMAPHORES */ /** @} */ diff --git a/src/chthreads.c b/src/chthreads.c index 1f37bb808..8a27acdb9 100644 --- a/src/chthreads.c +++ b/src/chthreads.c @@ -34,8 +34,9 @@ void _InitThread(t_prio prio, t_tmode mode, Thread *tp) { tp->p_flags = mode; tp->p_prio = prio; tp->p_rdymsg = RDY_OK; -#ifdef CH_USE_RT_SEMAPHORES - tp->p_rtcnt = 0; +#ifdef CH_USE_MUTEXES + tp->p_mtxlist = NULL; + tp->p_realprio = prio; #endif #ifdef CH_USE_WAITEXIT list_init(&tp->p_waiting); @@ -125,11 +126,14 @@ void chThdSetPriority(t_prio newprio) { chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()") chSysLock(); -#ifdef CH_USE_RT_SEMAPHORES - if (currp->p_rtcnt) - currp->p_prio = newprio + MEPRIO; +#ifdef CH_USE_MUTEXES + if (currp->p_prio != currp->p_realprio) { + if (newprio > currp->p_prio) + currp->p_prio = newprio; + } else currp->p_prio = newprio; + currp->p_realprio = newprio; #else currp->p_prio = newprio; #endif diff --git a/src/include/ch.h b/src/include/ch.h index be251415f..2c2bb2f7c 100644 --- a/src/include/ch.h +++ b/src/include/ch.h @@ -57,6 +57,10 @@ #include "semaphores.h" #endif +#ifndef _MUTEXES_H_ +#include "mutexes.h" +#endif + #ifndef _EVENTS_H_ #include "events.h" #endif diff --git a/src/include/mutexes.h b/src/include/mutexes.h new file mode 100644 index 000000000..e2881423d --- /dev/null +++ b/src/include/mutexes.h @@ -0,0 +1,66 @@ +/* + 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 . +*/ + +/** + * @addtogroup Mutexes + * @{ + */ + +#ifndef _MUTEXES_H_ +#define _MUTEXES_H_ + +#ifdef CH_USE_MUTEXES + +typedef struct Mutex Mutex; + +struct Mutex { + /** Queue of the threads sleeping on this Mutex.*/ + ThreadsQueue m_queue; + /** Owner \p Thread pointer or \p NULL.*/ + Thread *m_owner; + /** Next \p Mutex into an owner-list, \p NULL if none.*/ + Mutex *m_next; +}; + +#ifdef __cplusplus +extern "C" { +#endif + void chMtxInit(Mutex *mp); + void chMtxLock(Mutex *mp); + void chMtxLockS(Mutex *mp); + BOOL chMtxTryLock(Mutex *mp); + BOOL chMtxTryLockS(Mutex *mp); + void chMtxUnlock(void); + void chMtxUnlockS(void); + void chMtxUnlockAll(void); + void chMtxUnlockAllS(void); +#ifdef __cplusplus +} +#endif + +/** + * Returns \p TRUE if the mutex queus contains at least a waiting thread. + */ +#define chMtxQueueNotEmptyS(mp) notempty(&(mp)->m_queue) + +#endif /* CH_USE_MUTEXES */ + +#endif /* _MUTEXES_H_ */ + +/** @} */ diff --git a/src/include/semaphores.h b/src/include/semaphores.h index e17d03a6a..0457da81d 100644 --- a/src/include/semaphores.h +++ b/src/include/semaphores.h @@ -52,13 +52,6 @@ extern "C" { void chSemSignal(Semaphore *sp); void chSemSignalI(Semaphore *sp); void chSemSignalWait(Semaphore *sps, Semaphore *spw); - -#ifdef CH_USE_RT_SEMAPHORES - void chSemRaisePrioWait(Semaphore *sp); - void chSemLowerPrioSignal(Semaphore *sp); - void chSemRaisePrioSignalWait(Semaphore *sps, Semaphore *spw); - void chSemLowerPrioSignalWait(Semaphore *sps, Semaphore *spw); -#endif #ifdef __cplusplus } #endif @@ -82,6 +75,6 @@ extern "C" { #endif /* CH_USE_SEMAPHORES */ -#endif /* _SEM_H_ */ +#endif /* _SEMAPHORES_H_ */ /** @} */ diff --git a/src/include/threads.h b/src/include/threads.h index 0783c4e9a..241b44442 100644 --- a/src/include/threads.h +++ b/src/include/threads.h @@ -62,6 +62,9 @@ struct Thread { /** Semaphore where the thread is waiting on (only in \p PRWTSEM state).*/ Semaphore *p_semp; #endif +#ifdef CH_USE_MUTEXES + Mutex *p_mtxp; +#endif #ifdef CH_USE_EVENTS /** Enabled events mask (only while in \p PRWTEVENT state).*/ t_eventmask p_ewmask; @@ -96,9 +99,10 @@ struct Thread { /** Pending events mask.*/ t_eventmask p_epending; #endif -#ifdef CH_USE_RT_SEMAPHORES - /** RT semaphores depth counter.*/ - t_cnt p_rtcnt; +#ifdef CH_USE_MUTEXES + /** Owner mutexes list, \p NULL terminated.*/ + Mutex *p_mtxlist; + t_prio p_realprio; #endif }; @@ -112,18 +116,20 @@ struct Thread { #define PRSUSPENDED 3 /** Thread state: Waiting on a semaphore.*/ #define PRWTSEM 4 +/** Thread state: Waiting on a mutex.*/ +#define PRWTMTX 5 /** Thread state: Waiting in \p chThdSleep() or \p chThdSleepUntil().*/ -#define PRSLEEP 5 +#define PRSLEEP 6 /** Thread state: Waiting in \p chThdWait().*/ -#define PRWAIT 6 +#define PRWAIT 7 /** Thread state: Waiting in \p chEvtWait().*/ -#define PRWTEVENT 7 +#define PRWTEVENT 8 /** Thread state: Waiting in \p chMsgSend().*/ -#define PRSNDMSG 8 +#define PRSNDMSG 9 /** Thread state: Waiting in \p chMsgWait().*/ -#define PRWTMSG 9 +#define PRWTMSG 10 /** Thread state: After termination.*/ -#define PREXIT 10 +#define PREXIT 11 /** Thread option: Termination requested flag.*/ #define P_TERMINATE 1 @@ -138,8 +144,6 @@ struct Thread { #define NORMALPRIO 64 /** Highest user priority.*/ #define HIGHPRIO 127 -/** Boosted base priority.*/ -#define MEPRIO 128 /** Greatest possible priority.*/ #define ABSPRIO 255 diff --git a/src/templates/chconf.h b/src/templates/chconf.h index 187eb2373..fb8ae6a69 100644 --- a/src/templates/chconf.h +++ b/src/templates/chconf.h @@ -78,10 +78,9 @@ * @note requires \p CH_USE_VIRTUAL_TIMERS.*/ #define CH_USE_SEMAPHORES_TIMEOUT -/** Configuration option: if specified then the Semaphores APIs with priority - * shift are included in the kernel. - * @note requires \p CH_USE_SEMAPHORES.*/ -#define CH_USE_RT_SEMAPHORES +/** Configuration option: if specified then the Mutexes APIs are included in + * the kernel.*/ +#define CH_USE_MUTEXES /** Configuration option: if specified then the Events APIs are included in * the kernel.*/ -- cgit v1.2.3