summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/coremsg.c
blob: 72454b5d44b7dc96522cf7f967113494611db1fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 *  CORE Message Queue Handler
 *
 *  DESCRIPTION:
 *
 *  This package is the implementation of the CORE Message Queue Handler.
 *  This core object provides task synchronization and communication functions
 *  via messages passed to queue objects.
 *
 *  COPYRIGHT (c) 1989-2009.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/system.h>
#include <rtems/score/chain.h>
#include <rtems/score/isr.h>
#include <rtems/score/object.h>
#include <rtems/score/coremsg.h>
#include <rtems/score/states.h>
#include <rtems/score/thread.h>
#include <rtems/score/wkspace.h>

/*
 *  size_t_mult32_with_overflow
 *
 *  This method multiplies two size_t 32-bit numbers and checks
 *  for overflow.  It returns false if an overflow occurred and
 *  the result is bad.
 */
static inline bool size_t_mult32_with_overflow(
  size_t  a,
  size_t  b,
  size_t *c
)
{
  long long x = (long long)a*b;

  if ( x > SIZE_MAX )
    return false;
  *c = (size_t) x;
  return true;
}

/*
 *  _CORE_message_queue_Initialize
 *
 *  This routine initializes a newly created message queue based on the
 *  specified data.
 *
 *  Input parameters:
 *    the_message_queue            - the message queue to initialize
 *    the_class                    - the API specific object class
 *    the_message_queue_attributes - the message queue's attributes
 *    maximum_pending_messages     - maximum message and reserved buffer count
 *    maximum_message_size         - maximum size of each message
 *
 *  Output parameters:
 *    true   - if the message queue is initialized
 *    false  - if the message queue is NOT initialized
 */

bool _CORE_message_queue_Initialize(
  CORE_message_queue_Control    *the_message_queue,
  CORE_message_queue_Attributes *the_message_queue_attributes,
  uint32_t                       maximum_pending_messages,
  size_t                         maximum_message_size
)
{
  size_t message_buffering_required = 0;
  size_t allocated_message_size;

  the_message_queue->maximum_pending_messages   = maximum_pending_messages;
  the_message_queue->number_of_pending_messages = 0;
  the_message_queue->maximum_message_size       = maximum_message_size;
  _CORE_message_queue_Set_notify( the_message_queue, NULL, NULL );

  /*
   *  Round size up to multiple of a pointer for chain init and
   *  check for overflow on adding overhead to each message.
   */
  allocated_message_size = maximum_message_size;
  if (allocated_message_size & (sizeof(uint32_t) - 1)) {
    allocated_message_size += sizeof(uint32_t);
    allocated_message_size &= ~(sizeof(uint32_t) - 1);
  }

  if (allocated_message_size < maximum_message_size)
    return false;

  /*
   *  Calculate how much total memory is required for message buffering and
   *  check for overflow on the multiplication.
   */
  if ( !size_t_mult32_with_overflow(
        (size_t) maximum_pending_messages,
        allocated_message_size + sizeof(CORE_message_queue_Buffer_control),
        &message_buffering_required ) ) 
    return false;

  /*
   *  Attempt to allocate the message memory
   */
  the_message_queue->message_buffers = (CORE_message_queue_Buffer *)
     _Workspace_Allocate( message_buffering_required );

  if (the_message_queue->message_buffers == 0)
    return false;

  /*
   *  Initialize the pool of inactive messages, pending messages,
   *  and set of waiting threads.
   */
  _Chain_Initialize (
    &the_message_queue->Inactive_messages,
    the_message_queue->message_buffers,
    (size_t) maximum_pending_messages,
    allocated_message_size + sizeof( CORE_message_queue_Buffer_control )
  );

  _Chain_Initialize_empty( &the_message_queue->Pending_messages );

  _Thread_queue_Initialize(
    &the_message_queue->Wait_queue,
    _CORE_message_queue_Is_priority( the_message_queue_attributes ) ?
       THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO,
    STATES_WAITING_FOR_MESSAGE,
    CORE_MESSAGE_QUEUE_STATUS_TIMEOUT
  );

  return true;
}