| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/child/child_thread.h" | 5 #include "content/child/child_thread.h" |
| 6 | 6 |
| 7 #include <signal.h> | 7 #include <signal.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 const int kConnectionTimeoutS = 15; | 63 const int kConnectionTimeoutS = 15; |
| 64 | 64 |
| 65 base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls = | 65 base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls = |
| 66 LAZY_INSTANCE_INITIALIZER; | 66 LAZY_INSTANCE_INITIALIZER; |
| 67 | 67 |
| 68 // This isn't needed on Windows because there the sandbox's job object | 68 // This isn't needed on Windows because there the sandbox's job object |
| 69 // terminates child processes automatically. For unsandboxed processes (i.e. | 69 // terminates child processes automatically. For unsandboxed processes (i.e. |
| 70 // plugins), PluginThread has EnsureTerminateMessageFilter. | 70 // plugins), PluginThread has EnsureTerminateMessageFilter. |
| 71 #if defined(OS_POSIX) | 71 #if defined(OS_POSIX) |
| 72 | 72 |
| 73 // A thread delegate that waits for |duration| and then signals the process | |
| 74 // with SIGALRM. | |
| 75 class WaitAndExitDelegate : public base::PlatformThread::Delegate { | |
| 76 public: | |
| 77 explicit WaitAndExitDelegate(base::TimeDelta duration) | |
| 78 : duration_(duration) {} | |
| 79 virtual ~WaitAndExitDelegate() OVERRIDE {} | |
| 80 | |
| 81 virtual void ThreadMain() OVERRIDE { | |
| 82 base::PlatformThread::Sleep(duration_); | |
| 83 // This used to be implemented with alarm(2). Make sure to not break | |
| 84 // anything that requires the process being signaled. | |
| 85 CHECK_EQ(0, raise(SIGALRM)); | |
| 86 | |
| 87 base::PlatformThread::Sleep((base::TimeDelta::FromSeconds(10))); | |
| 88 // If something erroneously blocked SIGALRM, this will trigger. | |
| 89 NOTREACHED(); | |
| 90 _exit(0); | |
| 91 } | |
| 92 | |
| 93 private: | |
| 94 const base::TimeDelta duration_; | |
| 95 DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate); | |
| 96 }; | |
| 97 | |
| 98 // This is similar to using alarm(2), except it will spawn a thread | |
| 99 // which will sleep for |duration| before raising SIGALRM. | |
| 100 bool CreateAlarmThread(base::TimeDelta duration) { | |
| 101 scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration)); | |
| 102 | |
| 103 const bool thread_created = base::PlatformThread::CreateNonJoinable( | |
| 104 0 /* stack_size */, delegate.get()); | |
| 105 if (!thread_created) | |
| 106 return false; | |
| 107 | |
| 108 // A non joinable thread has been created. The thread will either terminate | |
| 109 // the process or will be terminated by the process. Therefore, keep the | |
| 110 // delegate object alive for the lifetime of the process. | |
| 111 WaitAndExitDelegate* leaking_delegate = delegate.release(); | |
| 112 ANNOTATE_LEAKING_OBJECT_PTR(leaking_delegate); | |
| 113 ignore_result(leaking_delegate); | |
| 114 return true; | |
| 115 } | |
| 116 | |
| 117 class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { | 73 class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { |
| 118 public: | 74 public: |
| 119 // IPC::ChannelProxy::MessageFilter | 75 // IPC::ChannelProxy::MessageFilter |
| 120 virtual void OnChannelError() OVERRIDE { | 76 virtual void OnChannelError() OVERRIDE { |
| 121 // For renderer/worker processes: | 77 // For renderer/worker processes: |
| 122 // On POSIX, at least, one can install an unload handler which loops | 78 // On POSIX, at least, one can install an unload handler which loops |
| 123 // forever and leave behind a renderer process which eats 100% CPU forever. | 79 // forever and leave behind a renderer process which eats 100% CPU forever. |
| 124 // | 80 // |
| 125 // This is because the terminate signals (ViewMsg_ShouldClose and the error | 81 // This is because the terminate signals (ViewMsg_ShouldClose and the error |
| 126 // from the IPC channel) are routed to the main message loop but never | 82 // from the IPC channel) are routed to the main message loop but never |
| 127 // processed (because that message loop is stuck in V8). | 83 // processed (because that message loop is stuck in V8). |
| 128 // | 84 // |
| 129 // One could make the browser SIGKILL the renderers, but that leaves open a | 85 // One could make the browser SIGKILL the renderers, but that leaves open a |
| 130 // large window where a browser failure (or a user, manually terminating | 86 // large window where a browser failure (or a user, manually terminating |
| 131 // the browser because "it's stuck") will leave behind a process eating all | 87 // the browser because "it's stuck") will leave behind a process eating all |
| 132 // the CPU. | 88 // the CPU. |
| 133 // | 89 // |
| 134 // So, we install a filter on the channel so that we can process this event | 90 // So, we install a filter on the channel so that we can process this event |
| 135 // here and kill the process. | 91 // here and kill the process. |
| 136 if (CommandLine::ForCurrentProcess()-> | 92 _exit(0); |
| 137 HasSwitch(switches::kChildCleanExit)) { | |
| 138 // If clean exit is requested, we want to kill this process after giving | |
| 139 // it 60 seconds to run exit handlers. Exit handlers may including ones | |
| 140 // that write profile data to disk (which happens under profile collection | |
| 141 // mode). | |
| 142 CHECK(CreateAlarmThread(base::TimeDelta::FromSeconds(60))); | |
| 143 #if defined(LEAK_SANITIZER) | |
| 144 // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If | |
| 145 // leaks are found, the process will exit here. | |
| 146 __lsan_do_leak_check(); | |
| 147 #endif | |
| 148 } else { | |
| 149 _exit(0); | |
| 150 } | |
| 151 } | 93 } |
| 152 | 94 |
| 153 protected: | 95 protected: |
| 154 virtual ~SuicideOnChannelErrorFilter() {} | 96 virtual ~SuicideOnChannelErrorFilter() {} |
| 155 }; | 97 }; |
| 156 | 98 |
| 157 #endif // OS(POSIX) | 99 #endif // OS(POSIX) |
| 158 | 100 |
| 159 #if defined(OS_ANDROID) | 101 #if defined(OS_ANDROID) |
| 160 ChildThread* g_child_thread = NULL; | 102 ChildThread* g_child_thread = NULL; |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 // inflight that would addref it. | 480 // inflight that would addref it. |
| 539 Send(new ChildProcessHostMsg_ShutdownRequest); | 481 Send(new ChildProcessHostMsg_ShutdownRequest); |
| 540 } | 482 } |
| 541 | 483 |
| 542 void ChildThread::EnsureConnected() { | 484 void ChildThread::EnsureConnected() { |
| 543 VLOG(0) << "ChildThread::EnsureConnected()"; | 485 VLOG(0) << "ChildThread::EnsureConnected()"; |
| 544 base::KillProcess(base::GetCurrentProcessHandle(), 0, false); | 486 base::KillProcess(base::GetCurrentProcessHandle(), 0, false); |
| 545 } | 487 } |
| 546 | 488 |
| 547 } // namespace content | 489 } // namespace content |
| OLD | NEW |