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
3// found in the LICENSE file.
4
5#include "content/child/child_process.h"
6
7#if defined(OS_POSIX) && !defined(OS_ANDROID)
8#include <signal.h>  // For SigUSR1Handler below.
9#endif
10
11#include "base/lazy_instance.h"
12#include "base/message_loop/message_loop.h"
13#include "base/metrics/statistics_recorder.h"
14#include "base/process/process_handle.h"
15#include "base/strings/string_number_conversions.h"
16#include "base/strings/utf_string_conversions.h"
17#include "base/threading/thread.h"
18#include "base/threading/thread_local.h"
19#include "content/child/child_thread.h"
20
21#if defined(OS_ANDROID)
22#include "base/debug/debugger.h"
23#endif
24
25#if defined(OS_POSIX) && !defined(OS_ANDROID)
26static void SigUSR1Handler(int signal) { }
27#endif
28
29namespace content {
30
31namespace {
32
33base::LazyInstance<base::ThreadLocalPointer<ChildProcess> > g_lazy_tls =
34    LAZY_INSTANCE_INITIALIZER;
35}
36
37ChildProcess::ChildProcess()
38    : ref_count_(0),
39      shutdown_event_(true, false),
40      io_thread_("Chrome_ChildIOThread") {
41  DCHECK(!g_lazy_tls.Pointer()->Get());
42  g_lazy_tls.Pointer()->Set(this);
43
44  base::StatisticsRecorder::Initialize();
45
46  // We can't recover from failing to start the IO thread.
47  CHECK(io_thread_.StartWithOptions(
48      base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
49
50#if defined(OS_ANDROID)
51  io_thread_.SetPriority(base::kThreadPriority_Display);
52#endif
53}
54
55ChildProcess::~ChildProcess() {
56  DCHECK(g_lazy_tls.Pointer()->Get() == this);
57
58  // Signal this event before destroying the child process.  That way all
59  // background threads can cleanup.
60  // For example, in the renderer the RenderThread instances will be able to
61  // notice shutdown before the render process begins waiting for them to exit.
62  shutdown_event_.Signal();
63
64  // Kill the main thread object before nulling child_process, since
65  // destruction code might depend on it.
66  if (main_thread_) {  // null in unittests.
67    main_thread_->Shutdown();
68    main_thread_.reset();
69  }
70
71  g_lazy_tls.Pointer()->Set(NULL);
72  io_thread_.Stop();
73}
74
75ChildThread* ChildProcess::main_thread() {
76  return main_thread_.get();
77}
78
79void ChildProcess::set_main_thread(ChildThread* thread) {
80  main_thread_.reset(thread);
81}
82
83void ChildProcess::AddRefProcess() {
84  DCHECK(!main_thread_.get() ||  // null in unittests.
85         base::MessageLoop::current() == main_thread_->message_loop());
86  ref_count_++;
87}
88
89void ChildProcess::ReleaseProcess() {
90  DCHECK(!main_thread_.get() ||  // null in unittests.
91         base::MessageLoop::current() == main_thread_->message_loop());
92  DCHECK(ref_count_);
93  if (--ref_count_)
94    return;
95
96  if (main_thread_)  // null in unittests.
97    main_thread_->OnProcessFinalRelease();
98}
99
100ChildProcess* ChildProcess::current() {
101  return g_lazy_tls.Pointer()->Get();
102}
103
104base::WaitableEvent* ChildProcess::GetShutDownEvent() {
105  return &shutdown_event_;
106}
107
108void ChildProcess::WaitForDebugger(const std::string& label) {
109#if defined(OS_WIN)
110#if defined(GOOGLE_CHROME_BUILD)
111  std::string title = "Google Chrome";
112#else  // CHROMIUM_BUILD
113  std::string title = "Chromium";
114#endif  // CHROMIUM_BUILD
115  title += " ";
116  title += label;  // makes attaching to process easier
117  std::string message = label;
118  message += " starting with pid: ";
119  message += base::IntToString(base::GetCurrentProcId());
120  ::MessageBox(NULL, base::UTF8ToWide(message).c_str(),
121               base::UTF8ToWide(title).c_str(),
122               MB_OK | MB_SETFOREGROUND);
123#elif defined(OS_POSIX)
124#if defined(OS_ANDROID)
125  LOG(ERROR) << label << " waiting for GDB.";
126  // Wait 24 hours for a debugger to be attached to the current process.
127  base::debug::WaitForDebugger(24 * 60 * 60, false);
128#else
129  // TODO(playmobil): In the long term, overriding this flag doesn't seem
130  // right, either use our own flag or open a dialog we can use.
131  // This is just to ease debugging in the interim.
132  LOG(ERROR) << label
133             << " ("
134             << getpid()
135             << ") paused waiting for debugger to attach. "
136             << "Send SIGUSR1 to unpause.";
137  // Install a signal handler so that pause can be woken.
138  struct sigaction sa;
139  memset(&sa, 0, sizeof(sa));
140  sa.sa_handler = SigUSR1Handler;
141  sigaction(SIGUSR1, &sa, NULL);
142
143  pause();
144#endif  // defined(OS_ANDROID)
145#endif  // defined(OS_POSIX)
146}
147
148}  // namespace content
149