qequeue.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /**
  2. * @file
  3. * @brief QP natvie, platform-independent, thread-safe event queue interface
  4. * @ingroup qf
  5. * @cond
  6. ******************************************************************************
  7. * Last updated for version 5.4.0
  8. * Last updated on 2015-04-13
  9. *
  10. * Q u a n t u m L e a P s
  11. * ---------------------------
  12. * innovating embedded systems
  13. *
  14. * Copyright (C) Quantum Leaps, www.state-machine.com.
  15. *
  16. * This program is open source software: you can redistribute it and/or
  17. * modify it under the terms of the GNU General Public License as published
  18. * by the Free Software Foundation, either version 3 of the License, or
  19. * (at your option) any later version.
  20. *
  21. * Alternatively, this program may be distributed and modified under the
  22. * terms of Quantum Leaps commercial licenses, which expressly supersede
  23. * the GNU General Public License and are specifically designed for
  24. * licensees interested in retaining the proprietary status of their code.
  25. *
  26. * This program is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. * GNU General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU General Public License
  32. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  33. *
  34. * Contact information:
  35. * Web: www.state-machine.com
  36. * Email: info@state-machine.com
  37. ******************************************************************************
  38. * @endcond
  39. */
  40. #ifndef qequeue_h
  41. #define qequeue_h
  42. /**
  43. * @description
  44. * This header file must be included in all QF ports that use native QF
  45. * event queue for active objects. Also, this file needs to be included
  46. * in the QP/C library when the application uses QActive_defer()/
  47. * QActive_recall(). Finally, this file is also needed when the "raw"
  48. * thread-safe queues are used for communication between active objects
  49. * and non-framework entities, such as ISRs, device drivers, or legacy
  50. * code.
  51. */
  52. #ifndef QF_EQUEUE_CTR_SIZE
  53. /*! The size (in bytes) of the ring-buffer counters used in the
  54. * native QF event queue implementation. Valid values: 1, 2, or 4;
  55. * default 1. */
  56. /**
  57. * @description
  58. * This macro can be defined in the QF port file (qf_port.h) to
  59. * configure the ::QEQueueCtr type. Here the macro is not defined so the
  60. * default of 1 byte is chosen.
  61. */
  62. #define QF_EQUEUE_CTR_SIZE 1
  63. #endif
  64. #if (QF_EQUEUE_CTR_SIZE == 1)
  65. /*! The data type to store the ring-buffer counters based on
  66. * the macro #QF_EQUEUE_CTR_SIZE. */
  67. /**
  68. * @description
  69. * The dynamic range of this data type determines the maximum length
  70. * of the ring buffer managed by the native QF event queue.
  71. */
  72. typedef uint_fast8_t QEQueueCtr;
  73. #elif (QF_EQUEUE_CTR_SIZE == 2)
  74. typedef uint_fast16_t QEQueueCtr;
  75. #elif (QF_EQUEUE_CTR_SIZE == 4)
  76. typedef uint_fast32_t QEQueueCtr;
  77. #else
  78. #error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
  79. #endif
  80. /****************************************************************************/
  81. /*! Native QF Event Queue */
  82. /**
  83. * @description
  84. * This class describes the native QF event queue, which can be used as
  85. * the event queue for active objects, or as a simple "raw" event queue for
  86. * thread-safe event passing among non-framework entities, such as ISRs,
  87. * device drivers, or other third-party components.@n
  88. * @n
  89. * The native QF event queue is configured by defining the macro
  90. * #QF_EQUEUE_TYPE as ::QEQueue in the specific QF port header file.@n
  91. * @n
  92. * The ::QEQueue structure contains only data members for managing an event
  93. * queue, but does not contain the storage for the queue buffer, which must
  94. * be provided externally during the queue initialization.@n
  95. * @n
  96. * The event queue can store only event pointers, not the whole events. The
  97. * internal implementation uses the standard ring-buffer plus one external
  98. * location that optimizes the queue operation for the most frequent case
  99. * of empty queue.@n
  100. * @n
  101. * The ::QEQueue structure is used with two sets of functions. One set is for
  102. * the active object event queue, which might need to block the active object
  103. * task when the event queue is empty and might need to unblock it when
  104. * events are posted to the queue. The interface for the native active object
  105. * event queue consists of the following functions: QActive_post(),
  106. * QActive_postLIFO(), and QActive_get_(). Additionally the function
  107. * QEQueue_init() is used to initialize the queue.@n
  108. * @n
  109. * The other set of functions, uses ::QEQueue as a simple "raw" event
  110. * queue to pass events between entities other than active objects, such as
  111. * ISRs. The "raw" event queue is not capable of blocking on the get()
  112. * operation, but is still thread-safe because it uses QF critical section
  113. * to protect its integrity. The interface for the "raw" thread-safe queue
  114. * consists of the following functions: QEQueue_post(),
  115. * QEQueue_postLIFO(), and QEQueue_get(). Additionally the function
  116. * QEQueue_init() is used to initialize the queue.
  117. *
  118. * @note Most event queue operations (both the active object queues and
  119. * the "raw" queues) internally use the QF critical section. You should be
  120. * careful not to invoke those operations from other critical sections when
  121. * nesting of critical sections is not supported.
  122. *
  123. * @sa ::QEQueue for the description of the data members
  124. */
  125. typedef struct QEQueue {
  126. /*! pointer to event at the front of the queue. */
  127. /**
  128. * @description
  129. * All incoming and outgoing events pass through the frontEvt location.
  130. * When the queue is empty (which is most of the time), the extra
  131. * frontEvt location allows to bypass the ring buffer altogether,
  132. * greatly optimizing the performance of the queue. Only bursts of events
  133. * engage the ring buffer.
  134. *
  135. * @note The additional role of this attribute is to indicate the empty
  136. * status of the queue. The queue is empty when frontEvt is NULL.
  137. */
  138. QEvt const * volatile frontEvt;
  139. /*! pointer to the start of the ring buffer. */
  140. QEvt const **ring;
  141. /*! offset of the end of the ring buffer from the start of the buffer. */
  142. QEQueueCtr end;
  143. /*! offset to where next event will be inserted into the buffer. */
  144. QEQueueCtr volatile head;
  145. /*! offset of where next event will be extracted from the buffer. */
  146. QEQueueCtr volatile tail;
  147. /*! number of free events in the ring buffer. */
  148. QEQueueCtr volatile nFree;
  149. /*! minimum number of free events ever in the ring buffer. */
  150. /**
  151. * @description
  152. * this attribute remembers the low-watermark of the ring buffer,
  153. * which provides a valuable information for sizing event queues.
  154. * @sa QF_getQueueMargin().
  155. */
  156. QEQueueCtr nMin;
  157. } QEQueue;
  158. /* public class operations */
  159. /*! Initialize the native QF event queue */
  160. void QEQueue_init(QEQueue * const me,
  161. QEvt const *qSto[], uint_fast16_t const qLen);
  162. /*! Post an event to the "raw" thread-safe event queue (FIFO). */
  163. bool QEQueue_post(QEQueue * const me, QEvt const * const e,
  164. uint_fast16_t const margin);
  165. /*! Post an event to the "raw" thread-safe event queue (LIFO). */
  166. void QEQueue_postLIFO(QEQueue * const me, QEvt const * const e);
  167. /*! Obtain an event from the "raw" thread-safe queue. */
  168. QEvt const *QEQueue_get(QEQueue * const me);
  169. /*! "raw" thread-safe QF event queue operation for obtaining the number
  170. * of free entries still available in the queue. */
  171. /**
  172. * @description
  173. * This operation needs to be used with caution because the number of free
  174. * entries can change unexpectedly. The main intent for using this operation
  175. * is in conjunction with event deferral. In this case the queue is accessed
  176. * only from a single thread (by a single AO), so the number of free
  177. * entries cannot change unexpectedly.
  178. *
  179. * @param[in] me_ pointer (see @ref oop)
  180. *
  181. * @returns the current number of free slots in the queue.
  182. */
  183. #define QEQueue_getNFree(me_) ((me_)->nFree)
  184. /*! "raw" thread-safe QF event queue operation for obtaining the minimum
  185. * number of free entries ever in the queue (a.k.a. "low-watermark"). */
  186. /**
  187. * @description
  188. * This operation needs to be used with caution because the "low-watermark"
  189. * can change unexpectedly. The main intent for using this operation is to
  190. * get an idea of queue usage to size the queue adequately.
  191. *
  192. * @param[in] me_ pointer (see @ref oop)
  193. *
  194. * @returns the minimum number of free entries ever in the queue since init.
  195. */
  196. #define QEQueue_getNMin(me_) ((me_)->nMin)
  197. /*! "raw" thread-safe QF event queue operation to find out if the queue
  198. * is empty. */
  199. /**
  200. * @description
  201. * This operation needs to be used with caution because the queue status
  202. * can change unexpectedly. The main intent for using this operation is in
  203. * conjunction with event deferral. In this case the queue is accessed only
  204. * from a single thread (by a single AO), so no other entity can post
  205. * events to the queue.
  206. *
  207. * @param[in] me_ pointer (see @ref oop)
  208. *
  209. * @returns 'true' if the queue is current empty and 'false' otherwise.
  210. */
  211. #define QEQueue_isEmpty(me_) ((me_)->frontEvt == (QEvt const *)0)
  212. #endif /* qequeue_h */