[dawn][common] Add FetchMax helpers for atomic max. Change-Id: I5ad1a97eb7839d957b0e24497f1c5693e8d2ffe4 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/247998 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Loko Kung <lokokung@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/common/Atomic.h b/src/dawn/common/Atomic.h new file mode 100644 index 0000000..f585509 --- /dev/null +++ b/src/dawn/common/Atomic.h
@@ -0,0 +1,50 @@ +// Copyright 2025 The Dawn & Tint Authors +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef SRC_DAWN_COMMON_ATOMIC_H_ +#define SRC_DAWN_COMMON_ATOMIC_H_ + +#include <atomic> +#include <concepts> + +namespace dawn { + +// Equivalent to C++ stdlib's fetch_max that is only available in C++26 and beyond. This returns the +// value preceding the effects of this function. +template <typename T> + requires std::totally_ordered<T> +T FetchMax(std::atomic<T>& t, T arg) { + // Atomically set |t| to |arg| if |arg| > |t|. + T current = t.load(std::memory_order::acquire); + while (arg > current && t.compare_exchange_weak(current, arg, std::memory_order::acq_rel)) { + } + return current; +} + +} // namespace dawn + +#endif // SRC_DAWN_COMMON_RESULT_H_
diff --git a/src/dawn/common/BUILD.gn b/src/dawn/common/BUILD.gn index 461d726..e10e3d2 100644 --- a/src/dawn/common/BUILD.gn +++ b/src/dawn/common/BUILD.gn
@@ -268,6 +268,7 @@ "Alloc.h", "Assert.cpp", "Assert.h", + "Atomic.h", "BitSetRangeIterator.h", "Compiler.h", "Constants.h",
diff --git a/src/dawn/common/CMakeLists.txt b/src/dawn/common/CMakeLists.txt index 0360786..cfa2747 100644 --- a/src/dawn/common/CMakeLists.txt +++ b/src/dawn/common/CMakeLists.txt
@@ -48,6 +48,7 @@ "AlignedAlloc.h" "Alloc.h" "Assert.h" + "Atomic.h" "BitSetRangeIterator.h" "Compiler.h" "Constants.h"
diff --git a/src/dawn/native/EventManager.cpp b/src/dawn/native/EventManager.cpp index 50f85f1..1865258 100644 --- a/src/dawn/native/EventManager.cpp +++ b/src/dawn/native/EventManager.cpp
@@ -35,6 +35,7 @@ #include "absl/strings/str_format.h" #include "dawn/common/Assert.h" +#include "dawn/common/Atomic.h" #include "dawn/common/FutureUtils.h" #include "dawn/common/Log.h" #include "dawn/native/ChainUtils.h" @@ -368,11 +369,7 @@ return; } if (event->mCallbackMode != wgpu::CallbackMode::WaitAnyOnly) { - FutureID lastProcessedEventID = mLastProcessEventID.load(std::memory_order_acquire); - while (lastProcessedEventID < futureID && - !mLastProcessEventID.compare_exchange_weak(lastProcessedEventID, futureID, - std::memory_order_acq_rel)) { - } + FetchMax(mLastProcessEventID, futureID); } (*events)->emplace(futureID, std::move(event)); });
diff --git a/src/dawn/native/ExecutionQueue.cpp b/src/dawn/native/ExecutionQueue.cpp index 3fb78aa..4645106 100644 --- a/src/dawn/native/ExecutionQueue.cpp +++ b/src/dawn/native/ExecutionQueue.cpp
@@ -31,6 +31,8 @@ #include <utility> #include <vector> +#include "dawn/common/Atomic.h" + namespace dawn::native { ExecutionSerial ExecutionQueueBase::GetPendingCommandSerial() const { @@ -53,11 +55,8 @@ ExecutionSerial(mLastSubmittedSerial.load(std::memory_order_acquire))); // Atomically set mCompletedSerial to completedSerial if completedSerial is larger. - uint64_t current = mCompletedSerial.load(std::memory_order_acquire); - while (uint64_t(completedSerial) > current && - !mCompletedSerial.compare_exchange_weak(current, uint64_t(completedSerial), - std::memory_order_acq_rel)) { - } + FetchMax(mCompletedSerial, uint64_t(completedSerial)); + // TODO(crbug.com/421945313): We should call |UpdateCompletedSerial| here also, but since some // backends rely on the device lock for safe use of |CheckAndUpdateCompletedSerials|, we // separate that call out for now. @@ -74,11 +73,7 @@ void ExecutionQueueBase::UpdateCompletedSerial(ExecutionSerial completedSerial) { // Atomically set mCompletedSerial to completedSerial if completedSerial is larger. - uint64_t current = mCompletedSerial.load(std::memory_order_acquire); - while (uint64_t(completedSerial) > current && - !mCompletedSerial.compare_exchange_weak(current, uint64_t(completedSerial), - std::memory_order_acq_rel)) { - } + FetchMax(mCompletedSerial, uint64_t(completedSerial)); std::vector<Task> pending; mWaitingTasks.Use([&](auto tasks) {