]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Demo / FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator / lib / FreeRTOS-Plus-POSIX / source / FreeRTOS_POSIX_mqueue.c
1 /*\r
2  * Amazon FreeRTOS POSIX V1.1.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /**\r
27  * @file FreeRTOS_POSIX_mqueue.c\r
28  * @brief Implementation of message queue functions in mqueue.h\r
29  */\r
30 \r
31 /* C standard library includes. */\r
32 #include <string.h>\r
33 \r
34 /* FreeRTOS+POSIX includes. */\r
35 #include "FreeRTOS_POSIX.h"\r
36 #include "FreeRTOS_POSIX/errno.h"\r
37 #include "FreeRTOS_POSIX/fcntl.h"\r
38 #include "FreeRTOS_POSIX/mqueue.h"\r
39 #include "FreeRTOS_POSIX/utils.h"\r
40 \r
41 /**\r
42  * @brief Element of the FreeRTOS queues that store mq data.\r
43  */\r
44 typedef struct QueueElement\r
45 {\r
46     char * pcData;    /**< Data in queue. Type char* to match msg_ptr. */\r
47     size_t xDataSize; /**< Size of data pointed by pcData. */\r
48 } QueueElement_t;\r
49 \r
50 /**\r
51  * @brief Data structure of an mq.\r
52  *\r
53  * FreeRTOS isn't guaranteed to have a file-like abstraction, so message\r
54  * queues in this implementation are stored as a linked list (in RAM).\r
55  */\r
56 typedef struct QueueListElement\r
57 {\r
58     Link_t xLink;              /**< Pointer to the next element in the list. */\r
59     QueueHandle_t xQueue;      /**< FreeRTOS queue handle. */\r
60     size_t xOpenDescriptors;   /**< Number of threads that have opened this queue. */\r
61     char * pcName;             /**< Null-terminated queue name. */\r
62     struct mq_attr xAttr;      /**< Queue attibutes. */\r
63     BaseType_t xPendingUnlink; /**< If pdTRUE, this queue will be unlinked once all descriptors close. */\r
64 } QueueListElement_t;\r
65 \r
66 /*-----------------------------------------------------------*/\r
67 \r
68 /**\r
69  * @brief Convert an absolute timespec into a tick timeout, taking into account\r
70  * queue flags.\r
71  *\r
72  * @param[in] lMessageQueueFlags Message queue flags to consider.\r
73  * @param[in] pxAbsoluteTimeout The absolute timespec to convert.\r
74  * @param[out] pxTimeoutTicks Output parameter of the timeout in ticks.\r
75  *\r
76  * @return 0 if successful; EINVAL if pxAbsoluteTimeout is invalid, or ETIMEDOUT\r
77  * if pxAbsoluteTimeout is in the past.\r
78  */\r
79 static int prvCalculateTickTimeout( long lMessageQueueFlags,\r
80                                     const struct timespec * const pxAbsoluteTimeout,\r
81                                     TickType_t * pxTimeoutTicks );\r
82 \r
83 /**\r
84  * @brief Add a new queue to the queue list.\r
85  *\r
86  * @param[out] ppxMessageQueue Pointer to new queue.\r
87  * @param[in] pxAttr mq_attr of the new queue.\r
88  * @param[in] pcName Name of new queue.\r
89  * @param[in] xNameLength Length of pcName.\r
90  *\r
91  * @return pdTRUE if the queue is found; pdFALSE otherwise.\r
92  */\r
93 static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue,\r
94                                             const struct mq_attr * const pxAttr,\r
95                                             const char * const pcName,\r
96                                             size_t xNameLength );\r
97 \r
98 /**\r
99  * @brief Free all the resources used by a message queue.\r
100  *\r
101  * @param[out] pxMessageQueue Pointer to queue to free.\r
102  *\r
103  * @return nothing\r
104  */\r
105 static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue );\r
106 \r
107 /**\r
108  * @brief Attempt to find the queue identified by pcName or xMqId in the queue list.\r
109  *\r
110  * Matches queues by pcName first; if pcName is NULL, matches by xMqId.\r
111  * @param[out] ppxQueueListElement Output parameter set when queue is found.\r
112  * @param[in] pcName A queue name to match.\r
113  * @param[in] xMessageQueueDescriptor A queue descriptor to match.\r
114  *\r
115  * @return pdTRUE if the queue is found; pdFALSE otherwise.\r
116  */\r
117 static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,\r
118                                       const char * const pcName,\r
119                                       mqd_t xMessageQueueDescriptor );\r
120 \r
121 /**\r
122  * @brief Initialize the queue list.\r
123  *\r
124  * Performs initialization of the queue list mutex and queue list head.\r
125  *\r
126  * @return nothing\r
127  */\r
128 static void prvInitializeQueueList( void );\r
129 \r
130 /**\r
131  * @brief Checks that pcName is a valid name for a message queue.\r
132  *\r
133  * Also outputs the length of pcName.\r
134  * @param[in] pcName The name to check.\r
135  * @param[out] pxNameLength Output parameter for name length.\r
136  *\r
137  * @return pdTRUE if the name is valid; pdFALSE otherwise.\r
138  */\r
139 static BaseType_t prvValidateQueueName( const char * const pcName,\r
140                                         size_t * pxNameLength );\r
141 \r
142 /**\r
143  * @brief Guards access to the list of message queues.\r
144  */\r
145 static StaticSemaphore_t xQueueListMutex = { { 0 }, .u = { 0 } };\r
146 \r
147 /**\r
148  * @brief Head of the linked list of queues.\r
149  */\r
150 static Link_t xQueueListHead = { 0 };\r
151 \r
152 /*-----------------------------------------------------------*/\r
153 \r
154 static int prvCalculateTickTimeout( long lMessageQueueFlags,\r
155                                     const struct timespec * const pxAbsoluteTimeout,\r
156                                     TickType_t * pxTimeoutTicks )\r
157 {\r
158     int iStatus = 0;\r
159 \r
160     /* Check for nonblocking queue. */\r
161     if( lMessageQueueFlags & O_NONBLOCK )\r
162     {\r
163         /* No additional checks are done for nonblocking queues. Timeout is 0. */\r
164         *pxTimeoutTicks = 0;\r
165     }\r
166     else\r
167     {\r
168         /* No absolute timeout given. Block forever. */\r
169         if( pxAbsoluteTimeout == NULL )\r
170         {\r
171             *pxTimeoutTicks = portMAX_DELAY;\r
172         }\r
173         else\r
174         {\r
175             struct timespec xCurrentTime = { 0 };\r
176 \r
177             /* Check that the given timespec is valid. */\r
178             if( UTILS_ValidateTimespec( pxAbsoluteTimeout ) == false )\r
179             {\r
180                 iStatus = EINVAL;\r
181             }\r
182 \r
183             /* Get current time */\r
184             if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) )\r
185             {\r
186                 iStatus = EINVAL;\r
187             }\r
188 \r
189             /* Convert absolute timespec to ticks. */\r
190             if( ( iStatus == 0 ) &&\r
191                 ( UTILS_AbsoluteTimespecToDeltaTicks( pxAbsoluteTimeout, &xCurrentTime, pxTimeoutTicks ) != 0 ) )\r
192             {\r
193                 iStatus = ETIMEDOUT;\r
194             }\r
195         }\r
196     }\r
197 \r
198     return iStatus;\r
199 }\r
200 \r
201 /*-----------------------------------------------------------*/\r
202 \r
203 static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue,\r
204                                             const struct mq_attr * const pxAttr,\r
205                                             const char * const pcName,\r
206                                             size_t xNameLength )\r
207 {\r
208     BaseType_t xStatus = pdTRUE;\r
209 \r
210     /* Allocate space for a new queue element. */\r
211     *ppxMessageQueue = pvPortMalloc( sizeof( QueueListElement_t ) );\r
212 \r
213     /* Check that memory allocation succeeded. */\r
214     if( *ppxMessageQueue == NULL )\r
215     {\r
216         xStatus = pdFALSE;\r
217     }\r
218 \r
219     /* Create the FreeRTOS queue. */\r
220     if( xStatus == pdTRUE )\r
221     {\r
222         ( *ppxMessageQueue )->xQueue =\r
223             xQueueCreate( pxAttr->mq_maxmsg, sizeof( QueueElement_t ) );\r
224 \r
225         /* Check that queue creation succeeded. */\r
226         if( ( *ppxMessageQueue )->xQueue == NULL )\r
227         {\r
228             vPortFree( *ppxMessageQueue );\r
229             xStatus = pdFALSE;\r
230         }\r
231     }\r
232 \r
233     if( xStatus == pdTRUE )\r
234     {\r
235         /* Allocate space for the queue name plus null-terminator. */\r
236         ( *ppxMessageQueue )->pcName = pvPortMalloc( xNameLength + 1 );\r
237 \r
238         /* Check that memory was successfully allocated for queue name. */\r
239         if( ( *ppxMessageQueue )->pcName == NULL )\r
240         {\r
241             vQueueDelete( ( *ppxMessageQueue )->xQueue );\r
242             vPortFree( *ppxMessageQueue );\r
243             xStatus = pdFALSE;\r
244         }\r
245         else\r
246         {\r
247             /* Copy queue name. Copying xNameLength+1 will cause strncpy to add\r
248              * the null-terminator. */\r
249             ( void ) strncpy( ( *ppxMessageQueue )->pcName, pcName, xNameLength + 1 );\r
250         }\r
251     }\r
252 \r
253     if( xStatus == pdTRUE )\r
254     {\r
255         /* Copy attributes. */\r
256         ( *ppxMessageQueue )->xAttr = *pxAttr;\r
257 \r
258         /* A newly-created queue will have 1 open descriptor for it. */\r
259         ( *ppxMessageQueue )->xOpenDescriptors = 1;\r
260 \r
261         /* A newly-created queue will not be pending unlink. */\r
262         ( *ppxMessageQueue )->xPendingUnlink = pdFALSE;\r
263 \r
264         /* Add the new queue to the list. */\r
265         listADD( &xQueueListHead, &( *ppxMessageQueue )->xLink );\r
266     }\r
267 \r
268     return xStatus;\r
269 }\r
270 \r
271 /*-----------------------------------------------------------*/\r
272 \r
273 static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue )\r
274 {\r
275     QueueElement_t xQueueElement = { 0 };\r
276 \r
277     /* Free all data in the queue. It's assumed that no more data will be added\r
278      * to the queue, so xQueueReceive does not block. */\r
279     while( xQueueReceive( pxMessageQueue->xQueue,\r
280                           ( void * ) &xQueueElement,\r
281                           0 ) == pdTRUE )\r
282     {\r
283         vPortFree( xQueueElement.pcData );\r
284     }\r
285 \r
286     /* Free memory used by this message queue. */\r
287     vQueueDelete( pxMessageQueue->xQueue );\r
288     vPortFree( ( void * ) pxMessageQueue->pcName );\r
289     vPortFree( ( void * ) pxMessageQueue );\r
290 }\r
291 \r
292 /*-----------------------------------------------------------*/\r
293 \r
294 static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,\r
295                                       const char * const pcName,\r
296                                       mqd_t xMessageQueueDescriptor )\r
297 {\r
298     Link_t * pxQueueListLink = NULL;\r
299     QueueListElement_t * pxMessageQueue = NULL;\r
300     BaseType_t xQueueFound = pdFALSE;\r
301 \r
302     /* Iterate through the list of queues. */\r
303     listFOR_EACH( pxQueueListLink, &xQueueListHead )\r
304     {\r
305         pxMessageQueue = listCONTAINER( pxQueueListLink, QueueListElement_t, xLink );\r
306 \r
307         /* Match by name first if provided. */\r
308         if( ( pcName != NULL ) && ( strcmp( pxMessageQueue->pcName, pcName ) == 0 ) )\r
309         {\r
310             xQueueFound = pdTRUE;\r
311             break;\r
312         }\r
313         /* If name doesn't match, match by descriptor. */\r
314         else\r
315         {\r
316             if( ( mqd_t ) pxMessageQueue == xMessageQueueDescriptor )\r
317             {\r
318                 xQueueFound = pdTRUE;\r
319                 break;\r
320             }\r
321         }\r
322     }\r
323 \r
324     /* If the queue was found, set the output parameter. */\r
325     if( ( xQueueFound == pdTRUE ) && ( ppxQueueListElement != NULL ) )\r
326     {\r
327         *ppxQueueListElement = pxMessageQueue;\r
328     }\r
329 \r
330     return xQueueFound;\r
331 }\r
332 \r
333 /*-----------------------------------------------------------*/\r
334 \r
335 static void prvInitializeQueueList( void )\r
336 {\r
337     /* Keep track of whether the queue list has been initialized. */\r
338     static BaseType_t xQueueListInitialized = pdFALSE;\r
339 \r
340     /* Check if queue list needs to be initialized. */\r
341     if( xQueueListInitialized == pdFALSE )\r
342     {\r
343         /* Initialization must be in a critical section to prevent two threads\r
344          * from initializing at the same time. */\r
345         taskENTER_CRITICAL();\r
346 \r
347         /* Check again that queue list is still uninitialized, i.e. it wasn't\r
348          * initialized while this function was waiting to enter the critical\r
349          * section. */\r
350         if( xQueueListInitialized == pdFALSE )\r
351         {\r
352             /* Initialize the queue list mutex and list head. */\r
353             ( void ) xSemaphoreCreateMutexStatic( &xQueueListMutex );\r
354             listINIT_HEAD( &xQueueListHead );\r
355             xQueueListInitialized = pdTRUE;\r
356         }\r
357 \r
358         /* Exit the critical section. */\r
359         taskEXIT_CRITICAL();\r
360     }\r
361 }\r
362 \r
363 /*-----------------------------------------------------------*/\r
364 \r
365 static BaseType_t prvValidateQueueName( const char * const pcName,\r
366                                         size_t * pxNameLength )\r
367 {\r
368     BaseType_t xStatus = pdTRUE;\r
369     size_t xNameLength = 0;\r
370 \r
371     /* All message queue names must start with '/'. */\r
372     if( pcName[ 0 ] != '/' )\r
373     {\r
374         xStatus = pdFALSE;\r
375     }\r
376     else\r
377     {\r
378         /* Get the length of pcName, excluding the first '/' and null-terminator. */\r
379         xNameLength = UTILS_strnlen( pcName, NAME_MAX + 2 );\r
380 \r
381         if( xNameLength == NAME_MAX + 2 )\r
382         {\r
383             /* Name too long. */\r
384             xStatus = pdFALSE;\r
385         }\r
386         else\r
387         {\r
388             /* Name length passes, set output parameter. */\r
389             *pxNameLength = xNameLength;\r
390         }\r
391     }\r
392 \r
393     return xStatus;\r
394 }\r
395 \r
396 /*-----------------------------------------------------------*/\r
397 \r
398 int mq_close( mqd_t mqdes )\r
399 {\r
400     int iStatus = 0;\r
401     QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;\r
402     BaseType_t xQueueRemoved = pdFALSE;\r
403 \r
404     /* Initialize the queue list, if needed. */\r
405     prvInitializeQueueList();\r
406 \r
407     /* Lock the mutex that guards access to the queue list. This call will\r
408      * never fail because it blocks forever. */\r
409     ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );\r
410 \r
411     /* Attempt to find the message queue based on the given descriptor. */\r
412     if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )\r
413     {\r
414         /* Decrement the number of open descriptors. */\r
415         if( pxMessageQueue->xOpenDescriptors > 0 )\r
416         {\r
417             pxMessageQueue->xOpenDescriptors--;\r
418         }\r
419 \r
420         /* Check if the queue has any more open descriptors. */\r
421         if( pxMessageQueue->xOpenDescriptors == 0 )\r
422         {\r
423             /* If no open descriptors remain and mq_unlink has already been called,\r
424              * remove the queue. */\r
425             if( pxMessageQueue->xPendingUnlink == pdTRUE )\r
426             {\r
427                 listREMOVE( &pxMessageQueue->xLink );\r
428 \r
429                 /* Set the flag to delete the queue. Deleting the queue is deferred\r
430                  * until xQueueListMutex is released. */\r
431                 xQueueRemoved = pdTRUE;\r
432             }\r
433             /* Otherwise, wait for the call to mq_unlink. */\r
434             else\r
435             {\r
436                 pxMessageQueue->xPendingUnlink = pdTRUE;\r
437             }\r
438         }\r
439     }\r
440     else\r
441     {\r
442         /* Queue not found; bad descriptor. */\r
443         errno = EBADF;\r
444         iStatus = -1;\r
445     }\r
446 \r
447     /* Release the mutex protecting the queue list. */\r
448     ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );\r
449 \r
450     /* Delete all resources used by the queue if needed. */\r
451     if( xQueueRemoved == pdTRUE )\r
452     {\r
453         prvDeleteMessageQueue( pxMessageQueue );\r
454     }\r
455 \r
456     return iStatus;\r
457 }\r
458 \r
459 /*-----------------------------------------------------------*/\r
460 \r
461 int mq_getattr( mqd_t mqdes,\r
462                 struct mq_attr * mqstat )\r
463 {\r
464     int iStatus = 0;\r
465     QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;\r
466 \r
467     /* Lock the mutex that guards access to the queue list. This call will\r
468      * never fail because it blocks forever. */\r
469     ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );\r
470 \r
471     /* Find the mq referenced by mqdes. */\r
472     if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )\r
473     {\r
474         /* Update the number of messages in the queue and copy the attributes\r
475          * into mqstat. */\r
476         pxMessageQueue->xAttr.mq_curmsgs = ( long ) uxQueueMessagesWaiting( pxMessageQueue->xQueue );\r
477         *mqstat = pxMessageQueue->xAttr;\r
478     }\r
479     else\r
480     {\r
481         /* Queue not found; bad descriptor. */\r
482         errno = EBADF;\r
483         iStatus = -1;\r
484     }\r
485 \r
486     /* Release the mutex protecting the queue list. */\r
487     ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );\r
488 \r
489     return iStatus;\r
490 }\r
491 \r
492 /*-----------------------------------------------------------*/\r
493 \r
494 mqd_t mq_open( const char * name,\r
495                int oflag,\r
496                mode_t mode,\r
497                struct mq_attr * attr )\r
498 {\r
499     mqd_t xMessageQueue = NULL;\r
500     size_t xNameLength = 0;\r
501 \r
502     /* Default mq_attr. */\r
503     struct mq_attr xQueueCreationAttr =\r
504     {\r
505         .mq_flags   = 0,\r
506         .mq_maxmsg  = posixconfigMQ_MAX_MESSAGES,\r
507         .mq_msgsize = posixconfigMQ_MAX_SIZE,\r
508         .mq_curmsgs = 0\r
509     };\r
510 \r
511     /* Silence warnings about unused parameters. */\r
512     ( void ) mode;\r
513 \r
514     /* Initialize the queue list, if needed. */\r
515     prvInitializeQueueList();\r
516 \r
517     /* Check queue name. */\r
518     if( prvValidateQueueName( name, &xNameLength ) == pdFALSE )\r
519     {\r
520         /* Invalid name. */\r
521         errno = EINVAL;\r
522         xMessageQueue = ( mqd_t ) -1;\r
523     }\r
524 \r
525     /* Check attributes, if given. */\r
526     if( xMessageQueue == NULL )\r
527     {\r
528         if( ( oflag & O_CREAT ) && ( attr != NULL ) && ( ( attr->mq_maxmsg <= 0 ) || ( attr->mq_msgsize <= 0 ) ) )\r
529         {\r
530             /* Invalid mq_attr.mq_maxmsg or mq_attr.mq_msgsize. */\r
531             errno = EINVAL;\r
532             xMessageQueue = ( mqd_t ) -1;\r
533         }\r
534     }\r
535 \r
536     if( xMessageQueue == NULL )\r
537     {\r
538         /* Lock the mutex that guards access to the queue list. This call will\r
539          * never fail because it blocks forever. */\r
540         ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );\r
541 \r
542         /* Search the queue list to check if the queue exists. */\r
543         if( prvFindQueueInList( ( QueueListElement_t ** ) &xMessageQueue,\r
544                                 name,\r
545                                 ( mqd_t ) NULL ) == pdTRUE )\r
546         {\r
547             /* If the mq exists, check that this function wasn't called with\r
548              * O_CREAT and O_EXCL. */\r
549             if( ( oflag & O_EXCL ) && ( oflag & O_CREAT ) )\r
550             {\r
551                 errno = EEXIST;\r
552                 xMessageQueue = ( mqd_t ) -1;\r
553             }\r
554             else\r
555             {\r
556                 /* Check if the mq has been unlinked and is pending removal. */\r
557                 if( ( ( QueueListElement_t * ) xMessageQueue )->xPendingUnlink == pdTRUE )\r
558                 {\r
559                     /* Queue pending deletion. Don't allow it to be re-opened. */\r
560                     errno = EINVAL;\r
561                     xMessageQueue = ( mqd_t ) -1;\r
562                 }\r
563                 else\r
564                 {\r
565                     /* Increase count of open file descriptors for queue. */\r
566                     ( ( QueueListElement_t * ) xMessageQueue )->xOpenDescriptors++;\r
567                 }\r
568             }\r
569         }\r
570         /* Queue does not exist. */\r
571         else\r
572         {\r
573             /* Only create the new queue if O_CREAT was specified. */\r
574             if( oflag & O_CREAT )\r
575             {\r
576                 /* Copy attributes if provided. */\r
577                 if( attr != NULL )\r
578                 {\r
579                     xQueueCreationAttr = *attr;\r
580                 }\r
581 \r
582                 /* Copy oflags. */\r
583                 xQueueCreationAttr.mq_flags = ( long ) oflag;\r
584 \r
585                 /* Create the new message queue. */\r
586                 if( prvCreateNewMessageQueue( ( QueueListElement_t ** ) &xMessageQueue,\r
587                                               &xQueueCreationAttr,\r
588                                               name,\r
589                                               xNameLength ) == pdFALSE )\r
590                 {\r
591                     errno = ENOSPC;\r
592                     xMessageQueue = ( mqd_t ) -1;\r
593                 }\r
594             }\r
595             else\r
596             {\r
597                 errno = ENOENT;\r
598                 xMessageQueue = ( mqd_t ) -1;\r
599             }\r
600         }\r
601 \r
602         /* Release the mutex protecting the queue list. */\r
603         ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );\r
604     }\r
605 \r
606     return xMessageQueue;\r
607 }\r
608 \r
609 /*-----------------------------------------------------------*/\r
610 \r
611 ssize_t mq_receive( mqd_t mqdes,\r
612                     char * msg_ptr,\r
613                     size_t msg_len,\r
614                     unsigned int * msg_prio )\r
615 {\r
616     return mq_timedreceive( mqdes, msg_ptr, msg_len, msg_prio, NULL );\r
617 }\r
618 \r
619 /*-----------------------------------------------------------*/\r
620 \r
621 int mq_send( mqd_t mqdes,\r
622              const char * msg_ptr,\r
623              size_t msg_len,\r
624              unsigned msg_prio )\r
625 {\r
626     return mq_timedsend( mqdes, msg_ptr, msg_len, msg_prio, NULL );\r
627 }\r
628 \r
629 /*-----------------------------------------------------------*/\r
630 \r
631 ssize_t mq_timedreceive( mqd_t mqdes,\r
632                          char * msg_ptr,\r
633                          size_t msg_len,\r
634                          unsigned * msg_prio,\r
635                          const struct timespec * abstime )\r
636 {\r
637     ssize_t xStatus = 0;\r
638     int iCalculateTimeoutReturn = 0;\r
639     TickType_t xTimeoutTicks = 0;\r
640     QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;\r
641     QueueElement_t xReceiveData = { 0 };\r
642 \r
643     /* Silence warnings about unused parameters. */\r
644     ( void ) msg_prio;\r
645 \r
646     /* Lock the mutex that guards access to the queue list. This call will\r
647      * never fail because it blocks forever. */\r
648     ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );\r
649 \r
650     /* Find the mq referenced by mqdes. */\r
651     if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )\r
652     {\r
653         /* Queue not found; bad descriptor. */\r
654         errno = EBADF;\r
655         xStatus = -1;\r
656     }\r
657 \r
658     /* Verify that msg_len is large enough. */\r
659     if( xStatus == 0 )\r
660     {\r
661         if( msg_len < ( size_t ) pxMessageQueue->xAttr.mq_msgsize )\r
662         {\r
663             /* msg_len too small. */\r
664             errno = EMSGSIZE;\r
665             xStatus = -1;\r
666         }\r
667     }\r
668 \r
669     if( xStatus == 0 )\r
670     {\r
671         /* Convert abstime to a tick timeout. */\r
672         iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,\r
673                                                            abstime,\r
674                                                            &xTimeoutTicks );\r
675 \r
676         if( iCalculateTimeoutReturn != 0 )\r
677         {\r
678             errno = iCalculateTimeoutReturn;\r
679             xStatus = -1;\r
680         }\r
681     }\r
682 \r
683     /* Release the mutex protecting the queue list. */\r
684     ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );\r
685 \r
686     if( xStatus == 0 )\r
687     {\r
688         /* Receive data from the FreeRTOS queue. */\r
689         if( xQueueReceive( pxMessageQueue->xQueue,\r
690                            &xReceiveData,\r
691                            xTimeoutTicks ) == pdFALSE )\r
692         {\r
693             /* If queue receive fails, set the appropriate errno. */\r
694             if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )\r
695             {\r
696                 /* Set errno to EAGAIN for nonblocking mq. */\r
697                 errno = EAGAIN;\r
698             }\r
699             else\r
700             {\r
701                 /* Otherwise, set errno to ETIMEDOUT. */\r
702                 errno = ETIMEDOUT;\r
703             }\r
704 \r
705             xStatus = -1;\r
706         }\r
707     }\r
708 \r
709     if( xStatus == 0 )\r
710     {\r
711         /* Get the length of data for return value. */\r
712         xStatus = ( ssize_t ) xReceiveData.xDataSize;\r
713 \r
714         /* Copy received data into given buffer, then free it. */\r
715         ( void ) memcpy( msg_ptr, xReceiveData.pcData, xReceiveData.xDataSize );\r
716         vPortFree( xReceiveData.pcData );\r
717     }\r
718 \r
719     return xStatus;\r
720 }\r
721 \r
722 /*-----------------------------------------------------------*/\r
723 \r
724 int mq_timedsend( mqd_t mqdes,\r
725                   const char * msg_ptr,\r
726                   size_t msg_len,\r
727                   unsigned int msg_prio,\r
728                   const struct timespec * abstime )\r
729 {\r
730     int iStatus = 0, iCalculateTimeoutReturn = 0;\r
731     TickType_t xTimeoutTicks = 0;\r
732     QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;\r
733     QueueElement_t xSendData = { 0 };\r
734 \r
735     /* Silence warnings about unused parameters. */\r
736     ( void ) msg_prio;\r
737 \r
738     /* Lock the mutex that guards access to the queue list. This call will\r
739      * never fail because it blocks forever. */\r
740     ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );\r
741 \r
742     /* Find the mq referenced by mqdes. */\r
743     if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )\r
744     {\r
745         /* Queue not found; bad descriptor. */\r
746         errno = EBADF;\r
747         iStatus = -1;\r
748     }\r
749 \r
750     /* Verify that mq_msgsize is large enough. */\r
751     if( iStatus == 0 )\r
752     {\r
753         if( msg_len > ( size_t ) pxMessageQueue->xAttr.mq_msgsize )\r
754         {\r
755             /* msg_len too large. */\r
756             errno = EMSGSIZE;\r
757             iStatus = -1;\r
758         }\r
759     }\r
760 \r
761     if( iStatus == 0 )\r
762     {\r
763         /* Convert abstime to a tick timeout. */\r
764         iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,\r
765                                                            abstime,\r
766                                                            &xTimeoutTicks );\r
767 \r
768         if( iCalculateTimeoutReturn != 0 )\r
769         {\r
770             errno = iCalculateTimeoutReturn;\r
771             iStatus = -1;\r
772         }\r
773     }\r
774 \r
775     /* Release the mutex protecting the queue list. */\r
776     ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );\r
777 \r
778     /* Allocate memory for the message. */\r
779     if( iStatus == 0 )\r
780     {\r
781         xSendData.xDataSize = msg_len;\r
782         xSendData.pcData = pvPortMalloc( msg_len );\r
783 \r
784         /* Check that memory allocation succeeded. */\r
785         if( xSendData.pcData == NULL )\r
786         {\r
787             /* msg_len too large. */\r
788             errno = EMSGSIZE;\r
789             iStatus = -1;\r
790         }\r
791         else\r
792         {\r
793             /* Copy the data to send. */\r
794             ( void ) memcpy( xSendData.pcData, msg_ptr, msg_len );\r
795         }\r
796     }\r
797 \r
798     if( iStatus == 0 )\r
799     {\r
800         /* Send data to the FreeRTOS queue. */\r
801         if( xQueueSend( pxMessageQueue->xQueue,\r
802                         &xSendData,\r
803                         xTimeoutTicks ) == pdFALSE )\r
804         {\r
805             /* If queue send fails, set the appropriate errno. */\r
806             if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )\r
807             {\r
808                 /* Set errno to EAGAIN for nonblocking mq. */\r
809                 errno = EAGAIN;\r
810             }\r
811             else\r
812             {\r
813                 /* Otherwise, set errno to ETIMEDOUT. */\r
814                 errno = ETIMEDOUT;\r
815             }\r
816 \r
817             /* Free the allocated queue data. */\r
818             vPortFree( xSendData.pcData );\r
819 \r
820             iStatus = -1;\r
821         }\r
822     }\r
823 \r
824     return iStatus;\r
825 }\r
826 \r
827 /*-----------------------------------------------------------*/\r
828 \r
829 int mq_unlink( const char * name )\r
830 {\r
831     int iStatus = 0;\r
832     size_t xNameSize = 0;\r
833     BaseType_t xQueueRemoved = pdFALSE;\r
834     QueueListElement_t * pxMessageQueue = NULL;\r
835 \r
836     /* Initialize the queue list, if needed. */\r
837     prvInitializeQueueList();\r
838 \r
839     /* Check queue name. */\r
840     if( prvValidateQueueName( name, &xNameSize ) == pdFALSE )\r
841     {\r
842         /* Error with mq name. */\r
843         errno = EINVAL;\r
844         iStatus = -1;\r
845     }\r
846 \r
847     if( iStatus == 0 )\r
848     {\r
849         /* Lock the mutex that guards access to the queue list. This call will\r
850          * never fail because it blocks forever. */\r
851         ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );\r
852 \r
853         /* Check if the named queue exists. */\r
854         if( prvFindQueueInList( &pxMessageQueue, name, ( mqd_t ) NULL ) == pdTRUE )\r
855         {\r
856             /* If the queue exists and there are no open descriptors to it,\r
857              * remove it from the list. */\r
858             if( pxMessageQueue->xOpenDescriptors == 0 )\r
859             {\r
860                 listREMOVE( &pxMessageQueue->xLink );\r
861 \r
862                 /* Set the flag to delete the queue. Deleting the queue is deferred\r
863                  * until xQueueListMutex is released. */\r
864                 xQueueRemoved = pdTRUE;\r
865             }\r
866             else\r
867             {\r
868                 /* If the queue has open descriptors, set the pending unlink flag\r
869                  * so that mq_close will free its resources. */\r
870                 pxMessageQueue->xPendingUnlink = pdTRUE;\r
871             }\r
872         }\r
873         else\r
874         {\r
875             /* The named message queue doesn't exist. */\r
876             errno = ENOENT;\r
877             iStatus = -1;\r
878         }\r
879 \r
880         /* Release the mutex protecting the queue list. */\r
881         ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );\r
882     }\r
883 \r
884     /* Delete all resources used by the queue if needed. */\r
885     if( xQueueRemoved == pdTRUE )\r
886     {\r
887         prvDeleteMessageQueue( pxMessageQueue );\r
888     }\r
889 \r
890     return iStatus;\r
891 }\r
892 \r
893 /*-----------------------------------------------------------*/\r