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"
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
) {
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
;
32 static base::LazyInstance
<ProcessProxyRegistry
> g_process_proxy_registry
=
33 LAZY_INSTANCE_INITIALIZER
;
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).
57 // Close all proxies we own.
58 while (!proxy_map_
.empty())
59 CloseProcess(proxy_map_
.begin()->first
);
63 ProcessProxyRegistry
* ProcessProxyRegistry::Get() {
64 return g_process_proxy_registry
.Pointer();
67 bool ProcessProxyRegistry::OpenProcess(
68 const std::string
& command
,
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()) {
81 // Create and open new proxy.
82 scoped_refptr
<ProcessProxy
> proxy(new ProcessProxy());
83 if (!proxy
->Open(command
, pid
))
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
))) {
93 watcher_thread
->Stop();
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
;
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())
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())
125 it
->second
.proxy
->Close();
126 it
->second
.watcher_thread
->Stop();
127 proxy_map_
.erase(it
);
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())
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
);
148 std::map
<pid_t
, ProcessProxyInfo
>::iterator it
= proxy_map_
.find(pid
);
149 if (it
== proxy_map_
.end())
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
155 if (type
== PROCESS_OUTPUT_TYPE_EXIT
)
159 } // namespace chromeos