/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/hotspot/share/utilities/singleWriterSynchronizer.cpp
99 строк
4 KB
Kim Barrett
8367013: Add Atomic<T> to package/replace idiom of volatile var plus AtomicAccess:: operations
13 ноя 2025, 11:43
13 ноя 2025, 11:43
10220ed
Код
Авторство
О чём код?
/* * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" #include "utilities/singleWriterSynchronizer.hpp" SingleWriterSynchronizer::SingleWriterSynchronizer() : _enter(0), _exit(), // The initial value of 1 for _waiting_for puts it on the inactive // track, so no thread exiting a critical section will match it. _waiting_for(1), _wakeup() DEBUG_ONLY(COMMA _writers(0)) {} // Wait until all threads that entered a critical section before // synchronization have exited that critical section. void SingleWriterSynchronizer::synchronize() { // Side-effect in assert balanced by debug-only dec at end. assert(_writers.fetch_then_add(1u) == 0u, "multiple writers"); // We don't know anything about the muxing between this invocation // and invocations in other threads. We must start with the latest // _enter polarity, else we could clobber the wrong _exit value on // the first iteration. So fence to ensure everything here follows // whatever muxing was used. OrderAccess::fence(); uint value = _enter.load_relaxed(); // (1) Determine the old and new exit counters, based on the // polarity (bit0 value) of the on-entry enter counter. Atomic<uint>& new_exit = _exit[(value + 1) & 1]; // (2) Change the in-use exit counter to the new counter, by adding // 1 to the enter counter (flipping the polarity), meanwhile // "simultaneously" initializing the new exit counter to that enter // value. Note: The new exit counter is not being used by read // operations until this change of _enter succeeds. uint old; do { old = value; new_exit.store_relaxed(++value); value = _enter.compare_exchange(old, value); } while (old != value); // Critical sections entered before we changed the polarity will use // the old exit counter. Critical sections entered after the change // will use the new exit counter. Atomic<uint>& old_exit = _exit[old & 1]; assert(&new_exit != &old_exit, "invariant"); // (3) Inform threads in in-progress critical sections that there is // a pending synchronize waiting. The thread that completes the // request (_exit value == old) will signal the _wakeup semaphore to // allow us to proceed. _waiting_for.store_relaxed(old); // Write of _waiting_for must precede read of _exit and associated // conditional semaphore wait. If they were re-ordered then a // critical section exit could miss the wakeup request, failing to // signal us while we're waiting. OrderAccess::fence(); // (4) Wait for all the critical sections started before the change // to complete, e.g. for the value of old_exit to catch up with old. // Loop because there could be pending wakeups unrelated to this // synchronize request. while (old != old_exit.load_acquire()) { _wakeup.wait(); } // (5) Drain any pending wakeups. A critical section exit may have // completed our request and seen our _waiting_for before we checked // for completion. There are also possible (though rare) spurious // wakeup signals in the timing gap between changing the _enter // polarity and setting _waiting_for. Enough of any of those could // lead to semaphore overflow. This doesn't guarantee no unrelated // wakeups for the next wait, but prevents unbounded accumulation. while (_wakeup.trywait()) {} assert(_writers.sub_then_fetch(1u) == 0u, "invariant"); }