This is Unofficial EPICS BASE Doxygen Site
osdMessageQueue.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE Versions 3.13.7
7 * and higher are distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 /*
11  * Author W. Eric Norum
12  * norume@aps.anl.gov
13  * 630 252 4793
14  */
15 
16 /*
17  * We want to access information which is
18  * normally hidden from application programs.
19  */
20 #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
21 
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <rtems.h>
27 #include <rtems/error.h>
28 #include "epicsMessageQueue.h"
29 #include "errlog.h"
30 
31 LIBCOM_API epicsMessageQueueId epicsStdCall
32 epicsMessageQueueCreate(unsigned int capacity, unsigned int maximumMessageSize)
33 {
34  rtems_status_code sc;
35  epicsMessageQueueId id = calloc(1, sizeof(*id));
36  rtems_interrupt_level level;
37  static char c1 = 'a';
38  static char c2 = 'a';
39  static char c3 = 'a';
40 
41  if(!id)
42  return NULL;
43 
44  sc = rtems_message_queue_create (rtems_build_name ('Q', c3, c2, c1),
45  capacity,
46  maximumMessageSize,
47  RTEMS_FIFO|RTEMS_LOCAL,
48  &id->id);
49  if (sc != RTEMS_SUCCESSFUL) {
50  free(id);
51  errlogPrintf ("Can't create message queue: %s\n", rtems_status_text (sc));
52  return NULL;
53  }
54  id->maxSize = maximumMessageSize;
55  id->localBuf = NULL;
56  rtems_interrupt_disable (level);
57  if (c1 == 'z') {
58  if (c2 == 'z') {
59  if (c3 == 'z') {
60  c3 = 'a';
61  }
62  else {
63  c3++;
64  }
65  c2 = 'a';
66  }
67  else {
68  c2++;
69  }
70  c1 = 'a';
71  }
72  else {
73  c1++;
74  }
75  rtems_interrupt_enable (level);
76  return id;
77 }
78 
79 static rtems_status_code rtems_message_queue_send_timeout(
80  rtems_id id,
81  void *buffer,
82  uint32_t size,
83  rtems_interval timeout)
84 {
85  Message_queue_Control *the_message_queue;
86  Objects_Locations location;
87  CORE_message_queue_Status msg_status;
88 
89  the_message_queue = _Message_queue_Get( id, &location );
90  switch ( location )
91  {
92  case OBJECTS_ERROR:
93  return RTEMS_INVALID_ID;
94 
95  case OBJECTS_LOCAL:
96  msg_status = _CORE_message_queue_Send(
97  &the_message_queue->message_queue,
98  buffer,
99  size,
100  id,
101  NULL,
102  1,
103  timeout
104  );
105 
106  _Thread_Enable_dispatch();
107 
108  /*
109  * If we had to block, then this is where the task returns
110  * after it wakes up. The returned status is correct for
111  * non-blocking operations but if we blocked, then we need
112  * to look at the status in our TCB.
113  */
114 
115  if ( msg_status == CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT )
116  msg_status = _Thread_Executing->Wait.return_code;
117  return _Message_queue_Translate_core_message_queue_return_code( msg_status );
118  }
119  return RTEMS_INTERNAL_ERROR; /* unreached - only to remove warnings */
120 }
121 
122 LIBCOM_API int epicsStdCall epicsMessageQueueSend(
124  void *message,
125  unsigned int messageSize)
126 {
127  if (rtems_message_queue_send_timeout(id->id, message, messageSize, RTEMS_NO_TIMEOUT) == RTEMS_SUCCESSFUL)
128  return 0;
129  else
130  return -1;
131 }
132 
133 LIBCOM_API int epicsStdCall epicsMessageQueueSendWithTimeout(
135  void *message,
136  unsigned int messageSize,
137  double timeout)
138 {
139  rtems_interval delay;
140  extern double rtemsTicksPerSecond_double;
141 
142  /*
143  * Convert time to ticks
144  */
145  if (timeout <= 0.0)
146  return epicsMessageQueueTrySend(id, message, messageSize);
147  delay = (int)(timeout * rtemsTicksPerSecond_double);
148  if (delay == 0)
149  delay++;
150  if (rtems_message_queue_send_timeout(id->id, message, messageSize, delay) == RTEMS_SUCCESSFUL)
151  return 0;
152  else
153  return -1;
154 }
155 
156 static int receiveMessage(
158  void *buffer,
159  uint32_t size,
160  uint32_t wait,
161  rtems_interval delay)
162 {
163  size_t rsize;
164  rtems_status_code sc;
165 
166  if (size < id->maxSize) {
167  if (id->localBuf == NULL) {
168  id->localBuf = malloc(id->maxSize);
169  if (id->localBuf == NULL)
170  return -1;
171  }
172  rsize = receiveMessage(id, id->localBuf, id->maxSize, wait, delay);
173  if (rsize > size)
174  return -1;
175  memcpy(buffer, id->localBuf, rsize);
176  }
177  else {
178  sc = rtems_message_queue_receive(id->id, buffer, &rsize, wait, delay);
179  if (sc != RTEMS_SUCCESSFUL)
180  return -1;
181  }
182  return rsize;
183 }
184 
185 LIBCOM_API int epicsStdCall epicsMessageQueueTryReceive(
187  void *message,
188  unsigned int size)
189 {
190  return receiveMessage(id, message, size, RTEMS_NO_WAIT, 0);
191 }
192 
193 LIBCOM_API int epicsStdCall epicsMessageQueueReceive(
195  void *message,
196  unsigned int size)
197 {
198  return receiveMessage(id, message, size, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
199 }
200 
201 LIBCOM_API int epicsStdCall epicsMessageQueueReceiveWithTimeout(
203  void *message,
204  unsigned int size,
205  double timeout)
206 {
207  rtems_interval delay;
208  uint32_t wait;
209  extern double rtemsTicksPerSecond_double;
210 
211  /*
212  * Convert time to ticks
213  */
214  if (timeout <= 0.0) {
215  wait = RTEMS_NO_WAIT;
216  delay = 0;
217  }
218  else {
219  wait = RTEMS_WAIT;
220  delay = (int)(timeout * rtemsTicksPerSecond_double);
221  if (delay == 0)
222  delay++;
223  }
224  return receiveMessage(id, message, size, wait, delay);
225 }
226 
227 LIBCOM_API int epicsStdCall epicsMessageQueuePending(
229 {
230  uint32_t count;
231  rtems_status_code sc;
232 
233  sc = rtems_message_queue_get_number_pending(id->id, &count);
234  if (sc != RTEMS_SUCCESSFUL) {
235  errlogPrintf("Message queue %x get number pending failed: %s\n",
236  (unsigned int)id,
237  rtems_status_text(sc));
238  return -1;
239  }
240  return count;
241 }
242 
243 LIBCOM_API void epicsStdCall epicsMessageQueueShow(
245  int level)
246 {
247  int pending = epicsMessageQueuePending(id);
248  if (pending >= 0)
249  printf ("Message queue %lx -- Pending: %d\n", (unsigned long)id, pending);
250 }
double timeout
Definition: pvutils.cpp:25
LIBCOM_API int epicsStdCall epicsMessageQueueTryReceive(epicsMessageQueueId id, void *message, unsigned int size)
Try to receive a message.
LIBCOM_API void epicsStdCall epicsMessageQueueShow(epicsMessageQueueId id, int level)
Displays some information about the message queue.
LIBCOM_API int epicsStdCall epicsMessageQueueReceiveWithTimeout(epicsMessageQueueId id, void *message, unsigned int size, double timeout)
Wait for a message to be queued.
#define epicsMessageQueueTrySend(q, m, l)
#define printf
Definition: epicsStdio.h:41
LIBCOM_API int epicsStdCall epicsMessageQueueReceive(epicsMessageQueueId id, void *message, unsigned int size)
Fetch the next message on the queue.
#define NULL
Definition: catime.c:38
LIBCOM_API int epicsStdCall epicsMessageQueueSend(epicsMessageQueueId id, void *message, unsigned int messageSize)
Send a message.
double rtemsTicksPerSecond_double
Definition: osdTime.cpp:143
LIBCOM_API int epicsStdCall epicsMessageQueuePending(epicsMessageQueueId id)
How many messages are queued.
LIBCOM_API epicsMessageQueueId epicsStdCall epicsMessageQueueCreate(unsigned int capacity, unsigned int maximumMessageSize)
Create a message queue.
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
A C++ and a C facility for communication between threads.
LIBCOM_API int epicsStdCall epicsMessageQueueSendWithTimeout(epicsMessageQueueId id, void *message, unsigned int messageSize, double timeout)
Send a message or timeout.