mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
Merge branch 'fix/freertos-linux-simulator' into 'master'
fix(freertos): discard stale wake events on linux port context switch Closes IDF-15882 See merge request espressif/esp-idf!50285
This commit is contained in:
@@ -219,6 +219,33 @@ static void linux_port_switch_context(TaskHandle_t current_task_hdl)
|
||||
* in its initial event_wait (linux_port_task_runner), so we must
|
||||
* signal it even though current_thread == next_thread. */
|
||||
if (next_thread != current_thread || !s_scheduler_started) {
|
||||
/* Discard any stale wake on the task being switched out.
|
||||
*
|
||||
* Because tasks are pthreads that cannot be forcibly paused,
|
||||
* the port can only "unschedule" a task by choosing a different
|
||||
* next task; the outgoing task keeps running until it next
|
||||
* blocks itself in event_wait (e.g. via vPortYield). If, while
|
||||
* it was unscheduled, the scheduler already switched back into
|
||||
* it (event_signal in a later switch) without the task ever
|
||||
* having parked in event_wait, that signal is never consumed
|
||||
* and event_triggered stays latched. Its next voluntary block
|
||||
* would then return immediately instead of blocking (e.g.
|
||||
* vTaskDelay(100ms) returning in 0ms).
|
||||
*
|
||||
* Clearing here, under s_port_mutex and atomically with the
|
||||
* scheduling decision, drops that latched-but-unconsumed wake.
|
||||
* It is safe: a legitimate wake can only be delivered later,
|
||||
* when the scheduler next selects this task as next_thread.
|
||||
*
|
||||
* Reached only for a genuine switch to a different task:
|
||||
* entering this block with next_thread == current_thread
|
||||
* happens solely on the first switch (!s_scheduler_started),
|
||||
* which the current_thread NULL-check below also tolerates.
|
||||
* The NULL-check additionally guards the deleted-task path
|
||||
* where the outgoing task has no thread mapping. */
|
||||
if (current_thread) {
|
||||
event_clear(current_thread->ev);
|
||||
}
|
||||
linux_port_unblock_thread(next_thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,12 @@ void event_signal(event_t *ev)
|
||||
pthread_cond_signal(&ev->cond);
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/* Discard a pending signal that was never consumed by a wait */
|
||||
void event_clear(event_t *ev)
|
||||
{
|
||||
pthread_mutex_lock(&ev->mutex);
|
||||
ev->event_triggered = false;
|
||||
pthread_mutex_unlock(&ev->mutex);
|
||||
}
|
||||
|
||||
@@ -92,6 +92,13 @@ bool event_wait_timed(event_t *ev, time_t ms);
|
||||
*/
|
||||
void event_signal(event_t *ev);
|
||||
|
||||
/**
|
||||
* @brief Discard a pending signal that was never consumed by a wait
|
||||
*
|
||||
* @param ev
|
||||
*/
|
||||
void event_clear(event_t *ev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user