1*ee754c2dSkamil //===-- xray_recursion_guard.h ---------------------------------*- C++ -*-===//
2*ee754c2dSkamil //
3*ee754c2dSkamil //                     The LLVM Compiler Infrastructure
4*ee754c2dSkamil //
5*ee754c2dSkamil // This file is distributed under the University of Illinois Open Source
6*ee754c2dSkamil // License. See LICENSE.TXT for details.
7*ee754c2dSkamil //
8*ee754c2dSkamil //===----------------------------------------------------------------------===//
9*ee754c2dSkamil //
10*ee754c2dSkamil // This file is a part of XRay, a dynamic runtime instrumentation system.
11*ee754c2dSkamil //
12*ee754c2dSkamil //===----------------------------------------------------------------------===//
13*ee754c2dSkamil #ifndef XRAY_XRAY_RECURSION_GUARD_H
14*ee754c2dSkamil #define XRAY_XRAY_RECURSION_GUARD_H
15*ee754c2dSkamil 
16*ee754c2dSkamil #include "sanitizer_common/sanitizer_atomic.h"
17*ee754c2dSkamil 
18*ee754c2dSkamil namespace __xray {
19*ee754c2dSkamil 
20*ee754c2dSkamil /// The RecursionGuard is useful for guarding against signal handlers which are
21*ee754c2dSkamil /// also potentially calling XRay-instrumented functions. To use the
22*ee754c2dSkamil /// RecursionGuard, you'll typically need a thread_local atomic_uint8_t:
23*ee754c2dSkamil ///
24*ee754c2dSkamil ///   thread_local atomic_uint8_t Guard{0};
25*ee754c2dSkamil ///
26*ee754c2dSkamil ///   // In a handler function:
27*ee754c2dSkamil ///   void handleArg0(int32_t F, XRayEntryType T) {
28*ee754c2dSkamil ///     RecursionGuard G(Guard);
29*ee754c2dSkamil ///     if (!G)
30*ee754c2dSkamil ///       return;  // Failed to acquire the guard.
31*ee754c2dSkamil ///     ...
32*ee754c2dSkamil ///   }
33*ee754c2dSkamil ///
34*ee754c2dSkamil class RecursionGuard {
35*ee754c2dSkamil   atomic_uint8_t &Running;
36*ee754c2dSkamil   const bool Valid;
37*ee754c2dSkamil 
38*ee754c2dSkamil public:
RecursionGuard(atomic_uint8_t & R)39*ee754c2dSkamil   explicit inline RecursionGuard(atomic_uint8_t &R)
40*ee754c2dSkamil       : Running(R), Valid(!atomic_exchange(&R, 1, memory_order_acq_rel)) {}
41*ee754c2dSkamil 
42*ee754c2dSkamil   inline RecursionGuard(const RecursionGuard &) = delete;
43*ee754c2dSkamil   inline RecursionGuard(RecursionGuard &&) = delete;
44*ee754c2dSkamil   inline RecursionGuard &operator=(const RecursionGuard &) = delete;
45*ee754c2dSkamil   inline RecursionGuard &operator=(RecursionGuard &&) = delete;
46*ee754c2dSkamil 
47*ee754c2dSkamil   explicit inline operator bool() const { return Valid; }
48*ee754c2dSkamil 
~RecursionGuard()49*ee754c2dSkamil   inline ~RecursionGuard() noexcept {
50*ee754c2dSkamil     if (Valid)
51*ee754c2dSkamil       atomic_store(&Running, 0, memory_order_release);
52*ee754c2dSkamil   }
53*ee754c2dSkamil };
54*ee754c2dSkamil 
55*ee754c2dSkamil } // namespace __xray
56*ee754c2dSkamil 
57*ee754c2dSkamil #endif // XRAY_XRAY_RECURSION_GUARD_H
58