@@ -5198,7 +5198,7 @@ void vTaskPlaceOnEventList( List_t * const pxEventList,
5198
5198
5199
5199
configASSERT ( pxEventList );
5200
5200
5201
- /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
5201
+ /* THIS FUNCTION MUST BE CALLED WITH THE
5202
5202
* SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
5203
5203
5204
5204
/* Place the event list item of the TCB in the appropriate event list.
@@ -7480,28 +7480,68 @@ TickType_t uxTaskResetEventItemValue( void )
7480
7480
TickType_t xTicksToWait )
7481
7481
{
7482
7482
uint32_t ulReturn ;
7483
+ BaseType_t xAlreadyYielded ;
7483
7484
7484
7485
traceENTER_ulTaskGenericNotifyTake ( uxIndexToWaitOn , xClearCountOnExit , xTicksToWait );
7485
7486
7486
7487
configASSERT ( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );
7487
7488
7488
7489
taskENTER_CRITICAL ();
7490
+
7491
+ /* Only block if the notification count is not already non-zero. */
7492
+ if ( pxCurrentTCB -> ulNotifiedValue [ uxIndexToWaitOn ] == 0UL )
7489
7493
{
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 )
7492
7498
{
7493
- /* Mark this task as waiting for a notification. */
7494
- pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION ;
7499
+ traceTASK_NOTIFY_TAKE_BLOCK ( uxIndexToWaitOn );
7495
7500
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 ();
7497
7536
{
7537
+ taskEXIT_CRITICAL ();
7538
+
7498
7539
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE );
7499
- traceTASK_NOTIFY_TAKE_BLOCK ( uxIndexToWaitOn );
7540
+ }
7541
+ xAlreadyYielded = xTaskResumeAll ();
7500
7542
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
+ {
7505
7545
taskYIELD_WITHIN_API ();
7506
7546
}
7507
7547
else
@@ -7511,10 +7551,13 @@ TickType_t uxTaskResetEventItemValue( void )
7511
7551
}
7512
7552
else
7513
7553
{
7514
- mtCOVERAGE_TEST_MARKER ();
7554
+ taskEXIT_CRITICAL ();
7515
7555
}
7516
7556
}
7517
- taskEXIT_CRITICAL ();
7557
+ else
7558
+ {
7559
+ taskEXIT_CRITICAL ();
7560
+ }
7518
7561
7519
7562
taskENTER_CRITICAL ();
7520
7563
{
@@ -7557,34 +7600,73 @@ TickType_t uxTaskResetEventItemValue( void )
7557
7600
uint32_t * pulNotificationValue ,
7558
7601
TickType_t xTicksToWait )
7559
7602
{
7560
- BaseType_t xReturn ;
7603
+ BaseType_t xReturn , xAlreadyYielded ;
7561
7604
7562
7605
traceENTER_xTaskGenericNotifyWait ( uxIndexToWaitOn , ulBitsToClearOnEntry , ulBitsToClearOnExit , pulNotificationValue , xTicksToWait );
7563
7606
7564
7607
configASSERT ( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES );
7565
7608
7566
7609
taskENTER_CRITICAL ();
7610
+
7611
+ /* Only block if a notification is not already pending. */
7612
+ if ( pxCurrentTCB -> ucNotifyState [ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED )
7567
7613
{
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 ;
7575
7618
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 ;
7578
7621
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 ();
7580
7661
{
7662
+ taskEXIT_CRITICAL ();
7663
+
7581
7664
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE );
7582
- traceTASK_NOTIFY_WAIT_BLOCK ( uxIndexToWaitOn );
7665
+ }
7666
+ xAlreadyYielded = xTaskResumeAll ();
7583
7667
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
+ {
7588
7670
taskYIELD_WITHIN_API ();
7589
7671
}
7590
7672
else
@@ -7594,10 +7676,13 @@ TickType_t uxTaskResetEventItemValue( void )
7594
7676
}
7595
7677
else
7596
7678
{
7597
- mtCOVERAGE_TEST_MARKER ();
7679
+ taskEXIT_CRITICAL ();
7598
7680
}
7599
7681
}
7600
- taskEXIT_CRITICAL ();
7682
+ else
7683
+ {
7684
+ taskEXIT_CRITICAL ();
7685
+ }
7601
7686
7602
7687
taskENTER_CRITICAL ();
7603
7688
{
0 commit comments