blob: d178c0d798e5dc28d232fa981fead9ce0ac0cff1 [file] [log] [blame]
James Kuszmaul3224b8e2022-01-07 19:00:39 -08001#include "aos/util/scoped_pipe.h"
2
Stephan Pleinesb1177672024-05-27 17:48:32 -07003#include <errno.h>
James Kuszmaul3224b8e2022-01-07 19:00:39 -08004#include <fcntl.h>
Stephan Pleinesb1177672024-05-27 17:48:32 -07005#include <unistd.h>
6
7#include <ostream>
Austin Schuh60e77942022-05-16 17:48:24 -07008
James Kuszmaul3224b8e2022-01-07 19:00:39 -08009#include "glog/logging.h"
10
11namespace aos::util {
12
13ScopedPipe::ScopedPipe(int fd) : fd_(fd) {}
14
15ScopedPipe::~ScopedPipe() {
16 if (fd_ != -1) {
17 PCHECK(close(fd_) != -1);
18 }
19}
20
21ScopedPipe::ScopedPipe(ScopedPipe &&scoped_pipe) : fd_(scoped_pipe.fd_) {
22 scoped_pipe.fd_ = -1;
23}
24
25ScopedPipe &ScopedPipe::operator=(ScopedPipe &&scoped_pipe) {
26 if (fd_ != -1) {
27 PCHECK(close(fd_) != -1);
28 }
29 fd_ = scoped_pipe.fd_;
30 scoped_pipe.fd_ = -1;
31 return *this;
32}
33
James Kuszmauld42edb42022-01-07 18:00:16 -080034ScopedPipe::PipePair ScopedPipe::MakePipe() {
James Kuszmaul3224b8e2022-01-07 19:00:39 -080035 int fds[2];
36 PCHECK(pipe(fds) != -1);
37 PCHECK(fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK) != -1);
38 PCHECK(fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK) != -1);
James Kuszmauld42edb42022-01-07 18:00:16 -080039 return {std::unique_ptr<ScopedReadPipe>(new ScopedReadPipe(fds[0])),
40 std::unique_ptr<ScopedWritePipe>(new ScopedWritePipe(fds[1]))};
41}
42
43void ScopedPipe::SetCloexec() {
44 // FD_CLOEXEC is the only known file descriptor flag, but call GETFD just in
45 // case.
46 int flags = fcntl(fd(), F_GETFD);
47 PCHECK(flags != -1);
48 PCHECK(fcntl(fd(), F_SETFD, flags | FD_CLOEXEC) != -1);
James Kuszmaul3224b8e2022-01-07 19:00:39 -080049}
50
James Kuszmaul731a05d2022-01-07 17:59:26 -080051size_t ScopedPipe::ScopedReadPipe::Read(std::string *buffer) {
Austin Schuh6bdcc372024-06-27 14:49:11 -070052 CHECK(buffer != nullptr);
James Kuszmaul731a05d2022-01-07 17:59:26 -080053 constexpr ssize_t kBufferSize = 1024;
54 const size_t original_size = buffer->size();
55 size_t read_bytes = 0;
56 while (true) {
57 buffer->resize(buffer->size() + kBufferSize);
58 const ssize_t result =
59 read(fd(), buffer->data() + buffer->size() - kBufferSize, kBufferSize);
60 if (result == -1) {
61 if (errno == EAGAIN || errno == EWOULDBLOCK) {
Austin Schuh0d164112023-08-17 12:50:51 -070062 buffer->resize(original_size + read_bytes);
63 return read_bytes;
James Kuszmaul731a05d2022-01-07 17:59:26 -080064 }
65 PLOG(FATAL) << "Error on reading pipe.";
66 } else if (result < kBufferSize) {
67 read_bytes += result;
68 buffer->resize(original_size + read_bytes);
69 break;
70 } else {
71 CHECK_EQ(result, kBufferSize);
72 read_bytes += result;
73 }
74 }
75 return read_bytes;
76}
77
James Kuszmaul3224b8e2022-01-07 19:00:39 -080078std::optional<uint32_t> ScopedPipe::ScopedReadPipe::Read() {
79 uint32_t buf;
80 ssize_t result = read(fd(), &buf, sizeof(buf));
81 if (result == sizeof(buf)) {
82 return buf;
83 } else {
84 return std::nullopt;
85 }
86}
87
88void ScopedPipe::ScopedWritePipe::Write(uint32_t data) {
89 ssize_t result = write(fd(), &data, sizeof(data));
90 PCHECK(result != -1);
James Kuszmaul731a05d2022-01-07 17:59:26 -080091 CHECK_EQ(static_cast<size_t>(result), sizeof(data));
92}
93
94void ScopedPipe::ScopedWritePipe::Write(absl::Span<const uint8_t> data) {
95 ssize_t result = write(fd(), data.data(), data.size());
96 PCHECK(result != -1);
97 CHECK_EQ(static_cast<size_t>(result), data.size());
James Kuszmaul3224b8e2022-01-07 19:00:39 -080098}
99
100} // namespace aos::util