Roll src/third_party/skia 726cf90:183b57f
[chromium-blink-merge.git] / chromeos / process_proxy / process_proxy_registry.cc
blobaa2e9d829519b1a5c567a44bbe3e669a682e6d16
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 kStderrOutputType[] = "stderr";
17 const char kExitOutputType[] = "exit";
19 const char* ProcessOutputTypeToString(ProcessOutputType type) {
20 switch (type) {
21 case PROCESS_OUTPUT_TYPE_OUT:
22 return kStdoutOutputType;
23 case PROCESS_OUTPUT_TYPE_ERR:
24 return kStderrOutputType;
25 case PROCESS_OUTPUT_TYPE_EXIT:
26 return kExitOutputType;
27 default:
28 return NULL;
32 static base::LazyInstance<ProcessProxyRegistry> g_process_proxy_registry =
33 LAZY_INSTANCE_INITIALIZER;
35 } // namespace
37 ProcessProxyRegistry::ProcessProxyInfo::ProcessProxyInfo() {
40 ProcessProxyRegistry::ProcessProxyInfo::ProcessProxyInfo(
41 const ProcessProxyInfo& other) {
42 // This should be called with empty info only.
43 DCHECK(!other.proxy.get() && !other.watcher_thread.get());
46 ProcessProxyRegistry::ProcessProxyInfo::~ProcessProxyInfo() {
49 ProcessProxyRegistry::ProcessProxyRegistry() {
52 ProcessProxyRegistry::~ProcessProxyRegistry() {
53 // TODO(tbarzic): Fix issue with ProcessProxyRegistry being destroyed
54 // on a different thread (it's a LazyInstance).
55 DetachFromThread();
57 // Close all proxies we own.
58 while (!proxy_map_.empty())
59 CloseProcess(proxy_map_.begin()->first);
62 // static
63 ProcessProxyRegistry* ProcessProxyRegistry::Get() {
64 return g_process_proxy_registry.Pointer();
67 bool ProcessProxyRegistry::OpenProcess(
68 const std::string& command,
69 pid_t* pid,
70 const ProcessOutputCallbackWithPid& callback) {
71 DCHECK(CalledOnValidThread());
73 // TODO(tbarzic): Instead of creating a new thread for each new process proxy,
74 // use one thread for all processes.
75 // We will need new thread for proxy's outpu watcher.
76 scoped_ptr<base::Thread> watcher_thread(new base::Thread(kWatcherThreadName));
77 if (!watcher_thread->Start()) {
78 return false;
81 // Create and open new proxy.
82 scoped_refptr<ProcessProxy> proxy(new ProcessProxy());
83 if (!proxy->Open(command, pid))
84 return false;
86 // Kick off watcher.
87 // We can use Unretained because proxy will stop calling callback after it is
88 // closed, which is done befire this object goes away.
89 if (!proxy->StartWatchingOnThread(watcher_thread.get(),
90 base::Bind(&ProcessProxyRegistry::OnProcessOutput,
91 base::Unretained(this), *pid))) {
92 proxy->Close();
93 watcher_thread->Stop();
94 return false;
97 DCHECK(proxy_map_.find(*pid) == proxy_map_.end());
99 // Save info for newly created proxy. We cannot do this before ProcessProxy is
100 // created because we don't know |pid| then.
101 ProcessProxyInfo& info = proxy_map_[*pid];
102 info.proxy.swap(proxy);
103 info.watcher_thread.reset(watcher_thread.release());
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 it->second.watcher_thread->Stop();
127 proxy_map_.erase(it);
128 return true;
131 bool ProcessProxyRegistry::OnTerminalResize(pid_t pid, int width, int height) {
132 DCHECK(CalledOnValidThread());
134 std::map<pid_t, ProcessProxyInfo>::iterator it = proxy_map_.find(pid);
135 if (it == proxy_map_.end())
136 return false;
138 return it->second.proxy->OnTerminalResize(width, height);
141 void ProcessProxyRegistry::OnProcessOutput(pid_t pid,
142 ProcessOutputType type, const std::string& data) {
143 DCHECK(CalledOnValidThread());
145 const char* type_str = ProcessOutputTypeToString(type);
146 DCHECK(type_str);
148 std::map<pid_t, ProcessProxyInfo>::iterator it = proxy_map_.find(pid);
149 if (it == proxy_map_.end())
150 return;
151 it->second.callback.Run(pid, std::string(type_str), data);
153 // Contact with the slave end of the terminal has been lost. We have to close
154 // the process.
155 if (type == PROCESS_OUTPUT_TYPE_EXIT)
156 CloseProcess(pid);
159 } // namespace chromeos