Fix: define _LGPL_SOURCE in C files
[lttng-tools.git] / src / common / compat / compat-epoll.c
CommitLineData
5eb91c98
DG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
d14d33bf
AM
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.
5eb91c98
DG
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 *
d14d33bf
AM
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.
5eb91c98
DG
16 */
17
4c462e79 18#define _GNU_SOURCE
6c1c0768 19#define _LGPL_SOURCE
d21b0d71 20#include <assert.h>
5eb91c98
DG
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>
3bd1e081 27#include <config.h>
5eb91c98 28
db758600 29#include <common/error.h>
990570ed 30#include <common/defaults.h>
cfa9a5a2
DG
31#include <common/macros.h>
32#include <common/utils.h>
5eb91c98
DG
33
34#include "poll.h"
35
36unsigned int poll_max_size;
37
d21b0d71
DG
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 */
43static 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 }
53efb85a
MD
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 }
d21b0d71
DG
60 events->events = ptr;
61 events->alloc_size = new_size;
62
63 return 0;
64
65error:
66 return -1;
67}
68
5eb91c98
DG
69/*
70 * Create epoll set and allocate returned events structure.
71 */
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
80 /* Don't bust the limit here */
fb3a43a9 81 if (size > poll_max_size && poll_max_size != 0) {
5eb91c98
DG
82 size = poll_max_size;
83 }
84
f263b7fd 85 ret = compat_glibc_epoll_create(size, flags);
5eb91c98
DG
86 if (ret < 0) {
87 /* At this point, every error is fatal */
4c462e79 88 PERROR("epoll_create1");
5eb91c98
DG
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) {
4c462e79 97 PERROR("zmalloc epoll set");
5eb91c98
DG
98 goto error_close;
99 }
100
d21b0d71 101 events->alloc_size = events->init_size = size;
5eb91c98
DG
102 events->nb_fd = 0;
103
104 return 0;
105
106error_close:
4c462e79
MD
107 ret = close(events->epfd);
108 if (ret) {
109 PERROR("close");
110 }
5eb91c98
DG
111error:
112 return -1;
113}
114
115/*
116 * Add a fd to the epoll set with requesting events.
117 */
118int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
119{
d21b0d71
DG
120 int ret;
121 struct epoll_event ev;
5eb91c98
DG
122
123 if (events == NULL || events->events == NULL || fd < 0) {
124 ERR("Bad compat epoll add arguments");
125 goto error;
126 }
127
53efb85a
MD
128 /*
129 * Zero struct epoll_event to ensure all representations of its
130 * union are zeroed.
131 */
132 memset(&ev, 0, sizeof(ev));
5eb91c98
DG
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:
b7a6b49f
DG
140 /* If exist, it's OK. */
141 goto end;
5eb91c98
DG
142 case ENOSPC:
143 case EPERM:
4c462e79
MD
144 /* Print PERROR and goto end not failing. Show must go on. */
145 PERROR("epoll_ctl ADD");
5eb91c98
DG
146 goto end;
147 default:
4c462e79 148 PERROR("epoll_ctl ADD fatal");
5eb91c98
DG
149 goto error;
150 }
151 }
152
153 events->nb_fd++;
154
5eb91c98
DG
155end:
156 return 0;
157
158error:
159 return -1;
160}
161
162/*
163 * Remove a fd from the epoll set.
164 */
165int 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:
4c462e79
MD
178 /* Print PERROR and goto end not failing. Show must go on. */
179 PERROR("epoll_ctl DEL");
5eb91c98
DG
180 goto end;
181 default:
4c462e79 182 PERROR("epoll_ctl DEL fatal");
5eb91c98
DG
183 goto error;
184 }
5eb91c98
DG
185 }
186
187 events->nb_fd--;
188
189end:
190 return 0;
191
192error:
193 return -1;
194}
195
196/*
197 * Wait on epoll set. This is a blocking call of timeout value.
198 */
199int compat_epoll_wait(struct lttng_poll_event *events, int timeout)
200{
201 int ret;
d21b0d71 202 uint32_t new_size;
5eb91c98 203
d21b0d71 204 if (events == NULL || events->events == NULL) {
5eb91c98
DG
205 ERR("Wrong arguments in compat_epoll_wait");
206 goto error;
207 }
208
d21b0d71
DG
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. */
cfa9a5a2
DG
217 new_size = max_t(uint32_t,
218 1U << utils_get_count_order_u32(events->nb_fd),
219 events->alloc_size << 1UL);
d21b0d71
DG
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. */
cfa9a5a2
DG
223 new_size = max_t(uint32_t,
224 utils_get_count_order_u32(events->nb_fd) >> 1U,
225 events->alloc_size >> 1U);
d21b0d71
DG
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
3ada8405
DG
239 do {
240 ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
241 } while (ret == -1 && errno == EINTR);
5eb91c98
DG
242 if (ret < 0) {
243 /* At this point, every error is fatal */
4c462e79 244 PERROR("epoll_wait");
5eb91c98
DG
245 goto error;
246 }
247
9ddba525
DG
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 */
5eb91c98
DG
252 return ret;
253
254error:
255 return -1;
256}
257
258/*
259 * Setup poll set maximum size.
260 */
261void compat_epoll_set_max_size(void)
262{
263 int ret, fd;
13021756 264 ssize_t size_ret;
5eb91c98
DG
265 char buf[64];
266
990570ed 267 poll_max_size = DEFAULT_POLL_SIZE;
5eb91c98 268
990570ed 269 fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
5eb91c98
DG
270 if (fd < 0) {
271 return;
272 }
273
6cd525e8
MD
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)) {
4c462e79 280 PERROR("read set max size");
5eb91c98
DG
281 goto error;
282 }
6cd525e8 283 buf[size_ret] = '\0';
5eb91c98
DG
284
285 poll_max_size = atoi(buf);
d21b0d71 286 if (poll_max_size == 0) {
5eb91c98 287 /* Extra precaution */
990570ed 288 poll_max_size = DEFAULT_POLL_SIZE;
5eb91c98
DG
289 }
290
291 DBG("epoll set max size is %d", poll_max_size);
292
293error:
4c462e79
MD
294 ret = close(fd);
295 if (ret) {
296 PERROR("close");
297 }
5eb91c98 298}
This page took 0.056285 seconds and 5 git commands to generate.