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