1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "pipe.h"
17
18 #include "failure_retry.h"
19
20 #include <vector>
21 #include <array>
22 #include <cerrno>
23
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <poll.h>
27
28 namespace panda::os::unix {
29
CreatePipe()30 std::pair<UniqueFd, UniqueFd> CreatePipe()
31 {
32 constexpr size_t FD_NUM = 2;
33 std::array<int, FD_NUM> fds {};
34 // NOLINTNEXTLINE(android-cloexec-pipe)
35 if (PANDA_FAILURE_RETRY(pipe(fds.data())) == -1) {
36 return std::pair<UniqueFd, UniqueFd>();
37 }
38 return std::pair<UniqueFd, UniqueFd>(UniqueFd(fds[0]), UniqueFd(fds[1]));
39 }
40
SetFdNonblocking(const UniqueFd & fd)41 int SetFdNonblocking(const UniqueFd &fd)
42 {
43 size_t flags;
44 #ifdef O_NONBLOCK
45 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
46 int res = fcntl(fd.Get(), F_GETFL, 0);
47 if (res < 0) {
48 flags = 0;
49 } else {
50 flags = static_cast<size_t>(res);
51 }
52 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-signed-bitwise)
53 return fcntl(fd.Get(), F_SETFL, flags | O_NONBLOCK);
54 #else
55 flags = 1;
56 return ioctl(fd, FIONBIO, &flags);
57 #endif
58 }
59
ReadFromPipe(const UniqueFd & pipe_fd,void * buf,size_t size)60 Expected<size_t, Error> ReadFromPipe(const UniqueFd &pipe_fd, void *buf, size_t size)
61 {
62 ssize_t bytes_read = PANDA_FAILURE_RETRY(read(pipe_fd.Get(), buf, size));
63 if (bytes_read < 0) {
64 return Unexpected(Error(errno));
65 }
66 return {static_cast<size_t>(bytes_read)};
67 }
68
WriteToPipe(const UniqueFd & pipe_fd,const void * buf,size_t size)69 Expected<size_t, Error> WriteToPipe(const UniqueFd &pipe_fd, const void *buf, size_t size)
70 {
71 ssize_t bytes_written = PANDA_FAILURE_RETRY(write(pipe_fd.Get(), buf, size));
72 if (bytes_written < 0) {
73 return Unexpected(Error(errno));
74 }
75 return {static_cast<size_t>(bytes_written)};
76 }
77
WaitForEvent(const UniqueFd * handles,size_t size,EventType type)78 Expected<size_t, Error> WaitForEvent(const UniqueFd *handles, size_t size, EventType type)
79 {
80 uint16_t poll_events;
81 switch (type) {
82 case EventType::READY:
83 poll_events = POLLIN;
84 break;
85
86 default:
87 return Unexpected(Error("Unknown event type"));
88 }
89
90 // Initialize poll set
91 std::vector<pollfd> pollfds(size);
92 for (size_t i = 0; i < size; i++) {
93 pollfds[i].fd = handles[i].Get(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
94 pollfds[i].events = static_cast<int16_t>(poll_events);
95 }
96
97 while (true) {
98 int res = PANDA_FAILURE_RETRY(poll(pollfds.data(), size, -1));
99 if (res == -1) {
100 return Unexpected(Error(errno));
101 }
102
103 for (size_t i = 0; i < size; i++) {
104 if ((static_cast<size_t>(pollfds[i].revents) & poll_events) == poll_events) {
105 return {i};
106 }
107 }
108 }
109 }
110
Dup2(const UniqueFd & source,const UniqueFd & target)111 std::optional<Error> Dup2(const UniqueFd &source, const UniqueFd &target)
112 {
113 if (!source.IsValid()) {
114 return Error("Source fd is invalid");
115 }
116 if (PANDA_FAILURE_RETRY(dup2(source.Get(), target.Get())) == -1) {
117 return Error(errno);
118 }
119 return {};
120 }
121
122 } // namespace panda::os::unix
123