11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
61cb0ef41Sopenharmony_ci#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <atomic>
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cinamespace cppgc {
111cb0ef41Sopenharmony_cinamespace internal {
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci// A flag which provides a fast check whether a scope may be entered on the
141cb0ef41Sopenharmony_ci// current thread, without needing to access thread-local storage or mutex.  Can
151cb0ef41Sopenharmony_ci// have false positives (i.e., spuriously report that it might be entered), so
161cb0ef41Sopenharmony_ci// it is expected that this will be used in tandem with a precise check that the
171cb0ef41Sopenharmony_ci// scope is in fact entered on that thread.
181cb0ef41Sopenharmony_ci//
191cb0ef41Sopenharmony_ci// Example:
201cb0ef41Sopenharmony_ci//   g_frobnicating_flag.MightBeEntered() &&
211cb0ef41Sopenharmony_ci//   ThreadLocalFrobnicator().IsFrobnicating()
221cb0ef41Sopenharmony_ci//
231cb0ef41Sopenharmony_ci// Relaxed atomic operations are sufficient, since:
241cb0ef41Sopenharmony_ci// - all accesses remain atomic
251cb0ef41Sopenharmony_ci// - each thread must observe its own operations in order
261cb0ef41Sopenharmony_ci// - no thread ever exits the flag more times than it enters (if used correctly)
271cb0ef41Sopenharmony_ci// And so if a thread observes zero, it must be because it has observed an equal
281cb0ef41Sopenharmony_ci// number of exits as entries.
291cb0ef41Sopenharmony_ciclass AtomicEntryFlag final {
301cb0ef41Sopenharmony_ci public:
311cb0ef41Sopenharmony_ci  void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); }
321cb0ef41Sopenharmony_ci  void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); }
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci  // Returns false only if the current thread is not between a call to Enter
351cb0ef41Sopenharmony_ci  // and a call to Exit. Returns true if this thread or another thread may
361cb0ef41Sopenharmony_ci  // currently be in the scope guarded by this flag.
371cb0ef41Sopenharmony_ci  bool MightBeEntered() const {
381cb0ef41Sopenharmony_ci    return entries_.load(std::memory_order_relaxed) != 0;
391cb0ef41Sopenharmony_ci  }
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci private:
421cb0ef41Sopenharmony_ci  std::atomic_int entries_{0};
431cb0ef41Sopenharmony_ci};
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci}  // namespace internal
461cb0ef41Sopenharmony_ci}  // namespace cppgc
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci#endif  // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
49