2015-05-14 16:05:04 -04:00
|
|
|
/// @file
|
2015-12-31 14:56:37 -05:00
|
|
|
/// @brief QP::QMutex::init(), QP::QMutex::lock(), and QP::QMutex::unlock()
|
2014-04-13 21:35:34 -04:00
|
|
|
/// definitions.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @ingroup qk
|
|
|
|
/// @cond
|
2014-04-13 21:35:34 -04:00
|
|
|
///***************************************************************************
|
2014-09-22 11:48:11 -04:00
|
|
|
/// Product: QK/C++
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Last updated for version 5.6.0
|
|
|
|
/// Last updated on 2015-12-30
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
|
|
|
/// Q u a n t u m L e a P s
|
|
|
|
/// ---------------------------
|
|
|
|
/// innovating embedded systems
|
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Copyright (C) Quantum Leaps, LLC. All rights reserved.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
|
|
|
/// This program is open source 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.
|
|
|
|
///
|
|
|
|
/// Alternatively, this program may be distributed and modified under the
|
|
|
|
/// terms of Quantum Leaps commercial licenses, which expressly supersede
|
|
|
|
/// the GNU General Public License and are specifically designed for
|
|
|
|
/// licensees interested in retaining the proprietary status of their code.
|
|
|
|
///
|
|
|
|
/// This program 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/>.
|
|
|
|
///
|
|
|
|
/// Contact information:
|
2015-12-31 14:56:37 -05:00
|
|
|
/// http://www.state-machine.com
|
|
|
|
/// mailto:info@state-machine.com
|
2014-04-13 21:35:34 -04:00
|
|
|
///***************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @endcond
|
2014-04-13 21:35:34 -04:00
|
|
|
|
|
|
|
#define QP_IMPL // this is QF/QK implementation
|
|
|
|
#include "qf_port.h" // QF port
|
|
|
|
#include "qk_pkg.h" // QK package-scope internal interface
|
2015-12-31 14:56:37 -05:00
|
|
|
#include "qassert.h" // QP assertions
|
2014-04-13 21:35:34 -04:00
|
|
|
#ifdef Q_SPY // QS software tracing enabled?
|
|
|
|
#include "qs_port.h" // include QS port
|
|
|
|
#else
|
|
|
|
#include "qs_dummy.h" // disable the QS software tracing
|
|
|
|
#endif // Q_SPY
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-12-31 14:56:37 -05:00
|
|
|
// protection against including this source file in a wrong project
|
|
|
|
#ifndef qk_h
|
|
|
|
#error "Source file included in a project NOT based on the QK kernel"
|
|
|
|
#endif // qk_h
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
namespace QP {
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-12-31 14:56:37 -05:00
|
|
|
Q_DEFINE_THIS_MODULE("qk_mutex")
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//****************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Initialize the QK priority ceiling mutex.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
/// @param[in] prioCeiling ceiling priotity of the mutex
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
/// @note The ceiling priority must be unused by any AO. The ceiling
|
|
|
|
/// priority must be higher than priority of any AO that uses the
|
|
|
|
/// protected resource.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @usage
|
|
|
|
/// @include qk_mux.cpp
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
void QMutex::init(uint_fast8_t const prioCeiling) {
|
2012-08-14 18:00:48 -04:00
|
|
|
QF_CRIT_STAT_
|
2015-12-31 14:56:37 -05:00
|
|
|
|
2012-08-14 18:00:48 -04:00
|
|
|
QF_CRIT_ENTRY_();
|
2015-12-31 14:56:37 -05:00
|
|
|
/// @pre the celiling priority of the mutex must not be zero and cannot
|
|
|
|
/// exceed the maximum #QF_MAX_ACTIVE. Also, the ceiling priority must
|
|
|
|
/// not be already in use. QF requires priority to be __unique__.
|
|
|
|
///
|
|
|
|
Q_REQUIRE_ID(100, (static_cast<uint_fast8_t>(0) < prioCeiling)
|
|
|
|
&& (prioCeiling <= (uint_fast8_t)QF_MAX_ACTIVE)
|
|
|
|
&& (QF::active_[prioCeiling] == static_cast<QMActive *>(0)));
|
|
|
|
|
|
|
|
m_prioCeiling = prioCeiling;
|
|
|
|
m_lockNest = static_cast<uint_fast8_t>(0);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-12-31 14:56:37 -05:00
|
|
|
// reserve the ceiling priority level for this mutex
|
|
|
|
QF::active_[prioCeiling] = reinterpret_cast<QMActive *>(this);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
|
|
|
QF_CRIT_EXIT_();
|
|
|
|
}
|
2014-04-13 21:35:34 -04:00
|
|
|
|
|
|
|
//****************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Lock the QK priority ceiling mutex.
|
|
|
|
///
|
|
|
|
/// @note This function should be always paired with QXK_mutexUnlock(). The
|
|
|
|
/// code between QK_mutexLock() and QK_mutexUnlock() should be kept to the
|
|
|
|
/// minimum.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
/// @usage
|
|
|
|
/// @include qk_mux.cpp
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
void QMutex::lock(void) {
|
|
|
|
QF_CRIT_STAT_
|
|
|
|
|
|
|
|
QF_CRIT_ENTRY_();
|
|
|
|
// is the scheduler unloacked?
|
|
|
|
if (QK_currPrio_ <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE)) {
|
|
|
|
QMActive *act = QF::active_[QK_currPrio_];
|
|
|
|
|
|
|
|
/// @pre QMutex_lock() must not be called from ISR level,
|
|
|
|
/// the thread priority must not exceed the mutex priority ceiling
|
|
|
|
/// and the mutex must be initialized.
|
|
|
|
///
|
|
|
|
Q_REQUIRE_ID(200, (!QK_ISR_CONTEXT_()) /* don't call from an ISR! */
|
|
|
|
&& (act->m_thread <= m_prioCeiling)
|
|
|
|
&& (QF::active_[m_prioCeiling] != static_cast<QMActive *>(0)));
|
|
|
|
|
|
|
|
// is the mutex available?
|
|
|
|
if (m_lockNest == static_cast<uint_fast8_t>(0)) {
|
|
|
|
m_lockNest = static_cast<uint_fast8_t>(1);
|
|
|
|
|
|
|
|
// the priority slot must be set to this mutex
|
|
|
|
Q_ASSERT_ID(210, QF::active_[m_prioCeiling]
|
|
|
|
== reinterpret_cast<QMActive *>(this));
|
|
|
|
|
|
|
|
// switch the priority of this thread to the ceiling priority
|
|
|
|
QF::active_[m_prioCeiling] = act;
|
|
|
|
// set to the ceiling
|
|
|
|
act->m_prio = m_prioCeiling;
|
|
|
|
|
|
|
|
if (QK_readySet_.hasElement(act->m_thread)) {
|
|
|
|
QK_readySet_.remove(act->m_thread);
|
|
|
|
QK_readySet_.insert(act->m_prio);
|
|
|
|
}
|
|
|
|
QK_currPrio_ = act->m_prio;
|
|
|
|
|
|
|
|
QS_BEGIN_NOCRIT_(QS_QK_MUTEX_LOCK,
|
|
|
|
static_cast<void *>(0), static_cast<void *>(0))
|
|
|
|
QS_TIME_(); // timestamp
|
|
|
|
QS_2U8_(static_cast<uint8_t>(act->m_thread), // the start prio
|
|
|
|
static_cast<uint8_t>(act->m_prio)); // current ceiling
|
|
|
|
QS_END_NOCRIT_()
|
|
|
|
}
|
|
|
|
// is the mutex locked by this thread already (nested locking)?
|
|
|
|
else if (QF::active_[m_prioCeiling] == act) {
|
|
|
|
++m_lockNest;
|
|
|
|
}
|
|
|
|
// the mutex can't be locked by a different AO -- error
|
|
|
|
else {
|
|
|
|
Q_ERROR_ID(220);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QF_CRIT_EXIT_();
|
|
|
|
}
|
|
|
|
|
|
|
|
//****************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Unlock the QK priority ceiling mutex.
|
|
|
|
///
|
|
|
|
/// @param[in,out] me pointer (see @ref oop)
|
|
|
|
///
|
|
|
|
/// @note This function should be always paired with QK_mutexLock(). The
|
|
|
|
/// code between QK_mutexLock() and QK_mutexUnlock() should be kept to the
|
|
|
|
/// minimum.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @usage
|
|
|
|
/// @include qk_mux.cpp
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
void QMutex::unlock(void) {
|
2012-08-14 18:00:48 -04:00
|
|
|
QF_CRIT_STAT_
|
2015-12-31 14:56:37 -05:00
|
|
|
|
2012-08-14 18:00:48 -04:00
|
|
|
QF_CRIT_ENTRY_();
|
2015-12-31 14:56:37 -05:00
|
|
|
// is the scheduler unloacked?
|
|
|
|
if (QK_currPrio_ <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE)) {
|
|
|
|
QMActive *act = QF::active_[QK_currPrio_];
|
|
|
|
|
|
|
|
/// @pre QMutex_unlock() must not be called from ISR level
|
|
|
|
/// and the mutex must be owned by this thread.
|
|
|
|
///
|
|
|
|
Q_REQUIRE_ID(300, (!QK_ISR_CONTEXT_()) /* don't call from an ISR! */
|
|
|
|
&& (m_lockNest > static_cast<uint_fast8_t>(0))
|
|
|
|
&& (QF::active_[m_prioCeiling] == act));
|
|
|
|
|
|
|
|
// Unlocking the first nesting level?
|
|
|
|
if (m_lockNest == static_cast<uint_fast8_t>(1)) {
|
|
|
|
uint_fast8_t p;
|
|
|
|
|
|
|
|
m_lockNest = static_cast<uint_fast8_t>(0);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-12-31 14:56:37 -05:00
|
|
|
// reclaim the ceiling priority for this mutex
|
|
|
|
QF::active_[m_prioCeiling] = reinterpret_cast<QMActive *>(this);
|
|
|
|
|
|
|
|
// restore the start priority for this AO...
|
|
|
|
act->m_prio = act->m_thread;
|
|
|
|
QK_currPrio_ = act->m_thread;
|
|
|
|
if (QK_readySet_.hasElement(m_prioCeiling)) {
|
|
|
|
QK_readySet_.remove(m_prioCeiling);
|
|
|
|
QK_readySet_.insert(act->m_thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
QS_BEGIN_NOCRIT_(QS_QK_MUTEX_UNLOCK,
|
|
|
|
static_cast<void *>(0), static_cast<void *>(0))
|
|
|
|
QS_TIME_(); // timestamp
|
|
|
|
QS_2U8_(static_cast<uint8_t>(act->m_thread), // the start prio
|
|
|
|
static_cast<uint8_t>(m_prioCeiling));// curr ceiling
|
|
|
|
QS_END_NOCRIT_()
|
|
|
|
|
|
|
|
// find if some other AO has higher priority than the current
|
|
|
|
p = QK_schedPrio_();
|
|
|
|
if (p != static_cast<uint_fast8_t>(0)) {
|
|
|
|
QK_sched_(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// this AO is releasing a nested mutex lock
|
|
|
|
else {
|
|
|
|
--m_lockNest;
|
2012-08-14 18:00:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
QF_CRIT_EXIT_();
|
|
|
|
}
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
} // namespace QP
|
2013-10-10 20:01:51 -04:00
|
|
|
|