Fix: tests: `-Wstringop-overflow` warning
[lttng-tools.git] / src / common / compat / compat-poll.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2019 - Yannick Lamarre <ylamarre@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _LGPL_SOURCE
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <sys/resource.h>
23 #include <sys/time.h>
24 #include <stdbool.h>
25
26 #include <common/defaults.h>
27 #include <common/error.h>
28 #include <common/macros.h>
29 #include <common/utils.h>
30
31 #include "poll.h"
32
33
34 /*
35 * Maximum number of fd we can monitor.
36 *
37 * For poll(2), the max fds must not exceed RLIMIT_NOFILE given by
38 * getrlimit(2).
39 */
40 static unsigned int poll_max_size;
41
42 /*
43 * Resize the epoll events structure of the new size.
44 *
45 * Return 0 on success or else -1 with the current events pointer untouched.
46 */
47 static int resize_poll_event(struct compat_poll_event_array *array,
48 uint32_t new_size)
49 {
50 struct pollfd *ptr;
51
52 assert(array);
53
54 /* Refuse to resize the array more than the max size. */
55 if (new_size > poll_max_size) {
56 goto error;
57 }
58
59 ptr = realloc(array->events, new_size * sizeof(*ptr));
60 if (ptr == NULL) {
61 PERROR("realloc epoll add");
62 goto error;
63 }
64 if (new_size > array->alloc_size) {
65 /* Zero newly allocated memory */
66 memset(ptr + array->alloc_size, 0,
67 (new_size - array->alloc_size) * sizeof(*ptr));
68 }
69 array->events = ptr;
70 array->alloc_size = new_size;
71
72 return 0;
73
74 error:
75 return -1;
76 }
77
78 /*
79 * Update events with the current events object.
80 */
81 static int update_current_events(struct lttng_poll_event *events)
82 {
83 int ret;
84 struct compat_poll_event_array *current, *wait;
85
86 assert(events);
87
88 current = &events->current;
89 wait = &events->wait;
90
91 wait->nb_fd = current->nb_fd;
92 if (current->alloc_size != wait->alloc_size) {
93 ret = resize_poll_event(wait, current->alloc_size);
94 if (ret < 0) {
95 goto error;
96 }
97 }
98 memcpy(wait->events, current->events,
99 current->nb_fd * sizeof(*current->events));
100
101 /* Update is done. */
102 events->need_update = 0;
103
104 return 0;
105
106 error:
107 return -1;
108 }
109
110 /*
111 * Create pollfd data structure.
112 */
113 LTTNG_HIDDEN
114 int compat_poll_create(struct lttng_poll_event *events, int size)
115 {
116 struct compat_poll_event_array *current, *wait;
117
118 if (events == NULL || size <= 0) {
119 ERR("Wrong arguments for poll create");
120 goto error;
121 }
122
123 if (!poll_max_size) {
124 if (lttng_poll_set_max_size()) {
125 goto error;
126 }
127 }
128
129 /* Don't bust the limit here */
130 if (size > poll_max_size) {
131 size = poll_max_size;
132 }
133
134 /* Reset everything before begining the allocation. */
135 memset(events, 0, sizeof(struct lttng_poll_event));
136
137 current = &events->current;
138 wait = &events->wait;
139
140 /* This *must* be freed by using lttng_poll_free() */
141 wait->events = zmalloc(size * sizeof(struct pollfd));
142 if (wait->events == NULL) {
143 PERROR("zmalloc struct pollfd");
144 goto error;
145 }
146
147 wait->alloc_size = wait->init_size = size;
148
149 current->events = zmalloc(size * sizeof(struct pollfd));
150 if (current->events == NULL) {
151 PERROR("zmalloc struct current pollfd");
152 goto error;
153 }
154
155 current->alloc_size = current->init_size = size;
156
157 return 0;
158
159 error:
160 return -1;
161 }
162
163 /*
164 * Add fd to pollfd data structure with requested events.
165 */
166 LTTNG_HIDDEN
167 int compat_poll_add(struct lttng_poll_event *events, int fd,
168 uint32_t req_events)
169 {
170 int new_size, ret, i;
171 struct compat_poll_event_array *current;
172
173 if (events == NULL || events->current.events == NULL || fd < 0) {
174 ERR("Bad compat poll add arguments");
175 goto error;
176 }
177
178 current = &events->current;
179
180 /* Check if fd we are trying to add is already there. */
181 for (i = 0; i < current->nb_fd; i++) {
182 if (current->events[i].fd == fd) {
183 errno = EEXIST;
184 goto error;
185 }
186 }
187
188 /* Resize array if needed. */
189 new_size = 1U << utils_get_count_order_u32(current->nb_fd + 1);
190 if (new_size != current->alloc_size && new_size >= current->init_size) {
191 ret = resize_poll_event(current, new_size);
192 if (ret < 0) {
193 goto error;
194 }
195 }
196
197 current->events[current->nb_fd].fd = fd;
198 current->events[current->nb_fd].events = req_events;
199 current->nb_fd++;
200 events->need_update = 1;
201
202 DBG("fd %d of %d added to pollfd", fd, current->nb_fd);
203
204 return 0;
205
206 error:
207 return -1;
208 }
209
210 /*
211 * Modify an fd's events..
212 */
213 LTTNG_HIDDEN
214 int compat_poll_mod(struct lttng_poll_event *events, int fd,
215 uint32_t req_events)
216 {
217 int i;
218 struct compat_poll_event_array *current;
219
220 if (events == NULL || events->current.nb_fd == 0 ||
221 events->current.events == NULL || fd < 0) {
222 ERR("Bad compat poll mod arguments");
223 goto error;
224 }
225
226 current = &events->current;
227
228 for (i = 0; i < current->nb_fd; i++) {
229 if (current->events[i].fd == fd) {
230 current->events[i].events = req_events;
231 events->need_update = 1;
232 break;
233 }
234 }
235
236 /*
237 * The epoll flavor doesn't flag modifying a non-included FD as an
238 * error.
239 */
240
241 return 0;
242
243 error:
244 return -1;
245 }
246
247 /*
248 * Remove a fd from the pollfd structure.
249 */
250 LTTNG_HIDDEN
251 int compat_poll_del(struct lttng_poll_event *events, int fd)
252 {
253 int i, count = 0, ret;
254 uint32_t new_size;
255 struct compat_poll_event_array *current;
256
257 if (events == NULL || events->current.nb_fd == 0 ||
258 events->current.events == NULL || fd < 0) {
259 goto error;
260 }
261
262 /* Ease our life a bit. */
263 current = &events->current;
264
265 for (i = 0; i < current->nb_fd; i++) {
266 /* Don't put back the fd we want to delete */
267 if (current->events[i].fd != fd) {
268 current->events[count].fd = current->events[i].fd;
269 current->events[count].events = current->events[i].events;
270 count++;
271 }
272 }
273
274 /* The fd was not in our set, return no error as with epoll. */
275 if (current->nb_fd == count) {
276 goto end;
277 }
278
279 /* No fd duplicate should be ever added into array. */
280 assert(current->nb_fd - 1 == count);
281 current->nb_fd = count;
282
283 /* Resize array if needed. */
284 new_size = 1U << utils_get_count_order_u32(current->nb_fd);
285 if (new_size != current->alloc_size && new_size >= current->init_size
286 && current->nb_fd != 0) {
287 ret = resize_poll_event(current, new_size);
288 if (ret < 0) {
289 goto error;
290 }
291 }
292
293 events->need_update = 1;
294
295 end:
296 return 0;
297
298 error:
299 return -1;
300 }
301
302 /*
303 * Wait on poll() with timeout. Blocking call.
304 */
305 LTTNG_HIDDEN
306 int compat_poll_wait(struct lttng_poll_event *events, int timeout,
307 bool interruptible)
308 {
309 int ret, active_fd_count;
310 int idle_pfd_index = 0;
311 size_t i;
312
313 if (events == NULL || events->current.events == NULL) {
314 ERR("poll wait arguments error");
315 goto error;
316 }
317 assert(events->current.nb_fd >= 0);
318
319 if (events->current.nb_fd == 0) {
320 /* Return an invalid error to be consistent with epoll. */
321 errno = EINVAL;
322 events->wait.nb_fd = 0;
323 goto error;
324 }
325
326 if (events->need_update) {
327 ret = update_current_events(events);
328 if (ret < 0) {
329 errno = ENOMEM;
330 goto error;
331 }
332 }
333
334 do {
335 ret = poll(events->wait.events, events->wait.nb_fd, timeout);
336 } while (!interruptible && ret == -1 && errno == EINTR);
337 if (ret < 0) {
338 if (errno != EINTR) {
339 PERROR("poll wait");
340 }
341 goto error;
342 }
343
344 active_fd_count = ret;
345
346 /*
347 * Swap all active pollfd structs to the beginning of the
348 * array to emulate compat-epoll behaviour. This algorithm takes
349 * advantage of poll's returned value and the burst nature of active
350 * events on the file descriptors. The while loop guarantees that
351 * idle_pfd will always point to an idle fd.
352 */
353 if (active_fd_count == events->wait.nb_fd) {
354 goto end;
355 }
356 while (idle_pfd_index < active_fd_count &&
357 events->wait.events[idle_pfd_index].revents != 0) {
358 idle_pfd_index++;
359 }
360
361 for (i = idle_pfd_index + 1; idle_pfd_index < active_fd_count;
362 i++) {
363 struct pollfd swap_pfd;
364 struct pollfd *idle_pfd = &events->wait.events[idle_pfd_index];
365 struct pollfd *current_pfd = &events->wait.events[i];
366
367 if (idle_pfd->revents != 0) {
368 swap_pfd = *current_pfd;
369 *current_pfd = *idle_pfd;
370 *idle_pfd = swap_pfd;
371 idle_pfd_index++;
372 }
373 }
374
375 end:
376 return ret;
377
378 error:
379 return -1;
380 }
381
382 /*
383 * Setup poll set maximum size.
384 */
385 LTTNG_HIDDEN
386 int compat_poll_set_max_size(void)
387 {
388 int ret, retval = 0;
389 struct rlimit lim;
390
391 ret = getrlimit(RLIMIT_NOFILE, &lim);
392 if (ret < 0) {
393 PERROR("getrlimit poll RLIMIT_NOFILE");
394 retval = -1;
395 goto end;
396 }
397
398 poll_max_size = lim.rlim_cur;
399 end:
400 if (poll_max_size == 0) {
401 poll_max_size = DEFAULT_POLL_SIZE;
402 }
403 DBG("poll set max size set to %u", poll_max_size);
404 return retval;
405 }
This page took 0.041845 seconds and 4 git commands to generate.