1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkOnce_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkOnce_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkThreadAnnotations.h" 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker #include <atomic> 14*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 15*c8dee2aaSAndroid Build Coastguard Worker #include <utility> 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker // SkOnce provides call-once guarantees for Skia, much like std::once_flag/std::call_once(). 18*c8dee2aaSAndroid Build Coastguard Worker // 19*c8dee2aaSAndroid Build Coastguard Worker // There should be no particularly error-prone gotcha use cases when using SkOnce. 20*c8dee2aaSAndroid Build Coastguard Worker // It works correctly as a class member, a local, a global, a function-scoped static, whatever. 21*c8dee2aaSAndroid Build Coastguard Worker 22*c8dee2aaSAndroid Build Coastguard Worker class SkOnce { 23*c8dee2aaSAndroid Build Coastguard Worker public: 24*c8dee2aaSAndroid Build Coastguard Worker constexpr SkOnce() = default; 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker template <typename Fn, typename... Args> operator()27*c8dee2aaSAndroid Build Coastguard Worker void operator()(Fn&& fn, Args&&... args) { 28*c8dee2aaSAndroid Build Coastguard Worker auto state = fState.load(std::memory_order_acquire); 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard Worker if (state == Done) { 31*c8dee2aaSAndroid Build Coastguard Worker return; 32*c8dee2aaSAndroid Build Coastguard Worker } 33*c8dee2aaSAndroid Build Coastguard Worker 34*c8dee2aaSAndroid Build Coastguard Worker // If it looks like no one has started calling fn(), try to claim that job. 35*c8dee2aaSAndroid Build Coastguard Worker if (state == NotStarted && fState.compare_exchange_strong(state, Claimed, 36*c8dee2aaSAndroid Build Coastguard Worker std::memory_order_relaxed, 37*c8dee2aaSAndroid Build Coastguard Worker std::memory_order_relaxed)) { 38*c8dee2aaSAndroid Build Coastguard Worker // Great! We'll run fn() then notify the other threads by releasing Done into fState. 39*c8dee2aaSAndroid Build Coastguard Worker fn(std::forward<Args>(args)...); 40*c8dee2aaSAndroid Build Coastguard Worker return fState.store(Done, std::memory_order_release); 41*c8dee2aaSAndroid Build Coastguard Worker } 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker // Some other thread is calling fn(). 44*c8dee2aaSAndroid Build Coastguard Worker // We'll just spin here acquiring until it releases Done into fState. 45*c8dee2aaSAndroid Build Coastguard Worker SK_POTENTIALLY_BLOCKING_REGION_BEGIN; 46*c8dee2aaSAndroid Build Coastguard Worker while (fState.load(std::memory_order_acquire) != Done) { /*spin*/ } 47*c8dee2aaSAndroid Build Coastguard Worker SK_POTENTIALLY_BLOCKING_REGION_END; 48*c8dee2aaSAndroid Build Coastguard Worker } 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Worker private: 51*c8dee2aaSAndroid Build Coastguard Worker enum State : uint8_t { NotStarted, Claimed, Done}; 52*c8dee2aaSAndroid Build Coastguard Worker std::atomic<uint8_t> fState{NotStarted}; 53*c8dee2aaSAndroid Build Coastguard Worker }; 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker #endif // SkOnce_DEFINED 56