blob: 8b54df524de9523969e7556ece120fdb3414575a [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "runtime_probe/utils/pipe_utils.h"
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <string>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
namespace runtime_probe {
namespace {
enum class PipeState {
PENDING,
ERROR,
DONE,
};
// The system-defined size of buffer used to read from a pipe.
constexpr size_t kBufferSize = PIPE_BUF;
// Seconds to wait for runtime_probe helper to send probe results.
constexpr time_t kWaitSeconds = 5;
PipeState ReadPipe(int src_fd, std::string* dst_str) {
char buffer[kBufferSize];
const ssize_t bytes_read = HANDLE_EINTR(read(src_fd, buffer, kBufferSize));
if (bytes_read < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
PLOG(ERROR) << "read() from fd " << src_fd << " failed";
return PipeState::ERROR;
}
if (bytes_read == 0) {
return PipeState::DONE;
}
if (bytes_read > 0) {
dst_str->append(buffer, bytes_read);
}
return PipeState::PENDING;
}
} // namespace
bool ReadNonblockingPipeToString(int fd, std::string* out) {
fd_set read_fds;
struct timeval timeout;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
timeout.tv_sec = kWaitSeconds;
timeout.tv_usec = 0;
while (true) {
int retval =
HANDLE_EINTR(select(fd + 1, &read_fds, nullptr, nullptr, &timeout));
if (retval < 0) {
PLOG(ERROR) << "select() failed from runtime_probe_helper";
return false;
}
// Should only happen on timeout. Log a warning here, so we get at least a
// log if the process is stale.
if (retval == 0) {
LOG(WARNING) << "select() timed out. Process might be stale.";
return false;
}
PipeState state = ReadPipe(fd, out);
if (state == PipeState::DONE) {
return true;
}
if (state == PipeState::ERROR) {
return false;
}
}
}
} // namespace runtime_probe