Skip to content

Commit 5929dc7

Browse files
authored
Merge branch 'main' into ARM_CRx_MPU
2 parents 72ee9e3 + 7284d84 commit 5929dc7

File tree

1 file changed

+87
-124
lines changed

1 file changed

+87
-124
lines changed

tasks.c

Lines changed: 87 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -3822,6 +3822,9 @@ void vTaskSuspendAll( void )
38223822

38233823
if( xSchedulerRunning != pdFALSE )
38243824
{
3825+
/* This must never be called from inside a critical section. */
3826+
configASSERT( portGET_CRITICAL_NESTING_COUNT() == 0 );
3827+
38253828
/* Writes to uxSchedulerSuspended must be protected by both the task AND ISR locks.
38263829
* We must disable interrupts before we grab the locks in the event that this task is
38273830
* interrupted and switches context before incrementing uxSchedulerSuspended.
@@ -3840,14 +3843,7 @@ void vTaskSuspendAll( void )
38403843
* it. */
38413844
if( uxSchedulerSuspended == 0U )
38423845
{
3843-
if( portGET_CRITICAL_NESTING_COUNT() == 0U )
3844-
{
3845-
prvCheckForRunStateChange();
3846-
}
3847-
else
3848-
{
3849-
mtCOVERAGE_TEST_MARKER();
3850-
}
3846+
prvCheckForRunStateChange();
38513847
}
38523848
else
38533849
{
@@ -7676,83 +7672,67 @@ TickType_t uxTaskResetEventItemValue( void )
76767672
TickType_t xTicksToWait )
76777673
{
76787674
uint32_t ulReturn;
7679-
BaseType_t xAlreadyYielded;
7675+
BaseType_t xAlreadyYielded, xShouldBlock = pdFALSE;
76807676

76817677
traceENTER_ulTaskGenericNotifyTake( uxIndexToWaitOn, xClearCountOnExit, xTicksToWait );
76827678

76837679
configASSERT( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );
76847680

7685-
taskENTER_CRITICAL();
7686-
7687-
/* Only block if the notification count is not already non-zero. */
7688-
if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] == 0UL )
7681+
/* We suspend the scheduler here as prvAddCurrentTaskToDelayedList is a
7682+
* non-deterministic operation. */
7683+
vTaskSuspendAll();
76897684
{
7690-
/* Mark this task as waiting for a notification. */
7691-
pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION;
7692-
7693-
if( xTicksToWait > ( TickType_t ) 0 )
7685+
/* We MUST enter a critical section to atomically check if a notification
7686+
* has occurred and set the flag to indicate that we are waiting for
7687+
* a notification. If we do not do so, a notification sent from an ISR
7688+
* will get lost. */
7689+
taskENTER_CRITICAL();
76947690
{
7695-
traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWaitOn );
7696-
7697-
/* We MUST suspend the scheduler before exiting the critical
7698-
* section (i.e. before enabling interrupts).
7699-
*
7700-
* If we do not do so, a notification sent from an ISR, which
7701-
* happens after exiting the critical section and before
7702-
* suspending the scheduler, will get lost. The sequence of
7703-
* events will be:
7704-
* 1. Exit critical section.
7705-
* 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7706-
* task to the Ready list.
7707-
* 3. Suspend scheduler.
7708-
* 4. prvAddCurrentTaskToDelayedList moves the task to the
7709-
* delayed or suspended list.
7710-
* 5. Resume scheduler does not touch the task (because it is
7711-
* not on the pendingReady list), effectively losing the
7712-
* notification from the ISR.
7713-
*
7714-
* The same does not happen when we suspend the scheduler before
7715-
* exiting the critical section. The sequence of events in this
7716-
* case will be:
7717-
* 1. Suspend scheduler.
7718-
* 2. Exit critical section.
7719-
* 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7720-
* task to the pendingReady list as the scheduler is
7721-
* suspended.
7722-
* 4. prvAddCurrentTaskToDelayedList adds the task to delayed or
7723-
* suspended list. Note that this operation does not nullify
7724-
* the add to pendingReady list done in the above step because
7725-
* a different list item, namely xEventListItem, is used for
7726-
* adding the task to the pendingReady list. In other words,
7727-
* the task still remains on the pendingReady list.
7728-
* 5. Resume scheduler moves the task from pendingReady list to
7729-
* the Ready list.
7730-
*/
7731-
vTaskSuspendAll();
7691+
/* Only block if the notification count is not already non-zero. */
7692+
if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] == 0UL )
77327693
{
7733-
taskEXIT_CRITICAL();
7694+
/* Mark this task as waiting for a notification. */
7695+
pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION;
77347696

7735-
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
7736-
}
7737-
xAlreadyYielded = xTaskResumeAll();
7738-
7739-
if( xAlreadyYielded == pdFALSE )
7740-
{
7741-
taskYIELD_WITHIN_API();
7697+
if( xTicksToWait > ( TickType_t ) 0 )
7698+
{
7699+
xShouldBlock = pdTRUE;
7700+
}
7701+
else
7702+
{
7703+
mtCOVERAGE_TEST_MARKER();
7704+
}
77427705
}
77437706
else
77447707
{
77457708
mtCOVERAGE_TEST_MARKER();
77467709
}
77477710
}
7711+
taskEXIT_CRITICAL();
7712+
7713+
/* We are now out of the critical section but the scheduler is still
7714+
* suspended, so we are safe to do non-deterministic operations such
7715+
* as prvAddCurrentTaskToDelayedList. */
7716+
if( xShouldBlock == pdTRUE )
7717+
{
7718+
traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWaitOn );
7719+
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
7720+
}
77487721
else
77497722
{
7750-
taskEXIT_CRITICAL();
7723+
mtCOVERAGE_TEST_MARKER();
77517724
}
77527725
}
7726+
xAlreadyYielded = xTaskResumeAll();
7727+
7728+
/* Force a reschedule if xTaskResumeAll has not already done so. */
7729+
if( ( xShouldBlock == pdTRUE ) && ( xAlreadyYielded == pdFALSE ) )
7730+
{
7731+
taskYIELD_WITHIN_API();
7732+
}
77537733
else
77547734
{
7755-
taskEXIT_CRITICAL();
7735+
mtCOVERAGE_TEST_MARKER();
77567736
}
77577737

77587738
taskENTER_CRITICAL();
@@ -7796,88 +7776,71 @@ TickType_t uxTaskResetEventItemValue( void )
77967776
uint32_t * pulNotificationValue,
77977777
TickType_t xTicksToWait )
77987778
{
7799-
BaseType_t xReturn, xAlreadyYielded;
7779+
BaseType_t xReturn, xAlreadyYielded, xShouldBlock = pdFALSE;
78007780

78017781
traceENTER_xTaskGenericNotifyWait( uxIndexToWaitOn, ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait );
78027782

78037783
configASSERT( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );
78047784

7805-
taskENTER_CRITICAL();
7806-
7807-
/* Only block if a notification is not already pending. */
7808-
if( pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED )
7785+
/* We suspend the scheduler here as prvAddCurrentTaskToDelayedList is a
7786+
* non-deterministic operation. */
7787+
vTaskSuspendAll();
78097788
{
7810-
/* Clear bits in the task's notification value as bits may get
7811-
* set by the notifying task or interrupt. This can be used to
7812-
* clear the value to zero. */
7813-
pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] &= ~ulBitsToClearOnEntry;
7814-
7815-
/* Mark this task as waiting for a notification. */
7816-
pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION;
7817-
7818-
if( xTicksToWait > ( TickType_t ) 0 )
7789+
/* We MUST enter a critical section to atomically check and update the
7790+
* task notification value. If we do not do so, a notification from
7791+
* an ISR will get lost. */
7792+
taskENTER_CRITICAL();
78197793
{
7820-
traceTASK_NOTIFY_WAIT_BLOCK( uxIndexToWaitOn );
7821-
7822-
/* We MUST suspend the scheduler before exiting the critical
7823-
* section (i.e. before enabling interrupts).
7824-
*
7825-
* If we do not do so, a notification sent from an ISR, which
7826-
* happens after exiting the critical section and before
7827-
* suspending the scheduler, will get lost. The sequence of
7828-
* events will be:
7829-
* 1. Exit critical section.
7830-
* 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7831-
* task to the Ready list.
7832-
* 3. Suspend scheduler.
7833-
* 4. prvAddCurrentTaskToDelayedList moves the task to the
7834-
* delayed or suspended list.
7835-
* 5. Resume scheduler does not touch the task (because it is
7836-
* not on the pendingReady list), effectively losing the
7837-
* notification from the ISR.
7838-
*
7839-
* The same does not happen when we suspend the scheduler before
7840-
* exiting the critical section. The sequence of events in this
7841-
* case will be:
7842-
* 1. Suspend scheduler.
7843-
* 2. Exit critical section.
7844-
* 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7845-
* task to the pendingReady list as the scheduler is
7846-
* suspended.
7847-
* 4. prvAddCurrentTaskToDelayedList adds the task to delayed or
7848-
* suspended list. Note that this operation does not nullify
7849-
* the add to pendingReady list done in the above step because
7850-
* a different list item, namely xEventListItem, is used for
7851-
* adding the task to the pendingReady list. In other words,
7852-
* the task still remains on the pendingReady list.
7853-
* 5. Resume scheduler moves the task from pendingReady list to
7854-
* the Ready list.
7855-
*/
7856-
vTaskSuspendAll();
7794+
/* Only block if a notification is not already pending. */
7795+
if( pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED )
78577796
{
7858-
taskEXIT_CRITICAL();
7797+
/* Clear bits in the task's notification value as bits may get
7798+
* set by the notifying task or interrupt. This can be used
7799+
* to clear the value to zero. */
7800+
pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] &= ~ulBitsToClearOnEntry;
78597801

7860-
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
7861-
}
7862-
xAlreadyYielded = xTaskResumeAll();
7802+
/* Mark this task as waiting for a notification. */
7803+
pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION;
78637804

7864-
if( xAlreadyYielded == pdFALSE )
7865-
{
7866-
taskYIELD_WITHIN_API();
7805+
if( xTicksToWait > ( TickType_t ) 0 )
7806+
{
7807+
xShouldBlock = pdTRUE;
7808+
}
7809+
else
7810+
{
7811+
mtCOVERAGE_TEST_MARKER();
7812+
}
78677813
}
78687814
else
78697815
{
78707816
mtCOVERAGE_TEST_MARKER();
78717817
}
78727818
}
7819+
taskEXIT_CRITICAL();
7820+
7821+
/* We are now out of the critical section but the scheduler is still
7822+
* suspended, so we are safe to do non-deterministic operations such
7823+
* as prvAddCurrentTaskToDelayedList. */
7824+
if( xShouldBlock == pdTRUE )
7825+
{
7826+
traceTASK_NOTIFY_WAIT_BLOCK( uxIndexToWaitOn );
7827+
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
7828+
}
78737829
else
78747830
{
7875-
taskEXIT_CRITICAL();
7831+
mtCOVERAGE_TEST_MARKER();
78767832
}
78777833
}
7834+
xAlreadyYielded = xTaskResumeAll();
7835+
7836+
/* Force a reschedule if xTaskResumeAll has not already done so. */
7837+
if( ( xShouldBlock == pdTRUE ) && ( xAlreadyYielded == pdFALSE ) )
7838+
{
7839+
taskYIELD_WITHIN_API();
7840+
}
78787841
else
78797842
{
7880-
taskEXIT_CRITICAL();
7843+
mtCOVERAGE_TEST_MARKER();
78817844
}
78827845

78837846
taskENTER_CRITICAL();

0 commit comments

Comments
 (0)