@@ -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