Fix: define _LGPL_SOURCE in C files
[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 /* Don't bust the limit here */
81 if (size > poll_max_size && poll_max_size != 0) {
82 size = poll_max_size;
83 }
84
85 ret = compat_glibc_epoll_create(size, flags);
86 if (ret < 0) {
87 /* At this point, every error is fatal */
88 PERROR("epoll_create1");
89 goto error;
90 }
91
92 events->epfd = ret;
93
94 /* This *must* be freed by using lttng_poll_free() */
95 events->events = zmalloc(size * sizeof(struct epoll_event));
96 if (events->events == NULL) {
97 PERROR("zmalloc epoll set");
98 goto error_close;
99 }
100
101 events->alloc_size = events->init_size = size;
102 events->nb_fd = 0;
103
104 return 0;
105
106 error_close:
107 ret = close(events->epfd);
108 if (ret) {
109 PERROR("close");
110 }
111 error:
112 return -1;
113 }
114
115 /*
116 * Add a fd to the epoll set with requesting events.
117 */
118 int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
119 {
120 int ret;
121 struct epoll_event ev;
122
123 if (events == NULL || events->events == NULL || fd < 0) {
124 ERR("Bad compat epoll add arguments");
125 goto error;
126 }
127
128 /*
129 * Zero struct epoll_event to ensure all representations of its
130 * union are zeroed.
131 */
132 memset(&ev, 0, sizeof(ev));
133 ev.events = req_events;
134 ev.data.fd = fd;
135
136 ret = epoll_ctl(events->epfd, EPOLL_CTL_ADD, fd, &ev);
137 if (ret < 0) {
138 switch (errno) {
139 case EEXIST:
140 /* If exist, it's OK. */
141 goto end;
142 case ENOSPC:
143 case EPERM:
144 /* Print PERROR and goto end not failing. Show must go on. */
145 PERROR("epoll_ctl ADD");
146 goto end;
147 default:
148 PERROR("epoll_ctl ADD fatal");
149 goto error;
150 }
151 }
152
153 events->nb_fd++;
154
155 end:
156 return 0;
157
158 error:
159 return -1;
160 }
161
162 /*
163 * Remove a fd from the epoll set.
164 */
165 int compat_epoll_del(struct lttng_poll_event *events, int fd)
166 {
167 int ret;
168
169 if (events == NULL || fd < 0) {
170 goto error;
171 }
172
173 ret = epoll_ctl(events->epfd, EPOLL_CTL_DEL, fd, NULL);
174 if (ret < 0) {
175 switch (errno) {
176 case ENOENT:
177 case EPERM:
178 /* Print PERROR and goto end not failing. Show must go on. */
179 PERROR("epoll_ctl DEL");
180 goto end;
181 default:
182 PERROR("epoll_ctl DEL fatal");
183 goto error;
184 }
185 }
186
187 events->nb_fd--;
188
189 end:
190 return 0;
191
192 error:
193 return -1;
194 }
195
196 /*
197 * Wait on epoll set. This is a blocking call of timeout value.
198 */
199 int compat_epoll_wait(struct lttng_poll_event *events, int timeout)
200 {
201 int ret;
202 uint32_t new_size;
203
204 if (events == NULL || events->events == NULL) {
205 ERR("Wrong arguments in compat_epoll_wait");
206 goto error;
207 }
208
209 /*
210 * Resize if needed before waiting. We could either expand the array or
211 * shrink it down. It's important to note that after this step, we are
212 * ensured that the events argument of the epoll_wait call will be large
213 * enough to hold every possible returned events.
214 */
215 if (events->nb_fd > events->alloc_size) {
216 /* Expand if the nb_fd is higher than the actual size. */
217 new_size = max_t(uint32_t,
218 1U << utils_get_count_order_u32(events->nb_fd),
219 events->alloc_size << 1UL);
220 } else if ((events->nb_fd << 1UL) <= events->alloc_size &&
221 events->nb_fd >= events->init_size) {
222 /* Shrink if nb_fd multiplied by two is <= than the actual size. */
223 new_size = max_t(uint32_t,
224 utils_get_count_order_u32(events->nb_fd) >> 1U,
225 events->alloc_size >> 1U);
226 } else {
227 /* Indicate that we don't want to resize. */
228 new_size = 0;
229 }
230
231 if (new_size) {
232 ret = resize_poll_event(events, new_size);
233 if (ret < 0) {
234 /* ENOMEM problem at this point. */
235 goto error;
236 }
237 }
238
239 do {
240 ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
241 } while (ret == -1 && errno == EINTR);
242 if (ret < 0) {
243 /* At this point, every error is fatal */
244 PERROR("epoll_wait");
245 goto error;
246 }
247
248 /*
249 * Since the returned events are set sequentially in the "events" structure
250 * we only need to return the epoll_wait value and iterate over it.
251 */
252 return ret;
253
254 error:
255 return -1;
256 }
257
258 /*
259 * Setup poll set maximum size.
260 */
261 void compat_epoll_set_max_size(void)
262 {
263 int ret, fd;
264 ssize_t size_ret;
265 char buf[64];
266
267 poll_max_size = DEFAULT_POLL_SIZE;
268
269 fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
270 if (fd < 0) {
271 return;
272 }
273
274 size_ret = lttng_read(fd, buf, sizeof(buf));
275 /*
276 * Allow reading a file smaller than buf, but keep space for
277 * final \0.
278 */
279 if (size_ret < 0 || size_ret >= sizeof(buf)) {
280 PERROR("read set max size");
281 goto error;
282 }
283 buf[size_ret] = '\0';
284
285 poll_max_size = atoi(buf);
286 if (poll_max_size == 0) {
287 /* Extra precaution */
288 poll_max_size = DEFAULT_POLL_SIZE;
289 }
290
291 DBG("epoll set max size is %d", poll_max_size);
292
293 error:
294 ret = close(fd);
295 if (ret) {
296 PERROR("close");
297 }
298 }
This page took 0.035306 seconds and 5 git commands to generate.