blob: ef4473f7aaef662ed374348585d8025a642dd4dc [file] [log] [blame]
Colin Cross1369ba42016-04-26 16:51:32 -07001/*
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
Colin Cross8837c722019-03-20 16:02:54 -070027#include "Allocator.h"
Colin Cross1369ba42016-04-26 16:51:32 -070028#include "log.h"
29
Colin Cross1fa81f52017-06-21 13:13:00 -070030namespace android {
31
Colin Cross1369ba42016-04-26 16:51:32 -070032class ScopedSignalHandler {
33 public:
34 using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
35
Colin Cross8837c722019-03-20 16:02:54 -070036 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 }
Colin Cross401319a2017-06-22 10:50:05 -070042 ~ScopedSignalHandler() { reset(); }
Colin Cross1369ba42016-04-26 16:51:32 -070043
44 template <class F>
45 void install(int signal, F&& f) {
Colin Cross3c444842017-06-29 17:12:01 -070046 if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
Colin Cross1369ba42016-04-26 16:51:32 -070047
Colin Cross8837c722019-03-20 16:02:54 -070048 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); });
Colin Cross1369ba42016-04-26 16:51:32 -070054
Christopher Ferris56b8d862017-05-03 17:34:29 -070055 struct sigaction act {};
Colin Cross8837c722019-03-20 16:02:54 -070056 act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
57 ((*handler_map_)[signal])(signal, si, uctx);
58 };
Colin Cross1369ba42016-04-26 16:51:32 -070059 act.sa_flags = SA_SIGINFO;
60
61 int ret = sigaction(signal, &act, &old_act_);
62 if (ret < 0) {
Christopher Ferris56b8d862017-05-03 17:34:29 -070063 MEM_LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
Colin Cross1369ba42016-04-26 16:51:32 -070064 }
65
66 signal_ = signal;
67 }
68
69 void reset() {
70 if (signal_ != -1) {
71 int ret = sigaction(signal_, &old_act_, NULL);
72 if (ret < 0) {
Christopher Ferris56b8d862017-05-03 17:34:29 -070073 MEM_ALOGE("failed to uninstall segfault handler");
Colin Cross1369ba42016-04-26 16:51:32 -070074 }
Colin Cross8837c722019-03-20 16:02:54 -070075
76 handler_map_->erase(signal_);
77 if (handler_map_->empty()) {
78 handler_map_.reset();
79 }
Colin Cross1369ba42016-04-26 16:51:32 -070080 signal_ = -1;
81 }
82 }
83
Colin Cross1369ba42016-04-26 16:51:32 -070084 private:
85 using SignalFn = std::function<void(int, siginfo_t*, void*)>;
Colin Cross8837c722019-03-20 16:02:54 -070086 using SignalFnMap = allocator::unordered_map<int, SignalFn>;
Colin Cross1369ba42016-04-26 16:51:32 -070087 DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
Colin Cross1369ba42016-04-26 16:51:32 -070088 int signal_;
89 struct sigaction old_act_;
Colin Cross8837c722019-03-20 16:02:54 -070090 static Allocator<SignalFnMap>::unique_ptr handler_map_;
Colin Cross1369ba42016-04-26 16:51:32 -070091};
92
Colin Cross1fa81f52017-06-21 13:13:00 -070093} // namespace android
94
Colin Cross401319a2017-06-22 10:50:05 -070095#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_