1/*
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 <fcntl.h>
20#include <pthread.h>
21#include <signal.h>
22#include <stdlib.h>
23#include <sys/stat.h>
24#include <sys/time.h>
25#include <sys/types.h>
26#include <unistd.h>
27
28#include "base/unix_file/fd_file.h"
29#include "class_linker.h"
30#include "gc/heap.h"
31#include "instruction_set.h"
32#include "os.h"
33#include "runtime.h"
34#include "scoped_thread_state_change.h"
35#include "signal_set.h"
36#include "thread.h"
37#include "thread_list.h"
38#include "utils.h"
39
40namespace art {
41
42static void DumpCmdLine(std::ostream& os) {
43#if defined(__linux__)
44  // Show the original command line, and the current command line too if it's changed.
45  // On Android, /proc/self/cmdline will have been rewritten to something like "system_server".
46  // Note: The string "Cmd line:" is chosen to match the format used by debuggerd.
47  std::string current_cmd_line;
48  if (ReadFileToString("/proc/self/cmdline", &current_cmd_line)) {
49    current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1);  // trim trailing '\0's
50    std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' ');
51
52    os << "Cmd line: " << current_cmd_line << "\n";
53    const char* stashed_cmd_line = GetCmdLine();
54    if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line
55            && strcmp(stashed_cmd_line, "<unset>") != 0) {
56      os << "Original command line: " << stashed_cmd_line << "\n";
57    }
58  }
59#else
60  os << "Cmd line: " << GetCmdLine() << "\n";
61#endif
62}
63
64SignalCatcher::SignalCatcher(const std::string& stack_trace_file)
65    : stack_trace_file_(stack_trace_file),
66      lock_("SignalCatcher lock"),
67      cond_("SignalCatcher::cond_", lock_),
68      thread_(NULL) {
69  SetHaltFlag(false);
70
71  // Create a raw pthread; its start routine will attach to the runtime.
72  CHECK_PTHREAD_CALL(pthread_create, (&pthread_, NULL, &Run, this), "signal catcher thread");
73
74  Thread* self = Thread::Current();
75  MutexLock mu(self, lock_);
76  while (thread_ == NULL) {
77    cond_.Wait(self);
78  }
79}
80
81SignalCatcher::~SignalCatcher() {
82  // Since we know the thread is just sitting around waiting for signals
83  // to arrive, send it one.
84  SetHaltFlag(true);
85  CHECK_PTHREAD_CALL(pthread_kill, (pthread_, SIGQUIT), "signal catcher shutdown");
86  CHECK_PTHREAD_CALL(pthread_join, (pthread_, NULL), "signal catcher shutdown");
87}
88
89void SignalCatcher::SetHaltFlag(bool new_value) {
90  MutexLock mu(Thread::Current(), lock_);
91  halt_ = new_value;
92}
93
94bool SignalCatcher::ShouldHalt() {
95  MutexLock mu(Thread::Current(), lock_);
96  return halt_;
97}
98
99void SignalCatcher::Output(const std::string& s) {
100  if (stack_trace_file_.empty()) {
101    LOG(INFO) << s;
102    return;
103  }
104
105  ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput);
106  int fd = open(stack_trace_file_.c_str(), O_APPEND | O_CREAT | O_WRONLY, 0666);
107  if (fd == -1) {
108    PLOG(ERROR) << "Unable to open stack trace file '" << stack_trace_file_ << "'";
109    return;
110  }
111  std::unique_ptr<File> file(new File(fd, stack_trace_file_));
112  if (!file->WriteFully(s.data(), s.size())) {
113    PLOG(ERROR) << "Failed to write stack traces to '" << stack_trace_file_ << "'";
114  } else {
115    LOG(INFO) << "Wrote stack traces to '" << stack_trace_file_ << "'";
116  }
117}
118
119void SignalCatcher::HandleSigQuit() {
120  Runtime* runtime = Runtime::Current();
121  ThreadList* thread_list = runtime->GetThreadList();
122
123  // Grab exclusively the mutator lock, set state to Runnable without checking for a pending
124  // suspend request as we're going to suspend soon anyway. We set the state to Runnable to avoid
125  // giving away the mutator lock.
126  thread_list->SuspendAll();
127  Thread* self = Thread::Current();
128  Locks::mutator_lock_->AssertExclusiveHeld(self);
129  const char* old_cause = self->StartAssertNoThreadSuspension("Handling SIGQUIT");
130  ThreadState old_state = self->SetStateUnsafe(kRunnable);
131
132  std::ostringstream os;
133  os << "\n"
134      << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
135
136  DumpCmdLine(os);
137
138  // Note: The string "ABI:" is chosen to match the format used by debuggerd.
139  os << "ABI: " << GetInstructionSetString(runtime->GetInstructionSet()) << "\n";
140
141  os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";
142
143  runtime->DumpForSigQuit(os);
144
145  if (false) {
146    std::string maps;
147    if (ReadFileToString("/proc/self/maps", &maps)) {
148      os << "/proc/self/maps:\n" << maps;
149    }
150  }
151  os << "----- end " << getpid() << " -----\n";
152  CHECK_EQ(self->SetStateUnsafe(old_state), kRunnable);
153  self->EndAssertNoThreadSuspension(old_cause);
154  thread_list->ResumeAll();
155  // Run the checkpoints after resuming the threads to prevent deadlocks if the checkpoint function
156  // acquires the mutator lock.
157  if (self->ReadFlag(kCheckpointRequest)) {
158    self->RunCheckpointFunction();
159  }
160  Output(os.str());
161}
162
163void SignalCatcher::HandleSigUsr1() {
164  LOG(INFO) << "SIGUSR1 forcing GC (no HPROF)";
165  Runtime::Current()->GetHeap()->CollectGarbage(false);
166}
167
168int SignalCatcher::WaitForSignal(Thread* self, SignalSet& signals) {
169  ScopedThreadStateChange tsc(self, kWaitingInMainSignalCatcherLoop);
170
171  // Signals for sigwait() must be blocked but not ignored.  We
172  // block signals like SIGQUIT for all threads, so the condition
173  // is met.  When the signal hits, we wake up, without any signal
174  // handlers being invoked.
175  int signal_number = signals.Wait();
176  if (!ShouldHalt()) {
177    // Let the user know we got the signal, just in case the system's too screwed for us to
178    // actually do what they want us to do...
179    LOG(INFO) << *self << ": reacting to signal " << signal_number;
180
181    // If anyone's holding locks (which might prevent us from getting back into state Runnable), say so...
182    Runtime::Current()->DumpLockHolders(LOG(INFO));
183  }
184
185  return signal_number;
186}
187
188void* SignalCatcher::Run(void* arg) {
189  SignalCatcher* signal_catcher = reinterpret_cast<SignalCatcher*>(arg);
190  CHECK(signal_catcher != NULL);
191
192  Runtime* runtime = Runtime::Current();
193  CHECK(runtime->AttachCurrentThread("Signal Catcher", true, runtime->GetSystemThreadGroup(),
194                                     !runtime->IsCompiler()));
195
196  Thread* self = Thread::Current();
197  DCHECK_NE(self->GetState(), kRunnable);
198  {
199    MutexLock mu(self, signal_catcher->lock_);
200    signal_catcher->thread_ = self;
201    signal_catcher->cond_.Broadcast(self);
202  }
203
204  // Set up mask with signals we want to handle.
205  SignalSet signals;
206  signals.Add(SIGQUIT);
207  signals.Add(SIGUSR1);
208
209  while (true) {
210    int signal_number = signal_catcher->WaitForSignal(self, signals);
211    if (signal_catcher->ShouldHalt()) {
212      runtime->DetachCurrentThread();
213      return NULL;
214    }
215
216    switch (signal_number) {
217    case SIGQUIT:
218      signal_catcher->HandleSigQuit();
219      break;
220    case SIGUSR1:
221      signal_catcher->HandleSigUsr1();
222      break;
223    default:
224      LOG(ERROR) << "Unexpected signal %d" << signal_number;
225      break;
226    }
227  }
228}
229
230}  // namespace art
231