1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/browser_main_posix.h" 6 7 #include <errno.h> 8 #include <limits.h> 9 #include <signal.h> 10 #include <sys/resource.h> 11 #include <unistd.h> 12 13 #include <string> 14 15 #include "base/command_line.h" 16 #include "base/eintr_wrapper.h" 17 #include "base/logging.h" 18 #include "base/string_number_conversions.h" 19 #include "chrome/browser/defaults.h" 20 #include "chrome/browser/ui/browser_list.h" 21 #include "chrome/common/chrome_switches.h" 22 #include "content/browser/browser_thread.h" 23 24 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) 25 #include "chrome/browser/printing/print_dialog_gtk.h" 26 #endif 27 28 namespace { 29 30 // See comment in |PreEarlyInitialization()|, where sigaction is called. 31 void SIGCHLDHandler(int signal) { 32 } 33 34 int g_shutdown_pipe_write_fd = -1; 35 int g_shutdown_pipe_read_fd = -1; 36 37 // Common code between SIG{HUP, INT, TERM}Handler. 38 void GracefulShutdownHandler(int signal) { 39 // Reinstall the default handler. We had one shot at graceful shutdown. 40 struct sigaction action; 41 memset(&action, 0, sizeof(action)); 42 action.sa_handler = SIG_DFL; 43 RAW_CHECK(sigaction(signal, &action, NULL) == 0); 44 45 RAW_CHECK(g_shutdown_pipe_write_fd != -1); 46 RAW_CHECK(g_shutdown_pipe_read_fd != -1); 47 size_t bytes_written = 0; 48 do { 49 int rv = HANDLE_EINTR( 50 write(g_shutdown_pipe_write_fd, 51 reinterpret_cast<const char*>(&signal) + bytes_written, 52 sizeof(signal) - bytes_written)); 53 RAW_CHECK(rv >= 0); 54 bytes_written += rv; 55 } while (bytes_written < sizeof(signal)); 56 } 57 58 // See comment in |PreEarlyInitialization()|, where sigaction is called. 59 void SIGHUPHandler(int signal) { 60 RAW_CHECK(signal == SIGHUP); 61 GracefulShutdownHandler(signal); 62 } 63 64 // See comment in |PreEarlyInitialization()|, where sigaction is called. 65 void SIGINTHandler(int signal) { 66 RAW_CHECK(signal == SIGINT); 67 GracefulShutdownHandler(signal); 68 } 69 70 // See comment in |PreEarlyInitialization()|, where sigaction is called. 71 void SIGTERMHandler(int signal) { 72 RAW_CHECK(signal == SIGTERM); 73 GracefulShutdownHandler(signal); 74 } 75 76 class ShutdownDetector : public base::PlatformThread::Delegate { 77 public: 78 explicit ShutdownDetector(int shutdown_fd); 79 80 virtual void ThreadMain(); 81 82 private: 83 const int shutdown_fd_; 84 85 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); 86 }; 87 88 ShutdownDetector::ShutdownDetector(int shutdown_fd) 89 : shutdown_fd_(shutdown_fd) { 90 CHECK_NE(shutdown_fd_, -1); 91 } 92 93 94 // These functions are used to help us diagnose crash dumps that happen 95 // during the shutdown process. 96 NOINLINE void ShutdownFDReadError() { 97 // Ensure function isn't optimized away. 98 asm(""); 99 sleep(UINT_MAX); 100 } 101 102 NOINLINE void ShutdownFDClosedError() { 103 // Ensure function isn't optimized away. 104 asm(""); 105 sleep(UINT_MAX); 106 } 107 108 NOINLINE void CloseAllBrowsersAndExitPosted() { 109 // Ensure function isn't optimized away. 110 asm(""); 111 sleep(UINT_MAX); 112 } 113 114 void ShutdownDetector::ThreadMain() { 115 base::PlatformThread::SetName("CrShutdownDetector"); 116 117 int signal; 118 size_t bytes_read = 0; 119 ssize_t ret; 120 do { 121 ret = HANDLE_EINTR( 122 read(shutdown_fd_, 123 reinterpret_cast<char*>(&signal) + bytes_read, 124 sizeof(signal) - bytes_read)); 125 if (ret < 0) { 126 NOTREACHED() << "Unexpected error: " << strerror(errno); 127 ShutdownFDReadError(); 128 break; 129 } else if (ret == 0) { 130 NOTREACHED() << "Unexpected closure of shutdown pipe."; 131 ShutdownFDClosedError(); 132 break; 133 } 134 bytes_read += ret; 135 } while (bytes_read < sizeof(signal)); 136 137 VLOG(1) << "Handling shutdown for signal " << signal << "."; 138 139 if (!BrowserThread::PostTask( 140 BrowserThread::UI, FROM_HERE, 141 NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) { 142 // Without a UI thread to post the exit task to, there aren't many 143 // options. Raise the signal again. The default handler will pick it up 144 // and cause an ungraceful exit. 145 RAW_LOG(WARNING, "No UI thread, exiting ungracefully."); 146 kill(getpid(), signal); 147 148 // The signal may be handled on another thread. Give that a chance to 149 // happen. 150 sleep(3); 151 152 // We really should be dead by now. For whatever reason, we're not. Exit 153 // immediately, with the exit status set to the signal number with bit 8 154 // set. On the systems that we care about, this exit status is what is 155 // normally used to indicate an exit by this signal's default handler. 156 // This mechanism isn't a de jure standard, but even in the worst case, it 157 // should at least result in an immediate exit. 158 RAW_LOG(WARNING, "Still here, exiting really ungracefully."); 159 _exit(signal | (1 << 7)); 160 } 161 CloseAllBrowsersAndExitPosted(); 162 } 163 164 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard 165 // limit, whichever is lower. 166 void SetFileDescriptorLimit(unsigned int max_descriptors) { 167 struct rlimit limits; 168 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { 169 unsigned int new_limit = max_descriptors; 170 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { 171 new_limit = limits.rlim_max; 172 } 173 limits.rlim_cur = new_limit; 174 if (setrlimit(RLIMIT_NOFILE, &limits) != 0) { 175 PLOG(INFO) << "Failed to set file descriptor limit"; 176 } 177 } else { 178 PLOG(INFO) << "Failed to get file descriptor limit"; 179 } 180 } 181 182 } // namespace 183 184 // BrowserMainPartsPosix ------------------------------------------------------- 185 186 void BrowserMainPartsPosix::PreEarlyInitialization() { 187 // We need to accept SIGCHLD, even though our handler is a no-op because 188 // otherwise we cannot wait on children. (According to POSIX 2001.) 189 struct sigaction action; 190 memset(&action, 0, sizeof(action)); 191 action.sa_handler = SIGCHLDHandler; 192 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); 193 194 // If adding to this list of signal handlers, note the new signal probably 195 // needs to be reset in child processes. See 196 // base/process_util_posix.cc:LaunchApp 197 198 // We need to handle SIGTERM, because that is how many POSIX-based distros ask 199 // processes to quit gracefully at shutdown time. 200 memset(&action, 0, sizeof(action)); 201 action.sa_handler = SIGTERMHandler; 202 CHECK(sigaction(SIGTERM, &action, NULL) == 0); 203 // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If 204 // the browser process is being debugged, GDB will catch the SIGINT first. 205 action.sa_handler = SIGINTHandler; 206 CHECK(sigaction(SIGINT, &action, NULL) == 0); 207 // And SIGHUP, for when the terminal disappears. On shutdown, many Linux 208 // distros send SIGHUP, SIGTERM, and then SIGKILL. 209 action.sa_handler = SIGHUPHandler; 210 CHECK(sigaction(SIGHUP, &action, NULL) == 0); 211 212 const std::string fd_limit_string = 213 parsed_command_line().GetSwitchValueASCII( 214 switches::kFileDescriptorLimit); 215 int fd_limit = 0; 216 if (!fd_limit_string.empty()) { 217 base::StringToInt(fd_limit_string, &fd_limit); 218 } 219 #if defined(OS_MACOSX) 220 // We use quite a few file descriptors for our IPC, and the default limit on 221 // the Mac is low (256), so bump it up if there is no explicit override. 222 if (fd_limit == 0) { 223 fd_limit = 1024; 224 } 225 #endif // OS_MACOSX 226 if (fd_limit > 0) 227 SetFileDescriptorLimit(fd_limit); 228 229 #if defined(OS_CHROMEOS) 230 if (parsed_command_line().HasSwitch(switches::kGuestSession)) { 231 // Disable sync and extensions if we're in "browse without sign-in" mode. 232 CommandLine* singleton_command_line = CommandLine::ForCurrentProcess(); 233 singleton_command_line->AppendSwitch(switches::kDisableSync); 234 singleton_command_line->AppendSwitch(switches::kDisableExtensions); 235 browser_defaults::bookmarks_enabled = false; 236 } 237 #endif 238 } 239 240 void BrowserMainPartsPosix::PostMainMessageLoopStart() { 241 int pipefd[2]; 242 int ret = pipe(pipefd); 243 if (ret < 0) { 244 PLOG(DFATAL) << "Failed to create pipe"; 245 } else { 246 g_shutdown_pipe_read_fd = pipefd[0]; 247 g_shutdown_pipe_write_fd = pipefd[1]; 248 const size_t kShutdownDetectorThreadStackSize = 4096; 249 // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so 250 // if you change this, you'll probably need to change the suppression. 251 if (!base::PlatformThread::CreateNonJoinable( 252 kShutdownDetectorThreadStackSize, 253 new ShutdownDetector(g_shutdown_pipe_read_fd))) { 254 LOG(DFATAL) << "Failed to create shutdown detector task."; 255 } 256 } 257 258 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) 259 printing::PrintingContextCairo::SetCreatePrintDialogFunction( 260 &PrintDialogGtk::CreatePrintDialog); 261 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) 262 } 263