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 40 namespace art { 41 42 static 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", ¤t_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 64 SignalCatcher::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 81 SignalCatcher::~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 89 void SignalCatcher::SetHaltFlag(bool new_value) { 90 MutexLock mu(Thread::Current(), lock_); 91 halt_ = new_value; 92 } 93 94 bool SignalCatcher::ShouldHalt() { 95 MutexLock mu(Thread::Current(), lock_); 96 return halt_; 97 } 98 99 void 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_, true)); 112 bool success = file->WriteFully(s.data(), s.size()); 113 if (success) { 114 success = file->FlushCloseOrErase() == 0; 115 } else { 116 file->Erase(); 117 } 118 if (success) { 119 LOG(INFO) << "Wrote stack traces to '" << stack_trace_file_ << "'"; 120 } else { 121 PLOG(ERROR) << "Failed to write stack traces to '" << stack_trace_file_ << "'"; 122 } 123 } 124 125 void SignalCatcher::HandleSigQuit() { 126 Runtime* runtime = Runtime::Current(); 127 ThreadList* thread_list = runtime->GetThreadList(); 128 129 // Grab exclusively the mutator lock, set state to Runnable without checking for a pending 130 // suspend request as we're going to suspend soon anyway. We set the state to Runnable to avoid 131 // giving away the mutator lock. 132 thread_list->SuspendAll(); 133 Thread* self = Thread::Current(); 134 Locks::mutator_lock_->AssertExclusiveHeld(self); 135 const char* old_cause = self->StartAssertNoThreadSuspension("Handling SIGQUIT"); 136 ThreadState old_state = self->SetStateUnsafe(kRunnable); 137 138 std::ostringstream os; 139 os << "\n" 140 << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n"; 141 142 DumpCmdLine(os); 143 144 // Note: The string "ABI:" is chosen to match the format used by debuggerd. 145 os << "ABI: " << GetInstructionSetString(runtime->GetInstructionSet()) << "\n"; 146 147 os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n"; 148 149 runtime->DumpForSigQuit(os); 150 151 if (false) { 152 std::string maps; 153 if (ReadFileToString("/proc/self/maps", &maps)) { 154 os << "/proc/self/maps:\n" << maps; 155 } 156 } 157 os << "----- end " << getpid() << " -----\n"; 158 CHECK_EQ(self->SetStateUnsafe(old_state), kRunnable); 159 self->EndAssertNoThreadSuspension(old_cause); 160 thread_list->ResumeAll(); 161 // Run the checkpoints after resuming the threads to prevent deadlocks if the checkpoint function 162 // acquires the mutator lock. 163 if (self->ReadFlag(kCheckpointRequest)) { 164 self->RunCheckpointFunction(); 165 } 166 Output(os.str()); 167 } 168 169 void SignalCatcher::HandleSigUsr1() { 170 LOG(INFO) << "SIGUSR1 forcing GC (no HPROF)"; 171 Runtime::Current()->GetHeap()->CollectGarbage(false); 172 } 173 174 int SignalCatcher::WaitForSignal(Thread* self, SignalSet& signals) { 175 ScopedThreadStateChange tsc(self, kWaitingInMainSignalCatcherLoop); 176 177 // Signals for sigwait() must be blocked but not ignored. We 178 // block signals like SIGQUIT for all threads, so the condition 179 // is met. When the signal hits, we wake up, without any signal 180 // handlers being invoked. 181 int signal_number = signals.Wait(); 182 if (!ShouldHalt()) { 183 // Let the user know we got the signal, just in case the system's too screwed for us to 184 // actually do what they want us to do... 185 LOG(INFO) << *self << ": reacting to signal " << signal_number; 186 187 // If anyone's holding locks (which might prevent us from getting back into state Runnable), say so... 188 Runtime::Current()->DumpLockHolders(LOG(INFO)); 189 } 190 191 return signal_number; 192 } 193 194 void* SignalCatcher::Run(void* arg) { 195 SignalCatcher* signal_catcher = reinterpret_cast<SignalCatcher*>(arg); 196 CHECK(signal_catcher != NULL); 197 198 Runtime* runtime = Runtime::Current(); 199 CHECK(runtime->AttachCurrentThread("Signal Catcher", true, runtime->GetSystemThreadGroup(), 200 !runtime->IsCompiler())); 201 202 Thread* self = Thread::Current(); 203 DCHECK_NE(self->GetState(), kRunnable); 204 { 205 MutexLock mu(self, signal_catcher->lock_); 206 signal_catcher->thread_ = self; 207 signal_catcher->cond_.Broadcast(self); 208 } 209 210 // Set up mask with signals we want to handle. 211 SignalSet signals; 212 signals.Add(SIGQUIT); 213 signals.Add(SIGUSR1); 214 215 while (true) { 216 int signal_number = signal_catcher->WaitForSignal(self, signals); 217 if (signal_catcher->ShouldHalt()) { 218 runtime->DetachCurrentThread(); 219 return NULL; 220 } 221 222 switch (signal_number) { 223 case SIGQUIT: 224 signal_catcher->HandleSigQuit(); 225 break; 226 case SIGUSR1: 227 signal_catcher->HandleSigUsr1(); 228 break; 229 default: 230 LOG(ERROR) << "Unexpected signal %d" << signal_number; 231 break; 232 } 233 } 234 } 235 236 } // namespace art 237