mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
Preparing for new release...
Kernel changes: - Remove an assert that was preventing xQueueSendFromISR() being used to give a mutex from an ISR (mutexes cannot be given using xSemaphoreGiveFromISR()). - Introduce xTaskNotifyAndQueryFromISR() as the interrupt safe version of xTaskNotifyAndQuery(). Common demo task changes: - Update IntSemTest.c to prove the theory that it is safe to give a mutex type semaphore from an interrupt using xQueueSendFromISR() instead of xSemaphoreGiveFromISR(). - Update TaskNotify.c to test the new xTaskNotifyAndQuery() from ISR fuction.
This commit is contained in:
parent
25b911e0bd
commit
4c3722bd76
|
@ -163,7 +163,7 @@ static SemaphoreHandle_t xMasterSlaveMutex = NULL;
|
||||||
/* Flag that allows the master task to control when the interrupt gives or does
|
/* Flag that allows the master task to control when the interrupt gives or does
|
||||||
not give the mutex. There is no mutual exclusion on this variable, but this is
|
not give the mutex. There is no mutual exclusion on this variable, but this is
|
||||||
only test code and it should be fine in the 32=bit test environment. */
|
only test code and it should be fine in the 32=bit test environment. */
|
||||||
static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE;
|
static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE, xOkToGiveMasterSlaveMutex = pdFALSE;
|
||||||
|
|
||||||
/* Used to coordinate timing between tasks and the interrupt. */
|
/* Used to coordinate timing between tasks and the interrupt. */
|
||||||
const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||||
|
@ -217,6 +217,8 @@ static void vInterruptMutexMasterTask( void *pvParameters )
|
||||||
|
|
||||||
static void prvTakeAndGiveInTheSameOrder( void )
|
static void prvTakeAndGiveInTheSameOrder( void )
|
||||||
{
|
{
|
||||||
|
static BaseType_t xGiveFromTask = pdTRUE;
|
||||||
|
|
||||||
/* Ensure the slave is suspended, and that this task is running at the
|
/* Ensure the slave is suspended, and that this task is running at the
|
||||||
lower priority as expected as the start conditions. */
|
lower priority as expected as the start conditions. */
|
||||||
#if( INCLUDE_eTaskGetState == 1 )
|
#if( INCLUDE_eTaskGetState == 1 )
|
||||||
|
@ -293,12 +295,29 @@ static void prvTakeAndGiveInTheSameOrder( void )
|
||||||
/* Finally give back the shared mutex. This time the higher priority
|
/* Finally give back the shared mutex. This time the higher priority
|
||||||
task should run before this task runs again - so this task should have
|
task should run before this task runs again - so this task should have
|
||||||
disinherited the priority and the higher priority task should be in the
|
disinherited the priority and the higher priority task should be in the
|
||||||
suspended state again. */
|
suspended state again. Alternatve beetween giving the mutex from this task,
|
||||||
|
and giving it from the interrupt. */
|
||||||
|
if( xGiveFromTask == pdTRUE )
|
||||||
|
{
|
||||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||||
{
|
{
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Give the mutex from the interrupt on the next go around. */
|
||||||
|
xGiveFromTask = pdFALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Wait for the mutex to be given from the interrupt. */
|
||||||
|
xOkToGiveMasterSlaveMutex = pdTRUE;
|
||||||
|
vTaskDelay( xInterruptGivePeriod + ( xInterruptGivePeriod >> 1 ) );
|
||||||
|
xOkToGiveMasterSlaveMutex = pdFALSE;
|
||||||
|
|
||||||
|
/* Give the mutex from the task on the next go around. */
|
||||||
|
xGiveFromTask = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||||
{
|
{
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
|
@ -514,15 +533,36 @@ TickType_t xTimeNow;
|
||||||
xTimeNow = xTaskGetTickCountFromISR();
|
xTimeNow = xTaskGetTickCountFromISR();
|
||||||
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
|
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
|
||||||
{
|
{
|
||||||
configASSERT( xISRMutex );
|
|
||||||
if( xOkToGiveMutex != pdFALSE )
|
if( xOkToGiveMutex != pdFALSE )
|
||||||
{
|
{
|
||||||
|
configASSERT( xISRMutex );
|
||||||
|
|
||||||
/* Null is used as the second parameter in this give, and non-NULL
|
/* Null is used as the second parameter in this give, and non-NULL
|
||||||
in the other gives for code coverage reasons. */
|
in the other gives, for code coverage reasons. NOTE: This is a
|
||||||
xSemaphoreGiveFromISR( xISRMutex, NULL );
|
Mutex, so xQueueGiveFromISR() should be used in place of
|
||||||
|
xSemaphoreGiveFromISR() in case there is a mutex holder that has
|
||||||
|
inherited a priority (although, in the case of xISRMutex, there
|
||||||
|
isn't). The "item to queue" parameter is set to NULL as no data is
|
||||||
|
copied into a mutex.*/
|
||||||
|
xQueueSendFromISR( ( QueueHandle_t ) xISRMutex, NULL, NULL );
|
||||||
|
|
||||||
/* Second give attempt should fail. */
|
/* Second give attempt should fail. */
|
||||||
configASSERT( xSemaphoreGiveFromISR( xISRMutex, &xHigherPriorityTaskWoken ) == pdFAIL );
|
configASSERT( xQueueSendFromISR( xISRMutex, NULL, &xHigherPriorityTaskWoken ) == pdFAIL );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( xOkToGiveMasterSlaveMutex != pdFALSE )
|
||||||
|
{
|
||||||
|
configASSERT( xOkToGiveMasterSlaveMutex );
|
||||||
|
|
||||||
|
/* NOTE: This is a Mutex, so xQueueGiveFromISR() should be used in
|
||||||
|
place of xSemaphoreGiveFromISR() in case there is a mutex holder
|
||||||
|
that has inherited a priority (as indeed there is in this case).
|
||||||
|
The "item to queue" parameter is set to NULL as no data is copied
|
||||||
|
into a mutex. */
|
||||||
|
xQueueSendFromISR( ( QueueHandle_t ) xMasterSlaveMutex, NULL, NULL );
|
||||||
|
|
||||||
|
/* Second give attempt should fail. */
|
||||||
|
configASSERT( xQueueSendFromISR( xMasterSlaveMutex, NULL, &xHigherPriorityTaskWoken ) == pdFAIL );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( xOkToGiveCountingSemaphore != pdFALSE )
|
if( xOkToGiveCountingSemaphore != pdFALSE )
|
||||||
|
|
|
@ -472,8 +472,10 @@ TickType_t xPeriod;
|
||||||
|
|
||||||
void xNotifyTaskFromISR( void )
|
void xNotifyTaskFromISR( void )
|
||||||
{
|
{
|
||||||
static BaseType_t xCallCount = 0;
|
static BaseType_t xCallCount = 0, xAPIToUse = 0;
|
||||||
const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
|
const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
|
||||||
|
uint32_t ulPreviousValue;
|
||||||
|
const uint32_t ulUnexpectedValue = 0xff;
|
||||||
|
|
||||||
/* The task performs some tests before starting the timer that gives the
|
/* The task performs some tests before starting the timer that gives the
|
||||||
notification from this interrupt. If the timer has not been created yet
|
notification from this interrupt. If the timer has not been created yet
|
||||||
|
@ -488,7 +490,28 @@ const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
|
||||||
/* It is time to 'give' the notification again. */
|
/* It is time to 'give' the notification again. */
|
||||||
xCallCount = 0;
|
xCallCount = 0;
|
||||||
|
|
||||||
vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
|
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
|
||||||
|
and xTaskNotifyAndQueryFromISR(). */
|
||||||
|
switch( xAPIToUse )
|
||||||
|
{
|
||||||
|
case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
|
||||||
|
xAPIToUse++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
|
||||||
|
xAPIToUse++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: ulPreviousValue = ulUnexpectedValue;
|
||||||
|
xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
|
||||||
|
configASSERT( ulPreviousValue != ulUnexpectedValue );
|
||||||
|
xAPIToUse = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:/* Should never get here!. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ulTimerNotificationsSent++;
|
ulTimerNotificationsSent++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,8 @@ volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0;
|
||||||
( void ) ulLine;
|
( void ) ulLine;
|
||||||
( void ) pcFileName;
|
( void ) pcFileName;
|
||||||
|
|
||||||
|
printf( "ASSERT! Line %d, file %s\r\n", ulLine, pcFileName );
|
||||||
|
|
||||||
taskENTER_CRITICAL();
|
taskENTER_CRITICAL();
|
||||||
{
|
{
|
||||||
/* Stop the trace recording. */
|
/* Stop the trace recording. */
|
||||||
|
|
|
@ -1563,7 +1563,9 @@ BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNo
|
||||||
* \defgroup xTaskNotify xTaskNotify
|
* \defgroup xTaskNotify xTaskNotify
|
||||||
* \ingroup TaskNotifications
|
* \ingroup TaskNotifications
|
||||||
*/
|
*/
|
||||||
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||||
|
#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )
|
||||||
|
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* task. h
|
* task. h
|
||||||
|
|
|
@ -1219,9 +1219,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
if the item size is not 0. */
|
if the item size is not 0. */
|
||||||
configASSERT( pxQueue->uxItemSize == 0 );
|
configASSERT( pxQueue->uxItemSize == 0 );
|
||||||
|
|
||||||
/* Normally a mutex would not be given from an interrupt, and doing so is
|
/* Normally a mutex would not be given from an interrupt, especially if
|
||||||
definitely wrong if there is a mutex holder as priority inheritance makes no
|
there is a mutex holder, as priority inheritance makes no sense for an
|
||||||
sense for an interrupts, only tasks. */
|
interrupts, only tasks. However, on occasions when it is wanted to give
|
||||||
|
a mutex from an interrupt, use xQueueSendFromISR() in place of
|
||||||
|
xSemaphoreGiveFromISR(). */
|
||||||
configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );
|
configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );
|
||||||
|
|
||||||
/* RTOS ports that support interrupt nesting have the concept of a maximum
|
/* RTOS ports that support interrupt nesting have the concept of a maximum
|
||||||
|
|
|
@ -3489,12 +3489,6 @@ TCB_t *pxTCB;
|
||||||
|
|
||||||
if( pxMutexHolder != NULL )
|
if( pxMutexHolder != NULL )
|
||||||
{
|
{
|
||||||
/* A task can only have an inherited priority if it holds the mutex.
|
|
||||||
If the mutex is held by a task then it cannot be given from an
|
|
||||||
interrupt, and if a mutex is given by the holding task then it must
|
|
||||||
be the running state task. */
|
|
||||||
configASSERT( pxTCB == pxCurrentTCB );
|
|
||||||
|
|
||||||
configASSERT( pxTCB->uxMutexesHeld );
|
configASSERT( pxTCB->uxMutexesHeld );
|
||||||
( pxTCB->uxMutexesHeld )--;
|
( pxTCB->uxMutexesHeld )--;
|
||||||
|
|
||||||
|
@ -4236,7 +4230,7 @@ TickType_t uxReturn;
|
||||||
|
|
||||||
#if( configUSE_TASK_NOTIFICATIONS == 1 )
|
#if( configUSE_TASK_NOTIFICATIONS == 1 )
|
||||||
|
|
||||||
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken )
|
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
|
||||||
{
|
{
|
||||||
TCB_t * pxTCB;
|
TCB_t * pxTCB;
|
||||||
eNotifyValue eOriginalNotifyState;
|
eNotifyValue eOriginalNotifyState;
|
||||||
|
@ -4267,8 +4261,12 @@ TickType_t uxReturn;
|
||||||
|
|
||||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
{
|
{
|
||||||
eOriginalNotifyState = pxTCB->eNotifyState;
|
if( pulPreviousNotificationValue != NULL )
|
||||||
|
{
|
||||||
|
*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
eOriginalNotifyState = pxTCB->eNotifyState;
|
||||||
pxTCB->eNotifyState = eNotified;
|
pxTCB->eNotifyState = eNotified;
|
||||||
|
|
||||||
switch( eAction )
|
switch( eAction )
|
||||||
|
|
Loading…
Reference in a new issue