This source file includes following definitions.
- InitReadFdSet
- CloseFd
- on_read_callback_
- Start
- WatchProcessOutput
- VerifyFileDescriptor
- ReadFromFd
- OnStop
#include "chromeos/process_proxy/process_output_watcher.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
namespace {
void InitReadFdSet(int out_fd, int stop_fd, fd_set* set) {
FD_ZERO(set);
if (out_fd != -1)
FD_SET(out_fd, set);
FD_SET(stop_fd, set);
}
void CloseFd(int* fd) {
if (*fd >= 0) {
if (IGNORE_EINTR(close(*fd)) != 0)
DPLOG(WARNING) << "close fd " << *fd << " failed.";
}
*fd = -1;
}
}
namespace chromeos {
ProcessOutputWatcher::ProcessOutputWatcher(int out_fd, int stop_fd,
const ProcessOutputCallback& callback)
: out_fd_(out_fd),
stop_fd_(stop_fd),
on_read_callback_(callback) {
VerifyFileDescriptor(out_fd_);
VerifyFileDescriptor(stop_fd_);
max_fd_ = std::max(out_fd_, stop_fd_);
read_buffer_size_ = arraysize(read_buffer_) - 1;
}
void ProcessOutputWatcher::Start() {
WatchProcessOutput();
OnStop();
}
ProcessOutputWatcher::~ProcessOutputWatcher() {
CloseFd(&out_fd_);
CloseFd(&stop_fd_);
}
void ProcessOutputWatcher::WatchProcessOutput() {
while (true) {
fd_set rfds;
DCHECK(stop_fd_ >= 0);
InitReadFdSet(out_fd_, stop_fd_, &rfds);
int select_result =
HANDLE_EINTR(select(max_fd_ + 1, &rfds, NULL, NULL, NULL));
if (select_result < 0) {
DPLOG(WARNING) << "select failed";
return;
}
if (FD_ISSET(stop_fd_, &rfds)) {
return;
}
if (out_fd_ != -1 && FD_ISSET(out_fd_, &rfds)) {
ReadFromFd(PROCESS_OUTPUT_TYPE_OUT, &out_fd_);
}
}
}
void ProcessOutputWatcher::VerifyFileDescriptor(int fd) {
CHECK_LE(0, fd);
CHECK_GT(FD_SETSIZE, fd);
}
void ProcessOutputWatcher::ReadFromFd(ProcessOutputType type, int* fd) {
ssize_t bytes_read = HANDLE_EINTR(read(*fd, read_buffer_, read_buffer_size_));
if (bytes_read < 0)
DPLOG(WARNING) << "read from buffer failed";
if (bytes_read > 0) {
on_read_callback_.Run(type, std::string(read_buffer_, bytes_read));
}
if (bytes_read <= 0) {
CloseFd(fd);
on_read_callback_.Run(PROCESS_OUTPUT_TYPE_EXIT, "");
}
}
void ProcessOutputWatcher::OnStop() {
delete this;
}
}