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

Side by Side Diff: content/browser/zygote_host/zygote_host_impl_linux.cc

Issue 148443006: Linux: tear down Zygote at browser shutdown. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Don't reset init_. Rely on control_fd_ for DCHECKs. Created 6 years, 10 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/browser/zygote_host/zygote_host_impl_linux.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/browser/zygote_host/zygote_host_impl_linux.h" 5 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
6 6
7 #include <sys/socket.h> 7 #include <sys/socket.h>
8 #include <sys/stat.h> 8 #include <sys/stat.h>
9 #include <sys/types.h> 9 #include <sys/types.h>
10 #include <unistd.h> 10 #include <unistd.h>
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 45
46 namespace content { 46 namespace content {
47 47
48 // static 48 // static
49 ZygoteHost* ZygoteHost::GetInstance() { 49 ZygoteHost* ZygoteHost::GetInstance() {
50 return ZygoteHostImpl::GetInstance(); 50 return ZygoteHostImpl::GetInstance();
51 } 51 }
52 52
53 ZygoteHostImpl::ZygoteHostImpl() 53 ZygoteHostImpl::ZygoteHostImpl()
54 : control_fd_(-1), 54 : control_fd_(-1),
55 control_lock_(),
55 pid_(-1), 56 pid_(-1),
56 init_(false), 57 init_(false),
57 using_suid_sandbox_(false), 58 using_suid_sandbox_(false),
59 sandbox_binary_(),
58 have_read_sandbox_status_word_(false), 60 have_read_sandbox_status_word_(false),
59 sandbox_status_(0) {} 61 sandbox_status_(0),
62 child_tracking_lock_(),
63 list_of_running_zygote_children_(),
64 should_teardown_after_last_child_exits_(false) {}
60 65
61 ZygoteHostImpl::~ZygoteHostImpl() { 66 ZygoteHostImpl::~ZygoteHostImpl() { TearDown(); }
62 if (init_)
63 close(control_fd_);
64 }
65 67
66 // static 68 // static
67 ZygoteHostImpl* ZygoteHostImpl::GetInstance() { 69 ZygoteHostImpl* ZygoteHostImpl::GetInstance() {
68 return Singleton<ZygoteHostImpl>::get(); 70 return Singleton<ZygoteHostImpl>::get();
69 } 71 }
70 72
71 void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { 73 void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
72 DCHECK(!init_); 74 DCHECK(!init_);
73 init_ = true; 75 init_ = true;
74 76
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 close(fds[1]); 212 close(fds[1]);
211 control_fd_ = fds[0]; 213 control_fd_ = fds[0];
212 214
213 Pickle pickle; 215 Pickle pickle;
214 pickle.WriteInt(kZygoteCommandGetSandboxStatus); 216 pickle.WriteInt(kZygoteCommandGetSandboxStatus);
215 if (!SendMessage(pickle, NULL)) 217 if (!SendMessage(pickle, NULL))
216 LOG(FATAL) << "Cannot communicate with zygote"; 218 LOG(FATAL) << "Cannot communicate with zygote";
217 // We don't wait for the reply. We'll read it in ReadReply. 219 // We don't wait for the reply. We'll read it in ReadReply.
218 } 220 }
219 221
222 void ZygoteHostImpl::TearDownAfterLastChild() {
223 base::AutoLock lock(child_tracking_lock_);
224 should_teardown_after_last_child_exits_ = true;
225 if (list_of_running_zygote_children_.empty()) {
226 TearDown();
piman 2014/01/28 22:38:32 Can we release the lock before calling TearDown? T
jln (very slow on Chromium) 2014/01/28 23:22:11 On 2014/01/28 22:38:32, piman wrote: [...]
227 }
228 }
229
230 // Note: this is also called from the destructor.
231 void ZygoteHostImpl::TearDown() {
232 base::AutoLock lock(control_lock_);
233 if (control_fd_ > -1) {
234 // Closing the IPC channel will act as a notification to exit
235 // to the Zygote.
236 if (IGNORE_EINTR(close(control_fd_))) {
237 PLOG(ERROR) << "Could not close Zygote control channel.";
238 NOTREACHED();
239 }
240 control_fd_ = -1;
241 }
242 }
243
244 void ZygoteHostImpl::ZygoteChildBorn(pid_t process) {
245 base::AutoLock lock(child_tracking_lock_);
246 bool new_element_inserted =
247 list_of_running_zygote_children_.insert(process).second;
248 DCHECK(new_element_inserted);
249 }
250
251 void ZygoteHostImpl::ZygoteChildDied(pid_t process) {
252 base::AutoLock lock(child_tracking_lock_);
253 size_t num_erased = list_of_running_zygote_children_.erase(process);
254 DCHECK_EQ(1U, num_erased);
255 if (should_teardown_after_last_child_exits_ &&
256 list_of_running_zygote_children_.empty()) {
257 TearDown();
258 }
259 }
260
220 bool ZygoteHostImpl::SendMessage(const Pickle& data, 261 bool ZygoteHostImpl::SendMessage(const Pickle& data,
221 const std::vector<int>* fds) { 262 const std::vector<int>* fds) {
263 DCHECK_NE(-1, control_fd_);
222 CHECK(data.size() <= kZygoteMaxMessageLength) 264 CHECK(data.size() <= kZygoteMaxMessageLength)
223 << "Trying to send too-large message to zygote (sending " << data.size() 265 << "Trying to send too-large message to zygote (sending " << data.size()
224 << " bytes, max is " << kZygoteMaxMessageLength << ")"; 266 << " bytes, max is " << kZygoteMaxMessageLength << ")";
225 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) 267 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors)
226 << "Trying to send message with too many file descriptors to zygote " 268 << "Trying to send message with too many file descriptors to zygote "
227 << "(sending " << fds->size() << ", max is " 269 << "(sending " << fds->size() << ", max is "
228 << UnixDomainSocket::kMaxFileDescriptors << ")"; 270 << UnixDomainSocket::kMaxFileDescriptors << ")";
229 271
230 return UnixDomainSocket::SendMsg(control_fd_, 272 return UnixDomainSocket::SendMsg(control_fd_,
231 data.data(), data.size(), 273 data.data(), data.size(),
232 fds ? *fds : std::vector<int>()); 274 fds ? *fds : std::vector<int>());
233 } 275 }
234 276
235 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { 277 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) {
278 DCHECK_NE(-1, control_fd_);
236 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, 279 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote,
237 // but don't wait for the reply. Thus, the first time that we read from the 280 // but don't wait for the reply. Thus, the first time that we read from the
238 // zygote, we get the reply to that request. 281 // zygote, we get the reply to that request.
239 if (!have_read_sandbox_status_word_) { 282 if (!have_read_sandbox_status_word_) {
240 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, 283 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_,
241 sizeof(sandbox_status_))) != 284 sizeof(sandbox_status_))) !=
242 sizeof(sandbox_status_)) { 285 sizeof(sandbox_status_)) {
243 return -1; 286 return -1;
244 } 287 }
245 have_read_sandbox_status_word_ = true; 288 have_read_sandbox_status_word_ = true;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 #if !defined(OS_OPENBSD) 372 #if !defined(OS_OPENBSD)
330 // This is just a starting score for a renderer or extension (the 373 // This is just a starting score for a renderer or extension (the
331 // only types of processes that will be started this way). It will 374 // only types of processes that will be started this way). It will
332 // get adjusted as time goes on. (This is the same value as 375 // get adjusted as time goes on. (This is the same value as
333 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but 376 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but
334 // that's not something we can include here.) 377 // that's not something we can include here.)
335 const int kLowestRendererOomScore = 300; 378 const int kLowestRendererOomScore = 300;
336 AdjustRendererOOMScore(pid, kLowestRendererOomScore); 379 AdjustRendererOOMScore(pid, kLowestRendererOomScore);
337 #endif 380 #endif
338 381
382 ZygoteChildBorn(pid);
339 return pid; 383 return pid;
340 } 384 }
341 385
342 #if !defined(OS_OPENBSD) 386 #if !defined(OS_OPENBSD)
343 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, 387 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
344 int score) { 388 int score) {
345 // 1) You can't change the oom_score_adj of a non-dumpable process 389 // 1) You can't change the oom_score_adj of a non-dumpable process
346 // (EPERM) unless you're root. Because of this, we can't set the 390 // (EPERM) unless you're root. Because of this, we can't set the
347 // oom_adj from the browser process. 391 // oom_adj from the browser process.
348 // 392 //
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 #endif 452 #endif
409 453
410 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { 454 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) {
411 DCHECK(init_); 455 DCHECK(init_);
412 Pickle pickle; 456 Pickle pickle;
413 457
414 pickle.WriteInt(kZygoteCommandReap); 458 pickle.WriteInt(kZygoteCommandReap);
415 pickle.WriteInt(process); 459 pickle.WriteInt(process);
416 if (!SendMessage(pickle, NULL)) 460 if (!SendMessage(pickle, NULL))
417 LOG(ERROR) << "Failed to send Reap message to zygote"; 461 LOG(ERROR) << "Failed to send Reap message to zygote";
462 ZygoteChildDied(process);
418 } 463 }
419 464
420 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( 465 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus(
421 base::ProcessHandle handle, 466 base::ProcessHandle handle,
422 bool known_dead, 467 bool known_dead,
423 int* exit_code) { 468 int* exit_code) {
424 DCHECK(init_); 469 DCHECK(init_);
425 Pickle pickle; 470 Pickle pickle;
426 pickle.WriteInt(kZygoteCommandGetTerminationStatus); 471 pickle.WriteInt(kZygoteCommandGetTerminationStatus);
427 pickle.WriteBool(known_dead); 472 pickle.WriteBool(known_dead);
428 pickle.WriteInt(handle); 473 pickle.WriteInt(handle);
429 474
430 // Set this now to handle the early termination cases.
431 if (exit_code)
432 *exit_code = RESULT_CODE_NORMAL_EXIT;
433
434 static const unsigned kMaxMessageLength = 128; 475 static const unsigned kMaxMessageLength = 128;
435 char buf[kMaxMessageLength]; 476 char buf[kMaxMessageLength];
436 ssize_t len; 477 ssize_t len;
437 { 478 {
438 base::AutoLock lock(control_lock_); 479 base::AutoLock lock(control_lock_);
439 if (!SendMessage(pickle, NULL)) 480 if (!SendMessage(pickle, NULL))
440 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; 481 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote";
441 len = ReadReply(buf, sizeof(buf)); 482 len = ReadReply(buf, sizeof(buf));
442 } 483 }
443 484
485 // Set this now to handle the error cases.
486 if (exit_code)
487 *exit_code = RESULT_CODE_NORMAL_EXIT;
488 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
489
444 if (len == -1) { 490 if (len == -1) {
445 LOG(WARNING) << "Error reading message from zygote: " << errno; 491 LOG(WARNING) << "Error reading message from zygote: " << errno;
446 return base::TERMINATION_STATUS_NORMAL_TERMINATION;
447 } else if (len == 0) { 492 } else if (len == 0) {
448 LOG(WARNING) << "Socket closed prematurely."; 493 LOG(WARNING) << "Socket closed prematurely.";
449 return base::TERMINATION_STATUS_NORMAL_TERMINATION; 494 } else {
495 Pickle read_pickle(buf, len);
496 int tmp_status, tmp_exit_code;
497 PickleIterator iter(read_pickle);
498 if (!read_pickle.ReadInt(&iter, &tmp_status) ||
499 !read_pickle.ReadInt(&iter, &tmp_exit_code)) {
500 LOG(WARNING)
501 << "Error parsing GetTerminationStatus response from zygote.";
502 } else {
503 if (exit_code)
504 *exit_code = tmp_exit_code;
505 status = tmp_status;
506 }
450 } 507 }
451 508
452 Pickle read_pickle(buf, len); 509 if (status != base::TERMINATION_STATUS_STILL_RUNNING) {
453 int status, tmp_exit_code; 510 ZygoteChildDied(handle);
454 PickleIterator iter(read_pickle);
455 if (!read_pickle.ReadInt(&iter, &status) ||
456 !read_pickle.ReadInt(&iter, &tmp_exit_code)) {
457 LOG(WARNING) << "Error parsing GetTerminationStatus response from zygote.";
458 return base::TERMINATION_STATUS_NORMAL_TERMINATION;
459 } 511 }
460
461 if (exit_code)
462 *exit_code = tmp_exit_code;
463
464 return static_cast<base::TerminationStatus>(status); 512 return static_cast<base::TerminationStatus>(status);
465 } 513 }
466 514
467 pid_t ZygoteHostImpl::GetPid() const { 515 pid_t ZygoteHostImpl::GetPid() const {
468 return pid_; 516 return pid_;
469 } 517 }
470 518
471 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { 519 pid_t ZygoteHostImpl::GetSandboxHelperPid() const {
472 return RenderSandboxHostLinux::GetInstance()->pid(); 520 return RenderSandboxHostLinux::GetInstance()->pid();
473 } 521 }
474 522
475 int ZygoteHostImpl::GetSandboxStatus() const { 523 int ZygoteHostImpl::GetSandboxStatus() const {
476 if (have_read_sandbox_status_word_) 524 if (have_read_sandbox_status_word_)
477 return sandbox_status_; 525 return sandbox_status_;
478 return 0; 526 return 0;
479 } 527 }
480 528
481 } // namespace content 529 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/zygote_host/zygote_host_impl_linux.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698