From c1181032c2262b631e9e99d929b0bc46b65ee77e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 7 Jul 2022 06:29:09 -0400 Subject: [PATCH] fix freeze on `@threads` loop exit (#45899) Closes #45626, hopefully. (cherry picked from commit f7e0c7eeff59a920d4b836c2af832e6622c84157) --- src/jl_uv.c | 1 + src/partr.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index d2a78c26bbc72..726290605ee32 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -60,6 +60,7 @@ void JL_UV_LOCK(void) } else { jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, 1); + jl_fence(); // [^store_buffering_2] jl_wake_libuv(); JL_LOCK(&jl_uv_mutex); jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, -1); diff --git a/src/partr.c b/src/partr.c index c8cc3245ebb4c..ddba203b92b1d 100644 --- a/src/partr.c +++ b/src/partr.c @@ -40,7 +40,14 @@ static const int16_t sleeping = 1; // * 2a: `multiq_insert` // * 2b: `jl_atomic_load_relaxed(&ptls->sleep_check_state)` in `jl_wakeup_thread` returns `not_sleeping` // i.e., the dequeuer misses the enqueue and enqueuer misses the sleep state transition. - +// [^store_buffering_2]: and also +// * Enqueuer: +// * 1a: `jl_atomic_store_relaxed(jl_uv_n_waiters, 1)` in `JL_UV_LOCK` +// * 1b: "cheap read" of `handle->pending` in `uv_async_send` (via `JL_UV_LOCK`) loads `0` +// * Dequeuer: +// * 2a: store `2` to `handle->pending` in `uv_async_send` (via `JL_UV_LOCK` in `jl_task_get_next`) +// * 2b: `jl_atomic_load_relaxed(jl_uv_n_waiters)` in `jl_task_get_next` returns `0` +// i.e., the dequeuer misses the `n_waiters` is set and enqueuer misses the `uv_stop` flag (in `signal_async`) transition to cleared JULIA_DEBUG_SLEEPWAKE( uint64_t wakeup_enter; @@ -462,7 +469,7 @@ static int may_sleep(jl_ptls_t ptls) JL_NOTSAFEPOINT // by the thread itself. As a result, if this returns false, it will // continue returning false. If it returns true, we know the total // modification order of the fences. - jl_fence(); // [^store_buffering_1] + jl_fence(); // [^store_buffering_1] [^store_buffering_2] return jl_atomic_load_relaxed(&ptls->sleep_check_state) == sleeping; }