llvm-project/compiler-rt/lib/xray/xray_recursion_guard.h
Dean Michael Berris c561970b27 [XRay][compiler-rt] Refactor recursion guard for Basic and FDR Mode
Summary:
This change extracts the recursion guard implementation from FDR Mode
and updates it to do the following:

- Do the atomic operation correctly to be signal-handler safe.

- Make it usable in both FDR and Basic Modes.

Before this change, the recursion guard relied on an unsynchronised read
and write on a volatile thread-local. A signal handler could then run in
between the read and the write, and then be able to run instrumented
code as part of the signal handling. Using an atomic exchange instead
fixes that by doing a proper mutual exclusion even in the presence of
signal handling.

Reviewers: kpw, eizan, jfb

Reviewed By: eizan

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D47696

llvm-svn: 334064
2018-06-06 06:07:48 +00:00

58 lines
1.8 KiB
C++

//===-- xray_recursion_guard.h ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of XRay, a dynamic runtime instrumentation system.
//
//===----------------------------------------------------------------------===//
#ifndef XRAY_XRAY_RECURSION_GUARD_H
#define XRAY_XRAY_RECURSION_GUARD_H
#include "sanitizer_common/sanitizer_atomic.h"
namespace __xray {
/// The RecursionGuard is useful for guarding against signal handlers which are
/// also potentially calling XRay-instrumented functions. To use the
/// RecursionGuard, you'll typically need a thread_local atomic_uint8_t:
///
/// thread_local atomic_uint8_t Guard{0};
///
/// // In a handler function:
/// void handleArg0(int32_t F, XRayEntryType T) {
/// RecursionGuard G(Guard);
/// if (!G)
/// return; // Failed to acquire the guard.
/// ...
/// }
///
class RecursionGuard {
atomic_uint8_t &Running;
const bool Valid;
public:
explicit inline RecursionGuard(atomic_uint8_t &R)
: Running(R), Valid(!atomic_exchange(&R, 1, memory_order_acq_rel)) {}
inline RecursionGuard(const RecursionGuard &) = delete;
inline RecursionGuard(RecursionGuard &&) = delete;
inline RecursionGuard &operator=(const RecursionGuard &) = delete;
inline RecursionGuard &operator=(RecursionGuard &&) = delete;
explicit inline operator bool() const { return Valid; }
inline ~RecursionGuard() noexcept {
if (Valid)
atomic_store(&Running, 0, memory_order_release);
}
};
} // namespace __xray
#endif // XRAY_XRAY_RECURSION_GUARD_H