blob: d677b07460a2bc6d79965043f48910b7423ded9b [file] [log] [blame]
James Kuszmaul3224b8e2022-01-07 19:00:39 -08001#include "aos/util/scoped_pipe.h"
2
3#include <fcntl.h>
4#include "glog/logging.h"
5
6namespace aos::util {
7
8ScopedPipe::ScopedPipe(int fd) : fd_(fd) {}
9
10ScopedPipe::~ScopedPipe() {
11 if (fd_ != -1) {
12 PCHECK(close(fd_) != -1);
13 }
14}
15
16ScopedPipe::ScopedPipe(ScopedPipe &&scoped_pipe) : fd_(scoped_pipe.fd_) {
17 scoped_pipe.fd_ = -1;
18}
19
20ScopedPipe &ScopedPipe::operator=(ScopedPipe &&scoped_pipe) {
21 if (fd_ != -1) {
22 PCHECK(close(fd_) != -1);
23 }
24 fd_ = scoped_pipe.fd_;
25 scoped_pipe.fd_ = -1;
26 return *this;
27}
28
James Kuszmauld42edb42022-01-07 18:00:16 -080029ScopedPipe::PipePair ScopedPipe::MakePipe() {
James Kuszmaul3224b8e2022-01-07 19:00:39 -080030 int fds[2];
31 PCHECK(pipe(fds) != -1);
32 PCHECK(fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK) != -1);
33 PCHECK(fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK) != -1);
James Kuszmauld42edb42022-01-07 18:00:16 -080034 return {std::unique_ptr<ScopedReadPipe>(new ScopedReadPipe(fds[0])),
35 std::unique_ptr<ScopedWritePipe>(new ScopedWritePipe(fds[1]))};
36}
37
38void ScopedPipe::SetCloexec() {
39 // FD_CLOEXEC is the only known file descriptor flag, but call GETFD just in
40 // case.
41 int flags = fcntl(fd(), F_GETFD);
42 PCHECK(flags != -1);
43 PCHECK(fcntl(fd(), F_SETFD, flags | FD_CLOEXEC) != -1);
James Kuszmaul3224b8e2022-01-07 19:00:39 -080044}
45
James Kuszmaul731a05d2022-01-07 17:59:26 -080046size_t ScopedPipe::ScopedReadPipe::Read(std::string *buffer) {
47 CHECK_NOTNULL(buffer);
48 constexpr ssize_t kBufferSize = 1024;
49 const size_t original_size = buffer->size();
50 size_t read_bytes = 0;
51 while (true) {
52 buffer->resize(buffer->size() + kBufferSize);
53 const ssize_t result =
54 read(fd(), buffer->data() + buffer->size() - kBufferSize, kBufferSize);
55 if (result == -1) {
56 if (errno == EAGAIN || errno == EWOULDBLOCK) {
57 buffer->resize(original_size);
58 return 0;
59 }
60 PLOG(FATAL) << "Error on reading pipe.";
61 } else if (result < kBufferSize) {
62 read_bytes += result;
63 buffer->resize(original_size + read_bytes);
64 break;
65 } else {
66 CHECK_EQ(result, kBufferSize);
67 read_bytes += result;
68 }
69 }
70 return read_bytes;
71}
72
James Kuszmaul3224b8e2022-01-07 19:00:39 -080073std::optional<uint32_t> ScopedPipe::ScopedReadPipe::Read() {
74 uint32_t buf;
75 ssize_t result = read(fd(), &buf, sizeof(buf));
76 if (result == sizeof(buf)) {
77 return buf;
78 } else {
79 return std::nullopt;
80 }
81}
82
83void ScopedPipe::ScopedWritePipe::Write(uint32_t data) {
84 ssize_t result = write(fd(), &data, sizeof(data));
85 PCHECK(result != -1);
James Kuszmaul731a05d2022-01-07 17:59:26 -080086 CHECK_EQ(static_cast<size_t>(result), sizeof(data));
87}
88
89void ScopedPipe::ScopedWritePipe::Write(absl::Span<const uint8_t> data) {
90 ssize_t result = write(fd(), data.data(), data.size());
91 PCHECK(result != -1);
92 CHECK_EQ(static_cast<size_t>(result), data.size());
James Kuszmaul3224b8e2022-01-07 19:00:39 -080093}
94
95} // namespace aos::util