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 |