| OLD | NEW |
| (Empty) |
| 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 "chrome/browser/chromeos/process_proxy/process_output_watcher.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <cstdio> | |
| 9 #include <cstring> | |
| 10 | |
| 11 #include <sys/ioctl.h> | |
| 12 #include <sys/select.h> | |
| 13 #include <unistd.h> | |
| 14 | |
| 15 #include "base/logging.h" | |
| 16 #include "base/posix/eintr_wrapper.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 void InitReadFdSet(int out_fd, int stop_fd, fd_set* set) { | |
| 21 FD_ZERO(set); | |
| 22 if (out_fd != -1) | |
| 23 FD_SET(out_fd, set); | |
| 24 FD_SET(stop_fd, set); | |
| 25 } | |
| 26 | |
| 27 void CloseFd(int* fd) { | |
| 28 if (*fd >= 0) { | |
| 29 if (HANDLE_EINTR(close(*fd)) != 0) | |
| 30 DPLOG(WARNING) << "close fd " << *fd << " failed."; | |
| 31 } | |
| 32 *fd = -1; | |
| 33 } | |
| 34 | |
| 35 } // namespace | |
| 36 | |
| 37 ProcessOutputWatcher::ProcessOutputWatcher(int out_fd, int stop_fd, | |
| 38 const ProcessOutputCallback& callback) | |
| 39 : out_fd_(out_fd), | |
| 40 stop_fd_(stop_fd), | |
| 41 on_read_callback_(callback) { | |
| 42 VerifyFileDescriptor(out_fd_); | |
| 43 VerifyFileDescriptor(stop_fd_); | |
| 44 max_fd_ = std::max(out_fd_, stop_fd_); | |
| 45 // We want to be sure we will be able to add 0 at the end of the input, so -1. | |
| 46 read_buffer_size_ = arraysize(read_buffer_) - 1; | |
| 47 } | |
| 48 | |
| 49 void ProcessOutputWatcher::Start() { | |
| 50 WatchProcessOutput(); | |
| 51 OnStop(); | |
| 52 } | |
| 53 | |
| 54 ProcessOutputWatcher::~ProcessOutputWatcher() { | |
| 55 CloseFd(&out_fd_); | |
| 56 CloseFd(&stop_fd_); | |
| 57 } | |
| 58 | |
| 59 void ProcessOutputWatcher::WatchProcessOutput() { | |
| 60 while (true) { | |
| 61 // This has to be reset with every watch cycle. | |
| 62 fd_set rfds; | |
| 63 DCHECK(stop_fd_ >= 0); | |
| 64 InitReadFdSet(out_fd_, stop_fd_, &rfds); | |
| 65 | |
| 66 int select_result = | |
| 67 HANDLE_EINTR(select(max_fd_ + 1, &rfds, NULL, NULL, NULL)); | |
| 68 | |
| 69 if (select_result < 0) { | |
| 70 DPLOG(WARNING) << "select failed"; | |
| 71 return; | |
| 72 } | |
| 73 | |
| 74 // Check if we were stopped. | |
| 75 if (FD_ISSET(stop_fd_, &rfds)) { | |
| 76 return; | |
| 77 } | |
| 78 | |
| 79 if (out_fd_ != -1 && FD_ISSET(out_fd_, &rfds)) { | |
| 80 ReadFromFd(PROCESS_OUTPUT_TYPE_OUT, &out_fd_); | |
| 81 } | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 void ProcessOutputWatcher::VerifyFileDescriptor(int fd) { | |
| 86 CHECK_LE(0, fd); | |
| 87 CHECK_GT(FD_SETSIZE, fd); | |
| 88 } | |
| 89 | |
| 90 void ProcessOutputWatcher::ReadFromFd(ProcessOutputType type, int* fd) { | |
| 91 // We don't want to necessary read pipe until it is empty so we don't starve | |
| 92 // other streams in case data is written faster than we read it. If there is | |
| 93 // more than read_buffer_size_ bytes in pipe, it will be read in the next | |
| 94 // iteration. | |
| 95 ssize_t bytes_read = HANDLE_EINTR(read(*fd, read_buffer_, read_buffer_size_)); | |
| 96 if (bytes_read < 0) | |
| 97 DPLOG(WARNING) << "read from buffer failed"; | |
| 98 | |
| 99 if (bytes_read > 0) { | |
| 100 on_read_callback_.Run(type, std::string(read_buffer_, bytes_read)); | |
| 101 } | |
| 102 | |
| 103 // If there is nothing on the output the watched process has exited (slave end | |
| 104 // of pty is closed). | |
| 105 if (bytes_read <= 0) { | |
| 106 // Slave pseudo terminal has been closed, we won't need master fd anymore. | |
| 107 CloseFd(fd); | |
| 108 | |
| 109 // We have lost contact with the process, so report it. | |
| 110 on_read_callback_.Run(PROCESS_OUTPUT_TYPE_EXIT, ""); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 void ProcessOutputWatcher::OnStop() { | |
| 115 delete this; | |
| 116 } | |
| OLD | NEW |