mirror of
https://github.com/QuantumLeaps/qpcpp.git
synced 2025-01-28 06:02:56 +08:00
5.9.9-beta
This commit is contained in:
parent
4116239a1f
commit
36b434c1a4
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
------ ----- ----- ------ ------ -----
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_();
|
||||
|
@ -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
|
||||
|
@ -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_();
|
||||
|
@ -1,2 +0,0 @@
|
||||
QP/C++ 5.9.8
|
||||
2017-09-15
|
2
version-5.9.9
Normal file
2
version-5.9.9
Normal file
@ -0,0 +1,2 @@
|
||||
QP/C++ 5.9.9
|
||||
2017-09-29
|
Loading…
x
Reference in New Issue
Block a user