1 /*
2  * Copyright (C) 2021 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 #include "perfetto/ext/base/ctrl_c_handler.h"
18 
19 #include "perfetto/base/build_config.h"
20 #include "perfetto/base/compiler.h"
21 #include "perfetto/base/logging.h"
22 
23 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
24 #include <Windows.h>
25 #include <io.h>
26 #else
27 #include <signal.h>
28 #include <unistd.h>
29 #endif
30 
31 namespace perfetto {
32 namespace base {
33 
34 namespace {
35 CtrlCHandlerFunction g_handler = nullptr;
36 }
37 
InstallCtrCHandler(CtrlCHandlerFunction handler)38 void InstallCtrCHandler(CtrlCHandlerFunction handler) {
39   PERFETTO_CHECK(g_handler == nullptr);
40   g_handler = handler;
41 
42 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
43   auto trampoline = [](DWORD type) -> int {
44     if (type == CTRL_C_EVENT) {
45       g_handler();
46       return true;
47     }
48     return false;
49   };
50   ::SetConsoleCtrlHandler(trampoline, true);
51 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
52     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
53     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
54   // Setup signal handler.
55   struct sigaction sa {};
56 
57 // Glibc headers for sa_sigaction trigger this.
58 #pragma GCC diagnostic push
59 #if defined(__clang__)
60 #pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
61 #endif
62   sa.sa_handler = [](int) { g_handler(); };
63   sa.sa_flags = static_cast<decltype(sa.sa_flags)>(SA_RESETHAND | SA_RESTART);
64 #pragma GCC diagnostic pop
65   sigaction(SIGINT, &sa, nullptr);
66   sigaction(SIGTERM, &sa, nullptr);
67 #else
68   // Do nothing on NaCL and Fuchsia.
69   ignore_result(handler);
70 #endif
71 }
72 
73 }  // namespace base
74 }  // namespace perfetto
75