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