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_output_watcher.h"
11 #include <sys/ioctl.h>
12 #include <sys/select.h>
15 #include "base/logging.h"
16 #include "base/posix/eintr_wrapper.h"
20 void InitReadFdSet(int out_fd
, int stop_fd
, fd_set
* set
) {
27 void CloseFd(int* fd
) {
29 if (IGNORE_EINTR(close(*fd
)) != 0)
30 DPLOG(WARNING
) << "close fd " << *fd
<< " failed.";
39 ProcessOutputWatcher::ProcessOutputWatcher(int out_fd
, int stop_fd
,
40 const ProcessOutputCallback
& callback
)
43 on_read_callback_(callback
) {
44 VerifyFileDescriptor(out_fd_
);
45 VerifyFileDescriptor(stop_fd_
);
46 max_fd_
= std::max(out_fd_
, stop_fd_
);
47 // We want to be sure we will be able to add 0 at the end of the input, so -1.
48 read_buffer_size_
= arraysize(read_buffer_
) - 1;
51 void ProcessOutputWatcher::Start() {
56 ProcessOutputWatcher::~ProcessOutputWatcher() {
61 void ProcessOutputWatcher::WatchProcessOutput() {
63 // This has to be reset with every watch cycle.
65 DCHECK(stop_fd_
>= 0);
66 InitReadFdSet(out_fd_
, stop_fd_
, &rfds
);
69 HANDLE_EINTR(select(max_fd_
+ 1, &rfds
, NULL
, NULL
, NULL
));
71 if (select_result
< 0) {
72 DPLOG(WARNING
) << "select failed";
76 // Check if we were stopped.
77 if (FD_ISSET(stop_fd_
, &rfds
)) {
81 if (out_fd_
!= -1 && FD_ISSET(out_fd_
, &rfds
)) {
82 ReadFromFd(PROCESS_OUTPUT_TYPE_OUT
, &out_fd_
);
87 void ProcessOutputWatcher::VerifyFileDescriptor(int fd
) {
89 CHECK_GT(FD_SETSIZE
, fd
);
92 void ProcessOutputWatcher::ReadFromFd(ProcessOutputType type
, int* fd
) {
93 // We don't want to necessary read pipe until it is empty so we don't starve
94 // other streams in case data is written faster than we read it. If there is
95 // more than read_buffer_size_ bytes in pipe, it will be read in the next
97 ssize_t bytes_read
= HANDLE_EINTR(read(*fd
, read_buffer_
, read_buffer_size_
));
99 DPLOG(WARNING
) << "read from buffer failed";
101 if (bytes_read
> 0) {
102 on_read_callback_
.Run(type
, std::string(read_buffer_
, bytes_read
));
105 // If there is nothing on the output the watched process has exited (slave end
106 // of pty is closed).
107 if (bytes_read
<= 0) {
108 // Slave pseudo terminal has been closed, we won't need master fd anymore.
111 // We have lost contact with the process, so report it.
112 on_read_callback_
.Run(PROCESS_OUTPUT_TYPE_EXIT
, "");
116 void ProcessOutputWatcher::OnStop() {
120 } // namespace chromeos