epoll/poll compat: expose interruptible API
[lttng-tools.git] / src / common / compat / compat-epoll.c
CommitLineData
5eb91c98
DG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
d14d33bf
AM
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
5eb91c98
DG
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
d14d33bf
AM
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
5eb91c98
DG
16 */
17
6c1c0768 18#define _LGPL_SOURCE
d21b0d71 19#include <assert.h>
5eb91c98
DG
20#include <fcntl.h>
21#include <limits.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
9f32e9bf 26#include <stdbool.h>
5eb91c98 27
db758600 28#include <common/error.h>
990570ed 29#include <common/defaults.h>
cfa9a5a2
DG
30#include <common/macros.h>
31#include <common/utils.h>
5eb91c98
DG
32
33#include "poll.h"
34
35unsigned int poll_max_size;
36
d21b0d71
DG
37/*
38 * Resize the epoll events structure of the new size.
39 *
40 * Return 0 on success or else -1 with the current events pointer untouched.
41 */
42static int resize_poll_event(struct lttng_poll_event *events,
43 uint32_t new_size)
44{
45 struct epoll_event *ptr;
46
47 assert(events);
48
49 ptr = realloc(events->events, new_size * sizeof(*ptr));
50 if (ptr == NULL) {
51 PERROR("realloc epoll add");
52 goto error;
53 }
53efb85a
MD
54 if (new_size > events->alloc_size) {
55 /* Zero newly allocated memory */
56 memset(ptr + events->alloc_size, 0,
57 (new_size - events->alloc_size) * sizeof(*ptr));
58 }
d21b0d71
DG
59 events->events = ptr;
60 events->alloc_size = new_size;
61
62 return 0;
63
64error:
65 return -1;
66}
67
5eb91c98
DG
68/*
69 * Create epoll set and allocate returned events structure.
70 */
71int compat_epoll_create(struct lttng_poll_event *events, int size, int flags)
72{
73 int ret;
74
75 if (events == NULL || size <= 0) {
76 goto error;
77 }
78
dbe23f45 79 if (!poll_max_size) {
22dad568
JG
80 if (lttng_poll_set_max_size()) {
81 goto error;
82 }
dbe23f45
MD
83 }
84
5eb91c98 85 /* Don't bust the limit here */
dbe23f45 86 if (size > poll_max_size) {
5eb91c98
DG
87 size = poll_max_size;
88 }
89
f263b7fd 90 ret = compat_glibc_epoll_create(size, flags);
5eb91c98
DG
91 if (ret < 0) {
92 /* At this point, every error is fatal */
4c462e79 93 PERROR("epoll_create1");
5eb91c98
DG
94 goto error;
95 }
96
97 events->epfd = ret;
98
99 /* This *must* be freed by using lttng_poll_free() */
100 events->events = zmalloc(size * sizeof(struct epoll_event));
101 if (events->events == NULL) {
4c462e79 102 PERROR("zmalloc epoll set");
5eb91c98
DG
103 goto error_close;
104 }
105
d21b0d71 106 events->alloc_size = events->init_size = size;
5eb91c98
DG
107 events->nb_fd = 0;
108
109 return 0;
110
111error_close:
4c462e79
MD
112 ret = close(events->epfd);
113 if (ret) {
114 PERROR("close");
115 }
5eb91c98
DG
116error:
117 return -1;
118}
119
120/*
121 * Add a fd to the epoll set with requesting events.
122 */
123int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
124{
d21b0d71
DG
125 int ret;
126 struct epoll_event ev;
5eb91c98
DG
127
128 if (events == NULL || events->events == NULL || fd < 0) {
129 ERR("Bad compat epoll add arguments");
130 goto error;
131 }
132
53efb85a
MD
133 /*
134 * Zero struct epoll_event to ensure all representations of its
135 * union are zeroed.
136 */
137 memset(&ev, 0, sizeof(ev));
5eb91c98
DG
138 ev.events = req_events;
139 ev.data.fd = fd;
140
141 ret = epoll_ctl(events->epfd, EPOLL_CTL_ADD, fd, &ev);
142 if (ret < 0) {
143 switch (errno) {
144 case EEXIST:
b7a6b49f
DG
145 /* If exist, it's OK. */
146 goto end;
5eb91c98
DG
147 case ENOSPC:
148 case EPERM:
4c462e79
MD
149 /* Print PERROR and goto end not failing. Show must go on. */
150 PERROR("epoll_ctl ADD");
5eb91c98
DG
151 goto end;
152 default:
4c462e79 153 PERROR("epoll_ctl ADD fatal");
5eb91c98
DG
154 goto error;
155 }
156 }
157
158 events->nb_fd++;
159
5eb91c98
DG
160end:
161 return 0;
162
163error:
164 return -1;
165}
166
167/*
168 * Remove a fd from the epoll set.
169 */
170int compat_epoll_del(struct lttng_poll_event *events, int fd)
171{
172 int ret;
173
dbe23f45 174 if (events == NULL || fd < 0 || events->nb_fd == 0) {
5eb91c98
DG
175 goto error;
176 }
177
178 ret = epoll_ctl(events->epfd, EPOLL_CTL_DEL, fd, NULL);
179 if (ret < 0) {
180 switch (errno) {
181 case ENOENT:
182 case EPERM:
4c462e79
MD
183 /* Print PERROR and goto end not failing. Show must go on. */
184 PERROR("epoll_ctl DEL");
5eb91c98
DG
185 goto end;
186 default:
4c462e79 187 PERROR("epoll_ctl DEL fatal");
5eb91c98
DG
188 goto error;
189 }
5eb91c98
DG
190 }
191
192 events->nb_fd--;
193
194end:
195 return 0;
f057dfc3
JG
196
197error:
198 return -1;
199}
200
201/*
202 * Set an fd's events.
203 */
204int compat_epoll_mod(struct lttng_poll_event *events, int fd, uint32_t req_events)
205{
206 int ret;
207 struct epoll_event ev;
208
209 if (events == NULL || fd < 0 || events->nb_fd == 0) {
210 goto error;
211 }
212
213 /*
214 * Zero struct epoll_event to ensure all representations of its
215 * union are zeroed.
216 */
217 memset(&ev, 0, sizeof(ev));
218 ev.events = req_events;
219 ev.data.fd = fd;
220
221 ret = epoll_ctl(events->epfd, EPOLL_CTL_MOD, fd, &ev);
222 if (ret < 0) {
223 switch (errno) {
224 case ENOENT:
225 case EPERM:
226 /* Print PERROR and goto end not failing. Show must go on. */
227 PERROR("epoll_ctl MOD");
228 goto end;
229 default:
230 PERROR("epoll_ctl MOD fatal");
231 goto error;
232 }
233 }
234
235end:
236 return 0;
5eb91c98
DG
237
238error:
239 return -1;
240}
241
242/*
243 * Wait on epoll set. This is a blocking call of timeout value.
244 */
9f32e9bf
MD
245int compat_epoll_wait(struct lttng_poll_event *events, int timeout,
246 bool interruptible)
5eb91c98
DG
247{
248 int ret;
d21b0d71 249 uint32_t new_size;
5eb91c98 250
d21b0d71 251 if (events == NULL || events->events == NULL) {
5eb91c98
DG
252 ERR("Wrong arguments in compat_epoll_wait");
253 goto error;
254 }
dbe23f45
MD
255
256 if (events->nb_fd == 0) {
257 errno = EINVAL;
258 return -1;
259 }
5eb91c98 260
d21b0d71
DG
261 /*
262 * Resize if needed before waiting. We could either expand the array or
263 * shrink it down. It's important to note that after this step, we are
264 * ensured that the events argument of the epoll_wait call will be large
265 * enough to hold every possible returned events.
266 */
dbe23f45
MD
267 new_size = 1U << utils_get_count_order_u32(events->nb_fd);
268 if (new_size != events->alloc_size && new_size >= events->init_size) {
d21b0d71
DG
269 ret = resize_poll_event(events, new_size);
270 if (ret < 0) {
271 /* ENOMEM problem at this point. */
272 goto error;
273 }
274 }
275
3ada8405
DG
276 do {
277 ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
9f32e9bf 278 } while (!interruptible && ret == -1 && errno == EINTR);
5eb91c98 279 if (ret < 0) {
9f32e9bf
MD
280 if (errno != EINTR) {
281 PERROR("epoll_wait");
282 }
5eb91c98
DG
283 goto error;
284 }
285
9ddba525
DG
286 /*
287 * Since the returned events are set sequentially in the "events" structure
288 * we only need to return the epoll_wait value and iterate over it.
289 */
5eb91c98
DG
290 return ret;
291
292error:
293 return -1;
294}
295
296/*
297 * Setup poll set maximum size.
298 */
dbe23f45 299int compat_epoll_set_max_size(void)
5eb91c98 300{
dbe23f45 301 int ret, fd, retval = 0;
13021756 302 ssize_t size_ret;
5eb91c98
DG
303 char buf[64];
304
990570ed 305 fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
5eb91c98 306 if (fd < 0) {
d3f531ff
JR
307 /*
308 * Failing on opening [1] is not an error per see. [1] was
309 * introduced in Linux 2.6.28 but epoll is available since
310 * 2.5.44. Hence, goto end and set a default value without
311 * setting an error return value.
312 *
313 * [1] /proc/sys/fs/epoll/max_user_watches
314 */
315 retval = 0;
dbe23f45 316 goto end;
5eb91c98
DG
317 }
318
6cd525e8
MD
319 size_ret = lttng_read(fd, buf, sizeof(buf));
320 /*
321 * Allow reading a file smaller than buf, but keep space for
322 * final \0.
323 */
324 if (size_ret < 0 || size_ret >= sizeof(buf)) {
4c462e79 325 PERROR("read set max size");
dbe23f45
MD
326 retval = -1;
327 goto end_read;
5eb91c98 328 }
6cd525e8 329 buf[size_ret] = '\0';
5eb91c98 330 poll_max_size = atoi(buf);
dbe23f45 331end_read:
4c462e79
MD
332 ret = close(fd);
333 if (ret) {
334 PERROR("close");
335 }
dbe23f45
MD
336end:
337 if (!poll_max_size) {
338 poll_max_size = DEFAULT_POLL_SIZE;
339 }
340 DBG("epoll set max size is %d", poll_max_size);
341 return retval;
5eb91c98 342}
This page took 0.060411 seconds and 4 git commands to generate.