diff --git a/3rd_party b/3rd_party index db8b6155..054cd1ab 160000 --- a/3rd_party +++ b/3rd_party @@ -1 +1 @@ -Subproject commit db8b6155e6931d2c55315dfd55b0e1fac0f96e33 +Subproject commit 054cd1abe4b4abef5e45f36b1ce8f2aff4575494 diff --git a/README.md b/README.md index 2dcdda41..9d9c1fbd 100644 --- a/README.md +++ b/README.md @@ -4,26 +4,25 @@ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/QuantumLeaps/qpcpp)](https://github.com/QuantumLeaps/qpcpp/releases/latest) - View QP/C++ Revision History at: https://www.state-machine.com/qpcpp/history.html > **NOTE:** If you're interested in the latest QP/C++ version from GitHub, -it is highly recommended that you clone this repo like that: +it is recommended that you clone this repo like that: ``` git clone https://github.com/QuantumLeaps/qpcpp --recurse-submodules --depth 1 ``` -Alternatively, you can also download the latest -[QP/C++ Release](https://github.com/QuantumLeaps/qpcpp/releases). +Alternatively, you can also download one of the stable +[QP/C++ Releases][QP-Rel]. # Getting Started with QP/C++ The most recommended way of obtaining QP/C++ is by downloading the [QP-bundle](https://www.state-machine.com/#Downloads), which includes QP/C++ -as well as the QM modeling tool and the QTools collection. The main advantage of -obtaining QP/C++ bundled together like that is that you get all components, -tools and examples ready to go. +as well as the [QM modeling tool][QM] and the [QTools collection][QTools]. +The main advantage of obtaining QP/C++ bundled together like that is +that you get all components, tools and examples ready to go. ### Getting Started Resources - ["QP/C++ Tutorial"][Tutorial] @@ -35,82 +34,96 @@ provides instructions on how to download, install, and get started with QP. - [AppNote: "Getting Started with QP Real-Time Embedded Frameworks"][AN] contains also a tutorial, in which you build a simple "Blinky" application. +## Licensing +The QP frameworks (QP/C and QP/C++) are licensed under the +[dual licensing model](https://www.state-machine.com/licensing), with +the following licensing options: + +1. [Open-source licensing](https://www.state-machine.com/licensing#Open) under the +[GNU General Public License (GPLv3)](https://www.gnu.org/licenses/gpl-3.0.en.html). + +> NOTE: GPL requires that all modifications to the original code +as well as your application code (Derivative Works as defined in the +Copyright Law) must also be released under the terms of the GPL +open source license. + +2. [Closed-source licensing](https://www.state-machine.com/licensing#Closed) under one of +[Quantum Leaps commercial licenses](https://www.state-machine.com/licensing#Commercial), +which are specifically designed for users interested in retaining the +proprietary status of their code. + +> NOTE: If your company has a policy forbidding open source in your product, +all QP frameworks can be licensed commercially, in which case you don't use +any open source license and you do not violate your policy. + # About QP/C++ QP/C++ (Quantum Platform in C++) is a lightweight, open source [Real-Time Embedded Framework (RTEF)][RTEF] for building modern embedded -software as systems of asynchronous, event-driven [active objects][Active] +software as systems of asynchronous, event-driven [Active Objects][Active] (actors). The [QP/C++] framework is a member of a [QP] family consisting of [QP/C] and [QP/C++] frameworks, which are strictly quality controlled, thoroughly documented, and [commercially licensable][Lic]. ## Safer Model of Concurrency -The [QP] framework family is based on the [Active Object][Active] (**actor**) -design pattern, which inherently supports and automatically enforces the -following best practices of concurrent programming: +The [QP] framework family implements the +[Active Object model of computation][AO_model], which is **inherently safer** +than the traditional "shared state concurrency" based on explicit mutual +exclusion and managing RTOS threads by blocking. The Active Object model +supports and automatically enforces the following best practices +of concurrent programming: -- Keep data isolated and bound to active objects' threads. Threads should +- Keep data isolated and bound to Active Objects' threads. Threads should hide (**encapsulate**) their private data and other resources, and not share them with the rest of the system. -- Communicate among active object threads **asynchronously** via event -objects. Using asynchronous events keeps the threads running truly +- Communicate among Active Object threads **asynchronously** via [Event +objects][Event]. Using asynchronous events keeps the threads running truly independently, **without blocking** on each other. -- Active object threads should spend their lifetime responding to incoming +- Active Object threads should spend their lifetime responding to incoming events, so their mainline should consist of an **event-loop** that handles events one at a time (to completion), thus avoiding any concurrency hazards -within an active object thread itself. +within an Active Object thread itself. -This architecture is generally **safer**, more responsive and easier to -understand and maintain than the shared-state concurrency of a conventional -RTOS. It also provides higher level of abstraction and the *correct* -abstractions to effectively apply **modeling** and **code generation** to -deeply embedded real-time systems. +This architecture also provides higher level of abstraction and the *correct* +abstractions to effectively apply [Hierarchical State Machines][HSM], +**modeling** and **code generation** to deeply embedded real-time systems. ## Hierarchical State Machines -The behavior of active objects is specified in QP/C++ by means of +The behavior of Active Objects is specified in QP/C++ by means of [Hierarchical State Machines][HSM] (UML statecharts). The framework supports manual coding of UML state machines in C as well as automatic **code generation** by means of the free [QM modeling tool][QM]. ## Built-in Real-Time Kernels -The QP/C++ framework can run on bare-metal single-chip microcontrollers, -completely replacing a traditional RTOS. The framework contains a selection -of **built-in real-time kernels**, such as the cooperative QV kernel, the -preemptive non-blocking QK kernel, and the preemptive, blocking QXK kernel -that provides all the features you might expect from a traditional RTOS. -Native QP ports and ready-to-use examples are provided for major CPUs, such -as ARM Cortex-M (M0/M0+/M3/M4/M7). +The QP/C++ framework can run on standalone on single-chip microcontrollers, +without any traditional RTOS. The framework contains a selection of +**built-in real-time kernels**, such as the [non-preemptive QV kernel][QV], +the [preemptive non-blocking QK kernel][QK], and the preemptive, +[dual-mode QXK kernel][QXK] that provides all the features you might expect +from a traditional RTOS. Native QP ports and ready-to-use examples are provided +for major CPUs, such as ARM Cortex-M (M0/M0+/M3/M4/M7/M23/M33/M85). ## Traditional RTOS/OS -QP/C++ can also work with a traditional RTOS, such as ThreadX, FreeRTOS, embOS, -uC/OS-II and TI-RTOS, as well as with (embedded) Linux (POSIX) and Windows. +QP/C++ can also work with a traditional RTOS, such as ThreadX, embOS, FreeRTOS, +uC/OS-II and Zephyr, as well as with (embedded) Linux (POSIX) and Windows. ## Popularity and Maturity -With 20 years of continuous development, over [350 commercial licensees][Cust], -and many times more open source users worldwide, the QP™ frameworks are the +With 20 years of continuous development, [400+ commercial licensees][Cust], +and many times more open source users worldwide, the QP frameworks are the most popular such offering on the market. They power countless electronic products ranging from implantable medical devices to complex weapon systems. -# QP/C++ Licensing -QP/C++ is licensed under the sustainable [dual licensing model][Lic], -in which both the open source software distribution mechanism and -traditional closed source software distribution models are combined. - -> **NOTE:** If your company has a policy forbidding open source in your -product, all QP frameworks can be [licensed commercially][Lic], in which case -you don't use any open source license and you do not violate your policy. - - # QP/C++ Documentation The online HTML documentation for the **latest** version of QP/C++ is located at: https://www.state-machine.com/qpcpp The offline HTML documentation for **this** particular version of QP/C++ -is located in the sub-folder [html](html). To view the offline documentation, -open the file [html/index.html](html/index.html) in your web browser. +is located in the sub-folder [html](html) (included in the [QP/C++ releases][QP-Rel]). +To view the offline documentation, open the file [html/index.html](html/index.html) +in your web browser. # How to Get Help? @@ -127,16 +140,19 @@ If you like this project, please give it a star (in the upper-right corner of yo ![GitHub star](https://www.state-machine.com/img/github-star.jpg) - - [RTEF]: - [QP]: - [QP/C]: - [QP/C++]: - [QM]: - [Active]: - [HSM]: - [Lic]: - [Cust]: - [AN]: + [RTEF]: + [QP]: + [QP/C]: + [QP/C++]: + [QM]: + [QTools]: + [QP-Rel]: + [Active]: + [AO_model]: + [Event]: + [HSM]: + [Lic]: + [Cust]: + [AN]: [Tutorial]: - [Video]: + [Video]: diff --git a/examples b/examples index a4becf08..4c76095e 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit a4becf08ed700750fce0bfea22a8968349330e55 +Subproject commit 4c76095e91087b69c97ce5e602690210a97893af diff --git a/include/qequeue.hpp b/include/qequeue.hpp index d648bbb2..177231fe 100644 --- a/include/qequeue.hpp +++ b/include/qequeue.hpp @@ -93,10 +93,6 @@ public: m_nFree(0U), m_nMin(0U) {} - -#ifdef Q_XTOR - ~QEQueue(); -#endif // def Q_XTOR void init( QEvt const * qSto[], std::uint_fast16_t const qLen) noexcept; diff --git a/include/qmpool.hpp b/include/qmpool.hpp index 6e005172..a05aa78e 100644 --- a/include/qmpool.hpp +++ b/include/qmpool.hpp @@ -118,10 +118,6 @@ public: m_nFree(0U), m_nMin(0U) {} - -#ifdef Q_XTOR - ~QMPool(); -#endif // def Q_XTOR void init( void * const poolSto, std::uint_fast32_t const poolSize, diff --git a/include/qp.hpp b/include/qp.hpp index 0000778d..7201d1fe 100644 --- a/include/qp.hpp +++ b/include/qp.hpp @@ -44,11 +44,9 @@ #define QP_HPP_ //============================================================================ -#define QP_VERSION 733U -#define QP_VERSION_STR "7.3.3" - -//! Encrypted current QP release (7.3.3) and date (2024-03-01) -#define QP_RELEASE 0x70C4F752U +#define QP_VERSION_STR "7.3.5-rc.1" +#define QP_VERSION 735U +#define QP_RELEASE 0x70A1DEF0U //============================================================================ //! @cond INTERNAL @@ -970,10 +968,6 @@ public: QActive * const act, QSignal const sig, std::uint_fast8_t const tickRate = 0U) noexcept; - -#ifdef Q_XTOR - ~QTimeEvt(); -#endif // def Q_XTOR void armX( QTimeEvtCtr const nTicks, QTimeEvtCtr const interval = 0U) noexcept; diff --git a/include/qsafe.h b/include/qsafe.h index 39ebb11c..43e772ac 100644 --- a/include/qsafe.h +++ b/include/qsafe.h @@ -3,7 +3,7 @@ // Model: qpc.qm // File: ${include::qsafe.h} // -// This code has been generated by QM 5.3.0 . +// This code has been generated by QM 6.1.1 . // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. // // This code is covered by the following QP license: @@ -150,6 +150,9 @@ extern "C" { //${QP-FuSa::Q_INVARIANT} .................................................... #define Q_INVARIANT(expr_) Q_ASSERT(expr_) +//${QP-FuSa::Q_INVARIANT_INCRIT} ............................................. +#define Q_INVARIANT_INCRIT(id_, expr_) Q_ASSERT_INCRIT((id_), (expr_)) + //${QP-FuSa::Q_ASSERT_STATIC} ................................................ #define Q_ASSERT_STATIC(expr_) extern char Q_static_assert_[(expr_) ? 1 : -1] diff --git a/ports/arm-cm/qxk/armclang/qxk_port.cpp b/ports/arm-cm/qxk/armclang/qxk_port.cpp index 5df013fb..ad2fe15d 100644 --- a/ports/arm-cm/qxk/armclang/qxk_port.cpp +++ b/ports/arm-cm/qxk/armclang/qxk_port.cpp @@ -27,8 +27,8 @@ // // //============================================================================ -//! @date Last updated on: 2023-12-04 -//! @version Last updated for: @ref qpcpp_7_3_1 +//! @date Last updated on: 2024-05-28 +//! @version Last updated for: @ref qpcpp_7_3_5 //! //! @file //! @brief QXK/C++ port to ARM Cortex-M, ARM-CLANG @@ -385,10 +385,10 @@ __asm volatile ( " MOVS r1,#1 \n" " LSLS r1,r1,#27 \n" // r1 := (1 << 27) (UNPENDSVSET bit) " LDR r2,=" STRINGIFY(SCB_ICSR) "\n" // Interrupt Control and State - " STR r1,[r2] \n" // ICSR[27] := 1 (unpend PendSV) + " STR r1,[r2] \n" // ICSR[27] := 1 (un-pend PendSV) // Check QXK_priv_.next, which contains the pointer to the next thread - // to run, which is set in QXK_ISR_EXIT(). This pointer must not be NULL. + // to run, which is set in QXK_ISR_EXIT(). Return if QXK_priv_.next == 0 " LDR r3,=QXK_priv_ \n" " LDR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // r1 := QXK_priv_.next " CMP r0,#0 \n" // is (QXK_priv_.next == 0)? @@ -498,7 +498,7 @@ __asm volatile ( " MOV lr,r2 \n" // make sure MSP is used #else // ARMv7-M or higher #ifdef __ARM_FP //--------- if VFP available... - " POP {r0,lr} \n" // restore alighner and EXC_RETURN into lr + " POP {r0,lr} \n" // restore aligner and EXC_RETURN into lr " DSB \n" // ARM Erratum 838869 " TST lr,#(1 << 4) \n" // is it return to the VFP exception frame? " IT EQ \n" // if EXC_RETURN[4] is zero... @@ -517,19 +517,18 @@ __asm volatile ( " BCC PendSV_activate \n" // if (next->prio > actPrio) activate the next AO // otherwise no activation needed... - " MOVS r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" // QXK_priv_.curr := 0 - " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // QXK_priv_.next := 0 + " MOVS r2,#0 \n" + " STR r2,[r3,#" STRINGIFY(QXK_CURR) "]\n" // QXK_priv_.curr := 0 + " STR r2,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // QXK_priv_.next := 0 " PUSH {r0,lr} \n" // save the aligner + EXC_RETURN #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) - // r0 is still 0 (parameter next) for QXK_contextSw_() + " CMP r0,#0 \n" // r0 == QXK_priv_.next->prio + " BEQ PendSV_idle \n" // if (QXK_priv_.next->prio != 0) + " MOV r0,r12 \n" // r0 := parameter 'next' for QXK_contextSw_() + "PendSV_idle: \n" " LDR r3,=QXK_contextSw_ \n" " BLX r3 \n" // call QXK_contextSw_() -#ifdef QF_MEM_ISOLATE - " LDR r3,=QF_onMemApp \n" - " BLX r3 \n" // call QF_onMemApp() -#endif #endif // defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) " B PendSV_return1 \n" // skip over saving aligner + EXC_RETURN @@ -538,6 +537,10 @@ __asm volatile ( " PUSH {r0,lr} \n" // save the aligner + EXC_RETURN "PendSV_return1: \n" +#ifdef QF_MEM_ISOLATE + " LDR r3,=QF_onMemApp \n" + " BLX r3 \n" // call QF_onMemApp() +#endif " LDR r0,=QF_int_enable_ \n" " BLX r0 \n" // call QF_int_enable_() //>>>>>>>>>>>>>>>>>>>>>>>> CRITICAL SECTION END >>>>>>>>>>>>>>>>>>>>>>>>> @@ -600,7 +603,7 @@ __asm volatile ( " PUSH {r0-r2,lr} \n" // save next, osObject, EXC_RETURN #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) - " MOV r0,r12 \n" // parameter next + " MOV r0,r12 \n" // r0 := parameter 'next' for QXK_contextSw_() " LDR r3,=QXK_contextSw_ \n" " BLX r3 \n" // call QXK_contextSw_() #ifdef QF_MEM_ISOLATE @@ -753,7 +756,7 @@ __asm volatile ( " ADD sp,sp,#(8*4) \n" // remove one 8-register exception frame #ifdef __ARM_FP //--------- if VFP available... - " POP {r0,lr} \n" // restore alighner and EXC_RETURN into lr + " POP {r0,lr} \n" // restore aligher and EXC_RETURN into lr " DSB \n" // ARM Erratum 838869 " TST lr,#(1 << 4) \n" // is it return to the VFP exception frame? " IT EQ \n" // if EXC_RETURN[4] is zero... diff --git a/ports/arm-cm/qxk/gnu/qxk_port.cpp b/ports/arm-cm/qxk/gnu/qxk_port.cpp index dda5c499..3aee0726 100644 --- a/ports/arm-cm/qxk/gnu/qxk_port.cpp +++ b/ports/arm-cm/qxk/gnu/qxk_port.cpp @@ -27,8 +27,8 @@ // // //============================================================================ -//! @date Last updated on: 2024-01-30 -//! @version Last updated for: @ref qpcpp_7_3_3 +//! @date Last updated on: 2024-05-28 +//! @version Last updated for: @ref qpcpp_7_3_5 //! //! @file //! @brief QXK/C++ port to ARM Cortex-M, GNU-ARM @@ -390,10 +390,10 @@ __asm volatile ( " MOV r1,#1 \n" " LSL r1,r1,#27 \n" // r1 := (1 << 27) (UNPENDSVSET bit) " LDR r2,=" STRINGIFY(SCB_ICSR) "\n" // Interrupt Control and State - " STR r1,[r2] \n" // ICSR[27] := 1 (unpend PendSV) + " STR r1,[r2] \n" // ICSR[27] := 1 (un-pend PendSV) // Check QXK_priv_.next, which contains the pointer to the next thread - // to run, which is set in QXK_ISR_EXIT(). This pointer must not be NULL. + // to run, which is set in QXK_ISR_EXIT(). Return if QXK_priv_.next == 0 " LDR r3,=QXK_priv_ \n" " LDR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // r1 := QXK_priv_.next " CMP r0,#0 \n" // is (QXK_priv_.next == 0)? @@ -503,7 +503,7 @@ __asm volatile ( " MOV lr,r2 \n" // make sure MSP is used #else // ARMv7-M or higher #ifdef __ARM_FP //--------- if VFP available... - " POP {r0,lr} \n" // restore alighner and EXC_RETURN into lr + " POP {r0,lr} \n" // restore aligner and EXC_RETURN into lr " DSB \n" // ARM Erratum 838869 " TST lr,#(1 << 4) \n" // is it return to the VFP exception frame? " IT EQ \n" // if EXC_RETURN[4] is zero... @@ -522,19 +522,18 @@ __asm volatile ( " BCC PendSV_activate \n" // if (next->prio > actPrio) activate the next AO // otherwise no activation needed... - " MOV r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" // QXK_priv_.curr := 0 - " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // QXK_priv_.next := 0 + " MOV r2,#0 \n" + " STR r2,[r3,#" STRINGIFY(QXK_CURR) "]\n" // QXK_priv_.curr := 0 + " STR r2,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // QXK_priv_.next := 0 " PUSH {r0,lr} \n" // save the aligner + EXC_RETURN #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) - // r0 is still 0 (parameter next) for QXK_contextSw_() + " CMP r0,#0 \n" // r0 == QXK_priv_.next->prio + " BEQ PendSV_idle \n" // if (QXK_priv_.next->prio != 0) + " MOV r0,r12 \n" // r0 := parameter 'next' for QXK_contextSw_() + "PendSV_idle: \n" " LDR r3,=QXK_contextSw_ \n" " BLX r3 \n" // call QXK_contextSw_() -#ifdef QF_MEM_ISOLATE - " LDR r3,=QF_onMemApp \n" - " BLX r3 \n" // call QF_onMemApp() -#endif #endif // defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) " B PendSV_return1 \n" // skip over saving aligner + EXC_RETURN @@ -543,6 +542,10 @@ __asm volatile ( " PUSH {r0,lr} \n" // save the aligner + EXC_RETURN "PendSV_return1: \n" +#ifdef QF_MEM_ISOLATE + " LDR r3,=QF_onMemApp \n" + " BLX r3 \n" // call QF_onMemApp() +#endif " LDR r0,=QF_int_enable_ \n" " BLX r0 \n" // call QF_int_enable_() //>>>>>>>>>>>>>>>>>>>>>>>> CRITICAL SECTION END >>>>>>>>>>>>>>>>>>>>>>>>> @@ -605,7 +608,7 @@ __asm volatile ( " PUSH {r0-r2,lr} \n" // save next, osObject, EXC_RETURN #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) - " MOV r0,r12 \n" // parameter next + " MOV r0,r12 \n" // r0 := parameter 'next' for QXK_contextSw_() " LDR r3,=QXK_contextSw_ \n" " BLX r3 \n" // call QXK_contextSw_() #ifdef QF_MEM_ISOLATE @@ -758,7 +761,7 @@ __asm volatile ( " ADD sp,sp,#(8*4) \n" // remove one 8-register exception frame #ifdef __ARM_FP //--------- if VFP available... - " POP {r0,lr} \n" // restore alighner and EXC_RETURN into lr + " POP {r0,lr} \n" // restore aligher and EXC_RETURN into lr " DSB \n" // ARM Erratum 838869 " TST lr,#(1 << 4) \n" // is it return to the VFP exception frame? " IT EQ \n" // if EXC_RETURN[4] is zero... diff --git a/ports/arm-cm/qxk/iar/qxk_port.cpp b/ports/arm-cm/qxk/iar/qxk_port.cpp index 36ae6b1e..9bf581d8 100644 --- a/ports/arm-cm/qxk/iar/qxk_port.cpp +++ b/ports/arm-cm/qxk/iar/qxk_port.cpp @@ -27,8 +27,8 @@ // // //============================================================================ -//! @date Last updated on: 2023-12-10 -//! @version Last updated for: @ref qpcpp_7_3_1 +//! @date Last updated on: 2024-05-28 +//! @version Last updated for: @ref qpcpp_7_3_5 //! //! @file //! @brief QXK/C++ port to ARM Cortex-M, IAR-ARM @@ -389,10 +389,10 @@ __asm volatile ( " MOVS r1,#1 \n" " LSLS r1,r1,#27 \n" // r1 := (1 << 27) (UNPENDSVSET bit) " LDR r2,=" STRINGIFY(SCB_ICSR) "\n" // Interrupt Control and State - " STR r1,[r2] \n" // ICSR[27] := 1 (unpend PendSV) + " STR r1,[r2] \n" // ICSR[27] := 1 (un-pend PendSV) // Check QXK_priv_.next, which contains the pointer to the next thread - // to run, which is set in QXK_ISR_EXIT(). This pointer must not be NULL. + // to run, which is set in QXK_ISR_EXIT(). Return if QXK_priv_.next == 0 " LDR r3,=QXK_priv_ \n" " LDR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // r1 := QXK_priv_.next " CMP r0,#0 \n" // is (QXK_priv_.next == 0)? @@ -502,7 +502,7 @@ __asm volatile ( " MOV lr,r2 \n" // make sure MSP is used #else // ARMv7-M or higher #ifdef __ARM_FP //--------- if VFP available... - " POP {r0,lr} \n" // restore alighner and EXC_RETURN into lr + " POP {r0,lr} \n" // restore aligner and EXC_RETURN into lr " DSB \n" // ARM Erratum 838869 " TST lr,#(1 << 4) \n" // is it return to the VFP exception frame? " IT EQ \n" // if EXC_RETURN[4] is zero... @@ -521,19 +521,18 @@ __asm volatile ( " BCC PendSV_activate \n" // if (next->prio > actPrio) activate the next AO // otherwise no activation needed... - " MOVS r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" // QXK_priv_.curr := 0 - " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // QXK_priv_.next := 0 + " MOVS r2,#0 \n" + " STR r2,[r3,#" STRINGIFY(QXK_CURR) "]\n" // QXK_priv_.curr := 0 + " STR r2,[r3,#" STRINGIFY(QXK_NEXT) "]\n" // QXK_priv_.next := 0 " PUSH {r0,lr} \n" // save the aligner + EXC_RETURN #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) - // r0 is still 0 (parameter next) for QXK_contextSw_() + " CMP r0,#0 \n" // r0 == QXK_priv_.next->prio + " BEQ PendSV_idle \n" // if (QXK_priv_.next->prio != 0) + " MOV r0,r12 \n" // r0 := parameter 'next' for QXK_contextSw_() + "PendSV_idle: \n" " LDR r3,=QXK_contextSw_ \n" " BLX r3 \n" // call QXK_contextSw_() -#ifdef QF_MEM_ISOLATE - " LDR r3,=QF_onMemApp \n" - " BLX r3 \n" // call QF_onMemApp() -#endif #endif // defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) " B PendSV_return1 \n" // skip over saving aligner + EXC_RETURN @@ -542,6 +541,10 @@ __asm volatile ( " PUSH {r0,lr} \n" // save the aligner + EXC_RETURN "PendSV_return1: \n" +#ifdef QF_MEM_ISOLATE + " LDR r3,=QF_onMemApp \n" + " BLX r3 \n" // call QF_onMemApp() +#endif " LDR r0,=QF_int_enable_ \n" " BLX r0 \n" // call QF_int_enable_() //>>>>>>>>>>>>>>>>>>>>>>>> CRITICAL SECTION END >>>>>>>>>>>>>>>>>>>>>>>>> @@ -604,7 +607,7 @@ __asm volatile ( " PUSH {r0-r2,lr} \n" // save next, osObject, EXC_RETURN #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) - " MOV r0,r12 \n" // parameter next + " MOV r0,r12 \n" // r0 := parameter 'next' for QXK_contextSw_() " LDR r3,=QXK_contextSw_ \n" " BLX r3 \n" // call QXK_contextSw_() #ifdef QF_MEM_ISOLATE @@ -757,7 +760,7 @@ __asm volatile ( " ADD sp,sp,#(8*4) \n" // remove one 8-register exception frame #ifdef __ARM_FP //--------- if VFP available... - " POP {r0,lr} \n" // restore alighner and EXC_RETURN into lr + " POP {r0,lr} \n" // restore aligher and EXC_RETURN into lr " DSB \n" // ARM Erratum 838869 " TST lr,#(1 << 4) \n" // is it return to the VFP exception frame? " IT EQ \n" // if EXC_RETURN[4] is zero... diff --git a/ports/lint-plus/options.lnt b/ports/lint-plus/options.lnt index cb496832..1aac7674 100644 --- a/ports/lint-plus/options.lnt +++ b/ports/lint-plus/options.lnt @@ -22,17 +22,18 @@ // // //============================================================================ -//! @date Last updated on: 2024-02-19 -//! @version Last updated for: @ref qpcpp_7_3_0 +//! @date Last updated on: 2024-05-01 +//! @version Last updated for version: 7.3.4 //! //! @file //! @brief PC-Lint-Plus option file for linting QP/C++ source code //============================================================================ // general options --unit_check // perform only subset check (suppresses Global Wrapup) --max_threads=1 // suppress message "no '-max_threads=N' option" -//-vf // print names of all source files (for debugging linting) +-unit_check // perform only subset check (suppresses Global Wrapup) +-max_threads=1 // suppress message "no '-max_threads=N' option" +++efreeze(686) // never suppress (see PC-Lint-Plus in Safety-Critical) +//-vf // print names of all source files (for debugging linting) // include directories -i. // QP/C++ port includes (see also qk/ and qv/) @@ -40,12 +41,8 @@ // standards au-autosar.lnt // AUTOSAR:C++14 -au-ds.lnt // Dan Saks recommendations -au-ql-cpp11.lnt // Quantum Leaps coding standard for C++11 - - -// size/alignment options -cpu.lnt // for the chosen CPU +au-ds.lnt // Dan Saks recommendations +cpu.lnt // size/alignment options for the chosen CPU // defined macros (might be undefined on command-line with -u) -dQ_SPY @@ -83,6 +80,7 @@ qpcpp.lnt // QP/C++ options Q_ASSERT_INCRIT, Q_REQUIRE_INCRIT, Q_ENSURE_INCRIT, + Q_INVARIANT_INCRIT, Q_ERROR_INCRIT) //! M4-D4.9(A) function-like macro diff --git a/ports/lint-plus2/16bit/cpu.lnt b/ports/lint-plus2/16bit/cpu.lnt new file mode 100644 index 00000000..d5cc76b1 --- /dev/null +++ b/ports/lint-plus2/16bit/cpu.lnt @@ -0,0 +1,6 @@ +// Size Options for 16bit CPU (e.g., MSP430) +-si2 -sl4 -sll8 -ss2 -sw2 -sp2 -sf4 -sd8 -sld8 + +// Alignment options for 16bit CPU +-ai2 -al2 -all2 -as2 -af4 -ad8 -ald8 + diff --git a/ports/lint-plus2/16bit/cstdint b/ports/lint-plus2/16bit/cstdint new file mode 100644 index 00000000..0566fa50 --- /dev/null +++ b/ports/lint-plus2/16bit/cstdint @@ -0,0 +1,39 @@ +/// @file cstdint +/// This is an emulation of a Standard C++ Library header for 16bit CPUs, +/// like MSP430. + +#ifndef _GLIBCXX_CSTDINT +#define _GLIBCXX_CSTDINT + +//lint -save +//lint -e9093 AUTOSAR:M17-0-2 the name ... is reserved to the compiler +//lint -e9145 AUTOSAR:M7-3-6 9145: using declaration in header + +namespace std { + + using int8_t = signed char; //!< exact-width 8-bit signed int + using int16_t = signed int; //!< exact-width 16-bit signed int + using int32_t = signed long int; //!< exact-width 32-bit signed int + using int64_t = signed long long; //!< exact-width 64-bit signed int + + using uint8_t = unsigned char; //!< exact-width 8-bit unsigned int + using uint16_t = unsigned int; //!< exact-width 16-bit unsigned int + using uint32_t = unsigned long int; //!< exact-width 32-bit unsigned int + using uint64_t = unsigned long long; //!< exact-width 64-bit unsigned int + + // Fastest minimum-width types. WG14/N843 C99 Standard, Section 7.18.1.3 + using int_fast8_t = signed int; //!< fast at-least 8-bit signed int + using uint_fast8_t = unsigned int; //!< fast at-least 8-bit unsigned int + using int_fast16_t = signed int; //!< fast at-least 16-bit signed int + using uint_fast16_t = unsigned int; //!< fast at-least 16-bit unsigned int + using int_fast32_t = signed long; //!< fast at-least 32-bit signed int + using uint_fast32_t = unsigned long; //!< fast at-least 32-bit unsigned int + + // unsigned integer type capable of holding a pointer to void. + using uintptr_t = unsigned; //!< unsigned int capable of holding void* + +} // namespace std + +//lint -restore + +#endif // _GLIBCXX_CSTDINT diff --git a/ports/lint-plus2/16bit/qs_port.hpp b/ports/lint-plus2/16bit/qs_port.hpp new file mode 100644 index 00000000..35dfe808 --- /dev/null +++ b/ports/lint-plus2/16bit/qs_port.hpp @@ -0,0 +1,58 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2023-08-17 +//! @version Last updated for: @ref qpcpp_7_3_0 +//! +//! @file +//! @brief QS/C++ port to a 32-bit CPU, generic C++ compiler +//! @description +//! This is an example QP/C++ port with the documentation for the main +//! items, such as configuration macros, functions, and includes. + +#ifndef QS_PORT_HPP_ +#define QS_PORT_HPP_ + +// QS time-stamp size in bytes +#define QS_TIME_SIZE 4U + +// object pointer size in bytes +#define QS_OBJ_PTR_SIZE 2U + +// function pointer size in bytes +#define QS_FUN_PTR_SIZE 2U + +//============================================================================ +// NOTE: QS might be used with or without other QP components, in which case +// the separate definitions of the macros QF_CRIT_STAT, QF_CRIT_ENTRY(), +// and QF_CRIT_EXIT() are needed. In this port QS is configured to be used with +// the other QP component, by simply including "qp_port.hpp" *before* "qs.hpp". +// +#ifndef QP_PORT_HPP_ +#include "qp_port.hpp" // use QS with QP +#endif + +#include "qs.hpp" // QS platform-independent public interface + +#endif // QS_PORT_HPP_ diff --git a/ports/lint-plus2/32bit/cpu.lnt b/ports/lint-plus2/32bit/cpu.lnt new file mode 100644 index 00000000..9281e892 --- /dev/null +++ b/ports/lint-plus2/32bit/cpu.lnt @@ -0,0 +1,3 @@ +// Size Options for 32bit CPU (e.g., ARM Cortex-M) +-si4 -sl4 -sll8 -ss2 -sw4 -sp4 -sf4 -sd8 -sld8 + diff --git a/ports/lint-plus2/32bit/cstdint b/ports/lint-plus2/32bit/cstdint new file mode 100644 index 00000000..b372ca32 --- /dev/null +++ b/ports/lint-plus2/32bit/cstdint @@ -0,0 +1,39 @@ +/// @file cstdint +/// This is an emulation of a Standard C++ Library header for 32bit CPUs, +/// like ARM Cortex-M. + +#ifndef _GLIBCXX_CSTDINT +#define _GLIBCXX_CSTDINT + +//lint -save +//lint -e9093 AUTOSAR:M17-0-2 the name ... is reserved to the compiler +//lint -e9145 AUTOSAR:M7-3-6 9145: using declaration in header + +namespace std { + + using int8_t = signed char; //!< exact-width 8-bit signed int + using int16_t = signed short; //!< exact-width 16-bit signed int + using int32_t = signed long; //!< exact-width 32-bit signed int + using int64_t = signed long long; //!< exact-width 64-bit signed int + + using uint8_t = unsigned char; //!< exact-width 8-bit unsigned int + using uint16_t = unsigned short; //!< exact-width 16-bit unsigned int + using uint32_t = unsigned long; //!< exact-width 32-bit unsigned int + using uint64_t = unsigned long long; //!< exact-width 64-bit unsigned int + + // Fastest minimum-width types. WG14/N843 C99 Standard, Section 7.18.1.3 + using int_fast8_t = signed int; //!< fast at-least 8-bit signed int + using uint_fast8_t = unsigned int; //!< fast at-least 8-bit unsigned int + using int_fast16_t = signed int; //!< fast at-least 16-bit signed int + using uint_fast16_t = unsigned int; //!< fast at-least 16-bit unsigned int + using int_fast32_t = signed long; //!< fast at-least 32-bit signed int + using uint_fast32_t = unsigned long; //!< fast at-least 32-bit unsigned int + + // unsigned integer type capable of holding a pointer to void. + using uintptr_t = unsigned; //!< unsigned int capable of holding void* + +} // namespace std + +//lint -restore + +#endif // _GLIBCXX_CSTDINT diff --git a/ports/lint-plus2/32bit/qs_port.hpp b/ports/lint-plus2/32bit/qs_port.hpp new file mode 100644 index 00000000..e55d5bc6 --- /dev/null +++ b/ports/lint-plus2/32bit/qs_port.hpp @@ -0,0 +1,61 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2023-08-17 +//! @version Last updated for: @ref qpcpp_7_3_0 +//! +//! @file +//! @brief QS/C++ port to a 32-bit CPU, generic C++ compiler +//! @description +//! This is an example QP/C++ port with the documentation for the main +//! items, such as configuration macros, functions, and includes. + +#ifndef QS_PORT_HPP_ +#define QS_PORT_HPP_ + +//! QS buffer counter size in bytes +#define QS_CTR_SIZE 2U + +//! QS time-stamp size in bytes +#define QS_TIME_SIZE 4U + +//! object pointer size in bytes +#define QS_OBJ_PTR_SIZE 4U + +//! function pointer size in bytes +#define QS_FUN_PTR_SIZE 4U + +//============================================================================ +// NOTE: QS might be used with or without other QP components, in which case +// the separate definitions of the macros QF_CRIT_STAT, QF_CRIT_ENTRY(), +// and QF_CRIT_EXIT() are needed. In this port QS is configured to be used with +// the other QP component, by simply including "qp_port.hpp" *before* "qs.hpp". +// +#ifndef QP_PORT_HPP_ +#include "qp_port.hpp" // use QS with QP +#endif + +#include "qs.hpp" // QS platform-independent public interface + +#endif // QS_PORT_HPP_ diff --git a/ports/lint-plus2/au-ds.lnt b/ports/lint-plus2/au-ds.lnt new file mode 100644 index 00000000..38fcd673 --- /dev/null +++ b/ports/lint-plus2/au-ds.lnt @@ -0,0 +1,21 @@ +// au-ds.lnt -- Author options - Dan Saks + +/* + This options file can be used to explicitly activate those + checks advocated by Dan Saks in his series of presentations on + "C++ Gotchas". + + You can use this file directly when linting your programs as in: + + lin au-ds files + + */ + ++fsc // consider string constants as const char * ++e1933 // turn on "virtual call from member detection" + +// The rationale for the following two options are fully described +// in Dan Saks' article "const T vs. T const". Visit his web site +// at www.dansaks.com and click "Published Articles". +// +-fqb +e963 // require T const rather than const T diff --git a/ports/lint-plus2/cstddef b/ports/lint-plus2/cstddef new file mode 100644 index 00000000..f2d44f23 --- /dev/null +++ b/ports/lint-plus2/cstddef @@ -0,0 +1,42 @@ +#ifndef _CSTDDEF_ +#define _CSTDDEF_ + +//lint -save +//lint -e9093 the name is reserved to the compiler +//lint -e9141 global declaration of symbol 'operator new' +//lint -e9215 unnamed parameter for 'non-virtual' function 'operator new' + +namespace std { + using ptrdiff_t = unsigned int; + using size_t = unsigned int; + using max_align_t = unsigned int; + using nullptr_t = decltype(nullptr); + + enum class byte : unsigned char {}; + + // byte type operations + template + constexpr byte& operator<<=(byte& b, IntType shift) noexcept; + template + constexpr byte operator<<(byte b, IntType shift) noexcept; + template + constexpr byte& operator>>=(byte& b, IntType shift) noexcept; + template + constexpr byte operator>>(byte b, IntType shift) noexcept; + constexpr byte& operator|=(byte& l, byte r) noexcept; + constexpr byte operator|(byte l, byte r) noexcept; + constexpr byte& operator&=(byte& l, byte r) noexcept; + constexpr byte operator&(byte l, byte r) noexcept; + constexpr byte& operator^=(byte& l, byte r) noexcept; + constexpr byte operator^(byte l, byte r) noexcept; + constexpr byte operator~(byte b) noexcept; + template + constexpr IntType to_integer(byte b) noexcept; +} + +#define NULL nullptr +//#define offsetof(type, member) ... + +//lint -restore + +#endif // _CSTDDEF_ \ No newline at end of file diff --git a/ports/lint-plus2/make.bat b/ports/lint-plus2/make.bat new file mode 100644 index 00000000..fb85591f --- /dev/null +++ b/ports/lint-plus2/make.bat @@ -0,0 +1,70 @@ +@echo off +:: =========================================================================== +:: Batch script for linting QP/C with PC-Lint-Plus2 +:: Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +:: +:: SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +:: +:: This software is dual-licensed under the terms of the open source GNU +:: General Public License version 3 (or any later version), or alternatively, +:: under the terms of one of the closed source Quantum Leaps commercial +:: licenses. +:: +:: The terms of the open source GNU General Public License version 3 +:: can be found at: +:: +:: The terms of the closed source Quantum Leaps commercial licenses +:: can be found at: +:: +:: Redistributions in source code must retain this top-level comment block. +:: Plagiarizing this software to sidestep the license obligations is illegal. +:: +:: Contact information: +:: +:: +:: =========================================================================== +@setlocal + +:: usage of make.bat +@echo Usage: make [16bit] [-u...] files +@echo examples: +@echo make -uQ_SPY -uQ_UTEST : use 32bit CPU (default) and undefine Q_SPY/Q_UTEST +@echo make 16bit -uQ_SPY : use 16bit CPU includes and undefine Q_SPY +@echo. + +:: NOTE: adjust to for your installation directory of PC-Lint-Plus +@set PCLP=C:\tools\lint-plus2.2-beta\windows +@set PCLP_EXE=%PCLP%\pclp64.exe + +if NOT exist "%PCLP%" ( + @echo The PC-Lint-Plus toolset not found. Please adjust make.bat + @goto end +) + +:: set the QP/C++ directory +set QPCPP=..\.. + +if "%1"=="16bit" ( + set LINTFLAGS=-i16bit options.lnt %1 %2 %3 %4 + @echo 16bit CPU +) else ( + set LINTFLAGS=-i32bit options.lnt %1 %2 %3 %4 + @echo 32bit CPU default +) + +:: cleanup +@del *.log + +:: linting ------------------------------------------------------------------- +%PCLP_EXE% -os(lint_qf.log) std.lnt %LINTFLAGS% -iqv ..\..\src\qf\*.cpp + +%PCLP_EXE% -os(lint_qv.log) std.lnt %LINTFLAGS% -iqv ..\..\src\qv\*.cpp + +%PCLP_EXE% -os(lint_qk.log) std.lnt %LINTFLAGS% -iqk ..\..\src\qk\*.cpp + +%PCLP_EXE% -os(lint_qxk.log) std.lnt %LINTFLAGS% -iqxk ..\..\src\qxk\*.cpp + +%PCLP_EXE% -os(lint_qs.log) std.lnt %LINTFLAGS% -iqv ..\..\src\qs\*.cpp + +:end +@endlocal diff --git a/ports/lint-plus2/options.lnt b/ports/lint-plus2/options.lnt new file mode 100644 index 00000000..adfd8c61 --- /dev/null +++ b/ports/lint-plus2/options.lnt @@ -0,0 +1,406 @@ +//============================================================================ +// QP/C Real-Time Embedded Framework (RTEF) +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2024-05-01 +//! @version Last updated for version: 7.3.4 +//! +//! @file +//! @brief PC-Lint-Plus option file for linting QP/C++ source code + +//============================================================================ +// general options +-unit_check // perform only subset check (suppresses Global Wrapup) +-max_threads=1 // suppress message "no '-max_threads=N' option" +++efreeze(686) // never suppress (see PC-Lint-Plus in Safety-Critical) +//-vf // print names of all source files (for debugging linting) + +// include directories +-i%PCLP%/lnt // PC-Lint-Plus standard .lnt files +-i. // QP/C++ port includes (see also qk/ and qv/) +-i%QPCPP%/include // QP/C++ public includes + +// standards +au-autosar.lnt // AUTOSAR:C++14 +au-ds.lnt // Dan Saks recommendations +cpu.lnt // size/alignment options for the chosen CPU + +// defined macros (might be undefined on command-line with -u) +-dQ_SPY +-dQ_UTEST + +//============================================================================ +// QP/C++ options for clients +qpcpp.lnt // QP/C++ options + +//============================================================================ +// additional suppression rules for building QP/C source code... + +// general suppression for now... + +// preprocessor directive ... is deprecated. [AUTOSAR Rule A16-0-1] +-e586 + +// preprocessor directive encountered in conditionally excluded region +// [AUTOSAR Rule A16-0-1], [AUTOSAR Rule A16-6-1] +-e886 + +// friend ... in class +-e9435 + +// symbol ... has array type +-e9436 + +// enum ... is not a scoped enumeration [AUTOSAR Rule A7-2-3] +-e9419 + +// QEP ----------------------------------------------------------------------- + +//! MC++R16-0-4 function-like macro ??? +-esym(9026, + Q_ASSERT_INCRIT, + Q_REQUIRE_INCRIT, + Q_ENSURE_INCRIT, + Q_INVARIANT_INCRIT, + Q_ERROR_INCRIT) + +//! M4-D4.9(A) function-like macro +//! @tr{DVP-QP-MC4-D04_09B} +-esym(9026, + QHSM_RESERVED_EVT_, + QS_STATE_ENTRY_, + QS_STATE_EXIT_) + +// implicit conversion of enum 'QP::QAsm::QStateRet' to integral type +-esym(641, + QP::QAsm::QStateRet) + +// MC++R7-1-2 parameter of function could be pointer to const +-esym(818, + QP::QHsm::top) + +// QF ------------------------------------------------------------------------ + +// MC++R16-0-4 function-like macro +-esym(9026, + QF_CRIT_ENTRY, + QF_CRIT_EXIT, + QF_MEM_SYS, + QF_MEM_APP, + QF_CONST_CAST_, + QF_SCHED_LOCK_, + QF_SCHED_UNLOCK_, + QF_PTR_RANGE_, + QF_MPOOL_EL, + Q_ACTION_CAST, + QTICKER_CAST_) + +// MC++R16-0-4 function-like macro +-esym(9026, + QACTIVE_EQUEUE_WAIT_, + QACTIVE_EQUEUE_SIGNAL_, + QF_EPOOL_INIT_, + QF_EPOOL_EVENT_SIZE_, + QF_EPOOL_GET_, + QF_EPOOL_PUT_) + +// MC++R10-0-6 unparenthesized macro parameter in definition of macro +-esym(9022, + QF_CONST_CAST_) + +// [AUTOSAR Rule A5-2-3] cast drops const qualifier +-emacro(9005, + QF_CONST_CAST_) + +// M3-R11.3(r) cast from pointer to object type +-emacro(9087, + QTICKER_CAST_) + +// suspicious pointer-to-pointer conversion (area too small) +-emacro(826, + QTICKER_CAST_) + +// AC++M5-2-9 casting from pointer type to integer type +-emacro(9091, + Q_UINTPTR_CAST_) + +// [AC++M12-1-1] non-static data member not initialized by ctor +-esym(1401, + QP::QEvt::*, + QP::QActive::*) + +// definition of macro ends in semi-colon +-esym(823, + QF_SCHED_STAT_) + +// MC++5-2-8 conversion from integer type (0) to pointer type +-emacro(9010, + Q_ACTION_CAST) + + +// M3-R11.8(r) cast drops const qualifier +-emacro(9005, + QF_EPOOL_PUT_) + +// M3-D11.5(a) conversion from pointer to void to other pointer type +-efunc(9079, + QF_bzero) + +// M3-R17.8(a) function parameter modified +-efunc(9044, + QF_LOG2, + QMPool_init) + +// M3-R18.1(r) potential out of bounds pointer access +-emacro(661, + QF_EPOOL_EVENT_SIZE_) + +// AR-M5-2-8 conversion from pointer to void to other pointer type +-emacro(9079, + QF_EPOOL_GET_) + +// M3-R18.3(r) relational operator <= applied to pointers +-emacro(946, + QF_PTR_RANGE_) + +// M3-R8.13(a) parameter of function could be pointer to const +-efunc(818, + QP::QActive::start, + QP::QTicker::postLIFO) + +// MC++R0-1-1 statement is unreachable due to unconditional transfer +// of control (assertion) +//-efunc(527, +// QP::QMActive::isIn, +// QP::QMActive::state, +// QP::QMActive::childState) + +// MC++R7-1-1 parameter of function could be declared const +-esym(952, + QP::QEQueue::init) + +// AC++M5-2-3: downcast of polymorphic type +-efunc(9171, + QP::QActive::post_, + QP::QActive::postLIFO) + +// BARR-C:2018 R 6.2c return statement before end of function +-efunc(904, + QP::QActive::post_, + QP::QActive::postLIFO) + +// [AC++M5-2-2]: casting from base class to derived class (QP::QActiveDummy) +-efunc(1939, + QP::QActive::post_, + QP::QActive::postLIFO) + +// PCLP-1731: public virtual function (in a class without virtual destructor) +-esym(1731, + QP::QTicker::*) + + // PCLP-1933: call to unqualified virtual function from non-static member function +-efunc(1933, + QP::QActive::start) + +// PCLP-9079: +-efunc(9079, + QP::QF::bzero_, + QP::QTimeEvt::armX, + QP::QTimeEvt::disarm, + QP::QTimeEvt::rearm, + QP::QMPool::init, + QP::QMPool::get, + QP::QMPool::put) + + +// QV ------------------------------------------------------------------------ +// MC++R16-0-4 function-like macro +-esym(9026, + QV_CPU_SLEEP) + + +// QK ------------------------------------------------------------------------ + +// MC++R16-0-4 function-like macro +-esym(9026, + QK_ISR_CONTEXT_, + QK_ISR_ENTRY, + QK_ISR_EXIT) + + +// QXK ----------------------------------------------------------------------- +// MC++R16-0-4 function-like macro +-esym(9026, + QXK_ISR_CONTEXT_, + QXK_CONTEXT_SWITCH_, + QXK_PTR_CAST_, + QXTHREAD_CAST_, + QXTHREAD_EQUEUE_SIGNAL_) + +// MC++R10-0-6 unparenthesized macro parameter in definition of macro +-esym(9022, + QXK_PTR_CAST_) + +// MC++R5-2-7 pointer type converted to unrelated pointer +-emacro(9176, + Q_STATE_CAST) + +// M3-R11.3(r) cast to pointer to different object type +//-emacro(9087, +// QXK_PTR_CAST_, +// QXTHREAD_CAST_) + +// MC++R5-2-7 pointer type converted to unrelated pointer type +-emacro(9176, + QXK_PTR_CAST_) + +// MC++R5-2-3 downcast of polymorphic type ... to type ... +-emacro(9171, + QXK_PTR_CAST_) + +// casting from base class 'QP::QActive' to derived class +-emacro(1939, + QXK_PTR_CAST_) + +// suspicious pointer-to-pointer conversion (area too small) +-emacro(826, + QXK_PTR_CAST_, + QXTHREAD_CAST_) + + +// QS ------------------------------------------------------------------------ +// the following options are needed only when Q_SPY is defined + +// MC++R16-0-4 function-like macro +-esym(9026, + QS_CRIT_ENTRY, + QS_CRIT_EXIT, + QS_MEM_SYS, + QS_MEM_APP, + QS_PTR_AT_, + QS_PTR_INC_, + QS_INSERT_BYTE_, + QS_INSERT_ESC_BYTE_, + QS_REC_NUM_) + +// M3-R14.3(r) boolean condition for 'if' always evaluates to 'false' +-emacro(774,, + QS_INSERT_BYTE_, + QS_INSERT_ESC_BYTE_, + QS_BEGIN_PRE_, + QS_BEGIN_PRE_) + +// the right operand to << always evaluates to 0 +-emacro(845, + QS_BEGIN_PRE_, + QS_BEGIN_PRE_) + +// excessive shift value (precision 3 shifted right by 3) +-emacro(572, + QS_BEGIN_PRE_, + QS_BEGIN_PRE_) + +// constant expression evaluates to 0 in 'binary' operation '>>' +-emacro(778, + QS_BEGIN_PRE_, + QS_BEGIN_PRE_) + +// constant value used in Boolean context +-emacro(506, + QS_BEGIN_PRE_, + QS_BEGIN_PRE_) + +// bitwise operator '>>' applied to signed underlying type [AS-M5-0-21] +-emacro(9130, + QS_BEGIN_PRE_, + QS_BEGIN_PRE_) + +// use of c-style cast to void [AS-A5-2-2] +-emacro(1954, + QS_END_PRE_) + +// MC++R0-1-9 operator == always evaluates to true +-emacro(948, + QS_BEGIN_PRE_) + +// MC++R0-1-1, MC++R0-1-2, MC++R0-1-9 +// left operand to '||' always evaluates to 'true' +-emacro(944, + QS_BEGIN_PRE_) + +// MC++R5-2-9 casting from pointer type to integer type +-emacro(9091, + QS_OBJ_PRE_, + QS_FUN_PRE_) + +// M3-R11.6(r) explicit cast from 'void *volatile' to 'uint32_t' +//-emacro(923, +// QS_OBJ_PRE_, +// QS_FUN_PRE_) + +// M3-R11.1(4) conversion between pointer to function and differing type +//-emacro(9074, +// QS_FUN_PRE_) + +// definition of macro ends in semi-colon +-esym(823, + QS_CRIT_STAT, + QS_BEGIN_PRE_) + +// union initialization +-efunc(708, + QS_f64_fmt_) + +// M3-R19.2(a) union declared +-efunc(9018, + QS_f32_fmt_, + QS_f64_fmt_) + +// MC++R10-0-6 unparenthesized macro parameter in definition of macro +-esym(9022, + QS_TEST_PROBE, + QS_TEST_PROBE_ID) + +// AR M5-0-10 the result of the ~ operator applied to an object with an +// underlying type of 'unsigned char' must be cast to 'unsigned char' +// in this context +-efunc(9126, + QP::QS::glbFilter_, + QP::QS::locFilter_) + +// don't report problems within QS_target_info_() function +-efunc(9130, + QP::QS_target_info_) +-efunc(9114, + QP::QS_target_info_) +-efunc(9117, + QP::QS_target_info_) +-efunc(9125, + QP::QS_target_info_) +-efunc(9112, + QP::QS_target_info_) +-efunc(9128, + QP::QS_target_info_) +-efunc(737, + QP::QS_target_info_) + diff --git a/ports/lint-plus2/qk/qp_port.hpp b/ports/lint-plus2/qk/qp_port.hpp new file mode 100644 index 00000000..89d9a211 --- /dev/null +++ b/ports/lint-plus2/qk/qp_port.hpp @@ -0,0 +1,101 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software +// +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2023-09-07 +//! @version Last updated for: @ref qpcpp_7_3_0 +//! +//! @file +//! @brief QP/C++ port for QK kernel, Generic C++11 + +#ifndef QP_PORT_HPP_ +#define QP_PORT_HPP_ + +#include // Exact-width types. C++11 Standard + +#ifdef QP_CONFIG +#include "qp_config.hpp" // external QP configuration +#endif + +// no-return function specifier (C++11 Standard) +#define Q_NORETURN [[ noreturn ]] void + +// QF configuration for QK -- data members of the QActive class... + +// QK event-queue used for AOs +#define QACTIVE_EQUEUE_TYPE QEQueue + +// QF "thread" type used to store the MPU settings in the AO +#define QACTIVE_THREAD_TYPE void const * + +// interrupt disabling mechanism +#define QF_INT_DISABLE() intDisable() +#define QF_INT_ENABLE() intEnable() + +// QF critical section mechanism +#define QF_CRIT_STAT std::uint32_t crit_stat_; +#define QF_CRIT_ENTRY() (crit_stat_ = critEntry()) +#define QF_CRIT_EXIT() critExit(crit_stat_) + +// Check if the code executes in the ISR context +#define QK_ISR_CONTEXT_() (QK_get_IPSR() != 0U) + +// Define the ISR entry sequence +#define QK_ISR_ENTRY() (static_cast(0)) + +// Define the ISR exit sequence +#define QK_ISR_EXIT() \ +do { \ + QF_INT_DISABLE(); \ + --QK_priv_.intNest; \ + if (QK_priv_.intNest == 0U) { \ + if (QK_sched_() != 0U) { \ + QK_activate_(); \ + } \ + } \ + QF_INT_ENABLE(); \ +} while (false) + +extern "C" { + +void intDisable(void); +void intEnable(void); +std::uint32_t critEntry(void); +void critExit(std::uint32_t stat); +std::uint32_t QK_get_IPSR(void); + +} // extern "C" + +// include files ------------------------------------------------------------- +#include "qequeue.hpp" // QK kernel uses the native QP event queue +#include "qmpool.hpp" // QK kernel uses the native QP memory pool +#include "qp.hpp" // QP framework +#include "qk.hpp" // QK kernel + +#endif // QP_PORT_HPP_ + diff --git a/ports/lint-plus2/qpcpp.lnt b/ports/lint-plus2/qpcpp.lnt new file mode 100644 index 00000000..dd1d1eb1 --- /dev/null +++ b/ports/lint-plus2/qpcpp.lnt @@ -0,0 +1,459 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2024-02-18 +//! @version Last updated for version: 7.3.3 +//! +//! @file +//! @brief PC-Lint-Plus option file for linting QP/C++ __Applications__ + +//---------------------------------------------------------------------------- +// globally suppress the following warnings: +-e546 // explicitly taking address of function +-e717 // monocarpic do-while used to group statements +-e1756 // variable has 'static' storage duration and non-POD type +-e3412 // class has virtual functions but non-virtual destructor + +// Assertions ---------------------------------------------------------------- + +// give Q_onError() the semantics of "exit" +-function(exit, + Q_onError) + +// C-style array type [AUTOSAR Rule A18-1-1] +-esym(9436, + QP::versionStr) + +// AC++M16-3-2 function-like macro +-esym(9026, + Q_DEFINE_THIS_MODULE, + Q_ASSERT_STATIC, + Q_ASSERT, + Q_ASSERT_ID, + Q_ERROR, + Q_ERROR_ID, + Q_REQUIRE, + Q_REQUIRE_ID, + Q_ENSURE, + Q_ENSURE_ID, + Q_INVARIANT, + Q_INVARIANT_ID, + Q_DIM) + +// use of c-style cast to void [AS-A5-2-2] +-emacro(1954, + Q_ASSERT, + Q_ASSERT_ID, + Q_ERROR, + Q_ERROR_ID, + Q_REQUIRE, + Q_REQUIRE_ID, + Q_ENSURE, + Q_ENSURE_ID, + Q_INVARIANT, + Q_INVARIANT_ID, + Q_ASSERT_INCRIT) + +// MC++R10-0-6 unparenthesized macro parameter in definition of macro +-esym(9022, + Q_DEFINE_THIS_FILE, + Q_DEFINE_THIS_MODULE) + +// definition of macro ends in semi-colon +-esym(823, + Q_DEFINE_THIS_FILE, + Q_DEFINE_THIS_MODULE) + +// AC++M16-3-2 function-like macro +-esym(9026, + Q_UNUSED_PAR, + Q_DIM, + Q_UINT2PTR_CAST, + Q_UINTPTR_CAST_) + +// MC++R5-2-4 use of c-style cast +-emacro(1924, + Q_ASSERT, + Q_ASSERT_ID, + Q_ERROR, + Q_ERROR_ID) + + +// QEP ----------------------------------------------------------------------- + +// MC++R7-3-1 global declaration of symbol +-esym(9141, + char_t, + int_t, + enum_t, + float32_t, + float64_t) + +// AUTOSAR Rule A3-3-2 non-private data member within a non-POD structure +// NOTE: public access needed for extern "C" functions +-esym(9150, + QP::QAsmAttr::*, + QP::QAsm::*) + +// AC++M16-3-2 function-like macro +-esym(9026, + INIT, + DISPATCH, + Q_STATE_DECL, + Q_STATE_DEF, + QM_STATE_DECL, + QM_STATE_DEF, + QM_SM_STATE_DECL, + QM_ACTION_DECL, + QM_ACTION_DEF, + QHSM_INIT, + QHSM_DISPATCH, + Q_TRAN, + Q_TRAN_HIST, + Q_SUPER, + Q_HANDLED, + Q_UNHANDLED, + QM_ENTRY, + QM_EXIT, + QM_SM_EXIT, + QM_TRAN, + QM_TRAN_INIT, + QM_TRAN_HIST, + QM_TRAN_EP, + QM_TRAN_XP, + QM_SUPER, + QM_SUPER_SUB, + QM_HANDLED, + QM_UNHANDLED, + Q_HSM_UPCAST, + Q_EVT_CAST, + Q_STATE_CAST, + Q_UINT2PTR_CAST) + +// MC++R5-2-8 conversion from pointer to other pointer type +-emacro(9079, + Q_EVT_CAST) + +// MC++R5-2-2 casting from base class 'QP::QEvt' to derived class +-emacro(1939, + Q_EVT_CAST) + +// MC++R10-0-6 unparenthesized macro parameter 'class_' in definition of macro +-esym(9022, + Q_EVT_CAST, + Q_UINT2PTR_CAST, + Q_STATE_DECL, + Q_STATE_DEF, + QM_STATE_DECL, + QM_STATE_DEF, + QM_SM_STATE_DECL, + QM_ACTION_DECL, + QM_ACTION_DEF, + QEP_TRIG_, + QEP_ENTER_, + QEP_EXIT_) + +// MC++16-3-1 multiple use of stringize/pasting operators in definition of macro +-esym(9023, + Q_STATE_DECL, + Q_STATE_DEF, + QM_STATE_DECL, + QM_STATE_DEF, + QM_SM_STATE_DECL, + QM_ACTION_DEF) + +// AC++M16-3-2 stringize operator used in definition of function-like macro +-esym(9024, + Q_STATE_DECL, + Q_STATE_DEF, + QM_STATE_DECL, + QM_STATE_DEF, + QM_SM_STATE_DECL, + QM_ACTION_DECL, + QM_ACTION_DEF) + +// MC++R5-2-8 conversion from pointer to void to other pointer type +-emacro(9079, + Q_STATE_DEF, + QM_STATE_DEF, + QM_ACTION_DEF) + + // MC++R9-3-3 member function could be made const +-emacro(1762, + Q_STATE_DEF, + QM_STATE_DEF) + +// MC++9-5-1 union declared +-esym(9018, + QP::QAsmAttr) + +// MC++5-2-8 conversion from integer type (0) to pointer type +-emacro(9010, + Q_STATE_CAST) + +// public virtual function 'QP::QHsm::...' +-esym(1731, + QP::QHsm::*, + QP::QMsm::*) + + +// QF ------------------------------------------------------------------------ + +// AUTOSAR Rule A3-3-2 non-private data member within a non-POD structure +// NOTE: public access needed for extern "C" functions +-esym(9150, + QP::QF::QF_Attr::*) + +// AC++M16-3-2 function-like macro +-esym(9026, + POST, + POST_X, + PUBLISH, + TICK_X, + TICK, + TRIG, + QF_INT_DISABLE, + QF_INT_ENABLE, + QF_CRIT_EXIT_NOP, + QF_LOG2, + Q_PRIO, + Q_NEW, + Q_NEW_X, + Q_NEW_REF, + Q_DELETE_REF, + QF_INT_DISABLE, + QF_INT_ENABLE, + QF_MPOOL_EL) + +// MC++R0-3-2 ignoring return value of function +-emacro(534, + POST) + +// [AUTOSAR Rule M17-0-2] the name xxx is reserved to the compiler +-esym(9093, + remove) // QPrioSet::remove() + +// MC++R5-2-7 pointer type converted to unrelated pointer type +-emacro(9176, + QF_QMACTIVE_TO_QMSM_CAST_, + QF_QMACTIVE_TO_QMSM_CONST_CAST_) + +// MC++R5-2-2 casting from base class 'QP::QEvt' to derived class +-emacro(1939, + Q_NEW, + Q_NEW_X) + +// MC++R10-0-6 unparenthesized macro parameter in definition of macro +-esym(9022, + Q_NEW, + Q_NEW_X, + Q_NEW_REF) + + +// QK ------------------------------------------------------------------------ + +// AC++M16-3-2 function-like macro +-esym(9026, + QK_ISR_ENTRY, + QK_ISR_EXIT) + +// AC++M7-3-1 global declaration of symbol +-esym(9141, + QK_Attr) + +// MC++R11-0-1 non-private data member within a non-POD structure +// NOTE: public access needed for extern "C" functions +-esym(9150, + QK_Attr::*) + + +// QXK ----------------------------------------------------------------------- +// MC++R16-0-4 function-like macro +-esym(9026, + QXK_ISR_ENTRY, + QXK_ISR_EXIT, + QXK_TLS) + +// MC++R7-3-1 global declaration of symbol +-esym(9141, + QXK_Attr) + +// MC++R10-0-6 unparenthesized macro parameter in definition of macro +-esym(9022, + QXK_TLS) + +// MC++R5-2-8 conversion from pointer to void to other pointer type +-emacro(9079, + QXK_PTR_CAST_) + +// MC++R5-2-2 casting from base class to derived class +-emacro(1939, + QXTHREAD_CAST_) + +// MC++R5-2-3 downcast of polymorphic type +-emacro(9171, + QXTHREAD_CAST_) + +// [AUTOSAR Rule M17-0-2] the name 'signal' is reserved to the compiler +-esym(9093, + signal) + +// public virtual function 'QP::QXThread::...' +-esym(1731, + QP::QXThread::*) + +// [AUTOSAR Rule M8-4-2] parameter of function has different name than +// overridden function +-esym(9272, + QP::QXMutex::init*) + +// function xxx matches the name of a standard library function +-esym(8502, + signal) // QXSemaphore::signal() + + +// QS ------------------------------------------------------------------------ + +// AC++M16-3-2 function-like macro +-esym(9026, + QS_INIT, + QS_EXIT, + QS_DUMP, + QS_RESET, + QS_GLB_FILTER, + QS_LOC_FILTER, + QS_FILTER_AP_OBJ, + QS_GET_BYTE, + QS_GET_BLOCK, + QS_BEGIN_ID, + QS_END, + QS_BEGIN_INCRIT, + QS_END_INCRIT, + QS_QF_CRIT_ENTRY, + QS_QF_CRIT_EXIT, + QS_QF_ISR_ENTRY, + QS_QF_ISR_EXIT, + QS_ONLY, + QS_I8, + QS_U8, + QS_I16, + QS_U16, + QS_I32, + QS_I64, + QS_U32, + QS_F32, + QS_F64, + QS_U64, + QS_U32_HEX, + QS_STR, + QS_OBJ, + QS_FUN, + QS_SIG_DICTIONARY, + QS_OBJ_DICTIONARY, + QS_OBJ_ARR_DICTIONARY, + QS_FUN_DICTIONARY, + QS_USR_DICTIONARY, + QS_ENUM_DICTIONARY, + QS_ASSERTION, + QS_FLUSH, + QS_MEM, + QS_ENUM, + QS_SIG, + QS_PTR_AT_, + QS_RX_PUT, + QS_OUTPUT, + QS_RX_INPUT, + QS_TEST_PAUSE, + QS_TEST_PROBE_DEF, + QS_TEST_PROBE, + QS_TEST_PROBE_ID) + +// AC++M16-3-2 function-like macro +-esym(9026, + QS_GLB_CHECK_, + QS_LOC_CHECK_, + QS_BEGIN_PRE_, + QS_END_PRE_, + QS_BEGIN_PRE_, + QS_END_PRE_, + QS_U8_PRE_, + QS_2U8_PRE_, + QS_U16_PRE_, + QS_U32_PRE_, + QS_STR_PRE_, + QS_TIME_PRE_, + QS_SIG_PRE_, + QS_EVS_PRE_, + QS_OBJ_PRE_, + QS_FUN_PRE_, + QS_EQC_PRE_, + QS_MPC_PRE_, + QS_MPS_PRE_, + QS_TEC_PRE_) + +// AC++M16-3-2 function-like macro +-esym(9026, + QS_REC_DONE) + +// definition of macro ends in semi-colon +-esym(823, + QS_TEST_PROBE_DEF) + +// M3-R11.1(r) conversion between pointer to function type +-emacro(9074, + QS_FUN_DICTIONARY, + QS_TEST_PROBE_DEF) + +// AC++M16-3-2 stringize operator used in definition of function-like macro +-esym(9024, + QS_OBJ_DICTIONARY, + QS_OBJ_ARR_DICTIONARY, + QS_FUN_DICTIONARY, + QS_SIG_DICTIONARY, + QS_USR_DICTIONARY, + QS_ENUM_DICTIONARY) + +// M3-R10.3(r) cannot assign enum to different essential type +-emacro(9034, + QS_SIG_DICTIONARY) + +// implicit conversion of enum to integral type 'int' +-emacro(641, + QS_SIG_DICTIONARY) + +// MC++R11-0-1 non-private data member within a non-POD structure +-esym(9150, + QP::QEvt::*, + QP::QActive::*, + QP::QF::Attr::*, + QP::QS::QSrxPriv::*) + +// MC++9-5-1 union declared +-esym(9018, + F32Rep, + F64Rep, + U32Rep, + TCast, + QP::QS::RxAttr::Variant) + diff --git a/ports/lint-plus2/qv/qp_port.hpp b/ports/lint-plus2/qv/qp_port.hpp new file mode 100644 index 00000000..9c7c7be2 --- /dev/null +++ b/ports/lint-plus2/qv/qp_port.hpp @@ -0,0 +1,89 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software +// +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2023-09-07 +//! @version Last updated for: @ref qpcpp_7_3_0 +//! +//! @file +//! @brief QP/C++ port for QV kernel, Generic C++ + +#ifndef QP_PORT_HPP_ +#define QP_PORT_HPP_ + +#include // Exact-width types. C++11 Standard + +#ifdef QP_CONFIG +#include "qp_config.hpp" // external QP configuration +#endif + +// no-return function specifier (C++11 Standard) +#define Q_NORETURN [[ noreturn ]] void + +// QF configuration for QV -- data members of the QActive class... + +// QV event-queue used for AOs +#define QACTIVE_EQUEUE_TYPE QEQueue + +// QF "thread" type used to store the MPU settings in the AO +#define QACTIVE_THREAD_TYPE void const * + +// interrupt disabling mechanism +#define QF_INT_DISABLE() intDisable() +#define QF_INT_ENABLE() intEnable() + +// QF critical section mechanism +#define QF_CRIT_STAT std::uint32_t crit_stat_; +#define QF_CRIT_ENTRY() (crit_stat_ = critEntry()) +#define QF_CRIT_EXIT() critExit(crit_stat_) + +#define QV_CPU_SLEEP() \ +do { \ + __disable_interrupt(); \ + QF_INT_ENABLE(); \ + __WFI(); \ + __enable_interrupt(); \ +} while (false) + +extern "C" { + +void intDisable(void); +void intEnable(void); +std::uint32_t critEntry(void); +void critExit(std::uint32_t stat); + +} // extern "C" + +// include files ------------------------------------------------------------- +#include "qequeue.hpp" // QV kernel uses the native QP event queue +#include "qmpool.hpp" // QV kernel uses the native QP memory pool +#include "qp.hpp" // QP framework +#include "qv.hpp" // QV kernel + +#endif // QP_PORT_HPP_ + diff --git a/ports/lint-plus2/qxk/qp_port.hpp b/ports/lint-plus2/qxk/qp_port.hpp new file mode 100644 index 00000000..3211158c --- /dev/null +++ b/ports/lint-plus2/qxk/qp_port.hpp @@ -0,0 +1,104 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software +// +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2023-09-07 +//! @version Last updated for: @ref qpcpp_7_3_0 +//! +//! @file +//! @brief QP/C++ port for QXK kernel, Generic C++ + +#ifndef QP_PORT_HPP_ +#define QP_PORT_HPP_ + +#include // Exact-width types. C++11 Standard + +#ifdef QP_CONFIG +#include "qp_config.hpp" // external QP configuration +#endif + +// no-return function specifier (C++11 Standard) +#define Q_NORETURN [[ noreturn ]] void + +// QF configuration for QXK -- data members of the QActive class... + +// QXK event-queue type used for AOs and eXtended threads. +#define QACTIVE_EQUEUE_TYPE QEQueue + +// QXK OS-Object type used for the private stack pointer for eXtended threads. +// (The private stack pointer is NULL for basic-threads). +#define QACTIVE_OS_OBJ_TYPE void* + +// QF "thread" type used to store the MPU settings in the AO +#define QACTIVE_THREAD_TYPE void const * + +// interrupt disabling mechanism +#define QF_INT_DISABLE() intDisable() +#define QF_INT_ENABLE() intEnable() + +// QF critical section mechanism +#define QF_CRIT_STAT std::uint32_t crit_stat_; +#define QF_CRIT_ENTRY() (crit_stat_ = critEntry()) +#define QF_CRIT_EXIT() critExit(crit_stat_) + +// Check if the code executes in the ISR context +#define QXK_ISR_CONTEXT_() (QXK_get_IPSR() != 0U) + +// Define the ISR entry sequence +#define QXK_ISR_ENTRY() (static_cast(0)) + +// Define the ISR exit sequence +#define QXK_ISR_EXIT() do { \ + QF_INT_DISABLE(); \ + if (QXK_sched_() != 0U) { \ + *Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) = (1U << 28U);\ + } \ + QF_INT_ENABLE(); \ +} while (false) + +#define QXK_CONTEXT_SWITCH_() (QXK_trigPendSV()) + +extern "C" { + +void intDisable(void); +void intEnable(void); +std::uint32_t critEntry(void); +void critExit(std::uint32_t stat); +std::uint32_t QXK_get_IPSR(void); +void QXK_trigPendSV(void); + +} // extern "C" + +// include files ------------------------------------------------------------- +#include "qequeue.hpp" // QK kernel uses the native QP event queue +#include "qmpool.hpp" // QK kernel uses the native QP memory pool +#include "qp.hpp" // QP framework +#include "qxk.hpp" // QXK kernel + +#endif // QP_PORT_HPP_ + diff --git a/ports/lint-plus2/std.lnt b/ports/lint-plus2/std.lnt new file mode 100644 index 00000000..0b77cdb5 --- /dev/null +++ b/ports/lint-plus2/std.lnt @@ -0,0 +1,45 @@ +//============================================================================ +// QP/C++ Real-Time Embedded Framework (RTEF) +// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial +// +// This software is dual-licensed under the terms of the open source GNU +// General Public License version 3 (or any later version), or alternatively, +// under the terms of one of the closed source Quantum Leaps commercial +// licenses. +// +// The terms of the open source GNU General Public License version 3 +// can be found at: +// +// The terms of the closed source Quantum Leaps commercial licenses +// can be found at: +// +// Redistributions in source code must retain this top-level comment block. +// Plagiarizing this software to sidestep the license obligations is illegal. +// +// Contact information: +// +// +//============================================================================ +//! @date Last updated on: 2023-08-08 +//! @version Last updated for version: 7.3.0 +//! +//! @file +//! @brief PC-Lint-Plus standard option file + +// message formatting options... +-hF1 // output: a single line ++ffn // use full path names +//-"format=%(\q%f\q %l %C%) %t %n: %m" +//-width(0,0) // do not break lines +-width(120,4) // break lines after 99 characters with 4 characters indent ++flm // make sure no foreign includes change the format + ++rw(inline, entry) + +-zero(99) // don't stop because of warnings +-passes(2) // make two passes (for better error messages) +-restore_at_end // don't let -e options bleed to other files +-summary() // produce a summary of all produced messages + diff --git a/ports/win32/Makefile b/ports/win32/Makefile deleted file mode 100644 index a6aaa8f2..00000000 --- a/ports/win32/Makefile +++ /dev/null @@ -1,226 +0,0 @@ -############################################################################## -# QP/C++ Real-Time Embedded Framework (RTEF) -# -# Q u a n t u m L e a P s -# ------------------------ -# Modern Embedded Software -# -# Copyright (C) 2005 Quantum Leaps, LLC, . -# -# SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial -# -# This software is dual-licensed under the terms of the open source GNU -# General Public License version 3 (or any later version), or alternatively, -# under the terms of one of the closed source Quantum Leaps commercial -# licenses. -# -# The terms of the open source GNU General Public License version 3 -# can be found at: -# -# The terms of the closed source Quantum Leaps commercial licenses -# can be found at: -# -# Redistributions in source code must retain this top-level comment block. -# Plagiarizing this software to sidestep the license obligations is illegal. -# -# Contact information: -# -# -############################################################################## -# examples of invoking this Makefile: -# building configurations: Debug (default), Release and Spy -# make -# make CONF=rel -# make CONF=spy -# -# cleaning configurations: Debug (default), Release, and Spy -# make clean -# make CONF=rel clean -# make CONF=spy clean -# -# NOTE: -# To use this Makefile on Windows, you will need the GNU make utility, which -# is included in the QTools collection for Windows, see: -# https://github.com/QuantumLeaps/qtools -# - -#----------------------------------------------------------------------------- -# project name: -# -PROJECT := qp - -#----------------------------------------------------------------------------- -# project directories: -# - -# location of the QP/C++ framework -QPCPP := ../.. - -# QP port used in this project -QP_PORT_DIR := . - -# list of all source directories used by this project -VPATH = \ - $(QPCPP)/src/qf \ - $(QPCPP)/src/qs \ - $(QP_PORT_DIR) - -# list of all include directories needed by this project -INCLUDES = \ - -I$(QPCPP)/include \ - -I$(QPCPP)/src \ - -I$(QP_PORT_DIR) - -#----------------------------------------------------------------------------- -# files -# - -# C source files -C_SRCS := \ - qwin_gui.c - -# C++ source files -CPP_SRCS := \ - qep_hsm.cpp \ - qep_msm.cpp \ - qf_actq.cpp \ - qf_defer.cpp \ - qf_dyn.cpp \ - qf_mem.cpp \ - qf_ps.cpp \ - qf_qact.cpp \ - qf_qeq.cpp \ - qf_qmact.cpp \ - qf_time.cpp \ - qf_port.cpp - -# C++ QS source files -CPP_QS_SRCS := \ - qs.cpp \ - qs_rx.cpp \ - qs_fp.cpp \ - qs_64bit.cpp \ - qs_port.cpp - -# defines: -DEFINES := -DQWIN_GUI -DQP_API_VERSION=9999 - -#----------------------------------------------------------------------------- -# MinGW toolset (NOTE: assumed to be on your PATH) -# -# NOTE: -# MinGW toolset is included in the Qtools collection for Windows, see: -# https://github.com/QuantumLeaps/qtools - -CC := gcc -CPP := g++ -LIB := ar - - -############################################################################## -# Typically, you should not need to change anything below this line - -# basic utilities (included in Qtools for Windows), see: -# https://github.com/QuantumLeaps/qtools - -MKDIR := mkdir -RM := rm - -#----------------------------------------------------------------------------- -# build options for various configurations -# - -LIBFLAGS := rs - -ifeq (rel, $(CONF)) # Release configuration ................................. - -BIN_DIR := rel - -# gcc options: -CFLAGS := -c -O3 -fno-pie -std=c99 -pedantic -Wall -Wextra -W \ - $(INCLUDES) $(DEFINES) -DNDEBUG - -CPPFLAGS := -c -O3 -fno-pie -std=c++11 -pedantic -Wall -Wextra \ - -fno-rtti -fno-exceptions \ - $(INCLUDES) $(DEFINES) -DNDEBUG - -else ifeq (spy, $(CONF)) # Spy configuration ................................ - -BIN_DIR := spy - -# add the QS sources... -C_SRCS += $(C_QS_SRCS) - -# gcc options: -CFLAGS := -c -g -O -fno-pie -std=c99 -pedantic -Wall -Wextra -W \ - $(INCLUDES) $(DEFINES) -DQ_SPY - -CPPFLAGS := -c -g -O -fno-pie -std=c++11 -pedantic -Wall -Wextra \ - -fno-rtti -fno-exceptions \ - $(INCLUDES) $(DEFINES) -DQ_SPY - -else # default Debug configuration ......................................... - -BIN_DIR := dbg - -# gcc options: -CFLAGS := -c -g -O -fno-pie -std=c99 -pedantic -Wall -Wextra -W \ - $(INCLUDES) $(DEFINES) - -CPPFLAGS := -c -g -O -fno-pie -std=c++11 -pedantic -Wall -Wextra \ - -fno-rtti -fno-exceptions \ - $(INCLUDES) $(DEFINES) - -endif - -#----------------------------------------------------------------------------- -C_OBJS := $(patsubst %.c,%.o, $(notdir $(C_SRCS))) -CPP_OBJS := $(patsubst %.cpp,%.o,$(notdir $(CPP_SRCS))) - -TARGET_LIB := $(BIN_DIR)/lib$(PROJECT).a -C_OBJS_EXT := $(addprefix $(BIN_DIR)/, $(C_OBJS)) -C_DEPS_EXT := $(patsubst %.o,%.d, $(C_OBJS_EXT)) -CPP_OBJS_EXT := $(addprefix $(BIN_DIR)/, $(CPP_OBJS)) -CPP_DEPS_EXT := $(patsubst %.o,%.d, $(CPP_OBJS_EXT)) - -# create $(BIN_DIR) if it does not exist -ifeq ("$(wildcard $(BIN_DIR))","") -$(shell $(MKDIR) $(BIN_DIR)) -endif - -#----------------------------------------------------------------------------- -# rules -# - -all: $(TARGET_LIB) - -$(RM) $(BIN_DIR)/*.o - -$(TARGET_LIB) : $(ASM_OBJS_EXT) $(C_OBJS_EXT) $(CPP_OBJS_EXT) - $(LIB) $(LIBFLAGS) $@ $^ - -$(BIN_DIR)/%.o : %.c - $(CC) $(CFLAGS) $< -o $@ - -$(BIN_DIR)/%.o : %.cpp - $(CPP) $(CPPFLAGS) $< -o $@ - -#----------------------------------------------------------------------------- -# the clean target -# -.PHONY : clean -clean: - -$(RM) $(BIN_DIR)/*.o $(TARGET_LIB) - -#----------------------------------------------------------------------------- -# the show target for debugging -# -show: - @echo PROJECT = $(PROJECT) - @echo CONF = $(CONF) - @echo TARGET_LIB = $(TARGET_LIB) - @echo C_SRCS = $(C_SRCS) - @echo CPP_SRCS = $(CPP_SRCS) - @echo C_OBJS_EXT = $(C_OBJS_EXT) - @echo C_DEPS_EXT = $(C_DEPS_EXT) - @echo CPP_OBJS_EXT = $(CPP_OBJS_EXT) - @echo CPP_DEPS_EXT = $(CPP_DEPS_EXT) diff --git a/qpcpp.md5 b/qpcpp.md5 index 655bd5af..ae799bdc 100644 --- a/qpcpp.md5 +++ b/qpcpp.md5 @@ -1,51 +1,51 @@ -27d2d0d96374af4853a6a31a25ac3ef8 *qpcpp.qm -da3f0e1d1bc147b9e5ee801bc1fdd130 *include/qequeue.hpp +0c7051849804080425142a71b1e9b13b *qpcpp.qm +2c7717f261e842ae0449a321d3c50f3e *include/qequeue.hpp fe1ff6084ff592ca8d14a6efffec296c *include/qk.hpp -ebf2cb455c1471c2248bbde4b90ce634 *include/qmpool.hpp -344c0ecb3d7f5645a5f4e75aea7956ac *include/qp.hpp +0cf7c36bbbca2e0ebfe61347e9e572e5 *include/qmpool.hpp +1290aa2707d23ea765a131a4c30d7ce9 *include/qp.hpp 61c7a3aa8cb265f478915f39b7fae9cc *include/qp_pkg.hpp 81e2fed348f03200d00b4d7c4473826f *include/qpcpp.hpp be2da5d56117fd172f12c8b6589f6402 *include/qs.hpp d59808009be96849963572ffcbf9dceb *include/qs_dummy.hpp db4013ceefb33498f5d38e15d0cb9323 *include/qs_pkg.hpp -2a36b08d4f3ec92da6ae6f7c18ad83ca *include/qsafe.h +f59bf88705afe5b0acc999f8b47a6745 *include/qsafe.h e66cf5dd191fb0e7c1f8660fb477b860 *include/qstamp.hpp d42a19307ba3c0c5b890431767f35b42 *include/qv.hpp c0bc33e3823dde00803a301c4b85637d *include/qxk.hpp ccc88dc7734a312ee0e33c437db7f3eb *src/qf/CMakeLists.txt -88c84e634597fafced2012faea838750 *src/qf/qep_hsm.cpp -becbd953c6da010daddf4907784e9766 *src/qf/qep_msm.cpp +43c0ce7d29c9dd18691899c883b3f5eb *src/qf/qep_hsm.cpp +dec4234285d4efd40b3ae6f680bc7179 *src/qf/qep_msm.cpp 8b5c1ece58069ed5582864fd2dc58167 *src/qf/qf_act.cpp -8fca896aa3dee712f6c844a0f31c130e *src/qf/qf_actq.cpp +eba1e6d624f4b1c7c82b2f98ef3e9198 *src/qf/qf_actq.cpp 39b02b596faa57abfa96b0f7c3f7fb82 *src/qf/qf_defer.cpp -069220fa20ca5bd9e0ddfcb2f4f8f0ba *src/qf/qf_dyn.cpp -0d3572af3a2acbf7144b27be35fa018a *src/qf/qf_mem.cpp -40218fcd6cbb521f2c8ae5f7c0d5c04e *src/qf/qf_ps.cpp +7b797a3a69836d0aba3c600130606f01 *src/qf/qf_dyn.cpp +f23875214b4c4c905bdb0567d900b36b *src/qf/qf_mem.cpp +37cfa5b9419f1e00608267ff29fbc1a8 *src/qf/qf_ps.cpp 19cf8976578a43e93bfbb51dbe932b6c *src/qf/qf_qact.cpp 46f954811c55e933e016bb36ab22adcd *src/qf/qf_qeq.cpp 816dc7182f4014539f6f5304782ddb7b *src/qf/qf_qmact.cpp -c49e1c15e6d6e035668d910c8d13a684 *src/qf/qf_time.cpp +c551aafbf9ecba93cfdb12f81fbfba61 *src/qf/qf_time.cpp 4dc7ca60248f4c13034e6f2481c7663d *src/qk/CMakeLists.txt -5670063d7e71927b7d5c98a6db38c351 *src/qk/qk.cpp +1a314e2a9fba927f6648772121790c5f *src/qk/qk.cpp 2557d617414f8cbdcbfeaab619d296bb *src/qs/CMakeLists.txt -ecdd6f0f0a7dc56d8bb0c769e67b48fc *src/qs/qs.cpp +bd1870c2a952b47ef613cc67406aca80 *src/qs/qs.cpp a2ca20b2332d025067645839e4b25711 *src/qs/qs_64bit.cpp 8f6551c7786fdbb106c3d1bc7824c060 *src/qs/qs_fp.cpp 4af89f114491668f7a26af694ff11993 *src/qs/qs_rx.cpp 2655cd10d009075b71a84368fb6bf4d4 *src/qs/qstamp.cpp 180d454ecdbd08f522ff9a9c299de5df *src/qs/qutest.cpp cf2fae9b29aab50c5cd69d7d519cb0db *src/qv/CMakeLists.txt -80b65ecb456e0a8efaaa14f7f30aac81 *src/qv/qv.cpp +abfb725ec432f1f56b72e2be4c62e9d3 *src/qv/qv.cpp 3c916b7d6a6ce58963153f51801858df *src/qxk/CMakeLists.txt -9a0b0803b84b7c4cf0fe1e34187371f8 *src/qxk/qxk.cpp -efe0395b16911eaff880649a9968d6a3 *src/qxk/qxk_mutex.cpp +7fed39c66ef913b79b82116b54af21de *src/qxk/qxk.cpp +309a3f6772f0cadfa8e50b545852b995 *src/qxk/qxk_mutex.cpp ce5ff1926bd91dd8683e0232d3e1d471 *src/qxk/qxk_sema.cpp 78ec1d0d6aa9efbdc8b3d09e6deea40e *src/qxk/qxk_xthr.cpp bf56a383eb7dafafa408d6219b585b40 *ports/lint-plus/au-autosar.lnt e3e3f3000f9a80a446255ef52f3a6299 *ports/lint-plus/au-autosar19.lnt 2a8fea61bccbe5e8c7536a29f2ec8e98 *ports/lint-plus/au-ds.lnt ede719cdbc201d14586a3f11e77ced26 *ports/lint-plus/au-ql-cpp11.lnt -dddbecd55afec10d85006f7787e40c7d *ports/lint-plus/options.lnt +3935c8cc585d08999ba9fb9055cc3705 *ports/lint-plus/options.lnt 00e7bc0ddabc998469615ac2ff9d79f1 *ports/lint-plus/qpcpp.lnt 5f789348dba099c2055f737ba756faac *ports/lint-plus/std.lnt 1f3d9dfbf71077abbdb9f27c96879101 *ports/arm-cm/qk/armclang/qk_port.cpp @@ -70,14 +70,14 @@ c6227ba01b71184c9e03ee6c8137ffc2 *ports/arm-cm/qk/gnu/qp_port.hpp fed596b153b928c8631e2712361049af *ports/arm-cm/qv/iar/qv_port.cpp fbab3cb88a019df3a12ee56a4a6f90b2 *ports/arm-cm/qxk/armclang/qp_port.hpp 91a3b66c3f12a98bef48b00640ed5e6d *ports/arm-cm/qxk/armclang/qs_port.hpp -347f34d732e241dda4ba56133ce89993 *ports/arm-cm/qxk/armclang/qxk_port.cpp +3e6878ba5e8df9ed733edf9f2da2ae9e *ports/arm-cm/qxk/armclang/qxk_port.cpp e219623c0ac1ee0fcb24d9b2245e406e *ports/arm-cm/qxk/config/qp_config.hpp 246d7b72e2f0c1e3ba6e699740dbe390 *ports/arm-cm/qxk/gnu/qp_port.hpp 91a3b66c3f12a98bef48b00640ed5e6d *ports/arm-cm/qxk/gnu/qs_port.hpp -1a120fbd8eabd3ee8f36fa9965120147 *ports/arm-cm/qxk/gnu/qxk_port.cpp +f12841a5d59075aa3e1e9cfb683c4b98 *ports/arm-cm/qxk/gnu/qxk_port.cpp 55b897c657e225d775cf6121d6278585 *ports/arm-cm/qxk/iar/qp_port.hpp 91a3b66c3f12a98bef48b00640ed5e6d *ports/arm-cm/qxk/iar/qs_port.hpp -01d7a7198b209b43e49df8df5ca8ea2b *ports/arm-cm/qxk/iar/qxk_port.cpp +bcb7406483cc9280c2b05113f6078cb6 *ports/arm-cm/qxk/iar/qxk_port.cpp 0f3ac7def7c330e85912d95527c94ebc *ports/arm-cm/qutest/qp_port.hpp 4c0ab6f6ad804f0bd70f146d53a1d197 *ports/arm-cm/qutest/qs_port.hpp a595b03768298546cd9dff7f4e8876f7 *ports/arm-cr/qk/config/qp_config.hpp @@ -148,7 +148,6 @@ e898e8f446a8fcfd84b5092144b21ef3 *ports/posix-qutest/qs_port.hpp 0ac7e3d28e684d07baacdcd0d3e65c4a *ports/posix-qutest/README.md 7955fc33c291eb6b8ebabaae0d6bd0da *ports/posix-qutest/safe_std.h 84541985a09da4e23055531452d74a02 *ports/win32/CMakeLists.txt -ccec9e69c078e6b6889b7cba2e6195dd *ports/win32/Makefile b98e9825ffcbd8178145207316bf7910 *ports/win32/qf_port.cpp fc5a9085222501f994b6d517d6624a52 *ports/win32/qp_port.hpp b53aafe66b369a2e54344c792e481c1c *ports/win32/qs_port.cpp diff --git a/qpcpp.qm b/qpcpp.qm index 987fa10c..532d2ba6 100644 --- a/qpcpp.qm +++ b/qpcpp.qm @@ -472,27 +472,27 @@ QS_MEM_APP(); QF_CRIT_EXIT(); // drill down into the state hierarchy with initial transitions... -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit do { QStateHandler path[MAX_NEST_DEPTH_]; // tran entry path array std::int_fast8_t ip = 0; // tran entry path index path[0] = m_temp.fun; static_cast<void>(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); - while (m_temp.fun != t) { + // note: ip is here the fixed upper loop bound + while ((m_temp.fun != t) && (ip < (MAX_NEST_DEPTH_ - 1))) { ++ip; path[ip] = m_temp.fun; static_cast<void>(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); } QF_CRIT_ENTRY(); - // The initial transition source state must be reached - // Too many state nesting levels or "malformed" HSM. - Q_ASSERT_INCRIT(220, m_temp.fun == t); + // too many state nesting levels or "malformed" HSM + Q_ENSURE_INCRIT(220, ip < MAX_NEST_DEPTH_); QF_CRIT_EXIT(); m_temp.fun = path[0]; // retrace the entry path in reverse (desired) order... + // note: ip is the fixed upper loop bound do { // enter path[ip] if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) @@ -520,14 +520,9 @@ do { QS_CRIT_EXIT(); } #endif // Q_SPY - - --limit; -} while ((r == Q_RET_TRAN) && (limit > 0)); +} while (r == Q_RET_TRAN); QF_CRIT_ENTRY(); -// Loop limit must not be reached. -// Too many state nesting levels or likely "malformed" HSM -Q_ENSURE_INCRIT(290, limit > 0); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qsId) @@ -567,9 +562,9 @@ QStateHandler t = s; QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_REQUIRE_INCRIT(300, (s != Q_STATE_CAST(0)) +Q_INVARIANT_INCRIT(302, (s != Q_STATE_CAST(0)) && (m_state.uint == static_cast<std::uintptr_t>(~m_temp.uint))); -Q_REQUIRE_INCRIT(302, QEvt::verify_(e)); +Q_INVARIANT_INCRIT(303, QEvt::verify_(e)); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_DISPATCH, qsId) @@ -585,7 +580,7 @@ QF_CRIT_EXIT(); // process the event hierarchically... QState r; m_temp.fun = s; -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit +std::int_fast8_t ip = MAX_NEST_DEPTH_; // fixed upper loop bound do { s = m_temp.fun; r = (*s)(this, e); // invoke state handler s @@ -605,11 +600,11 @@ do { r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG); // superstate of s } - --limit; -} while ((r == Q_RET_SUPER) && (limit > 0)); + --ip; +} while ((r == Q_RET_SUPER) && (ip > 0)); QF_CRIT_ENTRY(); -Q_ASSERT_INCRIT(310, limit > 0); +Q_ENSURE_INCRIT(310, ip > 0); QF_CRIT_EXIT(); if (r >= Q_RET_TRAN) { // regular tran. taken? @@ -620,21 +615,21 @@ if (r >= Q_RET_TRAN) { // regular tran. taken? path[2] = s; // tran. source // exit current state to tran. source s... - limit = MAX_NEST_DEPTH_; // loop hard limit - for (; (t != s) && (limit > 0); t = m_temp.fun) { + ip = MAX_NEST_DEPTH_; // fixed upper loop bound + for (; (t != s) && (ip > 0); t = m_temp.fun) { // exit from t if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) { QS_STATE_EXIT_(t, qsId); // find superstate of t static_cast<void>(QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG)); } - --limit; + --ip; } QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(320, limit > 0); + Q_ENSURE_INCRIT(320, ip > 0); QF_CRIT_EXIT(); - std::int_fast8_t ip = hsm_tran(path, qsId); // take the tran. + ip = hsm_tran(path, qsId); // take the tran. #ifdef Q_SPY if (r == Q_RET_TRAN_HIST) { @@ -651,6 +646,7 @@ if (r >= Q_RET_TRAN) { // regular tran. taken? #endif // Q_SPY // execute state entry actions in the desired order... + // note: ip is the fixed upper loop bound for (; ip >= 0; --ip) { // enter path[ip] if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) @@ -681,6 +677,7 @@ if (r >= Q_RET_TRAN) { // regular tran. taken? // find superstate static_cast<void>(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); + // note: ip is the fixed upper loop bound while ((m_temp.fun != t) && (ip < (MAX_NEST_DEPTH_ - 1))) { ++ip; path[ip] = m_temp.fun; @@ -689,14 +686,14 @@ if (r >= Q_RET_TRAN) { // regular tran. taken? QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); } QF_CRIT_ENTRY(); - // The initial transition source state must be reached. - // Too many state nesting levels or "malformed" HSM. - Q_ASSERT_INCRIT(330, m_temp.fun == t); + // too many state nesting levels or "malformed" HSM + Q_ENSURE_INCRIT(330, ip < MAX_NEST_DEPTH_); QF_CRIT_EXIT(); m_temp.fun = path[0]; // retrace the entry path in reverse (correct) order... + // note: ip is the fixed upper loop bound do { // enter path[ip] if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) @@ -762,17 +759,17 @@ m_temp.uint = ~m_state.uint; QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_REQUIRE_INCRIT(602, m_state.uint - == static_cast<std::uintptr_t>(~m_temp.uint)); +Q_INVARIANT_INCRIT(602, m_state.uint + == static_cast<std::uintptr_t>(~m_temp.uint)); QF_CRIT_EXIT(); bool inState = false; // assume that this HSM is not in 'state' // scan the state hierarchy bottom-up QStateHandler s = m_state.fun; -std::int_fast8_t limit = MAX_NEST_DEPTH_ + 1; // loop hard limit +std::int_fast8_t lbound = MAX_NEST_DEPTH_ + 1; // fixed upper loop bound QState r = Q_RET_SUPER; -for (; (r != Q_RET_IGNORED) && (limit > 0); --limit) { +for (; (r != Q_RET_IGNORED) && (lbound > 0); --lbound) { if (s == state) { // do the states match? inState = true; // 'true' means that match found break; // break out of the for-loop @@ -784,7 +781,7 @@ for (; (r != Q_RET_IGNORED) && (limit > 0); --limit) { } QF_CRIT_ENTRY(); -Q_ENSURE_INCRIT(690, limit > 0); +Q_ENSURE_INCRIT(690, lbound > 0); QF_CRIT_EXIT(); #ifndef Q_UNSAFE @@ -798,12 +795,13 @@ return inState; // return the status noexcept - QStateHandler child = m_state.fun; // start with the current state + QStateHandler child = m_state.fun; // start with current state bool isFound = false; // start with the child not found // establish stable state configuration m_temp.fun = child; QState r; +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { // is this the parent of the current child? if (m_temp.fun == parent) { @@ -814,7 +812,9 @@ do { child = m_temp.fun; r = QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG); } -} while (r != Q_RET_IGNORED); // QHsm::top() state not reached + --lbound; +} while ((r != Q_RET_IGNORED) // QHsm::top() state not reached + && (lbound > 0)); #ifndef Q_UNSAFE m_temp.uint = ~m_state.uint; @@ -822,10 +822,12 @@ m_temp.uint = ~m_state.uint; QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_ASSERT_INCRIT(890, isFound); +// NOTE: the following postcondition can only succeed when +// (lbound > 0), so no extra check is necessary. +Q_ENSURE_INCRIT(890, isFound); QF_CRIT_EXIT(); -return child; // return the child +return child; @@ -894,6 +896,7 @@ else { t = m_temp.fun; // save source->super // find target->super->super... + // note: ip is the fixed upper loop bound QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG); while ((r == Q_RET_SUPER) && (ip < (MAX_NEST_DEPTH_ - 1))) @@ -910,9 +913,10 @@ else { } } QF_CRIT_ENTRY(); - // Tran. source must be found within the nesting depth - // Too many state nesting levels or "malformed" HSM. - Q_ASSERT_INCRIT(510, r != Q_RET_SUPER); + // NOTE: The following postcondition succeeds only when + // ip < QHSM_MAX_NEST_DEPTH, so no additional check is necessary + // too many state nesting levels or "malformed" HSM. + Q_ENSURE_INCRIT(510, r != Q_RET_SUPER); QF_CRIT_EXIT(); // the LCA not found yet? @@ -928,6 +932,7 @@ else { // == target->super->super... iq = ip; r = Q_RET_IGNORED; // indicate that the LCA NOT found + // note: iq is the fixed upper loop bound do { if (t == path[iq]) { // is this the LCA? r = Q_RET_HANDLED; // indicate the LCA found @@ -944,7 +949,7 @@ else { // (g) check each source->super->... // for each target->super... r = Q_RET_IGNORED; // keep looping - std::int_fast8_t limit = MAX_NEST_DEPTH_; + std::int_fast8_t lbound = MAX_NEST_DEPTH_; do { // exit from t if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) @@ -969,10 +974,10 @@ else { } } while (iq >= 0); - --limit; - } while ((r != Q_RET_HANDLED) && (limit > 0)); + --lbound; + } while ((r != Q_RET_HANDLED) && (lbound > 0)); QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(530, limit > 0); + Q_ASSERT_INCRIT(530, lbound > 0); QF_CRIT_EXIT(); } } @@ -1037,15 +1042,15 @@ QF_CRIT_EXIT(); m_state.obj = m_temp.tatbl->target; // drill down into the state hierarchy with initial transitions... -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { // execute the tran. table r = execTatbl_(m_temp.tatbl, qsId); - --limit; -} while ((r >= Q_RET_TRAN_INIT) && (limit > 0)); + --lbound; +} while ((r >= Q_RET_TRAN_INIT) && (lbound > 0)); QF_CRIT_ENTRY(); -Q_ENSURE_INCRIT(290, limit > 0); +Q_ENSURE_INCRIT(290, lbound > 0); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qsId) @@ -1084,9 +1089,9 @@ QMState const *t = s; QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_REQUIRE_INCRIT(300, (s != nullptr) +Q_INVARIANT_INCRIT(300, (s != nullptr) && (m_state.uint == static_cast<std::uintptr_t>(~m_temp.uint))); -Q_REQUIRE_INCRIT(302, QEvt::verify_(e)); +Q_INVARIANT_INCRIT(302, QEvt::verify_(e)); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_DISPATCH, qsId) @@ -1101,7 +1106,7 @@ QF_CRIT_EXIT(); // scan the state hierarchy up to the top state... QState r; -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { r = (*t->stateHandler)(this, e); // call state handler function @@ -1134,10 +1139,10 @@ do { t = t->superstate; // advance to the superstate } - --limit; -} while ((t != nullptr) && (limit > 0)); + --lbound; +} while ((t != nullptr) && (lbound > 0)); QF_CRIT_ENTRY(); -Q_ASSERT_INCRIT(310, limit > 0); +Q_ASSERT_INCRIT(310, lbound > 0); QF_CRIT_EXIT(); if (r >= Q_RET_TRAN) { // any kind of tran. taken? @@ -1150,7 +1155,7 @@ if (r >= Q_RET_TRAN) { // any kind of tran. taken? QF_CRIT_EXIT(); #endif // Q_SPY - limit = MAX_NEST_DEPTH_; // loop hard limit + lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { // save the tran-action table before it gets clobbered QMTranActTable const * const tatbl = m_temp.tatbl; @@ -1217,11 +1222,11 @@ if (r >= Q_RET_TRAN) { // any kind of tran. taken? } t = s; // set target to the current state - --limit; - } while ((r >= Q_RET_TRAN) && (limit > 0)); + --lbound; + } while ((r >= Q_RET_TRAN) && (lbound > 0)); QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(320, limit > 0); + Q_ASSERT_INCRIT(320, lbound > 0); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_TRAN, qsId) @@ -1289,8 +1294,8 @@ m_temp.uint = ~m_state.uint; bool inState = false; // assume that this SM is not in 'state' QMState const *s = m_state.obj; -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit -for (; (s != nullptr) && (limit > 0); --limit) { +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound +for (; (s != nullptr) && (lbound > 0); --lbound) { if (s->stateHandler == state) { // match found? inState = true; break; @@ -1302,7 +1307,7 @@ for (; (s != nullptr) && (limit > 0); --limit) { QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_ENSURE_INCRIT(490, limit > 0); +Q_ENSURE_INCRIT(490, lbound > 0); QF_CRIT_EXIT(); return inState; @@ -1316,8 +1321,8 @@ return inState; bool inState = false; // assume that this SM is not in 'state' QMState const *s = m_state.obj; -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit -for (; (s != nullptr) && (limit > 0); --limit) { +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound +for (; (s != nullptr) && (lbound > 0); --lbound) { if (s == stateObj) { // match found? inState = true; break; @@ -1329,7 +1334,7 @@ for (; (s != nullptr) && (limit > 0); --limit) { QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_ENSURE_INCRIT(590, limit > 0); +Q_ENSURE_INCRIT(590, lbound > 0); QF_CRIT_EXIT(); return inState; @@ -1343,9 +1348,9 @@ return inState; bool isFound = false; // start with the child not found QMState const *s; -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound for (s = m_state.obj; - (s != nullptr) && (limit > 0); + (s != nullptr) && (lbound > 0); s = s->superstate) { if (s == parent) { @@ -1355,17 +1360,17 @@ for (s = m_state.obj; else { child = s; } - --limit; + --lbound; } QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_ASSERT_INCRIT(610, limit > 0); +Q_ASSERT_INCRIT(610, lbound > 0); QF_CRIT_EXIT(); if (!isFound) { // still not found? - limit = MAX_NEST_DEPTH_; // loop hard limit + lbound = MAX_NEST_DEPTH_; // fixed upper loop bound for (s = m_temp.obj; - (s != nullptr) && (limit > 0); + (s != nullptr) && (lbound > 0); s = s->superstate) { if (s == parent) { @@ -1375,12 +1380,12 @@ if (!isFound) { // still not found? else { child = s; } - --limit; + --lbound; } } QF_CRIT_ENTRY(); -Q_ENSURE_INCRIT(690, isFound && (limit > 0)); +Q_ENSURE_INCRIT(690, isFound && (lbound > 0)); QF_CRIT_EXIT(); return child; // return the child @@ -1403,9 +1408,9 @@ Q_REQUIRE_INCRIT(700, tatbl != nullptr); QF_CRIT_EXIT(); QState r = Q_RET_NULL; -std::int_fast8_t limit = MAX_TRAN_LENGTH_; // loop hard limit +std::int_fast8_t lbound = MAX_TRAN_LENGTH_; // fixed upper loop bound QActionHandler const *a = &tatbl->act[0]; -for (; (*a != nullptr) && (limit > 0); ++a) { +for (; (*a != nullptr) && (lbound > 0); ++a) { r = (*(*a))(this); // call the action through the 'a' pointer #ifdef Q_SPY QS_CRIT_ENTRY(); @@ -1449,7 +1454,7 @@ for (; (*a != nullptr) && (limit > 0); ++a) { QS_MEM_APP(); QS_CRIT_EXIT(); #endif // Q_SPY - --limit; + --lbound; } QF_CRIT_ENTRY(); Q_ENSURE_INCRIT(790, *a == nullptr); @@ -1476,8 +1481,8 @@ QF_CRIT_STAT // exit states from the current state to the tran. source state QMState const *s = cs; -std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit -for (; (s != ts) && (limit > 0); --limit) { +std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound +for (; (s != ts) && (lbound > 0); --lbound) { // exit action provided in state 's'? if (s->exitAction != nullptr) { // execute the exit action @@ -1503,7 +1508,7 @@ for (; (s != ts) && (limit > 0); --limit) { } } QF_CRIT_ENTRY(); -Q_ENSURE_INCRIT(890, limit > 0); +Q_ENSURE_INCRIT(890, lbound > 0); QF_CRIT_EXIT(); @@ -2161,7 +2166,7 @@ QF_MEM_SYS(); #ifndef Q_UNSAFE std::uint8_t const pcopy = static_cast<std::uint8_t>(~m_prio_dis); -Q_REQUIRE_INCRIT(102, (QEvt::verify_(e)) && (m_prio == pcopy)); +Q_INVARIANT_INCRIT(102, (QEvt::verify_(e)) && (m_prio == pcopy)); #endif QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary @@ -2300,7 +2305,7 @@ QF_MEM_SYS(); #ifndef Q_UNSAFE std::uint8_t const pcopy = static_cast<std::uint8_t>(~m_prio_dis); -Q_REQUIRE_INCRIT(202, (QEvt::verify_(e)) && (m_prio == pcopy)); +Q_INVARIANT_INCRIT(202, (QEvt::verify_(e)) && (m_prio == pcopy)); #endif #ifdef QXK_HPP_ @@ -2466,7 +2471,7 @@ QF_CRIT_ENTRY(); QF_MEM_SYS(); Q_REQUIRE_INCRIT(200, sig < static_cast<QSignal>(maxPubSignal_)); -Q_REQUIRE_INCRIT(202, +Q_INVARIANT_INCRIT(202, subscrList_[sig].m_set.verify_(&subscrList_[sig].m_set_dis)); QS_BEGIN_PRE_(QS_QF_PUBLISH, qsId) @@ -2509,9 +2514,9 @@ if (subscrSet.notEmpty()) { // any subscribers? QF_SCHED_STAT_ QF_SCHED_LOCK_(p); // lock the scheduler up to AO's prio - std::uint_fast8_t limit = QF_MAX_ACTIVE + 1U; + std::uint_fast8_t lbound = QF_MAX_ACTIVE + 1U; do { // loop over all subscribers - --limit; + --lbound; // POST() asserts internally if the queue overflows a->POST(e, sender); @@ -2533,7 +2538,7 @@ if (subscrSet.notEmpty()) { // any subscribers? else { p = 0U; // no more subscribers } - } while ((p != 0U) && (limit > 0U)); + } while ((p != 0U) && (lbound > 0U)); QF_CRIT_ENTRY(); Q_ENSURE_INCRIT(290, p == 0U); @@ -2564,7 +2569,7 @@ Q_REQUIRE_INCRIT(300, (Q_USER_SIG <= sig) && (sig < maxPubSignal_) && (0U < p) && (p <= QF_MAX_ACTIVE) && (registry_[p] == this)); -Q_REQUIRE_INCRIT(302, +Q_INVARIANT_INCRIT(302, subscrList_[sig].m_set.verify_(&subscrList_[sig].m_set_dis)); QS_BEGIN_PRE_(QS_QF_ACTIVE_SUBSCRIBE, m_prio) @@ -2597,7 +2602,7 @@ Q_REQUIRE_INCRIT(400, (Q_USER_SIG <= sig) && (sig < maxPubSignal_) && (0U < p) && (p <= QF_MAX_ACTIVE) && (registry_[p] == this)); -Q_REQUIRE_INCRIT(402, +Q_INVARIANT_INCRIT(402, subscrList_[sig].m_set.verify_(&subscrList_[sig].m_set_dis)); QS_BEGIN_PRE_(QS_QF_ACTIVE_UNSUBSCRIBE, m_prio) @@ -2929,8 +2934,6 @@ QF_CRIT_EXIT(); // reused to hold the tickRate as well as other information refCtr_ = static_cast<std::uint8_t>(tickRate); - - noexcept @@ -3159,8 +3162,8 @@ QS_BEGIN_PRE_(QS_QF_TICK, 0U) QS_END_PRE_() // scan the linked-list of time events at this rate... -std::uint_fast8_t limit = 2U*QF_MAX_ACTIVE; // loop hard limit -for (; limit > 0U; --limit) { +std::uint_fast8_t lbound = 2U*QF_MAX_ACTIVE; // fixed upper loop bound +for (; lbound > 0U; --lbound) { QTimeEvt *e = prev->m_next; // advance down the time evt. list if (e == nullptr) { // end of the list? @@ -3180,7 +3183,7 @@ for (; limit > 0U; --limit) { } // the time event 'e' must be valid - Q_ASSERT_INCRIT(112, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(112, QEvt::verify_(e)); if (e->m_ctr == 0U) { // time event scheduled for removal? prev->m_next = e->m_next; @@ -3269,7 +3272,7 @@ for (; limit > 0U; --limit) { QF_MEM_SYS(); } -Q_ENSURE_INCRIT(190, limit > 0U); +Q_ENSURE_INCRIT(190, lbound > 0U); QF_MEM_APP(); QF_CRIT_EXIT(); @@ -3489,8 +3492,6 @@ QF_CRIT_EXIT(); m_nFree(0U), m_nMin(0U) - - noexcept @@ -3760,8 +3761,6 @@ return e; m_nFree(0U), m_nMin(0U) - - noexcept @@ -3850,8 +3849,8 @@ if (m_nFree > static_cast<QMPoolCtr>(margin)) { QFreeBlock * const fb_next = fb->m_next; // the free block must have integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(302, Q_UINTPTR_CAST_(fb_next) - == static_cast<std::uintptr_t>(~fb->m_next_dis)); + Q_INVARIANT_INCRIT(302, Q_UINTPTR_CAST_(fb_next) + == static_cast<std::uintptr_t>(~fb->m_next_dis)); m_nFree = (m_nFree - 1U); // one free block less if (m_nFree == 0U) { // is the pool becoming empty? @@ -3929,7 +3928,7 @@ fb->m_next_dis = static_cast<std::uintptr_t>( #endif // set as new head of the free list -m_free_head = static_cast<QFreeBlock *>(block); +m_free_head = fb; m_nFree = m_nFree + 1U; // one more free block in this pool @@ -4234,7 +4233,7 @@ return e; QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_REQUIRE_INCRIT(402, QEvt::verify_(e)); +Q_INVARIANT_INCRIT(402, QEvt::verify_(e)); std::uint_fast8_t const poolNum = e->getPoolNum_(); @@ -4299,7 +4298,7 @@ Q_UNUSED_PAR(evtRef); QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_REQUIRE_INCRIT(502, QEvt::verify_(e)); +Q_INVARIANT_INCRIT(502, QEvt::verify_(e)); std::uint_fast8_t const poolNum = e->getPoolNum_(); @@ -4330,7 +4329,7 @@ return e; QF_CRIT_STAT QF_CRIT_ENTRY(); -Q_REQUIRE_INCRIT(602, QEvt::verify_(e)); +Q_INVARIANT_INCRIT(602, QEvt::verify_(e)); #ifdef Q_SPY std::uint_fast8_t const poolNum = e->getPoolNum_(); @@ -4632,7 +4631,7 @@ gc(evtRef); // recycle the referenced event QF_CRIT_ENTRY(); QF_MEM_SYS(); -Q_ASSERT_INCRIT(102, priv_.schedCeil +Q_INVARIANT_INCRIT(102, priv_.schedCeil == static_cast<std::uint_fast8_t>(~priv_.schedCeil_dis)); if (ceiling > priv_.schedCeil) { // raising the scheduler ceiling? @@ -4658,7 +4657,7 @@ QF_CRIT_EXIT(); QF_CRIT_ENTRY(); QF_MEM_SYS(); -Q_ASSERT_INCRIT(202, priv_.schedCeil +Q_INVARIANT_INCRIT(202, priv_.schedCeil == static_cast<std::uint_fast8_t>(~priv_.schedCeil_dis)); if (priv_.schedCeil != 0U) { // actually enabling the scheduler? @@ -4730,10 +4729,10 @@ std::uint_fast8_t pprev = 0U; // previous prio. for (;;) { // QV event loop... // check internal integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(302, + Q_INVARIANT_INCRIT(302, QV::priv_.readySet.verify_(&QV::priv_.readySet_dis)); // check internal integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(303, QV::priv_.schedCeil + Q_INVARIANT_INCRIT(303, QV::priv_.schedCeil == static_cast<std::uint_fast8_t>(~QV::priv_.schedCeil_dis)); // find the maximum prio. AO ready to run @@ -4908,7 +4907,7 @@ QF_CRIT_ENTRY(); QF_MEM_SYS(); Q_REQUIRE_INCRIT(100, !QK_ISR_CONTEXT_()); -Q_REQUIRE_INCRIT(102, QK_priv_.lockCeil +Q_INVARIANT_INCRIT(102, QK_priv_.lockCeil == static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil_dis)); // first store the previous lock prio @@ -4950,7 +4949,7 @@ if (prevCeil != 0xFFU) { QF_CRIT_ENTRY(); QF_MEM_SYS(); - Q_REQUIRE_INCRIT(202, QK_priv_.lockCeil + Q_INVARIANT_INCRIT(202, QK_priv_.lockCeil == static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil_dis)); Q_REQUIRE_INCRIT(210, (!QK_ISR_CONTEXT_()) && (QK_priv_.lockCeil > prevCeil)); @@ -5134,7 +5133,7 @@ QF_CRIT_EXIT(); noexcept // NOTE: this function is entered with interrupts DISABLED -Q_REQUIRE_INCRIT(402, +Q_INVARIANT_INCRIT(402, QK_priv_.readySet.verify_(&QK_priv_.readySet_dis)); std::uint_fast8_t p; @@ -5145,7 +5144,7 @@ else { // find the highest-prio AO with non-empty event queue p = QK_priv_.readySet.findMax(); - Q_ASSERT_INCRIT(412, QK_priv_.actThre + Q_INVARIANT_INCRIT(412, QK_priv_.actThre == static_cast<std::uint_fast8_t>(~QK_priv_.actThre_dis)); // is the AO's prio. below the active preemption-threshold? @@ -5153,7 +5152,7 @@ else { p = 0U; // no activation needed } else { - Q_ASSERT_INCRIT(422, QK_priv_.lockCeil + Q_INVARIANT_INCRIT(422, QK_priv_.lockCeil == static_cast<std::uint_fast8_t>(~QK_priv_.lockCeil_dis)); // is the AO's prio. below the lock-ceiling? @@ -5161,7 +5160,7 @@ else { p = 0U; // no activation needed } else { - Q_ASSERT_INCRIT(432, QK_priv_.nextPrio + Q_INVARIANT_INCRIT(432, QK_priv_.nextPrio == static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio_dis)); QK_priv_.nextPrio = p; // next AO to run #ifndef Q_UNSAFE @@ -5182,7 +5181,7 @@ return p; std::uint_fast8_t const prio_in = QK_priv_.actPrio; // save initial prio. std::uint_fast8_t p = QK_priv_.nextPrio; // next prio to run -Q_REQUIRE_INCRIT(502, +Q_INVARIANT_INCRIT(502, (prio_in == static_cast<std::uint_fast8_t>(~QK_priv_.actPrio_dis)) && (p == static_cast<std::uint_fast8_t>(~QK_priv_.nextPrio_dis))); Q_REQUIRE_INCRIT(510, (prio_in <= QF_MAX_ACTIVE) @@ -5207,7 +5206,7 @@ else { Q_ASSERT_INCRIT(510, a != nullptr); pthre_in = static_cast<std::uint_fast8_t>(a->getPThre()); - Q_ASSERT_INCRIT(511, pthre_in == static_cast<std::uint_fast8_t>( + Q_INVARIANT_INCRIT(511, pthre_in == static_cast<std::uint_fast8_t>( ~static_cast<std::uint_fast8_t>(a->m_pthre_dis) & 0xFFU)); } @@ -5217,7 +5216,7 @@ do { Q_ASSERT_INCRIT(520, a != nullptr); // the AO must be registered std::uint_fast8_t const pthre = static_cast<std::uint_fast8_t>(a->getPThre()); - Q_ASSERT_INCRIT(522, pthre == static_cast<std::uint_fast8_t>( + Q_INVARIANT_INCRIT(522, pthre == static_cast<std::uint_fast8_t>( ~static_cast<std::uint_fast8_t>(a->m_pthre_dis) & 0xFFU)); // set new active prio. and preemption-threshold @@ -5245,6 +5244,7 @@ do { } #endif // QF_ON_CONTEXT_SW || Q_SPY + QF_MEM_APP(); QF_INT_ENABLE(); // unconditionally enable interrupts QP::QEvt const * const e = a->get_(); @@ -5261,7 +5261,7 @@ do { QF_MEM_SYS(); // internal integrity check (duplicate inverse storage) - Q_ASSERT_INCRIT(532, + Q_INVARIANT_INCRIT(532, QK_priv_.readySet.verify_(&QK_priv_.readySet_dis)); if (a->getEQueue().isEmpty()) { // empty queue? @@ -5283,7 +5283,7 @@ do { p = 0U; // no activation needed } else { - Q_ASSERT_INCRIT(542, + Q_INVARIANT_INCRIT(542, QK_priv_.lockCeil == ~QK_priv_.lockCeil_dis); // is the AO's prio. below the lock preemption-threshold? @@ -6176,7 +6176,7 @@ if (m_ao.m_eQueue.m_nFree == 0U) { // is the mutex locked by this thread already (nested locking)? else if (m_ao.m_osObject == curr) { - // the nesting level beyond the arbitrary but high limit + // the nesting level beyond the arbitrary but high bound // most likely means cyclic or recursive locking of a mutex. Q_ASSERT_INCRIT(220, m_ao.m_eQueue.m_nFree < 0xFFU); @@ -6323,7 +6323,7 @@ if (m_ao.m_eQueue.m_nFree == 0U) { } // is the mutex locked by this thread already (nested locking)? else if (m_ao.m_osObject == curr) { - // the nesting level must not exceed the specified limit + // the nesting level must not exceed the specified bound Q_ASSERT_INCRIT(320, m_ao.m_eQueue.m_nFree < 0xFFU); // lock one more level @@ -6677,7 +6677,7 @@ else { // starting QXThread noexcept - Q_REQUIRE_INCRIT(402, + Q_INVARIANT_INCRIT(402, QXK_priv_.readySet.verify_(&QXK_priv_.readySet_dis)); std::uint_fast8_t p; @@ -6756,6 +6756,7 @@ std::uint_fast8_t p = next->getPrio(); do { QXK_priv_.actPrio = p; // next active prio + QF_MEM_APP(); QF_INT_ENABLE(); // unconditionally enable interrupts QP::QEvt const * const e = next->get_(); @@ -6771,7 +6772,7 @@ do { QF_MEM_SYS(); // check internal integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(502, + Q_INVARIANT_INCRIT(502, QXK_priv_.readySet.verify_(&QXK_priv_.readySet_dis)); if (next->getEQueue().isEmpty()) { // empty queue? @@ -8454,11 +8455,9 @@ if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qsId_)) { \ #define QP_HPP_ //============================================================================ -#define QP_VERSION 733U -#define QP_VERSION_STR "7.3.3" - -//! Encrypted current QP release (7.3.3) and date (2024-03-01) -#define QP_RELEASE 0x70C4F752U +#define QP_VERSION_STR "7.3.5-rc.1" +#define QP_VERSION 735U +#define QP_RELEASE 0x70A1DEF0U //============================================================================ //! @cond INTERNAL @@ -10871,7 +10870,7 @@ void target_info_pre_(std::uint8_t const isReset) { QS::u8_raw_(QS_OBJ_PTR_SIZE | (QS_FUN_PTR_SIZE << 4U)); QS::u8_raw_(QS_TIME_SIZE); - // send the limits... + // send the bounds... QS::u8_raw_(QF_MAX_ACTIVE); QS::u8_raw_(QF_MAX_EPOOL | (QF_MAX_TICK_RATE << 4U)); diff --git a/src/qf/qep_hsm.cpp b/src/qf/qep_hsm.cpp index 615ef8a2..908ef622 100644 --- a/src/qf/qep_hsm.cpp +++ b/src/qf/qep_hsm.cpp @@ -172,27 +172,27 @@ void QHsm::init( QF_CRIT_EXIT(); // drill down into the state hierarchy with initial transitions... - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit do { QStateHandler path[MAX_NEST_DEPTH_]; // tran entry path array std::int_fast8_t ip = 0; // tran entry path index path[0] = m_temp.fun; static_cast(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); - while (m_temp.fun != t) { + // note: ip is here the fixed upper loop bound + while ((m_temp.fun != t) && (ip < (MAX_NEST_DEPTH_ - 1))) { ++ip; path[ip] = m_temp.fun; static_cast(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); } QF_CRIT_ENTRY(); - // The initial transition source state must be reached - // Too many state nesting levels or "malformed" HSM. - Q_ASSERT_INCRIT(220, m_temp.fun == t); + // too many state nesting levels or "malformed" HSM + Q_ENSURE_INCRIT(220, ip < MAX_NEST_DEPTH_); QF_CRIT_EXIT(); m_temp.fun = path[0]; // retrace the entry path in reverse (desired) order... + // note: ip is the fixed upper loop bound do { // enter path[ip] if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) @@ -220,14 +220,9 @@ void QHsm::init( QS_CRIT_EXIT(); } #endif // Q_SPY - - --limit; - } while ((r == Q_RET_TRAN) && (limit > 0)); + } while (r == Q_RET_TRAN); QF_CRIT_ENTRY(); - // Loop limit must not be reached. - // Too many state nesting levels or likely "malformed" HSM - Q_ENSURE_INCRIT(290, limit > 0); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qsId) @@ -259,9 +254,9 @@ void QHsm::dispatch( QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_REQUIRE_INCRIT(300, (s != Q_STATE_CAST(0)) + Q_INVARIANT_INCRIT(302, (s != Q_STATE_CAST(0)) && (m_state.uint == static_cast(~m_temp.uint))); - Q_REQUIRE_INCRIT(302, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(303, QEvt::verify_(e)); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_DISPATCH, qsId) @@ -277,7 +272,7 @@ void QHsm::dispatch( // process the event hierarchically... QState r; m_temp.fun = s; - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit + std::int_fast8_t ip = MAX_NEST_DEPTH_; // fixed upper loop bound do { s = m_temp.fun; r = (*s)(this, e); // invoke state handler s @@ -297,11 +292,11 @@ void QHsm::dispatch( r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG); // superstate of s } - --limit; - } while ((r == Q_RET_SUPER) && (limit > 0)); + --ip; + } while ((r == Q_RET_SUPER) && (ip > 0)); QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(310, limit > 0); + Q_ENSURE_INCRIT(310, ip > 0); QF_CRIT_EXIT(); if (r >= Q_RET_TRAN) { // regular tran. taken? @@ -312,21 +307,21 @@ void QHsm::dispatch( path[2] = s; // tran. source // exit current state to tran. source s... - limit = MAX_NEST_DEPTH_; // loop hard limit - for (; (t != s) && (limit > 0); t = m_temp.fun) { + ip = MAX_NEST_DEPTH_; // fixed upper loop bound + for (; (t != s) && (ip > 0); t = m_temp.fun) { // exit from t if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) { QS_STATE_EXIT_(t, qsId); // find superstate of t static_cast(QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG)); } - --limit; + --ip; } QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(320, limit > 0); + Q_ENSURE_INCRIT(320, ip > 0); QF_CRIT_EXIT(); - std::int_fast8_t ip = hsm_tran(path, qsId); // take the tran. + ip = hsm_tran(path, qsId); // take the tran. #ifdef Q_SPY if (r == Q_RET_TRAN_HIST) { @@ -343,6 +338,7 @@ void QHsm::dispatch( #endif // Q_SPY // execute state entry actions in the desired order... + // note: ip is the fixed upper loop bound for (; ip >= 0; --ip) { // enter path[ip] if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) @@ -373,6 +369,7 @@ void QHsm::dispatch( // find superstate static_cast(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); + // note: ip is the fixed upper loop bound while ((m_temp.fun != t) && (ip < (MAX_NEST_DEPTH_ - 1))) { ++ip; path[ip] = m_temp.fun; @@ -381,14 +378,14 @@ void QHsm::dispatch( QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG)); } QF_CRIT_ENTRY(); - // The initial transition source state must be reached. - // Too many state nesting levels or "malformed" HSM. - Q_ASSERT_INCRIT(330, m_temp.fun == t); + // too many state nesting levels or "malformed" HSM + Q_ENSURE_INCRIT(330, ip < MAX_NEST_DEPTH_); QF_CRIT_EXIT(); m_temp.fun = path[0]; // retrace the entry path in reverse (correct) order... + // note: ip is the fixed upper loop bound do { // enter path[ip] if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) @@ -452,17 +449,17 @@ void QHsm::dispatch( bool QHsm::isIn(QStateHandler const state) noexcept { QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_REQUIRE_INCRIT(602, m_state.uint - == static_cast(~m_temp.uint)); + Q_INVARIANT_INCRIT(602, m_state.uint + == static_cast(~m_temp.uint)); QF_CRIT_EXIT(); bool inState = false; // assume that this HSM is not in 'state' // scan the state hierarchy bottom-up QStateHandler s = m_state.fun; - std::int_fast8_t limit = MAX_NEST_DEPTH_ + 1; // loop hard limit + std::int_fast8_t lbound = MAX_NEST_DEPTH_ + 1; // fixed upper loop bound QState r = Q_RET_SUPER; - for (; (r != Q_RET_IGNORED) && (limit > 0); --limit) { + for (; (r != Q_RET_IGNORED) && (lbound > 0); --lbound) { if (s == state) { // do the states match? inState = true; // 'true' means that match found break; // break out of the for-loop @@ -474,7 +471,7 @@ bool QHsm::isIn(QStateHandler const state) noexcept { } QF_CRIT_ENTRY(); - Q_ENSURE_INCRIT(690, limit > 0); + Q_ENSURE_INCRIT(690, lbound > 0); QF_CRIT_EXIT(); #ifndef Q_UNSAFE @@ -486,12 +483,13 @@ bool QHsm::isIn(QStateHandler const state) noexcept { //${QEP::QHsm::childState} ................................................... QStateHandler QHsm::childState(QStateHandler const parent) noexcept { - QStateHandler child = m_state.fun; // start with the current state + QStateHandler child = m_state.fun; // start with current state bool isFound = false; // start with the child not found // establish stable state configuration m_temp.fun = child; QState r; + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { // is this the parent of the current child? if (m_temp.fun == parent) { @@ -502,7 +500,9 @@ QStateHandler QHsm::childState(QStateHandler const parent) noexcept { child = m_temp.fun; r = QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG); } - } while (r != Q_RET_IGNORED); // QHsm::top() state not reached + --lbound; + } while ((r != Q_RET_IGNORED) // QHsm::top() state not reached + && (lbound > 0)); #ifndef Q_UNSAFE m_temp.uint = ~m_state.uint; @@ -510,10 +510,12 @@ QStateHandler QHsm::childState(QStateHandler const parent) noexcept { QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(890, isFound); + // NOTE: the following postcondition can only succeed when + // (lbound > 0), so no extra check is necessary. + Q_ENSURE_INCRIT(890, isFound); QF_CRIT_EXIT(); - return child; // return the child + return child; } //${QEP::QHsm::hsm_tran} ..................................................... @@ -577,6 +579,7 @@ std::int_fast8_t QHsm::hsm_tran( t = m_temp.fun; // save source->super // find target->super->super... + // note: ip is the fixed upper loop bound QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG); while ((r == Q_RET_SUPER) && (ip < (MAX_NEST_DEPTH_ - 1))) @@ -593,9 +596,10 @@ std::int_fast8_t QHsm::hsm_tran( } } QF_CRIT_ENTRY(); - // Tran. source must be found within the nesting depth - // Too many state nesting levels or "malformed" HSM. - Q_ASSERT_INCRIT(510, r != Q_RET_SUPER); + // NOTE: The following postcondition succeeds only when + // ip < QHSM_MAX_NEST_DEPTH, so no additional check is necessary + // too many state nesting levels or "malformed" HSM. + Q_ENSURE_INCRIT(510, r != Q_RET_SUPER); QF_CRIT_EXIT(); // the LCA not found yet? @@ -611,6 +615,7 @@ std::int_fast8_t QHsm::hsm_tran( // == target->super->super... iq = ip; r = Q_RET_IGNORED; // indicate that the LCA NOT found + // note: iq is the fixed upper loop bound do { if (t == path[iq]) { // is this the LCA? r = Q_RET_HANDLED; // indicate the LCA found @@ -627,7 +632,7 @@ std::int_fast8_t QHsm::hsm_tran( // (g) check each source->super->... // for each target->super... r = Q_RET_IGNORED; // keep looping - std::int_fast8_t limit = MAX_NEST_DEPTH_; + std::int_fast8_t lbound = MAX_NEST_DEPTH_; do { // exit from t if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) @@ -652,10 +657,10 @@ std::int_fast8_t QHsm::hsm_tran( } } while (iq >= 0); - --limit; - } while ((r != Q_RET_HANDLED) && (limit > 0)); + --lbound; + } while ((r != Q_RET_HANDLED) && (lbound > 0)); QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(530, limit > 0); + Q_ASSERT_INCRIT(530, lbound > 0); QF_CRIT_EXIT(); } } diff --git a/src/qf/qep_msm.cpp b/src/qf/qep_msm.cpp index ac9e4bff..9c786699 100644 --- a/src/qf/qep_msm.cpp +++ b/src/qf/qep_msm.cpp @@ -138,15 +138,15 @@ void QMsm::init( m_state.obj = m_temp.tatbl->target; // drill down into the state hierarchy with initial transitions... - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { // execute the tran. table r = execTatbl_(m_temp.tatbl, qsId); - --limit; - } while ((r >= Q_RET_TRAN_INIT) && (limit > 0)); + --lbound; + } while ((r >= Q_RET_TRAN_INIT) && (lbound > 0)); QF_CRIT_ENTRY(); - Q_ENSURE_INCRIT(290, limit > 0); + Q_ENSURE_INCRIT(290, lbound > 0); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qsId) @@ -177,9 +177,9 @@ void QMsm::dispatch( QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_REQUIRE_INCRIT(300, (s != nullptr) + Q_INVARIANT_INCRIT(300, (s != nullptr) && (m_state.uint == static_cast(~m_temp.uint))); - Q_REQUIRE_INCRIT(302, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(302, QEvt::verify_(e)); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_DISPATCH, qsId) @@ -194,7 +194,7 @@ void QMsm::dispatch( // scan the state hierarchy up to the top state... QState r; - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { r = (*t->stateHandler)(this, e); // call state handler function @@ -227,10 +227,10 @@ void QMsm::dispatch( t = t->superstate; // advance to the superstate } - --limit; - } while ((t != nullptr) && (limit > 0)); + --lbound; + } while ((t != nullptr) && (lbound > 0)); QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(310, limit > 0); + Q_ASSERT_INCRIT(310, lbound > 0); QF_CRIT_EXIT(); if (r >= Q_RET_TRAN) { // any kind of tran. taken? @@ -243,7 +243,7 @@ void QMsm::dispatch( QF_CRIT_EXIT(); #endif // Q_SPY - limit = MAX_NEST_DEPTH_; // loop hard limit + lbound = MAX_NEST_DEPTH_; // fixed upper loop bound do { // save the tran-action table before it gets clobbered QMTranActTable const * const tatbl = m_temp.tatbl; @@ -310,11 +310,11 @@ void QMsm::dispatch( } t = s; // set target to the current state - --limit; - } while ((r >= Q_RET_TRAN) && (limit > 0)); + --lbound; + } while ((r >= Q_RET_TRAN) && (lbound > 0)); QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(320, limit > 0); + Q_ASSERT_INCRIT(320, lbound > 0); QS_MEM_SYS(); QS_BEGIN_PRE_(QS_QEP_TRAN, qsId) @@ -375,8 +375,8 @@ bool QMsm::isIn(QStateHandler const state) noexcept { bool inState = false; // assume that this SM is not in 'state' QMState const *s = m_state.obj; - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit - for (; (s != nullptr) && (limit > 0); --limit) { + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound + for (; (s != nullptr) && (lbound > 0); --lbound) { if (s->stateHandler == state) { // match found? inState = true; break; @@ -388,7 +388,7 @@ bool QMsm::isIn(QStateHandler const state) noexcept { QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_ENSURE_INCRIT(490, limit > 0); + Q_ENSURE_INCRIT(490, lbound > 0); QF_CRIT_EXIT(); return inState; @@ -399,8 +399,8 @@ bool QMsm::isInState(QMState const * const stateObj) const noexcept { bool inState = false; // assume that this SM is not in 'state' QMState const *s = m_state.obj; - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit - for (; (s != nullptr) && (limit > 0); --limit) { + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound + for (; (s != nullptr) && (lbound > 0); --lbound) { if (s == stateObj) { // match found? inState = true; break; @@ -412,7 +412,7 @@ bool QMsm::isInState(QMState const * const stateObj) const noexcept { QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_ENSURE_INCRIT(590, limit > 0); + Q_ENSURE_INCRIT(590, lbound > 0); QF_CRIT_EXIT(); return inState; @@ -424,9 +424,9 @@ QMState const * QMsm::childStateObj(QMState const * const parent) const noexcept bool isFound = false; // start with the child not found QMState const *s; - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound for (s = m_state.obj; - (s != nullptr) && (limit > 0); + (s != nullptr) && (lbound > 0); s = s->superstate) { if (s == parent) { @@ -436,17 +436,17 @@ QMState const * QMsm::childStateObj(QMState const * const parent) const noexcept else { child = s; } - --limit; + --lbound; } QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_ASSERT_INCRIT(610, limit > 0); + Q_ASSERT_INCRIT(610, lbound > 0); QF_CRIT_EXIT(); if (!isFound) { // still not found? - limit = MAX_NEST_DEPTH_; // loop hard limit + lbound = MAX_NEST_DEPTH_; // fixed upper loop bound for (s = m_temp.obj; - (s != nullptr) && (limit > 0); + (s != nullptr) && (lbound > 0); s = s->superstate) { if (s == parent) { @@ -456,12 +456,12 @@ QMState const * QMsm::childStateObj(QMState const * const parent) const noexcept else { child = s; } - --limit; + --lbound; } } QF_CRIT_ENTRY(); - Q_ENSURE_INCRIT(690, isFound && (limit > 0)); + Q_ENSURE_INCRIT(690, isFound && (lbound > 0)); QF_CRIT_EXIT(); return child; // return the child @@ -484,9 +484,9 @@ QState QMsm::execTatbl_( QF_CRIT_EXIT(); QState r = Q_RET_NULL; - std::int_fast8_t limit = MAX_TRAN_LENGTH_; // loop hard limit + std::int_fast8_t lbound = MAX_TRAN_LENGTH_; // fixed upper loop bound QActionHandler const *a = &tatbl->act[0]; - for (; (*a != nullptr) && (limit > 0); ++a) { + for (; (*a != nullptr) && (lbound > 0); ++a) { r = (*(*a))(this); // call the action through the 'a' pointer #ifdef Q_SPY QS_CRIT_ENTRY(); @@ -530,7 +530,7 @@ QState QMsm::execTatbl_( QS_MEM_APP(); QS_CRIT_EXIT(); #endif // Q_SPY - --limit; + --lbound; } QF_CRIT_ENTRY(); Q_ENSURE_INCRIT(790, *a == nullptr); @@ -556,8 +556,8 @@ void QMsm::exitToTranSource_( // exit states from the current state to the tran. source state QMState const *s = cs; - std::int_fast8_t limit = MAX_NEST_DEPTH_; // loop hard limit - for (; (s != ts) && (limit > 0); --limit) { + std::int_fast8_t lbound = MAX_NEST_DEPTH_; // fixed upper loop bound + for (; (s != ts) && (lbound > 0); --lbound) { // exit action provided in state 's'? if (s->exitAction != nullptr) { // execute the exit action @@ -583,7 +583,7 @@ void QMsm::exitToTranSource_( } } QF_CRIT_ENTRY(); - Q_ENSURE_INCRIT(890, limit > 0); + Q_ENSURE_INCRIT(890, lbound > 0); QF_CRIT_EXIT(); } diff --git a/src/qf/qf_actq.cpp b/src/qf/qf_actq.cpp index 8a63504f..3a2f6295 100644 --- a/src/qf/qf_actq.cpp +++ b/src/qf/qf_actq.cpp @@ -91,7 +91,7 @@ bool QActive::post_( #ifndef Q_UNSAFE std::uint8_t const pcopy = static_cast(~m_prio_dis); - Q_REQUIRE_INCRIT(102, (QEvt::verify_(e)) && (m_prio == pcopy)); + Q_INVARIANT_INCRIT(102, (QEvt::verify_(e)) && (m_prio == pcopy)); #endif QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary @@ -234,7 +234,7 @@ void QActive::postLIFO(QEvt const * const e) noexcept { #ifndef Q_UNSAFE std::uint8_t const pcopy = static_cast(~m_prio_dis); - Q_REQUIRE_INCRIT(202, (QEvt::verify_(e)) && (m_prio == pcopy)); + Q_INVARIANT_INCRIT(202, (QEvt::verify_(e)) && (m_prio == pcopy)); #endif #ifdef QXK_HPP_ diff --git a/src/qf/qf_dyn.cpp b/src/qf/qf_dyn.cpp index 99a37dc2..2d1272fa 100644 --- a/src/qf/qf_dyn.cpp +++ b/src/qf/qf_dyn.cpp @@ -236,7 +236,7 @@ QEvt * newX_( void gc(QEvt const * const e) noexcept { QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_REQUIRE_INCRIT(402, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(402, QEvt::verify_(e)); std::uint_fast8_t const poolNum = e->getPoolNum_(); @@ -300,7 +300,7 @@ QEvt const * newRef_( QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_REQUIRE_INCRIT(502, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(502, QEvt::verify_(e)); std::uint_fast8_t const poolNum = e->getPoolNum_(); @@ -329,7 +329,7 @@ void deleteRef_(QEvt const * const evtRef) noexcept { QF_CRIT_STAT QF_CRIT_ENTRY(); - Q_REQUIRE_INCRIT(602, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(602, QEvt::verify_(e)); #ifdef Q_SPY std::uint_fast8_t const poolNum = e->getPoolNum_(); diff --git a/src/qf/qf_mem.cpp b/src/qf/qf_mem.cpp index 8714b862..b8d1383c 100644 --- a/src/qf/qf_mem.cpp +++ b/src/qf/qf_mem.cpp @@ -152,8 +152,8 @@ void * QMPool::get( QFreeBlock * const fb_next = fb->m_next; // the free block must have integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(302, Q_UINTPTR_CAST_(fb_next) - == static_cast(~fb->m_next_dis)); + Q_INVARIANT_INCRIT(302, Q_UINTPTR_CAST_(fb_next) + == static_cast(~fb->m_next_dis)); m_nFree = (m_nFree - 1U); // one free block less if (m_nFree == 0U) { // is the pool becoming empty? @@ -230,7 +230,7 @@ void QMPool::put( #endif // set as new head of the free list - m_free_head = static_cast(block); + m_free_head = fb; m_nFree = m_nFree + 1U; // one more free block in this pool diff --git a/src/qf/qf_ps.cpp b/src/qf/qf_ps.cpp index 94c883f8..6b85156c 100644 --- a/src/qf/qf_ps.cpp +++ b/src/qf/qf_ps.cpp @@ -121,7 +121,7 @@ void QActive::publish_( QF_MEM_SYS(); Q_REQUIRE_INCRIT(200, sig < static_cast(maxPubSignal_)); - Q_REQUIRE_INCRIT(202, + Q_INVARIANT_INCRIT(202, subscrList_[sig].m_set.verify_(&subscrList_[sig].m_set_dis)); QS_BEGIN_PRE_(QS_QF_PUBLISH, qsId) @@ -164,9 +164,9 @@ void QActive::publish_( QF_SCHED_STAT_ QF_SCHED_LOCK_(p); // lock the scheduler up to AO's prio - std::uint_fast8_t limit = QF_MAX_ACTIVE + 1U; + std::uint_fast8_t lbound = QF_MAX_ACTIVE + 1U; do { // loop over all subscribers - --limit; + --lbound; // POST() asserts internally if the queue overflows a->POST(e, sender); @@ -188,7 +188,7 @@ void QActive::publish_( else { p = 0U; // no more subscribers } - } while ((p != 0U) && (limit > 0U)); + } while ((p != 0U) && (lbound > 0U)); QF_CRIT_ENTRY(); Q_ENSURE_INCRIT(290, p == 0U); @@ -223,7 +223,7 @@ void QActive::subscribe(enum_t const sig) const noexcept { && (sig < maxPubSignal_) && (0U < p) && (p <= QF_MAX_ACTIVE) && (registry_[p] == this)); - Q_REQUIRE_INCRIT(302, + Q_INVARIANT_INCRIT(302, subscrList_[sig].m_set.verify_(&subscrList_[sig].m_set_dis)); QS_BEGIN_PRE_(QS_QF_ACTIVE_SUBSCRIBE, m_prio) @@ -260,7 +260,7 @@ void QActive::unsubscribe(enum_t const sig) const noexcept { && (sig < maxPubSignal_) && (0U < p) && (p <= QF_MAX_ACTIVE) && (registry_[p] == this)); - Q_REQUIRE_INCRIT(402, + Q_INVARIANT_INCRIT(402, subscrList_[sig].m_set.verify_(&subscrList_[sig].m_set_dis)); QS_BEGIN_PRE_(QS_QF_ACTIVE_UNSUBSCRIBE, m_prio) diff --git a/src/qf/qf_time.cpp b/src/qf/qf_time.cpp index cd8187b2..711f70a5 100644 --- a/src/qf/qf_time.cpp +++ b/src/qf/qf_time.cpp @@ -300,8 +300,8 @@ void QTimeEvt::tick( QS_END_PRE_() // scan the linked-list of time events at this rate... - std::uint_fast8_t limit = 2U*QF_MAX_ACTIVE; // loop hard limit - for (; limit > 0U; --limit) { + std::uint_fast8_t lbound = 2U*QF_MAX_ACTIVE; // fixed upper loop bound + for (; lbound > 0U; --lbound) { QTimeEvt *e = prev->m_next; // advance down the time evt. list if (e == nullptr) { // end of the list? @@ -321,7 +321,7 @@ void QTimeEvt::tick( } // the time event 'e' must be valid - Q_ASSERT_INCRIT(112, QEvt::verify_(e)); + Q_INVARIANT_INCRIT(112, QEvt::verify_(e)); if (e->m_ctr == 0U) { // time event scheduled for removal? prev->m_next = e->m_next; @@ -410,7 +410,7 @@ void QTimeEvt::tick( QF_MEM_SYS(); } - Q_ENSURE_INCRIT(190, limit > 0U); + Q_ENSURE_INCRIT(190, lbound > 0U); QF_MEM_APP(); QF_CRIT_EXIT(); } diff --git a/src/qk/qk.cpp b/src/qk/qk.cpp index 7dd44be1..1dc7e9a7 100644 --- a/src/qk/qk.cpp +++ b/src/qk/qk.cpp @@ -79,7 +79,7 @@ QSchedStatus schedLock(std::uint_fast8_t const ceiling) noexcept { QF_MEM_SYS(); Q_REQUIRE_INCRIT(100, !QK_ISR_CONTEXT_()); - Q_REQUIRE_INCRIT(102, QK_priv_.lockCeil + Q_INVARIANT_INCRIT(102, QK_priv_.lockCeil == static_cast(~QK_priv_.lockCeil_dis)); // first store the previous lock prio @@ -119,7 +119,7 @@ void schedUnlock(QSchedStatus const prevCeil) noexcept { QF_CRIT_ENTRY(); QF_MEM_SYS(); - Q_REQUIRE_INCRIT(202, QK_priv_.lockCeil + Q_INVARIANT_INCRIT(202, QK_priv_.lockCeil == static_cast(~QK_priv_.lockCeil_dis)); Q_REQUIRE_INCRIT(210, (!QK_ISR_CONTEXT_()) && (QK_priv_.lockCeil > prevCeil)); @@ -161,7 +161,7 @@ QK_Attr QK_priv_; std::uint_fast8_t QK_sched_() noexcept { // NOTE: this function is entered with interrupts DISABLED - Q_REQUIRE_INCRIT(402, + Q_INVARIANT_INCRIT(402, QK_priv_.readySet.verify_(&QK_priv_.readySet_dis)); std::uint_fast8_t p; @@ -172,7 +172,7 @@ std::uint_fast8_t QK_sched_() noexcept { // find the highest-prio AO with non-empty event queue p = QK_priv_.readySet.findMax(); - Q_ASSERT_INCRIT(412, QK_priv_.actThre + Q_INVARIANT_INCRIT(412, QK_priv_.actThre == static_cast(~QK_priv_.actThre_dis)); // is the AO's prio. below the active preemption-threshold? @@ -180,7 +180,7 @@ std::uint_fast8_t QK_sched_() noexcept { p = 0U; // no activation needed } else { - Q_ASSERT_INCRIT(422, QK_priv_.lockCeil + Q_INVARIANT_INCRIT(422, QK_priv_.lockCeil == static_cast(~QK_priv_.lockCeil_dis)); // is the AO's prio. below the lock-ceiling? @@ -188,7 +188,7 @@ std::uint_fast8_t QK_sched_() noexcept { p = 0U; // no activation needed } else { - Q_ASSERT_INCRIT(432, QK_priv_.nextPrio + Q_INVARIANT_INCRIT(432, QK_priv_.nextPrio == static_cast(~QK_priv_.nextPrio_dis)); QK_priv_.nextPrio = p; // next AO to run #ifndef Q_UNSAFE @@ -209,7 +209,7 @@ void QK_activate_() noexcept { std::uint_fast8_t const prio_in = QK_priv_.actPrio; // save initial prio. std::uint_fast8_t p = QK_priv_.nextPrio; // next prio to run - Q_REQUIRE_INCRIT(502, + Q_INVARIANT_INCRIT(502, (prio_in == static_cast(~QK_priv_.actPrio_dis)) && (p == static_cast(~QK_priv_.nextPrio_dis))); Q_REQUIRE_INCRIT(510, (prio_in <= QF_MAX_ACTIVE) @@ -234,7 +234,7 @@ void QK_activate_() noexcept { Q_ASSERT_INCRIT(510, a != nullptr); pthre_in = static_cast(a->getPThre()); - Q_ASSERT_INCRIT(511, pthre_in == static_cast( + Q_INVARIANT_INCRIT(511, pthre_in == static_cast( ~static_cast(a->m_pthre_dis) & 0xFFU)); } @@ -244,7 +244,7 @@ void QK_activate_() noexcept { Q_ASSERT_INCRIT(520, a != nullptr); // the AO must be registered std::uint_fast8_t const pthre = static_cast(a->getPThre()); - Q_ASSERT_INCRIT(522, pthre == static_cast( + Q_INVARIANT_INCRIT(522, pthre == static_cast( ~static_cast(a->m_pthre_dis) & 0xFFU)); // set new active prio. and preemption-threshold @@ -272,6 +272,7 @@ void QK_activate_() noexcept { } #endif // QF_ON_CONTEXT_SW || Q_SPY + QF_MEM_APP(); QF_INT_ENABLE(); // unconditionally enable interrupts QP::QEvt const * const e = a->get_(); @@ -288,7 +289,7 @@ void QK_activate_() noexcept { QF_MEM_SYS(); // internal integrity check (duplicate inverse storage) - Q_ASSERT_INCRIT(532, + Q_INVARIANT_INCRIT(532, QK_priv_.readySet.verify_(&QK_priv_.readySet_dis)); if (a->getEQueue().isEmpty()) { // empty queue? @@ -310,7 +311,7 @@ void QK_activate_() noexcept { p = 0U; // no activation needed } else { - Q_ASSERT_INCRIT(542, + Q_INVARIANT_INCRIT(542, QK_priv_.lockCeil == ~QK_priv_.lockCeil_dis); // is the AO's prio. below the lock preemption-threshold? diff --git a/src/qs/qs.cpp b/src/qs/qs.cpp index e783cbfd..71d131aa 100644 --- a/src/qs/qs.cpp +++ b/src/qs/qs.cpp @@ -998,7 +998,7 @@ void target_info_pre_(std::uint8_t const isReset) { QS::u8_raw_(QS_OBJ_PTR_SIZE | (QS_FUN_PTR_SIZE << 4U)); QS::u8_raw_(QS_TIME_SIZE); - // send the limits... + // send the bounds... QS::u8_raw_(QF_MAX_ACTIVE); QS::u8_raw_(QF_MAX_EPOOL | (QF_MAX_TICK_RATE << 4U)); diff --git a/src/qv/qv.cpp b/src/qv/qv.cpp index 5d2d4ff6..f7a0116c 100644 --- a/src/qv/qv.cpp +++ b/src/qv/qv.cpp @@ -81,7 +81,7 @@ void schedDisable(std::uint_fast8_t const ceiling) { QF_CRIT_ENTRY(); QF_MEM_SYS(); - Q_ASSERT_INCRIT(102, priv_.schedCeil + Q_INVARIANT_INCRIT(102, priv_.schedCeil == static_cast(~priv_.schedCeil_dis)); if (ceiling > priv_.schedCeil) { // raising the scheduler ceiling? @@ -108,7 +108,7 @@ void schedEnable() { QF_CRIT_ENTRY(); QF_MEM_SYS(); - Q_ASSERT_INCRIT(202, priv_.schedCeil + Q_INVARIANT_INCRIT(202, priv_.schedCeil == static_cast(~priv_.schedCeil_dis)); if (priv_.schedCeil != 0U) { // actually enabling the scheduler? @@ -186,10 +186,10 @@ int_t run() { for (;;) { // QV event loop... // check internal integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(302, + Q_INVARIANT_INCRIT(302, QV::priv_.readySet.verify_(&QV::priv_.readySet_dis)); // check internal integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(303, QV::priv_.schedCeil + Q_INVARIANT_INCRIT(303, QV::priv_.schedCeil == static_cast(~QV::priv_.schedCeil_dis)); // find the maximum prio. AO ready to run diff --git a/src/qxk/qxk.cpp b/src/qxk/qxk.cpp index 54a71b49..d52d078d 100644 --- a/src/qxk/qxk.cpp +++ b/src/qxk/qxk.cpp @@ -175,7 +175,7 @@ QXK_Attr QXK_priv_; //${QXK-extern-C::QXK_sched_} ................................................ std::uint_fast8_t QXK_sched_() noexcept { - Q_REQUIRE_INCRIT(402, + Q_INVARIANT_INCRIT(402, QXK_priv_.readySet.verify_(&QXK_priv_.readySet_dis)); std::uint_fast8_t p; @@ -254,6 +254,7 @@ void QXK_activate_() noexcept { do { QXK_priv_.actPrio = p; // next active prio + QF_MEM_APP(); QF_INT_ENABLE(); // unconditionally enable interrupts QP::QEvt const * const e = next->get_(); @@ -269,7 +270,7 @@ void QXK_activate_() noexcept { QF_MEM_SYS(); // check internal integrity (duplicate inverse storage) - Q_ASSERT_INCRIT(502, + Q_INVARIANT_INCRIT(502, QXK_priv_.readySet.verify_(&QXK_priv_.readySet_dis)); if (next->getEQueue().isEmpty()) { // empty queue? diff --git a/src/qxk/qxk_mutex.cpp b/src/qxk/qxk_mutex.cpp index 7835fcce..52f23c74 100644 --- a/src/qxk/qxk_mutex.cpp +++ b/src/qxk/qxk_mutex.cpp @@ -165,7 +165,7 @@ bool QXMutex::lock(QTimeEvtCtr const nTicks) noexcept { // is the mutex locked by this thread already (nested locking)? else if (m_ao.m_osObject == curr) { - // the nesting level beyond the arbitrary but high limit + // the nesting level beyond the arbitrary but high bound // most likely means cyclic or recursive locking of a mutex. Q_ASSERT_INCRIT(220, m_ao.m_eQueue.m_nFree < 0xFFU); @@ -312,7 +312,7 @@ bool QXMutex::tryLock() noexcept { } // is the mutex locked by this thread already (nested locking)? else if (m_ao.m_osObject == curr) { - // the nesting level must not exceed the specified limit + // the nesting level must not exceed the specified bound Q_ASSERT_INCRIT(320, m_ao.m_eQueue.m_nFree < 0xFFU); // lock one more level