TNeoKernel  v1.04
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tn_dqueue.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeoKernel: 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  * TNeoKernel: copyright © 2014 Dmitry Frank.
8  *
9  * TNeoKernel 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: TNeoKernel.
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  * TNeoKernel 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  /// list of tasks waiting to send data
109  ///
110  /// list of tasks waiting to receive data
112 
113  ///
114  /// array of `void *` to store data queue items. Can be `TN_NULL`.
115  void **data_fifo;
116  ///
117  /// capacity (total items count). Can be 0.
119  ///
120  /// count of non-free items in `data_fifo`
122  ///
123  /// index of the item which will be written next time
124  int head_idx;
125  ///
126  /// index of the item which will be read next time
127  int tail_idx;
128  ///
129  /// id for object validity verification
131  ///
132  /// connected event group
134 };
135 
136 /**
137  * DQueue-specific fields related to waiting task,
138  * to be included in struct TN_Task.
139  */
141  /// if task tries to send the data to the data queue,
142  /// and there's no space in the queue, value to put to queue is stored
143  /// in this field
144  void *data_elem;
145 };
146 
147 
148 /*******************************************************************************
149  * GLOBAL VARIABLES
150  ******************************************************************************/
151 
152 /*******************************************************************************
153  * DEFINITIONS
154  ******************************************************************************/
155 
156 /*******************************************************************************
157  * PUBLIC FUNCTION PROTOTYPES
158  ******************************************************************************/
159 
160 /**
161  * Construct data queue. `id_dque` member should not contain `#TN_ID_DATAQUEUE`,
162  * otherwise, `#TN_RC_WPARAM` is returned.
163  *
164  * $(TN_CALL_FROM_TASK)
165  * $(TN_CALL_FROM_ISR)
166  * $(TN_LEGEND_LINK)
167  *
168  * @param dque pointer to already allocated struct TN_DQueue.
169  * @param data_fifo pointer to already allocated array of `void *` to store
170  * data queue items. Can be `#TN_NULL`.
171  * @param items_cnt capacity of queue
172  * (count of elements in the `data_fifo` array)
173  * Can be 0.
174  *
175  * @return
176  * * `#TN_RC_OK` if queue was successfully created;
177  * * If `#TN_CHECK_PARAM` is non-zero, additional return code
178  * is available: `#TN_RC_WPARAM`.
179  */
181  struct TN_DQueue *dque,
182  void **data_fifo,
183  int items_cnt
184  );
185 
186 
187 /**
188  * Destruct data queue.
189  *
190  * All tasks that wait for writing to or reading from the queue become
191  * runnable with `#TN_RC_DELETED` code returned.
192  *
193  * $(TN_CALL_FROM_TASK)
194  * $(TN_CAN_SWITCH_CONTEXT)
195  * $(TN_LEGEND_LINK)
196  *
197  * @param dque pointer to data queue to be deleted
198  *
199  * @return
200  * * `#TN_RC_OK` if queue was successfully deleted;
201  * * `#TN_RC_WCONTEXT` if called from wrong context;
202  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
203  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
204  */
205 enum TN_RCode tn_queue_delete(struct TN_DQueue *dque);
206 
207 
208 /**
209  * Send the data element specified by the `p_data` to the data queue
210  * specified by the `dque`.
211  *
212  * If there are tasks in the data queue's `wait_receive` list already, the
213  * function releases the task from the head of the `wait_receive` list, makes
214  * this task runnable and transfers the parameter `p_data` to task's
215  * function, that caused it to wait.
216  *
217  * If there are no tasks in the data queue's `wait_receive` list, parameter
218  * `p_data` is placed to the tail of data FIFO. If the data FIFO is full,
219  * behavior depends on the `timeout` value: refer to `#TN_Timeout`.
220  *
221  * $(TN_CALL_FROM_TASK)
222  * $(TN_CAN_SWITCH_CONTEXT)
223  * $(TN_CAN_SLEEP)
224  * $(TN_LEGEND_LINK)
225  *
226  * @param dque pointer to data queue to send data to
227  * @param p_data value to send
228  * @param timeout refer to `#TN_Timeout`
229  *
230  * @return
231  * * `#TN_RC_OK` if data was successfully sent;
232  * * `#TN_RC_WCONTEXT` if called from wrong context;
233  * * Other possible return codes depend on `timeout` value,
234  * refer to `#TN_Timeout`
235  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
236  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
237  *
238  * @see `#TN_Timeout`
239  */
241  struct TN_DQueue *dque,
242  void *p_data,
243  TN_Timeout timeout
244  );
245 
246 /**
247  * The same as `tn_queue_send()` with zero timeout
248  *
249  * $(TN_CALL_FROM_TASK)
250  * $(TN_CAN_SWITCH_CONTEXT)
251  * $(TN_LEGEND_LINK)
252  */
254  struct TN_DQueue *dque,
255  void *p_data
256  );
257 
258 /**
259  * The same as `tn_queue_send()` with zero timeout, but for using in the ISR.
260  *
261  * $(TN_CALL_FROM_ISR)
262  * $(TN_CAN_SWITCH_CONTEXT)
263  * $(TN_LEGEND_LINK)
264  */
266  struct TN_DQueue *dque,
267  void *p_data
268  );
269 
270 /**
271  * Receive the data element from the data queue specified by the `dque` and
272  * place it into the address specified by the `pp_data`. If the FIFO already
273  * has data, function removes an entry from the end of the data queue FIFO and
274  * returns it into the `pp_data` function parameter.
275  *
276  * If there are task(s) in the data queue's `wait_send` list, first one gets
277  * removed from the head of `wait_send` list, becomes runnable and puts the
278  * data entry, stored in this task, to the tail of data FIFO. If there are no
279  * entries in the data FIFO and there are no tasks in the wait_send list,
280  * behavior depends on the `timeout` value: refer to `#TN_Timeout`.
281  *
282  * $(TN_CALL_FROM_TASK)
283  * $(TN_CAN_SWITCH_CONTEXT)
284  * $(TN_CAN_SLEEP)
285  * $(TN_LEGEND_LINK)
286  *
287  * @param dque pointer to data queue to receive data from
288  * @param pp_data pointer to location to store the value
289  * @param timeout refer to `#TN_Timeout`
290  *
291  * @return
292  * * `#TN_RC_OK` if data was successfully received;
293  * * `#TN_RC_WCONTEXT` if called from wrong context;
294  * * Other possible return codes depend on `timeout` value,
295  * refer to `#TN_Timeout`
296  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
297  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
298  *
299  * @see `#TN_Timeout`
300  */
302  struct TN_DQueue *dque,
303  void **pp_data,
304  TN_Timeout timeout
305  );
306 
307 /**
308  * The same as `tn_queue_receive()` with zero timeout
309  *
310  * $(TN_CALL_FROM_TASK)
311  * $(TN_CAN_SWITCH_CONTEXT)
312  * $(TN_LEGEND_LINK)
313  */
315  struct TN_DQueue *dque,
316  void **pp_data
317  );
318 
319 /**
320  * The same as `tn_queue_receive()` with zero timeout, but for using in the ISR.
321  *
322  * $(TN_CALL_FROM_ISR)
323  * $(TN_CAN_SWITCH_CONTEXT)
324  * $(TN_LEGEND_LINK)
325  */
327  struct TN_DQueue *dque,
328  void **pp_data
329  );
330 
331 
332 /**
333  * Connect an event group to the queue.
334  * Refer to the section \ref eventgrp_connect for details.
335  *
336  * Only one event group can be connected to the queue at a time. If you
337  * connect event group while another event group is already connected,
338  * the old link is discarded.
339  *
340  * @param dque
341  * queue to which event group should be connected
342  * @param eventgrp
343  * event groupt to connect
344  * @param pattern
345  * flags pattern that should be managed by the queue automatically
346  *
347  * $(TN_CALL_FROM_TASK)
348  * $(TN_CALL_FROM_ISR)
349  * $(TN_LEGEND_LINK)
350  */
352  struct TN_DQueue *dque,
353  struct TN_EventGrp *eventgrp,
354  TN_UWord pattern
355  );
356 
357 
358 /**
359  * Disconnect a connected event group from the queue.
360  * Refer to the section \ref eventgrp_connect for details.
361  *
362  * If there is no event group connected, nothing is changed.
363  *
364  * @param dque queue from which event group should be disconnected
365  *
366  * $(TN_CALL_FROM_TASK)
367  * $(TN_CALL_FROM_ISR)
368  * $(TN_LEGEND_LINK)
369  */
371  struct TN_DQueue *dque
372  );
373 
374 
375 #ifdef __cplusplus
376 } /* extern "C" */
377 #endif
378 
379 #endif // _TN_DQUEUE_H
380 
381 /*******************************************************************************
382  * end of file
383  ******************************************************************************/
384 
385 
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:111
struct TN_ListItem wait_send_list
list of tasks waiting to send data
Definition: tn_dqueue.h:108
enum TN_ObjId id_dque
id for object validity verification
Definition: tn_dqueue.h:130
Circular doubly linked list, for internal kernel usage.
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:80
enum TN_RCode tn_queue_send(struct TN_DQueue *dque, void *p_data, TN_Timeout timeout)
Send the data element specified by the p_data to the data queue specified by the dque.
void ** data_fifo
array of void * to store data queue items. Can be TN_NULL.
Definition: tn_dqueue.h:115
DQueue-specific fields related to waiting task, to be included in struct TN_Task. ...
Definition: tn_dqueue.h:140
TN_ObjId
Magic number for object validity verification TODO: use TN_UWord here instead of unsigned int...
Definition: tn_common.h:65
unsigned long TN_Timeout
The value representing maximum number of system ticks to wait.
Definition: tn_common.h:183
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:124
int filled_items_cnt
count of non-free items in data_fifo
Definition: tn_dqueue.h:121
int items_cnt
capacity (total items count). Can be 0.
Definition: tn_dqueue.h:118
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:144
int tail_idx
index of the item which will be read next time
Definition: tn_dqueue.h:127
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.
enum TN_RCode tn_queue_receive(struct TN_DQueue *dque, void **pp_data, TN_Timeout timeout)
Receive the data element from the data queue specified by the dque and place it into the address spec...
struct TN_EGrpLink eventgrp_link
connected event group
Definition: tn_dqueue.h:133
Event group.
Definition: tn_eventgrp.h:159
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_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.