TNeo  v1.08
tn_dqueue.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeo: real-time kernel initially based on TNKernel
4  *
5  * TNKernel: copyright 2004, 2013 Yuri Tiomkin.
6  * PIC32-specific routines: copyright 2013, 2014 Anders Montonen.
7  * TNeo: copyright 2014 Dmitry Frank.
8  *
9  * TNeo was born as a thorough review and re-implementation of
10  * TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11  * as well as new features being added, and it is tested carefully with
12  * unit-tests.
13  *
14  * API is changed somewhat, so it's not 100% compatible with TNKernel,
15  * hence the new name: TNeo.
16  *
17  * Permission to use, copy, modify, and distribute this software in source
18  * and binary forms and its documentation for any purpose and without fee
19  * is hereby granted, provided that the above copyright notice appear
20  * in all copies and that both that copyright notice and this permission
21  * notice appear in supporting documentation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  ******************************************************************************/
36 
37 /**
38  * \file
39  *
40  * A data queue is a FIFO that stores pointer (of type `void *`) in each cell,
41  * called (in uITRON style) a data element. A data queue also has an associated
42  * wait queue each for sending (`wait_send` queue) and for receiving
43  * (`wait_receive` queue). A task that sends a data element tries to put the
44  * data element into the FIFO. If there is no space left in the FIFO, the task
45  * is switched to the waiting state and placed in the data queue's `wait_send`
46  * queue until space appears (another task gets a data element from the data
47  * queue).
48  *
49  * A task that receives a data element tries to get a data element
50  * from the FIFO. If the FIFO is empty (there is no data in the data queue),
51  * the task is switched to the waiting state and placed in the data queue's
52  * `wait_receive` queue until data element arrive (another task puts some data
53  * element into the data queue). To use a data queue just for the synchronous
54  * message passing, set size of the FIFO to 0. The data element to be sent and
55  * received can be interpreted as a pointer or an integer and may have value 0
56  * (`TN_NULL`).
57  *
58  * For the useful pattern on how to use queue together with \ref tn_fmem.h
59  * "fixed memory pool", refer to the example: `examples/queue`. Be sure
60  * to examine the readme there.
61  *
62  * TNeo offers a way to wait for a message from multiple queues in just a
63  * single call, refer to the section \ref eventgrp_connect for details. Related
64  * queue services:
65  *
66  * - `tn_queue_eventgrp_connect()`
67  * - `tn_queue_eventgrp_disconnect()`
68  *
69  * There is an example project available that demonstrates event group
70  * connection technique: `examples/queue_eventgrp_conn`. Be sure to examine the
71  * readme there.
72  *
73  */
74 
75 #ifndef _TN_DQUEUE_H
76 #define _TN_DQUEUE_H
77 
78 /*******************************************************************************
79  * INCLUDED FILES
80  ******************************************************************************/
81 
82 #include "tn_list.h"
83 #include "tn_common.h"
84 #include "tn_eventgrp.h"
85 
86 
87 
88 /*******************************************************************************
89  * EXTERN TYPES
90  ******************************************************************************/
91 
92 
93 
94 #ifdef __cplusplus
95 extern "C" { /*}*/
96 #endif
97 
98 /*******************************************************************************
99  * PUBLIC TYPES
100  ******************************************************************************/
101 
102 /**
103  * Structure representing data queue object
104  */
105 struct TN_DQueue {
106  ///
107  /// id for object validity verification.
108  /// This field is in the beginning of the structure to make it easier
109  /// to detect memory corruption.
111  ///
112  /// list of tasks waiting to send data
114  ///
115  /// list of tasks waiting to receive data
117 
118  ///
119  /// array of `void *` to store data queue items. Can be `TN_NULL`.
120  void **data_fifo;
121  ///
122  /// capacity (total items count). Can be 0.
124  ///
125  /// count of non-free items in `data_fifo`
127  ///
128  /// index of the item which will be written next time
129  int head_idx;
130  ///
131  /// index of the item which will be read next time
132  int tail_idx;
133  ///
134  /// connected event group
136 };
137 
138 /**
139  * DQueue-specific fields related to waiting task,
140  * to be included in struct TN_Task.
141  */
143  /// if task tries to send the data to the data queue,
144  /// and there's no space in the queue, value to put to queue is stored
145  /// in this field
146  void *data_elem;
147 };
148 
149 
150 /*******************************************************************************
151  * PROTECTED GLOBAL DATA
152  ******************************************************************************/
153 
154 /*******************************************************************************
155  * DEFINITIONS
156  ******************************************************************************/
157 
158 /*******************************************************************************
159  * PUBLIC FUNCTION PROTOTYPES
160  ******************************************************************************/
161 
162 /**
163  * Construct data queue. `id_dque` member should not contain `#TN_ID_DATAQUEUE`,
164  * otherwise, `#TN_RC_WPARAM` is returned.
165  *
166  * $(TN_CALL_FROM_TASK)
167  * $(TN_CALL_FROM_ISR)
168  * $(TN_LEGEND_LINK)
169  *
170  * @param dque pointer to already allocated struct TN_DQueue.
171  * @param data_fifo pointer to already allocated array of `void *` to store
172  * data queue items. Can be `#TN_NULL`.
173  * @param items_cnt capacity of queue
174  * (count of elements in the `data_fifo` array)
175  * Can be 0.
176  *
177  * @return
178  * * `#TN_RC_OK` if queue was successfully created;
179  * * If `#TN_CHECK_PARAM` is non-zero, additional return code
180  * is available: `#TN_RC_WPARAM`.
181  */
183  struct TN_DQueue *dque,
184  void **data_fifo,
185  int items_cnt
186  );
187 
188 
189 /**
190  * Destruct data queue.
191  *
192  * All tasks that wait for writing to or reading from the queue become
193  * runnable with `#TN_RC_DELETED` code returned.
194  *
195  * $(TN_CALL_FROM_TASK)
196  * $(TN_CAN_SWITCH_CONTEXT)
197  * $(TN_LEGEND_LINK)
198  *
199  * @param dque pointer to data queue to be deleted
200  *
201  * @return
202  * * `#TN_RC_OK` if queue was successfully deleted;
203  * * `#TN_RC_WCONTEXT` if called from wrong context;
204  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
205  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
206  */
207 enum TN_RCode tn_queue_delete(struct TN_DQueue *dque);
208 
209 
210 /**
211  * Send the data element specified by the `p_data` to the data queue
212  * specified by the `dque`.
213  *
214  * If there are tasks in the data queue's `wait_receive` list already, the
215  * function releases the task from the head of the `wait_receive` list, makes
216  * this task runnable and transfers the parameter `p_data` to task's
217  * function, that caused it to wait.
218  *
219  * If there are no tasks in the data queue's `wait_receive` list, parameter
220  * `p_data` is placed to the tail of data FIFO. If the data FIFO is full,
221  * behavior depends on the `timeout` value: refer to `#TN_TickCnt`.
222  *
223  * $(TN_CALL_FROM_TASK)
224  * $(TN_CAN_SWITCH_CONTEXT)
225  * $(TN_CAN_SLEEP)
226  * $(TN_LEGEND_LINK)
227  *
228  * @param dque pointer to data queue to send data to
229  * @param p_data value to send
230  * @param timeout refer to `#TN_TickCnt`
231  *
232  * @return
233  * * `#TN_RC_OK` if data was successfully sent;
234  * * `#TN_RC_WCONTEXT` if called from wrong context;
235  * * Other possible return codes depend on `timeout` value,
236  * refer to `#TN_TickCnt`
237  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
238  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
239  *
240  * @see `#TN_TickCnt`
241  */
243  struct TN_DQueue *dque,
244  void *p_data,
245  TN_TickCnt timeout
246  );
247 
248 /**
249  * The same as `tn_queue_send()` with zero timeout
250  *
251  * $(TN_CALL_FROM_TASK)
252  * $(TN_CAN_SWITCH_CONTEXT)
253  * $(TN_LEGEND_LINK)
254  */
256  struct TN_DQueue *dque,
257  void *p_data
258  );
259 
260 /**
261  * The same as `tn_queue_send()` with zero timeout, but for using in the ISR.
262  *
263  * $(TN_CALL_FROM_ISR)
264  * $(TN_CAN_SWITCH_CONTEXT)
265  * $(TN_LEGEND_LINK)
266  */
268  struct TN_DQueue *dque,
269  void *p_data
270  );
271 
272 /**
273  * Receive the data element from the data queue specified by the `dque` and
274  * place it into the address specified by the `pp_data`. If the FIFO already
275  * has data, function removes an entry from the end of the data queue FIFO and
276  * returns it into the `pp_data` function parameter.
277  *
278  * If there are task(s) in the data queue's `wait_send` list, first one gets
279  * removed from the head of `wait_send` list, becomes runnable and puts the
280  * data entry, stored in this task, to the tail of data FIFO. If there are no
281  * entries in the data FIFO and there are no tasks in the wait_send list,
282  * behavior depends on the `timeout` value: refer to `#TN_TickCnt`.
283  *
284  * $(TN_CALL_FROM_TASK)
285  * $(TN_CAN_SWITCH_CONTEXT)
286  * $(TN_CAN_SLEEP)
287  * $(TN_LEGEND_LINK)
288  *
289  * @param dque pointer to data queue to receive data from
290  * @param pp_data pointer to location to store the value
291  * @param timeout refer to `#TN_TickCnt`
292  *
293  * @return
294  * * `#TN_RC_OK` if data was successfully received;
295  * * `#TN_RC_WCONTEXT` if called from wrong context;
296  * * Other possible return codes depend on `timeout` value,
297  * refer to `#TN_TickCnt`
298  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
299  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
300  *
301  * @see `#TN_TickCnt`
302  */
304  struct TN_DQueue *dque,
305  void **pp_data,
306  TN_TickCnt timeout
307  );
308 
309 /**
310  * The same as `tn_queue_receive()` with zero timeout
311  *
312  * $(TN_CALL_FROM_TASK)
313  * $(TN_CAN_SWITCH_CONTEXT)
314  * $(TN_LEGEND_LINK)
315  */
317  struct TN_DQueue *dque,
318  void **pp_data
319  );
320 
321 /**
322  * The same as `tn_queue_receive()` with zero timeout, but for using in the ISR.
323  *
324  * $(TN_CALL_FROM_ISR)
325  * $(TN_CAN_SWITCH_CONTEXT)
326  * $(TN_LEGEND_LINK)
327  */
329  struct TN_DQueue *dque,
330  void **pp_data
331  );
332 
333 
334 /**
335  * Returns number of free items in the queue
336  *
337  * $(TN_CALL_FROM_TASK)
338  * $(TN_CALL_FROM_ISR)
339  * $(TN_LEGEND_LINK)
340  *
341  * @param dque
342  * Pointer to queue.
343  *
344  * @return
345  * Number of free items in the queue, or -1 if wrong params were given (the
346  * check is performed if only `#TN_CHECK_PARAM` is non-zero)
347  */
349  struct TN_DQueue *dque
350  );
351 
352 
353 /**
354  * Returns number of used (non-free) items in the queue
355  *
356  * $(TN_CALL_FROM_TASK)
357  * $(TN_CALL_FROM_ISR)
358  * $(TN_LEGEND_LINK)
359  *
360  * @param dque
361  * Pointer to queue.
362  *
363  * @return
364  * Number of used (non-free) items in the queue, or -1 if wrong params were
365  * given (the check is performed if only `#TN_CHECK_PARAM` is non-zero)
366  */
368  struct TN_DQueue *dque
369  );
370 
371 
372 /**
373  * Connect an event group to the queue.
374  * Refer to the section \ref eventgrp_connect for details.
375  *
376  * Only one event group can be connected to the queue at a time. If you
377  * connect event group while another event group is already connected,
378  * the old link is discarded.
379  *
380  * @param dque
381  * queue to which event group should be connected
382  * @param eventgrp
383  * event groupt to connect
384  * @param pattern
385  * flags pattern that should be managed by the queue automatically
386  *
387  * $(TN_CALL_FROM_TASK)
388  * $(TN_CALL_FROM_ISR)
389  * $(TN_LEGEND_LINK)
390  */
392  struct TN_DQueue *dque,
393  struct TN_EventGrp *eventgrp,
394  TN_UWord pattern
395  );
396 
397 
398 /**
399  * Disconnect a connected event group from the queue.
400  * Refer to the section \ref eventgrp_connect for details.
401  *
402  * If there is no event group connected, nothing is changed.
403  *
404  * @param dque queue from which event group should be disconnected
405  *
406  * $(TN_CALL_FROM_TASK)
407  * $(TN_CALL_FROM_ISR)
408  * $(TN_LEGEND_LINK)
409  */
411  struct TN_DQueue *dque
412  );
413 
414 
415 #ifdef __cplusplus
416 } /* extern "C" */
417 #endif
418 
419 #endif // _TN_DQUEUE_H
420 
421 /*******************************************************************************
422  * end of file
423  ******************************************************************************/
424 
425 
enum TN_RCode tn_queue_receive_polling(struct TN_DQueue *dque, void **pp_data)
The same as tn_queue_receive() with zero timeout.
struct TN_ListItem wait_receive_list
list of tasks waiting to receive data
Definition: tn_dqueue.h:116
struct TN_ListItem wait_send_list
list of tasks waiting to send data
Definition: tn_dqueue.h:113
enum TN_ObjId id_dque
id for object validity verification.
Definition: tn_dqueue.h:110
Circular doubly linked list, for internal kernel usage.
int tn_queue_used_items_cnt_get(struct TN_DQueue *dque)
Returns number of used (non-free) items in the queue.
enum TN_RCode tn_queue_ireceive_polling(struct TN_DQueue *dque, void **pp_data)
The same as tn_queue_receive() with zero timeout, but for using in the ISR.
Structure representing data queue object.
Definition: tn_dqueue.h:105
TN_RCode
Result code returned by kernel services.
Definition: tn_common.h:81
void ** data_fifo
array of void * to store data queue items. Can be TN_NULL.
Definition: tn_dqueue.h:120
DQueue-specific fields related to waiting task, to be included in struct TN_Task. ...
Definition: tn_dqueue.h:142
TN_ObjId
Magic number for object validity verification.
Definition: tn_common.h:65
unsigned long TN_TickCnt
Type for system tick count, it is used by the kernel to represent absolute tick count value as well a...
Definition: tn_common.h:188
enum TN_RCode tn_queue_eventgrp_connect(struct TN_DQueue *dque, struct TN_EventGrp *eventgrp, TN_UWord pattern)
Connect an event group to the queue.
Definitions used through the whole kernel.
int head_idx
index of the item which will be written next time
Definition: tn_dqueue.h:129
int filled_items_cnt
count of non-free items in data_fifo
Definition: tn_dqueue.h:126
int items_cnt
capacity (total items count). Can be 0.
Definition: tn_dqueue.h:123
Event group.
void * data_elem
if task tries to send the data to the data queue, and there's no space in the queue, value to put to queue is stored in this field
Definition: tn_dqueue.h:146
int tail_idx
index of the item which will be read next time
Definition: tn_dqueue.h:132
int tn_queue_free_items_cnt_get(struct TN_DQueue *dque)
Returns number of free items in the queue.
enum TN_RCode tn_queue_receive(struct TN_DQueue *dque, void **pp_data, TN_TickCnt timeout)
Receive the data element from the data queue specified by the dque and place it into the address spec...
enum TN_RCode tn_queue_eventgrp_disconnect(struct TN_DQueue *dque)
Disconnect a connected event group from the queue.
enum TN_RCode tn_queue_create(struct TN_DQueue *dque, void **data_fifo, int items_cnt)
Construct data queue.
struct TN_EGrpLink eventgrp_link
connected event group
Definition: tn_dqueue.h:135
Event group.
Definition: tn_eventgrp.h:212
enum TN_RCode tn_queue_send_polling(struct TN_DQueue *dque, void *p_data)
The same as tn_queue_send() with zero timeout.
enum TN_RCode tn_queue_send(struct TN_DQueue *dque, void *p_data, TN_TickCnt timeout)
Send the data element specified by the p_data to the data queue specified by the dque.
enum TN_RCode tn_queue_isend_polling(struct TN_DQueue *dque, void *p_data)
The same as tn_queue_send() with zero timeout, but for using in the ISR.
Circular doubly linked list item, for internal kernel usage.
Definition: tn_list.h:63
unsigned int TN_UWord
Unsigned integer type whose size is equal to the size of CPU register.
enum TN_RCode tn_queue_delete(struct TN_DQueue *dque)
Destruct data queue.