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: +* - * 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 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 )
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 */