2 * Amazon FreeRTOS POSIX V1.1.0
\r
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * @file FreeRTOS_POSIX_mqueue.c
\r
28 * @brief Implementation of message queue functions in mqueue.h
\r
31 /* C standard library includes. */
\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
42 * @brief Element of the FreeRTOS queues that store mq data.
\r
44 typedef struct QueueElement
\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
51 * @brief Data structure of an mq.
\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
56 typedef struct QueueListElement
\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
66 /*-----------------------------------------------------------*/
\r
69 * @brief Convert an absolute timespec into a tick timeout, taking into account
\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
76 * @return 0 if successful; EINVAL if pxAbsoluteTimeout is invalid, or ETIMEDOUT
\r
77 * if pxAbsoluteTimeout is in the past.
\r
79 static int prvCalculateTickTimeout( long lMessageQueueFlags,
\r
80 const struct timespec * const pxAbsoluteTimeout,
\r
81 TickType_t * pxTimeoutTicks );
\r
84 * @brief Add a new queue to the queue list.
\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
91 * @return pdTRUE if the queue is found; pdFALSE otherwise.
\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
99 * @brief Free all the resources used by a message queue.
\r
101 * @param[out] pxMessageQueue Pointer to queue to free.
\r
105 static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue );
\r
108 * @brief Attempt to find the queue identified by pcName or xMqId in the queue list.
\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
115 * @return pdTRUE if the queue is found; pdFALSE otherwise.
\r
117 static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,
\r
118 const char * const pcName,
\r
119 mqd_t xMessageQueueDescriptor );
\r
122 * @brief Initialize the queue list.
\r
124 * Performs initialization of the queue list mutex and queue list head.
\r
128 static void prvInitializeQueueList( void );
\r
131 * @brief Checks that pcName is a valid name for a message queue.
\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
137 * @return pdTRUE if the name is valid; pdFALSE otherwise.
\r
139 static BaseType_t prvValidateQueueName( const char * const pcName,
\r
140 size_t * pxNameLength );
\r
143 * @brief Guards access to the list of message queues.
\r
145 static StaticSemaphore_t xQueueListMutex = { { 0 }, .u = { 0 } };
\r
148 * @brief Head of the linked list of queues.
\r
150 static Link_t xQueueListHead = { 0 };
\r
152 /*-----------------------------------------------------------*/
\r
154 static int prvCalculateTickTimeout( long lMessageQueueFlags,
\r
155 const struct timespec * const pxAbsoluteTimeout,
\r
156 TickType_t * pxTimeoutTicks )
\r
160 /* Check for nonblocking queue. */
\r
161 if( lMessageQueueFlags & O_NONBLOCK )
\r
163 /* No additional checks are done for nonblocking queues. Timeout is 0. */
\r
164 *pxTimeoutTicks = 0;
\r
168 /* No absolute timeout given. Block forever. */
\r
169 if( pxAbsoluteTimeout == NULL )
\r
171 *pxTimeoutTicks = portMAX_DELAY;
\r
175 struct timespec xCurrentTime = { 0 };
\r
177 /* Check that the given timespec is valid. */
\r
178 if( UTILS_ValidateTimespec( pxAbsoluteTimeout ) == false )
\r
183 /* Get current time */
\r
184 if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) )
\r
189 /* Convert absolute timespec to ticks. */
\r
190 if( ( iStatus == 0 ) &&
\r
191 ( UTILS_AbsoluteTimespecToDeltaTicks( pxAbsoluteTimeout, &xCurrentTime, pxTimeoutTicks ) != 0 ) )
\r
193 iStatus = ETIMEDOUT;
\r
201 /*-----------------------------------------------------------*/
\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
208 BaseType_t xStatus = pdTRUE;
\r
210 /* Allocate space for a new queue element. */
\r
211 *ppxMessageQueue = pvPortMalloc( sizeof( QueueListElement_t ) );
\r
213 /* Check that memory allocation succeeded. */
\r
214 if( *ppxMessageQueue == NULL )
\r
219 /* Create the FreeRTOS queue. */
\r
220 if( xStatus == pdTRUE )
\r
222 ( *ppxMessageQueue )->xQueue =
\r
223 xQueueCreate( pxAttr->mq_maxmsg, sizeof( QueueElement_t ) );
\r
225 /* Check that queue creation succeeded. */
\r
226 if( ( *ppxMessageQueue )->xQueue == NULL )
\r
228 vPortFree( *ppxMessageQueue );
\r
233 if( xStatus == pdTRUE )
\r
235 /* Allocate space for the queue name plus null-terminator. */
\r
236 ( *ppxMessageQueue )->pcName = pvPortMalloc( xNameLength + 1 );
\r
238 /* Check that memory was successfully allocated for queue name. */
\r
239 if( ( *ppxMessageQueue )->pcName == NULL )
\r
241 vQueueDelete( ( *ppxMessageQueue )->xQueue );
\r
242 vPortFree( *ppxMessageQueue );
\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
253 if( xStatus == pdTRUE )
\r
255 /* Copy attributes. */
\r
256 ( *ppxMessageQueue )->xAttr = *pxAttr;
\r
258 /* A newly-created queue will have 1 open descriptor for it. */
\r
259 ( *ppxMessageQueue )->xOpenDescriptors = 1;
\r
261 /* A newly-created queue will not be pending unlink. */
\r
262 ( *ppxMessageQueue )->xPendingUnlink = pdFALSE;
\r
264 /* Add the new queue to the list. */
\r
265 listADD( &xQueueListHead, &( *ppxMessageQueue )->xLink );
\r
271 /*-----------------------------------------------------------*/
\r
273 static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue )
\r
275 QueueElement_t xQueueElement = { 0 };
\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
283 vPortFree( xQueueElement.pcData );
\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
292 /*-----------------------------------------------------------*/
\r
294 static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,
\r
295 const char * const pcName,
\r
296 mqd_t xMessageQueueDescriptor )
\r
298 Link_t * pxQueueListLink = NULL;
\r
299 QueueListElement_t * pxMessageQueue = NULL;
\r
300 BaseType_t xQueueFound = pdFALSE;
\r
302 /* Iterate through the list of queues. */
\r
303 listFOR_EACH( pxQueueListLink, &xQueueListHead )
\r
305 pxMessageQueue = listCONTAINER( pxQueueListLink, QueueListElement_t, xLink );
\r
307 /* Match by name first if provided. */
\r
308 if( ( pcName != NULL ) && ( strcmp( pxMessageQueue->pcName, pcName ) == 0 ) )
\r
310 xQueueFound = pdTRUE;
\r
313 /* If name doesn't match, match by descriptor. */
\r
316 if( ( mqd_t ) pxMessageQueue == xMessageQueueDescriptor )
\r
318 xQueueFound = pdTRUE;
\r
324 /* If the queue was found, set the output parameter. */
\r
325 if( ( xQueueFound == pdTRUE ) && ( ppxQueueListElement != NULL ) )
\r
327 *ppxQueueListElement = pxMessageQueue;
\r
330 return xQueueFound;
\r
333 /*-----------------------------------------------------------*/
\r
335 static void prvInitializeQueueList( void )
\r
337 /* Keep track of whether the queue list has been initialized. */
\r
338 static BaseType_t xQueueListInitialized = pdFALSE;
\r
340 /* Check if queue list needs to be initialized. */
\r
341 if( xQueueListInitialized == pdFALSE )
\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
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
350 if( xQueueListInitialized == pdFALSE )
\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
358 /* Exit the critical section. */
\r
359 taskEXIT_CRITICAL();
\r
363 /*-----------------------------------------------------------*/
\r
365 static BaseType_t prvValidateQueueName( const char * const pcName,
\r
366 size_t * pxNameLength )
\r
368 BaseType_t xStatus = pdTRUE;
\r
369 size_t xNameLength = 0;
\r
371 /* All message queue names must start with '/'. */
\r
372 if( pcName[ 0 ] != '/' )
\r
378 /* Get the length of pcName, excluding the first '/' and null-terminator. */
\r
379 xNameLength = UTILS_strnlen( pcName, NAME_MAX + 2 );
\r
381 if( xNameLength == NAME_MAX + 2 )
\r
383 /* Name too long. */
\r
388 /* Name length passes, set output parameter. */
\r
389 *pxNameLength = xNameLength;
\r
396 /*-----------------------------------------------------------*/
\r
398 int mq_close( mqd_t mqdes )
\r
401 QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
\r
402 BaseType_t xQueueRemoved = pdFALSE;
\r
404 /* Initialize the queue list, if needed. */
\r
405 prvInitializeQueueList();
\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
411 /* Attempt to find the message queue based on the given descriptor. */
\r
412 if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )
\r
414 /* Decrement the number of open descriptors. */
\r
415 if( pxMessageQueue->xOpenDescriptors > 0 )
\r
417 pxMessageQueue->xOpenDescriptors--;
\r
420 /* Check if the queue has any more open descriptors. */
\r
421 if( pxMessageQueue->xOpenDescriptors == 0 )
\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
427 listREMOVE( &pxMessageQueue->xLink );
\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
433 /* Otherwise, wait for the call to mq_unlink. */
\r
436 pxMessageQueue->xPendingUnlink = pdTRUE;
\r
442 /* Queue not found; bad descriptor. */
\r
447 /* Release the mutex protecting the queue list. */
\r
448 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
\r
450 /* Delete all resources used by the queue if needed. */
\r
451 if( xQueueRemoved == pdTRUE )
\r
453 prvDeleteMessageQueue( pxMessageQueue );
\r
459 /*-----------------------------------------------------------*/
\r
461 int mq_getattr( mqd_t mqdes,
\r
462 struct mq_attr * mqstat )
\r
465 QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
\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
471 /* Find the mq referenced by mqdes. */
\r
472 if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )
\r
474 /* Update the number of messages in the queue and copy the attributes
\r
476 pxMessageQueue->xAttr.mq_curmsgs = ( long ) uxQueueMessagesWaiting( pxMessageQueue->xQueue );
\r
477 *mqstat = pxMessageQueue->xAttr;
\r
481 /* Queue not found; bad descriptor. */
\r
486 /* Release the mutex protecting the queue list. */
\r
487 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
\r
492 /*-----------------------------------------------------------*/
\r
494 mqd_t mq_open( const char * name,
\r
497 struct mq_attr * attr )
\r
499 mqd_t xMessageQueue = NULL;
\r
500 size_t xNameLength = 0;
\r
502 /* Default mq_attr. */
\r
503 struct mq_attr xQueueCreationAttr =
\r
506 .mq_maxmsg = posixconfigMQ_MAX_MESSAGES,
\r
507 .mq_msgsize = posixconfigMQ_MAX_SIZE,
\r
511 /* Silence warnings about unused parameters. */
\r
514 /* Initialize the queue list, if needed. */
\r
515 prvInitializeQueueList();
\r
517 /* Check queue name. */
\r
518 if( prvValidateQueueName( name, &xNameLength ) == pdFALSE )
\r
520 /* Invalid name. */
\r
522 xMessageQueue = ( mqd_t ) -1;
\r
525 /* Check attributes, if given. */
\r
526 if( xMessageQueue == NULL )
\r
528 if( ( oflag & O_CREAT ) && ( attr != NULL ) && ( ( attr->mq_maxmsg <= 0 ) || ( attr->mq_msgsize <= 0 ) ) )
\r
530 /* Invalid mq_attr.mq_maxmsg or mq_attr.mq_msgsize. */
\r
532 xMessageQueue = ( mqd_t ) -1;
\r
536 if( xMessageQueue == NULL )
\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
542 /* Search the queue list to check if the queue exists. */
\r
543 if( prvFindQueueInList( ( QueueListElement_t ** ) &xMessageQueue,
\r
545 ( mqd_t ) NULL ) == pdTRUE )
\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
552 xMessageQueue = ( mqd_t ) -1;
\r
556 /* Check if the mq has been unlinked and is pending removal. */
\r
557 if( ( ( QueueListElement_t * ) xMessageQueue )->xPendingUnlink == pdTRUE )
\r
559 /* Queue pending deletion. Don't allow it to be re-opened. */
\r
561 xMessageQueue = ( mqd_t ) -1;
\r
565 /* Increase count of open file descriptors for queue. */
\r
566 ( ( QueueListElement_t * ) xMessageQueue )->xOpenDescriptors++;
\r
570 /* Queue does not exist. */
\r
573 /* Only create the new queue if O_CREAT was specified. */
\r
574 if( oflag & O_CREAT )
\r
576 /* Copy attributes if provided. */
\r
579 xQueueCreationAttr = *attr;
\r
583 xQueueCreationAttr.mq_flags = ( long ) oflag;
\r
585 /* Create the new message queue. */
\r
586 if( prvCreateNewMessageQueue( ( QueueListElement_t ** ) &xMessageQueue,
\r
587 &xQueueCreationAttr,
\r
589 xNameLength ) == pdFALSE )
\r
592 xMessageQueue = ( mqd_t ) -1;
\r
598 xMessageQueue = ( mqd_t ) -1;
\r
602 /* Release the mutex protecting the queue list. */
\r
603 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
\r
606 return xMessageQueue;
\r
609 /*-----------------------------------------------------------*/
\r
611 ssize_t mq_receive( mqd_t mqdes,
\r
614 unsigned int * msg_prio )
\r
616 return mq_timedreceive( mqdes, msg_ptr, msg_len, msg_prio, NULL );
\r
619 /*-----------------------------------------------------------*/
\r
621 int mq_send( mqd_t mqdes,
\r
622 const char * msg_ptr,
\r
624 unsigned msg_prio )
\r
626 return mq_timedsend( mqdes, msg_ptr, msg_len, msg_prio, NULL );
\r
629 /*-----------------------------------------------------------*/
\r
631 ssize_t mq_timedreceive( mqd_t mqdes,
\r
634 unsigned * msg_prio,
\r
635 const struct timespec * abstime )
\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
643 /* Silence warnings about unused parameters. */
\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
650 /* Find the mq referenced by mqdes. */
\r
651 if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )
\r
653 /* Queue not found; bad descriptor. */
\r
658 /* Verify that msg_len is large enough. */
\r
661 if( msg_len < ( size_t ) pxMessageQueue->xAttr.mq_msgsize )
\r
663 /* msg_len too small. */
\r
671 /* Convert abstime to a tick timeout. */
\r
672 iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,
\r
676 if( iCalculateTimeoutReturn != 0 )
\r
678 errno = iCalculateTimeoutReturn;
\r
683 /* Release the mutex protecting the queue list. */
\r
684 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
\r
688 /* Receive data from the FreeRTOS queue. */
\r
689 if( xQueueReceive( pxMessageQueue->xQueue,
\r
691 xTimeoutTicks ) == pdFALSE )
\r
693 /* If queue receive fails, set the appropriate errno. */
\r
694 if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )
\r
696 /* Set errno to EAGAIN for nonblocking mq. */
\r
701 /* Otherwise, set errno to ETIMEDOUT. */
\r
711 /* Get the length of data for return value. */
\r
712 xStatus = ( ssize_t ) xReceiveData.xDataSize;
\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
722 /*-----------------------------------------------------------*/
\r
724 int mq_timedsend( mqd_t mqdes,
\r
725 const char * msg_ptr,
\r
727 unsigned int msg_prio,
\r
728 const struct timespec * abstime )
\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
735 /* Silence warnings about unused parameters. */
\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
742 /* Find the mq referenced by mqdes. */
\r
743 if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )
\r
745 /* Queue not found; bad descriptor. */
\r
750 /* Verify that mq_msgsize is large enough. */
\r
753 if( msg_len > ( size_t ) pxMessageQueue->xAttr.mq_msgsize )
\r
755 /* msg_len too large. */
\r
763 /* Convert abstime to a tick timeout. */
\r
764 iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,
\r
768 if( iCalculateTimeoutReturn != 0 )
\r
770 errno = iCalculateTimeoutReturn;
\r
775 /* Release the mutex protecting the queue list. */
\r
776 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
\r
778 /* Allocate memory for the message. */
\r
781 xSendData.xDataSize = msg_len;
\r
782 xSendData.pcData = pvPortMalloc( msg_len );
\r
784 /* Check that memory allocation succeeded. */
\r
785 if( xSendData.pcData == NULL )
\r
787 /* msg_len too large. */
\r
793 /* Copy the data to send. */
\r
794 ( void ) memcpy( xSendData.pcData, msg_ptr, msg_len );
\r
800 /* Send data to the FreeRTOS queue. */
\r
801 if( xQueueSend( pxMessageQueue->xQueue,
\r
803 xTimeoutTicks ) == pdFALSE )
\r
805 /* If queue send fails, set the appropriate errno. */
\r
806 if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )
\r
808 /* Set errno to EAGAIN for nonblocking mq. */
\r
813 /* Otherwise, set errno to ETIMEDOUT. */
\r
817 /* Free the allocated queue data. */
\r
818 vPortFree( xSendData.pcData );
\r
827 /*-----------------------------------------------------------*/
\r
829 int mq_unlink( const char * name )
\r
832 size_t xNameSize = 0;
\r
833 BaseType_t xQueueRemoved = pdFALSE;
\r
834 QueueListElement_t * pxMessageQueue = NULL;
\r
836 /* Initialize the queue list, if needed. */
\r
837 prvInitializeQueueList();
\r
839 /* Check queue name. */
\r
840 if( prvValidateQueueName( name, &xNameSize ) == pdFALSE )
\r
842 /* Error with mq name. */
\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
853 /* Check if the named queue exists. */
\r
854 if( prvFindQueueInList( &pxMessageQueue, name, ( mqd_t ) NULL ) == pdTRUE )
\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
860 listREMOVE( &pxMessageQueue->xLink );
\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
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
875 /* The named message queue doesn't exist. */
\r
880 /* Release the mutex protecting the queue list. */
\r
881 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
\r
884 /* Delete all resources used by the queue if needed. */
\r
885 if( xQueueRemoved == pdTRUE )
\r
887 prvDeleteMessageQueue( pxMessageQueue );
\r
893 /*-----------------------------------------------------------*/
\r