1 #define _POSIX_C_SOURCE 200809L
2
3 #include "pipe.h"
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <limits.h>
8 #include <poll.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 #include "error.h"
13 #include "handle.h"
14
15 const int PIPE_INVALID = -1;
16
17 const short PIPE_EVENT_IN = POLLIN;
18 const short PIPE_EVENT_OUT = POLLOUT;
19
pipe_init(int * read,int * write)20 int pipe_init(int *read, int *write)
21 {
22 ASSERT(read);
23 ASSERT(write);
24
25 int pair[] = { PIPE_INVALID, PIPE_INVALID };
26 int r = -1;
27
28 r = pipe(pair);
29 if (r < 0) {
30 r = -errno;
31 goto finish;
32 }
33
34 r = handle_cloexec(pair[0], true);
35 if (r < 0) {
36 goto finish;
37 }
38
39 r = handle_cloexec(pair[1], true);
40 if (r < 0) {
41 goto finish;
42 }
43
44 *read = pair[0];
45 *write = pair[1];
46
47 pair[0] = PIPE_INVALID;
48 pair[1] = PIPE_INVALID;
49
50 finish:
51 pipe_destroy(pair[0]);
52 pipe_destroy(pair[1]);
53
54 return r;
55 }
56
pipe_nonblocking(int pipe,bool enable)57 int pipe_nonblocking(int pipe, bool enable)
58 {
59 int r = -1;
60
61 r = fcntl(pipe, F_GETFL, 0);
62 if (r < 0) {
63 return -errno;
64 }
65
66 r = enable ? r | O_NONBLOCK : r & ~O_NONBLOCK;
67
68 r = fcntl(pipe, F_SETFL, r);
69
70 return r < 0 ? -errno : 0;
71 }
72
pipe_read(int pipe,uint8_t * buffer,size_t size)73 int pipe_read(int pipe, uint8_t *buffer, size_t size)
74 {
75 ASSERT(pipe != PIPE_INVALID);
76 ASSERT(buffer);
77
78 int r = (int) read(pipe, buffer, size);
79
80 if (r == 0) {
81 // `read` returns 0 to indicate the other end of the pipe was closed.
82 return -EPIPE;
83 }
84
85 return r < 0 ? -errno : r;
86 }
87
pipe_write(int pipe,const uint8_t * buffer,size_t size)88 int pipe_write(int pipe, const uint8_t *buffer, size_t size)
89 {
90 ASSERT(pipe != PIPE_INVALID);
91 ASSERT(buffer);
92
93 int r = (int) write(pipe, buffer, size);
94
95 return r < 0 ? -errno : r;
96 }
97
pipe_poll(pipe_event_source * sources,size_t num_sources,int timeout)98 int pipe_poll(pipe_event_source *sources, size_t num_sources, int timeout)
99 {
100 ASSERT(num_sources <= INT_MAX);
101
102 struct pollfd *pollfds = NULL;
103 int r = -1;
104
105 pollfds = calloc(num_sources, sizeof(struct pollfd));
106 if (pollfds == NULL) {
107 r = -errno;
108 goto finish;
109 }
110
111 for (size_t i = 0; i < num_sources; i++) {
112 pollfds[i].fd = sources[i].pipe;
113 pollfds[i].events = sources[i].interests;
114 }
115
116 r = poll(pollfds, (nfds_t) num_sources, timeout);
117 if (r < 0) {
118 r = -errno;
119 goto finish;
120 }
121
122 for (size_t i = 0; i < num_sources; i++) {
123 sources[i].events = pollfds[i].revents;
124 }
125
126 finish:
127 free(pollfds);
128
129 return r;
130 }
131
pipe_shutdown(int pipe)132 int pipe_shutdown(int pipe)
133 {
134 (void) pipe;
135 return 0;
136 }
137
pipe_destroy(int pipe)138 int pipe_destroy(int pipe)
139 {
140 return handle_destroy(pipe);
141 }
142