@@ -5198,7 +5198,7 @@ void vTaskPlaceOnEventList( List_t * const pxEventList,
51985198
51995199 configASSERT ( pxEventList );
52005200
5201- /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
5201+ /* THIS FUNCTION MUST BE CALLED WITH THE
52025202 * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
52035203
52045204 /* Place the event list item of the TCB in the appropriate event list.
@@ -7480,28 +7480,68 @@ TickType_t uxTaskResetEventItemValue( void )
74807480 TickType_t xTicksToWait )
74817481 {
74827482 uint32_t ulReturn ;
7483+ BaseType_t xAlreadyYielded ;
74837484
74847485 traceENTER_ulTaskGenericNotifyTake ( uxIndexToWaitOn , xClearCountOnExit , xTicksToWait );
74857486
74867487 configASSERT ( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );
74877488
74887489 taskENTER_CRITICAL ();
7490+
7491+ /* Only block if the notification count is not already non-zero. */
7492+ if ( pxCurrentTCB -> ulNotifiedValue [ uxIndexToWaitOn ] == 0UL )
74897493 {
7490- /* Only block if the notification count is not already non-zero. */
7491- if ( pxCurrentTCB -> ulNotifiedValue [ uxIndexToWaitOn ] == 0UL )
7494+ /* Mark this task as waiting for a notification. */
7495+ pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION ;
7496+
7497+ if ( xTicksToWait > ( TickType_t ) 0 )
74927498 {
7493- /* Mark this task as waiting for a notification. */
7494- pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION ;
7499+ traceTASK_NOTIFY_TAKE_BLOCK ( uxIndexToWaitOn );
74957500
7496- if ( xTicksToWait > ( TickType_t ) 0 )
7501+ /* We MUST suspend the scheduler before exiting the critical
7502+ * section (i.e. before enabling interrupts).
7503+ *
7504+ * If we do not do so, a notification sent from an ISR, which
7505+ * happens after exiting the critical section and before
7506+ * suspending the scheduler, will get lost. The sequence of
7507+ * events will be:
7508+ * 1. Exit critical section.
7509+ * 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7510+ * task to the Ready list.
7511+ * 3. Suspend scheduler.
7512+ * 4. prvAddCurrentTaskToDelayedList moves the task to the
7513+ * delayed or suspended list.
7514+ * 5. Resume scheduler does not touch the task (because it is
7515+ * not on the pendingReady list), effectively losing the
7516+ * notification from the ISR.
7517+ *
7518+ * The same does not happen when we suspend the scheduler before
7519+ * exiting the critical section. The sequence of events in this
7520+ * case will be:
7521+ * 1. Suspend scheduler.
7522+ * 2. Exit critical section.
7523+ * 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7524+ * task to the pendingReady list as the scheduler is
7525+ * suspended.
7526+ * 4. prvAddCurrentTaskToDelayedList adds the task to delayed or
7527+ * suspended list. Note that this operation does not nullify
7528+ * the add to pendingReady list done in the above step because
7529+ * a different list item, namely xEventListItem, is used for
7530+ * adding the task to the pendingReady list. In other words,
7531+ * the task still remains on the pendingReady list.
7532+ * 5. Resume scheduler moves the task from pendingReady list to
7533+ * the Ready list.
7534+ */
7535+ vTaskSuspendAll ();
74977536 {
7537+ taskEXIT_CRITICAL ();
7538+
74987539 prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE );
7499- traceTASK_NOTIFY_TAKE_BLOCK ( uxIndexToWaitOn );
7540+ }
7541+ xAlreadyYielded = xTaskResumeAll ();
75007542
7501- /* All ports are written to allow a yield in a critical
7502- * section (some will yield immediately, others wait until the
7503- * critical section exits) - but it is not something that
7504- * application code should ever do. */
7543+ if ( xAlreadyYielded == pdFALSE )
7544+ {
75057545 taskYIELD_WITHIN_API ();
75067546 }
75077547 else
@@ -7511,10 +7551,13 @@ TickType_t uxTaskResetEventItemValue( void )
75117551 }
75127552 else
75137553 {
7514- mtCOVERAGE_TEST_MARKER ();
7554+ taskEXIT_CRITICAL ();
75157555 }
75167556 }
7517- taskEXIT_CRITICAL ();
7557+ else
7558+ {
7559+ taskEXIT_CRITICAL ();
7560+ }
75187561
75197562 taskENTER_CRITICAL ();
75207563 {
@@ -7557,34 +7600,73 @@ TickType_t uxTaskResetEventItemValue( void )
75577600 uint32_t * pulNotificationValue ,
75587601 TickType_t xTicksToWait )
75597602 {
7560- BaseType_t xReturn ;
7603+ BaseType_t xReturn , xAlreadyYielded ;
75617604
75627605 traceENTER_xTaskGenericNotifyWait ( uxIndexToWaitOn , ulBitsToClearOnEntry , ulBitsToClearOnExit , pulNotificationValue , xTicksToWait );
75637606
75647607 configASSERT ( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );
75657608
75667609 taskENTER_CRITICAL ();
7610+
7611+ /* Only block if a notification is not already pending. */
7612+ if ( pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED )
75677613 {
7568- /* Only block if a notification is not already pending. */
7569- if ( pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED )
7570- {
7571- /* Clear bits in the task's notification value as bits may get
7572- * set by the notifying task or interrupt. This can be used to
7573- * clear the value to zero. */
7574- pxCurrentTCB -> ulNotifiedValue [ uxIndexToWaitOn ] &= ~ulBitsToClearOnEntry ;
7614+ /* Clear bits in the task's notification value as bits may get
7615+ * set by the notifying task or interrupt. This can be used to
7616+ * clear the value to zero. */
7617+ pxCurrentTCB -> ulNotifiedValue [ uxIndexToWaitOn ] &= ~ulBitsToClearOnEntry ;
75757618
7576- /* Mark this task as waiting for a notification. */
7577- pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION ;
7619+ /* Mark this task as waiting for a notification. */
7620+ pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION ;
75787621
7579- if ( xTicksToWait > ( TickType_t ) 0 )
7622+ if ( xTicksToWait > ( TickType_t ) 0 )
7623+ {
7624+ traceTASK_NOTIFY_WAIT_BLOCK ( uxIndexToWaitOn );
7625+
7626+ /* We MUST suspend the scheduler before exiting the critical
7627+ * section (i.e. before enabling interrupts).
7628+ *
7629+ * If we do not do so, a notification sent from an ISR, which
7630+ * happens after exiting the critical section and before
7631+ * suspending the scheduler, will get lost. The sequence of
7632+ * events will be:
7633+ * 1. Exit critical section.
7634+ * 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7635+ * task to the Ready list.
7636+ * 3. Suspend scheduler.
7637+ * 4. prvAddCurrentTaskToDelayedList moves the task to the
7638+ * delayed or suspended list.
7639+ * 5. Resume scheduler does not touch the task (because it is
7640+ * not on the pendingReady list), effectively losing the
7641+ * notification from the ISR.
7642+ *
7643+ * The same does not happen when we suspend the scheduler before
7644+ * exiting the critical section. The sequence of events in this
7645+ * case will be:
7646+ * 1. Suspend scheduler.
7647+ * 2. Exit critical section.
7648+ * 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the
7649+ * task to the pendingReady list as the scheduler is
7650+ * suspended.
7651+ * 4. prvAddCurrentTaskToDelayedList adds the task to delayed or
7652+ * suspended list. Note that this operation does not nullify
7653+ * the add to pendingReady list done in the above step because
7654+ * a different list item, namely xEventListItem, is used for
7655+ * adding the task to the pendingReady list. In other words,
7656+ * the task still remains on the pendingReady list.
7657+ * 5. Resume scheduler moves the task from pendingReady list to
7658+ * the Ready list.
7659+ */
7660+ vTaskSuspendAll ();
75807661 {
7662+ taskEXIT_CRITICAL ();
7663+
75817664 prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE );
7582- traceTASK_NOTIFY_WAIT_BLOCK ( uxIndexToWaitOn );
7665+ }
7666+ xAlreadyYielded = xTaskResumeAll ();
75837667
7584- /* All ports are written to allow a yield in a critical
7585- * section (some will yield immediately, others wait until the
7586- * critical section exits) - but it is not something that
7587- * application code should ever do. */
7668+ if ( xAlreadyYielded == pdFALSE )
7669+ {
75887670 taskYIELD_WITHIN_API ();
75897671 }
75907672 else
@@ -7594,10 +7676,13 @@ TickType_t uxTaskResetEventItemValue( void )
75947676 }
75957677 else
75967678 {
7597- mtCOVERAGE_TEST_MARKER ();
7679+ taskEXIT_CRITICAL ();
75987680 }
75997681 }
7600- taskEXIT_CRITICAL ();
7682+ else
7683+ {
7684+ taskEXIT_CRITICAL ();
7685+ }
76017686
76027687 taskENTER_CRITICAL ();
76037688 {
0 commit comments