Port: Add macro for socket linking on solaris
[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
dbe23f45
MD
80 if (!poll_max_size) {
81 ERR("poll_max_size not initialized yet");
82 goto error;
83 }
84
5eb91c98 85 /* Don't bust the limit here */
dbe23f45 86 if (size > poll_max_size) {
5eb91c98
DG
87 size = poll_max_size;
88 }
89
f263b7fd 90 ret = compat_glibc_epoll_create(size, flags);
5eb91c98
DG
91 if (ret < 0) {
92 /* At this point, every error is fatal */
4c462e79 93 PERROR("epoll_create1");
5eb91c98
DG
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) {
4c462e79 102 PERROR("zmalloc epoll set");
5eb91c98
DG
103 goto error_close;
104 }
105
d21b0d71 106 events->alloc_size = events->init_size = size;
5eb91c98
DG
107 events->nb_fd = 0;
108
109 return 0;
110
111error_close:
4c462e79
MD
112 ret = close(events->epfd);
113 if (ret) {
114 PERROR("close");
115 }
5eb91c98
DG
116error:
117 return -1;
118}
119
120/*
121 * Add a fd to the epoll set with requesting events.
122 */
123int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
124{
d21b0d71
DG
125 int ret;
126 struct epoll_event ev;
5eb91c98
DG
127
128 if (events == NULL || events->events == NULL || fd < 0) {
129 ERR("Bad compat epoll add arguments");
130 goto error;
131 }
132
53efb85a
MD
133 /*
134 * Zero struct epoll_event to ensure all representations of its
135 * union are zeroed.
136 */
137 memset(&ev, 0, sizeof(ev));
5eb91c98
DG
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:
b7a6b49f
DG
145 /* If exist, it's OK. */
146 goto end;
5eb91c98
DG
147 case ENOSPC:
148 case EPERM:
4c462e79
MD
149 /* Print PERROR and goto end not failing. Show must go on. */
150 PERROR("epoll_ctl ADD");
5eb91c98
DG
151 goto end;
152 default:
4c462e79 153 PERROR("epoll_ctl ADD fatal");
5eb91c98
DG
154 goto error;
155 }
156 }
157
158 events->nb_fd++;
159
5eb91c98
DG
160end:
161 return 0;
162
163error:
164 return -1;
165}
166
167/*
168 * Remove a fd from the epoll set.
169 */
170int compat_epoll_del(struct lttng_poll_event *events, int fd)
171{
172 int ret;
173
dbe23f45 174 if (events == NULL || fd < 0 || events->nb_fd == 0) {
5eb91c98
DG
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:
4c462e79
MD
183 /* Print PERROR and goto end not failing. Show must go on. */
184 PERROR("epoll_ctl DEL");
5eb91c98
DG
185 goto end;
186 default:
4c462e79 187 PERROR("epoll_ctl DEL fatal");
5eb91c98
DG
188 goto error;
189 }
5eb91c98
DG
190 }
191
192 events->nb_fd--;
193
194end:
195 return 0;
196
197error:
198 return -1;
199}
200
201/*
202 * Wait on epoll set. This is a blocking call of timeout value.
203 */
204int compat_epoll_wait(struct lttng_poll_event *events, int timeout)
205{
206 int ret;
d21b0d71 207 uint32_t new_size;
5eb91c98 208
d21b0d71 209 if (events == NULL || events->events == NULL) {
5eb91c98
DG
210 ERR("Wrong arguments in compat_epoll_wait");
211 goto error;
212 }
dbe23f45
MD
213 assert(events->nb_fd >= 0);
214
215 if (events->nb_fd == 0) {
216 errno = EINVAL;
217 return -1;
218 }
5eb91c98 219
d21b0d71
DG
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 */
dbe23f45
MD
226 new_size = 1U << utils_get_count_order_u32(events->nb_fd);
227 if (new_size != events->alloc_size && new_size >= events->init_size) {
d21b0d71
DG
228 ret = resize_poll_event(events, new_size);
229 if (ret < 0) {
230 /* ENOMEM problem at this point. */
231 goto error;
232 }
233 }
234
3ada8405
DG
235 do {
236 ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
237 } while (ret == -1 && errno == EINTR);
5eb91c98
DG
238 if (ret < 0) {
239 /* At this point, every error is fatal */
4c462e79 240 PERROR("epoll_wait");
5eb91c98
DG
241 goto error;
242 }
243
9ddba525
DG
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 */
5eb91c98
DG
248 return ret;
249
250error:
251 return -1;
252}
253
254/*
255 * Setup poll set maximum size.
256 */
dbe23f45 257int compat_epoll_set_max_size(void)
5eb91c98 258{
dbe23f45 259 int ret, fd, retval = 0;
13021756 260 ssize_t size_ret;
5eb91c98
DG
261 char buf[64];
262
990570ed 263 fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
5eb91c98 264 if (fd < 0) {
dbe23f45
MD
265 retval = -1;
266 goto end;
5eb91c98
DG
267 }
268
6cd525e8
MD
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)) {
4c462e79 275 PERROR("read set max size");
dbe23f45
MD
276 retval = -1;
277 goto end_read;
5eb91c98 278 }
6cd525e8 279 buf[size_ret] = '\0';
5eb91c98 280 poll_max_size = atoi(buf);
dbe23f45 281end_read:
4c462e79
MD
282 ret = close(fd);
283 if (ret) {
284 PERROR("close");
285 }
dbe23f45
MD
286end:
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;
5eb91c98 292}
This page took 0.062344 seconds and 5 git commands to generate.