/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 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 .
*/
/**
* @file chmtx.c
* @brief Mutexes code.
*
* @addtogroup mutexes
* @details Mutexes related APIs and services.
*
*
Operation mode
* A mutex is a threads synchronization object that can be in two
* distinct states:
* - Not owned (unlocked).
* - Owned by a thread (locked).
* .
* Operations defined for mutexes:
* - Lock: The mutex is checked, if the mutex is not owned by
* some other thread then it is associated to the locking thread
* else the thread is queued on the mutex in a list ordered by
* priority.
* - Unlock: The mutex is released by the owner and the highest
* priority thread waiting in the queue, if any, is resumed and made
* owner of the mutex.
* .
* Constraints
* In ChibiOS/RT the Unlock operations are always performed in
* lock-reverse order. The unlock API does not even have a parameter,
* the mutex to unlock is selected from an internal, per-thread, stack
* of owned mutexes. This both improves the performance and is
* required for an efficient implementation of the priority
* inheritance mechanism.
*
* The priority inversion problem
* The mutexes in ChibiOS/RT implements the full priority
* inheritance mechanism in order handle the priority inversion
* problem.
* When a thread is queued on a mutex, any thread, directly or
* indirectly, holding the mutex gains the same priority of the
* waiting thread (if their priority was not already equal or higher).
* The mechanism works with any number of nested mutexes and any
* number of involved threads. The algorithm complexity (worst case)
* is N with N equal to the number of nested mutexes.
* @pre In order to use the mutex APIs the @p CH_USE_MUTEXES option
* must be enabled in @p chconf.h.
* @post Enabling mutexes requires 5-12 (depending on the architecture)
* extra bytes in the @p Thread structure.
* @{
*/
#include "ch.h"
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Initializes s @p Mutex structure.
*
* @param[out] mp pointer to a @p Mutex structure
*
* @init
*/
void chMtxInit(Mutex *mp) {
chDbgCheck(mp != NULL, "chMtxInit");
queue_init(&mp->m_queue);
mp->m_owner = NULL;
}
/**
* @brief Locks the specified mutex.
* @post The mutex is locked and inserted in the per-thread stack of owned
* mutexes.
*
* @param[in] mp pointer to the @p Mutex structure
*
* @api
*/
void chMtxLock(Mutex *mp) {
chSysLock();
chMtxLockS(mp);
chSysUnlock();
}
/**
* @brief Locks the specified mutex.
* @post The mutex is locked and inserted in the per-thread stack of owned
* mutexes.
*
* @param[in] mp pointer to the @p Mutex structure
*
* @sclass
*/
void chMtxLockS(Mutex *mp) {
Thread *ctp = currp;
chDbgCheck(mp != NULL, "chMtxLockS");
/* Ia 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 *tp = mp->m_owner;
/* Does the running thread have higher priority than the mutex
ownning 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 THD_STATE_WTMTX:
/* Re-enqueues the mutex owner with its new priority.*/
prio_insert(dequeue(tp), (ThreadsQueue *)tp->p_u.wtobjp);
tp = ((Mutex *)tp->p_u.wtobjp)->m_owner;
continue;
#if CH_USE_CONDVARS | CH_USE_SEMAPHORES_PRIORITY | CH_USE_MESSAGES_PRIORITY
#if CH_USE_CONDVARS
case THD_STATE_WTCOND:
#endif
#if CH_USE_SEMAPHORES_PRIORITY
case THD_STATE_WTSEM:
#endif
#if CH_USE_MESSAGES_PRIORITY
case THD_STATE_SNDMSG:
#endif
/* Re-enqueues tp with its new priority on the queue.*/
prio_insert(dequeue(tp), (ThreadsQueue *)tp->p_u.wtobjp);
break;
#endif
case THD_STATE_READY:
#if CH_DBG_ENABLE_ASSERTS
/* Prevents an assertion in chSchReadyI().*/
tp->p_state = THD_STATE_CURRENT;
#endif
/* Re-enqueues tp with its new priority on the ready list.*/
chSchReadyI(dequeue(tp));
}
break;
}
/* Sleep on the mutex.*/
prio_insert(ctp, &mp->m_queue);
ctp->p_u.wtobjp = mp;
chSchGoSleepS(THD_STATE_WTMTX);
/* It is assumed that the thread performing the unlock operation assigns
the mutex to this thread.*/
chDbgAssert(mp->m_owner == ctp, "chMtxLockS(), #1", "not owner");
chDbgAssert(ctp->p_mtxlist == mp, "chMtxLockS(), #2", "not owned");
}
else {
/* It was /*
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/>.
*/
/*
* STM32 drivers configuration.
* The following settings override the default settings present in
* the various device driver implementation headers.
* Note that the settings for each driver only have effect if the driver
* is enabled in halconf.h.
*
* IRQ priorities:
* 0xF0 Lowest, priority level reserved for PENDSV.
* 0xE0...0x40 Normal IRQs priority levels (0x80 used by SYSTICK).
* 0x30 Used by SVCALL, do not share.
* 0x20...0x00 Fast interrupts, can preempt the kernel but cannot use it.
*
* DMA priorities:
* 0...3 Lowest...Highest.
*/
/*
* ADC driver system settings.
*/
#define USE_STM32_ADC1 TRUE
#define STM32_ADC1_DMA_PRIORITY 3
#define STM32_ADC1_IRQ_PRIORITY 0x50
#define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt()
/*
* CAN driver system settings.
*/
#define USE_STM32_CAN1 TRUE
#define STM32_CAN1_IRQ_PRIORITY 0xB0
/*
* PWM driver system settings.
*/
#define USE_STM32_PWM1 TRUE
#define USE_STM32_PWM2 FALSE
#define USE_STM32_PWM3 FALSE
#define USE_STM32_PWM4 FALSE
#define STM32_PWM1_IRQ_PRIORITY 0x70
#define STM32_PWM2_IRQ_PRIORITY 0x70
#define STM32_PWM3_IRQ_PRIORITY 0x70
#define STM32_PWM4_IRQ_PRIORITY 0x70
/*
* SERIAL driver system settings.
*/
#define USE_STM32_USART1 FALSE
#define USE_STM32_USART2 TRUE
#define USE_STM32_USART3 FALSE
#if defined(STM32F10X_HD) || defined(STM32F10X_CL)
#define USE_STM32_UART4 FALSE
#define USE_STM32_UART5 FALSE
#endif
#define STM32_USART1_PRIORITY 0xC0
#define STM32_USART2_PRIORITY 0xC0
#define STM32_USART3_PRIORITY 0xC0
#if defined(STM32F10X_HD) || defined(STM32F10X_CL)
#define STM32_UART4_PRIORITY 0xC0
#define STM32_UART5_PRIORITY 0xC0
#endif
/*
* SPI driver system settings.
*/
#define USE_STM32_SPI1 TRUE
#define USE_STM32_SPI2 TRUE
#define STM32_SPI1_DMA_PRIORITY 2
#define STM32_SPI2_DMA_PRIORITY 2
#define STM32_SPI1_IRQ_PRIORITY 0xA0
#define STM32_SPI2_IRQ_PRIORITY 0xA0
#define STM32_SPI1_DMA_ERROR_HOOK() chSysHalt()