qxk.h 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. /*$file${include::qxk.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  2. /*
  3. * Model: qpc.qm
  4. * File: ${include::qxk.h}
  5. *
  6. * This code has been generated by QM 5.2.5 <www.state-machine.com/qm>.
  7. * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
  8. *
  9. * This code is covered by the following QP license:
  10. * License # : LicenseRef-QL-dual
  11. * Issued to : Any user of the QP/C real-time embedded framework
  12. * Framework(s) : qpc
  13. * Support ends : 2023-12-31
  14. * License scope:
  15. *
  16. * Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
  17. *
  18. * SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
  19. *
  20. * This software is dual-licensed under the terms of the open source GNU
  21. * General Public License version 3 (or any later version), or alternatively,
  22. * under the terms of one of the closed source Quantum Leaps commercial
  23. * licenses.
  24. *
  25. * The terms of the open source GNU General Public License version 3
  26. * can be found at: <www.gnu.org/licenses/gpl-3.0>
  27. *
  28. * The terms of the closed source Quantum Leaps commercial licenses
  29. * can be found at: <www.state-machine.com/licensing>
  30. *
  31. * Redistributions in source code must retain this top-level comment block.
  32. * Plagiarizing this software to sidestep the license obligations is illegal.
  33. *
  34. * Contact information:
  35. * <www.state-machine.com/licensing>
  36. * <info@state-machine.com>
  37. */
  38. /*$endhead${include::qxk.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  39. /*! @file
  40. * @brief QXK/C (preemptive dual-mode kernel) platform-independent
  41. * public interface.
  42. */
  43. #ifndef QXK_H_
  44. #define QXK_H_
  45. /*==========================================================================*/
  46. /* QF configuration for QXK -- data members of the QActive class... */
  47. /* QXK event-queue used for AOs */
  48. #define QF_EQUEUE_TYPE QEQueue
  49. /* QXK OS-object used to store the private stack pointer for extended threads.
  50. * (The private stack pointer is NULL for basic-threads).
  51. */
  52. #define QF_OS_OBJECT_TYPE void*
  53. /* QXK thread type used to store the private Thread-Local Storage pointer */
  54. #define QF_THREAD_TYPE void*
  55. /*! Access Thread-Local Storage (TLS) and cast it on the given `type_` */
  56. #define QXK_TLS(type_) ((type_)QXK_current()->thread)
  57. /*==========================================================================*/
  58. #include "qequeue.h" /* QXK kernel uses the native QP event queue */
  59. #include "qmpool.h" /* QXK kernel uses the native QP memory pool */
  60. #include "qf.h" /* QF framework integrates directly with QXK */
  61. /*==========================================================================*/
  62. /*$declare${QXK::QXK-extern-C} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  63. /*${QXK::QXK-extern-C::Attr} ...............................................*/
  64. /*! @brief The QXK kernel class
  65. * @class QXK
  66. *
  67. * @note
  68. * The order and alignment of the data members in this struct might
  69. * be important in QXK ports, where the members might be accessed
  70. * in assembly.
  71. */
  72. typedef struct QXK_Attr {
  73. struct QActive * volatile curr; /*!< current thread (NULL=basic) */
  74. struct QActive * volatile next; /*!< next thread to run */
  75. struct QActive * volatile prev; /*!< previous thread */
  76. uint8_t volatile actPrio; /*!< QF-prio of the active AO */
  77. uint8_t volatile lockCeil; /*!< lock-ceiling (0==no-lock) */
  78. uint8_t volatile lockHolder; /*!< prio of the lock holder */
  79. } QXK;
  80. /*${QXK::QXK-extern-C::attr_} ..............................................*/
  81. /*! attributes of the QXK kernel
  82. * @static @private @memberof QXK
  83. */
  84. extern QXK QXK_attr_;
  85. /*${QXK::QXK-extern-C::sched_} .............................................*/
  86. /*! QXK scheduler finds the highest-priority thread ready to run
  87. * @static @private @memberof QXK
  88. *
  89. * @details
  90. * The QXK scheduler finds the priority of the highest-priority thread
  91. * that is ready to run.
  92. *
  93. * @returns
  94. * the 1-based priority of the the thread (basic or extended) run next,
  95. * or zero if no eligible thread is found.
  96. *
  97. * @attention
  98. * QXK_sched_() must be always called with interrupts **disabled** and
  99. * returns with interrupts **disabled**.
  100. */
  101. uint_fast8_t QXK_sched_(void);
  102. /*${QXK::QXK-extern-C::activate_} ..........................................*/
  103. /*! QXK activator activates the next active object. The activated AO
  104. * preempts the currently executing AOs.
  105. * @static @private @memberof QXK
  106. *
  107. * @details
  108. * QXK_activate_() activates ready-to run AOs that are above the initial
  109. * active priority (QXK_attr_.actPrio).
  110. *
  111. * @precondition{qxk,700}
  112. * - QXK_attr_.next must be valid and the prio must be in range
  113. *
  114. * @attention
  115. * QXK_activate_() must be always called with interrupts **disabled** and
  116. * returns with interrupts **disabled**.
  117. */
  118. void QXK_activate_(void);
  119. /*${QXK::QXK-extern-C::current} ............................................*/
  120. /*! obtain the currently executing active-object/thread
  121. * @static @public @memberof QXK
  122. *
  123. * @returns
  124. * pointer to the currently executing active-object/thread
  125. *
  126. * @precondition{qxk,800}
  127. * - the QXK kernel must be running
  128. *
  129. * @postcondition{qxk,890}
  130. * - the current thread must be valid
  131. */
  132. QActive * QXK_current(void);
  133. /*${QXK::QXK-extern-C::stackInit_} .........................................*/
  134. /*! initialize the private stack of a given AO (defined in QXK port)
  135. * @static @private @memberof QXK
  136. */
  137. void QXK_stackInit_(
  138. void * thr,
  139. QXThreadHandler const handler,
  140. void * const stkSto,
  141. uint_fast16_t const stkSize);
  142. /*${QXK::QXK-extern-C::contextSw} ..........................................*/
  143. #if defined(Q_SPY) || defined(QF_ON_CONTEXT_SW)
  144. /*! QXK context switch management
  145. * @static @public @memberof QXK
  146. *
  147. * @details
  148. * This function performs software tracing (if #Q_SPY is defined)
  149. * and calls QF_onContextSw() (if #QF_ON_CONTEXT_SW is defined)
  150. *
  151. * @param[in] next pointer to the next thread (NULL for basic-thread)
  152. *
  153. * @attention
  154. * QXK_contextSw() is invoked with interrupts **disabled** and must also
  155. * return with interrupts **disabled**.
  156. */
  157. void QXK_contextSw(QActive * const next);
  158. #endif /* defined(Q_SPY) || defined(QF_ON_CONTEXT_SW) */
  159. /*$enddecl${QXK::QXK-extern-C} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  160. /*--------------------------------------------------------------------------*/
  161. /*$declare${QXK::QXK-base} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  162. /*${QXK::QXK-base::onIdle} .................................................*/
  163. /*! QXK idle callback (customized in BSPs for QXK)
  164. * @static @public @memberof QXK
  165. *
  166. * @details
  167. * QXK_onIdle() is called continuously by the QXK idle thread. This callback
  168. * gives the application an opportunity to enter a power-saving CPU mode,
  169. * or perform some other idle processing.
  170. *
  171. * @note
  172. * QXK_onIdle() is invoked with interrupts enabled and must also return with
  173. * interrupts enabled.
  174. */
  175. void QXK_onIdle(void);
  176. /*${QXK::QXK-base::schedLock} ..............................................*/
  177. /*! QXK Scheduler lock
  178. * @static @public @memberof QXK
  179. *
  180. * @details
  181. * This function locks the QXK scheduler to the specified ceiling.
  182. *
  183. * @param[in] ceiling preemption ceiling to which the QXK scheduler
  184. * needs to be locked
  185. *
  186. * @returns
  187. * The previous QXK Scheduler lock status, which is to be used to unlock
  188. * the scheduler by restoring its previous lock status in
  189. * QXK_schedUnlock().
  190. *
  191. * @precondition{qxk,400}
  192. * - the QXK scheduler lock cannot be called from an ISR
  193. *
  194. * @note
  195. * A QXK scheduler can be locked from both basic threads (AOs) and
  196. * extended threads and the scheduler locks can nest.
  197. *
  198. * @note
  199. * QXK_schedLock() must be always followed by the corresponding
  200. * QXK_schedUnlock().
  201. *
  202. * @attention
  203. * QXK will fire an assertion if a thread holding the lock attempts
  204. * to block.
  205. *
  206. * @sa QXK_schedUnlock()
  207. *
  208. * @usage
  209. * The following example shows how to lock and unlock the QXK scheduler:
  210. * @include qxk_lock.c
  211. */
  212. QSchedStatus QXK_schedLock(uint_fast8_t const ceiling);
  213. /*${QXK::QXK-base::schedUnlock} ............................................*/
  214. /*! QXK Scheduler unlock
  215. * @static @public @memberof QXK
  216. *
  217. * @details
  218. * This function unlocks the QXK scheduler to the previous status.
  219. *
  220. * @param[in] stat previous QXK Scheduler lock status returned from
  221. * QXK_schedLock()
  222. *
  223. * @precondition{qxk,500}
  224. * - the QXK scheduler cannot be unlocked from the ISR context
  225. * @precondition{qxk,501}
  226. * - the current lock ceiling must be greater than the previous
  227. *
  228. * @note
  229. * A QXK scheduler can be locked from both basic threads (AOs) and
  230. * extended threads and the scheduler locks can nest.
  231. *
  232. * @note
  233. * QXK_schedUnlock() must always follow the corresponding QXK_schedLock().
  234. *
  235. * @usage
  236. * The following example shows how to lock and unlock the QXK scheduler:
  237. * @include qxk_lock.c
  238. */
  239. void QXK_schedUnlock(QSchedStatus const stat);
  240. /*${QXK::QXK-base::Timeouts} ...............................................*/
  241. /*! timeout signals for extended threads
  242. * @static @private @memberof QXK
  243. */
  244. enum QXK_Timeouts {
  245. QXK_DELAY_SIG = 1,
  246. QXK_TIMEOUT_SIG
  247. };
  248. /*$enddecl${QXK::QXK-base} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  249. /*$declare${QXK::QXThread} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  250. /*${QXK::QXThread} .........................................................*/
  251. /*! @brief eXtended (blocking) thread of the QXK preemptive kernel
  252. * @class QXThread
  253. * @extends QActive
  254. *
  255. * @details
  256. * ::QXThread represents the eXtended (blocking) thread of the QXK
  257. * kernel. Each extended thread in the application must be represented
  258. * by the corresponding ::QXThread instance
  259. *
  260. * @note
  261. * Typically, ::QXThread is instantiated directly in the application code.
  262. * The customization of the thread occurs in the QXThread_ctor(), where you
  263. * provide the thread-handler function as the parameter.
  264. *
  265. * @usage
  266. * The following example illustrates how to instantiate and use an extended
  267. * thread in your application.
  268. * @include qxk_thread.c
  269. */
  270. typedef struct QXThread {
  271. /* protected: */
  272. QActive super;
  273. /* private: */
  274. /*! time event to handle blocking timeouts */
  275. QTimeEvt timeEvt;
  276. } QXThread;
  277. /* public: */
  278. /*! constructor of an extended-thread
  279. * @public @memberof QXThread
  280. *
  281. * @details
  282. * Performs the first step of QXThread initialization by assigning the
  283. * thread-handler function and the tick rate at which it will handle
  284. * the timeouts.
  285. *
  286. * @param[in,out] me current instance pointer (see @ref oop)
  287. * @param[in] handler the thread-handler function
  288. * @param[in] tickRate the ticking rate for timeouts in this thread
  289. * (see QXThread_delay() and QTIMEEVT_TICK_X())
  290. *
  291. * @note
  292. * Must be called only ONCE before QXTHREAD_START().
  293. *
  294. * @usage
  295. * The following example illustrates how to invoke QXThread_ctor() in the
  296. * main() function
  297. *
  298. * @include
  299. * qxk_thread_ctor.c
  300. */
  301. void QXThread_ctor(QXThread * const me,
  302. QXThreadHandler const handler,
  303. uint_fast8_t const tickRate);
  304. /*! delay (block) the current extended thread for a specified # ticks
  305. * @static @public @memberof QXThread
  306. *
  307. * @details
  308. * Blocking delay for the number of clock tick at the associated tick rate.
  309. *
  310. * @param[in] nTicks number of clock ticks (at the associated rate)
  311. * to wait for the event to arrive.
  312. *
  313. * @returns
  314. * 'true' if delay has expired, 'false' if it delay was canceled with
  315. * QXThread_delayCancel().
  316. *
  317. * @precondition{qxk_xthr,800}
  318. * - must NOT be called from an ISR;
  319. * - number of ticks cannot be zero
  320. * - be called from an extended thread;
  321. * - the thread must NOT be already blocked on any object.
  322. * @precondition{qxk_xthr,801}
  323. * - the thread must NOT be holding a scheduler lock.
  324. *
  325. * @note
  326. * For the delay to work, the QTIMEEVT_TICK_X() macro needs to be called
  327. * periodically at the associated clock tick rate.
  328. *
  329. * @sa QXThread_ctor()
  330. * @sa QTIMEEVT_TICK_X()
  331. */
  332. bool QXThread_delay(uint_fast16_t const nTicks);
  333. /*! cancel the delay
  334. * @public @memberof QXThread
  335. *
  336. * @details
  337. * Cancel the blocking delay and cause return from the QXThread_delay()
  338. * function.
  339. *
  340. * @returns
  341. * "true" if the thread was actually blocked on QXThread_delay() and
  342. * "false" otherwise.
  343. */
  344. bool QXThread_delayCancel(QXThread * const me);
  345. /*! obtain a message from the private message queue (block if no messages)
  346. * @static @public @memberof QXThread
  347. *
  348. * @details
  349. * The QXThread_queueGet() operation allows the calling extended thread to
  350. * receive QP events directly into its own built-in event queue from an ISR,
  351. * basic thread (AO), or another extended thread.
  352. *
  353. * If QXThread_queueGet() is called when no events are present in the
  354. * thread's private event queue, the operation blocks the current extended
  355. * thread until either an event is received, or a user-specified timeout
  356. * expires.
  357. *
  358. * @param[in] nTicks number of clock ticks (at the associated rate)
  359. * to wait for the event to arrive. The value of
  360. * ::QXTHREAD_NO_TIMEOUT indicates that no timeout will
  361. * occur and the queue will block indefinitely.
  362. * @returns
  363. * A pointer to the event. If the pointer is not NULL, the event was delivered.
  364. * Otherwise the event pointer of NULL indicates that the queue has timed out.
  365. *
  366. * @precondition{qxk_xthr,500}
  367. * - must NOT be called from an ISR;
  368. * - be called from an extended thread;
  369. * - the thread must NOT be already blocked on any object.
  370. * @precondition{qxk_xthr,501}
  371. * - the thread must NOT be holding a scheduler lock.
  372. */
  373. QEvt const * QXThread_queueGet(uint_fast16_t const nTicks);
  374. /* protected: */
  375. /*! Overrides QHsm_init_()
  376. * @private @memberof QXThread
  377. */
  378. void QXThread_init_(
  379. QHsm * const me,
  380. void const * const par,
  381. uint_fast8_t const qs_id);
  382. /*! Overrides QHsm_dispatch_()
  383. * @private @memberof QXThread
  384. */
  385. void QXThread_dispatch_(
  386. QHsm * const me,
  387. QEvt const * const e,
  388. uint_fast8_t const qs_id);
  389. /*! start QXThread private implementation
  390. * @private @memberof QXThread
  391. *
  392. * @details
  393. * Starts execution of an extended thread and registers it with the framework.
  394. * The extended thread becomes ready-to-run immediately and is scheduled
  395. * if the QXK is already running.
  396. *
  397. * @param[in,out] me current instance pointer (see @ref oop)
  398. * @param[in] prio QF-priority of the thread, but no preemption-
  399. * threshold. See also ::QPrioSpec.
  400. * @param[in] qSto pointer to the storage for the ring buffer of the
  401. * event queue. This cold be NULL, if this extended
  402. * thread does not use the built-in event queue.
  403. * @param[in] qLen length of the event queue [in events],
  404. * or zero if queue not used
  405. * @param[in] stkSto pointer to the stack storage (must be provided)
  406. * @param[in] stkSize stack size [in bytes] (must not be zero)
  407. * @param[in] par pointer to an extra parameter (might be NULL).
  408. *
  409. * @precondition{qxk_xthr,200}
  410. * - must NOT be called from an ISR;
  411. * - the stack storage must be provided;
  412. * - the thread must be instantiated (see QXThread_ctor())
  413. * - preemption-threshold is NOT provided (because QXK kernel
  414. * does not support preemption-threshold scheduling)
  415. *
  416. * @note
  417. * Currently, extended trheads in QXK do NOT support preemption-threshold.
  418. * The `prio` must NOT provide preemption-threshold and this function
  419. * will assert it in the precondition.
  420. *
  421. * @usage
  422. * QXThread_start_() should NOT be called directly, only via the macro
  423. * QXTHREAD_START(). The following example shows starting an extended
  424. * thread:
  425. * @include qxk_start.c
  426. */
  427. void QXThread_start_(
  428. QActive * const me,
  429. QPrioSpec const prioSpec,
  430. QEvt const * * const qSto,
  431. uint_fast16_t const qLen,
  432. void * const stkSto,
  433. uint_fast16_t const stkSize,
  434. void const * const par);
  435. /*! post to the QXThread event queue private implementation
  436. * @private @memberof QXThread
  437. *
  438. * @details
  439. * Direct event posting is the simplest asynchronous communication method
  440. * available in QF. The following example illustrates how the Philo active
  441. * object posts directly the HUNGRY event to the Table active object.
  442. * <br>
  443. * The parameter `margin` specifies the minimum number of free slots in
  444. * the queue that must be available for posting to succeed. The function
  445. * returns 1 (success) if the posting succeeded (with the provided margin)
  446. * and 0 (failure) when the posting fails.
  447. *
  448. * @param[in,out] me current instance pointer (see @ref oop)
  449. * @param[in] e pointer to the event to be posted
  450. * @param[in] margin number of required free slots in the queue after
  451. * posting the event. The special value #QF_NO_MARGIN
  452. * means that this function will assert if posting fails.
  453. * @param[in] sender pointer to a sender object (used only for QS tracing).
  454. *
  455. * @returns
  456. * 'true' (success) if the posting succeeded (with the provided margin) and
  457. * 'false' (failure) when the posting fails.
  458. *
  459. * @note
  460. * Should be called only via the macro QXTHREAD_POST_X().
  461. *
  462. * @note
  463. * The #QF_NO_MARGIN value of the `margin` parameter is special and
  464. * denotes situation when the post() operation is assumed to succeed
  465. * (event delivery guarantee). An assertion fires, when the event cannot
  466. * be delivered in this case.
  467. *
  468. * @note
  469. * For compatibility with the V-table from the superclass ::QActive, the
  470. * me-pointer is typed as pointing to QActive. However, the `me` pointer
  471. * here actually points to the QXThread subclass. Therefore the downcast
  472. * (QXThread *)me is always correct.
  473. */
  474. bool QXThread_post_(
  475. QActive * const me,
  476. QEvt const * const e,
  477. uint_fast16_t const margin,
  478. void const * const sender);
  479. /*! post to the QXThread event queue (LIFO) private implementation
  480. * @private @memberof QXThread
  481. *
  482. * @details
  483. * Last-In-First-Out (LIFO) policy is not supported for extened threads.
  484. *
  485. * @param[in] me current instance pointer (see @ref oop)
  486. * @param[in] e pointer to the event to post to the queue
  487. *
  488. * @sa
  489. * QActive_postLIFO_()
  490. */
  491. void QXThread_postLIFO_(
  492. QActive * const me,
  493. QEvt const * const e);
  494. /* private: */
  495. /*! block QXThread private implementation
  496. * @private @memberof QXThread
  497. *
  498. * @details
  499. * Internal implementation of blocking the given extended thread.
  500. *
  501. * @precondition{qxk_xthr,600}
  502. * - the thread holding the lock cannot block!
  503. *
  504. * @note
  505. * Must be called from within a critical section
  506. */
  507. void QXThread_block_(QXThread const * const me);
  508. /*! unblock QXThread private implementation
  509. * @private @memberof QXThread
  510. *
  511. * @details
  512. * Internal implementation of un-blocking the given extended thread.
  513. *
  514. * @note
  515. * must be called from within a critical section
  516. */
  517. void QXThread_unblock_(QXThread const * const me);
  518. /*! arm internal time event private implementation
  519. * @private @memberof QXThread
  520. *
  521. * @details
  522. * Internal implementation of arming the private time event for a given
  523. * timeout at a given system tick rate.
  524. *
  525. * @precondition{qxk_xthr,700}
  526. * - the time event must be unused
  527. *
  528. * @note
  529. * Must be called from within a critical section
  530. */
  531. void QXThread_teArm_(QXThread * const me,
  532. enum_t const sig,
  533. uint_fast16_t const nTicks);
  534. /*! disarm internal time event private implementation
  535. * @private @memberof QXThread
  536. *
  537. * @details
  538. * Internal implementation of disarming the private time event.
  539. *
  540. * @note
  541. * Must be called from within a critical section
  542. */
  543. bool QXThread_teDisarm_(QXThread * const me);
  544. /*! dummy static to force generation of "struct QXThread" */
  545. extern QXThread const * QXThread_dummy;
  546. /*$enddecl${QXK::QXThread} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  547. /*$declare${QXK::QXThreadVtable} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  548. /*${QXK::QXThreadVtable} ...................................................*/
  549. /*! @brief Virtual Table for the ::QXThread class
  550. * (inherited from ::QActiveVtable)
  551. *
  552. * @note
  553. * ::QXThread inherits ::QActive without adding any new virtual
  554. * functions and therefore, ::QXThreadVtable is typedef'ed as ::QActiveVtable.
  555. */
  556. typedef QActiveVtable QXThreadVtable;
  557. /*$enddecl${QXK::QXThreadVtable} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  558. /*$declare${QXK::QXSemaphore} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  559. /*${QXK::QXSemaphore} ......................................................*/
  560. /*! @brief Counting Semaphore of the QXK preemptive kernel
  561. * @class QXSemaphore
  562. *
  563. * @details
  564. * ::QXSemaphore is a blocking mechanism intended primarily for signaling
  565. * @ref ::QXThread "extended threads". The semaphore is initialized with
  566. * the maximum count (see QXSemaphore_init()), which allows you to create
  567. * a binary semaphore (when the maximum count is 1) and
  568. * counting semaphore when the maximum count is > 1.
  569. *
  570. * @usage
  571. * The following example illustrates how to instantiate and use the semaphore
  572. * in your application.
  573. * @include qxk_sema.c
  574. */
  575. typedef struct {
  576. /* private: */
  577. /*! set of extended threads waiting on this semaphore */
  578. QPSet waitSet;
  579. /*! semaphore up-down counter */
  580. uint8_t volatile count;
  581. /*! maximum value of the semaphore counter */
  582. uint8_t max_count;
  583. } QXSemaphore;
  584. /* public: */
  585. /*! initialize the counting semaphore
  586. * @public @memberof QXSemaphore
  587. *
  588. * @details
  589. * Initializes a semaphore with the specified count and maximum count.
  590. * If the semaphore is used for resource sharing, both the initial count
  591. * and maximum count should be set to the number of identical resources
  592. * guarded by the semaphore. If the semaphore is used as a signaling
  593. * mechanism, the initial count should set to 0 and maximum count to 1
  594. * (binary semaphore).
  595. *
  596. * @param[in,out] me current instance pointer (see @ref oop)
  597. * @param[in] count initial value of the semaphore counter
  598. * @param[in] max_count maximum value of the semaphore counter.
  599. * The purpose of the max_count is to limit the counter
  600. * so that the semaphore cannot unblock more times than
  601. * the maximum.
  602. *
  603. * @precondition{qxk_sema,100}
  604. * - max_count must be greater than zero
  605. *
  606. * @note
  607. * QXSemaphore_init() must be called **before** the semaphore can be used
  608. * (signaled or waited on).
  609. */
  610. void QXSemaphore_init(QXSemaphore * const me,
  611. uint_fast8_t const count,
  612. uint_fast8_t const max_count);
  613. /*! wait (block) on the semaphore
  614. * @public @memberof QXSemaphore
  615. *
  616. * @details
  617. * When an extended thread calls QXSemaphore_wait() and the value of the
  618. * semaphore counter is greater than 0, QXSemaphore_wait() decrements the
  619. * semaphore counter and returns (true) to its caller. However, if the value
  620. * of the semaphore counter is 0, the function places the calling thread in
  621. * the waiting list for the semaphore. The thread waits until the semaphore
  622. * is signaled by calling QXSemaphore_signal(), or the specified timeout
  623. * expires. If the semaphore is signaled before the timeout expires, QXK
  624. * resumes the highest-priority extended thread waiting for the semaphore.
  625. *
  626. * @param[in,out] me current instance pointer (see @ref oop)
  627. * @param[in] nTicks number of clock ticks (at the associated rate)
  628. * to wait for the semaphore. The value of
  629. * ::QXTHREAD_NO_TIMEOUT indicates that no timeout will
  630. * occur and the semaphore will wait indefinitely.
  631. * @returns
  632. * 'true' if the semaphore has been signaled and 'false' if a timeout
  633. * occurred.
  634. *
  635. * @precondition{qxk_sema,200}
  636. * - must NOT be called from an ISR;
  637. * - the semaphore must be initialized
  638. * - be called from an extended thread;
  639. * - the thread must NOT be already blocked on any object.
  640. *
  641. * @precondition{qxk_sema,201}
  642. * - the thread must NOT be holding a scheduler lock.
  643. *
  644. * @note
  645. * Multiple extended threads can wait for a given semaphore.
  646. */
  647. bool QXSemaphore_wait(QXSemaphore * const me,
  648. uint_fast16_t const nTicks);
  649. /*! try wait on the semaphore (non-blocking)
  650. * @public @memberof QXSemaphore
  651. *
  652. * @details
  653. * This function checks if the semaphore counter is greater than 0,
  654. * in which case the counter is decremented.
  655. *
  656. * @param[in,out] me current instance pointer (see @ref oop)
  657. *
  658. * @returns
  659. * 'true' if the semaphore has count available and 'false' NOT available.
  660. *
  661. * @precondition{qxk_sema,300}
  662. * - the semaphore must be initialized
  663. *
  664. * @note
  665. * This function can be called from any context, including ISRs and basic
  666. * threads (active objects).
  667. */
  668. bool QXSemaphore_tryWait(QXSemaphore * const me);
  669. /*! signal (unblock) the semaphore
  670. * @public @memberof QXSemaphore
  671. *
  672. * @details
  673. * If the semaphore counter value is 0 or more, it is incremented, and
  674. * this function returns to its caller. If the extended threads are waiting
  675. * for the semaphore to be signaled, QXSemaphore_signal() removes the highest-
  676. * priority thread waiting for the semaphore from the waiting list and makes
  677. * this thread ready-to-run. The QXK scheduler is then called to determine if
  678. * the awakened thread is now the highest-priority thread that is ready-to-run.
  679. *
  680. * @param[in,out] me current instance pointer (see @ref oop)
  681. *
  682. * @returns
  683. * 'true' when the semaphore signaled and 'false' when the semaphore count
  684. * exceeded the maximum.
  685. *
  686. * @precondition{qxk_sema,400}
  687. * - the semaphore must be initialized
  688. *
  689. * @note
  690. * A semaphore can be signaled from many places, including from ISRs, basic
  691. * threads (AOs), and extended threads.
  692. */
  693. bool QXSemaphore_signal(QXSemaphore * const me);
  694. /*$enddecl${QXK::QXSemaphore} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  695. /*$declare${QXK::QXMutex} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  696. /*${QXK::QXMutex} ..........................................................*/
  697. /*! @brief Blocking Mutex the QXK preemptive kernel
  698. * @class QXMutex
  699. *
  700. * @details
  701. * ::QXMutex is a blocking mutual exclusion mechanism that can also apply
  702. * the **priority-ceiling protocol** to avoid unbounded priority inversion
  703. * (if initialized with a non-zero ceiling priority, see QXMutex_init()).
  704. * In that case, ::QXMutex requires its own uinque QP priority level, which
  705. * cannot be used by any thread or any other ::QXMutex.
  706. * If initialized with preemption-ceiling of zero, ::QXMutex does **not**
  707. * use the priority-ceiling protocol and does not require a unique QP
  708. * priority (see QXMutex_init()).
  709. * ::QXMutex is **recursive** (re-entrant), which means that it can be locked
  710. * multiple times (up to 255 levels) by the *same* thread without causing
  711. * deadlock.
  712. * ::QXMutex is primarily intended for the @ref ::QXThread
  713. * "extened (blocking) threads", but can also be used by the @ref ::QActive
  714. * "basic threads" through the non-blocking QXMutex_tryLock() API.
  715. *
  716. * @note
  717. * ::QXMutex should be used in situations when at least one of the extended
  718. * threads contending for the mutex blocks while holding the mutex (between
  719. * the QXMutex_lock() and QXMutex_unlock() operations). If no blocking is
  720. * needed while holding the mutex, the more efficient non-blocking mechanism
  721. * of @ref srs_qxk_schedLock() "selective QXK scheduler locking" should be used
  722. * instead. @ref srs_qxk_schedLock() "Selective scheduler locking" is available
  723. * for both @ref ::QActive "basic threads" and @ref ::QXThread "extended
  724. * threads", so it is applicable to situations where resources are shared
  725. * among all these threads.
  726. *
  727. * @usage
  728. * The following example illustrates how to instantiate and use the mutex
  729. * in your application.
  730. * @include qxk_mutex.c
  731. */
  732. typedef struct {
  733. /* private: */
  734. /*! active object used as a placeholder AO for this mutex
  735. * in QActive_registry_[]
  736. */
  737. QActive ao;
  738. /*! set of extended-threads waiting on this mutex */
  739. QPSet waitSet;
  740. } QXMutex;
  741. /* public: */
  742. /*! initialize the QXK priority-ceiling mutex ::QXMutex
  743. * @public @memberof QXMutex
  744. *
  745. * @details
  746. * Initialize the QXK priority ceiling mutex.
  747. *
  748. * @param[in,out] me current instance pointer (see @ref oop)
  749. * @param[in] prioSpec the priority specification for the mutex
  750. * (See also ::QPrioSpec). This value might
  751. * also be zero.
  752. *
  753. * @precondition{qxk_mutex,100}
  754. * - preemption-threshold must not be used
  755. *
  756. * @note
  757. * `prioSpec == 0` means that the priority-ceiling protocol shall **not**
  758. * be used by this mutex. Such mutex will **not** change (boost) the
  759. * priority of the holding threads.<br>
  760. *
  761. * Conversely, `prioSpec != 0` means that the priority-ceiling protocol
  762. * shall be used by this mutex. Such mutex **will** temporarily boost
  763. * the priority and priority-threshold of the holding thread to the
  764. * priority specification in `prioSpec` (see ::QPrioSpec).
  765. *
  766. * @usage
  767. * @include qxk_mutex.c
  768. */
  769. void QXMutex_init(QXMutex * const me,
  770. QPrioSpec const prioSpec);
  771. /*! lock the QXK priority-ceiling mutex ::QXMutex
  772. * @public @memberof QXMutex
  773. *
  774. * @param[in,out] me current instance pointer (see @ref oop)
  775. * @param[in] nTicks number of clock ticks (at the associated rate)
  776. * to wait for the mutex. The value of
  777. * ::QXTHREAD_NO_TIMEOUT indicates that no timeout will
  778. * occur and the mutex could block indefinitely.
  779. * @returns
  780. * 'true' if the mutex has been acquired and 'false' if a timeout occurred.
  781. *
  782. * @precondition{qxk_mutex,200}
  783. * - must NOT be called from an ISR;
  784. * - must be called from an extended thread;
  785. * - the mutex-priority must be in range;
  786. * - the thread must NOT be already blocked on any object.
  787. *
  788. * @note
  789. * The mutex locks are allowed to nest, meaning that the same extended thread
  790. * can lock the same mutex multiple times (< 255). However, each call to
  791. * QXMutex_lock() must be balanced by the matching call to QXMutex_unlock().
  792. *
  793. * @usage
  794. * @include qxk_mutex.c
  795. */
  796. bool QXMutex_lock(QXMutex * const me,
  797. uint_fast16_t const nTicks);
  798. /*! try to lock the QXK priority-ceiling mutex ::QXMutex
  799. * @public @memberof QXMutex
  800. *
  801. * @param[in,out] me current instance pointer (see @ref oop)
  802. *
  803. * @returns
  804. * 'true' if the mutex was successfully locked and 'false' if the mutex was
  805. * unavailable and was NOT locked.
  806. *
  807. * @precondition{qxk_mutex,300}
  808. * - must NOT be called from an ISR;
  809. * - the calling thread must be valid;
  810. * - the mutex-priority must be in range
  811. *
  812. * @precondition{qxk_mutex,301}
  813. * - the thread must NOT be holding a scheduler lock.
  814. *
  815. * @note
  816. * This function **can** be called from both basic threads (active objects)
  817. * and extended threads.
  818. *
  819. * @note
  820. * The mutex locks are allowed to nest, meaning that the same extended thread
  821. * can lock the same mutex multiple times (<= 255). However, each successful
  822. * call to QXMutex_tryLock() must be balanced by the matching call to
  823. * QXMutex_unlock().
  824. */
  825. bool QXMutex_tryLock(QXMutex * const me);
  826. /*! unlock the QXK priority-ceiling mutex ::QXMutex
  827. * @public @memberof QXMutex
  828. *
  829. * @param[in,out] me current instance pointer (see @ref oop)
  830. *
  831. * @precondition{qxk_mutex,400}
  832. * - must NOT be called from an ISR;
  833. * - the calling thread must be valid;
  834. *
  835. * @precondition{qxk_mutex,401}
  836. * - the mutex must be already locked at least once.
  837. *
  838. * @precondition{qxk_mutex,402}
  839. * - the mutex must be held by this thread.
  840. *
  841. * @note
  842. * This function **can** be called from both basic threads (active objects)
  843. * and extended threads.
  844. *
  845. * @note
  846. * The mutex locks are allowed to nest, meaning that the same extended thread
  847. * can lock the same mutex multiple times (<= 225). However, each call to
  848. * QXMutex_lock() or a *successful* call to QXMutex_tryLock() must be
  849. * balanced by the matching call to QXMutex_unlock().
  850. *
  851. * @usage
  852. * @include qxk_mutex.c
  853. */
  854. void QXMutex_unlock(QXMutex * const me);
  855. /*$enddecl${QXK::QXMutex} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  856. /*$declare${QXK-macros} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  857. /*${QXK-macros::QXTHREAD_START} ............................................*/
  858. /*! Virtual call to start an extened thread
  859. *
  860. * @details
  861. * Starts execution of the thread and registers the AO with the framework.
  862. *
  863. * @param[in,out] me_ current instance pointer (see @ref oop)
  864. * @param[in] prioSpec_ priority specification at which to start the
  865. * extended thread (see ::QPrioSpec)
  866. * @param[in] qSto_ pointer to the storage for the ring buffer of the
  867. * event queue (used only with the built-in ::QEQueue)
  868. * @param[in] qLen_ length of the event queue (in events)
  869. * @param[in] stkSto_ pointer to the stack storage (used only when
  870. * per-AO stack is needed)
  871. * @param[in] stkSize_ stack size (in bytes)
  872. * @param[in] par_ pointer to the additional port-specific parameter(s)
  873. * (might be NULL).
  874. * @usage
  875. * @include qxk_start.c
  876. */
  877. #define QXTHREAD_START(me_, prioSpec_, qSto_, qLen_, stkSto_, stkSize_, par_) \
  878. do { \
  879. Q_ASSERT((me_)->super.super.vptr); \
  880. ((*((QActiveVtable const *)((me_)->super.super.vptr))->start)( \
  881. &(me_)->super, (prioSpec_), (QEvt const **)(qSto_), (qLen_), \
  882. (stkSto_), (stkSize_), (par_))); \
  883. } while (false)
  884. /*${QXK-macros::QXTHREAD_NO_TIMEOUT} .......................................*/
  885. /*! No-timeout when blocking on semaphores, mutextes, and queues */
  886. #define QXTHREAD_NO_TIMEOUT ((uint_fast16_t)0)
  887. /*${QXK-macros::QXTHREAD_POST_X} ...........................................*/
  888. /*! Asynchronous posting events to the event queue of an eXtended thread
  889. * @details
  890. * This macro does not assert if the queue overflows and cannot accept
  891. * the event with the specified margin of free slots remaining.
  892. *
  893. * @param[in,out] me_ current instance pointer (see @ref oop)
  894. * @param[in] e_ pointer to the event to post
  895. * @param[in] margin_ the minimum free slots in the queue, which
  896. * must still be available after posting the event.
  897. * The special value #QF_NO_MARGIN causes asserting
  898. * failure in case event allocation fails.
  899. * @param[in] sender_ pointer to the sender object (used in QS tracing)
  900. *
  901. * @returns
  902. * 'true' if the posting succeeded, and 'false' if the posting failed due
  903. * to insufficient margin of free slots available in the queue.
  904. *
  905. * @note
  906. * The `sender_` parameter is actually only used when QS tracing is enabled
  907. * (macro #Q_SPY is defined). When QS software tracing is disabled, the
  908. * QXTHREAD_POST_X() macro does not pass the `sender_` parameter, so the
  909. * overhead of passing this extra argument is entirely avoided.
  910. *
  911. * @note
  912. * The pointer to the sender object is not necessarily a pointer to an
  913. * active object. In fact, if QXTHREAD_POST_X() is called from an interrupt
  914. * or other context, you can create a unique object just to unambiguously
  915. * identify the sender of the event.
  916. *
  917. * @usage
  918. * @include qf_postx.c
  919. */
  920. #define QXTHREAD_POST_X(me_, e_, margin_, sender_) \
  921. QACTIVE_POST_X(&(me_)->super, (e_), (margin_), (sender_))
  922. /*$enddecl${QXK-macros} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  923. /*==========================================================================*/
  924. /* interface used only inside QP implementation, but not in applications */
  925. #ifdef QP_IMPL
  926. /* QXK implementation... */
  927. /*$declare${QXK-impl} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  928. /*${QXK-impl::QXK_ISR_CONTEXT_} ............................................*/
  929. #ifndef QXK_ISR_CONTEXT_
  930. /*! Internal macro that reports the execution context (ISR vs. thread)
  931. *
  932. * @returns true if the code executes in the ISR context and false
  933. * otherwise
  934. */
  935. #define QXK_ISR_CONTEXT_() (QF_intNest_ != 0U)
  936. #endif /* ndef QXK_ISR_CONTEXT_ */
  937. /*${QXK-impl::QF_SCHED_STAT_} ..............................................*/
  938. /*! QXK scheduler lock status */
  939. #define QF_SCHED_STAT_ QSchedStatus lockStat_;
  940. /*${QXK-impl::QF_SCHED_LOCK_} ..............................................*/
  941. /*! QXK selective scheduler locking */
  942. #define QF_SCHED_LOCK_(ceil_) do { \
  943. if (QXK_ISR_CONTEXT_()) { \
  944. lockStat_ = 0xFFU; \
  945. } else { \
  946. lockStat_ = QXK_schedLock((ceil_)); \
  947. } \
  948. } while (false)
  949. /*${QXK-impl::QF_SCHED_UNLOCK_} ............................................*/
  950. /*! QXK selective scheduler unlocking */
  951. #define QF_SCHED_UNLOCK_() do { \
  952. if (lockStat_ != 0xFFU) { \
  953. QXK_schedUnlock(lockStat_); \
  954. } \
  955. } while (false)
  956. /*${QXK-impl::QACTIVE_EQUEUE_WAIT_} ........................................*/
  957. /*! QXK native event queue waiting */
  958. #define QACTIVE_EQUEUE_WAIT_(me_) \
  959. (Q_ASSERT_ID(110, (me_)->eQueue.frontEvt != (QEvt *)0))
  960. /*${QXK-impl::QACTIVE_EQUEUE_SIGNAL_} ......................................*/
  961. /*! QXK native event queue signaling */
  962. #define QACTIVE_EQUEUE_SIGNAL_(me_) do { \
  963. QPSet_insert(&QF_readySet_, (uint_fast8_t)(me_)->prio); \
  964. if (!QXK_ISR_CONTEXT_()) { \
  965. if (QXK_sched_() != 0U) { \
  966. QXK_activate_(); \
  967. } \
  968. } \
  969. } while (false)
  970. /*${QXK-impl::QXK_PTR_CAST_} ...............................................*/
  971. /*! internal macro to encapsulate casting of pointers for MISRA deviations
  972. *
  973. * @details
  974. * This macro is specifically and exclusively used for casting pointers
  975. * that are never de-referenced, but only used for internal bookkeeping and
  976. * checking (via assertions) the correct operation of the QXK kernel.
  977. * Such pointer casting is not compliant with MISRA-2012-Rule 11.3(req)
  978. * as well as other messages (e.g., PC-Lint-Plus warning 826).
  979. * Defining this specific macro for this purpose allows to selectively
  980. * disable the warnings for this particular case.
  981. */
  982. #define QXK_PTR_CAST_(type_, ptr_) ((type_)(ptr_))
  983. /*${QXK-impl::QXTHREAD_CAST_} ..............................................*/
  984. /*! internal macro to encapsulate casting of pointers for MISRA deviations
  985. *
  986. * @details
  987. * This macro is specifically and exclusively used for downcasting pointers
  988. * to QActive to pointers to QXThread in situations when it is known
  989. * that such downcasting is correct.However, such pointer casting is not
  990. * compliant with MISRA-2012-Rule 11.3(req) as well as other messages (e.g.,
  991. * PC-Lint-Plus warning 826). Defining this specific macro for this purpose
  992. * allows to selectively disable the warnings for this particular case.
  993. */
  994. #define QXTHREAD_CAST_(ptr_) ((QXThread *)(ptr_))
  995. /*${QXK-impl::QXK_threadExit_} .............................................*/
  996. /*! called when QXThread exits
  997. * @private @memberof QXThread
  998. *
  999. * @details
  1000. * Called when the extended-thread handler function returns.
  1001. *
  1002. * @precondition{qxk,900}
  1003. * - must NOT be called from an ISR;
  1004. * - must be called from an extended thread
  1005. * @precondition{qxk,901}
  1006. * - the thread must NOT be holding a scheduler lock
  1007. *
  1008. * @note
  1009. * Most thread handler functions are structured as endless loops that never
  1010. * return. But it is also possible to structure threads as one-shot functions
  1011. * that perform their job and return. In that case this function peforms
  1012. * cleanup after the thread.
  1013. */
  1014. void QXK_threadExit_(void);
  1015. /*$enddecl${QXK-impl} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  1016. /* Native QF event pool operations... */
  1017. /*$declare${QF-QMPool-impl} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
  1018. /*${QF-QMPool-impl::QF_EPOOL_TYPE_} ........................................*/
  1019. #define QF_EPOOL_TYPE_ QMPool
  1020. /*${QF-QMPool-impl::QF_EPOOL_INIT_} ........................................*/
  1021. #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
  1022. (QMPool_init(&(p_), (poolSto_), (poolSize_), (evtSize_)))
  1023. /*${QF-QMPool-impl::QF_EPOOL_EVENT_SIZE_} ..................................*/
  1024. #define QF_EPOOL_EVENT_SIZE_(p_) ((uint_fast16_t)(p_).blockSize)
  1025. /*${QF-QMPool-impl::QF_EPOOL_GET_} .........................................*/
  1026. #define QF_EPOOL_GET_(p_, e_, m_, qs_id_) \
  1027. ((e_) = (QEvt *)QMPool_get(&(p_), (m_), (qs_id_)))
  1028. /*${QF-QMPool-impl::QF_EPOOL_PUT_} .........................................*/
  1029. #define QF_EPOOL_PUT_(p_, e_, qs_id_) \
  1030. (QMPool_put(&(p_), (e_), (qs_id_)))
  1031. /*$enddecl${QF-QMPool-impl} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
  1032. #endif /* QP_IMPL */
  1033. #endif /* QXK_H_ */