From f264341bacd7f8aae41772cc993f9741d68d59a1 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 7 Jul 2026 12:54:23 +0000 Subject: [PATCH] 8387490: G1: Dynamically creating worker threads exposes memory visibility race Reviewed-by: aboldtch, ayang --- src/hotspot/share/gc/shared/workerThread.cpp | 20 ++++++++++++-------- src/hotspot/share/gc/shared/workerThread.hpp | 8 ++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index 35749452c85..94d0d904340 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -103,7 +103,7 @@ bool WorkerThreads::allow_inject_creation_failure() const { return false; } - if (_created_workers == 0) { + if (_created_workers.load_relaxed() == 0) { // Never allow creation failures of the first worker, it will cause the VM to exit return false; } @@ -135,18 +135,20 @@ uint WorkerThreads::set_active_workers(uint num_workers) { "Invalid number of active workers %u (should be 1-%u)", num_workers, _max_workers); - while (_created_workers < num_workers) { - WorkerThread* const worker = create_worker(_created_workers); + uint local_created_workers = created_workers(); + while (local_created_workers < num_workers) { + WorkerThread* const worker = create_worker(local_created_workers); if (worker == nullptr) { log_error(gc, task)("Failed to create worker thread"); break; } - _workers[_created_workers] = worker; - _created_workers++; + _workers[local_created_workers] = worker; + local_created_workers++; + _created_workers.release_store(local_created_workers); } - _active_workers = MIN2(_created_workers, num_workers); + _active_workers = MIN2(local_created_workers, num_workers); log_trace(gc, task)("%s: using %d out of %d workers", _name, _active_workers, _max_workers); @@ -154,14 +156,16 @@ uint WorkerThreads::set_active_workers(uint num_workers) { } void WorkerThreads::threads_do(ThreadClosure* tc) const { - for (uint i = 0; i < _created_workers; i++) { + uint local_created_workers = created_workers(); + for (uint i = 0; i < local_created_workers; i++) { tc->do_thread(_workers[i]); } } template void WorkerThreads::threads_do_f(Function function) const { - for (uint i = 0; i < _created_workers; i++) { + uint local_created_workers = created_workers(); + for (uint i = 0; i < local_created_workers; i++) { function(_workers[i]); } } diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index 003ce8a2959..6ed28e5b9b7 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -88,7 +88,11 @@ private: const char* const _name; WorkerThread** _workers; const uint _max_workers; - uint _created_workers; + // _created_workers publishes the initialized prefix of _workers. + // Writers release-store to it after initializing an entry. Readers + // load-acquire before accessing _workers to not access uninitalized + // data. + Atomic _created_workers; uint _active_workers; WorkerTaskDispatcher _dispatcher; @@ -107,7 +111,7 @@ public: bool allow_inject_creation_failure() const; uint max_workers() const { return _max_workers; } - uint created_workers() const { return _created_workers; } + uint created_workers() const { return _created_workers.load_acquire(); } uint active_workers() const { return _active_workers; } uint set_active_workers(uint num_workers);