Fix: various compat poll/epoll issues
[lttng-tools.git] / src / common / compat / compat-epoll.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
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.
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 *
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.
16 */
17
18 #define _GNU_SOURCE
19 #define _LGPL_SOURCE
20 #include <assert.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <config.h>
28
29 #include <common/error.h>
30 #include <common/defaults.h>
31 #include <common/macros.h>
32 #include <common/utils.h>
33
34 #include "poll.h"
35
36 unsigned int poll_max_size;
37
38 /*
39 * Resize the epoll events structure of the new size.
40 *
41 * Return 0 on success or else -1 with the current events pointer untouched.
42 */
43 static int resize_poll_event(struct lttng_poll_event *events,
44 uint32_t new_size)
45 {
46 struct epoll_event *ptr;
47
48 assert(events);
49
50 ptr = realloc(events->events, new_size * sizeof(*ptr));
51 if (ptr == NULL) {
52 PERROR("realloc epoll add");
53 goto error;
54 }
55 if (new_size > events->alloc_size) {
56 /* Zero newly allocated memory */
57 memset(ptr + events->alloc_size, 0,
58 (new_size - events->alloc_size) * sizeof(*ptr));
59 }
60 events->events = ptr;
61 events->alloc_size = new_size;
62
63 return 0;
64
65 error:
66 return -1;
67 }
68
69 /*
70 * Create epoll set and allocate returned events structure.
71 */
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 ERR("poll_max_size not initialized yet");
82 goto error;
83 }
84
85 /* Don't bust the limit here */
86 if (size > poll_max_size) {
87 size = poll_max_size;
88 }
89
90 ret = compat_glibc_epoll_create(size, flags);
91 if (ret < 0) {
92 /* At this point, every error is fatal */
93 PERROR("epoll_create1");
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) {
102 PERROR("zmalloc epoll set");
103 goto error_close;
104 }
105
106 events->alloc_size = events->init_size = size;
107 events->nb_fd = 0;
108
109 return 0;
110
111 error_close:
112 ret = close(events->epfd);
113 if (ret) {
114 PERROR("close");
115 }
116 error:
117 return -1;
118 }
119
120 /*
121 * Add a fd to the epoll set with requesting events.
122 */
123 int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
124 {
125 int ret;
126 struct epoll_event ev;
127
128 if (events == NULL || events->events == NULL || fd < 0) {
129 ERR("Bad compat epoll add arguments");
130 goto error;
131 }
132
133 /*
134 * Zero struct epoll_event to ensure all representations of its
135 * union are zeroed.
136 */
137 memset(&ev, 0, sizeof(ev));
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:
145 /* If exist, it's OK. */
146 goto end;
147 case ENOSPC:
148 case EPERM:
149 /* Print PERROR and goto end not failing. Show must go on. */
150 PERROR("epoll_ctl ADD");
151 goto end;
152 default:
153 PERROR("epoll_ctl ADD fatal");
154 goto error;
155 }
156 }
157
158 events->nb_fd++;
159
160 end:
161 return 0;
162
163 error:
164 return -1;
165 }
166
167 /*
168 * Remove a fd from the epoll set.
169 */
170 int compat_epoll_del(struct lttng_poll_event *events, int fd)
171 {
172 int ret;
173
174 if (events == NULL || fd < 0 || events->nb_fd == 0) {
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:
183 /* Print PERROR and goto end not failing. Show must go on. */
184 PERROR("epoll_ctl DEL");
185 goto end;
186 default:
187 PERROR("epoll_ctl DEL fatal");
188 goto error;
189 }
190 }
191
192 events->nb_fd--;
193
194 end:
195 return 0;
196
197 error:
198 return -1;
199 }
200
201 /*
202 * Wait on epoll set. This is a blocking call of timeout value.
203 */
204 int compat_epoll_wait(struct lttng_poll_event *events, int timeout)
205 {
206 int ret;
207 uint32_t new_size;
208
209 if (events == NULL || events->events == NULL) {
210 ERR("Wrong arguments in compat_epoll_wait");
211 goto error;
212 }
213 assert(events->nb_fd >= 0);
214
215 if (events->nb_fd == 0) {
216 errno = EINVAL;
217 return -1;
218 }
219
220 /*
221 * Resize if needed before waiting. We could either expand the array or
222 * shrink it down. It's important to note that after this step, we are
223 * ensured that the events argument of the epoll_wait call will be large
224 * enough to hold every possible returned events.
225 */
226 new_size = 1U << utils_get_count_order_u32(events->nb_fd);
227 if (new_size != events->alloc_size && new_size >= events->init_size) {
228 ret = resize_poll_event(events, new_size);
229 if (ret < 0) {
230 /* ENOMEM problem at this point. */
231 goto error;
232 }
233 }
234
235 do {
236 ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
237 } while (ret == -1 && errno == EINTR);
238 if (ret < 0) {
239 /* At this point, every error is fatal */
240 PERROR("epoll_wait");
241 goto error;
242 }
243
244 /*
245 * Since the returned events are set sequentially in the "events" structure
246 * we only need to return the epoll_wait value and iterate over it.
247 */
248 return ret;
249
250 error:
251 return -1;
252 }
253
254 /*
255 * Setup poll set maximum size.
256 */
257 int compat_epoll_set_max_size(void)
258 {
259 int ret, fd, retval = 0;
260 ssize_t size_ret;
261 char buf[64];
262
263 fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
264 if (fd < 0) {
265 retval = -1;
266 goto end;
267 }
268
269 size_ret = lttng_read(fd, buf, sizeof(buf));
270 /*
271 * Allow reading a file smaller than buf, but keep space for
272 * final \0.
273 */
274 if (size_ret < 0 || size_ret >= sizeof(buf)) {
275 PERROR("read set max size");
276 retval = -1;
277 goto end_read;
278 }
279 buf[size_ret] = '\0';
280 poll_max_size = atoi(buf);
281 end_read:
282 ret = close(fd);
283 if (ret) {
284 PERROR("close");
285 }
286 end:
287 if (!poll_max_size) {
288 poll_max_size = DEFAULT_POLL_SIZE;
289 }
290 DBG("epoll set max size is %d", poll_max_size);
291 return retval;
292 }
This page took 0.035235 seconds and 5 git commands to generate.