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