From: David Goulet Date: Fri, 20 Jan 2012 20:51:04 +0000 (-0500) Subject: Move compat to common and create an internal lib X-Git-Tag: v2.0-pre18~15 X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=0ba98ebc83bf874d34c8c84b164a6ad803e9de75 Move compat to common and create an internal lib libcompat is the name of the new lib. Signed-off-by: David Goulet --- diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index e39207426..c431ade86 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -5,14 +5,7 @@ AM_CFLAGS = -fno-strict-aliasing bin_PROGRAMS = lttng-sessiond -if COMPAT_EPOLL -COMPAT=compat/compat-epoll.c -else -COMPAT=compat/compat-poll.c -endif - lttng_sessiond_SOURCES = utils.c utils.h \ - compat/poll.h $(COMPAT) \ trace-kernel.c trace-kernel.h \ kernel.c kernel.h \ ust-ctl.h ust-app.h trace-ust.h \ @@ -37,7 +30,8 @@ lttng_sessiond_LDADD = -lrt -lurcu-common -lurcu \ $(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la \ $(top_builddir)/src/common/kernel-ctl/libkernel-ctl.la \ $(top_builddir)/src/common/hashtable/libhashtable.la \ - $(top_builddir)/src/common/libcommon.la + $(top_builddir)/src/common/libcommon.la \ + $(top_builddir)/src/common/libcompat.la if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_LDADD += -llttng-ust-ctl diff --git a/src/bin/lttng-sessiond/compat/compat-epoll.c b/src/bin/lttng-sessiond/compat/compat-epoll.c deleted file mode 100644 index 5e969ee01..000000000 --- a/src/bin/lttng-sessiond/compat/compat-epoll.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2011 - David Goulet - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; only version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "poll.h" - -unsigned int poll_max_size; - -/* - * Create epoll set and allocate returned events structure. - */ -int compat_epoll_create(struct lttng_poll_event *events, int size, int flags) -{ - int ret; - - if (events == NULL || size <= 0) { - goto error; - } - - /* Don't bust the limit here */ - if (size > poll_max_size) { - size = poll_max_size; - } - - ret = epoll_create1(flags); - if (ret < 0) { - /* At this point, every error is fatal */ - perror("epoll_create1"); - goto error; - } - - events->epfd = ret; - - /* This *must* be freed by using lttng_poll_free() */ - events->events = zmalloc(size * sizeof(struct epoll_event)); - if (events->events == NULL) { - perror("zmalloc epoll set"); - goto error_close; - } - - events->events_size = size; - events->nb_fd = 0; - - return 0; - -error_close: - close(events->epfd); -error: - return -1; -} - -/* - * Add a fd to the epoll set with requesting events. - */ -int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events) -{ - int ret, new_size; - struct epoll_event ev, *ptr; - - if (events == NULL || events->events == NULL || fd < 0) { - ERR("Bad compat epoll add arguments"); - goto error; - } - - ev.events = req_events; - ev.data.fd = fd; - - ret = epoll_ctl(events->epfd, EPOLL_CTL_ADD, fd, &ev); - if (ret < 0) { - switch (errno) { - case EEXIST: - case ENOSPC: - case EPERM: - /* Print perror and goto end not failing. Show must go on. */ - perror("epoll_ctl ADD"); - goto end; - default: - perror("epoll_ctl ADD fatal"); - goto error; - } - } - - events->nb_fd++; - - if (events->nb_fd >= events->events_size) { - new_size = 2 * events->events_size; - ptr = realloc(events->events, new_size * sizeof(struct epoll_event)); - if (ptr == NULL) { - perror("realloc epoll add"); - goto error; - } - events->events = ptr; - events->events_size = new_size; - } - -end: - return 0; - -error: - return -1; -} - -/* - * Remove a fd from the epoll set. - */ -int compat_epoll_del(struct lttng_poll_event *events, int fd) -{ - int ret; - - if (events == NULL || fd < 0) { - goto error; - } - - ret = epoll_ctl(events->epfd, EPOLL_CTL_DEL, fd, NULL); - if (ret < 0) { - switch (errno) { - case ENOENT: - case EPERM: - /* Print perror and goto end not failing. Show must go on. */ - perror("epoll_ctl DEL"); - goto end; - default: - perror("epoll_ctl DEL fatal"); - goto error; - } - perror("epoll_ctl del"); - goto error; - } - - events->nb_fd--; - -end: - return 0; - -error: - return -1; -} - -/* - * Wait on epoll set. This is a blocking call of timeout value. - */ -int compat_epoll_wait(struct lttng_poll_event *events, int timeout) -{ - int ret; - - if (events == NULL || events->events == NULL || - events->events_size < events->nb_fd) { - ERR("Wrong arguments in compat_epoll_wait"); - goto error; - } - - do { - ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout); - } while (ret == -1 && errno == EINTR); - if (ret < 0) { - /* At this point, every error is fatal */ - perror("epoll_wait"); - goto error; - } - - return ret; - -error: - return -1; -} - -/* - * Setup poll set maximum size. - */ -void compat_epoll_set_max_size(void) -{ - int ret, fd; - char buf[64]; - - poll_max_size = LTTNG_POLL_DEFAULT_SIZE; - - fd = open(LTTNG_EPOLL_PROC_PATH, O_RDONLY); - if (fd < 0) { - return; - } - - ret = read(fd, buf, sizeof(buf)); - if (ret < 0) { - perror("read set max size"); - goto error; - } - - poll_max_size = atoi(buf); - if (poll_max_size <= 0) { - /* Extra precaution */ - poll_max_size = LTTNG_POLL_DEFAULT_SIZE; - } - - DBG("epoll set max size is %d", poll_max_size); - -error: - close(fd); -} diff --git a/src/bin/lttng-sessiond/compat/compat-poll.c b/src/bin/lttng-sessiond/compat/compat-poll.c deleted file mode 100644 index 50ef37472..000000000 --- a/src/bin/lttng-sessiond/compat/compat-poll.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2011 - David Goulet - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; only version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include - -#include - -#include "poll.h" - -unsigned int poll_max_size; - -/* - * Create pollfd data structure. - */ -int compat_poll_create(struct lttng_poll_event *events, int size) -{ - if (events == NULL || size <= 0) { - ERR("Wrong arguments for poll create"); - goto error; - } - - /* Don't bust the limit here */ - if (size > poll_max_size) { - size = poll_max_size; - } - - /* This *must* be freed by using lttng_poll_free() */ - events->events = zmalloc(size * sizeof(struct pollfd)); - if (events->events == NULL) { - perror("zmalloc struct pollfd"); - goto error; - } - - events->events_size = size; - events->nb_fd = 0; - - return 0; - -error: - return -1; -} - -/* - * Add fd to pollfd data structure with requested events. - */ -int compat_poll_add(struct lttng_poll_event *events, int fd, - uint32_t req_events) -{ - int new_size; - struct pollfd *ptr; - - if (events == NULL || events->events == NULL || fd < 0) { - ERR("Bad compat poll add arguments"); - goto error; - } - - /* Reallocate pollfd structure by a factor of 2 if needed. */ - if (events->nb_fd >= events->events_size) { - new_size = 2 * events->events_size; - ptr = realloc(events->events, new_size * sizeof(struct pollfd)); - if (ptr == NULL) { - perror("realloc poll add"); - goto error; - } - events->events = ptr; - events->events_size = new_size; - } - - events->events[events->nb_fd].fd = fd; - events->events[events->nb_fd].events = req_events; - events->nb_fd++; - - DBG("fd %d of %d added to pollfd", fd, events->nb_fd); - - return 0; - -error: - return -1; -} - -/* - * Remove a fd from the pollfd structure. - */ -int compat_poll_del(struct lttng_poll_event *events, int fd) -{ - int new_size, i, count = 0; - struct pollfd *old = NULL, *new = NULL; - - if (events == NULL || events->events == NULL || fd < 0) { - ERR("Wrong arguments for poll del"); - goto error; - } - - old = events->events; - new_size = events->events_size - 1; - - /* Safety check on size */ - if (new_size > poll_max_size) { - new_size = poll_max_size; - } - - new = zmalloc(new_size * sizeof(struct pollfd)); - if (new == NULL) { - perror("zmalloc poll del"); - goto error; - } - - for (i = 0; i < events->events_size; i++) { - /* Don't put back the fd we want to delete */ - if (old[i].fd != fd) { - new[count].fd = old[i].fd; - new[count].events = old[i].events; - count++; - } - } - - events->events_size = new_size; - events->events = new; - events->nb_fd--; - - free(old); - - return 0; - -error: - return -1; -} - -/* - * Wait on poll() with timeout. Blocking call. - */ -int compat_poll_wait(struct lttng_poll_event *events, int timeout) -{ - int ret; - - if (events == NULL || events->events == NULL || - events->events_size < events->nb_fd) { - ERR("poll wait arguments error"); - goto error; - } - - ret = poll(events->events, events->nb_fd, timeout); - if (ret < 0) { - /* At this point, every error is fatal */ - perror("poll wait"); - goto error; - } - - return ret; - -error: - return -1; -} - -/* - * Setup poll set maximum size. - */ -void compat_poll_set_max_size(void) -{ - int ret; - struct rlimit lim; - - /* Default value */ - poll_max_size = LTTNG_POLL_DEFAULT_SIZE; - - ret = getrlimit(RLIMIT_NOFILE, &lim); - if (ret < 0) { - perror("getrlimit poll RLIMIT_NOFILE"); - return; - } - - poll_max_size = lim.rlim_cur; - if (poll_max_size <= 0) { - /* Extra precaution */ - poll_max_size = LTTNG_POLL_DEFAULT_SIZE; - } - - DBG("poll set max size set to %u", poll_max_size); -} diff --git a/src/bin/lttng-sessiond/compat/poll.h b/src/bin/lttng-sessiond/compat/poll.h deleted file mode 100644 index a7766400d..000000000 --- a/src/bin/lttng-sessiond/compat/poll.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2011 - David Goulet - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; only version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _LTT_POLL_H -#define _LTT_POLL_H - -#include -#include - -#include - -/* - * Value taken from the hard limit allowed by the kernel when using setrlimit - * with RLIMIT_NOFILE on an Intel i7 CPU and Linux 3.0.3. - */ -#define LTTNG_POLL_DEFAULT_SIZE 65535 - -/* - * Maximum number of fd we can monitor. - * - * For epoll(7), /proc/sys/fs/epoll/max_user_watches (since Linux 2.6.28) will - * be used for the maximum size of the poll set. If this interface is not - * available, according to the manpage, the max_user_watches value is 1/25 (4%) - * of the available low memory divided by the registration cost in bytes which - * is 90 bytes on a 32-bit kernel and 160 bytes on a 64-bit kernel. - * - * For poll(2), the max fds must not exceed RLIMIT_NOFILE given by - * getrlimit(2). - */ -extern unsigned int poll_max_size; - -/* - * Used by lttng_poll_clean to free the events structure in a lttng_poll_event. - */ -static inline void __lttng_poll_free(void *events) -{ - free(events); -} - -/* - * epoll(7) implementation. - */ -#ifdef HAVE_EPOLL -#include - -/* See man epoll(7) for this define path */ -#define LTTNG_EPOLL_PROC_PATH "/proc/sys/fs/epoll/max_user_watches" - -enum { - /* Polling variables compatibility for epoll */ - LPOLLIN = EPOLLIN, - LPOLLPRI = EPOLLPRI, - LPOLLOUT = EPOLLOUT, - LPOLLRDNORM = EPOLLRDNORM, - LPOLLRDBAND = EPOLLRDBAND, - LPOLLWRNORM = EPOLLWRNORM, - LPOLLWRBAND = EPOLLWRBAND, - LPOLLMSG = EPOLLMSG, - LPOLLERR = EPOLLERR, - LPOLLHUP = EPOLLHUP, - LPOLLNVAL = EPOLLHUP, - LPOLLRDHUP = EPOLLRDHUP, - /* Close on exec feature of epoll */ - LTTNG_CLOEXEC = EPOLL_CLOEXEC, -}; - -struct compat_epoll_event { - int epfd; - uint32_t nb_fd; /* Current number of fd in events */ - uint32_t events_size; /* Size of events array */ - struct epoll_event *events; -}; -#define lttng_poll_event compat_epoll_event - -/* - * For the following calls, consider 'e' to be a lttng_poll_event pointer and i - * being the index of the events array. - */ -#define LTTNG_POLL_GETFD(e, i) LTTNG_REF(e)->events[i].data.fd -#define LTTNG_POLL_GETEV(e, i) LTTNG_REF(e)->events[i].events -#define LTTNG_POLL_GETNB(e) LTTNG_REF(e)->nb_fd -#define LTTNG_POLL_GETSZ(e) LTTNG_REF(e)->events_size - -/* - * Create the epoll set. No memory allocation is done here. - */ -extern int compat_epoll_create(struct lttng_poll_event *events, - int size, int flags); -#define lttng_poll_create(events, size, flags) \ - compat_epoll_create(events, size, flags); - -/* - * Wait on epoll set with the number of fd registered to the lttng_poll_event - * data structure (events). - */ -extern int compat_epoll_wait(struct lttng_poll_event *events, int timeout); -#define lttng_poll_wait(events, timeout) \ - compat_epoll_wait(events, timeout); - -/* - * Add a fd to the epoll set and resize the epoll_event structure if needed. - */ -extern int compat_epoll_add(struct lttng_poll_event *events, - int fd, uint32_t req_events); -#define lttng_poll_add(events, fd, req_events) \ - compat_epoll_add(events, fd, req_events); - -/* - * Remove a fd from the epoll set. - */ -extern int compat_epoll_del(struct lttng_poll_event *events, int fd); -#define lttng_poll_del(events, fd) \ - compat_epoll_del(events, fd); - -/* - * Set up the poll set limits variable poll_max_size - */ -extern void compat_epoll_set_max_size(void); -#define lttng_poll_set_max_size(void) \ - compat_epoll_set_max_size(void); - -/* - * This function memset with zero the structure since it can be reused at each - * round of a main loop. Being in a loop and using a non static number of fds, - * this function must be called to insure coherent events with associted fds. - */ -static inline void lttng_poll_reset(struct lttng_poll_event *events) -{ - if (events && events->events) { - memset(events->events, 0, - events->nb_fd * sizeof(struct epoll_event)); - } -} - -/* - * Clean the events structure of a lttng_poll_event. It's the caller - * responsability to free the lttng_poll_event memory. - */ -static inline void lttng_poll_clean(struct lttng_poll_event *events) -{ - if (events) { - close(events->epfd); - __lttng_poll_free((void *) events->events); - } -} - -#else /* HAVE_EPOLL */ -/* - * Fallback on poll(2) API - */ - -/* Needed for some poll event values */ -#ifndef __USE_XOPEN -#define __USE_XOPEN -#endif - -/* Needed for some poll event values */ -#ifndef __USE_GNU -#define __USE_GNU -#endif - -#include -#include - -enum { - /* Polling variables compatibility for poll */ - LPOLLIN = POLLIN, - LPOLLPRI = POLLPRI, - LPOLLOUT = POLLOUT, - LPOLLRDNORM = POLLRDNORM, - LPOLLRDBAND = POLLRDBAND, - LPOLLWRNORM = POLLWRNORM, - LPOLLWRBAND = POLLWRBAND, - LPOLLMSG = POLLMSG, - LPOLLERR = POLLERR, - LPOLLHUP = POLLHUP | POLLNVAL, - LPOLLRDHUP = POLLRDHUP, - /* Close on exec feature does not exist for poll(2) */ - LTTNG_CLOEXEC = 0xdead, -}; - -struct compat_poll_event { - uint32_t nb_fd; /* Current number of fd in events */ - uint32_t events_size; /* Size of events array */ - struct pollfd *events; -}; -#define lttng_poll_event compat_poll_event - -/* - * For the following calls, consider 'e' to be a lttng_poll_event pointer and i - * being the index of the events array. - */ -#define LTTNG_POLL_GETFD(e, i) LTTNG_REF(e)->events[i].fd -#define LTTNG_POLL_GETEV(e, i) LTTNG_REF(e)->events[i].revents -#define LTTNG_POLL_GETNB(e) LTTNG_REF(e)->nb_fd -#define LTTNG_POLL_GETSZ(e) LTTNG_REF(e)->events_size - -/* - * Create a pollfd structure of size 'size'. - */ -extern int compat_poll_create(struct lttng_poll_event *events, int size); -#define lttng_poll_create(events, size, flags) \ - compat_poll_create(events, size); - -/* - * Wait on poll(2) event with nb_fd registered to the lttng_poll_event data - * structure. - */ -extern int compat_poll_wait(struct lttng_poll_event *events, int timeout); -#define lttng_poll_wait(events, timeout) \ - compat_poll_wait(events, timeout); - -/* - * Add the fd to the pollfd structure. Resize if needed. - */ -extern int compat_poll_add(struct lttng_poll_event *events, - int fd, uint32_t req_events); -#define lttng_poll_add(events, fd, req_events) \ - compat_poll_add(events, fd, req_events); - -/* - * Remove the fd from the pollfd. Memory allocation is done to recreate a new - * pollfd, data is copied from the old pollfd to the new and, finally, the old - * one is freed(). - */ -extern int compat_poll_del(struct lttng_poll_event *events, int fd); -#define lttng_poll_del(events, fd) \ - compat_poll_del(events, fd); - -/* - * Set up the poll set limits variable poll_max_size - */ -extern void compat_poll_set_max_size(void); -#define lttng_poll_set_max_size(void) \ - compat_poll_set_max_size(void); - -/* - * No need to reset a pollfd structure for poll(2) - */ -static inline void lttng_poll_reset(struct lttng_poll_event *events) -{} - -/* - * Clean the events structure of a lttng_poll_event. It's the caller - * responsability to free the lttng_poll_event memory. - */ -static inline void lttng_poll_clean(struct lttng_poll_event *events) -{ - if (events) { - __lttng_poll_free((void *) events->events); - } -} - -#endif /* HAVE_EPOLL */ - -#endif /* _LTT_POLL_H */ diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 0d1a916c2..82deb9b0e 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -43,10 +43,10 @@ #include #include #include +#include #include "lttng-sessiond.h" #include "channel.h" -#include "compat/poll.h" #include "context.h" #include "event.h" #include "futex.h" diff --git a/src/common/Makefile.am b/src/common/Makefile.am index a8125bc40..6b11d5084 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -24,3 +24,13 @@ if HAVE_LIBLTTNG_UST_CTL libconsumer_la_LIBADD += \ $(top_builddir)/src/common/ust-consumer/libust-consumer.la endif + +if COMPAT_EPOLL +COMPAT=compat/compat-epoll.c +else +COMPAT=compat/compat-poll.c +endif + +noinst_LTLIBRARIES += libcompat.la + +libcompat_la_SOURCES = compat/poll.h $(COMPAT) diff --git a/src/common/compat/compat-epoll.c b/src/common/compat/compat-epoll.c new file mode 100644 index 000000000..5e969ee01 --- /dev/null +++ b/src/common/compat/compat-epoll.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; only version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "poll.h" + +unsigned int poll_max_size; + +/* + * Create epoll set and allocate returned events structure. + */ +int compat_epoll_create(struct lttng_poll_event *events, int size, int flags) +{ + int ret; + + if (events == NULL || size <= 0) { + goto error; + } + + /* Don't bust the limit here */ + if (size > poll_max_size) { + size = poll_max_size; + } + + ret = epoll_create1(flags); + if (ret < 0) { + /* At this point, every error is fatal */ + perror("epoll_create1"); + goto error; + } + + events->epfd = ret; + + /* This *must* be freed by using lttng_poll_free() */ + events->events = zmalloc(size * sizeof(struct epoll_event)); + if (events->events == NULL) { + perror("zmalloc epoll set"); + goto error_close; + } + + events->events_size = size; + events->nb_fd = 0; + + return 0; + +error_close: + close(events->epfd); +error: + return -1; +} + +/* + * Add a fd to the epoll set with requesting events. + */ +int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events) +{ + int ret, new_size; + struct epoll_event ev, *ptr; + + if (events == NULL || events->events == NULL || fd < 0) { + ERR("Bad compat epoll add arguments"); + goto error; + } + + ev.events = req_events; + ev.data.fd = fd; + + ret = epoll_ctl(events->epfd, EPOLL_CTL_ADD, fd, &ev); + if (ret < 0) { + switch (errno) { + case EEXIST: + case ENOSPC: + case EPERM: + /* Print perror and goto end not failing. Show must go on. */ + perror("epoll_ctl ADD"); + goto end; + default: + perror("epoll_ctl ADD fatal"); + goto error; + } + } + + events->nb_fd++; + + if (events->nb_fd >= events->events_size) { + new_size = 2 * events->events_size; + ptr = realloc(events->events, new_size * sizeof(struct epoll_event)); + if (ptr == NULL) { + perror("realloc epoll add"); + goto error; + } + events->events = ptr; + events->events_size = new_size; + } + +end: + return 0; + +error: + return -1; +} + +/* + * Remove a fd from the epoll set. + */ +int compat_epoll_del(struct lttng_poll_event *events, int fd) +{ + int ret; + + if (events == NULL || fd < 0) { + goto error; + } + + ret = epoll_ctl(events->epfd, EPOLL_CTL_DEL, fd, NULL); + if (ret < 0) { + switch (errno) { + case ENOENT: + case EPERM: + /* Print perror and goto end not failing. Show must go on. */ + perror("epoll_ctl DEL"); + goto end; + default: + perror("epoll_ctl DEL fatal"); + goto error; + } + perror("epoll_ctl del"); + goto error; + } + + events->nb_fd--; + +end: + return 0; + +error: + return -1; +} + +/* + * Wait on epoll set. This is a blocking call of timeout value. + */ +int compat_epoll_wait(struct lttng_poll_event *events, int timeout) +{ + int ret; + + if (events == NULL || events->events == NULL || + events->events_size < events->nb_fd) { + ERR("Wrong arguments in compat_epoll_wait"); + goto error; + } + + do { + ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout); + } while (ret == -1 && errno == EINTR); + if (ret < 0) { + /* At this point, every error is fatal */ + perror("epoll_wait"); + goto error; + } + + return ret; + +error: + return -1; +} + +/* + * Setup poll set maximum size. + */ +void compat_epoll_set_max_size(void) +{ + int ret, fd; + char buf[64]; + + poll_max_size = LTTNG_POLL_DEFAULT_SIZE; + + fd = open(LTTNG_EPOLL_PROC_PATH, O_RDONLY); + if (fd < 0) { + return; + } + + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) { + perror("read set max size"); + goto error; + } + + poll_max_size = atoi(buf); + if (poll_max_size <= 0) { + /* Extra precaution */ + poll_max_size = LTTNG_POLL_DEFAULT_SIZE; + } + + DBG("epoll set max size is %d", poll_max_size); + +error: + close(fd); +} diff --git a/src/common/compat/compat-poll.c b/src/common/compat/compat-poll.c new file mode 100644 index 000000000..50ef37472 --- /dev/null +++ b/src/common/compat/compat-poll.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; only version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include + +#include "poll.h" + +unsigned int poll_max_size; + +/* + * Create pollfd data structure. + */ +int compat_poll_create(struct lttng_poll_event *events, int size) +{ + if (events == NULL || size <= 0) { + ERR("Wrong arguments for poll create"); + goto error; + } + + /* Don't bust the limit here */ + if (size > poll_max_size) { + size = poll_max_size; + } + + /* This *must* be freed by using lttng_poll_free() */ + events->events = zmalloc(size * sizeof(struct pollfd)); + if (events->events == NULL) { + perror("zmalloc struct pollfd"); + goto error; + } + + events->events_size = size; + events->nb_fd = 0; + + return 0; + +error: + return -1; +} + +/* + * Add fd to pollfd data structure with requested events. + */ +int compat_poll_add(struct lttng_poll_event *events, int fd, + uint32_t req_events) +{ + int new_size; + struct pollfd *ptr; + + if (events == NULL || events->events == NULL || fd < 0) { + ERR("Bad compat poll add arguments"); + goto error; + } + + /* Reallocate pollfd structure by a factor of 2 if needed. */ + if (events->nb_fd >= events->events_size) { + new_size = 2 * events->events_size; + ptr = realloc(events->events, new_size * sizeof(struct pollfd)); + if (ptr == NULL) { + perror("realloc poll add"); + goto error; + } + events->events = ptr; + events->events_size = new_size; + } + + events->events[events->nb_fd].fd = fd; + events->events[events->nb_fd].events = req_events; + events->nb_fd++; + + DBG("fd %d of %d added to pollfd", fd, events->nb_fd); + + return 0; + +error: + return -1; +} + +/* + * Remove a fd from the pollfd structure. + */ +int compat_poll_del(struct lttng_poll_event *events, int fd) +{ + int new_size, i, count = 0; + struct pollfd *old = NULL, *new = NULL; + + if (events == NULL || events->events == NULL || fd < 0) { + ERR("Wrong arguments for poll del"); + goto error; + } + + old = events->events; + new_size = events->events_size - 1; + + /* Safety check on size */ + if (new_size > poll_max_size) { + new_size = poll_max_size; + } + + new = zmalloc(new_size * sizeof(struct pollfd)); + if (new == NULL) { + perror("zmalloc poll del"); + goto error; + } + + for (i = 0; i < events->events_size; i++) { + /* Don't put back the fd we want to delete */ + if (old[i].fd != fd) { + new[count].fd = old[i].fd; + new[count].events = old[i].events; + count++; + } + } + + events->events_size = new_size; + events->events = new; + events->nb_fd--; + + free(old); + + return 0; + +error: + return -1; +} + +/* + * Wait on poll() with timeout. Blocking call. + */ +int compat_poll_wait(struct lttng_poll_event *events, int timeout) +{ + int ret; + + if (events == NULL || events->events == NULL || + events->events_size < events->nb_fd) { + ERR("poll wait arguments error"); + goto error; + } + + ret = poll(events->events, events->nb_fd, timeout); + if (ret < 0) { + /* At this point, every error is fatal */ + perror("poll wait"); + goto error; + } + + return ret; + +error: + return -1; +} + +/* + * Setup poll set maximum size. + */ +void compat_poll_set_max_size(void) +{ + int ret; + struct rlimit lim; + + /* Default value */ + poll_max_size = LTTNG_POLL_DEFAULT_SIZE; + + ret = getrlimit(RLIMIT_NOFILE, &lim); + if (ret < 0) { + perror("getrlimit poll RLIMIT_NOFILE"); + return; + } + + poll_max_size = lim.rlim_cur; + if (poll_max_size <= 0) { + /* Extra precaution */ + poll_max_size = LTTNG_POLL_DEFAULT_SIZE; + } + + DBG("poll set max size set to %u", poll_max_size); +} diff --git a/src/common/compat/poll.h b/src/common/compat/poll.h new file mode 100644 index 000000000..a7766400d --- /dev/null +++ b/src/common/compat/poll.h @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; only version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LTT_POLL_H +#define _LTT_POLL_H + +#include +#include + +#include + +/* + * Value taken from the hard limit allowed by the kernel when using setrlimit + * with RLIMIT_NOFILE on an Intel i7 CPU and Linux 3.0.3. + */ +#define LTTNG_POLL_DEFAULT_SIZE 65535 + +/* + * Maximum number of fd we can monitor. + * + * For epoll(7), /proc/sys/fs/epoll/max_user_watches (since Linux 2.6.28) will + * be used for the maximum size of the poll set. If this interface is not + * available, according to the manpage, the max_user_watches value is 1/25 (4%) + * of the available low memory divided by the registration cost in bytes which + * is 90 bytes on a 32-bit kernel and 160 bytes on a 64-bit kernel. + * + * For poll(2), the max fds must not exceed RLIMIT_NOFILE given by + * getrlimit(2). + */ +extern unsigned int poll_max_size; + +/* + * Used by lttng_poll_clean to free the events structure in a lttng_poll_event. + */ +static inline void __lttng_poll_free(void *events) +{ + free(events); +} + +/* + * epoll(7) implementation. + */ +#ifdef HAVE_EPOLL +#include + +/* See man epoll(7) for this define path */ +#define LTTNG_EPOLL_PROC_PATH "/proc/sys/fs/epoll/max_user_watches" + +enum { + /* Polling variables compatibility for epoll */ + LPOLLIN = EPOLLIN, + LPOLLPRI = EPOLLPRI, + LPOLLOUT = EPOLLOUT, + LPOLLRDNORM = EPOLLRDNORM, + LPOLLRDBAND = EPOLLRDBAND, + LPOLLWRNORM = EPOLLWRNORM, + LPOLLWRBAND = EPOLLWRBAND, + LPOLLMSG = EPOLLMSG, + LPOLLERR = EPOLLERR, + LPOLLHUP = EPOLLHUP, + LPOLLNVAL = EPOLLHUP, + LPOLLRDHUP = EPOLLRDHUP, + /* Close on exec feature of epoll */ + LTTNG_CLOEXEC = EPOLL_CLOEXEC, +}; + +struct compat_epoll_event { + int epfd; + uint32_t nb_fd; /* Current number of fd in events */ + uint32_t events_size; /* Size of events array */ + struct epoll_event *events; +}; +#define lttng_poll_event compat_epoll_event + +/* + * For the following calls, consider 'e' to be a lttng_poll_event pointer and i + * being the index of the events array. + */ +#define LTTNG_POLL_GETFD(e, i) LTTNG_REF(e)->events[i].data.fd +#define LTTNG_POLL_GETEV(e, i) LTTNG_REF(e)->events[i].events +#define LTTNG_POLL_GETNB(e) LTTNG_REF(e)->nb_fd +#define LTTNG_POLL_GETSZ(e) LTTNG_REF(e)->events_size + +/* + * Create the epoll set. No memory allocation is done here. + */ +extern int compat_epoll_create(struct lttng_poll_event *events, + int size, int flags); +#define lttng_poll_create(events, size, flags) \ + compat_epoll_create(events, size, flags); + +/* + * Wait on epoll set with the number of fd registered to the lttng_poll_event + * data structure (events). + */ +extern int compat_epoll_wait(struct lttng_poll_event *events, int timeout); +#define lttng_poll_wait(events, timeout) \ + compat_epoll_wait(events, timeout); + +/* + * Add a fd to the epoll set and resize the epoll_event structure if needed. + */ +extern int compat_epoll_add(struct lttng_poll_event *events, + int fd, uint32_t req_events); +#define lttng_poll_add(events, fd, req_events) \ + compat_epoll_add(events, fd, req_events); + +/* + * Remove a fd from the epoll set. + */ +extern int compat_epoll_del(struct lttng_poll_event *events, int fd); +#define lttng_poll_del(events, fd) \ + compat_epoll_del(events, fd); + +/* + * Set up the poll set limits variable poll_max_size + */ +extern void compat_epoll_set_max_size(void); +#define lttng_poll_set_max_size(void) \ + compat_epoll_set_max_size(void); + +/* + * This function memset with zero the structure since it can be reused at each + * round of a main loop. Being in a loop and using a non static number of fds, + * this function must be called to insure coherent events with associted fds. + */ +static inline void lttng_poll_reset(struct lttng_poll_event *events) +{ + if (events && events->events) { + memset(events->events, 0, + events->nb_fd * sizeof(struct epoll_event)); + } +} + +/* + * Clean the events structure of a lttng_poll_event. It's the caller + * responsability to free the lttng_poll_event memory. + */ +static inline void lttng_poll_clean(struct lttng_poll_event *events) +{ + if (events) { + close(events->epfd); + __lttng_poll_free((void *) events->events); + } +} + +#else /* HAVE_EPOLL */ +/* + * Fallback on poll(2) API + */ + +/* Needed for some poll event values */ +#ifndef __USE_XOPEN +#define __USE_XOPEN +#endif + +/* Needed for some poll event values */ +#ifndef __USE_GNU +#define __USE_GNU +#endif + +#include +#include + +enum { + /* Polling variables compatibility for poll */ + LPOLLIN = POLLIN, + LPOLLPRI = POLLPRI, + LPOLLOUT = POLLOUT, + LPOLLRDNORM = POLLRDNORM, + LPOLLRDBAND = POLLRDBAND, + LPOLLWRNORM = POLLWRNORM, + LPOLLWRBAND = POLLWRBAND, + LPOLLMSG = POLLMSG, + LPOLLERR = POLLERR, + LPOLLHUP = POLLHUP | POLLNVAL, + LPOLLRDHUP = POLLRDHUP, + /* Close on exec feature does not exist for poll(2) */ + LTTNG_CLOEXEC = 0xdead, +}; + +struct compat_poll_event { + uint32_t nb_fd; /* Current number of fd in events */ + uint32_t events_size; /* Size of events array */ + struct pollfd *events; +}; +#define lttng_poll_event compat_poll_event + +/* + * For the following calls, consider 'e' to be a lttng_poll_event pointer and i + * being the index of the events array. + */ +#define LTTNG_POLL_GETFD(e, i) LTTNG_REF(e)->events[i].fd +#define LTTNG_POLL_GETEV(e, i) LTTNG_REF(e)->events[i].revents +#define LTTNG_POLL_GETNB(e) LTTNG_REF(e)->nb_fd +#define LTTNG_POLL_GETSZ(e) LTTNG_REF(e)->events_size + +/* + * Create a pollfd structure of size 'size'. + */ +extern int compat_poll_create(struct lttng_poll_event *events, int size); +#define lttng_poll_create(events, size, flags) \ + compat_poll_create(events, size); + +/* + * Wait on poll(2) event with nb_fd registered to the lttng_poll_event data + * structure. + */ +extern int compat_poll_wait(struct lttng_poll_event *events, int timeout); +#define lttng_poll_wait(events, timeout) \ + compat_poll_wait(events, timeout); + +/* + * Add the fd to the pollfd structure. Resize if needed. + */ +extern int compat_poll_add(struct lttng_poll_event *events, + int fd, uint32_t req_events); +#define lttng_poll_add(events, fd, req_events) \ + compat_poll_add(events, fd, req_events); + +/* + * Remove the fd from the pollfd. Memory allocation is done to recreate a new + * pollfd, data is copied from the old pollfd to the new and, finally, the old + * one is freed(). + */ +extern int compat_poll_del(struct lttng_poll_event *events, int fd); +#define lttng_poll_del(events, fd) \ + compat_poll_del(events, fd); + +/* + * Set up the poll set limits variable poll_max_size + */ +extern void compat_poll_set_max_size(void); +#define lttng_poll_set_max_size(void) \ + compat_poll_set_max_size(void); + +/* + * No need to reset a pollfd structure for poll(2) + */ +static inline void lttng_poll_reset(struct lttng_poll_event *events) +{} + +/* + * Clean the events structure of a lttng_poll_event. It's the caller + * responsability to free the lttng_poll_event memory. + */ +static inline void lttng_poll_clean(struct lttng_poll_event *events) +{ + if (events) { + __lttng_poll_free((void *) events->events); + } +} + +#endif /* HAVE_EPOLL */ + +#endif /* _LTT_POLL_H */