blob: e2e23608d597dbd829e3dfeaf69927541f70b2cd [file] [log] [blame]
Elliott Hughese27955c2011-08-26 15:21:24 -07001/*
2 * Copyright (C) 2008 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 "signal_catcher.h"
18
19#include <pthread.h>
20#include <signal.h>
21#include <stdlib.h>
22#include <sys/time.h>
23#include <unistd.h>
24
25#include "heap.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070026#include "runtime.h"
Elliott Hughese27955c2011-08-26 15:21:24 -070027#include "thread.h"
28#include "utils.h"
29
30namespace art {
31
32bool SignalCatcher::halt_ = false;
33
34SignalCatcher::SignalCatcher() {
35 // Create a raw pthread; its start routine will attach to the runtime.
36 errno = pthread_create(&thread_, NULL, &Run, NULL);
37 if (errno != 0) {
38 PLOG(FATAL) << "pthread_create failed for signal catcher thread";
39 }
40}
41
42SignalCatcher::~SignalCatcher() {
43 // Since we know the thread is just sitting around waiting for signals
44 // to arrive, send it one.
45 halt_ = true;
46 pthread_kill(thread_, SIGQUIT);
47 pthread_join(thread_, NULL);
48}
49
50void SignalCatcher::HandleSigQuit() {
51 // TODO: suspend all threads
52
Elliott Hughesd92bec42011-09-02 17:04:36 -070053 std::stringstream os;
54 os << "\n"
55 << "\n"
56 << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
Elliott Hughese27955c2011-08-26 15:21:24 -070057
Elliott Hughesd92bec42011-09-02 17:04:36 -070058 std::string cmdline;
59 if (ReadFileToString("/proc/self/cmdline", &cmdline)) {
60 std::replace(cmdline.begin(), cmdline.end(), '\0', ' ');
61 os << "Cmd line: " << cmdline << "\n";
62 }
Elliott Hughese27955c2011-08-26 15:21:24 -070063
Elliott Hughesd92bec42011-09-02 17:04:36 -070064 Runtime* runtime = Runtime::Current();
65 runtime->DumpStatistics(os);
66 runtime->GetThreadList()->Dump(os);
Elliott Hughese27955c2011-08-26 15:21:24 -070067
Elliott Hughesd92bec42011-09-02 17:04:36 -070068 std::string maps;
69 if (ReadFileToString("/proc/self/maps", &maps)) {
70 os << "/proc/self/maps:\n" << maps;
71 }
72
73 os << "----- end " << getpid() << " -----";
Elliott Hughese27955c2011-08-26 15:21:24 -070074
75 // TODO: resume all threads
76
Elliott Hughesd92bec42011-09-02 17:04:36 -070077 LOG(INFO) << os.str();
Elliott Hughese27955c2011-08-26 15:21:24 -070078}
79
80void SignalCatcher::HandleSigUsr1() {
81 LOG(INFO) << "SIGUSR1 forcing GC (no HPROF)";
82 Heap::CollectGarbage();
83}
84
Elliott Hughesad7c2a32011-08-31 11:58:10 -070085int WaitForSignal(Thread* thread, sigset_t& mask) {
86 ScopedThreadStateChange tsc(thread, Thread::kWaiting); // TODO: VMWAIT
87
88 // Signals for sigwait() must be blocked but not ignored. We
89 // block signals like SIGQUIT for all threads, so the condition
90 // is met. When the signal hits, we wake up, without any signal
91 // handlers being invoked.
92
93 // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
94 int signal_number;
95 int rc = TEMP_FAILURE_RETRY(sigwait(&mask, &signal_number));
96 if (rc != 0) {
97 PLOG(FATAL) << "sigwait failed";
98 }
99
100 return signal_number;
101}
102
Elliott Hughese27955c2011-08-26 15:21:24 -0700103void* SignalCatcher::Run(void*) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700104 Runtime::Current()->AttachCurrentThread("Signal Catcher", NULL, true);
Elliott Hughese27955c2011-08-26 15:21:24 -0700105 Thread* self = Thread::Current();
106 CHECK(self != NULL);
107
Elliott Hughese27955c2011-08-26 15:21:24 -0700108 // Set up mask with signals we want to handle.
109 sigset_t mask;
110 sigemptyset(&mask);
111 sigaddset(&mask, SIGQUIT);
112 sigaddset(&mask, SIGUSR1);
113
114 while (true) {
Elliott Hughesad7c2a32011-08-31 11:58:10 -0700115 int signal_number = WaitForSignal(self, mask);
Elliott Hughese27955c2011-08-26 15:21:24 -0700116 if (halt_) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700117 Runtime::Current()->DetachCurrentThread();
Elliott Hughese27955c2011-08-26 15:21:24 -0700118 return NULL;
119 }
120
Elliott Hughesad7c2a32011-08-31 11:58:10 -0700121 LOG(INFO) << *self << ": reacting to signal " << signal_number;
Elliott Hughese27955c2011-08-26 15:21:24 -0700122 switch (signal_number) {
123 case SIGQUIT:
124 HandleSigQuit();
125 break;
126 case SIGUSR1:
127 HandleSigUsr1();
128 break;
129 default:
130 LOG(ERROR) << "Unexpected signal %d" << signal_number;
131 break;
132 }
133 }
134}
135
136} // namespace art