Print this page
OS-5518 devpoll write feigns success in the face of EINTR
OS-5520 epoll_ctl not allowed to emit EINTR
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
OS-5459 epoll_ctl should throw EINVAL for loops
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libc/port/sys/epoll.c
+++ new/usr/src/lib/libc/port/sys/epoll.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 - * Copyright (c) 2014, Joyent, Inc. All rights reserved.
13 + * Copyright 2016 Joyent, Inc.
14 14 */
15 15
16 16 #include <sys/types.h>
17 17 #include <sys/epoll.h>
18 18 #include <sys/devpoll.h>
19 19 #include <unistd.h>
20 20 #include <errno.h>
21 21 #include <fcntl.h>
22 22 #include <poll.h>
23 23
24 24 /*
25 25 * Events that match their epoll(7) equivalents.
26 26 */
27 27 #if EPOLLIN != POLLIN
28 28 #error value of EPOLLIN does not match value of POLLIN
29 29 #endif
30 30
31 31 #if EPOLLPRI != POLLPRI
32 32 #error value of EPOLLPRI does not match value of POLLPRI
33 33 #endif
34 34
35 35 #if EPOLLOUT != POLLOUT
36 36 #error value of EPOLLOUT does not match value of POLLOUT
37 37 #endif
38 38
39 39 #if EPOLLRDNORM != POLLRDNORM
40 40 #error value of EPOLLRDNORM does not match value of POLLRDNORM
41 41 #endif
42 42
43 43 #if EPOLLRDBAND != POLLRDBAND
44 44 #error value of EPOLLRDBAND does not match value of POLLRDBAND
45 45 #endif
46 46
47 47 #if EPOLLERR != POLLERR
48 48 #error value of EPOLLERR does not match value of POLLERR
49 49 #endif
50 50
51 51 #if EPOLLHUP != POLLHUP
52 52 #error value of EPOLLHUP does not match value of POLLHUP
53 53 #endif
54 54
55 55 /*
56 56 * Events that we ignore entirely. They can be set in events, but they will
57 57 * never be returned.
58 58 */
59 59 #define EPOLLIGNORED (EPOLLMSG | EPOLLWAKEUP)
60 60
61 61 /*
62 62 * Events that we swizzle into other bit positions.
63 63 */
64 64 #define EPOLLSWIZZLED \
65 65 (EPOLLRDHUP | EPOLLONESHOT | EPOLLET | EPOLLWRBAND | EPOLLWRNORM)
66 66
67 67 int
68 68 epoll_create(int size)
69 69 {
70 70 int fd;
71 71
72 72 /*
73 73 * From the epoll_create() man page: "Since Linux 2.6.8, the size
74 74 * argument is ignored, but must be greater than zero." You keep using
75 75 * that word "ignored"...
76 76 */
77 77 if (size <= 0) {
78 78 errno = EINVAL;
79 79 return (-1);
80 80 }
81 81
82 82 if ((fd = open("/dev/poll", O_RDWR)) == -1)
83 83 return (-1);
84 84
85 85 if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) {
86 86 (void) close(fd);
87 87 return (-1);
88 88 }
89 89
90 90 return (fd);
91 91 }
92 92
93 93 int
94 94 epoll_create1(int flags)
95 95 {
96 96 int fd, oflags = O_RDWR;
97 97
98 98 if (flags & EPOLL_CLOEXEC)
99 99 oflags |= O_CLOEXEC;
100 100
101 101 if ((fd = open("/dev/poll", oflags)) == -1)
102 102 return (-1);
103 103
104 104 if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) {
105 105 (void) close(fd);
106 106 return (-1);
|
↓ open down ↓ |
83 lines elided |
↑ open up ↑ |
107 107 }
108 108
109 109 return (fd);
110 110 }
111 111
112 112 int
113 113 epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
114 114 {
115 115 dvpoll_epollfd_t epoll[2];
116 116 uint32_t events, ev = 0;
117 - int i = 0;
117 + int i = 0, res;
118 118
119 119 epoll[i].dpep_pollfd.fd = fd;
120 120
121 121 switch (op) {
122 122 case EPOLL_CTL_DEL:
123 123 ev = POLLREMOVE;
124 124 break;
125 125
126 126 case EPOLL_CTL_MOD:
127 127 /*
128 128 * In the modify case, we pass down two events: one to
129 129 * remove the event and another to add it back.
130 130 */
131 131 epoll[i++].dpep_pollfd.events = POLLREMOVE;
132 132 epoll[i].dpep_pollfd.fd = fd;
133 133 /* FALLTHROUGH */
134 134
135 135 case EPOLL_CTL_ADD:
136 136 /*
137 137 * Mask off the events that we ignore, and then swizzle the
138 138 * events for which our values differ from their epoll(7)
139 139 * equivalents.
140 140 */
141 141 events = event->events;
142 142 ev = events & ~(EPOLLIGNORED | EPOLLSWIZZLED);
143 143
144 144 if (events & EPOLLRDHUP)
145 145 ev |= POLLRDHUP;
146 146
147 147 if (events & EPOLLET)
148 148 ev |= POLLET;
149 149
150 150 if (events & EPOLLONESHOT)
151 151 ev |= POLLONESHOT;
152 152
153 153 if (events & EPOLLWRNORM)
154 154 ev |= POLLWRNORM;
155 155
156 156 if (events & EPOLLWRBAND)
157 157 ev |= POLLWRBAND;
|
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
158 158
159 159 epoll[i].dpep_data = event->data.u64;
160 160 break;
161 161
162 162 default:
163 163 errno = EOPNOTSUPP;
164 164 return (-1);
165 165 }
166 166
167 167 epoll[i].dpep_pollfd.events = ev;
168 +retry:
169 + res = write(epfd, epoll, sizeof (epoll[0]) * (i + 1));
168 170
169 - return (write(epfd, epoll, sizeof (epoll[0]) * (i + 1)) == -1 ? -1 : 0);
171 + if (res == -1) {
172 + if (errno == EINTR) {
173 + /*
174 + * Linux does not document EINTR as an allowed error
175 + * for epoll_ctl. The write must be retried if it is
176 + * not done automatically via SA_RESTART.
177 + */
178 + goto retry;
179 + }
180 + if (errno == ELOOP) {
181 + /*
182 + * Convert the specific /dev/poll error about an fd
183 + * loop into what is expected from the Linux epoll
184 + * interface.
185 + */
186 + errno = EINVAL;
187 + }
188 + return (-1);
189 + }
190 + return (0);
170 191 }
171 192
172 193 int
173 194 epoll_wait(int epfd, struct epoll_event *events,
174 195 int maxevents, int timeout)
175 196 {
176 197 struct dvpoll arg;
177 198
178 199 if (maxevents <= 0) {
179 200 errno = EINVAL;
180 201 return (-1);
181 202 }
182 203
183 204 arg.dp_nfds = maxevents;
184 205 arg.dp_timeout = timeout;
185 206 arg.dp_fds = (pollfd_t *)events;
186 207
187 208 return (ioctl(epfd, DP_POLL, &arg));
188 209 }
189 210
190 211 int
191 212 epoll_pwait(int epfd, struct epoll_event *events,
192 213 int maxevents, int timeout, const sigset_t *sigmask)
193 214 {
194 215 struct dvpoll arg;
195 216
196 217 if (maxevents <= 0) {
197 218 errno = EINVAL;
198 219 return (-1);
199 220 }
200 221
201 222 arg.dp_nfds = maxevents;
202 223 arg.dp_timeout = timeout;
203 224 arg.dp_fds = (pollfd_t *)events;
204 225 arg.dp_setp = (sigset_t *)sigmask;
205 226
206 227 return (ioctl(epfd, DP_PPOLL, &arg));
207 228 }
|
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX