tokenpipe.cpp raw
1 // Copyright (c) 2021-2022 The Limenka developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 #include <util/tokenpipe.h>
5
6 #include <limenka-build-config.h> // IWYU pragma: keep
7
8 #ifndef WIN32
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <optional>
13 #include <unistd.h>
14
15 TokenPipeEnd TokenPipe::TakeReadEnd()
16 {
17 TokenPipeEnd res(m_fds[0]);
18 m_fds[0] = -1;
19 return res;
20 }
21
22 TokenPipeEnd TokenPipe::TakeWriteEnd()
23 {
24 TokenPipeEnd res(m_fds[1]);
25 m_fds[1] = -1;
26 return res;
27 }
28
29 TokenPipeEnd::TokenPipeEnd(int fd) : m_fd(fd)
30 {
31 }
32
33 TokenPipeEnd::~TokenPipeEnd()
34 {
35 Close();
36 }
37
38 int TokenPipeEnd::TokenWrite(uint8_t token)
39 {
40 while (true) {
41 ssize_t result = write(m_fd, &token, 1);
42 if (result < 0) {
43 // Failure. It's possible that the write was interrupted by a signal,
44 // in that case retry.
45 if (errno != EINTR) {
46 return TS_ERR;
47 }
48 } else if (result == 0) {
49 return TS_EOS;
50 } else { // ==1
51 return 0;
52 }
53 }
54 }
55
56 int TokenPipeEnd::TokenRead()
57 {
58 uint8_t token;
59 while (true) {
60 ssize_t result = read(m_fd, &token, 1);
61 if (result < 0) {
62 // Failure. Check if the read was interrupted by a signal,
63 // in that case retry.
64 if (errno != EINTR) {
65 return TS_ERR;
66 }
67 } else if (result == 0) {
68 return TS_EOS;
69 } else { // ==1
70 return token;
71 }
72 }
73 return token;
74 }
75
76 void TokenPipeEnd::Close()
77 {
78 if (m_fd != -1) close(m_fd);
79 m_fd = -1;
80 }
81
82 std::optional<TokenPipe> TokenPipe::Make()
83 {
84 int fds[2] = {-1, -1};
85 #if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
86 if (pipe2(fds, O_CLOEXEC) != 0) {
87 return std::nullopt;
88 }
89 #else
90 if (pipe(fds) != 0) {
91 return std::nullopt;
92 }
93 #endif
94 return TokenPipe(fds);
95 }
96
97 TokenPipe::~TokenPipe()
98 {
99 Close();
100 }
101
102 void TokenPipe::Close()
103 {
104 if (m_fds[0] != -1) close(m_fds[0]);
105 if (m_fds[1] != -1) close(m_fds[1]);
106 m_fds[0] = m_fds[1] = -1;
107 }
108
109 #endif // WIN32
110