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

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 object
42 // terminates child processes automatically. For unsandboxed processes (i.e.
43 // plugins), PluginThread has EnsureTerminateMessageFilter.
Avi (use Gerrit) 2012/08/07 04:57:48 EnsureTerminateMessageFilter? So we've seen this b
jam 2012/08/07 05:07:46 What happened is plugins got fixed for all platfor
37 #if defined(OS_POSIX) 44 #if defined(OS_POSIX)
38 45
39 class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { 46 class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter {
40 public: 47 public:
41 // IPC::ChannelProxy::MessageFilter 48 // IPC::ChannelProxy::MessageFilter
42 virtual void OnChannelError() OVERRIDE { 49 virtual void OnChannelError() OVERRIDE {
43 // For renderer/worker processes: 50 // For renderer/worker processes:
44 // On POSIX, at least, one can install an unload handler which loops 51 // 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. 52 // forever and leave behind a renderer process which eats 100% CPU forever.
46 // 53 //
47 // This is because the terminate signals (ViewMsg_ShouldClose and the error 54 // 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 55 // from the IPC channel) are routed to the main message loop but never
49 // processed (because that message loop is stuck in V8). 56 // processed (because that message loop is stuck in V8).
50 // 57 //
51 // One could make the browser SIGKILL the renderers, but that leaves open a 58 // 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 59 // 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 60 // the browser because "it's stuck") will leave behind a process eating all
54 // the CPU. 61 // the CPU.
55 // 62 //
56 // So, we install a filter on the channel so that we can process this event 63 // So, we install a filter on the channel so that we can process this event
57 // here and kill the process. 64 // here and kill the process.
58 // 65 //
59 // We want to kill this process after giving it 30 seconds to run the exit 66 // 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 67 // handlers. SIGALRM has a default disposition of terminating the
61 // application. 68 // application.
62 LOG(INFO) << "SuicideOnChannelErrorFilter::OnChannelError";
63 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChildCleanExit)) 69 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChildCleanExit))
64 alarm(30); 70 alarm(30);
65 else 71 else
66 _exit(0); 72 _exit(0);
67 } 73 }
68 74
69 protected: 75 protected:
70 virtual ~SuicideOnChannelErrorFilter() {} 76 virtual ~SuicideOnChannelErrorFilter() {}
71 }; 77 };
72 78
73 #endif // OS(POSIX) 79 #endif // OS(POSIX)
74 80
75 } // namespace 81 } // namespace
76 82
77 ChildThread::ChildThread() { 83 ChildThread::ChildThread()
84 : ALLOW_THIS_IN_INITIALIZER_LIST(channel_connected_factory_(this)) {
78 channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 85 channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
79 switches::kProcessChannelID); 86 switches::kProcessChannelID);
80 Init(); 87 Init();
81 } 88 }
82 89
83 ChildThread::ChildThread(const std::string& channel_name) 90 ChildThread::ChildThread(const std::string& channel_name)
84 : channel_name_(channel_name) { 91 : channel_name_(channel_name),
92 ALLOW_THIS_IN_INITIALIZER_LIST(channel_connected_factory_(this)) {
85 Init(); 93 Init();
86 } 94 }
87 95
88 void ChildThread::Init() { 96 void ChildThread::Init() {
89 on_channel_error_called_ = false; 97 on_channel_error_called_ = false;
90 message_loop_ = MessageLoop::current(); 98 message_loop_ = MessageLoop::current();
91 channel_.reset(new IPC::SyncChannel(channel_name_, 99 channel_.reset(new IPC::SyncChannel(channel_name_,
92 IPC::Channel::MODE_CLIENT, this, 100 IPC::Channel::MODE_CLIENT, this,
93 ChildProcess::current()->io_message_loop_proxy(), true, 101 ChildProcess::current()->io_message_loop_proxy(), true,
94 ChildProcess::current()->GetShutDownEvent())); 102 ChildProcess::current()->GetShutDownEvent()));
95 #ifdef IPC_MESSAGE_LOG_ENABLED 103 #ifdef IPC_MESSAGE_LOG_ENABLED
96 IPC::Logging::GetInstance()->SetIPCSender(this); 104 IPC::Logging::GetInstance()->SetIPCSender(this);
97 #endif 105 #endif
98 106
99 resource_dispatcher_.reset(new ResourceDispatcher(this)); 107 resource_dispatcher_.reset(new ResourceDispatcher(this));
100 socket_stream_dispatcher_.reset(new SocketStreamDispatcher()); 108 socket_stream_dispatcher_.reset(new SocketStreamDispatcher());
101 file_system_dispatcher_.reset(new FileSystemDispatcher()); 109 file_system_dispatcher_.reset(new FileSystemDispatcher());
102 quota_dispatcher_.reset(new QuotaDispatcher()); 110 quota_dispatcher_.reset(new QuotaDispatcher());
103 111
104 sync_message_filter_ = 112 sync_message_filter_ =
105 new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); 113 new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent());
106 histogram_message_filter_ = new content::ChildHistogramMessageFilter(); 114 histogram_message_filter_ = new content::ChildHistogramMessageFilter();
107 115
108 channel_->AddFilter(histogram_message_filter_.get()); 116 channel_->AddFilter(histogram_message_filter_.get());
109 channel_->AddFilter(sync_message_filter_.get()); 117 channel_->AddFilter(sync_message_filter_.get());
110 channel_->AddFilter(new ChildTraceMessageFilter()); 118 channel_->AddFilter(new ChildTraceMessageFilter());
111 LOG(INFO) << "ChildThread::Init";
112 119
113 #if defined(OS_POSIX) 120 #if defined(OS_POSIX)
114 // Check that --process-type is specified so we don't do this in unit tests 121 // Check that --process-type is specified so we don't do this in unit tests
115 // and single-process mode. 122 // and single-process mode.
116 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType)) 123 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType))
117 channel_->AddFilter(new SuicideOnChannelErrorFilter()); 124 channel_->AddFilter(new SuicideOnChannelErrorFilter());
118 #endif 125 #endif
126
127 MessageLoop::current()->PostDelayedTask(
128 FROM_HERE,
129 base::Bind(&ChildThread::EnsureConnected,
130 channel_connected_factory_.GetWeakPtr()),
131 base::TimeDelta::FromSeconds(kConnectionTimeoutS));
119 } 132 }
120 133
121 ChildThread::~ChildThread() { 134 ChildThread::~ChildThread() {
122 #ifdef IPC_MESSAGE_LOG_ENABLED 135 #ifdef IPC_MESSAGE_LOG_ENABLED
123 IPC::Logging::GetInstance()->SetIPCSender(NULL); 136 IPC::Logging::GetInstance()->SetIPCSender(NULL);
124 #endif 137 #endif
125 138
126 channel_->RemoveFilter(histogram_message_filter_.get()); 139 channel_->RemoveFilter(histogram_message_filter_.get());
127 channel_->RemoveFilter(sync_message_filter_.get()); 140 channel_->RemoveFilter(sync_message_filter_.get());
128 141
129 // The ChannelProxy object caches a pointer to the IPC thread, so need to 142 // 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. 143 // 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 144 // 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 145 // 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 146 // 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 147 // 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, 148 // automatically. We used to watch the object handle on Windows to do this,
136 // but it wasn't possible to do so on POSIX. 149 // but it wasn't possible to do so on POSIX.
137 channel_->ClearIPCTaskRunner(); 150 channel_->ClearIPCTaskRunner();
138 } 151 }
139 152
140 void ChildThread::OnChannelConnected(int32 peer_pid) { 153 void ChildThread::OnChannelConnected(int32 peer_pid) {
141 LOG(INFO) << "ChildThread::OnChannelConnected"; 154 channel_connected_factory_.InvalidateWeakPtrs();
142 } 155 }
143 156
144 void ChildThread::OnChannelError() { 157 void ChildThread::OnChannelError() {
145 LOG(INFO) << "ChildThread::OnChannelError";
146 set_on_channel_error_called(true); 158 set_on_channel_error_called(true);
147 MessageLoop::current()->Quit(); 159 MessageLoop::current()->Quit();
148 } 160 }
149 161
150 bool ChildThread::Send(IPC::Message* msg) { 162 bool ChildThread::Send(IPC::Message* msg) {
151 DCHECK(MessageLoop::current() == message_loop()); 163 DCHECK(MessageLoop::current() == message_loop());
152 if (!channel_.get()) { 164 if (!channel_.get()) {
153 delete msg; 165 delete msg;
154 return false; 166 return false;
155 } 167 }
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 } 344 }
333 345
334 // The child process shutdown sequence is a request response based mechanism, 346 // 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 347 // 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. 348 // 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 349 // 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 350 // race conditions if the process refcount is 0 but there's an IPC message
339 // inflight that would addref it. 351 // inflight that would addref it.
340 Send(new ChildProcessHostMsg_ShutdownRequest); 352 Send(new ChildProcessHostMsg_ShutdownRequest);
341 } 353 }
354
355 void ChildThread::EnsureConnected() {
356 LOG(INFO) << "ChildThread::EnsureConnected()";
357 base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
358 }
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