Fix: potential use of uninitialized return value
[lttng-tools.git] / src / common / compat / compat-epoll.c
1 /*
2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <assert.h>
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>
16 #include <stdbool.h>
17
18 #include <common/error.h>
19 #include <common/defaults.h>
20 #include <common/macros.h>
21 #include <common/utils.h>
22
23 #include "poll.h"
24
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 */
35 static unsigned int poll_max_size;
36
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 */
42 static 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 }
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 }
59 events->events = ptr;
60 events->alloc_size = new_size;
61
62 return 0;
63
64 error:
65 return -1;
66 }
67
68 /*
69 * Create epoll set and allocate returned events structure.
70 */
71 LTTNG_HIDDEN
72 int 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
80 if (!poll_max_size) {
81 if (lttng_poll_set_max_size()) {
82 goto error;
83 }
84 }
85
86 /* Don't bust the limit here */
87 if (size > poll_max_size) {
88 size = poll_max_size;
89 }
90
91 ret = compat_glibc_epoll_create(size, flags);
92 if (ret < 0) {
93 /* At this point, every error is fatal */
94 PERROR("epoll_create1");
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) {
103 PERROR("zmalloc epoll set");
104 goto error_close;
105 }
106
107 events->alloc_size = events->init_size = size;
108 events->nb_fd = 0;
109
110 return 0;
111
112 error_close:
113 ret = close(events->epfd);
114 if (ret) {
115 PERROR("close");
116 }
117 error:
118 return -1;
119 }
120
121 /*
122 * Add a fd to the epoll set with requesting events.
123 */
124 LTTNG_HIDDEN
125 int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
126 {
127 int ret;
128 struct epoll_event ev;
129
130 if (events == NULL || events->events == NULL || fd < 0) {
131 ERR("Bad compat epoll add arguments");
132 goto error;
133 }
134
135 /*
136 * Zero struct epoll_event to ensure all representations of its
137 * union are zeroed.
138 */
139 memset(&ev, 0, sizeof(ev));
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:
147 /* If exist, it's OK. */
148 goto end;
149 case ENOSPC:
150 case EPERM:
151 /* Print PERROR and goto end not failing. Show must go on. */
152 PERROR("epoll_ctl ADD");
153 goto end;
154 default:
155 PERROR("epoll_ctl ADD fatal");
156 goto error;
157 }
158 }
159
160 events->nb_fd++;
161
162 end:
163 return 0;
164
165 error:
166 return -1;
167 }
168
169 /*
170 * Remove a fd from the epoll set.
171 */
172 LTTNG_HIDDEN
173 int compat_epoll_del(struct lttng_poll_event *events, int fd)
174 {
175 int ret;
176
177 if (events == NULL || fd < 0 || events->nb_fd == 0) {
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:
186 /* Print PERROR and goto end not failing. Show must go on. */
187 PERROR("epoll_ctl DEL");
188 goto end;
189 default:
190 PERROR("epoll_ctl DEL fatal");
191 goto error;
192 }
193 }
194
195 events->nb_fd--;
196
197 end:
198 return 0;
199
200 error:
201 return -1;
202 }
203
204 /*
205 * Set an fd's events.
206 */
207 LTTNG_HIDDEN
208 int 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
239 end:
240 return 0;
241
242 error:
243 return -1;
244 }
245
246 /*
247 * Wait on epoll set. This is a blocking call of timeout value.
248 */
249 LTTNG_HIDDEN
250 int compat_epoll_wait(struct lttng_poll_event *events, int timeout,
251 bool interruptible)
252 {
253 int ret;
254 uint32_t new_size;
255
256 if (events == NULL || events->events == NULL) {
257 ERR("Wrong arguments in compat_epoll_wait");
258 goto error;
259 }
260
261 if (events->nb_fd == 0) {
262 errno = EINVAL;
263 return -1;
264 }
265
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 */
272 new_size = 1U << utils_get_count_order_u32(events->nb_fd);
273 if (new_size != events->alloc_size && new_size >= events->init_size) {
274 ret = resize_poll_event(events, new_size);
275 if (ret < 0) {
276 /* ENOMEM problem at this point. */
277 goto error;
278 }
279 }
280
281 do {
282 ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
283 } while (!interruptible && ret == -1 && errno == EINTR);
284 if (ret < 0) {
285 if (errno != EINTR) {
286 PERROR("epoll_wait");
287 }
288 goto error;
289 }
290
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 */
295 return ret;
296
297 error:
298 return -1;
299 }
300
301 /*
302 * Setup poll set maximum size.
303 */
304 LTTNG_HIDDEN
305 int compat_epoll_set_max_size(void)
306 {
307 int ret, fd, retval = 0;
308 ssize_t size_ret;
309 char buf[64];
310
311 fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
312 if (fd < 0) {
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;
322 goto end;
323 }
324
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)) {
331 PERROR("read set max size");
332 retval = -1;
333 goto end_read;
334 }
335 buf[size_ret] = '\0';
336 poll_max_size = atoi(buf);
337 end_read:
338 ret = close(fd);
339 if (ret) {
340 PERROR("close");
341 }
342 end:
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;
348 }
This page took 0.055061 seconds and 4 git commands to generate.