#ifndef _LTT_POLL_H
#define _LTT_POLL_H
+#include <assert.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_EPOLL
#include <sys/epoll.h>
#include <stdio.h>
+#include <features.h>
+#include <common/compat/fcntl.h>
/* See man epoll(7) for this define path */
#define COMPAT_EPOLL_PROC_PATH "/proc/sys/fs/epoll/max_user_watches"
LPOLLNVAL = EPOLLHUP,
LPOLLRDHUP = EPOLLRDHUP,
/* Close on exec feature of epoll */
+#if __GLIBC_PREREQ(2, 9)
LTTNG_CLOEXEC = EPOLL_CLOEXEC,
+#else
+ /*
+ * EPOLL_CLOEXEC was added in glibc 2.8 (usually used in conjunction with
+ * epoll_create1(..)), but since neither EPOLL_CLOEXEC exists nor
+ * epoll_create1(..), we set it to FD_CLOEXEC so that we can pass it
+ * directly to fcntl(..) instead.
+ */
+ LTTNG_CLOEXEC = FD_CLOEXEC,
+#endif
};
struct compat_epoll_event {
int epfd;
uint32_t nb_fd; /* Current number of fd in events */
- uint32_t events_size; /* Size of events array */
+ uint32_t alloc_size; /* Size of events array */
+ uint32_t init_size; /* Initial size of events array */
struct epoll_event *events;
};
#define lttng_poll_event compat_epoll_event
+static inline int __lttng_epoll_get_prev_fd(struct lttng_poll_event *events,
+ int index, uint32_t nb_fd)
+{
+ assert(events);
+ assert(index != nb_fd);
+
+ if (index == 0 || nb_fd == 0) {
+ return -1;
+ } else {
+ return events->events[index - 1].data.fd;
+ }
+}
+
/*
* 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_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
+#define LTTNG_POLL_GET_PREV_FD(e, i, nb_fd) \
+ __lttng_epoll_get_prev_fd(LTTNG_REF(e), i, nb_fd)
/*
* Create the epoll set. No memory allocation is done here.
#define lttng_poll_create(events, size, flags) \
compat_epoll_create(events, size, flags)
+#if __GLIBC_PREREQ(2, 9)
+static inline int compat_glibc_epoll_create(int size __attribute__((unused)),
+ int flags)
+{
+ return epoll_create1(flags);
+}
+#else
+static inline int compat_glibc_epoll_create(int size, int flags)
+{
+ /*
+ * epoll_create1 was added in glibc 2.9, but unfortunatly reverting to
+ * epoll_create(..) also means that we lose the possibility to
+ * directly set the EPOLL_CLOEXEC, so try and do it anyway but through
+ * fcntl(..).
+ */
+ int efd = epoll_create(size);
+ assert(fcntl(efd, F_SETFD, flags) != -1);
+ return efd;
+}
+#endif
+
/*
* Wait on epoll set with the number of fd registered to the lttng_poll_event
* data structure (events).
/*
* Set up the poll set limits variable poll_max_size
*/
-extern void compat_epoll_set_max_size(void);
+extern int compat_epoll_set_max_size(void);
#define lttng_poll_set_max_size() \
compat_epoll_set_max_size()
}
}
+/*
+ * Initialize an already allocated poll event data structure. For epoll(), the
+ * epfd is set to -1 to indicate that it's not usable.
+ */
+static inline void lttng_poll_init(struct lttng_poll_event *events)
+{
+ memset(events, 0, sizeof(struct lttng_poll_event));
+ /* Set fd to -1 so if clean before created, we don't close 0. */
+ events->epfd = -1;
+}
+
/*
* Clean the events structure of a lttng_poll_event. It's the caller
* responsability to free the lttng_poll_event memory.
{
int ret;
- if (events) {
+ if (!events) {
+ return;
+ }
+
+ if (events->epfd >= 0) {
ret = close(events->epfd);
if (ret) {
- perror("close");
+ PERROR("close");
}
- __lttng_poll_free((void *) events->events);
}
+
+ __lttng_poll_free((void *) events->events);
}
#else /* HAVE_EPOLL */
#if __linux__
LPOLLMSG = POLLMSG,
LPOLLRDHUP = POLLRDHUP,
-#elif defined(__FreeBSD__)
+#elif (defined(__FreeBSD__) || defined(__CYGWIN__))
LPOLLMSG = 0,
LPOLLRDHUP = 0,
#else
LTTNG_CLOEXEC = 0xdead,
};
-struct compat_poll_event {
+struct compat_poll_event_array {
uint32_t nb_fd; /* Current number of fd in events */
- uint32_t events_size; /* Size of events array */
+ uint32_t alloc_size; /* Size of events array */
+ /* Initial size of the pollset. We never shrink below that. */
+ uint32_t init_size;
struct pollfd *events;
};
+
+struct compat_poll_event {
+ /*
+ * Modified by the wait action. Updated using current fields if the
+ * need_update flag is set.
+ */
+ struct compat_poll_event_array wait;
+ /*
+ * This is modified by add/del actions being the _current_ flow of
+ * execution before a poll wait is done.
+ */
+ struct compat_poll_event_array current;
+
+ /* Indicate if wait.events need to be updated from current. */
+ int need_update:1;
+};
#define lttng_poll_event compat_poll_event
+static inline int __lttng_poll_get_prev_fd(struct lttng_poll_event *events,
+ int index, uint32_t nb_fd)
+{
+ assert(events);
+ assert(index != nb_fd);
+
+ if (index == 0 || nb_fd == 0) {
+ return -1;
+ } else {
+ return events->current.events[index - 1].fd;
+ }
+}
+
/*
* 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
+#define LTTNG_POLL_GETFD(e, i) LTTNG_REF(e)->wait.events[i].fd
+#define LTTNG_POLL_GETEV(e, i) LTTNG_REF(e)->wait.events[i].revents
+#define LTTNG_POLL_GETNB(e) LTTNG_REF(e)->wait.nb_fd
+#define LTTNG_POLL_GETSZ(e) LTTNG_REF(e)->wait.events_size
+#define LTTNG_POLL_GET_PREV_FD(e, i, nb_fd) \
+ __lttng_poll_get_prev_fd(LTTNG_REF(e), i, nb_fd)
/*
* Create a pollfd structure of size 'size'.
/*
* Set up the poll set limits variable poll_max_size
*/
-extern void compat_poll_set_max_size(void);
+extern int compat_poll_set_max_size(void);
#define lttng_poll_set_max_size() \
compat_poll_set_max_size()
static inline void lttng_poll_reset(struct lttng_poll_event *events)
{}
+/*
+ * Initialize an already allocated poll event data structure.
+ */
+static inline void lttng_poll_init(struct lttng_poll_event *events)
+{
+ memset(events, 0, sizeof(struct lttng_poll_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) {
- __lttng_poll_free((void *) events->events);
+ __lttng_poll_free((void *) events->wait.events);
+ __lttng_poll_free((void *) events->current.events);
}
}