diff --git a/Demo/Common/Minimal/recmutex.c b/Demo/Common/Minimal/recmutex.c index fea1d32c4..a1ceb4485 100644 --- a/Demo/Common/Minimal/recmutex.c +++ b/Demo/Common/Minimal/recmutex.c @@ -37,11 +37,10 @@ /* The tasks defined on this page demonstrate the use of recursive mutexes. - All mutexes are created using a call to xSemaphoreCreateMutex(). For - recursive mutex functionality the created mutex should then be manipulated + For recursive mutex functionality the created mutex should be created using + xSemaphoreCreateRecursiveMutex(), then be manipulated using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API - functions. Recursive mutexes must NOT be passed as a parameter to the - standard mutex API functions xSemaphoreTake() and xSemaphoreGive(). + functions. This demo creates three tasks all of which access the same recursive mutex: diff --git a/Source/include/semphr.h b/Source/include/semphr.h index b5c61e04c..dc236a599 100644 --- a/Source/include/semphr.h +++ b/Source/include/semphr.h @@ -99,18 +99,21 @@ typedef xQueueHandle xSemaphoreHandle; * portTickType xBlockTime * ) * - * Macro to obtain a semaphore. The semaphore must of been created using - * vSemaphoreCreateBinary (). + * Macro to obtain a semaphore. The semaphore must have previously been + * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). * - * @param xSemaphore A handle to the semaphore being obtained. This is the - * handle returned by vSemaphoreCreateBinary (); + * @param xSemaphore A handle to the semaphore being taken - obtained when + * the semaophore was created. * * @param xBlockTime The time in ticks to wait for the semaphore to become * available. The macro portTICK_RATE_MS can be used to convert this to a - * real time. A block time of zero can be used to poll the semaphore. + * real time. A block time of zero can be used to poll the semaphore. A block + * time of portMAX_DELAY can be used to block indefinately (provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h). * - * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime - * expired without the semaphore becoming available. + * @return pdTRUE if the semaphore was obtained. pdFALSE + * if xBlockTime expired without the semaphore becoming available. * * Example usage:
@@ -156,6 +159,100 @@ typedef xQueueHandle xSemaphoreHandle;
  */
 #define xSemaphoreTake( xSemaphore, xBlockTime )		xQueueGenericReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime, pdFALSE )
 
+/**
+ * semphr. h
+ * xSemaphoreTakeRecursive( 
+ *                          xSemaphoreHandle xMutex, 
+ *                          portTickType xBlockTime 
+ *                        )
+ *
+ * Macro to recursively obtain, or 'take', a mutex type semaphore.  
+ * The mutex must have previously been created using a call to 
+ * xSemaphoreCreateRecursiveMutex();
+ * 
+ * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this
+ * macro to be available.
+ * 
+ * This macro must not be used on mutexes created using xSemaphoreCreateMutex().
+ *
+ * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex 
+ * doesn't become available again until the owner has called 
+ * xSemaphoreGiveRecursive() for each successful 'take' request.  For example, 
+ * if a task successfully 'takes' the same mutex 5 times then the mutex will 
+ * not be avilable to any other task until it has also  'given' the mutex back
+ * exactly five times.
+ *
+ * @param xMutex A handle to the mutex being obtained.  This is the
+ * handle returned by xSemaphoreCreateMutex();
+ *
+ * @param xBlockTime The time in ticks to wait for the semaphore to become
+ * available.  The macro portTICK_RATE_MS can be used to convert this to a
+ * real time.  A block time of zero can be used to poll the semaphore.  If
+ * the task already owns the semaphore then xSemaphoreTakeRecursive() will
+ * return immediately nomatter what the value of xBlockTime. 
+ *
+ * @return pdTRUE if the semaphore was obtained.  pdFALSE if xBlockTime
+ * expired without the semaphore becoming available.
+ *
+ * Example usage:
+ 
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.	
+        if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to 
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 );
+            xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be 
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, but instead buried in a more complex
+			// call structure.  This is just for illustrative puproses.
+            xSemaphoreGiveRecursive( xSemaphore );
+			xSemaphoreGiveRecursive( xSemaphore );
+			xSemaphoreGiveRecursive( xSemaphore );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive + * \ingroup Semaphores + */ +#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( xMutex, xBlockTime ) + + /* * xSemaphoreAltTake() is an alternative version of xSemaphoreTake(). * @@ -174,14 +271,18 @@ typedef xQueueHandle xSemaphoreHandle; * semphr. h *
xSemaphoreGive( xSemaphoreHandle xSemaphore )
* - * Macro to release a semaphore. The semaphore must of been created using - * vSemaphoreCreateBinary (), and obtained using sSemaphoreTake (). + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). * - * This must not be used from an ISR. See xSemaphoreGiveFromISR () for + * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for * an alternative which can be used from an ISR. * + * This macro must also not be used on semaphores created using + * xSemaphoreCreateRecursiveMutex(). + * * @param xSemaphore A handle to the semaphore being released. This is the - * handle returned by vSemaphoreCreateBinary (); + * handle returned when the semaphore was created. * * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. * Semaphores are implemented using queues. An error can occur if there is @@ -229,6 +330,90 @@ typedef xQueueHandle xSemaphoreHandle; */ #define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) +/** + * semphr. h + *
xSemaphoreGiveRecursive( xSemaphoreHandle xSemaphore )
+ * + * Macro to recursively release, or 'give', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be avilable to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being released, or 'given'. This is the + * handle returned by xSemaphoreCreateMutex(); + * + * @return pdTRUE if the semaphore was given. + * + * Example usage: +
+ xSemaphoreHandle xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.	
+        if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to 
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 );
+            xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be 
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, it would be more likely that the calls
+			// to xSemaphoreGiveRecursive() would be called as a call stack
+			// unwound.  This is just for demonstrative purposes.
+            xSemaphoreGiveRecursive( xSemaphore );
+			xSemaphoreGiveRecursive( xSemaphore );
+			xSemaphoreGiveRecursive( xSemaphore );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive + * \ingroup Semaphores + */ +#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( xMutex ) + /* * xSemaphoreAltGive() is an alternative version of xSemaphoreGive(). * @@ -251,8 +436,8 @@ typedef xQueueHandle xSemaphoreHandle; portSHORT sTaskPreviouslyWoken )
* - * Macro to release a semaphore. The semaphore must of been created using - * vSemaphoreCreateBinary (), and obtained using xSemaphoreTake (). + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting(). * * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) * must not be used with this macro. @@ -260,7 +445,7 @@ typedef xQueueHandle xSemaphoreHandle; * This macro can be used from an ISR. * * @param xSemaphore A handle to the semaphore being released. This is the - * handle returned by vSemaphoreCreateBinary (); + * handle returned when the semaphore was created. * * @param sTaskPreviouslyWoken This is included so an ISR can make multiple calls * to xSemaphoreGiveFromISR () from a single interrupt. The first call @@ -283,8 +468,8 @@ typedef xQueueHandle xSemaphoreHandle; { for( ;; ) { - // We want this task to run every 10 ticks or a timer. The semaphore - // was created before this task was started + // We want this task to run every 10 ticks of a timer. The semaphore + // was created before this task was started. // Block waiting for the semaphore to become available. if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE ) @@ -295,7 +480,8 @@ typedef xQueueHandle xSemaphoreHandle; // We have finished our task. Return to the top of the loop where // we will block on the semaphore until it is time to execute - // again. + // again. Note when using the semaphore for synchronisation with an + // ISR in this manner there is no need to 'give' the semaphore back. } } } @@ -316,11 +502,18 @@ typedef xQueueHandle xSemaphoreHandle; if( ucLocalTickCount >= TICKS_TO_WAIT ) { // Unblock the task by releasing the semaphore. - xSemaphoreGiveFromISR( xSemaphore, xTaskWoken ); + xTaskWoken = xSemaphoreGiveFromISR( xSemaphore, xTaskWoken ); // Reset the count so we release the semaphore again in 10 ticks time. ucLocalTickCount = 0; } + + if( xTaskWoken != pdFALSE ) + { + // We can force a context switch here. Context switching from an + // ISR uses port specific syntax. Check the demo task for your port + // to find the syntax required. + } } * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR @@ -335,6 +528,10 @@ typedef xQueueHandle xSemaphoreHandle; * Macro that implements a mutex semaphore by using the existing queue * mechanism. * + * Mutexes created using this macro can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros should not be used. + * * 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. @@ -370,6 +567,60 @@ typedef xQueueHandle xSemaphoreHandle; * \ingroup Semaphores */ #define xSemaphoreCreateMutex() xQueueCreateMutex() + + +/** + * semphr. h + *
xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )
+ * + * Macro that implements a recursive mutex by using the existing queue + * mechanism. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros should not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be avilable to any other task until it has also 'given' the mutex back + * exactly five times. + * + * 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 implementation 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. + * + * @return xSemaphore Handle to the created mutex semaphore. Should be of type + * xSemaphoreHandle. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.  
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \ingroup Semaphores + */ #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex() /** @@ -435,8 +686,6 @@ typedef xQueueHandle xSemaphoreHandle; */ #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( uxMaxCount, uxInitialCount ) -#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( xMutex, xBlockTime ) -#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( xMutex ) #endif /* SEMAPHORE_H */