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

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 call TearDown() while holding child_tracking_lock_. 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 bool do_teardown = false;
224 {
225 base::AutoLock lock(child_tracking_lock_);
226 should_teardown_after_last_child_exits_ = true;
227 do_teardown = list_of_running_zygote_children_.empty();
228 }
229 if (do_teardown) {
230 TearDown();
231 }
232 }
233
234 // Note: this is also called from the destructor.
235 void ZygoteHostImpl::TearDown() {
236 base::AutoLock lock(control_lock_);
237 if (control_fd_ > -1) {
238 // Closing the IPC channel will act as a notification to exit
239 // to the Zygote.
240 if (IGNORE_EINTR(close(control_fd_))) {
241 PLOG(ERROR) << "Could not close Zygote control channel.";
242 NOTREACHED();
243 }
244 control_fd_ = -1;
245 }
246 }
247
248 void ZygoteHostImpl::ZygoteChildBorn(pid_t process) {
249 base::AutoLock lock(child_tracking_lock_);
250 bool new_element_inserted =
251 list_of_running_zygote_children_.insert(process).second;
252 DCHECK(new_element_inserted);
253 }
254
255 void ZygoteHostImpl::ZygoteChildDied(pid_t process) {
256 bool do_teardown = false;
257 {
258 base::AutoLock lock(child_tracking_lock_);
259 size_t num_erased = list_of_running_zygote_children_.erase(process);
260 DCHECK_EQ(1U, num_erased);
261 do_teardown = should_teardown_after_last_child_exits_ &&
262 list_of_running_zygote_children_.empty();
263 }
264 if (do_teardown) {
265 TearDown();
266 }
267 }
268
220 bool ZygoteHostImpl::SendMessage(const Pickle& data, 269 bool ZygoteHostImpl::SendMessage(const Pickle& data,
221 const std::vector<int>* fds) { 270 const std::vector<int>* fds) {
271 DCHECK_NE(-1, control_fd_);
222 CHECK(data.size() <= kZygoteMaxMessageLength) 272 CHECK(data.size() <= kZygoteMaxMessageLength)
223 << "Trying to send too-large message to zygote (sending " << data.size() 273 << "Trying to send too-large message to zygote (sending " << data.size()
224 << " bytes, max is " << kZygoteMaxMessageLength << ")"; 274 << " bytes, max is " << kZygoteMaxMessageLength << ")";
225 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors) 275 CHECK(!fds || fds->size() <= UnixDomainSocket::kMaxFileDescriptors)
226 << "Trying to send message with too many file descriptors to zygote " 276 << "Trying to send message with too many file descriptors to zygote "
227 << "(sending " << fds->size() << ", max is " 277 << "(sending " << fds->size() << ", max is "
228 << UnixDomainSocket::kMaxFileDescriptors << ")"; 278 << UnixDomainSocket::kMaxFileDescriptors << ")";
229 279
230 return UnixDomainSocket::SendMsg(control_fd_, 280 return UnixDomainSocket::SendMsg(control_fd_,
231 data.data(), data.size(), 281 data.data(), data.size(),
232 fds ? *fds : std::vector<int>()); 282 fds ? *fds : std::vector<int>());
233 } 283 }
234 284
235 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) { 285 ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) {
286 DCHECK_NE(-1, control_fd_);
236 // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote, 287 // 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 288 // 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. 289 // zygote, we get the reply to that request.
239 if (!have_read_sandbox_status_word_) { 290 if (!have_read_sandbox_status_word_) {
240 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_, 291 if (HANDLE_EINTR(read(control_fd_, &sandbox_status_,
241 sizeof(sandbox_status_))) != 292 sizeof(sandbox_status_))) !=
242 sizeof(sandbox_status_)) { 293 sizeof(sandbox_status_)) {
243 return -1; 294 return -1;
244 } 295 }
245 have_read_sandbox_status_word_ = true; 296 have_read_sandbox_status_word_ = true;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 #if !defined(OS_OPENBSD) 380 #if !defined(OS_OPENBSD)
330 // This is just a starting score for a renderer or extension (the 381 // 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 382 // 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 383 // get adjusted as time goes on. (This is the same value as
333 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but 384 // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but
334 // that's not something we can include here.) 385 // that's not something we can include here.)
335 const int kLowestRendererOomScore = 300; 386 const int kLowestRendererOomScore = 300;
336 AdjustRendererOOMScore(pid, kLowestRendererOomScore); 387 AdjustRendererOOMScore(pid, kLowestRendererOomScore);
337 #endif 388 #endif
338 389
390 ZygoteChildBorn(pid);
339 return pid; 391 return pid;
340 } 392 }
341 393
342 #if !defined(OS_OPENBSD) 394 #if !defined(OS_OPENBSD)
343 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, 395 void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
344 int score) { 396 int score) {
345 // 1) You can't change the oom_score_adj of a non-dumpable process 397 // 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 398 // (EPERM) unless you're root. Because of this, we can't set the
347 // oom_adj from the browser process. 399 // oom_adj from the browser process.
348 // 400 //
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 #endif 460 #endif
409 461
410 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) { 462 void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) {
411 DCHECK(init_); 463 DCHECK(init_);
412 Pickle pickle; 464 Pickle pickle;
413 465
414 pickle.WriteInt(kZygoteCommandReap); 466 pickle.WriteInt(kZygoteCommandReap);
415 pickle.WriteInt(process); 467 pickle.WriteInt(process);
416 if (!SendMessage(pickle, NULL)) 468 if (!SendMessage(pickle, NULL))
417 LOG(ERROR) << "Failed to send Reap message to zygote"; 469 LOG(ERROR) << "Failed to send Reap message to zygote";
470 ZygoteChildDied(process);
418 } 471 }
419 472
420 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus( 473 base::TerminationStatus ZygoteHostImpl::GetTerminationStatus(
421 base::ProcessHandle handle, 474 base::ProcessHandle handle,
422 bool known_dead, 475 bool known_dead,
423 int* exit_code) { 476 int* exit_code) {
424 DCHECK(init_); 477 DCHECK(init_);
425 Pickle pickle; 478 Pickle pickle;
426 pickle.WriteInt(kZygoteCommandGetTerminationStatus); 479 pickle.WriteInt(kZygoteCommandGetTerminationStatus);
427 pickle.WriteBool(known_dead); 480 pickle.WriteBool(known_dead);
428 pickle.WriteInt(handle); 481 pickle.WriteInt(handle);
429 482
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; 483 static const unsigned kMaxMessageLength = 128;
435 char buf[kMaxMessageLength]; 484 char buf[kMaxMessageLength];
436 ssize_t len; 485 ssize_t len;
437 { 486 {
438 base::AutoLock lock(control_lock_); 487 base::AutoLock lock(control_lock_);
439 if (!SendMessage(pickle, NULL)) 488 if (!SendMessage(pickle, NULL))
440 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote"; 489 LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote";
441 len = ReadReply(buf, sizeof(buf)); 490 len = ReadReply(buf, sizeof(buf));
442 } 491 }
443 492
493 // Set this now to handle the error cases.
494 if (exit_code)
495 *exit_code = RESULT_CODE_NORMAL_EXIT;
496 int status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
497
444 if (len == -1) { 498 if (len == -1) {
445 LOG(WARNING) << "Error reading message from zygote: " << errno; 499 LOG(WARNING) << "Error reading message from zygote: " << errno;
446 return base::TERMINATION_STATUS_NORMAL_TERMINATION;
447 } else if (len == 0) { 500 } else if (len == 0) {
448 LOG(WARNING) << "Socket closed prematurely."; 501 LOG(WARNING) << "Socket closed prematurely.";
449 return base::TERMINATION_STATUS_NORMAL_TERMINATION; 502 } else {
503 Pickle read_pickle(buf, len);
504 int tmp_status, tmp_exit_code;
505 PickleIterator iter(read_pickle);
506 if (!read_pickle.ReadInt(&iter, &tmp_status) ||
507 !read_pickle.ReadInt(&iter, &tmp_exit_code)) {
508 LOG(WARNING)
509 << "Error parsing GetTerminationStatus response from zygote.";
510 } else {
511 if (exit_code)
512 *exit_code = tmp_exit_code;
513 status = tmp_status;
514 }
450 } 515 }
451 516
452 Pickle read_pickle(buf, len); 517 if (status != base::TERMINATION_STATUS_STILL_RUNNING) {
453 int status, tmp_exit_code; 518 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 } 519 }
460
461 if (exit_code)
462 *exit_code = tmp_exit_code;
463
464 return static_cast<base::TerminationStatus>(status); 520 return static_cast<base::TerminationStatus>(status);
465 } 521 }
466 522
467 pid_t ZygoteHostImpl::GetPid() const { 523 pid_t ZygoteHostImpl::GetPid() const {
468 return pid_; 524 return pid_;
469 } 525 }
470 526
471 pid_t ZygoteHostImpl::GetSandboxHelperPid() const { 527 pid_t ZygoteHostImpl::GetSandboxHelperPid() const {
472 return RenderSandboxHostLinux::GetInstance()->pid(); 528 return RenderSandboxHostLinux::GetInstance()->pid();
473 } 529 }
474 530
475 int ZygoteHostImpl::GetSandboxStatus() const { 531 int ZygoteHostImpl::GetSandboxStatus() const {
476 if (have_read_sandbox_status_word_) 532 if (have_read_sandbox_status_word_)
477 return sandbox_status_; 533 return sandbox_status_;
478 return 0; 534 return 0;
479 } 535 }
480 536
481 } // namespace content 537 } // 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