diff options
author | RichardBarry <RichardBarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2> | 2007-08-21 16:54:48 +0000 |
---|---|---|
committer | RichardBarry <RichardBarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2> | 2007-08-21 16:54:48 +0000 |
commit | d6b42adcfaa281263ea764ff0e40b72b214df713 (patch) | |
tree | 557c141649e16996fd7fdb259b31750528fc589a /Source | |
parent | 42eff320125c5a3ef576fb91d2af2071e07f847c (diff) | |
download | freertos-d6b42adcfaa281263ea764ff0e40b72b214df713.tar.gz |
Added xQueueSendToBack, xQueueSendToFront, xQueuePeek and xSemaphoreCreateMutex - along with GenQTest.c to demonstrate their usage.
git-svn-id: http://svn.code.sf.net/p/freertos/code/trunk@103 1d2547de-c912-0410-9cb9-b8ca96c0e9e2
Diffstat (limited to 'Source')
-rw-r--r-- | Source/include/FreeRTOS.h | 27 | ||||
-rw-r--r-- | Source/include/queue.h | 816 | ||||
-rw-r--r-- | Source/include/semphr.h | 60 | ||||
-rw-r--r-- | Source/include/task.h | 22 | ||||
-rw-r--r-- | Source/portable/Paradigm/Tern_EE/large_untested/portasm.h | 26 | ||||
-rw-r--r-- | Source/queue.c | 259 | ||||
-rw-r--r-- | Source/tasks.c | 157 |
7 files changed, 1189 insertions, 178 deletions
diff --git a/Source/include/FreeRTOS.h b/Source/include/FreeRTOS.h index 11ca53f62..3c02e6c6f 100644 --- a/Source/include/FreeRTOS.h +++ b/Source/include/FreeRTOS.h @@ -19,13 +19,13 @@ A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
- the source code for any proprietary components. See the licensing section
+ the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
***************************************************************************
- See http://www.FreeRTOS.org for documentation, latest information, license
- and contact details. Please ensure to read the configuration and relevant
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
@@ -37,8 +37,8 @@ #define INC_FREERTOS_H
-/*
- * Include the generic headers required for the FreeRTOS port being used.
+/*
+ * Include the generic headers required for the FreeRTOS port being used.
*/
#include <stddef.h>
@@ -58,7 +58,7 @@ /*
- * Check all the required application specific macros have been defined.
+ * Check all the required application specific macros have been defined.
* These macros are application specific and (as downloaded) are defined
* within FreeRTOSConfig.h.
*/
@@ -111,4 +111,19 @@ #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
+#ifndef configUSE_MUTEXES
+ #define configUSE_MUTEXES 0
+#endif
+
+#if ( configUSE_MUTEXES == 1 )
+ /* xTaskGetCurrentTaskHandle is used by the priority inheritance mechanism
+ within the mutex implementation so must be available if mutexes are used. */
+ #undef INCLUDE_xTaskGetCurrentTaskHandle
+ #define INCLUDE_xTaskGetCurrentTaskHandle 1
+#else
+ #ifndef INCLUDE_xTaskGetCurrentTaskHandle
+ #define INCLUDE_xTaskGetCurrentTaskHandle 0
+ #endif
#endif
+
+#endif /* INC_FREERTOS_H */
diff --git a/Source/include/queue.h b/Source/include/queue.h index 6ded97871..c9d448989 100644 --- a/Source/include/queue.h +++ b/Source/include/queue.h @@ -19,13 +19,13 @@ A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
- the source code for any proprietary components. See the licensing section
+ the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
***************************************************************************
- See http://www.FreeRTOS.org for documentation, latest information, license
- and contact details. Please ensure to read the configuration and relevant
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
@@ -38,12 +38,17 @@ typedef void * xQueueHandle;
+/* For internal use only. */
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+
+
/**
* queue. h
* <pre>
- xQueueHandle xQueueCreate(
- unsigned portBASE_TYPE uxQueueLength,
- unsigned portBASE_TYPE uxItemSize
+ xQueueHandle xQueueCreate(
+ unsigned portBASE_TYPE uxQueueLength,
+ unsigned portBASE_TYPE uxItemSize
);
* </pre>
*
@@ -52,15 +57,15 @@ typedef void * xQueueHandle; *
* @param uxQueueLength The maximum number of items that the queue can contain.
*
- * @param uxItemSize The number of bytes each item in the queue will require.
+ * @param uxItemSize The number of bytes each item in the queue will require.
* Items are queued by copy, not by reference, so this is the number of bytes
* that will be copied for each posted item. Each item on the queue must be
* the same size.
*
- * @return If the queue is successfully create then a handle to the newly
+ * @return If the queue is successfully create then a handle to the newly
* created queue is returned. If the queue cannot be created then 0 is
* returned.
- *
+ *
* Example usage:
<pre>
struct AMessage
@@ -99,20 +104,189 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA /**
* queue. h
* <pre>
- portBASE_TYPE xQueueSend(
- xQueueHandle xQueue,
- const void * pvItemToQueue,
- portTickType xTicksToWait
+ portBASE_TYPE xQueueSendToToFront(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ * </pre>
+ *
+ * This is a macro that calls xQueueGenericSend().
+ *
+ * Post an item to the front of a queue. The item is queued by copy, not by
+ * reference. This function must not be called from an interrupt service
+ * routine. See xQueueSendFromISR () for an alternative which may be used
+ * in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0. The
+ * time is defined in tick periods so the constant portTICK_RATE_MS
+ * should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_FRONT )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendToBack(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ * </pre>
+ *
+ * This is a macro that calls xQueueGenericSend().
+ *
+ * Post an item to the back of a queue. The item is queued by copy, not by
+ * reference. This function must not be called from an interrupt service
+ * routine. See xQueueSendFromISR () for an alternative which may be used
+ * in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0. The
+ * time is defined in tick periods so the constant portTICK_RATE_MS
+ * should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
);
* </pre>
*
+ * This is a macro that calls xQueueGenericSend(). It is included for
+ * backward compatibility with versions of FreeRTOS.org that did not
+ * include the xQueueSendToFront() and xQueueSendToBack() macros. It is
+ * equivalent to xQueueSendToBack().
+ *
* Post an item on a queue. The item is queued by copy, not by reference.
* This function must not be called from an interrupt service routine.
* See xQueueSendFromISR () for an alternative which may be used in an ISR.
*
* @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
@@ -120,7 +294,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * @param xTicksToWait The maximum amount of time the task should block
* waiting for space to become available on the queue, should it already
* be full. The call will return immediately if this is set to 0. The
- * time is defined in tick periods so the constant portTICK_RATE_MS
+ * time is defined in tick periods so the constant portTICK_RATE_MS
* should be used to convert to real time if this is required.
*
* @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
@@ -151,7 +325,7 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA if( xQueue1 != 0 )
{
- // Send an unsigned long. Wait for 10 ticks for space to become
+ // Send an unsigned long. Wait for 10 ticks for space to become
// available if necessary.
if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
{
@@ -173,21 +347,205 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * \defgroup xQueueSend xQueueSend
* \ingroup QueueManagement
*/
-signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
+#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK )
+
/**
* queue. h
* <pre>
- portBASE_TYPE xQueueReceive(
- xQueueHandle xQueue,
- void *pvBuffer,
- portTickType xTicksToWait
+ portBASE_TYPE xQueueGenericSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ portBASE_TYPE xCopyPosition
+ );
+ * </pre>
+ *
+ * It is preferred that the macros xQueueSend(), xQueueSendToFront() and
+ * xQueueSendToBack() are used in place of calling this function directly.
+ *
+ * Post an item on a queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueSendFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0. The
+ * time is defined in tick periods so the constant portTICK_RATE_MS
+ * should be used to convert to real time if this is required.
+ *
+ * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
+ * item at the back of the queue, or queueSEND_TO_FRONT to place the item
+ * at the front of the queue (for high priority messages).
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portTickType xCopyPosition );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueuePeek(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ );</pre>
+ *
+ * This is a macro that calls the xQueueGenericReceive() function.
+ *
+ * Receive an item from a queue without removing the item from the queue.
+ * The item is received by copy so a buffer of adequate size must be
+ * provided. The number of bytes copied into the buffer was defined when
+ * the queue was created.
+ *
+ * Successfully received items remain on the queue so will be returned again
+ * by the next call, or a call to xQueueReceive().
+ *
+ * This macro must not be used in an interrupt service routine.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Peek a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask, but the item still remains on the queue.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
);</pre>
*
- * Receive an item from a queue. The item is received by copy so a buffer of
+ * This is a macro that calls the xQueueGenericReceive() function.
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
* adequate size must be provided. The number of bytes copied into the buffer
* was defined when the queue was created.
*
+ * Successfully received items are removed from the queue.
+ *
* This function must not be used in an interrupt service routine. See
* xQueueReceiveFromISR for an alternative that can.
*
@@ -196,10 +554,10 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue *
* @param pvBuffer Pointer to the buffer into which the received item will
* be copied.
- *
+ *
* @param xTicksToWait The maximum amount of time the task should block
* waiting for an item to receive should the queue be empty at the time
- * of the call. The time is defined in tick periods so the constant
+ * of the call. The time is defined in tick periods so the constant
* portTICK_RATE_MS should be used to convert to real time if this is required.
*
* @return pdTRUE if an item was successfully received from the queue,
@@ -214,7 +572,7 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue } xMessage;
xQueueHandle xQueue;
-
+
// Task to create a queue and post a value.
void vATask( void *pvParameters )
{
@@ -260,7 +618,104 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue * \defgroup xQueueReceive xQueueReceive
* \ingroup QueueManagement
*/
-signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait );
+#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE )
+
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueGenericReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ portBASE_TYPE xJustPeek
+ );</pre>
+ *
+ * It is preferred that the macro xQueueReceive() be used rather than calling
+ * this function directly.
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
+ * adequate size must be provided. The number of bytes copied into the buffer
+ * was defined when the queue was created.
+ *
+ * This function must not be used in an interrupt service routine. See
+ * xQueueReceiveFromISR for an alternative that can.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @param xJustPeek When set to true, the item received from the queue is not
+ * actually removed from the queue - meaning a subsequent call to
+ * xQueueReceive() will return the same item. When set to false, the item
+ * being received from the queue is also removed from the queue.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Receive a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek );
/**
* queue. h
@@ -269,7 +724,7 @@ signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTic * Return the number of messages stored in a queue.
*
* @param xQueue A handle to the queue being queried.
- *
+ *
* @return The number of messages available in the queue.
*
* \page uxQueueMessagesWaiting uxQueueMessagesWaiting
@@ -283,7 +738,7 @@ unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue ); *
* Delete a queue - freeing all the memory allocated for storing of items
* placed on the queue.
- *
+ *
* @param xQueue A handle to the queue to be deleted.
*
* \page vQueueDelete vQueueDelete
@@ -294,13 +749,254 @@ void vQueueDelete( xQueueHandle xQueue ); /**
* queue. h
* <pre>
- portBASE_TYPE xQueueSendFromISR(
- xQueueHandle pxQueue,
- const void *pvItemToQueue,
- portBASE_TYPE xTaskPreviouslyWoken
+ portBASE_TYPE xQueueSendToFrontFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE xTaskPreviouslyWoken
+ );
+ </pre>
+ *
+ * This is a macro that calls xQueueGenericSendFromISR().
+ *
+ * Post an item to the front of a queue. It is safe to use this macro from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param cTaskPreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call. See the file serial .c in the
+ * PC port for a good example of this mechanism.
+ *
+ * @return pdTRUE if a task was woken by posting onto the queue. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+ // We have not woken a task at the start of the ISR.
+ cTaskWokenByPost = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte. The first time round the loop cTaskWokenByPost
+ // will be pdFALSE. If the queue send causes a task to wake we do
+ // not want the task to run until we have finished the ISR, so
+ // xQueueSendFromISR does not cause a context switch. Also we
+ // don't want subsequent posts to wake any other tasks, so we store
+ // the return value back into cTaskWokenByPost so xQueueSendFromISR
+ // knows not to wake any task the next iteration of the loop.
+ xTaskWokenByPost = xQueueSendToFrontFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( cTaskWokenByPost )
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToFromFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken, queueSEND_TO_FRONT )
+
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendToBackFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE xTaskPreviouslyWoken
+ );
+ </pre>
+ *
+ * This is a macro that calls xQueueGenericSendFromISR().
+ *
+ * Post an item to the back of a queue. It is safe to use this macro from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param cTaskPreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call. See the file serial .c in the
+ * PC port for a good example of this mechanism.
+ *
+ * @return pdTRUE if a task was woken by posting onto the queue. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+ // We have not woken a task at the start of the ISR.
+ cTaskWokenByPost = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte. The first time round the loop cTaskWokenByPost
+ // will be pdFALSE. If the queue send causes a task to wake we do
+ // not want the task to run until we have finished the ISR, so
+ // xQueueSendFromISR does not cause a context switch. Also we
+ // don't want subsequent posts to wake any other tasks, so we store
+ // the return value back into cTaskWokenByPost so xQueueSendFromISR
+ // knows not to wake any task the next iteration of the loop.
+ xTaskWokenByPost = xQueueSendToBackFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( cTaskWokenByPost )
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken, queueSEND_TO_BACK )
+
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE xTaskPreviouslyWoken
);
</pre>
*
+ * This is a macro that calls xQueueGenericSendFromISR(). It is included
+ * for backward compatibility with versions of FreeRTOS.org that did not
+ * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR()
+ * macros.
+ *
+ * Post an item to the back of a queue. It is safe to use this function from
+ * within an interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param cTaskPreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call. See the file serial .c in the
+ * PC port for a good example of this mechanism.
+ *
+ * @return pdTRUE if a task was woken by posting onto the queue. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+ // We have not woken a task at the start of the ISR.
+ cTaskWokenByPost = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte. The first time round the loop cTaskWokenByPost
+ // will be pdFALSE. If the queue send causes a task to wake we do
+ // not want the task to run until we have finished the ISR, so
+ // xQueueSendFromISR does not cause a context switch. Also we
+ // don't want subsequent posts to wake any other tasks, so we store
+ // the return value back into cTaskWokenByPost so xQueueSendFromISR
+ // knows not to wake any task the next iteration of the loop.
+ xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( cTaskWokenByPost )
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+#define xQueueSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken, queueSEND_TO_BACK )
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueGenericSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE xTaskPreviouslyWoken
+ portBASE_TYPE xCopyPosition
+ );
+ </pre>
+ *
+ * It is preferred that the macros xQueueSendFromISR(),
+ * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place
+ * of calling this function directly.
+ *
* Post an item on a queue. It is safe to use this function from within an
* interrupt service routine.
*
@@ -309,8 +1005,8 @@ void vQueueDelete( xQueueHandle xQueue ); * it would be preferable to store a pointer to the item being queued.
*
* @param xQueue The handle to the queue on which the item is to be posted.
- *
- * @param pvItemToQueue A pointer to the item that is to be placed on the
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
@@ -321,7 +1017,11 @@ void vQueueDelete( xQueueHandle xQueue ); * the value returned from the previous call. See the file serial .c in the
* PC port for a good example of this mechanism.
*
- * @return pdTRUE if a task was woken by posting onto the queue. This is
+ * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the
+ * item at the back of the queue, or queueSEND_TO_FRONT to place the item
+ * at the front of the queue (for high priority messages).
+ *
+ * @return pdTRUE if a task was woken by posting onto the queue. This is
* used by the ISR to determine if a context switch may be required following
* the ISR.
*
@@ -345,11 +1045,11 @@ void vQueueDelete( xQueueHandle xQueue ); // Post the byte. The first time round the loop cTaskWokenByPost
// will be pdFALSE. If the queue send causes a task to wake we do
// not want the task to run until we have finished the ISR, so
- // xQueueSendFromISR does not cause a context switch. Also we
+ // xQueueSendFromISR does not cause a context switch. Also we
// don't want subsequent posts to wake any other tasks, so we store
// the return value back into cTaskWokenByPost so xQueueSendFromISR
// knows not to wake any task the next iteration of the loop.
- xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+ xTaskWokenByPost = xQueueGenericSendFromISR( xRxQueue, &cIn, cTaskWokenByPost, queueSEND_TO_BACK );
} while( portINPUT_BYTE( BUFFER_COUNT ) );
@@ -364,16 +1064,16 @@ void vQueueDelete( xQueueHandle xQueue ); * \defgroup xQueueSendFromISR xQueueSendFromISR
* \ingroup QueueManagement
*/
-signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition );
/**
* queue. h
* <pre>
- portBASE_TYPE xQueueReceiveFromISR(
- xQueueHandle pxQueue,
- void *pvBuffer,
- portBASE_TYPE *pxTaskWoken
- );
+ portBASE_TYPE xQueueReceiveFromISR(
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portBASE_TYPE *pxTaskWoken
+ );
* </pre>
*
* Receive an item from a queue. It is safe to use this function from within an
@@ -384,7 +1084,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem *
* @param pvBuffer Pointer to the buffer into which the received item will
* be copied.
- *
+ *
* @param pxTaskWoken A task may be blocked waiting for space to become
* available on the queue. If xQueueReceiveFromISR causes such a task to
* unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will
@@ -395,9 +1095,9 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem *
* Example usage:
<pre>
-
+
xQueueHandle xQueue;
-
+
// Function to create a queue and post some values.
void vAFunction( void *pvParameters )
{
@@ -427,7 +1127,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
}
- // ISR that outputs all the characters received on the queue.
+ // ISR that outputs all the characters received on the queue.
void vISR_Routine( void )
{
portBASE_TYPE xTaskWokenByReceive = pdFALSE;
@@ -438,7 +1138,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem // A character was received. Output the character now.
vOutputCharacter( cRxedChar );
- // If removing the character from the queue woke the task that was
+ // If removing the character from the queue woke the task that was
// posting onto the queue cTaskWokenByReceive will have been set to
// pdTRUE. No matter how many times this loop iterates only one
// task will be woken.
@@ -453,13 +1153,13 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
* \ingroup QueueManagement
*/
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
-/*
- * The functions defined above are for passing data to and from tasks. The
- * functions below are the equivalents for passing data to and from
- * co-rtoutines.
+/*
+ * The functions defined above are for passing data to and from tasks. The
+ * functions below are the equivalents for passing data to and from
+ * co-routines.
*
* These functions are called from the co-routine macro implementation and
* should not be called directly from application code. Instead use the macro
@@ -470,5 +1170,11 @@ signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffe signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
-#endif
+/*
+ * For internal use only. Use xSemaphoreCreateMutex() instead of calling
+ * this function directly.
+ */
+xQueueHandle xQueueCreateMutex( void );
+
+#endif /* QUEUE_H */
diff --git a/Source/include/semphr.h b/Source/include/semphr.h index 266ad1ae9..18bbb444d 100644 --- a/Source/include/semphr.h +++ b/Source/include/semphr.h @@ -54,6 +54,13 @@ typedef xQueueHandle xSemaphoreHandle; * as we don't want to actually store any data - we just want to know if the
* queue is empty or full.
*
+ * This type of semaphore can be used for pure synchronisation between tasks or
+ * between an interrupt and a task. The semaphore need not be given back once
+ * obtained, so one task/interrupt can continuously 'give' the semaphore while
+ * another continuously 'takes' the semaphore. For this reason this type of
+ * semaphore does not use a priority inheritance mechanism. For an alternative
+ * that does use priority inheritance see xSemaphoreCreateMutex().
+ *
* @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.
*
* Example usage:
@@ -205,7 +212,7 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreGive xSemaphoreGive
* \ingroup Semaphores
*/
-#define xSemaphoreGive( xSemaphore ) xQueueSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME )
+#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
/**
* semphr. h
@@ -218,6 +225,9 @@ typedef xQueueHandle xSemaphoreHandle; * <i>Macro</i> to release a semaphore. The semaphore must of been created using
* vSemaphoreCreateBinary (), and obtained using xSemaphoreTake ().
*
+ * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
+ * must not be used with this macro.
+ *
* This macro can be used from an ISR.
*
* @param xSemaphore A handle to the semaphore being released. This is the
@@ -285,8 +295,52 @@ typedef xQueueHandle xSemaphoreHandle; * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
* \ingroup Semaphores
*/
-#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken ) xQueueSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken )
+#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken, queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreCreateMutex( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> that implements a mutex semaphore by using the existing queue
+ * mechanism.
+ *
+ * This type of semaphore uses a priority inheritance mechanism so a task
+ * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
+ * semaphore it is no longer required.
+ *
+ * Mutex type semaphores cannot be used from within interrupt service routines.
+ *
+ * See xSemaphoreCreateBinary() for an alternative implemnetation that can be
+ * used for pure synchronisation (where one task or interrupt always 'gives' the
+ * semaphore and another always 'takes' the semaphore) and from within interrupt
+ * service routines.
+ *
+ * @param xSemaphore Handle to the created mutex semaphore. Should be of type
+ * xSemaphoreHandle.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+ // This is a macro so pass the variable in directly.
+ vSemaphoreCreateMutex( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+ </pre>
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
+ * \ingroup Semaphores
+ */
+#define xSemaphoreCreateMutex() xQueueCreateMutex()
+
+#endif /* SEMAPHORE_H */
-#endif
diff --git a/Source/include/task.h b/Source/include/task.h index 7a4d1095b..6535fc8b3 100644 --- a/Source/include/task.h +++ b/Source/include/task.h @@ -364,7 +364,7 @@ void vTaskDelay( portTickType xTicksToDelay ); * \defgroup vTaskDelayUntil vTaskDelayUntil
* \ingroup TaskCtrl
*/
-void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
+void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement );
/**
* task. h
@@ -894,7 +894,7 @@ inline void vTaskIncrementTick( void ); * portTICK_RATE_MS can be used to convert kernel ticks into a real time
* period.
*/
-void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait );
+void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait );
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
@@ -911,7 +911,7 @@ void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait ); * @return pdTRUE if the task being removed has a higher priority than the task
* making the call, otherwise pdFALSE.
*/
-signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList );
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList );
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
@@ -944,13 +944,13 @@ xTaskHandle xTaskGetCurrentTaskHandle( void ); /*
* Capture the current time status for future reference.
*/
-void vTaskSetTimeOutState( xTimeOutType *pxTimeOut );
+void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut );
/*
* Compare the time status now with that previously captured to see if the
* timeout has expired.
*/
-portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait );
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait );
/*
* Shortcut used by the queue implementation to prevent unnecessary call to
@@ -964,6 +964,18 @@ void vTaskMissedYield( void ); */
portBASE_TYPE xTaskGetSchedulerState( void );
+/*
+ * Raises the priority of the mutex holder to that of the calling task should
+ * the mutex holder have a priority less than the calling task.
+ */
+void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder );
+
+/*
+ * Set the priority of a task back to its proper priority in the case that it
+ * inherited a higher priority while it was holding a semaphore.
+ */
+void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder );
+
#endif /* TASK_H */
diff --git a/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h b/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h index 51e80a3e7..1fbcc85b4 100644 --- a/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h +++ b/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h @@ -51,18 +51,18 @@ void portSWITCH_CONTEXT( void ); */
void portFIRST_CONTEXT( void );
-#define portSWITCH_CONTEXT()
-// asm { mov ax, seg pxCurrentTCB }
-// asm { mov ds, ax }
-// asm { les bx, pxCurrentTCB } /* Save the stack pointer into the TCB. */
-// asm { mov es:0x2[ bx ], ss }
-// asm { mov es:[ bx ], sp }
-// asm { call far ptr vTaskSwitchContext } /* Perform the switch. */
-// asm { mov ax, seg pxCurrentTCB } /* Restore the stack pointer from the TCB. */
-// asm { mov ds, ax }
-// asm { les bx, dword ptr pxCurrentTCB }
-// asm { mov ss, es:[ bx + 2 ] }
-// asm { mov sp, es:[ bx ] }
+#define portSWITCH_CONTEXT() \
+ asm { mov ax, seg pxCurrentTCB } \
+ asm { mov ds, ax } \
+ asm { les bx, pxCurrentTCB } /* Save the stack pointer into the TCB. */ \
+ asm { mov es:0x2[ bx ], ss } \
+ asm { mov es:[ bx ], sp } \
+ asm { call far ptr vTaskSwitchContext } /* Perform the switch. */ \
+ asm { mov ax, seg pxCurrentTCB } /* Restore the stack pointer from the TCB. */ \
+ asm { mov ds, ax } \
+ asm { les bx, dword ptr pxCurrentTCB } \
+ asm { mov ss, es:[ bx + 2 ] } \
+ asm { mov sp, es:[ bx ] }
#define portFIRST_CONTEXT() \
asm { mov ax, seg pxCurrentTCB } \
@@ -70,7 +70,7 @@ void portFIRST_CONTEXT( void ); asm { les bx, dword ptr pxCurrentTCB } \
asm { mov ss, es:[ bx + 2 ] } \
asm { mov sp, es:[ bx ] } \
- asm { pop bx } \
+ asm { pop bp } \
asm { pop di } \
asm { pop si } \
asm { pop ds } \
diff --git a/Source/queue.c b/Source/queue.c index 58d8ccde8..0431715df 100644 --- a/Source/queue.c +++ b/Source/queue.c @@ -70,9 +70,9 @@ Changes from V4.1.2: Changes from V4.1.3:
- + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely)
- case whereby a task unblocking due to a temporal event can remove/send an
- item from/to a queue when a higher priority task is still blocked on the
+ + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely)
+ case whereby a task unblocking due to a temporal event can remove/send an
+ item from/to a queue when a higher priority task is still blocked on the
queue. This modification is a result of the SafeRTOS testing.
*/
@@ -90,6 +90,15 @@ Changes from V4.1.3: #define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
#define queueERRONEOUS_UNBLOCK ( -1 )
+/* For internal use only. */
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+
+/* Effectively make a union out of the xQUEUE structure. */
+#define pxMutexHolder pcTail
+#define uxQueueType pcHead
+#define queueQUEUE_IS_MUTEX NULL
+
/*
* Definition of the queue used by the scheduler.
* Items are queued by copy, not reference.
@@ -109,8 +118,8 @@ typedef struct QueueDefinition unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
- signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
- signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+ signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+ signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
} xQUEUE;
/*-----------------------------------------------------------*/
@@ -127,12 +136,13 @@ typedef xQUEUE * xQueueHandle; * functions are documented in the API header file.
*/
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
-signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );
void vQueueDelete( xQueueHandle xQueue );
-signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
-signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition );
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+xQueueHandle xQueueCreateMutex( void );
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
@@ -166,20 +176,15 @@ static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ); static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
/*
- * Macro that copies an item into the queue. This is done by copying the item
- * byte for byte, not by reference. Updates the queue state to ensure it's
- * integrity after the copy.
+ * Copies an item into the queue, either at the front of the queue or the
+ * back of the queue.
*/
-#define prvCopyQueueData( pxQueue, pvItemToQueue ) \
-{ \
- memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); \
- ++( pxQueue->uxMessagesWaiting ); \
- pxQueue->pcWriteTo += pxQueue->uxItemSize; \
- if( pxQueue->pcWriteTo >= pxQueue->pcTail ) \
- { \
- pxQueue->pcWriteTo = pxQueue->pcHead; \
- } \
-}
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition );
+
+/*
+ * Copies an item out of a queue.
+ */
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer );
/*-----------------------------------------------------------*/
/*
@@ -248,7 +253,49 @@ size_t xQueueSizeInBytes; }
/*-----------------------------------------------------------*/
-signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
+#if ( configUSE_MUTEXES == 1 )
+
+ xQueueHandle xQueueCreateMutex( void )
+ {
+ xQUEUE *pxNewQueue;
+
+ /* Allocate the new queue structure. */
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
+ if( pxNewQueue != NULL )
+ {
+ /* Information required for priority inheritance. */
+ pxNewQueue->pxMutexHolder = NULL;
+ pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
+
+ /* Queues used as a mutex no data is actually copied into or out
+ of the queue. */
+ pxNewQueue->pcWriteTo = NULL;
+ pxNewQueue->pcReadFrom = NULL;
+
+ /* Each mutex has a length of 1 (like a binary semaphore) and
+ an item size of 0 as nothing is actually copied into or out
+ of the mutex. */
+ pxNewQueue->uxMessagesWaiting = 0;
+ pxNewQueue->uxLength = 1;
+ pxNewQueue->uxItemSize = 0;
+ pxNewQueue->xRxLock = queueUNLOCKED;
+ pxNewQueue->xTxLock = queueUNLOCKED;
+
+ /* Ensure the event queues start with the correct state. */
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
+
+ /* Start with the semaphore in the expected state. */
+ xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );
+ }
+
+ return pxNewQueue;
+ }
+
+#endif /* configUSE_MUTEXES */
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
{
signed portBASE_TYPE xReturn = pdPASS;
xTimeOutType xTimeOut;
@@ -285,15 +332,15 @@ xTimeOutType xTimeOut; queue being modified here. Places where the event list is modified
include:
- + xQueueSendFromISR(). This checks the lock on the queue to see if
- it has access. If the queue is locked then the Tx lock count is
+ + xQueueGenericSendFromISR(). This checks the lock on the queue to see
+ if it has access. If the queue is locked then the Tx lock count is
incremented to signify that a task waiting for data can be made ready
once the queue lock is removed. If the queue is not locked then
a task can be moved from the event list, but will not be removed
from the delayed list or placed in the ready list until the scheduler
is unlocked.
- + xQueueReceiveFromISR(). As per xQueueSendFromISR().
+ + xQueueReceiveFromISR(). As per xQueueGenericSendFromISR().
*/
/* If the queue is already full we may have to block. */
@@ -390,7 +437,7 @@ xTimeOutType xTimeOut; if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
- prvCopyQueueData( pxQueue, pvItemToQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
xReturn = pdPASS;
/* Update the TxLock count so prvUnlockQueue knows to check for
@@ -425,16 +472,16 @@ xTimeOutType xTimeOut; }
/*-----------------------------------------------------------*/
-signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )
{
- /* Similar to xQueueSend, except we don't block if there is no room in the
- queue. Also we don't directly wake a task that was blocked on a queue
- read, instead we return a flag to say whether a context switch is required
- or not (i.e. has a task with a higher priority than us been woken by this
- post). */
+ /* Similar to xQueueGenericSend, except we don't block if there is no room
+ in the queue. Also we don't directly wake a task that was blocked on a
+ queue read, instead we return a flag to say whether a context switch is
+ required or not (i.e. has a task with a higher priority than us been woken
+ by this post). */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
- prvCopyQueueData( pxQueue, pvItemToQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
/* If the queue is locked we do not alter the event list. This will
be done when the queue is unlocked later. */
@@ -467,13 +514,14 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem }
/*-----------------------------------------------------------*/
-signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
{
signed portBASE_TYPE xReturn = pdTRUE;
xTimeOutType xTimeOut;
+signed portCHAR *pcOriginalReadPosition;
- /* This function is very similar to xQueueSend(). See comments within
- xQueueSend() for a more detailed explanation.
+ /* This function is very similar to xQueueGenericSend(). See comments
+ within xQueueGenericSend() for a more detailed explanation.
Make sure other tasks do not access the queue. */
vTaskSuspendAll();
@@ -493,6 +541,17 @@ xTimeOutType xTimeOut; leave with nothing? */
if( xTicksToWait > ( portTickType ) 0 )
{
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ portENTER_CRITICAL();
+ vTaskPriorityInherit( ( xTaskHandle * const ) pxQueue->pxMutexHolder );
+ portEXIT_CRITICAL();
+ }
+ }
+ #endif
+
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
taskENTER_CRITICAL();
{
@@ -522,18 +581,39 @@ xTimeOutType xTimeOut; {
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
- pxQueue->pcReadFrom += pxQueue->uxItemSize;
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ /* Remember our read position in case we are just peeking. */
+ pcOriginalReadPosition = pxQueue->pcReadFrom;
+
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
+
+ if( xJustPeeking == pdFALSE )
{
- pxQueue->pcReadFrom = pxQueue->pcHead;
+ /* We are actually removing data. */
+ --( pxQueue->uxMessagesWaiting );
+
+ /* Increment the lock count so prvUnlockQueue knows to check for
+ tasks waiting for space to become available on the queue. */
+ ++( pxQueue->xRxLock );
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* Record the information required to implement
+ priority inheritance should it become necessary. */
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
+ }
+ }
+ #endif
}
- --( pxQueue->uxMessagesWaiting );
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
-
- /* Increment the lock count so prvUnlockQueue knows to check for
- tasks waiting for space to become available on the queue. */
- ++( pxQueue->xRxLock );
- xReturn = pdPASS;
+ else
+ {
+ /* We are not removing the data, so reset our read
+ pointer. */
+ pxQueue->pcReadFrom = pcOriginalReadPosition;
+ }
+
+ xReturn = pdPASS;
}
else
{
@@ -563,21 +643,15 @@ xTimeOutType xTimeOut; }
/*-----------------------------------------------------------*/
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )
{
signed portBASE_TYPE xReturn;
/* We cannot block from an ISR, so check there is data available. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
- /* Copy the data from the queue. */
- pxQueue->pcReadFrom += pxQueue->uxItemSize;
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )
- {
- pxQueue->pcReadFrom = pxQueue->pcHead;
- }
+ prvCopyDataFromQueue( pxQueue, pvBuffer );
--( pxQueue->uxMessagesWaiting );
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
/* If the queue is locked we will not modify the event list. Instead
we update the lock count so the task that unlocks the queue will know
@@ -636,6 +710,57 @@ void vQueueDelete( xQueueHandle pxQueue ) }
/*-----------------------------------------------------------*/
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
+{
+ if( pxQueue->uxItemSize == 0 )
+ {
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+ {
+ /* The mutex is no longer being held. */
+ vTaskPriorityDisinherit( ( xTaskHandle * const ) pxQueue->pxMutexHolder );
+ }
+ }
+ #endif
+ }
+ else if( xPosition == queueSEND_TO_BACK )
+ {
+ memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
+ pxQueue->pcWriteTo += pxQueue->uxItemSize;
+ if( pxQueue->pcWriteTo >= pxQueue->pcTail )
+ {
+ pxQueue->pcWriteTo = pxQueue->pcHead;
+ }
+ }
+ else
+ {
+ memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
+ pxQueue->pcReadFrom -= pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom < pxQueue->pcHead )
+ {
+ pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
+ }
+ }
+
+ ++( pxQueue->uxMessagesWaiting );
+}
+/*-----------------------------------------------------------*/
+
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )
+{
+ if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )
+ {
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+ }
+}
+/*-----------------------------------------------------------*/
+
static void prvUnlockQueue( xQueueHandle pxQueue )
{
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
@@ -722,7 +847,7 @@ signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQue signed portBASE_TYPE xReturn;
/* If the queue is already full we may have to block. A critical section
- is required to prevent an interrupt removing something from the queue
+ is required to prevent an interrupt removing something from the queue
between the check to see if the queue is full and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
@@ -754,19 +879,19 @@ signed portBASE_TYPE xReturn; if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
- prvCopyQueueData( pxQueue, pvItemToQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
xReturn = pdPASS;
/* Were any co-routines waiting for data to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
- /* In this instance the co-routine could be placed directly
- into the ready list as we are within a critical section.
- Instead the same pending ready list mechansim is used as if
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechanism is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
- /* The co-routine waiting has a higher priority so record
+ /* The co-routine waiting has a higher priority so record
that a yield might be appropriate. */
xReturn = errQUEUE_YIELD;
}
@@ -790,7 +915,7 @@ signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, port signed portBASE_TYPE xReturn;
/* If the queue is already empty we may have to block. A critical section
- is required to prevent an interrupt adding something to the queue
+ is required to prevent an interrupt adding something to the queue
between the check to see if the queue is empty and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
@@ -835,9 +960,9 @@ signed portBASE_TYPE xReturn; /* Were any co-routines waiting for space to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
- /* In this instance the co-routine could be placed directly
- into the ready list as we are within a critical section.
- Instead the same pending ready list mechansim is used as if
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechanism is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
@@ -866,9 +991,9 @@ signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvIt exit without doing anything. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
- prvCopyQueueData( pxQueue, pvItemToQueue );
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );
- /* We only want to wake one co-routine per ISR, so check that a
+ /* We only want to wake one co-routine per ISR, so check that a
co-routine has not already been woken. */
if( !xCoRoutinePreviouslyWoken )
{
diff --git a/Source/tasks.c b/Source/tasks.c index e572f5c09..7ed5637a1 100644 --- a/Source/tasks.c +++ b/Source/tasks.c @@ -229,10 +229,6 @@ Changes since V4.3.1: #define configMAX_TASK_NAME_LEN 16
#endif
-#ifndef INCLUDE_xTaskGetCurrentTaskHandle
- #define INCLUDE_xTaskGetCurrentTaskHandle 0
-#endif
-
#ifndef configIDLE_SHOULD_YIELD
#define configIDLE_SHOULD_YIELD 1
#endif
@@ -261,9 +257,16 @@ typedef struct tskTaskControlBlock xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
- unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
- unsigned portSHORT usStackDepth; /*< Total depth of the stack (when empty). This is defined as the number of variables the stack can hold, not the number of bytes. */
+
+ #if ( configUSE_TRACE_FACILITY == 1 )
+ unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
+ #endif
+
+ #if ( configUSE_MUTEXES == 1 )
+ unsigned portBASE_TYPE uxBasePriority;
+ #endif
+
} tskTCB;
/*lint -e956 */
@@ -429,7 +432,7 @@ register tskTCB *pxTCB; \ * Utility to ready a TCB for a given task. Mainly just copies the parameters
* into the TCB structure.
*/
-static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
/*
* Utility to ready all the lists used by the scheduler. This is called
@@ -485,7 +488,7 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth ); */
#if ( configUSE_TRACE_FACILITY == 1 )
- static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
+ static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
#endif
@@ -496,7 +499,7 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth ); */
#if ( configUSE_TRACE_FACILITY == 1 )
- unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte );
+ unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte );
#endif
@@ -524,7 +527,9 @@ signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR {
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB;
-static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
+#if ( configUSE_TRACE_FACILITY == 1 )
+ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
+#endif
/* Allocate the memory required by the TCB and stack for the new task.
checking that the allocation was successful. */
@@ -535,7 +540,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat portSTACK_TYPE *pxTopOfStack;
/* Setup the newly allocated TCB with the initial state of the task. */
- prvInitialiseTCBVariables( pxNewTCB, usStackDepth, pcName, uxPriority );
+ prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority );
/* Calculate the top of stack address. This depends on whether the
stack grows from high memory to low (as per the 80x86) or visa versa.
@@ -543,7 +548,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat required by the port. */
#if portSTACK_GROWTH < 0
{
- pxTopOfStack = pxNewTCB->pxStack + ( pxNewTCB->usStackDepth - 1 );
+ pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
}
#else
{
@@ -593,9 +598,13 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat uxTopUsedPriority = pxNewTCB->uxPriority;
}
- /* Add a counter into the TCB for tracing only. */
- pxNewTCB->uxTCBNumber = uxTaskNumber;
- uxTaskNumber++;
+ #if ( configUSE_TRACE_FACILITY == 1 )
+ {
+ /* Add a counter into the TCB for tracing only. */
+ pxNewTCB->uxTCBNumber = uxTaskNumber;
+ uxTaskNumber++;
+ }
+ #endif
prvAddTaskToReadyQueue( pxNewTCB );
@@ -695,7 +704,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat #if ( INCLUDE_vTaskDelayUntil == 1 )
- void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement )
+ void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
{
portTickType xTimeToWake;
portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
@@ -867,13 +876,22 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat /* If null is passed in here then we are changing the
priority of the calling function. */
pxTCB = prvGetTCBFromHandle( pxTask );
- uxCurrentPriority = pxTCB->uxPriority;
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ uxCurrentPriority = pxTCB->uxBasePriority;
+ }
+ #else
+ {
+ uxCurrentPriority = pxTCB->uxPriority;
+ }
+ #endif
if( uxCurrentPriority != uxNewPriority )
{
/* The priority change may have readied a task of higher
priority than the calling task. */
- if( uxNewPriority > pxCurrentTCB->uxPriority )
+ if( uxNewPriority > uxCurrentPriority )
{
if( pxTask != NULL )
{
@@ -891,7 +909,26 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat xYieldRequired = pdTRUE;
}
- pxTCB->uxPriority = uxNewPriority;
+
+
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ /* Only change the priority being used if the task is not
+ currently using an inherited priority. */
+ if( pxTCB->uxBasePriority == pxTCB->uxPriority )
+ {
+ pxTCB->uxPriority = uxNewPriority;
+ }
+
+ /* The base priority gets set whatever. */
+ pxTCB->uxBasePriority = uxNewPriority;
+ }
+ #else
+ {
+ pxTCB->uxPriority = uxNewPriority;
+ }
+ #endif
+
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxNewPriority );
/* If the task is in the blocked or suspended list we need do
@@ -1051,7 +1088,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat {
/* We cannot access the delayed or ready lists, so will hold this
task pending until the scheduler is resumed, at which point a
- yield will be preformed if necessary. */
+ yield will be performed if necessary. */
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
}
}
@@ -1457,7 +1494,7 @@ void vTaskSwitchContext( void ) }
/*-----------------------------------------------------------*/
-void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait )
+void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
{
portTickType xTimeToWake;
@@ -1527,7 +1564,7 @@ portTickType xTimeToWake; }
/*-----------------------------------------------------------*/
-signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList )
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
{
tskTCB *pxUnblockedTCB;
portBASE_TYPE xReturn;
@@ -1574,14 +1611,14 @@ portBASE_TYPE xReturn; }
/*-----------------------------------------------------------*/
-void vTaskSetTimeOutState( xTimeOutType *pxTimeOut )
+void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
{
pxTimeOut->xOverflowCount = xNumOfOverflows;
pxTimeOut->xTimeOnEntering = xTickCount;
}
/*-----------------------------------------------------------*/
-portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait )
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
{
portBASE_TYPE xReturn;
@@ -1701,10 +1738,8 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) -static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
{
- pxTCB->usStackDepth = usStackDepth;
-
/* Store the function name in the TCB. */
strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
@@ -1716,6 +1751,11 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStack }
pxTCB->uxPriority = uxPriority;
+ #if ( configUSE_MUTEXES == 1 )
+ {
+ pxTCB->uxBasePriority = uxPriority;
+ }
+ #endif
vListInitialiseItem( &( pxTCB->xGenericListItem ) );
vListInitialiseItem( &( pxTCB->xEventListItem ) );
@@ -1831,7 +1871,7 @@ tskTCB *pxNewTCB; #if ( configUSE_TRACE_FACILITY == 1 )
- static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
+ static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
{
volatile tskTCB *pxNextTCB, *pxFirstTCB;
static portCHAR pcStatusString[ 50 ];
@@ -1853,7 +1893,7 @@ tskTCB *pxNewTCB; /*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 )
- unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte )
+ unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )
{
register unsigned portSHORT usCount = 0;
@@ -1933,4 +1973,63 @@ tskTCB *pxNewTCB; #endif
+#if ( configUSE_MUTEXES == 1 )
+
+ void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
+ {
+ tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
+
+ if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
+ {
+ /* Adjust the mutex holder state to account for its new priority. */
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
+
+ /* If the task being modified is in the read state it will need to
+ be moved in to a new list. */
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
+ {
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Inherit the priority before being moved into the new list. */
+ pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ else
+ {
+ /* Just inherit the priority. */
+ pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+ }
+ }
+ }
+
+#endif
+
+#if ( configUSE_MUTEXES == 1 )
+
+ void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
+ {
+ tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
+
+ if( pxMutexHolder != NULL )
+ {
+ if( pxTCB->uxPriority != pxTCB->uxBasePriority )
+ {
+ /* We must be the running task to be able to give the mutex back.
+ Remove ourselves from the ready list we currently appear in. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Disinherit the priority before adding ourselves into the new
+ ready list. */
+ pxTCB->uxPriority = pxTCB->uxBasePriority;
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ }
+ }
+
+#endif
+
+
+
+
|