Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: content/common/child_thread.cc

Issue 10855013: Ensure we don't have zombie child processes that get started but never get a chance to connect to t… (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/common/child_thread.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/common/child_thread.h" 5 #include "content/common/child_thread.h"
6 6
7 #include "base/allocator/allocator_extension.h" 7 #include "base/allocator/allocator_extension.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/process.h" 10 #include "base/process.h"
11 #include "base/process_util.h"
11 #include "base/string_util.h" 12 #include "base/string_util.h"
12 #include "base/tracked_objects.h" 13 #include "base/tracked_objects.h"
13 #include "content/common/child_histogram_message_filter.h" 14 #include "content/common/child_histogram_message_filter.h"
14 #include "content/common/child_process.h" 15 #include "content/common/child_process.h"
15 #include "content/common/child_process_messages.h" 16 #include "content/common/child_process_messages.h"
16 #include "content/common/child_trace_message_filter.h" 17 #include "content/common/child_trace_message_filter.h"
17 #include "content/common/fileapi/file_system_dispatcher.h" 18 #include "content/common/fileapi/file_system_dispatcher.h"
18 #include "content/common/quota_dispatcher.h" 19 #include "content/common/quota_dispatcher.h"
19 #include "content/common/resource_dispatcher.h" 20 #include "content/common/resource_dispatcher.h"
20 #include "content/common/socket_stream_dispatcher.h" 21 #include "content/common/socket_stream_dispatcher.h"
21 #include "content/public/common/content_switches.h" 22 #include "content/public/common/content_switches.h"
22 #include "ipc/ipc_logging.h" 23 #include "ipc/ipc_logging.h"
23 #include "ipc/ipc_switches.h" 24 #include "ipc/ipc_switches.h"
24 #include "ipc/ipc_sync_channel.h" 25 #include "ipc/ipc_sync_channel.h"
25 #include "ipc/ipc_sync_message_filter.h" 26 #include "ipc/ipc_sync_message_filter.h"
26 #include "webkit/glue/webkit_glue.h" 27 #include "webkit/glue/webkit_glue.h"
27 28
28 #if defined(OS_WIN) 29 #if defined(OS_WIN)
29 #include "content/common/handle_enumerator_win.h" 30 #include "content/common/handle_enumerator_win.h"
30 #endif 31 #endif
31 32
32 using content::ResourceDispatcher; 33 using content::ResourceDispatcher;
33 using tracked_objects::ThreadData; 34 using tracked_objects::ThreadData;
34 35
35 namespace { 36 namespace {
36 37
38 // How long to wait for a connection to the browser process before giving up.
39 const int kConnectionTimeoutS = 15;
40
41 // This isn't needed on Windows because there the sandbox's job objects
42 // terminates child processes automatically. For unsanboxed processes (i.e.
Avi (use Gerrit) 2012/08/07 04:50:51 s/terminates/terminate/ to match quantity. s/unsan
jam 2012/08/07 04:54:28 updated objects to object since there's only one
43 // plugins), PluginThread has EnsureTerminateMessageFilter.
37 #if defined(OS_POSIX) 44 #if defined(OS_POSIX)
38 45
46 // How long to wait after the browser process goes away to kill ourselves.
47 const int kSuicideTimeoutS = 5;
48
39 class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { 49 class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter {
40 public: 50 public:
41 // IPC::ChannelProxy::MessageFilter 51 // IPC::ChannelProxy::MessageFilter
42 virtual void OnChannelError() OVERRIDE { 52 virtual void OnChannelError() OVERRIDE {
43 // For renderer/worker processes: 53 // For renderer/worker processes:
44 // On POSIX, at least, one can install an unload handler which loops 54 // On POSIX, at least, one can install an unload handler which loops
45 // forever and leave behind a renderer process which eats 100% CPU forever. 55 // forever and leave behind a renderer process which eats 100% CPU forever.
46 // 56 //
47 // This is because the terminate signals (ViewMsg_ShouldClose and the error 57 // This is because the terminate signals (ViewMsg_ShouldClose and the error
48 // from the IPC channel) are routed to the main message loop but never 58 // from the IPC channel) are routed to the main message loop but never
49 // processed (because that message loop is stuck in V8). 59 // processed (because that message loop is stuck in V8).
50 // 60 //
51 // One could make the browser SIGKILL the renderers, but that leaves open a 61 // One could make the browser SIGKILL the renderers, but that leaves open a
52 // large window where a browser failure (or a user, manually terminating 62 // large window where a browser failure (or a user, manually terminating
53 // the browser because "it's stuck") will leave behind a process eating all 63 // the browser because "it's stuck") will leave behind a process eating all
54 // the CPU. 64 // the CPU.
55 // 65 //
56 // So, we install a filter on the channel so that we can process this event 66 // So, we install a filter on the channel so that we can process this event
57 // here and kill the process. 67 // here and kill the process.
58 // 68 //
59 // We want to kill this process after giving it 30 seconds to run the exit 69 // We want to kill this process after giving it 30 seconds to run the exit
60 // handlers. SIGALRM has a default disposition of terminating the 70 // handlers. SIGALRM has a default disposition of terminating the
61 // application. 71 // application.
62 LOG(INFO) << "SuicideOnChannelErrorFilter::OnChannelError"; 72 if (CommandLine::ForCurrentProcess()->HasSwitch(
63 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChildCleanExit)) 73 switches::kChildCleanExit)) {
64 alarm(30); 74 alarm(30);
65 else 75 } else {
66 _exit(0); 76 MessageLoop::current()->PostDelayedTask(
77 FROM_HERE,
78 base::Bind(&SuicideOnChannelErrorFilter::Exit, this),
79 base::TimeDelta::FromSeconds(kSuicideTimeoutS));
Avi (use Gerrit) 2012/08/07 04:50:51 This change from immediate exit to delayed suicide
jam 2012/08/07 04:54:28 On second thoughts, I'll remove that from this cha
80 }
67 } 81 }
68 82
69 protected: 83 protected:
70 virtual ~SuicideOnChannelErrorFilter() {} 84 virtual ~SuicideOnChannelErrorFilter() {}
85
86 private:
87 void Exit() {
88 _exit(0);
89 }
71 }; 90 };
72 91
73 #endif // OS(POSIX) 92 #endif // OS(POSIX)
74 93
75 } // namespace 94 } // namespace
76 95
77 ChildThread::ChildThread() { 96 ChildThread::ChildThread()
97 : ALLOW_THIS_IN_INITIALIZER_LIST(channel_connected_factory_(this)) {
78 channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 98 channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
79 switches::kProcessChannelID); 99 switches::kProcessChannelID);
80 Init(); 100 Init();
81 } 101 }
82 102
83 ChildThread::ChildThread(const std::string& channel_name) 103 ChildThread::ChildThread(const std::string& channel_name)
84 : channel_name_(channel_name) { 104 : channel_name_(channel_name),
105 ALLOW_THIS_IN_INITIALIZER_LIST(channel_connected_factory_(this)) {
85 Init(); 106 Init();
86 } 107 }
87 108
88 void ChildThread::Init() { 109 void ChildThread::Init() {
89 on_channel_error_called_ = false; 110 on_channel_error_called_ = false;
90 message_loop_ = MessageLoop::current(); 111 message_loop_ = MessageLoop::current();
91 channel_.reset(new IPC::SyncChannel(channel_name_, 112 channel_.reset(new IPC::SyncChannel(channel_name_,
92 IPC::Channel::MODE_CLIENT, this, 113 IPC::Channel::MODE_CLIENT, this,
93 ChildProcess::current()->io_message_loop_proxy(), true, 114 ChildProcess::current()->io_message_loop_proxy(), true,
94 ChildProcess::current()->GetShutDownEvent())); 115 ChildProcess::current()->GetShutDownEvent()));
95 #ifdef IPC_MESSAGE_LOG_ENABLED 116 #ifdef IPC_MESSAGE_LOG_ENABLED
96 IPC::Logging::GetInstance()->SetIPCSender(this); 117 IPC::Logging::GetInstance()->SetIPCSender(this);
97 #endif 118 #endif
98 119
99 resource_dispatcher_.reset(new ResourceDispatcher(this)); 120 resource_dispatcher_.reset(new ResourceDispatcher(this));
100 socket_stream_dispatcher_.reset(new SocketStreamDispatcher()); 121 socket_stream_dispatcher_.reset(new SocketStreamDispatcher());
101 file_system_dispatcher_.reset(new FileSystemDispatcher()); 122 file_system_dispatcher_.reset(new FileSystemDispatcher());
102 quota_dispatcher_.reset(new QuotaDispatcher()); 123 quota_dispatcher_.reset(new QuotaDispatcher());
103 124
104 sync_message_filter_ = 125 sync_message_filter_ =
105 new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); 126 new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent());
106 histogram_message_filter_ = new content::ChildHistogramMessageFilter(); 127 histogram_message_filter_ = new content::ChildHistogramMessageFilter();
107 128
108 channel_->AddFilter(histogram_message_filter_.get()); 129 channel_->AddFilter(histogram_message_filter_.get());
109 channel_->AddFilter(sync_message_filter_.get()); 130 channel_->AddFilter(sync_message_filter_.get());
110 channel_->AddFilter(new ChildTraceMessageFilter()); 131 channel_->AddFilter(new ChildTraceMessageFilter());
111 LOG(INFO) << "ChildThread::Init";
112 132
113 #if defined(OS_POSIX) 133 #if defined(OS_POSIX)
114 // Check that --process-type is specified so we don't do this in unit tests 134 // Check that --process-type is specified so we don't do this in unit tests
115 // and single-process mode. 135 // and single-process mode.
116 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType)) 136 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType))
117 channel_->AddFilter(new SuicideOnChannelErrorFilter()); 137 channel_->AddFilter(new SuicideOnChannelErrorFilter());
118 #endif 138 #endif
139
140 MessageLoop::current()->PostDelayedTask(
141 FROM_HERE,
142 base::Bind(&ChildThread::EnsureConnected,
143 channel_connected_factory_.GetWeakPtr()),
144 base::TimeDelta::FromSeconds(kConnectionTimeoutS));
119 } 145 }
120 146
121 ChildThread::~ChildThread() { 147 ChildThread::~ChildThread() {
122 #ifdef IPC_MESSAGE_LOG_ENABLED 148 #ifdef IPC_MESSAGE_LOG_ENABLED
123 IPC::Logging::GetInstance()->SetIPCSender(NULL); 149 IPC::Logging::GetInstance()->SetIPCSender(NULL);
124 #endif 150 #endif
125 151
126 channel_->RemoveFilter(histogram_message_filter_.get()); 152 channel_->RemoveFilter(histogram_message_filter_.get());
127 channel_->RemoveFilter(sync_message_filter_.get()); 153 channel_->RemoveFilter(sync_message_filter_.get());
128 154
129 // The ChannelProxy object caches a pointer to the IPC thread, so need to 155 // The ChannelProxy object caches a pointer to the IPC thread, so need to
130 // reset it as it's not guaranteed to outlive this object. 156 // reset it as it's not guaranteed to outlive this object.
131 // NOTE: this also has the side-effect of not closing the main IPC channel to 157 // NOTE: this also has the side-effect of not closing the main IPC channel to
132 // the browser process. This is needed because this is the signal that the 158 // the browser process. This is needed because this is the signal that the
133 // browser uses to know that this process has died, so we need it to be alive 159 // browser uses to know that this process has died, so we need it to be alive
134 // until this process is shut down, and the OS closes the handle 160 // until this process is shut down, and the OS closes the handle
135 // automatically. We used to watch the object handle on Windows to do this, 161 // automatically. We used to watch the object handle on Windows to do this,
136 // but it wasn't possible to do so on POSIX. 162 // but it wasn't possible to do so on POSIX.
137 channel_->ClearIPCTaskRunner(); 163 channel_->ClearIPCTaskRunner();
138 } 164 }
139 165
140 void ChildThread::OnChannelConnected(int32 peer_pid) { 166 void ChildThread::OnChannelConnected(int32 peer_pid) {
141 LOG(INFO) << "ChildThread::OnChannelConnected"; 167 channel_connected_factory_.InvalidateWeakPtrs();
142 } 168 }
143 169
144 void ChildThread::OnChannelError() { 170 void ChildThread::OnChannelError() {
145 LOG(INFO) << "ChildThread::OnChannelError";
146 set_on_channel_error_called(true); 171 set_on_channel_error_called(true);
147 MessageLoop::current()->Quit(); 172 MessageLoop::current()->Quit();
148 } 173 }
149 174
150 bool ChildThread::Send(IPC::Message* msg) { 175 bool ChildThread::Send(IPC::Message* msg) {
151 DCHECK(MessageLoop::current() == message_loop()); 176 DCHECK(MessageLoop::current() == message_loop());
152 if (!channel_.get()) { 177 if (!channel_.get()) {
153 delete msg; 178 delete msg;
154 return false; 179 return false;
155 } 180 }
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 } 357 }
333 358
334 // The child process shutdown sequence is a request response based mechanism, 359 // The child process shutdown sequence is a request response based mechanism,
335 // where we send out an initial feeler request to the child process host 360 // where we send out an initial feeler request to the child process host
336 // instance in the browser to verify if it's ok to shutdown the child process. 361 // instance in the browser to verify if it's ok to shutdown the child process.
337 // The browser then sends back a response if it's ok to shutdown. This avoids 362 // The browser then sends back a response if it's ok to shutdown. This avoids
338 // race conditions if the process refcount is 0 but there's an IPC message 363 // race conditions if the process refcount is 0 but there's an IPC message
339 // inflight that would addref it. 364 // inflight that would addref it.
340 Send(new ChildProcessHostMsg_ShutdownRequest); 365 Send(new ChildProcessHostMsg_ShutdownRequest);
341 } 366 }
367
368 void ChildThread::EnsureConnected() {
369 LOG(INFO) << "ChildThread::EnsureConnected()";
370 base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
371 }
OLDNEW
« no previous file with comments | « content/common/child_thread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698