summaryrefslogtreecommitdiff
path: root/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c
diff options
context:
space:
mode:
authorAditya Naik2020-08-03 14:42:06 -0400
committerAditya Naik2020-08-03 14:42:06 -0400
commit11a52e4e88bcad1e6bddcf02f78e1cc5eaaec508 (patch)
treed7f725c30e618994a0650607ede73ab3efc72c67 /lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c
parent81b3f3d5336eab67e8eb21bb4011e552f3895a4e (diff)
RTOS skeleton with (UNIX) POSIX calls. Reorg of stream files
Diffstat (limited to 'lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c')
-rwxr-xr-xlib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c893
1 files changed, 893 insertions, 0 deletions
diff --git a/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c b/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c
new file mode 100755
index 0000000..9f9079b
--- /dev/null
+++ b/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c
@@ -0,0 +1,893 @@
+/*
+ * Amazon FreeRTOS POSIX V1.1.0
+ * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+/**
+ * @file FreeRTOS_POSIX_mqueue.c
+ * @brief Implementation of message queue functions in mqueue.h
+ */
+
+/* C standard library includes. */
+#include <string.h>
+
+/* FreeRTOS+POSIX includes. */
+#include "FreeRTOS_POSIX.h"
+#include "FreeRTOS_POSIX/errno.h"
+#include "FreeRTOS_POSIX/fcntl.h"
+#include "FreeRTOS_POSIX/mqueue.h"
+#include "FreeRTOS_POSIX/utils.h"
+
+/**
+ * @brief Element of the FreeRTOS queues that store mq data.
+ */
+typedef struct QueueElement
+{
+ char * pcData; /**< Data in queue. Type char* to match msg_ptr. */
+ size_t xDataSize; /**< Size of data pointed by pcData. */
+} QueueElement_t;
+
+/**
+ * @brief Data structure of an mq.
+ *
+ * FreeRTOS isn't guaranteed to have a file-like abstraction, so message
+ * queues in this implementation are stored as a linked list (in RAM).
+ */
+typedef struct QueueListElement
+{
+ Link_t xLink; /**< Pointer to the next element in the list. */
+ QueueHandle_t xQueue; /**< FreeRTOS queue handle. */
+ size_t xOpenDescriptors; /**< Number of threads that have opened this queue. */
+ char * pcName; /**< Null-terminated queue name. */
+ struct mq_attr xAttr; /**< Queue attibutes. */
+ BaseType_t xPendingUnlink; /**< If pdTRUE, this queue will be unlinked once all descriptors close. */
+} QueueListElement_t;
+
+/*-----------------------------------------------------------*/
+
+/**
+ * @brief Convert an absolute timespec into a tick timeout, taking into account
+ * queue flags.
+ *
+ * @param[in] lMessageQueueFlags Message queue flags to consider.
+ * @param[in] pxAbsoluteTimeout The absolute timespec to convert.
+ * @param[out] pxTimeoutTicks Output parameter of the timeout in ticks.
+ *
+ * @return 0 if successful; EINVAL if pxAbsoluteTimeout is invalid, or ETIMEDOUT
+ * if pxAbsoluteTimeout is in the past.
+ */
+static int prvCalculateTickTimeout( long lMessageQueueFlags,
+ const struct timespec * const pxAbsoluteTimeout,
+ TickType_t * pxTimeoutTicks );
+
+/**
+ * @brief Add a new queue to the queue list.
+ *
+ * @param[out] ppxMessageQueue Pointer to new queue.
+ * @param[in] pxAttr mq_attr of the new queue.
+ * @param[in] pcName Name of new queue.
+ * @param[in] xNameLength Length of pcName.
+ *
+ * @return pdTRUE if the queue is found; pdFALSE otherwise.
+ */
+static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue,
+ const struct mq_attr * const pxAttr,
+ const char * const pcName,
+ size_t xNameLength );
+
+/**
+ * @brief Free all the resources used by a message queue.
+ *
+ * @param[out] pxMessageQueue Pointer to queue to free.
+ *
+ * @return nothing
+ */
+static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue );
+
+/**
+ * @brief Attempt to find the queue identified by pcName or xMqId in the queue list.
+ *
+ * Matches queues by pcName first; if pcName is NULL, matches by xMqId.
+ * @param[out] ppxQueueListElement Output parameter set when queue is found.
+ * @param[in] pcName A queue name to match.
+ * @param[in] xMessageQueueDescriptor A queue descriptor to match.
+ *
+ * @return pdTRUE if the queue is found; pdFALSE otherwise.
+ */
+static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,
+ const char * const pcName,
+ mqd_t xMessageQueueDescriptor );
+
+/**
+ * @brief Initialize the queue list.
+ *
+ * Performs initialization of the queue list mutex and queue list head.
+ *
+ * @return nothing
+ */
+static void prvInitializeQueueList( void );
+
+/**
+ * @brief Checks that pcName is a valid name for a message queue.
+ *
+ * Also outputs the length of pcName.
+ * @param[in] pcName The name to check.
+ * @param[out] pxNameLength Output parameter for name length.
+ *
+ * @return pdTRUE if the name is valid; pdFALSE otherwise.
+ */
+static BaseType_t prvValidateQueueName( const char * const pcName,
+ size_t * pxNameLength );
+
+/**
+ * @brief Guards access to the list of message queues.
+ */
+static StaticSemaphore_t xQueueListMutex = { { 0 }, .u = { 0 } };
+
+/**
+ * @brief Head of the linked list of queues.
+ */
+static Link_t xQueueListHead = { 0 };
+
+/*-----------------------------------------------------------*/
+
+static int prvCalculateTickTimeout( long lMessageQueueFlags,
+ const struct timespec * const pxAbsoluteTimeout,
+ TickType_t * pxTimeoutTicks )
+{
+ int iStatus = 0;
+
+ /* Check for nonblocking queue. */
+ if( lMessageQueueFlags & O_NONBLOCK )
+ {
+ /* No additional checks are done for nonblocking queues. Timeout is 0. */
+ *pxTimeoutTicks = 0;
+ }
+ else
+ {
+ /* No absolute timeout given. Block forever. */
+ if( pxAbsoluteTimeout == NULL )
+ {
+ *pxTimeoutTicks = portMAX_DELAY;
+ }
+ else
+ {
+ struct timespec xCurrentTime = { 0 };
+
+ /* Check that the given timespec is valid. */
+ if( UTILS_ValidateTimespec( pxAbsoluteTimeout ) == false )
+ {
+ iStatus = EINVAL;
+ }
+
+ /* Get current time */
+ if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) )
+ {
+ iStatus = EINVAL;
+ }
+
+ /* Convert absolute timespec to ticks. */
+ if( ( iStatus == 0 ) &&
+ ( UTILS_AbsoluteTimespecToDeltaTicks( pxAbsoluteTimeout, &xCurrentTime, pxTimeoutTicks ) != 0 ) )
+ {
+ iStatus = ETIMEDOUT;
+ }
+ }
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue,
+ const struct mq_attr * const pxAttr,
+ const char * const pcName,
+ size_t xNameLength )
+{
+ BaseType_t xStatus = pdTRUE;
+
+ /* Allocate space for a new queue element. */
+ *ppxMessageQueue = pvPortMalloc( sizeof( QueueListElement_t ) );
+
+ /* Check that memory allocation succeeded. */
+ if( *ppxMessageQueue == NULL )
+ {
+ xStatus = pdFALSE;
+ }
+
+ /* Create the FreeRTOS queue. */
+ if( xStatus == pdTRUE )
+ {
+ ( *ppxMessageQueue )->xQueue =
+ xQueueCreate( pxAttr->mq_maxmsg, sizeof( QueueElement_t ) );
+
+ /* Check that queue creation succeeded. */
+ if( ( *ppxMessageQueue )->xQueue == NULL )
+ {
+ vPortFree( *ppxMessageQueue );
+ xStatus = pdFALSE;
+ }
+ }
+
+ if( xStatus == pdTRUE )
+ {
+ /* Allocate space for the queue name plus null-terminator. */
+ ( *ppxMessageQueue )->pcName = pvPortMalloc( xNameLength + 1 );
+
+ /* Check that memory was successfully allocated for queue name. */
+ if( ( *ppxMessageQueue )->pcName == NULL )
+ {
+ vQueueDelete( ( *ppxMessageQueue )->xQueue );
+ vPortFree( *ppxMessageQueue );
+ xStatus = pdFALSE;
+ }
+ else
+ {
+ /* Copy queue name. Copying xNameLength+1 will cause strncpy to add
+ * the null-terminator. */
+ ( void ) strncpy( ( *ppxMessageQueue )->pcName, pcName, xNameLength + 1 );
+ }
+ }
+
+ if( xStatus == pdTRUE )
+ {
+ /* Copy attributes. */
+ ( *ppxMessageQueue )->xAttr = *pxAttr;
+
+ /* A newly-created queue will have 1 open descriptor for it. */
+ ( *ppxMessageQueue )->xOpenDescriptors = 1;
+
+ /* A newly-created queue will not be pending unlink. */
+ ( *ppxMessageQueue )->xPendingUnlink = pdFALSE;
+
+ /* Add the new queue to the list. */
+ listADD( &xQueueListHead, &( *ppxMessageQueue )->xLink );
+ }
+
+ return xStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue )
+{
+ QueueElement_t xQueueElement = { 0 };
+
+ /* Free all data in the queue. It's assumed that no more data will be added
+ * to the queue, so xQueueReceive does not block. */
+ while( xQueueReceive( pxMessageQueue->xQueue,
+ ( void * ) &xQueueElement,
+ 0 ) == pdTRUE )
+ {
+ vPortFree( xQueueElement.pcData );
+ }
+
+ /* Free memory used by this message queue. */
+ vQueueDelete( pxMessageQueue->xQueue );
+ vPortFree( ( void * ) pxMessageQueue->pcName );
+ vPortFree( ( void * ) pxMessageQueue );
+}
+
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,
+ const char * const pcName,
+ mqd_t xMessageQueueDescriptor )
+{
+ Link_t * pxQueueListLink = NULL;
+ QueueListElement_t * pxMessageQueue = NULL;
+ BaseType_t xQueueFound = pdFALSE;
+
+ /* Iterate through the list of queues. */
+ listFOR_EACH( pxQueueListLink, &xQueueListHead )
+ {
+ pxMessageQueue = listCONTAINER( pxQueueListLink, QueueListElement_t, xLink );
+
+ /* Match by name first if provided. */
+ if( ( pcName != NULL ) && ( strcmp( pxMessageQueue->pcName, pcName ) == 0 ) )
+ {
+ xQueueFound = pdTRUE;
+ break;
+ }
+ /* If name doesn't match, match by descriptor. */
+ else
+ {
+ if( ( mqd_t ) pxMessageQueue == xMessageQueueDescriptor )
+ {
+ xQueueFound = pdTRUE;
+ break;
+ }
+ }
+ }
+
+ /* If the queue was found, set the output parameter. */
+ if( ( xQueueFound == pdTRUE ) && ( ppxQueueListElement != NULL ) )
+ {
+ *ppxQueueListElement = pxMessageQueue;
+ }
+
+ return xQueueFound;
+}
+
+/*-----------------------------------------------------------*/
+
+static void prvInitializeQueueList( void )
+{
+ /* Keep track of whether the queue list has been initialized. */
+ static BaseType_t xQueueListInitialized = pdFALSE;
+
+ /* Check if queue list needs to be initialized. */
+ if( xQueueListInitialized == pdFALSE )
+ {
+ /* Initialization must be in a critical section to prevent two threads
+ * from initializing at the same time. */
+ taskENTER_CRITICAL();
+
+ /* Check again that queue list is still uninitialized, i.e. it wasn't
+ * initialized while this function was waiting to enter the critical
+ * section. */
+ if( xQueueListInitialized == pdFALSE )
+ {
+ /* Initialize the queue list mutex and list head. */
+ ( void ) xSemaphoreCreateMutexStatic( &xQueueListMutex );
+ listINIT_HEAD( &xQueueListHead );
+ xQueueListInitialized = pdTRUE;
+ }
+
+ /* Exit the critical section. */
+ taskEXIT_CRITICAL();
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvValidateQueueName( const char * const pcName,
+ size_t * pxNameLength )
+{
+ BaseType_t xStatus = pdTRUE;
+ size_t xNameLength = 0;
+
+ /* All message queue names must start with '/'. */
+ if( pcName[ 0 ] != '/' )
+ {
+ xStatus = pdFALSE;
+ }
+ else
+ {
+ /* Get the length of pcName, excluding the first '/' and null-terminator. */
+ xNameLength = UTILS_strnlen( pcName, NAME_MAX + 2 );
+
+ if( xNameLength == NAME_MAX + 2 )
+ {
+ /* Name too long. */
+ xStatus = pdFALSE;
+ }
+ else
+ {
+ /* Name length passes, set output parameter. */
+ *pxNameLength = xNameLength;
+ }
+ }
+
+ return xStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int mq_close( mqd_t mqdes )
+{
+ int iStatus = 0;
+ QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
+ BaseType_t xQueueRemoved = pdFALSE;
+
+ /* Initialize the queue list, if needed. */
+ prvInitializeQueueList();
+
+ /* Lock the mutex that guards access to the queue list. This call will
+ * never fail because it blocks forever. */
+ ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
+
+ /* Attempt to find the message queue based on the given descriptor. */
+ if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )
+ {
+ /* Decrement the number of open descriptors. */
+ if( pxMessageQueue->xOpenDescriptors > 0 )
+ {
+ pxMessageQueue->xOpenDescriptors--;
+ }
+
+ /* Check if the queue has any more open descriptors. */
+ if( pxMessageQueue->xOpenDescriptors == 0 )
+ {
+ /* If no open descriptors remain and mq_unlink has already been called,
+ * remove the queue. */
+ if( pxMessageQueue->xPendingUnlink == pdTRUE )
+ {
+ listREMOVE( &pxMessageQueue->xLink );
+
+ /* Set the flag to delete the queue. Deleting the queue is deferred
+ * until xQueueListMutex is released. */
+ xQueueRemoved = pdTRUE;
+ }
+ /* Otherwise, wait for the call to mq_unlink. */
+ else
+ {
+ pxMessageQueue->xPendingUnlink = pdTRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Queue not found; bad descriptor. */
+ errno = EBADF;
+ iStatus = -1;
+ }
+
+ /* Release the mutex protecting the queue list. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
+
+ /* Delete all resources used by the queue if needed. */
+ if( xQueueRemoved == pdTRUE )
+ {
+ prvDeleteMessageQueue( pxMessageQueue );
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int mq_getattr( mqd_t mqdes,
+ struct mq_attr * mqstat )
+{
+ int iStatus = 0;
+ QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
+
+ /* Lock the mutex that guards access to the queue list. This call will
+ * never fail because it blocks forever. */
+ ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
+
+ /* Find the mq referenced by mqdes. */
+ if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )
+ {
+ /* Update the number of messages in the queue and copy the attributes
+ * into mqstat. */
+ pxMessageQueue->xAttr.mq_curmsgs = ( long ) uxQueueMessagesWaiting( pxMessageQueue->xQueue );
+ *mqstat = pxMessageQueue->xAttr;
+ }
+ else
+ {
+ /* Queue not found; bad descriptor. */
+ errno = EBADF;
+ iStatus = -1;
+ }
+
+ /* Release the mutex protecting the queue list. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+mqd_t mq_open( const char * name,
+ int oflag,
+ mode_t mode,
+ struct mq_attr * attr )
+{
+ mqd_t xMessageQueue = NULL;
+ size_t xNameLength = 0;
+
+ /* Default mq_attr. */
+ struct mq_attr xQueueCreationAttr =
+ {
+ .mq_flags = 0,
+ .mq_maxmsg = posixconfigMQ_MAX_MESSAGES,
+ .mq_msgsize = posixconfigMQ_MAX_SIZE,
+ .mq_curmsgs = 0
+ };
+
+ /* Silence warnings about unused parameters. */
+ ( void ) mode;
+
+ /* Initialize the queue list, if needed. */
+ prvInitializeQueueList();
+
+ /* Check queue name. */
+ if( prvValidateQueueName( name, &xNameLength ) == pdFALSE )
+ {
+ /* Invalid name. */
+ errno = EINVAL;
+ xMessageQueue = ( mqd_t ) -1;
+ }
+
+ /* Check attributes, if given. */
+ if( xMessageQueue == NULL )
+ {
+ if( ( oflag & O_CREAT ) && ( attr != NULL ) && ( ( attr->mq_maxmsg <= 0 ) || ( attr->mq_msgsize <= 0 ) ) )
+ {
+ /* Invalid mq_attr.mq_maxmsg or mq_attr.mq_msgsize. */
+ errno = EINVAL;
+ xMessageQueue = ( mqd_t ) -1;
+ }
+ }
+
+ if( xMessageQueue == NULL )
+ {
+ /* Lock the mutex that guards access to the queue list. This call will
+ * never fail because it blocks forever. */
+ ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
+
+ /* Search the queue list to check if the queue exists. */
+ if( prvFindQueueInList( ( QueueListElement_t ** ) &xMessageQueue,
+ name,
+ ( mqd_t ) NULL ) == pdTRUE )
+ {
+ /* If the mq exists, check that this function wasn't called with
+ * O_CREAT and O_EXCL. */
+ if( ( oflag & O_EXCL ) && ( oflag & O_CREAT ) )
+ {
+ errno = EEXIST;
+ xMessageQueue = ( mqd_t ) -1;
+ }
+ else
+ {
+ /* Check if the mq has been unlinked and is pending removal. */
+ if( ( ( QueueListElement_t * ) xMessageQueue )->xPendingUnlink == pdTRUE )
+ {
+ /* Queue pending deletion. Don't allow it to be re-opened. */
+ errno = EINVAL;
+ xMessageQueue = ( mqd_t ) -1;
+ }
+ else
+ {
+ /* Increase count of open file descriptors for queue. */
+ ( ( QueueListElement_t * ) xMessageQueue )->xOpenDescriptors++;
+ }
+ }
+ }
+ /* Queue does not exist. */
+ else
+ {
+ /* Only create the new queue if O_CREAT was specified. */
+ if( oflag & O_CREAT )
+ {
+ /* Copy attributes if provided. */
+ if( attr != NULL )
+ {
+ xQueueCreationAttr = *attr;
+ }
+
+ /* Copy oflags. */
+ xQueueCreationAttr.mq_flags = ( long ) oflag;
+
+ /* Create the new message queue. */
+ if( prvCreateNewMessageQueue( ( QueueListElement_t ** ) &xMessageQueue,
+ &xQueueCreationAttr,
+ name,
+ xNameLength ) == pdFALSE )
+ {
+ errno = ENOSPC;
+ xMessageQueue = ( mqd_t ) -1;
+ }
+ }
+ else
+ {
+ errno = ENOENT;
+ xMessageQueue = ( mqd_t ) -1;
+ }
+ }
+
+ /* Release the mutex protecting the queue list. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
+ }
+
+ return xMessageQueue;
+}
+
+/*-----------------------------------------------------------*/
+
+ssize_t mq_receive( mqd_t mqdes,
+ char * msg_ptr,
+ size_t msg_len,
+ unsigned int * msg_prio )
+{
+ return mq_timedreceive( mqdes, msg_ptr, msg_len, msg_prio, NULL );
+}
+
+/*-----------------------------------------------------------*/
+
+int mq_send( mqd_t mqdes,
+ const char * msg_ptr,
+ size_t msg_len,
+ unsigned msg_prio )
+{
+ return mq_timedsend( mqdes, msg_ptr, msg_len, msg_prio, NULL );
+}
+
+/*-----------------------------------------------------------*/
+
+ssize_t mq_timedreceive( mqd_t mqdes,
+ char * msg_ptr,
+ size_t msg_len,
+ unsigned * msg_prio,
+ const struct timespec * abstime )
+{
+ ssize_t xStatus = 0;
+ int iCalculateTimeoutReturn = 0;
+ TickType_t xTimeoutTicks = 0;
+ QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
+ QueueElement_t xReceiveData = { 0 };
+
+ /* Silence warnings about unused parameters. */
+ ( void ) msg_prio;
+
+ /* Lock the mutex that guards access to the queue list. This call will
+ * never fail because it blocks forever. */
+ ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
+
+ /* Find the mq referenced by mqdes. */
+ if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )
+ {
+ /* Queue not found; bad descriptor. */
+ errno = EBADF;
+ xStatus = -1;
+ }
+
+ /* Verify that msg_len is large enough. */
+ if( xStatus == 0 )
+ {
+ if( msg_len < ( size_t ) pxMessageQueue->xAttr.mq_msgsize )
+ {
+ /* msg_len too small. */
+ errno = EMSGSIZE;
+ xStatus = -1;
+ }
+ }
+
+ if( xStatus == 0 )
+ {
+ /* Convert abstime to a tick timeout. */
+ iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,
+ abstime,
+ &xTimeoutTicks );
+
+ if( iCalculateTimeoutReturn != 0 )
+ {
+ errno = iCalculateTimeoutReturn;
+ xStatus = -1;
+ }
+ }
+
+ /* Release the mutex protecting the queue list. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
+
+ if( xStatus == 0 )
+ {
+ /* Receive data from the FreeRTOS queue. */
+ if( xQueueReceive( pxMessageQueue->xQueue,
+ &xReceiveData,
+ xTimeoutTicks ) == pdFALSE )
+ {
+ /* If queue receive fails, set the appropriate errno. */
+ if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )
+ {
+ /* Set errno to EAGAIN for nonblocking mq. */
+ errno = EAGAIN;
+ }
+ else
+ {
+ /* Otherwise, set errno to ETIMEDOUT. */
+ errno = ETIMEDOUT;
+ }
+
+ xStatus = -1;
+ }
+ }
+
+ if( xStatus == 0 )
+ {
+ /* Get the length of data for return value. */
+ xStatus = ( ssize_t ) xReceiveData.xDataSize;
+
+ /* Copy received data into given buffer, then free it. */
+ ( void ) memcpy( msg_ptr, xReceiveData.pcData, xReceiveData.xDataSize );
+ vPortFree( xReceiveData.pcData );
+ }
+
+ return xStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int mq_timedsend( mqd_t mqdes,
+ const char * msg_ptr,
+ size_t msg_len,
+ unsigned int msg_prio,
+ const struct timespec * abstime )
+{
+ int iStatus = 0, iCalculateTimeoutReturn = 0;
+ TickType_t xTimeoutTicks = 0;
+ QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
+ QueueElement_t xSendData = { 0 };
+
+ /* Silence warnings about unused parameters. */
+ ( void ) msg_prio;
+
+ /* Lock the mutex that guards access to the queue list. This call will
+ * never fail because it blocks forever. */
+ ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
+
+ /* Find the mq referenced by mqdes. */
+ if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )
+ {
+ /* Queue not found; bad descriptor. */
+ errno = EBADF;
+ iStatus = -1;
+ }
+
+ /* Verify that mq_msgsize is large enough. */
+ if( iStatus == 0 )
+ {
+ if( msg_len > ( size_t ) pxMessageQueue->xAttr.mq_msgsize )
+ {
+ /* msg_len too large. */
+ errno = EMSGSIZE;
+ iStatus = -1;
+ }
+ }
+
+ if( iStatus == 0 )
+ {
+ /* Convert abstime to a tick timeout. */
+ iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,
+ abstime,
+ &xTimeoutTicks );
+
+ if( iCalculateTimeoutReturn != 0 )
+ {
+ errno = iCalculateTimeoutReturn;
+ iStatus = -1;
+ }
+ }
+
+ /* Release the mutex protecting the queue list. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
+
+ /* Allocate memory for the message. */
+ if( iStatus == 0 )
+ {
+ xSendData.xDataSize = msg_len;
+ xSendData.pcData = pvPortMalloc( msg_len );
+
+ /* Check that memory allocation succeeded. */
+ if( xSendData.pcData == NULL )
+ {
+ /* msg_len too large. */
+ errno = EMSGSIZE;
+ iStatus = -1;
+ }
+ else
+ {
+ /* Copy the data to send. */
+ ( void ) memcpy( xSendData.pcData, msg_ptr, msg_len );
+ }
+ }
+
+ if( iStatus == 0 )
+ {
+ /* Send data to the FreeRTOS queue. */
+ if( xQueueSend( pxMessageQueue->xQueue,
+ &xSendData,
+ xTimeoutTicks ) == pdFALSE )
+ {
+ /* If queue send fails, set the appropriate errno. */
+ if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )
+ {
+ /* Set errno to EAGAIN for nonblocking mq. */
+ errno = EAGAIN;
+ }
+ else
+ {
+ /* Otherwise, set errno to ETIMEDOUT. */
+ errno = ETIMEDOUT;
+ }
+
+ /* Free the allocated queue data. */
+ vPortFree( xSendData.pcData );
+
+ iStatus = -1;
+ }
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int mq_unlink( const char * name )
+{
+ int iStatus = 0;
+ size_t xNameSize = 0;
+ BaseType_t xQueueRemoved = pdFALSE;
+ QueueListElement_t * pxMessageQueue = NULL;
+
+ /* Initialize the queue list, if needed. */
+ prvInitializeQueueList();
+
+ /* Check queue name. */
+ if( prvValidateQueueName( name, &xNameSize ) == pdFALSE )
+ {
+ /* Error with mq name. */
+ errno = EINVAL;
+ iStatus = -1;
+ }
+
+ if( iStatus == 0 )
+ {
+ /* Lock the mutex that guards access to the queue list. This call will
+ * never fail because it blocks forever. */
+ ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
+
+ /* Check if the named queue exists. */
+ if( prvFindQueueInList( &pxMessageQueue, name, ( mqd_t ) NULL ) == pdTRUE )
+ {
+ /* If the queue exists and there are no open descriptors to it,
+ * remove it from the list. */
+ if( pxMessageQueue->xOpenDescriptors == 0 )
+ {
+ listREMOVE( &pxMessageQueue->xLink );
+
+ /* Set the flag to delete the queue. Deleting the queue is deferred
+ * until xQueueListMutex is released. */
+ xQueueRemoved = pdTRUE;
+ }
+ else
+ {
+ /* If the queue has open descriptors, set the pending unlink flag
+ * so that mq_close will free its resources. */
+ pxMessageQueue->xPendingUnlink = pdTRUE;
+ }
+ }
+ else
+ {
+ /* The named message queue doesn't exist. */
+ errno = ENOENT;
+ iStatus = -1;
+ }
+
+ /* Release the mutex protecting the queue list. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
+ }
+
+ /* Delete all resources used by the queue if needed. */
+ if( xQueueRemoved == pdTRUE )
+ {
+ prvDeleteMessageQueue( pxMessageQueue );
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/