source: rtems/cpukit/score/include/rtems/score/coremsgimpl.h @ 7580995

5
Last change on this file since 7580995 was 7580995, checked in by Sebastian Huber <sebastian.huber@…>, on 04/26/16 at 19:18:52

score: _CORE_message_queue_Close()

Move lock acquire to caller of _CORE_message_queue_Close() to allow
state checks during object close operations under lock protection.
Ensures deletion safety on uni-processor configuration.

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