source: rtems/cpukit/include/rtems/score/coremsgimpl.h @ 4a4f41e

Last change on this file since 4a4f41e was 4a4f41e, checked in by Sebastian Huber <sebastian.huber@…>, on 09/23/20 at 14:47:58

rtems: Add rtems_message_queue_construct()

In contrast to message queues created by rtems_message_queue_create(), the
message queues constructed by this directive use a user-provided message buffer
storage area.

Add RTEMS_MESSAGE_QUEUE_BUFFER() to define a message buffer type for message
buffer storage areas.

Update #4007.

  • Property mode set to 100644
File size: 22.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreMessageQueue
5 *
6 * @brief Inlined Routines in the Core Message Handler
7 *
8 * This include file contains the static inline implementation of all
9 * inlined routines in the Core Message Handler.
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2009.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *  http://www.rtems.org/license/LICENSE.
19 */
20
21#ifndef _RTEMS_SCORE_COREMSGIMPL_H
22#define _RTEMS_SCORE_COREMSGIMPL_H
23
24#include <rtems/score/coremsg.h>
25#include <rtems/score/status.h>
26#include <rtems/score/chainimpl.h>
27#include <rtems/score/threaddispatch.h>
28#include <rtems/score/threadqimpl.h>
29
30#include <limits.h>
31#include <string.h>
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37/**
38 * @addtogroup RTEMSScoreMessageQueue
39 *
40 * @{
41 */
42
43/**
44 *  @brief Used when appending messages onto a message queue.
45 *
46 *  This is the priority constant used when appending messages onto
47 *  a message queue.
48 */
49#define  CORE_MESSAGE_QUEUE_SEND_REQUEST   INT_MAX
50
51/**
52 *  @brief Used when prepending messages onto a message queue.
53 *
54 *  This is the priority constant used when prepending messages onto
55 *  a message queue.
56 */
57#define  CORE_MESSAGE_QUEUE_URGENT_REQUEST INT_MIN
58
59/**
60 *  @brief The modes in which a message may be submitted to a message queue.
61 *
62 *  The following type details the modes in which a message
63 *  may be submitted to a message queue.  The message may be posted
64 *  in a send or urgent fashion.
65 *
66 *  @note  All other values are message priorities.  Numerically smaller
67 *         priorities indicate higher priority messages.
68 */
69typedef int CORE_message_queue_Submit_types;
70
71/**
72 * @brief This handler shall allocate the message buffer storage area for a
73 *   message queue.
74 *
75 * The handler shall set the CORE_message_queue_Control::free_message_buffers
76 * member.
77 *
78 * @param[out] the_message_queue is the message queue control.
79 *
80 * @param size is the message buffer storage area size to allocate.
81 *
82 * @param arg is the handler argument.
83 *
84 * @retval NULL The allocation failed.
85 *
86 * @return Otherwise the pointer to the allocated message buffer storage area
87 *   begin shall be returned.
88 */
89typedef void *( *CORE_message_queue_Allocate_buffers )(
90  CORE_message_queue_Control *the_message_queue,
91  size_t                      size,
92  const void                 *arg
93);
94
95/**
96 * @brief This handler allocates the message buffer storage area for a message
97 *   queue from the RTEMS Workspace.
98 *
99 * The handler sets the CORE_message_queue_Control::free_message_buffers
100 * to _Workspace_Free().
101 *
102 * @param[out] the_message_queue is the message queue control.
103 *
104 * @param size is the message buffer storage area size to allocate.
105 *
106 * @param arg is the unused handler argument.
107 *
108 * @retval NULL The allocation failed.
109 *
110 * @return Otherwise the pointer to the allocated message buffer storage area
111 *   begin is returned.
112 */
113void *_CORE_message_queue_Workspace_allocate(
114  CORE_message_queue_Control *the_message_queue,
115  size_t                      size,
116  const void                 *arg
117);
118
119/**
120 * @brief Initializes a message queue.
121 *
122 * @param[out] the_message_queue is the message queue to initialize.
123 *
124 * @param discipline is the blocking discipline for the message queue.
125 *
126 * @param maximum_pending_messages is the maximum number of messages that will
127 *   be allowed to be pending at any given time.
128 *
129 * @param maximum_message_size is the size of the largest message that may be
130 *   sent to this message queue instance.
131 *
132 * @param allocate_buffers is the message buffer storage area allocation
133 *   handler.
134 *
135 * @param arg is the message buffer storage area allocation handler argument.
136 *
137 * @retval STATUS_SUCCESSFUL The message queue was initialized.
138 *
139 * @retval STATUS_MESSAGE_QUEUE_INVALID_SIZE Calculations with the maximum
140 *   pending messages or maximum message size produced an integer overflow.
141 *
142 * @retval STATUS_MESSAGE_QUEUE_NO_MEMORY The message buffer storage area
143 *   allocation failed.
144 */
145Status_Control _CORE_message_queue_Initialize(
146  CORE_message_queue_Control          *the_message_queue,
147  CORE_message_queue_Disciplines       discipline,
148  uint32_t                             maximum_pending_messages,
149  size_t                               maximum_message_size,
150  CORE_message_queue_Allocate_buffers  allocate_buffers,
151  const void                          *arg
152);
153
154/**
155 * @brief Closes a message queue.
156 *
157 * This package is the implementation of the CORE Message Queue Handler.
158 * This core object provides task synchronization and communication functions
159 * via messages passed to queue objects.
160 *
161 * This function closes a message by returning all allocated space and
162 * flushing @a the_message_queue's task wait queue.
163 *
164 * @param[in, out] the_message_queue The message queue to close.
165 * @param[in, out] queue_context The thread queue context used for
166 *   _CORE_message_queue_Acquire() or _CORE_message_queue_Acquire_critical().
167 */
168void _CORE_message_queue_Close(
169  CORE_message_queue_Control *the_message_queue,
170  Thread_queue_Context       *queue_context
171);
172
173/**
174 * @brief Flushes pending messages.
175 *
176 * This package is the implementation of the CORE Message Queue Handler.
177 * This core object provides task synchronization and communication functions
178 * via messages passed to queue objects.
179 *
180 * This function flushes @a the_message_queue's pending message queue.  The
181 * number of messages flushed from the queue is returned.
182 *
183 * @param[in, out] the_message_queue The message queue to flush.
184 * @param queue_context The thread queue context with interrupts disabled.
185 *
186 * @return This method returns the number of message pending messages flushed.
187 */
188uint32_t   _CORE_message_queue_Flush(
189  CORE_message_queue_Control *the_message_queue,
190  Thread_queue_Context       *queue_context
191);
192
193#if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
194/**
195 * @brief Flushes waiting threads.
196 *
197 * This function flushes the threads which are blocked on
198 * @a the_message_queue's pending message queue.  They are
199 * unblocked whether blocked sending or receiving. It returns
200 * the number of messages flushed from the queue.
201 *
202 * @param[in, out] the_message_queue The message queue to flush.
203 *
204 * @return This method returns the number of messages flushed from the queue.
205 */
206  void _CORE_message_queue_Flush_waiting_threads(
207    CORE_message_queue_Control *the_message_queue
208  );
209#endif
210
211/**
212 * @brief Broadcasts a message to the message queue.
213 *
214 * This package is the implementation of the CORE Message Queue Handler.
215 * This core object provides task synchronization and communication functions
216 * via messages passed to queue objects.
217 *
218 * This function sends a message for every thread waiting on the queue and
219 * returns the number of threads made ready by the message.
220 *
221 * @param[in, out] the_message_queue The message queue to operate upon.
222 * @param buffer The starting address of the message to broadcast.
223 * @param size The size of the message being broadcast.
224 * @param[out] count The variable that will contain the
225 *        number of tasks that are sent this message.
226 * @param queue_context The thread queue context used for
227 *   _CORE_message_queue_Acquire() or _CORE_message_queue_Acquire_critical().
228 *
229 * @retval STATUS_SUCCESSFUL The message was successfully broadcast.
230 * @retval STATUS_MESSAGE_INVALID_SIZE The message size was too big.
231 */
232Status_Control _CORE_message_queue_Broadcast(
233  CORE_message_queue_Control *the_message_queue,
234  const void                 *buffer,
235  size_t                      size,
236  uint32_t                   *count,
237  Thread_queue_Context       *queue_context
238);
239
240/**
241 * @brief Submits a message to the message queue.
242 *
243 * This routine implements the send and urgent message functions. It
244 * processes a message that is to be submitted to the designated
245 * message queue.  The message will either be processed as a
246 * send message which it will be inserted at the rear of the queue
247 * or it will be processed as an urgent message which will be inserted
248 * at the front of the queue.
249 *
250 * @param[in, out] the_message_queue The message queue to operate upon.
251 * @param executing The executing thread.
252 * @param buffer The starting address of the message to send.
253 * @param size The size of the message being send.
254 * @param submit_type Determines whether the message is prepended,
255 *        appended, or enqueued in priority order.
256 * @param wait Indicates whether the calling thread is willing to block
257 *        if the message queue is full.
258 * @param queue_context The thread queue context used for
259 *   _CORE_message_queue_Acquire() or _CORE_message_queue_Acquire_critical().
260 *
261 * @retval STATUS_SUCCESSFUL The message was successfully submitted to the message queue.
262 * @retval STATUS_MESSAGE_INVALID_SIZE The message size was too big.
263 * @retval STATUS_TOO_MANY No message buffers were available.
264 * @retval STATUS_MESSAGE_QUEUE_WAIT_IN_ISR The caller is in an ISR, do not block!
265 * @retval STATUS_TIMEOUT A timeout occured.
266 */
267Status_Control _CORE_message_queue_Submit(
268  CORE_message_queue_Control       *the_message_queue,
269  Thread_Control                   *executing,
270  const void                       *buffer,
271  size_t                            size,
272  CORE_message_queue_Submit_types   submit_type,
273  bool                              wait,
274  Thread_queue_Context             *queue_context
275);
276
277/**
278 * @brief Seizes a message from the message queue.
279 *
280 * This package is the implementation of the CORE Message Queue Handler.
281 * This core object provides task synchronization and communication functions
282 * via messages passed to queue objects.
283 *
284 * This kernel routine dequeues a message, copies the message buffer to
285 * a given destination buffer, and frees the message buffer to the
286 * inactive message pool.  The thread will be blocked if wait is true,
287 * otherwise an error will be given to the thread if no messages are available.
288 *
289 * @param[in, out] the_message_queue The message queue to seize a message from.
290 * @param executing The executing thread.
291 * @param[out] buffer The starting address of the message buffer to
292 *        to be filled in with a message.
293 * @param[out] size_p The size of the @a buffer,
294 *        indicates the maximum size message that the caller can receive.
295 * @param wait Indicates whether the calling thread is willing to block
296 *        if the message queue is empty.
297 * @param queue_context The thread queue context used for
298 *   _CORE_message_queue_Acquire() or _CORE_message_queue_Acquire_critical().
299 *
300 * @retval STATUS_SUCCESSFUL The message was successfully seized from the message queue.
301 * @retval STATUS_UNSATISFIED Wait was set to false and there is currently no pending message.
302 * @retval STATUS_TIMEOUT A timeout occured.
303 *
304 * @note Returns message priority via return area in TCB.
305 *
306 * - INTERRUPT LATENCY:
307 *   + available
308 *   + wait
309 */
310Status_Control _CORE_message_queue_Seize(
311  CORE_message_queue_Control *the_message_queue,
312  Thread_Control             *executing,
313  void                       *buffer,
314  size_t                     *size_p,
315  bool                        wait,
316  Thread_queue_Context       *queue_context
317);
318
319/**
320 * @brief Inserts a message into the message queue.
321 *
322 * Copies the specified content into the message storage space and then
323 * inserts the message into the message queue according to the submit type.
324 *
325 * @param[in, out] the_message_queue The message queue to insert a message in.
326 * @param[in, out] the_message The message to insert in the message queue.
327 * @param content_source The message content source.
328 * @param content_size The message content size in bytes.
329 * @param submit_type Determines whether the message is prepended,
330 *        appended, or enqueued in priority order.
331 */
332void _CORE_message_queue_Insert_message(
333  CORE_message_queue_Control        *the_message_queue,
334  CORE_message_queue_Buffer         *the_message,
335  const void                        *content_source,
336  size_t                             content_size,
337  CORE_message_queue_Submit_types    submit_type
338);
339
340/**
341 * @brief Sends a message to the message queue.
342 *
343 * @param[in, out] the_message_queue The message queue to send a message to.
344 * @param buffer The starting address of the message to send.
345 * @param sizeis The size of the message being send.
346 * @param wait Indicates whether the calling thread is willing to block
347 *        if the message queue is full.
348 * @param queue_context The thread queue context used for
349 *   _CORE_message_queue_Acquire() or _CORE_message_queue_Acquire_critical().
350 *
351 * @retval STATUS_SUCCESSFUL The message was successfully submitted to the message queue.
352 * @retval STATUS_MESSAGE_INVALID_SIZE The message size was too big.
353 * @retval STATUS_TOO_MANY No message buffers were available.
354 * @retval STATUS_MESSAGE_QUEUE_WAIT_IN_ISR The caller is in an ISR, do not block!
355 * @retval STATUS_TIMEOUT A timeout occured.
356 */
357RTEMS_INLINE_ROUTINE Status_Control _CORE_message_queue_Send(
358  CORE_message_queue_Control       *the_message_queue,
359  const void                       *buffer,
360  size_t                            size,
361  bool                              wait,
362  Thread_queue_Context             *queue_context
363)
364{
365  return _CORE_message_queue_Submit(
366    the_message_queue,
367    _Thread_Executing,
368    buffer,
369    size,
370    CORE_MESSAGE_QUEUE_SEND_REQUEST,
371    wait,
372    queue_context
373  );
374}
375
376/**
377 * @brief Sends an urgent message to the message queue.
378 *
379 * @param[in, out] the_message_queue The message queue to send an urgent message to.
380 * @param buffer The starting address of the message to send.
381 * @param sizeis The size of the message being send.
382 * @param wait Indicates whether the calling thread is willing to block
383 *        if the message queue is full.
384 * @param queue_context The thread queue context used for
385 *   _CORE_message_queue_Acquire() or _CORE_message_queue_Acquire_critical().
386 *
387 * @retval STATUS_SUCCESSFUL The message was successfully submitted to the message queue.
388 * @retval STATUS_MESSAGE_INVALID_SIZE The message size was too big.
389 * @retval STATUS_TOO_MANY No message buffers were available.
390 * @retval STATUS_MESSAGE_QUEUE_WAIT_IN_ISR The caller is in an ISR, do not block!
391 * @retval STATUS_TIMEOUT A timeout occured.
392 */
393RTEMS_INLINE_ROUTINE Status_Control _CORE_message_queue_Urgent(
394  CORE_message_queue_Control       *the_message_queue,
395  const void                       *buffer,
396  size_t                            size,
397  bool                              wait,
398  Thread_queue_Context             *queue_context
399)
400{
401  return _CORE_message_queue_Submit(
402    the_message_queue,
403    _Thread_Executing,
404    buffer,
405    size,
406    CORE_MESSAGE_QUEUE_URGENT_REQUEST,
407    wait,
408    queue_context
409  );
410}
411
412/**
413 * @brief Acquires the message queue.
414 *
415 * @param[in, out] the_message_queue Rhe message queue to acquire.
416 * @param queue_context The thread queue context.
417 */
418RTEMS_INLINE_ROUTINE void _CORE_message_queue_Acquire(
419  CORE_message_queue_Control *the_message_queue,
420  Thread_queue_Context       *queue_context
421)
422{
423  _Thread_queue_Acquire( &the_message_queue->Wait_queue, queue_context );
424}
425
426/**
427 * @brief Acquires the message queue critical.
428 *
429 * @param[in, out] the_message_queue The message queue to acquire critical.
430 * @param queue_context The thread queue context.
431 */
432RTEMS_INLINE_ROUTINE void _CORE_message_queue_Acquire_critical(
433  CORE_message_queue_Control *the_message_queue,
434  Thread_queue_Context       *queue_context
435)
436{
437  _Thread_queue_Acquire_critical( &the_message_queue->Wait_queue, queue_context );
438}
439
440/**
441 * @brief Releases the message queue.
442 *
443 * @param[in, out] the_message_queue The message queue to release.
444 * @param queue_context The thread queue context.
445 */
446RTEMS_INLINE_ROUTINE void _CORE_message_queue_Release(
447  CORE_message_queue_Control *the_message_queue,
448  Thread_queue_Context       *queue_context
449)
450{
451  _Thread_queue_Release( &the_message_queue->Wait_queue, queue_context );
452}
453
454/**
455 * @brief Copies the source message buffer to the destination message buffer.
456 *
457 * This routine copies the contents of the source message buffer
458 * to the destination message buffer.
459 *
460 * @param source The source message buffer to be copied.
461 * @param[out] destination The destination messag buffer to copy the source to.
462 * @param size The size of the source buffer.
463 */
464RTEMS_INLINE_ROUTINE void _CORE_message_queue_Copy_buffer (
465  const void *source,
466  void       *destination,
467  size_t      size
468)
469{
470  memcpy(destination, source, size);
471}
472
473/**
474 * @brief Allocates a message buffer from the inactive message buffer chain.
475 *
476 * This function allocates a message buffer from the inactive
477 * message buffer chain.
478 *
479 * @param the_message_queue The message queue to operate upon.
480 *
481 * @retval pointer The allocated message buffer.
482 * @retval NULL The inactive message buffer chain is empty.
483 */
484RTEMS_INLINE_ROUTINE CORE_message_queue_Buffer *
485_CORE_message_queue_Allocate_message_buffer (
486    CORE_message_queue_Control *the_message_queue
487)
488{
489   return (CORE_message_queue_Buffer *)
490     _Chain_Get_unprotected( &the_message_queue->Inactive_messages );
491}
492
493/**
494 * @brief Frees a message buffer to inactive message buffer chain.
495 *
496 * This routine frees a message buffer to the inactive
497 * message buffer chain.
498 *
499 * @param[in, out] the_message_queue The message queue to free the message buffer to.
500 * @param[out] the_message The message to be freed.
501 */
502RTEMS_INLINE_ROUTINE void _CORE_message_queue_Free_message_buffer (
503  CORE_message_queue_Control *the_message_queue,
504  CORE_message_queue_Buffer  *the_message
505)
506{
507  _Chain_Append_unprotected( &the_message_queue->Inactive_messages, &the_message->Node );
508}
509
510/**
511 * @brief Gets message priority.
512 *
513 * This function returns the priority of @a the_message.
514 *
515 * @param the_message The message to obtain the priority from.
516 *
517 * @retval priority The priority of this message.
518 * @retval 0 Message priority is disabled.
519 *
520 * @note It encapsulates the optional behavior that message priority is
521 *       disabled if no API requires it.
522 */
523RTEMS_INLINE_ROUTINE int _CORE_message_queue_Get_message_priority (
524  const CORE_message_queue_Buffer *the_message
525)
526{
527  #if defined(RTEMS_SCORE_COREMSG_ENABLE_MESSAGE_PRIORITY)
528    return the_message->priority;
529  #else
530    return 0;
531  #endif
532}
533
534/**
535 * @brief Gets first message of message queue and removes it.
536 *
537 * This function removes the first message from the_message_queue
538 * and returns a pointer to it.
539 *
540 * @param[in, out] the_message_queue The message queue to get the first message from.
541 *
542 * @retval pointer The first message if the message queue is not empty.
543 * @retval NULL The message queue is empty.
544 */
545RTEMS_INLINE_ROUTINE
546  CORE_message_queue_Buffer *_CORE_message_queue_Get_pending_message (
547  CORE_message_queue_Control *the_message_queue
548)
549{
550  return (CORE_message_queue_Buffer *)
551    _Chain_Get_unprotected( &the_message_queue->Pending_messages );
552}
553
554#if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION)
555  /**
556   * @brief Checks if notification is enabled.
557   *
558   * This function returns true if notification is enabled on this message
559   * queue and false otherwise.
560   *
561   * @param the_message_queue The message queue to check if the notification is enabled.
562   *
563   * @retval true Notification is enabled on this message queue.
564   * @retval false Notification is not enabled on this message queue.
565   */
566  RTEMS_INLINE_ROUTINE bool _CORE_message_queue_Is_notify_enabled (
567    CORE_message_queue_Control *the_message_queue
568  )
569  {
570    return (the_message_queue->notify_handler != NULL);
571  }
572#endif
573
574/**
575 * @brief Initializes notification information.
576 *
577 * This routine initializes the notification information for
578 * @a the_message_queue.
579 *
580 * @param[out] the_message_queue The message queue to initialize the notification information.
581 * @param[out] the_handler The notification information for the message queue.
582 */
583#if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION)
584  RTEMS_INLINE_ROUTINE void _CORE_message_queue_Set_notify (
585    CORE_message_queue_Control        *the_message_queue,
586    CORE_message_queue_Notify_Handler  the_handler
587  )
588  {
589    the_message_queue->notify_handler = the_handler;
590  }
591#else
592  /* turn it into nothing if not enabled */
593  #define _CORE_message_queue_Set_notify( the_message_queue, the_handler ) \
594    do { } while ( 0 )
595#endif
596
597/**
598 * @brief Gets the first locked thread waiting to receive and dequeues it.
599 *
600 * This method dequeues the first locked thread waiting to receive a message,
601 *      dequeues it and returns the corresponding Thread_Control.
602 *
603 * @param[in, out] the_message_queue The message queue to operate upon.
604 * @param buffer The buffer that is copied to the threads mutable_object.
605 * @param size The size of the buffer.
606 * @param submit_type Indicates whether the thread should be willing to block in the future.
607 * @param queue_context The thread queue context.
608 *
609 * @retval thread The Thread_Control for the first locked thread, if there is a locked thread.
610 * @retval NULL There are pending messages or no thread waiting to receive.
611 */
612RTEMS_INLINE_ROUTINE Thread_Control *_CORE_message_queue_Dequeue_receiver(
613  CORE_message_queue_Control      *the_message_queue,
614  const void                      *buffer,
615  size_t                           size,
616  CORE_message_queue_Submit_types  submit_type,
617  Thread_queue_Context            *queue_context
618)
619{
620  Thread_Control *the_thread;
621
622  /*
623   *  If there are pending messages, then there can't be threads
624   *  waiting for us to send them a message.
625   *
626   *  NOTE: This check is critical because threads can block on
627   *        send and receive and this ensures that we are broadcasting
628   *        the message to threads waiting to receive -- not to send.
629   */
630  if ( the_message_queue->number_of_pending_messages != 0 ) {
631    return NULL;
632  }
633
634  /*
635   *  There must be no pending messages if there is a thread waiting to
636   *  receive a message.
637   */
638  the_thread = _Thread_queue_First_locked(
639    &the_message_queue->Wait_queue,
640    the_message_queue->operations
641  );
642  if ( the_thread == NULL ) {
643    return NULL;
644  }
645
646   *(size_t *) the_thread->Wait.return_argument = size;
647   the_thread->Wait.count = (uint32_t) submit_type;
648
649  _CORE_message_queue_Copy_buffer(
650    buffer,
651    the_thread->Wait.return_argument_second.mutable_object,
652    size
653  );
654
655  _Thread_queue_Extract_critical(
656    &the_message_queue->Wait_queue.Queue,
657    the_message_queue->operations,
658    the_thread,
659    queue_context
660  );
661
662  return the_thread;
663}
664
665/** @} */
666
667#ifdef __cplusplus
668}
669#endif
670
671#endif
672/* end of include file */
Note: See TracBrowser for help on using the repository browser.