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