1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_ 18 #define LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_ 19 20 #include <errno.h> 21 #include <signal.h> 22 23 #include <functional> 24 25 #include "android-base/macros.h" 26 27 #include "Allocator.h" 28 #include "log.h" 29 30 namespace android { 31 32 class ScopedSignalHandler { 33 public: 34 using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>; 35 ScopedSignalHandler(Allocator<ScopedSignalHandler> allocator)36 explicit ScopedSignalHandler(Allocator<ScopedSignalHandler> allocator) : signal_(-1) { 37 if (handler_map_ == nullptr) { 38 Allocator<SignalFnMap> map_allocator = allocator; 39 handler_map_ = map_allocator.make_unique(allocator); 40 } 41 } ~ScopedSignalHandler()42 ~ScopedSignalHandler() { reset(); } 43 44 template <class F> install(int signal,F && f)45 void install(int signal, F&& f) { 46 if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed"); 47 48 if (handler_map_->find(signal) != handler_map_->end()) { 49 MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed for %d", signal); 50 } 51 52 (*handler_map_)[signal] = 53 SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); }); 54 55 struct sigaction act {}; 56 act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { 57 ((*handler_map_)[signal])(signal, si, uctx); 58 }; 59 act.sa_flags = SA_SIGINFO; 60 61 int ret = sigaction(signal, &act, &old_act_); 62 if (ret < 0) { 63 MEM_LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno)); 64 } 65 66 signal_ = signal; 67 } 68 reset()69 void reset() { 70 if (signal_ != -1) { 71 int ret = sigaction(signal_, &old_act_, NULL); 72 if (ret < 0) { 73 MEM_ALOGE("failed to uninstall segfault handler"); 74 } 75 76 handler_map_->erase(signal_); 77 if (handler_map_->empty()) { 78 handler_map_.reset(); 79 } 80 signal_ = -1; 81 } 82 } 83 84 private: 85 using SignalFn = std::function<void(int, siginfo_t*, void*)>; 86 using SignalFnMap = allocator::unordered_map<int, SignalFn>; 87 DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler); 88 int signal_; 89 struct sigaction old_act_; 90 static Allocator<SignalFnMap>::unique_ptr handler_map_; 91 }; 92 93 } // namespace android 94 95 #endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_ 96