Update V8 to version 4.7.52.
[chromium-blink-merge.git] / chromeos / process_proxy / process_proxy_registry.cc
blob3619720c3d64d80a2d5e1d406dc606159c403b03
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.
5 #include "chromeos/process_proxy/process_proxy_registry.h"
7 #include "base/bind.h"
9 namespace chromeos {
11 namespace {
13 const char kWatcherThreadName[] = "ProcessWatcherThread";
15 const char kStdoutOutputType[] = "stdout";
16 const char kExitOutputType[] = "exit";
18 const char* ProcessOutputTypeToString(ProcessOutputType type) {
19 switch (type) {
20 case PROCESS_OUTPUT_TYPE_OUT:
21 return kStdoutOutputType;
22 case PROCESS_OUTPUT_TYPE_EXIT:
23 return kExitOutputType;
24 default:
25 return NULL;
29 static base::LazyInstance<ProcessProxyRegistry> g_process_proxy_registry =
30 LAZY_INSTANCE_INITIALIZER;
32 } // namespace
34 ProcessProxyRegistry::ProcessProxyInfo::ProcessProxyInfo() {
37 ProcessProxyRegistry::ProcessProxyInfo::ProcessProxyInfo(
38 const ProcessProxyInfo& other) {
39 // This should be called with empty info only.
40 DCHECK(!other.proxy.get());
43 ProcessProxyRegistry::ProcessProxyInfo::~ProcessProxyInfo() {
46 ProcessProxyRegistry::ProcessProxyRegistry() {
49 ProcessProxyRegistry::~ProcessProxyRegistry() {
50 // TODO(tbarzic): Fix issue with ProcessProxyRegistry being destroyed
51 // on a different thread (it's a LazyInstance).
52 DetachFromThread();
54 ShutDown();
57 void ProcessProxyRegistry::ShutDown() {
58 // Close all proxies we own.
59 while (!proxy_map_.empty())
60 CloseProcess(proxy_map_.begin()->first);
62 if (watcher_thread_) {
63 watcher_thread_->Stop();
64 watcher_thread_.reset();
68 // static
69 ProcessProxyRegistry* ProcessProxyRegistry::Get() {
70 return g_process_proxy_registry.Pointer();
73 bool ProcessProxyRegistry::OpenProcess(
74 const std::string& command,
75 pid_t* pid,
76 const ProcessOutputCallbackWithPid& callback) {
77 DCHECK(CalledOnValidThread());
79 if (!EnsureWatcherThreadStarted())
80 return false;
82 // Create and open new proxy.
83 scoped_refptr<ProcessProxy> proxy(new ProcessProxy());
84 if (!proxy->Open(command, pid))
85 return false;
87 // Kick off watcher.
88 // We can use Unretained because proxy will stop calling callback after it is
89 // closed, which is done before this object goes away.
90 if (!proxy->StartWatchingOutput(
91 watcher_thread_->task_runner(),
92 base::Bind(&ProcessProxyRegistry::OnProcessOutput,
93 base::Unretained(this), *pid))) {
94 proxy->Close();
95 return false;
98 DCHECK(proxy_map_.find(*pid) == proxy_map_.end());
100 // Save info for newly created proxy. We cannot do this before ProcessProxy is
101 // created because we don't know |pid| then.
102 ProcessProxyInfo& info = proxy_map_[*pid];
103 info.proxy.swap(proxy);
104 info.process_id = *pid;
105 info.callback = callback;
106 return true;
109 bool ProcessProxyRegistry::SendInput(pid_t pid, const std::string& data) {
110 DCHECK(CalledOnValidThread());
112 std::map<pid_t, ProcessProxyInfo>::iterator it = proxy_map_.find(pid);
113 if (it == proxy_map_.end())
114 return false;
115 return it->second.proxy->Write(data);
118 bool ProcessProxyRegistry::CloseProcess(pid_t pid) {
119 DCHECK(CalledOnValidThread());
121 std::map<pid_t, ProcessProxyInfo>::iterator it = proxy_map_.find(pid);
122 if (it == proxy_map_.end())
123 return false;
125 it->second.proxy->Close();
126 proxy_map_.erase(it);
127 return true;
130 bool ProcessProxyRegistry::OnTerminalResize(pid_t pid, int width, int height) {
131 DCHECK(CalledOnValidThread());
133 std::map<pid_t, ProcessProxyInfo>::iterator it = proxy_map_.find(pid);
134 if (it == proxy_map_.end())
135 return false;
137 return it->second.proxy->OnTerminalResize(width, height);
140 void ProcessProxyRegistry::OnProcessOutput(pid_t pid,
141 ProcessOutputType type, const std::string& data) {
142 DCHECK(CalledOnValidThread());
144 const char* type_str = ProcessOutputTypeToString(type);
145 DCHECK(type_str);
147 std::map<pid_t, ProcessProxyInfo>::iterator it = proxy_map_.find(pid);
148 if (it == proxy_map_.end())
149 return;
150 it->second.callback.Run(pid, std::string(type_str), data);
152 // Contact with the slave end of the terminal has been lost. We have to close
153 // the process.
154 if (type == PROCESS_OUTPUT_TYPE_EXIT)
155 CloseProcess(pid);
158 bool ProcessProxyRegistry::EnsureWatcherThreadStarted() {
159 if (watcher_thread_.get())
160 return true;
162 // TODO(tbarzic): Change process output watcher to watch for fd readability on
163 // FILE thread, and move output reading to worker thread instead of
164 // spinning a new thread.
165 watcher_thread_.reset(new base::Thread(kWatcherThreadName));
166 return watcher_thread_->StartWithOptions(
167 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
170 } // namespace chromeos