X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fcompat%2Fcompat-epoll.c;h=25c9955045b3bb09435beea959d891c67f1c77a4;hp=5e969ee01115896f1286297966d22d94f216efb1;hb=13021756b87be3b7e41083f607fa0a54792d153a;hpb=0ba98ebc83bf874d34c8c84b164a6ad803e9de75 diff --git a/src/common/compat/compat-epoll.c b/src/common/compat/compat-epoll.c index 5e969ee01..25c995504 100644 --- a/src/common/compat/compat-epoll.c +++ b/src/common/compat/compat-epoll.c @@ -1,20 +1,22 @@ /* * 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 free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. * * 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. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _GNU_SOURCE +#include #include #include #include @@ -23,12 +25,41 @@ #include #include -#include +#include +#include +#include +#include #include "poll.h" unsigned int poll_max_size; +/* + * Resize the epoll events structure of the new size. + * + * Return 0 on success or else -1 with the current events pointer untouched. + */ +static int resize_poll_event(struct lttng_poll_event *events, + uint32_t new_size) +{ + struct epoll_event *ptr; + + assert(events); + + ptr = realloc(events->events, new_size * sizeof(*ptr)); + if (ptr == NULL) { + PERROR("realloc epoll add"); + goto error; + } + events->events = ptr; + events->alloc_size = new_size; + + return 0; + +error: + return -1; +} + /* * Create epoll set and allocate returned events structure. */ @@ -41,14 +72,14 @@ int compat_epoll_create(struct lttng_poll_event *events, int size, int flags) } /* Don't bust the limit here */ - if (size > poll_max_size) { + if (size > poll_max_size && poll_max_size != 0) { size = poll_max_size; } ret = epoll_create1(flags); if (ret < 0) { /* At this point, every error is fatal */ - perror("epoll_create1"); + PERROR("epoll_create1"); goto error; } @@ -57,17 +88,20 @@ int compat_epoll_create(struct lttng_poll_event *events, int size, int flags) /* 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"); + PERROR("zmalloc epoll set"); goto error_close; } - events->events_size = size; + events->alloc_size = events->init_size = size; events->nb_fd = 0; return 0; error_close: - close(events->epfd); + ret = close(events->epfd); + if (ret) { + PERROR("close"); + } error: return -1; } @@ -77,8 +111,8 @@ error: */ int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events) { - int ret, new_size; - struct epoll_event ev, *ptr; + int ret; + struct epoll_event ev; if (events == NULL || events->events == NULL || fd < 0) { ERR("Bad compat epoll add arguments"); @@ -92,30 +126,21 @@ int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_event if (ret < 0) { switch (errno) { case EEXIST: + /* If exist, it's OK. */ + goto end; case ENOSPC: case EPERM: - /* Print perror and goto end not failing. Show must go on. */ - perror("epoll_ctl ADD"); + /* Print PERROR and goto end not failing. Show must go on. */ + PERROR("epoll_ctl ADD"); goto end; default: - perror("epoll_ctl ADD fatal"); + 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; @@ -139,15 +164,13 @@ int compat_epoll_del(struct lttng_poll_event *events, int fd) switch (errno) { case ENOENT: case EPERM: - /* Print perror and goto end not failing. Show must go on. */ - perror("epoll_ctl DEL"); + /* Print PERROR and goto end not failing. Show must go on. */ + PERROR("epoll_ctl DEL"); goto end; default: - perror("epoll_ctl DEL fatal"); + PERROR("epoll_ctl DEL fatal"); goto error; } - perror("epoll_ctl del"); - goto error; } events->nb_fd--; @@ -165,22 +188,56 @@ error: int compat_epoll_wait(struct lttng_poll_event *events, int timeout) { int ret; + uint32_t new_size; - if (events == NULL || events->events == NULL || - events->events_size < events->nb_fd) { + if (events == NULL || events->events == NULL) { ERR("Wrong arguments in compat_epoll_wait"); goto error; } + /* + * Resize if needed before waiting. We could either expand the array or + * shrink it down. It's important to note that after this step, we are + * ensured that the events argument of the epoll_wait call will be large + * enough to hold every possible returned events. + */ + if (events->nb_fd > events->alloc_size) { + /* Expand if the nb_fd is higher than the actual size. */ + new_size = max_t(uint32_t, + 1U << utils_get_count_order_u32(events->nb_fd), + events->alloc_size << 1UL); + } else if ((events->nb_fd << 1UL) <= events->alloc_size && + events->nb_fd >= events->init_size) { + /* Shrink if nb_fd multiplied by two is <= than the actual size. */ + new_size = max_t(uint32_t, + utils_get_count_order_u32(events->nb_fd) >> 1U, + events->alloc_size >> 1U); + } else { + /* Indicate that we don't want to resize. */ + new_size = 0; + } + + if (new_size) { + ret = resize_poll_event(events, new_size); + if (ret < 0) { + /* ENOMEM problem at this point. */ + 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"); + PERROR("epoll_wait"); goto error; } + /* + * Since the returned events are set sequentially in the "events" structure + * we only need to return the epoll_wait value and iterate over it. + */ return ret; error: @@ -193,29 +250,38 @@ error: void compat_epoll_set_max_size(void) { int ret, fd; + ssize_t size_ret; char buf[64]; - poll_max_size = LTTNG_POLL_DEFAULT_SIZE; + poll_max_size = DEFAULT_POLL_SIZE; - fd = open(LTTNG_EPOLL_PROC_PATH, O_RDONLY); + fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY); if (fd < 0) { return; } - ret = read(fd, buf, sizeof(buf)); - if (ret < 0) { - perror("read set max size"); + size_ret = lttng_read(fd, buf, sizeof(buf)); + /* + * Allow reading a file smaller than buf, but keep space for + * final \0. + */ + if (size_ret < 0 || size_ret >= sizeof(buf)) { + PERROR("read set max size"); goto error; } + buf[size_ret] = '\0'; poll_max_size = atoi(buf); - if (poll_max_size <= 0) { + if (poll_max_size == 0) { /* Extra precaution */ - poll_max_size = LTTNG_POLL_DEFAULT_SIZE; + poll_max_size = DEFAULT_POLL_SIZE; } DBG("epoll set max size is %d", poll_max_size); error: - close(fd); + ret = close(fd); + if (ret) { + PERROR("close"); + } }