cpp/profiler/SignalHandler.h (103 lines of code) (raw):

/** * Copyright 2004-present, Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <phaser.h> #include <setjmp.h> #include <signal.h> #include <atomic> #include <mutex> namespace facebook { namespace profilo { namespace profiler { // // SignalHandler provides signal handling niceties for use by SamplingProfiler. // In particular, it has the following main facilities: // // 1. Ability to look up associated pointers from within a signal handler // context (Set/GetData). // 2. Stronger guarantees when disabling the signal handler (all concurrent // are guaranteed to have exited when Disable() returns). // 3. RAII helpers for use inside signal handlers (HandlerScope). // 4. Correct installation of the signal handler before all other signal // handlers when running on Android. // // Signal handlers should use the EnterHandler static method to announce // themselves and gain partial access to the relevant SignalHandler instance // (via the methods on the HandlerScope). // // Once a SignalHandler has been installed for a particular signal, the handler // function (i.e. HandlerPtr value passed to Initialize) *cannot* be changed. // This is the primary reason this implementation is only useful for // SamplingProfiler's purposes. // class SignalHandler { public: // // Enable processing of signals by this SignalHandler. // Installs the signal handler, if not yet installed. // Calls to HandlerScope::IsEnabled will return true after this. // void Enable(); // // Disables processing of signals by this SignalHandler. // Blocks until all signal handlers running at the time of this call // exit their respective HandlerScopes. // void Disable(); void SetData(void* data) { data_.store(data, std::memory_order_relaxed); } class HandlerScope { private: explicit HandlerScope(SignalHandler& handler) : handler_(handler) { enabled_ = false; if (!handler_.enabled_.load(std::memory_order_relaxed)) { return; } phase_ = phaser_enter(&handler_.phaser_); enabled_ = true; } SignalHandler& handler_; bool enabled_; phaser_phase phase_; friend class SignalHandler; public: HandlerScope(HandlerScope&& other) : handler_(other.handler_), enabled_(other.enabled_), phase_(other.phase_) { other.enabled_ = false; } HandlerScope& operator=(HandlerScope&& other) { enabled_ = other.enabled_; phase_ = other.phase_; other.enabled_ = false; return *this; } HandlerScope(const HandlerScope&) = delete; HandlerScope& operator=(const HandlerScope&) = delete; virtual ~HandlerScope() { if (enabled_) { phaser_exit(&handler_.phaser_, phase_); } } bool IsEnabled() const { return enabled_; } void* GetData() const { return handler_.data_.load(std::memory_order_relaxed); } // // Exits this HandlerScope, then performs a siglongjmp call. // void siglongjmp(sigjmp_buf& env, int val) { if (enabled_) { phaser_exit(&handler_.phaser_, phase_); enabled_ = false; } ::siglongjmp(env, val); } // // Exits this HandlerScope, then calls the previous signal handler. // void CallPreviousHandler(int signum, siginfo_t* info, void* ucontext) { if (enabled_) { phaser_exit(&handler_.phaser_, phase_); enabled_ = false; } handler_.CallPreviousHandler(signum, info, ucontext); } }; using HandlerPtr = void (*)(HandlerScope, int, siginfo_t*, void*); static SignalHandler& Initialize(int signum, HandlerPtr handler); // // Call first thing from a registered signal handler function. // static SignalHandler::HandlerScope EnterHandler(int signum); private: using SigactionPtr = void (*)(int, siginfo_t*, void*); friend class SignalHandler::HandlerScope; friend class SignalHandlerTestAccessor; SignalHandler(int signum, HandlerPtr handler); SignalHandler(const SignalHandler&) = delete; SignalHandler& operator=(const SignalHandler&) = delete; virtual ~SignalHandler(); static constexpr auto kSignalHandlerFlags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK | SA_RESTART; // global storage to facilitate looking up a SignalHandler instance from // within a signal handler context static std::atomic<SignalHandler*> globalRegisteredSignalHandlers[NSIG]; static phaser_t globalPhaser; static std::once_flag globalPhaserInit; int signum_; HandlerPtr handler_; std::atomic<void*> data_; phaser_t phaser_; std::atomic<bool> enabled_; struct sigaction old_sigaction_; static void AndroidAwareSigaction( int signum, SigactionPtr handler, struct sigaction* oldact); static void UniversalHandler(int signum, siginfo_t* siginfo, void* ucontext); void CallPreviousHandler(int signum, siginfo_t*, void*); }; } // namespace profiler } // namespace profilo } // namespace facebook