5.9.9-beta

This commit is contained in:
Quantum Leaps 2017-09-28 11:20:05 -04:00
parent 4116239a1f
commit 36b434c1a4
17 changed files with 433 additions and 328 deletions

View File

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "QP/C++"
PROJECT_NUMBER = "5.9.8"
PROJECT_NUMBER = "5.9.9"
PROJECT_BRIEF =
PROJECT_LOGO = images/header_logo_ql.png
OUTPUT_DIRECTORY =
@ -29,8 +29,8 @@ SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES += next{1}="<hr><b>Next:</b> @ref \1</p>"
ALIASES += description="@par <b>Description</b>"
ALIASES += hint="@par <b>Hint</b>@n"
ALIASES += usage="@par <b>Usage</b>@n"
ALIASES += hint="@par <b>Hint</b>"
ALIASES += usage="@par <b>Usage</b>"
ALIASES += reqdef{2}="<div class="vmargin20"></div>@anchor \1 <TABLE><TR ALIGN="left"><TH NOWRAP>\1</TH><TH WIDTH="100%">\2</TH></TR></TABLE>"
ALIASES += reqref{1}="@ref \1 \"\1\""
ALIASES += termdef{2}="@anchor term_\1 @par \2"

View File

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "QP/C++"
PROJECT_NUMBER = "5.9.8"
PROJECT_NUMBER = "5.9.9"
PROJECT_BRIEF =
PROJECT_LOGO = images/header_logo_ql.png
OUTPUT_DIRECTORY =
@ -29,8 +29,8 @@ SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES += next{1}="<hr><b>Next:</b> @ref \1</p>"
ALIASES += description="@par <b>Description</b>"
ALIASES += hint="@par <b>Hint</b>@n"
ALIASES += usage="@par <b>Usage</b>@n"
ALIASES += hint="@par <b>Hint</b>"
ALIASES += usage="@par <b>Usage</b>"
ALIASES += reqdef{2}="<div class="vmargin20"></div>@anchor \1 <TABLE><TR ALIGN="left"><TH NOWRAP>\1</TH><TH WIDTH="100%">\2</TH></TR></TABLE>"
ALIASES += reqref{1}="@ref \1 \"\1\""
ALIASES += termdef{2}="@anchor term_\1 @par \2"

View File

@ -214,8 +214,6 @@ QXK is a small, preemptive, priority-based, dual-mode **blocking** kernel that e
- QXThread class
- QXThread::QXThread()
- QXThread::start()
- %QXThread:: POST()
- %QXThread:: POST_X()
- QXThread::delay()
- QXThread::delayCancel()
- QXThread::queueGet()
@ -242,7 +240,8 @@ QXK is a small, preemptive, priority-based, dual-mode **blocking** kernel that e
<div class="separate"></div>
@subsection api_qxk_queue Message Queues
- QXThread::postX() - posting messages to blocking threads
- %QXThread:: POST()
- %QXThread:: POST_X()
- QXThread::queueGet() - waiting (blocking) on message queue

View File

@ -1,7 +1,7 @@
@echo off
:: ==========================================================================
:: Product: QP/C++ script for generating Doxygen documentation
:: Last Updated for Version: 5.9.8
:: Last Updated for Version: 5.9.9
:: Date of the Last Update: 2017-09-15
::
:: Q u a n t u m L e a P s
@ -38,7 +38,7 @@ echo usage:
echo make
echo make -CHM
set VERSION=5.9.8
set VERSION=5.9.9
:: Generate Resource Standard Metrics for QP/C++ .............................
set DOXHOME="C:\tools\doxygen\bin"

View File

@ -1,7 +1,7 @@
/** @page metrics Code Metrics
@code
Standard Code Metrics for QP/C++ 5.9.8
Standard Code Metrics for QP/C++ 5.9.9
Resource Standard Metrics (TM) for C, C++, C# and Java
Version 7.75 - mSquaredTechnologies.com
@ -9,7 +9,7 @@
License Type: Windows Single User License
Licensed To : Quantum Leaps, LLC
License No. : WS2975 License Date: Dec 15, 2013
Build Date : Sep 2 2009 Run Date: Sep 24, 2017
Build Date : Sep 2 2009 Run Date: Sep 27, 2017
(C)1996-2009 M Squared Technologies LLC
________________________________________________________________________
@ -709,7 +709,7 @@
~~ Total File Summary ~~
LOC 70 eLOC 64 lLOC 38 Comment 115 Lines 212
LOC 71 eLOC 65 lLOC 39 Comment 115 Lines 213
------------------------------------------------------------------------
~~ File Functional Summary ~~
@ -1974,62 +1974,67 @@
Parameters: (uint_fast8_t ceiling)
Cyclomatic Complexity Vg Detail
Function Base : 1
Logical and ( && ) : 2
Complexity Param 1 Return 1 Cyclo Vg 3 Total 5
LOC 12 eLOC 11 lLOC 7 Comment 20 Lines 22
Conditional if / else if: 1
Logical or ( || ) : 1
Logical and ( && ) : 1
Complexity Param 1 Return 1 Cyclo Vg 4 Total 6
LOC 16 eLOC 14 lLOC 8 Comment 30 Lines 24
Function: QP::QXMutex::lock
Parameters: (uint_fast16_t const nTicks)
Cyclomatic Complexity Vg Detail
Function Base : 1
Conditional if / else if: 2
Conditional if / else if: 4
Logical or ( || ) : 1
Logical and ( && ) : 4
Complexity Param 1 Return 1 Cyclo Vg 7 Total 9
LOC 45 eLOC 41 lLOC 27 Comment 50 Lines 78
Complexity Param 1 Return 1 Cyclo Vg 10 Total 12
LOC 54 eLOC 48 lLOC 29 Comment 51 Lines 91
Function: QP::QXMutex::tryLock
Parameters: (void)
Cyclomatic Complexity Vg Detail
Function Base : 1
Conditional if / else if: 3
Logical and ( && ) : 4
Complexity Param 0 Return 1 Cyclo Vg 8 Total 9
LOC 39 eLOC 34 lLOC 19 Comment 41 Lines 59
Conditional if / else if: 5
Logical or ( || ) : 1
Logical and ( && ) : 5
Complexity Param 0 Return 1 Cyclo Vg 12 Total 13
LOC 46 eLOC 39 lLOC 20 Comment 42 Lines 70
Function: QP::QXMutex::unlock
Parameters: (void)
Cyclomatic Complexity Vg Detail
Function Base : 1
Conditional if / else if: 4
Conditional if / else if: 7
Logical or ( || ) : 2
Logical and ( && ) : 8
Complexity Param 0 Return 1 Cyclo Vg 13 Total 14
LOC 56 eLOC 49 lLOC 25 Comment 57 Lines 95
Complexity Param 0 Return 1 Cyclo Vg 18 Total 19
LOC 67 eLOC 57 lLOC 27 Comment 61 Lines 112
------------------------------------------------------------------------
~~ Total File Summary ~~
LOC 167 eLOC 149 lLOC 78 Comment 217 Lines 388
LOC 198 eLOC 172 lLOC 84 Comment 233 Lines 440
------------------------------------------------------------------------
~~ File Functional Summary ~~
File Function Count....: 4
Total Function LOC.....: 152 Total Function Pts LOC : 3.2
Total Function eLOC....: 135 Total Function Pts eLOC: 2.8
Total Function lLOC....: 78 Total Function Pts lLOC: 1.5
Total Function LOC.....: 183 Total Function Pts LOC : 3.7
Total Function eLOC....: 158 Total Function Pts eLOC: 3.2
Total Function lLOC....: 84 Total Function Pts lLOC: 1.6
Total Function Params .: 2 Total Function Return .: 4
Total Cyclo Complexity : 31 Total Function Complex.: 37
Total Cyclo Complexity : 44 Total Function Complex.: 50
------ ----- ----- ------ ------ -----
Max Function LOC ......: 56 Average Function LOC ..: 38.00
Max Function eLOC .....: 49 Average Function eLOC .: 33.75
Max Function lLOC .....: 27 Average Function lLOC .: 19.50
Max Function LOC ......: 67 Average Function LOC ..: 45.75
Max Function eLOC .....: 57 Average Function eLOC .: 39.50
Max Function lLOC .....: 29 Average Function lLOC .: 21.00
------ ----- ----- ------ ------ -----
Max Function Parameters: 1 Avg Function Parameters: 0.50
Max Function Returns ..: 1 Avg Function Returns ..: 1.00
Max Interface Complex. : 2 Avg Interface Complex. : 1.50
Max Cyclomatic Complex.: 13 Avg Cyclomatic Complex.: 7.75
Max Total Complexity ..: 14 Avg Total Complexity ..: 9.25
Max Cyclomatic Complex.: 18 Avg Cyclomatic Complex.: 11.00
Max Total Complexity ..: 19 Avg Total Complexity ..: 12.50
________________________________________________________________________
End of File: ..\src\qxk\qxk_mutex.cpp
@ -2231,9 +2236,9 @@
~~ Total Project Summary ~~
LOC 4880 eLOC 4322 lLOC 1887 Comment 6443 Lines 11601
LOC 4912 eLOC 4346 lLOC 1894 Comment 6459 Lines 11654
Average per File, metric/37 files
LOC 131 eLOC 116 lLOC 51 Comment 174 Lines 313
LOC 132 eLOC 117 lLOC 51 Comment 174 Lines 314
------------------------------------------------------------------------
@ -3028,23 +3033,23 @@
Function: QP::QXMutex::init
Parameters: (uint_fast8_t ceiling)
Complexity Param 1 Return 1 Cyclo Vg 3 Total 5
LOC 12 eLOC 11 lLOC 7 Comment 20 Lines 22
Complexity Param 1 Return 1 Cyclo Vg 4 Total 6
LOC 16 eLOC 14 lLOC 8 Comment 30 Lines 24
Function: QP::QXMutex::lock
Parameters: (uint_fast16_t const nTicks)
Complexity Param 1 Return 1 Cyclo Vg 7 Total 9
LOC 45 eLOC 41 lLOC 27 Comment 50 Lines 78
Complexity Param 1 Return 1 Cyclo Vg 10 Total 12
LOC 54 eLOC 48 lLOC 29 Comment 51 Lines 91
Function: QP::QXMutex::tryLock
Parameters: (void)
Complexity Param 0 Return 1 Cyclo Vg 8 Total 9
LOC 39 eLOC 34 lLOC 19 Comment 41 Lines 59
Complexity Param 0 Return 1 Cyclo Vg 12 Total 13
LOC 46 eLOC 39 lLOC 20 Comment 42 Lines 70
Function: QP::QXMutex::unlock
Parameters: (void)
Complexity Param 0 Return 1 Cyclo Vg 13 Total 14
LOC 56 eLOC 49 lLOC 25 Comment 57 Lines 95
Complexity Param 0 Return 1 Cyclo Vg 18 Total 19
LOC 67 eLOC 57 lLOC 27 Comment 61 Lines 112
Function: QP::QXSemaphore::init
Parameters: (uint_fast16_t const count, uint_fast16_t const max_count)
@ -3134,30 +3139,30 @@
LOC 14 eLOC 11 lLOC 7 Comment 2 Lines 16
Total: Functions
LOC 2752 eLOC 2293 lLOC 1367 InCmp 340 CycloCmp 465
Function Points FP(LOC) 46.9 FP(eLOC) 39.7 FP(lLOC) 23.9
LOC 2783 eLOC 2316 lLOC 1373 InCmp 340 CycloCmp 478
Function Points FP(LOC) 47.5 FP(eLOC) 40.1 FP(lLOC) 24.0
------------------------------------------------------------------------
~~ Project Functional Analysis ~~
Total Functions .......: 175 Total Physical Lines ..: 3804
Total LOC .............: 2752 Total Function Pts LOC : 46.9
Total eLOC ............: 2293 Total Function Pts eLOC: 39.7
Total lLOC.............: 1367 Total Function Pts lLOC: 23.9
Total Cyclomatic Comp. : 465 Total Interface Comp. .: 340
Total Functions .......: 175 Total Physical Lines ..: 3847
Total LOC .............: 2783 Total Function Pts LOC : 47.5
Total eLOC ............: 2316 Total Function Pts eLOC: 40.1
Total lLOC.............: 1373 Total Function Pts lLOC: 24.0
Total Cyclomatic Comp. : 478 Total Interface Comp. .: 340
Total Parameters ......: 165 Total Return Points ...: 175
Total Comment Lines ...: 2697 Total Blank Lines .....: 514
Total Comment Lines ...: 2713 Total Blank Lines .....: 519
------ ----- ----- ------ ------ -----
Avg Physical Lines ....: 21.74
Avg LOC ...............: 15.73 Avg eLOC ..............: 13.10
Avg lLOC ..............: 7.81 Avg Cyclomatic Comp. ..: 2.66
Avg Physical Lines ....: 21.98
Avg LOC ...............: 15.90 Avg eLOC ..............: 13.23
Avg lLOC ..............: 7.85 Avg Cyclomatic Comp. ..: 2.73
Avg Interface Comp. ...: 1.94 Avg Parameters ........: 0.94
Avg Return Points .....: 1.00 Avg Comment Lines .....: 15.41
Avg Return Points .....: 1.00 Avg Comment Lines .....: 15.50
------ ----- ----- ------ ------ -----
Max LOC ...............: 117
Max eLOC ..............: 100 Max lLOC ..............: 61
Max Cyclomatic Comp. ..: 17 Max Interface Comp. ...: 7
Max Cyclomatic Comp. ..: 18 Max Interface Comp. ...: 7
Max Parameters ........: 6 Max Return Points .....: 1
Max Comment Lines .....: 111 Max Total Lines .......: 191
------ ----- ----- ------ ------ -----

View File

@ -1,7 +1,7 @@
///***************************************************************************
// Product: DPP example, EFM32-SLSTK3401A board, preemptive QXK kernel
// Last Updated for Version: 5.9.7
// Date of the Last Update: 2017-08-19
// Last Updated for Version: 5.9.9
// Date of the Last Update: 2017-09-27
//
// Q u a n t u m L e a P s
// ---------------------------
@ -436,18 +436,10 @@ bool QS::onStartup(void const *arg) {
DPP::QS_tickTime_ = DPP::QS_tickPeriod_; // to start the timestamp at zero
// setup the QS filters...
QS_FILTER_ON(QS_QEP_STATE_ENTRY);
QS_FILTER_ON(QS_QEP_STATE_EXIT);
QS_FILTER_ON(QS_QEP_STATE_INIT);
QS_FILTER_ON(QS_QEP_INIT_TRAN);
QS_FILTER_ON(QS_QEP_INTERN_TRAN);
QS_FILTER_ON(QS_QEP_TRAN);
QS_FILTER_ON(QS_QEP_IGNORED);
QS_FILTER_ON(QS_QEP_DISPATCH);
QS_FILTER_ON(QS_QEP_UNHANDLED);
QS_FILTER_ON(DPP::PHILO_STAT);
QS_FILTER_ON(DPP::COMMAND_STAT);
QS_FILTER_ON(QS_SM_RECORDS); // state machine records
QS_FILTER_ON(QS_UA_RECORDS); // all usedr records
//QS_FILTER_ON(QS_MUTEX_LOCK);
//QS_FILTER_ON(QS_MUTEX_UNLOCK);
return true; // return success
}

View File

@ -84,7 +84,7 @@
</option>
<option>
<name>OCDynDriverList</name>
<state>ARMSIM_ID</state>
<state>JLINK_ID</state>
</option>
<option>
<name>OCLastSavedByProductVersion</name>
@ -818,12 +818,12 @@
</option>
<option>
<name>CCJLinkInterfaceRadio</name>
<state>0</state>
<state>1</state>
</option>
<option>
<name>CCJLinkResetList</name>
<version>6</version>
<state>5</state>
<state>7</state>
</option>
<option>
<name>CCJLinkInterfaceCmdLine</name>
@ -888,7 +888,7 @@
</option>
<option>
<name>CCCpuClockEdit</name>
<state></state>
<state>40.0</state>
</option>
<option>
<name>CCSwoClockAuto</name>

View File

@ -1,7 +1,7 @@
//****************************************************************************
// DPP example for QXK
// Last updated for version 5.9.7
// Last updated on 2017-08-20
// Last updated for version 5.9.9
// Last updated on 2017-09-27
//
// Q u a n t u m L e a P s
// ---------------------------
@ -108,10 +108,12 @@ static void Thread2_run(QP::QXThread * const me) {
1U); // max_count==1 (binary semaphore)
// initialize the mutex before using it
// NOTE: Here the semaphore is initialized in the highest-priority thread
// that uses it. Alternatively, the semaphore can be initialized
// NOTE: Here the mutex is initialized in the highest-priority thread
// that uses it. Alternatively, the mutex can be initialized
// before any thread runs.
l_mutex.init(N_PHILO + 6U);
//l_mutex.init(0U); // priority-ceiling NOT used
l_mutex.init(N_PHILO + 6U); // priority-ceiling protocol used
me->m_thread = &l_tls2; // initialize the TLS for Thread2

View File

@ -1,7 +1,7 @@
//****************************************************************************
// DPP example for QXK
// Last updated for version 5.9.7
// Last updated on 2017-08-20
// Last updated for version 5.9.9
// Last updated on 2017-09-27
//
// Q u a n t u m L e a P s
// ---------------------------
@ -108,10 +108,12 @@ static void Thread2_run(QP::QXThread * const me) {
1U); // max_count==1 (binary semaphore)
// initialize the mutex before using it
// NOTE: Here the semaphore is initialized in the highest-priority thread
// that uses it. Alternatively, the semaphore can be initialized
// NOTE: Here the mutex is initialized in the highest-priority thread
// that uses it. Alternatively, the mutex can be initialized
// before any thread runs.
l_mutex.init(N_PHILO + 6U);
//l_mutex.init(0U); // priority-ceiling NOT used
l_mutex.init(N_PHILO + 6U); // priority-ceiling protocol used
me->m_thread = &l_tls2; // initialize the TLS for Thread2

View File

@ -3,8 +3,8 @@
/// @ingroup qep
/// @cond
///***************************************************************************
/// Last updated for version 5.9.8
/// Last updated on 2017-09-15
/// Last updated for version 5.9.9
/// Last updated on 2017-09-27
///
/// Q u a n t u m L e a P s
/// ---------------------------
@ -43,15 +43,15 @@
//! The current QP version as a decimal constant XYZ, where X is a 1-digit
// major version number, Y is a 1-digit minor version number, and Z is
// a 1-digit release number.
#define QP_VERSION 598
#define QP_VERSION 599
//! The current QP version number string of the form X.Y.Z, where X is
// a 1-digit major version number, Y is a 1-digit minor version number,
// and Z is a 1-digit release number.
#define QP_VERSION_STR "5.9.8"
#define QP_VERSION_STR "5.9.9"
//! Tamperproof current QP release (5.9.8) and date (2017-09-15)
#define QP_RELEASE 0x9A206E79U
//! Tamperproof current QP release (5.9.9) and date (2017-09-29)
#define QP_RELEASE 0x9A1E4B98U
//****************************************************************************
#ifndef Q_SIGNAL_SIZE

View File

@ -3,8 +3,8 @@
/// @ingroup qxk
/// @cond
///***************************************************************************
/// Last updated for version 5.9.7
/// Last updated on 2017-08-20
/// Last updated for version 5.9.9
/// Last updated on 2017-09-27
///
/// Q u a n t u m L e a P s
/// ---------------------------
@ -156,8 +156,8 @@ public:
private:
QPSet m_waitSet; //!< set of extended threads waiting on this semaphore
uint_fast16_t m_count;
uint_fast16_t m_max_count;
uint16_t m_count;
uint16_t m_max_count;
};
//****************************************************************************
@ -202,8 +202,9 @@ public:
private:
QPSet m_waitSet; //!< set of extended-threads waiting on this mutex
uint_fast8_t m_ceiling;
uint_fast8_t m_lockNest;
uint8_t m_ceiling;
uint8_t m_lockNest;
uint8_t m_holderPrio;
};
} // namespace QP

View File

@ -4,8 +4,8 @@
/// @cond
///***************************************************************************
/// Product: QK/C++
/// Last updated for version 5.9.7
/// Last updated on 2017-08-19
/// Last updated for version 5.9.9
/// Last updated on 2017-09-27
///
/// Q u a n t u m L e a P s
/// ---------------------------
@ -56,16 +56,27 @@ namespace QP {
Q_DEFINE_THIS_MODULE("qxk_mutex")
//****************************************************************************/
//****************************************************************************
/// @description
/// Initialize the QXK priority ceiling mutex.
///
/// @param[in] ceiling ceiling priotity of the mutex
/// @param[in] ceiling the ceiling-priotity of this mutex or zero.
///
/// @note
/// The ceiling priority must be unused by any thread. The ceiling
/// priority must be higher than priority of any thread that uses the
/// protected resource.
/// `ceiling == 0` means that the priority-ceiling protocol shall __not__
/// be used by this mutex. Such mutex will __not__ change (boost) the
/// priority of the holding thread.
///
/// @note
/// `ceiling > 0` means that the priority-ceiling protocol shall be used
/// by this mutex. Such mutex __will__ boost the priority of the holding
/// thread to the `ceiling` level for as long as the thread holds this mutex.
///
/// @attention
/// When the priority-ceiling protocol is used (`ceiling > 0`), the
/// `ceiling` priority must be unused by any other thread or mutex.
/// Also, the `ceiling` priority must be higher than priority of any thread
/// that uses this mutex.
///
/// @usage
/// @include qxk_mux.cpp
@ -75,26 +86,27 @@ void QXMutex::init(uint_fast8_t ceiling) {
QF_CRIT_ENTRY_();
/// @pre the celiling priority of the mutex must:
/// - not be zero;
/// - cannot exceed the maximum #QF_MAX_ACTIVE;
/// - the ceiling priority of the mutex must not be already in use;
/// (QF requires priority to be **unique**).
Q_REQUIRE_ID(100, (static_cast<uint_fast8_t>(0) < ceiling)
&& (ceiling <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
&& (QF::active_[ceiling] == static_cast<QActive *>(0)));
Q_REQUIRE_ID(100,
(ceiling <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
&& ((ceiling == static_cast<uint_fast8_t>(0))
|| (QF::active_[ceiling] == static_cast<QActive *>(0))));
m_ceiling = ceiling;
m_lockNest = static_cast<uint_fast8_t>(0);
m_ceiling = static_cast<uint8_t>(ceiling);
m_lockNest = static_cast<uint8_t>(0);
m_holderPrio = static_cast<uint8_t>(0);
QF::bzero(&m_waitSet, static_cast<uint_fast16_t>(sizeof(m_waitSet)));
// reserve the ceiling priority level for this mutex
QF::active_[ceiling] = reinterpret_cast<QActive *>(this);
if (ceiling != static_cast<uint_fast8_t>(0)) {
// reserve the ceiling priority level for this mutex
QF::active_[ceiling] = reinterpret_cast<QActive *>(this);
}
QF_CRIT_EXIT_();
}
//****************************************************************************
///
/// @description
/// Lock the QXK priority ceiling mutex QP::QXMutex.
///
@ -107,7 +119,7 @@ void QXMutex::init(uint_fast8_t ceiling) {
///
/// @note
/// The mutex locks are allowed to nest, meaning that the same extended thread
/// can lock the same mutex multiple times (<= 225). However, each call to
/// can lock the same mutex multiple times (< 255). However, each call to
/// QXMutex::lock() must be ballanced by the matching call to
/// QXMutex::unlock().
///
@ -115,67 +127,78 @@ void QXMutex::init(uint_fast8_t ceiling) {
/// @include qxk_mux.cpp
///
bool QXMutex::lock(uint_fast16_t const nTicks) {
QXThread *thr;
QXThread *curr;
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
thr = static_cast<QXThread *>(QXK_attr_.curr);
curr = static_cast<QXThread *>(QXK_attr_.curr);
/// @pre this function must:
/// - NOT be called from an ISR;
/// - be called from an extended thread;
/// - the thread priority must be below the ceiling of the mutex;
/// - the ceiling priority must not be used; or if used
/// - the thread priority must be below the ceiling of the mutex;
/// - the thread must NOT be holding a scheduler lock;
/// - the thread must NOT be already blocked on any object.
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
&& (thr != static_cast<QXThread *>(0)) /* thr must be extended */
&& (thr->m_startPrio < m_ceiling) /* prio below the ceiling */
&& (QXK_attr_.lockHolder != thr->m_prio) /* not holding a lock */
&& (thr->m_temp.obj == static_cast<QMState *>(0))); // not blocked
&& (curr != static_cast<QXThread *>(0)) /* curr must be extended */
&& ((m_ceiling == static_cast<uint8_t>(0)) /* below ceiling */
|| (curr->m_startPrio < static_cast<uint_fast8_t>(m_ceiling)))
&& (QXK_attr_.lockHolder != curr->m_prio) /* not holding a lock */
&& (curr->m_temp.obj == static_cast<QMState *>(0))); // not blocked
// is the mutex available?
if (m_lockNest == static_cast<uint_fast8_t>(0)) {
m_lockNest = static_cast<uint_fast8_t>(1);
if (m_lockNest == static_cast<uint8_t>(0)) {
m_lockNest = static_cast<uint8_t>(1);
// the priority slot must be set to this mutex */
Q_ASSERT_ID(210,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the priority slot must be set to this mutex */
Q_ASSERT_ID(210,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
// switch the priority of this thread to the mutex ceiling
thr->m_prio = m_ceiling;
QF::active_[m_ceiling] = thr;
// switch the priority of this thread to the mutex ceiling
curr->m_prio = static_cast<uint_fast8_t>(m_ceiling);
QF::active_[m_ceiling] = curr;
QXK_attr_.readySet.remove(thr->m_startPrio);
QXK_attr_.readySet.insert(thr->m_prio);
QXK_attr_.readySet.remove(curr->m_startPrio);
QXK_attr_.readySet.insert(curr->m_prio);
}
m_holderPrio = static_cast<uint8_t>(curr->m_startPrio);
QS_BEGIN_NOCRIT_(QS_MUTEX_LOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(thr->m_startPrio), /* start prio */
static_cast<uint8_t>(thr->m_prio)); // current ceiling
QS_2U8_(static_cast<uint8_t>(curr->m_startPrio), /* start prio */
m_ceiling); // current ceiling
QS_END_NOCRIT_()
}
// is the mutex locked by this thread already (nested locking)?
else if (QF::active_[m_ceiling] == thr) {
else if (static_cast<uint_fast8_t>(m_holderPrio) == curr->m_startPrio) {
// the nesting level must not exceed 0xFF
Q_ASSERT_ID(220, m_lockNest < static_cast<uint_fast8_t>(0xFF));
Q_ASSERT_ID(220, m_lockNest < static_cast<uint8_t>(0xFF));
++m_lockNest;
}
else { // the mutex is alredy locked by a different thread
// the prio slot must be claimed by the thread holding the mutex
Q_ASSERT_ID(230, QF::active_[m_ceiling] != static_cast<QActive *>(0));
// the ceiling holder priority must be valid
Q_ASSERT_ID(230, m_holderPrio != static_cast<uint8_t>(0));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the prio slot must be claimed by the thread holding the mutex
Q_ASSERT_ID(240,
QF::active_[m_ceiling] != static_cast<QActive *>(0));
}
// remove this thr prio from the ready set (block)
// and insert to the waiting set on this mutex
QXK_attr_.readySet.remove(thr->m_prio);
m_waitSet.insert(thr->m_prio);
QXK_attr_.readySet.remove(curr->m_prio);
m_waitSet.insert(curr->m_prio);
// store the blocking object (this mutex)
thr->m_temp.obj = reinterpret_cast<QMState *>(this);
thr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
curr->m_temp.obj = reinterpret_cast<QMState *>(this);
curr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
// schedule the next thread if multitasking started
(void)QXK_sched_();
@ -183,18 +206,19 @@ bool QXMutex::lock(uint_fast16_t const nTicks) {
QF_CRIT_EXIT_NOP(); // BLOCK here
QF_CRIT_ENTRY_();
// the blocking object must be this mutex
Q_ASSERT_ID(240, thr->m_temp.obj == reinterpret_cast<QMState *>(this));
thr->m_temp.obj = static_cast<QMState *>(0); // clear
// the blocking object of the current thread must be this mutex
Q_ASSERT_ID(240,
curr->m_temp.obj == reinterpret_cast<QMState *>(this));
curr->m_temp.obj = static_cast<QMState *>(0); // clear blocking obj.
}
QF_CRIT_EXIT_();
// signal of non-zero means that the time event has not expired
return thr->m_timeEvt.sig != static_cast<QSignal>(0);
return curr->m_timeEvt.sig != static_cast<QSignal>(0);
}
//****************************************************************************
///
/// @description
/// Try to lock the QXK priority ceiling mutex QP::QXMutex.
///
@ -208,8 +232,8 @@ bool QXMutex::lock(uint_fast16_t const nTicks) {
///
/// @note
/// The mutex locks are allowed to nest, meaning that the same extended thread
/// can lock the same mutex multiple times (<= 225). However, each successful
/// call to QXMutex_tryLock() must be ballanced by the matching call to
/// can lock the same mutex multiple times (< 255). However, each successful
/// call to QXMutex::tryLock() must be ballanced by the matching call to
/// QXMutex::unlock().
///
bool QXMutex::tryLock(void) {
@ -226,45 +250,56 @@ bool QXMutex::tryLock(void) {
/// - NOT be called from an ISR;
/// - the QXK kernel must be running;
/// - the calling thread must be valid;
/// - the thread priority must be below the ceiling of the mutex;
/// - the ceiling must be not used; or
/// - the thread priority must be below the ceiling of the mutex;
/// - the thread must NOT be holding a scheduler lock;
Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
&& (QXK_attr_.lockPrio <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
&& (curr != static_cast<QActive *>(0)) /* curr thread must be valid */
&& (curr->m_startPrio < m_ceiling) /* prio below the ceiling */
&& ((m_ceiling == static_cast<uint8_t>(0)) /* below ceiling */
|| (curr->m_startPrio < static_cast<uint_fast8_t>(m_ceiling)))
&& (curr->m_prio != QXK_attr_.lockHolder)); // not holding a lock
// is the mutex available?
if (m_lockNest == static_cast<uint_fast8_t>(0)) {
m_lockNest = static_cast<uint_fast8_t>(1);
if (m_lockNest == static_cast<uint8_t>(0)) {
m_lockNest = static_cast<uint8_t>(1);
// the priority slot must be set to this mutex
Q_ASSERT_ID(310,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the priority slot must be set to this mutex
Q_ASSERT_ID(310,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
// switch the priority of this thread to the mutex ceiling
curr->m_prio = m_ceiling;
QF::active_[m_ceiling] = curr;
// switch the priority of this thread to the mutex ceiling
curr->m_prio = static_cast<uint_fast8_t>(m_ceiling);
QF::active_[m_ceiling] = curr;
QXK_attr_.readySet.remove(curr->m_startPrio);
QXK_attr_.readySet.insert(curr->m_prio);
QXK_attr_.readySet.remove(curr->m_startPrio);
QXK_attr_.readySet.insert(curr->m_prio);
}
// make curr thread the new mutex holder
m_holderPrio = static_cast<uint8_t>(curr->m_startPrio);
QS_BEGIN_NOCRIT_(QS_MUTEX_LOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(curr->m_startPrio), /* start prio */
static_cast<uint8_t>(curr->m_prio)); // current ceiling
m_ceiling); // current ceiling
QS_END_NOCRIT_()
}
// is the mutex locked by this thread already (nested locking)?
else if (QF::active_[m_ceiling] == curr) {
// is the mutex held by this thread already (nested locking)?
else if (static_cast<uint_fast8_t>(m_holderPrio) == curr->m_startPrio) {
// the nesting level must not exceed 0xFF
Q_ASSERT_ID(320, m_lockNest < static_cast<uint_fast8_t>(0xFF));
Q_ASSERT_ID(320, m_lockNest < static_cast<uint8_t>(0xFF));
++m_lockNest;
}
else { // the mutex is alredy locked by a different thread
// the prio slot must be claimed by the thread holding the mutex
Q_ASSERT_ID(330, QF::active_[m_ceiling] != static_cast<QActive *>(0));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the prio slot must be claimed by the mutex holder
Q_ASSERT_ID(330, (m_holderPrio != static_cast<uint8_t>(0))
&& (QF::active_[m_ceiling] != QF::active_[m_holderPrio]));
}
curr = static_cast<QActive *>(0); // means that mutex is NOT available
}
QF_CRIT_EXIT_();
@ -282,8 +317,8 @@ bool QXMutex::tryLock(void) {
///
/// @note
/// The mutex locks are allowed to nest, meaning that the same extended thread
/// can lock the same mutex multiple times (<= 225). However, each call to
/// QXMutex::lock() or a _successfull_ call to QXMutex_tryLock() must be
/// can lock the same mutex multiple times (< 255). However, each call to
/// QXMutex::lock() or a _successfull_ call to QXMutex::tryLock() must be
/// ballanced by the matching call to QXMutex::unlock().
///
/// @usage
@ -303,29 +338,36 @@ void QXMutex::unlock(void) {
/// - NOT be called from an ISR;
/// - the calling thread must be valid;
/// - the mutex must be held by this thread;
/// - the holding thread must have priority equal to the mutex ceiling;
/// - the ceiling must not be used or
/// - the current thread must have priority equal to the mutex ceiling;
/// - the mutex must be already locked at least once.
Q_REQUIRE_ID(400, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
&& (curr != static_cast<QActive *>(0)) /* curr must be valid */
&& (curr == QF::active_[m_ceiling]) /* held by this thr */
&& (curr->m_prio == m_ceiling) /* thr prio at the ceiling */
&& (m_lockNest > static_cast<uint_fast8_t>(0)));//locked at least once
&& (curr->m_startPrio == static_cast<uint_fast8_t>(m_holderPrio))
&& ((m_ceiling == static_cast<uint8_t>(0)) /* curr at ceiling prio */
|| (curr->m_prio == static_cast<uint_fast8_t>(m_ceiling)))
&& (m_lockNest > static_cast<uint8_t>(0))); // locked at least once
// is this the last nesting level?
if (m_lockNest == static_cast<uint_fast8_t>(1)) {
if (m_lockNest == static_cast<uint8_t>(1)) {
// restore the holding thread's priority to the original
curr->m_prio = curr->m_startPrio;
if (m_ceiling != static_cast<uint8_t>(0)) {
// restore the holding thread's priority to the original
curr->m_prio = curr->m_startPrio;
// remove the boosted priority and insert the original priority
QXK_attr_.readySet.remove(m_ceiling);
QXK_attr_.readySet.insert(curr->m_startPrio);
// remove the boosted priority and insert the original priority
QXK_attr_.readySet.remove(static_cast<uint_fast8_t>(m_ceiling));
QXK_attr_.readySet.insert(curr->m_startPrio);
}
// the mutex no longer held by a thread
m_holderPrio = static_cast<uint8_t>(0);
QS_BEGIN_NOCRIT_(QS_MUTEX_UNLOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(curr->m_startPrio), /* start prio */
static_cast<uint8_t>(m_ceiling)); // the mutex ceiling
m_ceiling); // the mutex ceiling
QS_END_NOCRIT_()
// are any other threads waiting for this mutex?
@ -336,12 +378,15 @@ void QXMutex::unlock(void) {
QXThread *thr = static_cast<QXThread *>(QF::active_[p]);
// the waiting thread must:
// (1) have priority below the ceiling
// (1) the ceiling must not be used; or if used
// the thread must have priority below the ceiling
// (2) be extended
// (3) not be redy to run
// (4) have still the start priority
// (5) be blocked on this mutex
Q_ASSERT_ID(410, (p < m_ceiling)
Q_ASSERT_ID(410,
((m_ceiling == static_cast<uint8_t>(0)) /* below ceiling */
|| (p < static_cast<uint_fast8_t>(m_ceiling)))
&& (thr != static_cast<QXThread *>(0)) /* extended thread */
&& (!QXK_attr_.readySet.hasElement(p))
&& (thr->m_prio == thr->m_startPrio)
@ -353,25 +398,32 @@ void QXMutex::unlock(void) {
// this thread is no longer waiting for the mutex
m_waitSet.remove(p);
// switch the priority of this thread to the mutex ceiling
thr->m_prio = m_ceiling;
QF::active_[m_ceiling] = thr;
if (m_ceiling != static_cast<uint8_t>(0)) {
// switch the priority of this thread to the mutex ceiling
thr->m_prio = static_cast<uint_fast8_t>(m_ceiling);
QF::active_[m_ceiling] = thr;
}
// make the thread ready to run (at the ceiling prio)
// make thr the new mutex holder
m_holderPrio = static_cast<uint8_t>(thr->m_startPrio);
// make the thread ready to run
QXK_attr_.readySet.insert(thr->m_prio);
QS_BEGIN_NOCRIT_(QS_MUTEX_LOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(thr->m_startPrio),/*start prio*/
static_cast<uint8_t>(thr->m_prio)); // ceiling prio
m_ceiling); // ceiling prio
QS_END_NOCRIT_()
}
else { // no threads are waiting for this mutex
m_lockNest = static_cast<uint_fast8_t>(0);
m_lockNest = static_cast<uint8_t>(0);
// put the mutex at the priority ceiling slot
QF::active_[m_ceiling] = reinterpret_cast<QActive *>(this);
if (m_ceiling != static_cast<uint8_t>(0)) {
// put the mutex at the priority ceiling slot
QF::active_[m_ceiling] = reinterpret_cast<QActive *>(this);
}
}
// schedule the next thread if multitasking started

View File

@ -3,8 +3,8 @@
/// @ingroup qxk
/// @cond
////**************************************************************************
/// Last updated for version 5.9.7
/// Last updated on 2017-08-20
/// Last updated for version 5.9.9
/// Last updated on 2017-09-27
///
/// Q u a n t u m L e a P s
/// ---------------------------
@ -79,8 +79,8 @@ void QXSemaphore::init(uint_fast16_t const count,
Q_REQUIRE_ID(100, max_count > static_cast<uint_fast16_t>(0));
m_waitSet.setEmpty();
m_count = count;
m_max_count = max_count;
m_count = static_cast<uint16_t>(count);
m_max_count = static_cast<uint16_t>(max_count);
}
//****************************************************************************
@ -108,7 +108,7 @@ bool QXSemaphore::wait(uint_fast16_t const nTicks) {
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
QXThread *thr = static_cast<QXThread *>(QXK_attr_.curr);
QXThread *curr = static_cast<QXThread *>(QXK_attr_.curr);
/// @pre this function must:
/// (1) NOT be called from an ISR; (2) be called from an extended thread;
@ -116,34 +116,34 @@ bool QXSemaphore::wait(uint_fast16_t const nTicks) {
/// (4) the thread must NOT be already blocked on any object.
///
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
&& (thr != static_cast<QXThread *>(0)) /* current must be extended */
&& (curr != static_cast<QXThread *>(0)) /* curr must be extended */
&& (QXK_attr_.lockPrio == static_cast<uint_fast8_t>(0)) /* no lock */
&& (thr->m_temp.obj == static_cast<QMState *>(0))); // !blocked
&& (curr->m_temp.obj == static_cast<QMState *>(0))); // not blocked
if (m_count > static_cast<uint_fast16_t>(0)) {
if (m_count > static_cast<uint16_t>(0)) {
--m_count;
thr->m_timeEvt.sig = static_cast<QSignal>(QXK_SEMA_SIG); // non-zero
curr->m_timeEvt.sig = static_cast<QSignal>(QXK_SEMA_SIG); // non-zero
}
else {
// remember the blocking object
thr->m_temp.obj = reinterpret_cast<QMState const *>(this);
thr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
m_waitSet.insert(thr->m_prio);
QXK_attr_.readySet.remove(thr->m_prio);
curr->m_temp.obj = reinterpret_cast<QMState const *>(this);
curr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
m_waitSet.insert(curr->m_prio);
QXK_attr_.readySet.remove(curr->m_prio);
(void)QXK_sched_();
QF_CRIT_EXIT_();
QF_CRIT_EXIT_NOP(); // BLOCK here
QF_CRIT_ENTRY_();
// the blocking object must be this semaphore
Q_ASSERT_ID(210, thr->m_temp.obj
Q_ASSERT_ID(210, curr->m_temp.obj
== reinterpret_cast<QMState const *>(this));
thr->m_temp.obj = static_cast<QMState *>(0); // clear
curr->m_temp.obj = static_cast<QMState *>(0); // clear
}
QF_CRIT_EXIT_();
// signal of non-zero means that the time event has not expired
return (thr->m_timeEvt.sig != static_cast<QSignal>(0));
return (curr->m_timeEvt.sig != static_cast<QSignal>(0));
}
//****************************************************************************
@ -164,11 +164,11 @@ bool QXSemaphore::tryWait(void) {
QF_CRIT_STAT_
/// @pre the semaphore must be initialized
Q_REQUIRE_ID(300, (m_max_count > static_cast<uint_fast16_t>(0)));
Q_REQUIRE_ID(300, (m_max_count > static_cast<uint16_t>(0)));
QF_CRIT_ENTRY_();
// is the semaphore available?
if (m_count > static_cast<uint_fast16_t>(0)) {
if (m_count > static_cast<uint16_t>(0)) {
--m_count;
isAvailable = true;
}
@ -202,7 +202,7 @@ bool QXSemaphore::signal(void) {
QF_CRIT_STAT_
/// @pre the semaphore must be initialized
Q_REQUIRE_ID(400, (m_max_count > (uint_fast16_t)0));
Q_REQUIRE_ID(400, m_max_count > static_cast<uint16_t>(0));
QF_CRIT_ENTRY_();
if (m_waitSet.notEmpty()) {
@ -215,7 +215,7 @@ bool QXSemaphore::signal(void) {
// the thread must be extended and the semaphore count must be zero
Q_ASSERT_ID(410, (thr != static_cast<QXThread *>(0)) /* registered */
&& (thr->m_osObject != static_cast<void *>(0)) /* extended */
&& (m_count == static_cast<uint_fast16_t>(0))); // not signaled
&& (m_count == static_cast<uint16_t>(0))); // not signaled
// disarm the internal time event
(void)thr->teDisarm_();

View File

@ -4,8 +4,8 @@
/// @cond
///***************************************************************************
/// Product: QK/C++
/// Last updated for version 5.9.7
/// Last updated on 2017-08-19
/// Last updated for version 5.9.9
/// Last updated on 2017-09-27
///
/// Q u a n t u m L e a P s
/// ---------------------------
@ -56,16 +56,27 @@ namespace QP {
Q_DEFINE_THIS_MODULE("qxk_mutex")
//****************************************************************************/
//****************************************************************************
/// @description
/// Initialize the QXK priority ceiling mutex.
///
/// @param[in] ceiling ceiling priotity of the mutex
/// @param[in] ceiling the ceiling-priotity of this mutex or zero.
///
/// @note
/// The ceiling priority must be unused by any thread. The ceiling
/// priority must be higher than priority of any thread that uses the
/// protected resource.
/// `ceiling == 0` means that the priority-ceiling protocol shall __not__
/// be used by this mutex. Such mutex will __not__ change (boost) the
/// priority of the holding thread.
///
/// @note
/// `ceiling > 0` means that the priority-ceiling protocol shall be used
/// by this mutex. Such mutex __will__ boost the priority of the holding
/// thread to the `ceiling` level for as long as the thread holds this mutex.
///
/// @attention
/// When the priority-ceiling protocol is used (`ceiling > 0`), the
/// `ceiling` priority must be unused by any other thread or mutex.
/// Also, the `ceiling` priority must be higher than priority of any thread
/// that uses this mutex.
///
/// @usage
/// @include qxk_mux.cpp
@ -75,26 +86,27 @@ void QXMutex::init(uint_fast8_t ceiling) {
QF_CRIT_ENTRY_();
/// @pre the celiling priority of the mutex must:
/// - not be zero;
/// - cannot exceed the maximum #QF_MAX_ACTIVE;
/// - the ceiling priority of the mutex must not be already in use;
/// (QF requires priority to be **unique**).
Q_REQUIRE_ID(100, (static_cast<uint_fast8_t>(0) < ceiling)
&& (ceiling <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
&& (QF::active_[ceiling] == static_cast<QActive *>(0)));
Q_REQUIRE_ID(100,
(ceiling <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
&& ((ceiling == static_cast<uint_fast8_t>(0))
|| (QF::active_[ceiling] == static_cast<QActive *>(0))));
m_ceiling = ceiling;
m_lockNest = static_cast<uint_fast8_t>(0);
m_ceiling = static_cast<uint8_t>(ceiling);
m_lockNest = static_cast<uint8_t>(0);
m_holderPrio = static_cast<uint8_t>(0);
QF::bzero(&m_waitSet, static_cast<uint_fast16_t>(sizeof(m_waitSet)));
// reserve the ceiling priority level for this mutex
QF::active_[ceiling] = reinterpret_cast<QActive *>(this);
if (ceiling != static_cast<uint_fast8_t>(0)) {
// reserve the ceiling priority level for this mutex
QF::active_[ceiling] = reinterpret_cast<QActive *>(this);
}
QF_CRIT_EXIT_();
}
//****************************************************************************
///
/// @description
/// Lock the QXK priority ceiling mutex QP::QXMutex.
///
@ -107,7 +119,7 @@ void QXMutex::init(uint_fast8_t ceiling) {
///
/// @note
/// The mutex locks are allowed to nest, meaning that the same extended thread
/// can lock the same mutex multiple times (<= 225). However, each call to
/// can lock the same mutex multiple times (< 255). However, each call to
/// QXMutex::lock() must be ballanced by the matching call to
/// QXMutex::unlock().
///
@ -115,67 +127,78 @@ void QXMutex::init(uint_fast8_t ceiling) {
/// @include qxk_mux.cpp
///
bool QXMutex::lock(uint_fast16_t const nTicks) {
QXThread *thr;
QXThread *curr;
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
thr = static_cast<QXThread *>(QXK_attr_.curr);
curr = static_cast<QXThread *>(QXK_attr_.curr);
/// @pre this function must:
/// - NOT be called from an ISR;
/// - be called from an extended thread;
/// - the thread priority must be below the ceiling of the mutex;
/// - the ceiling priority must not be used; or if used
/// - the thread priority must be below the ceiling of the mutex;
/// - the thread must NOT be holding a scheduler lock;
/// - the thread must NOT be already blocked on any object.
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
&& (thr != static_cast<QXThread *>(0)) /* thr must be extended */
&& (thr->m_startPrio < m_ceiling) /* prio below the ceiling */
&& (QXK_attr_.lockHolder != thr->m_prio) /* not holding a lock */
&& (thr->m_temp.obj == static_cast<QMState *>(0))); // not blocked
&& (curr != static_cast<QXThread *>(0)) /* curr must be extended */
&& ((m_ceiling == static_cast<uint8_t>(0)) /* below ceiling */
|| (curr->m_startPrio < static_cast<uint_fast8_t>(m_ceiling)))
&& (QXK_attr_.lockHolder != curr->m_prio) /* not holding a lock */
&& (curr->m_temp.obj == static_cast<QMState *>(0))); // not blocked
// is the mutex available?
if (m_lockNest == static_cast<uint_fast8_t>(0)) {
m_lockNest = static_cast<uint_fast8_t>(1);
if (m_lockNest == static_cast<uint8_t>(0)) {
m_lockNest = static_cast<uint8_t>(1);
// the priority slot must be set to this mutex */
Q_ASSERT_ID(210,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the priority slot must be set to this mutex */
Q_ASSERT_ID(210,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
// switch the priority of this thread to the mutex ceiling
thr->m_prio = m_ceiling;
QF::active_[m_ceiling] = thr;
// switch the priority of this thread to the mutex ceiling
curr->m_prio = static_cast<uint_fast8_t>(m_ceiling);
QF::active_[m_ceiling] = curr;
QXK_attr_.readySet.remove(thr->m_startPrio);
QXK_attr_.readySet.insert(thr->m_prio);
QXK_attr_.readySet.remove(curr->m_startPrio);
QXK_attr_.readySet.insert(curr->m_prio);
}
m_holderPrio = static_cast<uint8_t>(curr->m_startPrio);
QS_BEGIN_NOCRIT_(QS_MUTEX_LOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(thr->m_startPrio), /* start prio */
static_cast<uint8_t>(thr->m_prio)); // current ceiling
QS_2U8_(static_cast<uint8_t>(curr->m_startPrio), /* start prio */
m_ceiling); // current ceiling
QS_END_NOCRIT_()
}
// is the mutex locked by this thread already (nested locking)?
else if (QF::active_[m_ceiling] == thr) {
else if (static_cast<uint_fast8_t>(m_holderPrio) == curr->m_startPrio) {
// the nesting level must not exceed 0xFF
Q_ASSERT_ID(220, m_lockNest < static_cast<uint_fast8_t>(0xFF));
Q_ASSERT_ID(220, m_lockNest < static_cast<uint8_t>(0xFF));
++m_lockNest;
}
else { // the mutex is alredy locked by a different thread
// the prio slot must be claimed by the thread holding the mutex
Q_ASSERT_ID(230, QF::active_[m_ceiling] != static_cast<QActive *>(0));
// the ceiling holder priority must be valid
Q_ASSERT_ID(230, m_holderPrio != static_cast<uint8_t>(0));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the prio slot must be claimed by the thread holding the mutex
Q_ASSERT_ID(240,
QF::active_[m_ceiling] != static_cast<QActive *>(0));
}
// remove this thr prio from the ready set (block)
// and insert to the waiting set on this mutex
QXK_attr_.readySet.remove(thr->m_prio);
m_waitSet.insert(thr->m_prio);
QXK_attr_.readySet.remove(curr->m_prio);
m_waitSet.insert(curr->m_prio);
// store the blocking object (this mutex)
thr->m_temp.obj = reinterpret_cast<QMState *>(this);
thr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
curr->m_temp.obj = reinterpret_cast<QMState *>(this);
curr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
// schedule the next thread if multitasking started
(void)QXK_sched_();
@ -183,18 +206,19 @@ bool QXMutex::lock(uint_fast16_t const nTicks) {
QF_CRIT_EXIT_NOP(); // BLOCK here
QF_CRIT_ENTRY_();
// the blocking object must be this mutex
Q_ASSERT_ID(240, thr->m_temp.obj == reinterpret_cast<QMState *>(this));
thr->m_temp.obj = static_cast<QMState *>(0); // clear
// the blocking object of the current thread must be this mutex
Q_ASSERT_ID(240,
curr->m_temp.obj == reinterpret_cast<QMState *>(this));
curr->m_temp.obj = static_cast<QMState *>(0); // clear blocking obj.
}
QF_CRIT_EXIT_();
// signal of non-zero means that the time event has not expired
return thr->m_timeEvt.sig != static_cast<QSignal>(0);
return curr->m_timeEvt.sig != static_cast<QSignal>(0);
}
//****************************************************************************
///
/// @description
/// Try to lock the QXK priority ceiling mutex QP::QXMutex.
///
@ -208,8 +232,8 @@ bool QXMutex::lock(uint_fast16_t const nTicks) {
///
/// @note
/// The mutex locks are allowed to nest, meaning that the same extended thread
/// can lock the same mutex multiple times (<= 225). However, each successful
/// call to QXMutex_tryLock() must be ballanced by the matching call to
/// can lock the same mutex multiple times (< 255). However, each successful
/// call to QXMutex::tryLock() must be ballanced by the matching call to
/// QXMutex::unlock().
///
bool QXMutex::tryLock(void) {
@ -226,45 +250,56 @@ bool QXMutex::tryLock(void) {
/// - NOT be called from an ISR;
/// - the QXK kernel must be running;
/// - the calling thread must be valid;
/// - the thread priority must be below the ceiling of the mutex;
/// - the ceiling must be not used; or
/// - the thread priority must be below the ceiling of the mutex;
/// - the thread must NOT be holding a scheduler lock;
Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
&& (QXK_attr_.lockPrio <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
&& (curr != static_cast<QActive *>(0)) /* curr thread must be valid */
&& (curr->m_startPrio < m_ceiling) /* prio below the ceiling */
&& ((m_ceiling == static_cast<uint8_t>(0)) /* below ceiling */
|| (curr->m_startPrio < static_cast<uint_fast8_t>(m_ceiling)))
&& (curr->m_prio != QXK_attr_.lockHolder)); // not holding a lock
// is the mutex available?
if (m_lockNest == static_cast<uint_fast8_t>(0)) {
m_lockNest = static_cast<uint_fast8_t>(1);
if (m_lockNest == static_cast<uint8_t>(0)) {
m_lockNest = static_cast<uint8_t>(1);
// the priority slot must be set to this mutex
Q_ASSERT_ID(310,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the priority slot must be set to this mutex
Q_ASSERT_ID(310,
QF::active_[m_ceiling] == reinterpret_cast<QActive *>(this));
// switch the priority of this thread to the mutex ceiling
curr->m_prio = m_ceiling;
QF::active_[m_ceiling] = curr;
// switch the priority of this thread to the mutex ceiling
curr->m_prio = static_cast<uint_fast8_t>(m_ceiling);
QF::active_[m_ceiling] = curr;
QXK_attr_.readySet.remove(curr->m_startPrio);
QXK_attr_.readySet.insert(curr->m_prio);
QXK_attr_.readySet.remove(curr->m_startPrio);
QXK_attr_.readySet.insert(curr->m_prio);
}
// make curr thread the new mutex holder
m_holderPrio = static_cast<uint8_t>(curr->m_startPrio);
QS_BEGIN_NOCRIT_(QS_MUTEX_LOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(curr->m_startPrio), /* start prio */
static_cast<uint8_t>(curr->m_prio)); // current ceiling
m_ceiling); // current ceiling
QS_END_NOCRIT_()
}
// is the mutex locked by this thread already (nested locking)?
else if (QF::active_[m_ceiling] == curr) {
// is the mutex held by this thread already (nested locking)?
else if (static_cast<uint_fast8_t>(m_holderPrio) == curr->m_startPrio) {
// the nesting level must not exceed 0xFF
Q_ASSERT_ID(320, m_lockNest < static_cast<uint_fast8_t>(0xFF));
Q_ASSERT_ID(320, m_lockNest < static_cast<uint8_t>(0xFF));
++m_lockNest;
}
else { // the mutex is alredy locked by a different thread
// the prio slot must be claimed by the thread holding the mutex
Q_ASSERT_ID(330, QF::active_[m_ceiling] != static_cast<QActive *>(0));
if (m_ceiling != static_cast<uint8_t>(0)) {
// the prio slot must be claimed by the mutex holder
Q_ASSERT_ID(330, (m_holderPrio != static_cast<uint8_t>(0))
&& (QF::active_[m_ceiling] != QF::active_[m_holderPrio]));
}
curr = static_cast<QActive *>(0); // means that mutex is NOT available
}
QF_CRIT_EXIT_();
@ -282,8 +317,8 @@ bool QXMutex::tryLock(void) {
///
/// @note
/// The mutex locks are allowed to nest, meaning that the same extended thread
/// can lock the same mutex multiple times (<= 225). However, each call to
/// QXMutex::lock() or a _successfull_ call to QXMutex_tryLock() must be
/// can lock the same mutex multiple times (< 255). However, each call to
/// QXMutex::lock() or a _successfull_ call to QXMutex::tryLock() must be
/// ballanced by the matching call to QXMutex::unlock().
///
/// @usage
@ -303,29 +338,36 @@ void QXMutex::unlock(void) {
/// - NOT be called from an ISR;
/// - the calling thread must be valid;
/// - the mutex must be held by this thread;
/// - the holding thread must have priority equal to the mutex ceiling;
/// - the ceiling must not be used or
/// - the current thread must have priority equal to the mutex ceiling;
/// - the mutex must be already locked at least once.
Q_REQUIRE_ID(400, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
&& (curr != static_cast<QActive *>(0)) /* curr must be valid */
&& (curr == QF::active_[m_ceiling]) /* held by this thr */
&& (curr->m_prio == m_ceiling) /* thr prio at the ceiling */
&& (m_lockNest > static_cast<uint_fast8_t>(0)));//locked at least once
&& (curr->m_startPrio == static_cast<uint_fast8_t>(m_holderPrio))
&& ((m_ceiling == static_cast<uint8_t>(0)) /* curr at ceiling prio */
|| (curr->m_prio == static_cast<uint_fast8_t>(m_ceiling)))
&& (m_lockNest > static_cast<uint8_t>(0))); // locked at least once
// is this the last nesting level?
if (m_lockNest == static_cast<uint_fast8_t>(1)) {
if (m_lockNest == static_cast<uint8_t>(1)) {
// restore the holding thread's priority to the original
curr->m_prio = curr->m_startPrio;
if (m_ceiling != static_cast<uint8_t>(0)) {
// restore the holding thread's priority to the original
curr->m_prio = curr->m_startPrio;
// remove the boosted priority and insert the original priority
QXK_attr_.readySet.remove(m_ceiling);
QXK_attr_.readySet.insert(curr->m_startPrio);
// remove the boosted priority and insert the original priority
QXK_attr_.readySet.remove(static_cast<uint_fast8_t>(m_ceiling));
QXK_attr_.readySet.insert(curr->m_startPrio);
}
// the mutex no longer held by a thread
m_holderPrio = static_cast<uint8_t>(0);
QS_BEGIN_NOCRIT_(QS_MUTEX_UNLOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(curr->m_startPrio), /* start prio */
static_cast<uint8_t>(m_ceiling)); // the mutex ceiling
m_ceiling); // the mutex ceiling
QS_END_NOCRIT_()
// are any other threads waiting for this mutex?
@ -336,12 +378,15 @@ void QXMutex::unlock(void) {
QXThread *thr = static_cast<QXThread *>(QF::active_[p]);
// the waiting thread must:
// (1) have priority below the ceiling
// (1) the ceiling must not be used; or if used
// the thread must have priority below the ceiling
// (2) be extended
// (3) not be redy to run
// (4) have still the start priority
// (5) be blocked on this mutex
Q_ASSERT_ID(410, (p < m_ceiling)
Q_ASSERT_ID(410,
((m_ceiling == static_cast<uint8_t>(0)) /* below ceiling */
|| (p < static_cast<uint_fast8_t>(m_ceiling)))
&& (thr != static_cast<QXThread *>(0)) /* extended thread */
&& (!QXK_attr_.readySet.hasElement(p))
&& (thr->m_prio == thr->m_startPrio)
@ -353,25 +398,32 @@ void QXMutex::unlock(void) {
// this thread is no longer waiting for the mutex
m_waitSet.remove(p);
// switch the priority of this thread to the mutex ceiling
thr->m_prio = m_ceiling;
QF::active_[m_ceiling] = thr;
if (m_ceiling != static_cast<uint8_t>(0)) {
// switch the priority of this thread to the mutex ceiling
thr->m_prio = static_cast<uint_fast8_t>(m_ceiling);
QF::active_[m_ceiling] = thr;
}
// make the thread ready to run (at the ceiling prio)
// make thr the new mutex holder
m_holderPrio = static_cast<uint8_t>(thr->m_startPrio);
// make the thread ready to run
QXK_attr_.readySet.insert(thr->m_prio);
QS_BEGIN_NOCRIT_(QS_MUTEX_LOCK,
static_cast<void *>(0), static_cast<void *>(0))
QS_TIME_(); // timestamp
QS_2U8_(static_cast<uint8_t>(thr->m_startPrio),/*start prio*/
static_cast<uint8_t>(thr->m_prio)); // ceiling prio
m_ceiling); // ceiling prio
QS_END_NOCRIT_()
}
else { // no threads are waiting for this mutex
m_lockNest = static_cast<uint_fast8_t>(0);
m_lockNest = static_cast<uint8_t>(0);
// put the mutex at the priority ceiling slot
QF::active_[m_ceiling] = reinterpret_cast<QActive *>(this);
if (m_ceiling != static_cast<uint8_t>(0)) {
// put the mutex at the priority ceiling slot
QF::active_[m_ceiling] = reinterpret_cast<QActive *>(this);
}
}
// schedule the next thread if multitasking started

View File

@ -3,8 +3,8 @@
/// @ingroup qxk
/// @cond
////**************************************************************************
/// Last updated for version 5.9.7
/// Last updated on 2017-08-20
/// Last updated for version 5.9.9
/// Last updated on 2017-09-27
///
/// Q u a n t u m L e a P s
/// ---------------------------
@ -79,8 +79,8 @@ void QXSemaphore::init(uint_fast16_t const count,
Q_REQUIRE_ID(100, max_count > static_cast<uint_fast16_t>(0));
m_waitSet.setEmpty();
m_count = count;
m_max_count = max_count;
m_count = static_cast<uint16_t>(count);
m_max_count = static_cast<uint16_t>(max_count);
}
//****************************************************************************
@ -108,7 +108,7 @@ bool QXSemaphore::wait(uint_fast16_t const nTicks) {
QF_CRIT_STAT_
QF_CRIT_ENTRY_();
QXThread *thr = static_cast<QXThread *>(QXK_attr_.curr);
QXThread *curr = static_cast<QXThread *>(QXK_attr_.curr);
/// @pre this function must:
/// (1) NOT be called from an ISR; (2) be called from an extended thread;
@ -116,34 +116,34 @@ bool QXSemaphore::wait(uint_fast16_t const nTicks) {
/// (4) the thread must NOT be already blocked on any object.
///
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
&& (thr != static_cast<QXThread *>(0)) /* current must be extended */
&& (curr != static_cast<QXThread *>(0)) /* curr must be extended */
&& (QXK_attr_.lockPrio == static_cast<uint_fast8_t>(0)) /* no lock */
&& (thr->m_temp.obj == static_cast<QMState *>(0))); // !blocked
&& (curr->m_temp.obj == static_cast<QMState *>(0))); // not blocked
if (m_count > static_cast<uint_fast16_t>(0)) {
if (m_count > static_cast<uint16_t>(0)) {
--m_count;
thr->m_timeEvt.sig = static_cast<QSignal>(QXK_SEMA_SIG); // non-zero
curr->m_timeEvt.sig = static_cast<QSignal>(QXK_SEMA_SIG); // non-zero
}
else {
// remember the blocking object
thr->m_temp.obj = reinterpret_cast<QMState const *>(this);
thr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
m_waitSet.insert(thr->m_prio);
QXK_attr_.readySet.remove(thr->m_prio);
curr->m_temp.obj = reinterpret_cast<QMState const *>(this);
curr->teArm_(static_cast<enum_t>(QXK_SEMA_SIG), nTicks);
m_waitSet.insert(curr->m_prio);
QXK_attr_.readySet.remove(curr->m_prio);
(void)QXK_sched_();
QF_CRIT_EXIT_();
QF_CRIT_EXIT_NOP(); // BLOCK here
QF_CRIT_ENTRY_();
// the blocking object must be this semaphore
Q_ASSERT_ID(210, thr->m_temp.obj
Q_ASSERT_ID(210, curr->m_temp.obj
== reinterpret_cast<QMState const *>(this));
thr->m_temp.obj = static_cast<QMState *>(0); // clear
curr->m_temp.obj = static_cast<QMState *>(0); // clear
}
QF_CRIT_EXIT_();
// signal of non-zero means that the time event has not expired
return (thr->m_timeEvt.sig != static_cast<QSignal>(0));
return (curr->m_timeEvt.sig != static_cast<QSignal>(0));
}
//****************************************************************************
@ -164,11 +164,11 @@ bool QXSemaphore::tryWait(void) {
QF_CRIT_STAT_
/// @pre the semaphore must be initialized
Q_REQUIRE_ID(300, (m_max_count > static_cast<uint_fast16_t>(0)));
Q_REQUIRE_ID(300, (m_max_count > static_cast<uint16_t>(0)));
QF_CRIT_ENTRY_();
// is the semaphore available?
if (m_count > static_cast<uint_fast16_t>(0)) {
if (m_count > static_cast<uint16_t>(0)) {
--m_count;
isAvailable = true;
}
@ -202,7 +202,7 @@ bool QXSemaphore::signal(void) {
QF_CRIT_STAT_
/// @pre the semaphore must be initialized
Q_REQUIRE_ID(400, (m_max_count > (uint_fast16_t)0));
Q_REQUIRE_ID(400, m_max_count > static_cast<uint16_t>(0));
QF_CRIT_ENTRY_();
if (m_waitSet.notEmpty()) {
@ -215,7 +215,7 @@ bool QXSemaphore::signal(void) {
// the thread must be extended and the semaphore count must be zero
Q_ASSERT_ID(410, (thr != static_cast<QXThread *>(0)) /* registered */
&& (thr->m_osObject != static_cast<void *>(0)) /* extended */
&& (m_count == static_cast<uint_fast16_t>(0))); // not signaled
&& (m_count == static_cast<uint16_t>(0))); // not signaled
// disarm the internal time event
(void)thr->teDisarm_();

View File

@ -1,2 +0,0 @@
QP/C++ 5.9.8
2017-09-15

2
version-5.9.9 Normal file
View File

@ -0,0 +1,2 @@
QP/C++ 5.9.9
2017-09-29