diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/errcode.c | 1 | ||||
-rw-r--r-- | src/common/errcode.h | 1 | ||||
-rw-r--r-- | src/common/evqueue.c | 3 | ||||
-rw-r--r-- | src/common/evqueue.h | 17 | ||||
-rw-r--r-- | src/common/fdset.c | 217 | ||||
-rw-r--r-- | src/common/fdset.h | 207 | ||||
-rw-r--r-- | src/common/fdset_epoll.c | 205 | ||||
-rw-r--r-- | src/common/fdset_epoll.h | 132 | ||||
-rw-r--r-- | src/common/fdset_kqueue.c | 260 | ||||
-rw-r--r-- | src/common/fdset_kqueue.h | 132 | ||||
-rw-r--r-- | src/common/fdset_poll.c | 218 | ||||
-rw-r--r-- | src/common/fdset_poll.h | 132 |
12 files changed, 134 insertions, 1391 deletions
diff --git a/src/common/errcode.c b/src/common/errcode.c index c03b473..b555805 100644 --- a/src/common/errcode.c +++ b/src/common/errcode.c @@ -76,7 +76,6 @@ const error_table_t knot_error_msgs[] = { /* Control states. */ { KNOT_CTL_STOP, "Stopping server." }, - { KNOT_CTL_RESTART, "Restarting server." }, /* Network errors. */ { KNOT_NET_EADDR, "Bad address or host name." }, diff --git a/src/common/errcode.h b/src/common/errcode.h index 13d1943..69f6ed5 100644 --- a/src/common/errcode.h +++ b/src/common/errcode.h @@ -95,7 +95,6 @@ enum knot_error { /* Control states. */ KNOT_CTL_STOP, /*!< Stop requested. */ - KNOT_CTL_RESTART, /*!< Restart requested. */ /* Network errors. */ KNOT_NET_EADDR, diff --git a/src/common/evqueue.c b/src/common/evqueue.c index 097d177..4b89554 100644 --- a/src/common/evqueue.c +++ b/src/common/evqueue.c @@ -22,9 +22,6 @@ #include "common/evqueue.h" #include "common/fdset.h" -/*! \brief Singleton application-wide event queue. */ -evqueue_t *s_evqueue = 0; - evqueue_t *evqueue_new() { evqueue_t* q = malloc(sizeof(evqueue_t)); diff --git a/src/common/evqueue.h b/src/common/evqueue.h index ffb3860..794b2d5 100644 --- a/src/common/evqueue.h +++ b/src/common/evqueue.h @@ -178,23 +178,6 @@ int evqueue_get(evqueue_t *q, event_t *ev); */ int evqueue_add(evqueue_t *q, const event_t *ev); -/* Singleton event queue pointer. */ -extern evqueue_t *s_evqueue; - -/*! - * \brief Event queue singleton. - */ -static inline evqueue_t *evqueue() { - return s_evqueue; -} - -/*! - * \brief Set event queue singleton. - */ -static inline void evqueue_set(evqueue_t *q) { - s_evqueue = q; -} - #endif /* _KNOTD_COMMON_EVQUEUE_H_ */ /*! @} */ diff --git a/src/common/fdset.c b/src/common/fdset.c index 3b4b75a..5f93d27 100644 --- a/src/common/fdset.c +++ b/src/common/fdset.c @@ -15,12 +15,11 @@ */ #include <config.h> -#include <dlfcn.h> +#include <stdlib.h> #include <string.h> -#include <stdio.h> #include <time.h> -#include <stdlib.h> #include "common/fdset.h" +#include "common.h" /* Workarounds for clock_gettime() not available on some platforms. */ #ifdef HAVE_CLOCK_GETTIME @@ -34,171 +33,137 @@ typedef struct timeval timev_t; #error Neither clock_gettime() nor gettimeofday() found. At least one is required. #endif -struct fdset_backend_t _fdset_backend = { - NULL -}; +/* Realloc memory or return error (part of fdset_resize). */ +#define MEM_RESIZE(tmp, p, n) \ + if ((tmp = realloc((p), (n))) == NULL) \ + return KNOT_ENOMEM; \ + (p) = tmp; -/*! \brief Set backend implementation. */ -static void fdset_set_backend(struct fdset_backend_t *backend) { - memcpy(&_fdset_backend, backend, sizeof(struct fdset_backend_t)); +static int fdset_resize(fdset_t *set, unsigned size) +{ + void *tmp = NULL; + MEM_RESIZE(tmp, set->ctx, size * sizeof(void*)); + MEM_RESIZE(tmp, set->pfd, size * sizeof(struct pollfd)); + MEM_RESIZE(tmp, set->timeout, size * sizeof(timev_t)); + set->size = size; + return KNOT_EOK; } -/* Linux epoll API. */ -#ifdef HAVE_EPOLL_WAIT - #include "common/fdset_epoll.h" -#endif /* HAVE_EPOLL_WAIT */ - -/* BSD kqueue API */ -#ifdef HAVE_KQUEUE - #include "common/fdset_kqueue.h" -#endif /* HAVE_KQUEUE */ - -/* POSIX poll API */ -#ifdef HAVE_POLL - #include "common/fdset_poll.h" -#endif /* HAVE_POLL */ - -/*! \brief Bootstrap polling subsystem (it is called automatically). */ -void __attribute__ ((constructor)) fdset_init() +int fdset_init(fdset_t *set, unsigned size) { - /* Preference: epoll */ -#ifdef HAVE_EPOLL_WAIT - if (dlsym(RTLD_DEFAULT, "epoll_wait") != 0) { - fdset_set_backend(&FDSET_EPOLL); - return; + if (set == NULL) { + return KNOT_EINVAL; } -#endif - /* Preference: kqueue */ -#ifdef HAVE_KQUEUE - if (dlsym(RTLD_DEFAULT, "kqueue") != 0) { - fdset_set_backend(&FDSET_KQUEUE); - return; - } -#endif + memset(set, 0, sizeof(fdset_t)); + return fdset_resize(set, size); +} - /* Fallback: poll */ -#ifdef HAVE_POLL - if (dlsym(RTLD_DEFAULT, "poll") != 0) { - fdset_set_backend(&FDSET_POLL); - return; +int fdset_clear(fdset_t* set) +{ + if (set == NULL) { + return KNOT_EINVAL; } -#endif - /* This shouldn't happen. */ - fprintf(stderr, "fdset: fatal error - no valid fdset backend found\n"); - return; + free(set->ctx); + free(set->pfd); + free(set->timeout); + memset(set, 0, sizeof(fdset_t)); + return KNOT_EOK; } -/*! - * \brief Compare file descriptors. - * - * \param a File descriptor. - * \param b File descriptor. - * - * \retval -1 if a < b - * \retval 0 if a == b - * \retval 1 if a > b - */ -static inline int fdset_compare(void *a, void *b) +int fdset_add(fdset_t *set, int fd, unsigned events, void *ctx) { - if (a > b) return 1; - if (a < b) return -1; - return 0; -} - -fdset_t *fdset_new() { - fdset_t* set = _fdset_backend.fdset_new(); - fdset_base_t *base = (fdset_base_t*)set; - if (base != NULL) { - /* Create atimes list. */ - base->atimes = skip_create_list(fdset_compare); - if (base->atimes == NULL) { - fdset_destroy(set); - set = NULL; - } + if (set == NULL || fd < 0) { + return KNOT_EINVAL; } - return set; + + /* Realloc needed. */ + if (set->n == set->size && fdset_resize(set, set->size + FDSET_INIT_SIZE)) + return KNOT_ENOMEM; + + /* Initialize. */ + int i = set->n++; + set->pfd[i].fd = fd; + set->pfd[i].events = events; + set->pfd[i].revents = 0; + set->ctx[i] = ctx; + set->timeout[i] = 0; + + /* Return index to this descriptor. */ + return i; } -int fdset_destroy(fdset_t* fdset) { - fdset_base_t *base = (fdset_base_t*)fdset; - if (base != NULL && base->atimes != NULL) { - skip_destroy_list(&base->atimes, NULL, free); +int fdset_remove(fdset_t *set, unsigned i) +{ + if (set == NULL || i >= set->n) { + return KNOT_EINVAL; } - return _fdset_backend.fdset_destroy(fdset); -} -int fdset_remove(fdset_t *fdset, int fd) { - fdset_base_t *base = (fdset_base_t*)fdset; - if (base != NULL && base->atimes != NULL) { - skip_remove(base->atimes, (void*)((size_t)fd), NULL, free); + /* Decrement number of elms. */ + --set->n; + + /* Nothing else if it is the last one. + * Move last -> i if some remain. */ + unsigned last = set->n; /* Already decremented */ + if (i < last) { + set->pfd[i] = set->pfd[last]; + set->timeout[i] = set->timeout[last]; + set->ctx[i] = set->ctx[last]; } - return _fdset_backend.fdset_remove(fdset, fd); + + return KNOT_EOK; } -int fdset_set_watchdog(fdset_t* fdset, int fd, int interval) +int fdset_set_watchdog(fdset_t* set, int i, int interval) { - fdset_base_t *base = (fdset_base_t*)fdset; - if (base == NULL || base->atimes == NULL) { - return -1; + if (set == NULL || i >= set->n) { + return KNOT_EINVAL; } /* Lift watchdog if interval is negative. */ if (interval < 0) { - skip_remove(base->atimes, (void*)((size_t)fd), NULL, free); - return 0; - } - - /* Find if exists. */ - timev_t *ts = NULL; - ts = (timev_t*)skip_find(base->atimes, (void*)((size_t)fd)); - if (ts == NULL) { - ts = malloc(sizeof(timev_t)); - if (ts == NULL) { - return -1; - } - skip_insert(base->atimes, (void*)((size_t)fd), (void*)ts, NULL); + set->timeout[i] = 0; + return KNOT_EOK; } /* Update clock. */ - if (time_now(ts) < 0) { - return -1; - } + timev_t now; + if (time_now(&now) < 0) + return KNOT_ERROR; - ts->tv_sec += interval; /* Only seconds precision. */ - return 0; + set->timeout[i] = now.tv_sec + interval; /* Only seconds precision. */ + return KNOT_EOK; } -int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t*, int, void*), void *data) +int fdset_sweep(fdset_t* set, fdset_sweep_cb_t cb, void *data) { - fdset_base_t *base = (fdset_base_t*)fdset; - if (base == NULL || base->atimes == NULL) { - return -1; + if (set == NULL || cb == NULL) { + return KNOT_EINVAL; } /* Get time threshold. */ timev_t now; if (time_now(&now) < 0) { - return -1; + return KNOT_ERROR; } - /* Inspect all nodes. */ - int sweeped = 0; - const skip_node_t *n = skip_first(base->atimes); - while (n != NULL) { - const skip_node_t* pnext = skip_next(n); - - /* Evaluate */ - timev_t *ts = (timev_t*)n->value; - if (ts->tv_sec <= now.tv_sec) { - cb(fdset, (int)(((ssize_t)n->key)), data); - ++sweeped; + unsigned i = 0; + while (i < set->n) { + + /* Check sweep state, remove if requested. */ + if (set->timeout[i] > 0 && set->timeout[i] <= now.tv_sec) { + if (cb(set, i, data) == FDSET_SWEEP) { + if (fdset_remove(set, i) == KNOT_EOK) + continue; /* Stay on the index. */ + } } - n = pnext; + + /* Next descriptor. */ + ++i; } - return sweeped; + return KNOT_EOK; } /* OpenBSD compatibility. */ diff --git a/src/common/fdset.h b/src/common/fdset.h index e1facdb..f0ef849 100644 --- a/src/common/fdset.h +++ b/src/common/fdset.h @@ -18,12 +18,7 @@ * * \author Marek Vavrusa <marek.vavrusa@nic.cz> * - * \brief Wrapper for native I/O multiplexing. - * - * Selects best implementation according to config. - * - poll() - * - epoll() - * - kqueue() + * \brief I/O multiplexing with context and timeouts for each fd. * * \addtogroup common_lib * @{ @@ -32,88 +27,36 @@ #ifndef _KNOTD_FDSET_H_ #define _KNOTD_FDSET_H_ +#include <config.h> #include <stddef.h> -#ifdef HAVE_SYS_SELECT_H - #include <sys/select.h> -#endif -#ifdef HAVE_SYS_TIME_H - #include <sys/time.h> -#endif -#ifdef HAVE_SIGNAL_H - #include <signal.h> -#endif -#include "skip-list.h" -#include "mempattern.h" - -/*! \brief Waiting for completion constants. */ -enum fdset_wait_t { - OS_EV_FOREVER = -1, /*!< Wait forever. */ - OS_EV_NOWAIT = 0 /*!< Return immediately. */ +#include <poll.h> +#include <sys/time.h> +#include <signal.h> + +#define FDSET_INIT_SIZE 256 /* Resize step. */ + +/*! \brief Set of filedescriptors with associated context and timeouts. */ +typedef struct fdset { + unsigned n; /*!< Active fds. */ + unsigned size; /*!< Array size (allocated). */ + void* *ctx; /*!< Context for each fd. */ + struct pollfd *pfd; /*!< poll state for each fd */ + time_t *timeout; /*!< Timeout for each fd (seconds precision). */ +} fdset_t; + +/*! \brief Mark-and-sweep state. */ +enum fdset_sweep_state { + FDSET_KEEP, + FDSET_SWEEP }; -/*! \brief Base for implementation-specific fdsets. */ -typedef struct fdset_base_t { - skip_list_t *atimes; -} fdset_base_t; +/*! \brief Sweep callback (set, index, data) */ +typedef enum fdset_sweep_state (*fdset_sweep_cb_t)(fdset_t*, int, void*); /*! - * \brief Opaque pointer to implementation-specific fdset data. - * \warning Implementation MUST have fdset_base_t member on the first place. - * Example: - * struct fdset_t { - * fdset_base_t base; - * ...other members... - * } + * \brief Initialize fdset to given size. */ -typedef struct fdset_t fdset_t; - -/*! \brief Unified event types. */ -enum fdset_event_t { - OS_EV_READ = 1 << 0, /*!< Readable event. */ - OS_EV_WRITE = 1 << 1, /*!< Writeable event. */ - OS_EV_ERROR = 1 << 2 /*!< Error event. */ -}; - -/*! \brief File descriptor set iterator. */ -typedef struct fdset_it_t { - int fd; /*!< Current file descriptor. */ - int events; /*!< Returned events. */ - size_t pos; /* Internal usage. */ -} fdset_it_t; - -/*! - * \brief File descriptor set implementation backend. - * \note Functions documentation following. - * \internal - */ -struct fdset_backend_t -{ - fdset_t* (*fdset_new)(); - int (*fdset_destroy)(fdset_t*); - int (*fdset_add)(fdset_t*, int, int); - int (*fdset_remove)(fdset_t*, int); - int (*fdset_wait)(fdset_t*, int); - int (*fdset_begin)(fdset_t*, fdset_it_t*); - int (*fdset_end)(fdset_t*, fdset_it_t*); - int (*fdset_next)(fdset_t*, fdset_it_t*); - const char* (*fdset_method)(); -}; - -/*! - * \brief Selected backend. - * \internal - */ -extern struct fdset_backend_t _fdset_backend; - -/*! - * \brief Create new fdset. - * - * FDSET implementation depends on system. - * - * \retval Pointer to initialized FDSET structure if successful. - * \retval NULL on error. - */ -fdset_t *fdset_new(); +int fdset_init(fdset_t *set, unsigned size); /*! * \brief Destroy FDSET. @@ -121,125 +64,61 @@ fdset_t *fdset_new(); * \retval 0 if successful. * \retval -1 on error. */ -int fdset_destroy(fdset_t* fdset); +int fdset_clear(fdset_t* set); /*! * \brief Add file descriptor to watched set. * - * \param fdset Target set. + * \param set Target set. * \param fd Added file descriptor. * \param events Mask of watched events. + * \param ctx Context (optional). * - * \retval 0 if successful. + * \retval index of the added fd if successful. * \retval -1 on errors. */ -static inline int fdset_add(fdset_t *fdset, int fd, int events) { - return _fdset_backend.fdset_add(fdset, fd, events); -} - +int fdset_add(fdset_t *set, int fd, unsigned events, void *ctx); /*! * \brief Remove file descriptor from watched set. * - * \param fdset Target set. - * \param fd File descriptor to be removed. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_remove(fdset_t *fdset, int fd); - -/*! - * \brief Poll set for new events. - * - * \param fdset Target set. - * \param timeout Timeout (OS_EV_FOREVER, OS_EV_NOWAIT or value in miliseconds). - * - * \retval Number of events if successful. - * \retval -1 on errors. - */ -static inline int fdset_wait(fdset_t *fdset, int timeout) { - return _fdset_backend.fdset_wait(fdset, timeout); -} - -/*! - * \brief Set event iterator to the beginning of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -static inline int fdset_begin(fdset_t *fdset, fdset_it_t *it) { - return _fdset_backend.fdset_begin(fdset, it); -} - -/*! - * \brief Set event iterator to the end of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. + * \param set Target set. + * \param i Index of the removed fd. * * \retval 0 if successful. * \retval -1 on errors. */ -static inline int fdset_end(fdset_t *fdset, fdset_it_t *it) { - return _fdset_backend.fdset_end(fdset, it); -} - -/*! - * \brief Set event iterator to the next event. - * - * Event iterator fd will be set to -1 if next event doesn't exist. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -static inline int fdset_next(fdset_t *fdset, fdset_it_t *it) { - return _fdset_backend.fdset_next(fdset, it); -} - -/*! - * \brief Returned name of underlying poll method. - * - * \retval Name if successful. - * \retval NULL if no method was loaded (shouldn't happen). - */ -static inline const char* fdset_method() { - return _fdset_backend.fdset_method(); -} +int fdset_remove(fdset_t *set, unsigned i); /*! * \brief Set file descriptor watchdog interval. * - * Descriptors without activity in given interval - * can be disposed with fdset_sweep(). + * Set time (interval from now) after which the associated file descriptor + * should be sweeped (see fdset_sweep). Good example is setting a grace period + * of N seconds between socket activity. If socket is not active within + * <now, now + interval>, it is sweeped and potentially closed. * - * \param fdset Target set. - * \param fd File descriptor. + * \param set Target set. + * \param i Index for the file descriptor. * \param interval Allowed interval without activity (seconds). - * <0 removes watchdog interval. + * -1 disables watchdog timer * * \retval 0 if successful. * \retval -1 on errors. */ -int fdset_set_watchdog(fdset_t* fdset, int fd, int interval); +int fdset_set_watchdog(fdset_t* set, int i, int interval); /*! * \brief Sweep file descriptors with exceeding inactivity period. * * \param fdset Target set. * \param cb Callback for sweeped descriptors. - * \param data Custom data for sweep operation. + * \param data Pointer to extra data. * * \retval number of sweeped descriptors. * \retval -1 on errors. */ -int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t*, int, void*), void *data); +int fdset_sweep(fdset_t* set, fdset_sweep_cb_t cb, void *data); /*! * \brief pselect(2) compatibility wrapper. diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c deleted file mode 100644 index f889dd3..0000000 --- a/src/common/fdset_epoll.c +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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, either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> - -#ifdef HAVE_EPOLL_WAIT - -#include <sys/epoll.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> - -#include "fdset_epoll.h" -#include "skip-list.h" - -#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ - -struct fdset_t { - fdset_base_t _base; - int epfd; - struct epoll_event *events; - size_t nfds; - size_t reserved; - size_t polled; -}; - -fdset_t *fdset_epoll_new() -{ - fdset_t *set = malloc(sizeof(fdset_t)); - if (set) { - /* Blank memory. */ - memset(set, 0, sizeof(fdset_t)); - - /* Create epoll fd. */ - set->epfd = epoll_create(OS_FDS_CHUNKSIZE); - } - - return set; -} - -int fdset_epoll_destroy(fdset_t * fdset) -{ - if(fdset == NULL) { - return -1; - } - - /* Teardown epoll. */ - close(fdset->epfd); - - /* OK if NULL. */ - free(fdset->events); - free(fdset); - return 0; -} - -int fdset_epoll_add(fdset_t *fdset, int fd, int events) -{ - if (fdset == NULL || fd < 0 || events <= 0) { - return -1; - } - - /* Realloc needed. */ - if (mreserve((char **)&fdset->events, sizeof(struct epoll_event), - fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved) < 0) { - return -1; - } - - /* Add to epoll set. */ - struct epoll_event ev; - memset(&ev, 0, sizeof(struct epoll_event)); - ev.events = EPOLLIN; - ev.data.fd = fd; - if (epoll_ctl(fdset->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { - return -1; - } - - ++fdset->nfds; - return 0; -} - -int fdset_epoll_remove(fdset_t *fdset, int fd) -{ - if (fdset == NULL || fd < 0) { - return -1; - } - - /* Attempt to remove from set. */ - struct epoll_event ev; - memset(&ev, 0, sizeof(struct epoll_event)); - if (epoll_ctl(fdset->epfd, EPOLL_CTL_DEL, fd, &ev) < 0) { - return -1; - } - - /* Overwrite current item. */ - --fdset->nfds; - - /* Trim excessive memory if possible (retval is not interesting). */ - mreserve((char **)&fdset->events, sizeof(struct epoll_event), - fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved); - - return 0; -} - -int fdset_epoll_wait(fdset_t *fdset, int timeout) -{ - if (fdset == NULL || fdset->nfds < 1 || fdset->events == NULL) { - return -1; - } - - /* Poll new events. */ - fdset->polled = 0; - int nfds = epoll_wait(fdset->epfd, fdset->events, fdset->nfds, timeout); - - /* Check. */ - if (nfds < 0) { - return -1; - } - - /* Events array is ordered from 0 to nfds. */ - fdset->polled = nfds; - return nfds; -} - -int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL) { - return -1; - } - - /* Find first. */ - it->pos = 0; - return fdset_next(fdset, it); -} - -int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL || fdset->nfds < 1) { - return -1; - } - - /* Check for polled events. */ - if (fdset->polled < 1) { - it->fd = -1; - it->pos = 0; - return -1; - } - - /* No end found, ends on the beginning. */ - size_t nid = fdset->polled - 1; - it->fd = fdset->events[nid].data.fd; - it->pos = nid; - it->events = 0; - return -1; -} - -int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL || fdset->nfds < 1) { - return -1; - } - - /* Check boundaries. */ - if (it->pos >= fdset->polled || it->pos >= fdset->nfds) { - return -1; - } - - /* Select next. */ - size_t nid = it->pos++; - it->fd = fdset->events[nid].data.fd; - it->events = 0; - return 0; -} - -const char* fdset_epoll_method() -{ - return "epoll"; -} - -/* Package APIs. */ -struct fdset_backend_t FDSET_EPOLL = { - .fdset_new = fdset_epoll_new, - .fdset_destroy = fdset_epoll_destroy, - .fdset_add = fdset_epoll_add, - .fdset_remove = fdset_epoll_remove, - .fdset_wait = fdset_epoll_wait, - .fdset_begin = fdset_epoll_begin, - .fdset_end = fdset_epoll_end, - .fdset_next = fdset_epoll_next, - .fdset_method = fdset_epoll_method -}; - -#endif diff --git a/src/common/fdset_epoll.h b/src/common/fdset_epoll.h deleted file mode 100644 index 58f25f8..0000000 --- a/src/common/fdset_epoll.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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, either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. - */ -/*! - * \file fdset_epoll.h - * - * \author Marek Vavrusa <marek.vavrusa@nic.cz> - * - * \brief Wrapper for epoll I/O multiplexing. - * - * \addtogroup common_lib - * @{ - */ - -#ifndef _KNOTD_FDSET_EPOLL_H_ -#define _KNOTD_FDSET_EPOLL_H_ - -#include "fdset.h" - -/*! - * \brief Create new fdset. - * - * Linux epoll() backend. - * - * \retval Pointer to initialized FDSET structure if successful. - * \retval NULL on error. - */ -fdset_t *fdset_epoll_new(); - -/*! - * \brief Destroy FDSET. - * - * \retval 0 if successful. - * \retval -1 on error. - */ -int fdset_epoll_destroy(fdset_t * fdset); - -/*! - * \brief Add file descriptor to watched set. - * - * \param fdset Target set. - * \param fd Added file descriptor. - * \param events Mask of watched events. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_epoll_add(fdset_t *fdset, int fd, int events); - -/*! - * \brief Remove file descriptor from watched set. - * - * \param fdset Target set. - * \param fd File descriptor to be removed. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_epoll_remove(fdset_t *fdset, int fd); - -/*! - * \brief Poll set for new events. - * - * \param fdset Target set. - * \param timeout Timeout (OS_EV_FOREVER, OS_EV_NOWAIT or value in miliseconds). - * - * \retval Number of events if successful. - * \retval -1 on errors. - */ -int fdset_epoll_wait(fdset_t *fdset, int timeout); - -/*! - * \brief Set event iterator to the beginning of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Set event iterator to the end of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Set event iterator to the next event. - * - * Event iterator fd will be set to -1 if next event doesn't exist. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Returned name of epoll method. - * - * \retval Name if successful. - * \retval NULL if no method was loaded (shouldn't happen). - */ -const char* fdset_epoll_method(); - -/*! \brief Exported API. */ -extern struct fdset_backend_t FDSET_EPOLL; - -#endif /* _KNOTD_FDSET_EPOLL_H_ */ - -/*! @} */ diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c deleted file mode 100644 index 7c52f71..0000000 --- a/src/common/fdset_kqueue.c +++ /dev/null @@ -1,260 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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, either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#ifdef HAVE_KQUEUE - -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/event.h> -#include <sys/time.h> -#include <time.h> - -#include "fdset_kqueue.h" - -#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ -#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */ - -struct fdset_t { - fdset_base_t _base; - int kq; - struct kevent *events; - struct kevent *revents; - size_t nfds; - size_t reserved; - size_t rreserved; - size_t polled; -}; - -fdset_t *fdset_kqueue_new() -{ - fdset_t *set = malloc(sizeof(fdset_t)); - if (set) { - /* Blank memory. */ - memset(set, 0, sizeof(fdset_t)); - - /* Create kqueue fd. */ - set->kq = kqueue(); - if (set->kq < 0) { - free(set); - set = 0; - } - } - - return set; -} - -int fdset_kqueue_destroy(fdset_t * fdset) -{ - if(fdset == NULL) { - return -1; - } - - /* Teardown kqueue. */ - close(fdset->kq); - - /* OK if NULL. */ - free(fdset->revents); - free(fdset->events); - free(fdset); - return 0; -} - -int fdset_kqueue_add(fdset_t *fdset, int fd, int events) -{ - if (fdset == NULL || fd < 0 || events <= 0) { - return -1; - } - - /* Realloc needed. */ - int ret = 0; - ret += mreserve((char **)&fdset->events, sizeof(struct kevent), - fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved); - ret += mreserve((char **)&fdset->revents, sizeof(struct kevent), - fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->rreserved); - if (ret != 0) { - return ret; - } - - /* Add to kqueue set. */ - int evfilt = EVFILT_READ; - EV_SET(&fdset->events[fdset->nfds], fd, evfilt, - EV_ADD|EV_ENABLE, 0, 0, 0); - memset(fdset->revents + fdset->nfds, 0, sizeof(struct kevent)); - - ++fdset->nfds; - return 0; -} - -int fdset_kqueue_remove(fdset_t *fdset, int fd) -{ - if (fdset == NULL || fd < 0) { - return -1; - } - - /* Find in set. */ - int pos = -1; - for (int i = 0; i < fdset->nfds; ++i) { - if (fdset->events[i].ident == fd) { - pos = i; - break; - } - } - - if (pos < 0) { - return -1; - } - - /* Remove filters. */ - EV_SET(&fdset->events[pos], fd, EVFILT_READ, - EV_DISABLE|EV_DELETE, 0, 0, 0); - - /* Attempt to remove from set. */ - size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct kevent); - memmove(fdset->events + pos, fdset->events + (pos + 1), remaining); - - /* Attempt to remove from revents set. */ - pos = -1; - for (int i = 0; i < fdset->nfds; ++i) { - if (fdset->events[i].ident == fd) { - pos = i; - break; - } - } - if (pos >= 0) { - size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct kevent); - memmove(fdset->revents + pos, fdset->revents + (pos + 1), remaining); - } - - - /* Overwrite current item. */ - --fdset->nfds; - - /* Trim excessive memory if possible (retval is not interesting). */ - mreserve((char **)&fdset->events, sizeof(struct kevent), - fdset->nfds, OS_FDS_CHUNKSIZE, &fdset->reserved); - mreserve((char **)&fdset->revents, sizeof(struct kevent), - fdset->nfds, OS_FDS_CHUNKSIZE, &fdset->rreserved); - - return 0; -} - -int fdset_kqueue_wait(fdset_t *fdset, int timeout) -{ - if (fdset == NULL || fdset->nfds < 1 || fdset->events == NULL) { - return -1; - } - - /* Set timeout. */ - struct timespec tmval; - struct timespec *tm = NULL; - if (timeout == 0) { - tmval.tv_sec = tmval.tv_nsec = 0; - tm = &tmval; - } else if (timeout > 0) { - tmval.tv_sec = timeout / 1000; /* ms -> s */ - timeout -= tmval.tv_sec * 1000; /* Cut off */ - tmval.tv_nsec = timeout * 1000000L; /* ms -> ns */ - tm = &tmval; - } - - /* Poll new events. */ - fdset->polled = 0; - int nfds = kevent(fdset->kq, fdset->events, fdset->nfds, - fdset->revents, fdset->nfds, tm); - - /* Check. */ - if (nfds < 0) { - return -1; - } - - /* Events array is ordered from 0 to nfds. */ - fdset->polled = nfds; - return nfds; -} - -int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL) { - return -1; - } - - /* Find first. */ - it->pos = 0; - it->fd = -1; - return fdset_next(fdset, it); -} - -int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL || fdset->nfds < 1) { - return -1; - } - - /* Check for polled events. */ - if (fdset->polled < 1) { - it->fd = -1; - it->pos = 0; - return -1; - } - - /* No end found, ends on the beginning. */ - size_t nid = fdset->polled - 1; - it->fd = fdset->revents[nid].ident; - it->pos = nid; - it->events = 0; /*! \todo Map events. */ - return -1; -} - -int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL || fdset->polled < 1) { - return -1; - } - - /* Check boundaries. */ - if (it->pos >= fdset->polled || it->pos >= fdset->nfds) { - return -1; - } - - /* Select next. */ - size_t nid = it->pos++; - it->fd = fdset->revents[nid].ident; - it->events = 0; /*! \todo Map events. */ - return 0; -} - -const char* fdset_kqueue_method() -{ - return "kqueue"; -} - -/* Package APIs. */ -struct fdset_backend_t FDSET_KQUEUE = { - .fdset_new = fdset_kqueue_new, - .fdset_destroy = fdset_kqueue_destroy, - .fdset_add = fdset_kqueue_add, - .fdset_remove = fdset_kqueue_remove, - .fdset_wait = fdset_kqueue_wait, - .fdset_begin = fdset_kqueue_begin, - .fdset_end = fdset_kqueue_end, - .fdset_next = fdset_kqueue_next, - .fdset_method = fdset_kqueue_method -}; - -#endif diff --git a/src/common/fdset_kqueue.h b/src/common/fdset_kqueue.h deleted file mode 100644 index 4b650a7..0000000 --- a/src/common/fdset_kqueue.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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, either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. - */ -/*! - * \file fdset_kqueue.h - * - * \author Marek Vavrusa <marek.vavrusa@nic.cz> - * - * \brief Wrapper for kqueue I/O multiplexing. - * - * \addtogroup common_lib - * @{ - */ - -#ifndef _KNOTD_FDSET_KQUEUE_H_ -#define _KNOTD_FDSET_KQUEUE_H_ - -#include "fdset.h" - -/*! - * \brief Create new fdset. - * - * BSD kqueue() backend. - * - * \retval Pointer to initialized FDSET structure if successful. - * \retval NULL on error. - */ -fdset_t *fdset_kqueue_new(); - -/*! - * \brief Destroy FDSET. - * - * \retval 0 if successful. - * \retval -1 on error. - */ -int fdset_kqueue_destroy(fdset_t * fdset); - -/*! - * \brief Add file descriptor to watched set. - * - * \param fdset Target set. - * \param fd Added file descriptor. - * \param events Mask of watched events. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_kqueue_add(fdset_t *fdset, int fd, int events); - -/*! - * \brief Remove file descriptor from watched set. - * - * \param fdset Target set. - * \param fd File descriptor to be removed. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_kqueue_remove(fdset_t *fdset, int fd); - -/*! - * \brief Poll set for new events. - * - * \param fdset Target set. - * \param timeout Timeout (OS_EV_FOREVER, OS_EV_NOWAIT or value in miliseconds). - * - * \retval Number of events if successful. - * \retval -1 on errors. - */ -int fdset_kqueue_wait(fdset_t *fdset, int timeout); - -/*! - * \brief Set event iterator to the beginning of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Set event iterator to the end of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Set event iterator to the next event. - * - * Event iterator fd will be set to -1 if next event doesn't exist. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Returned name of kqueue method. - * - * \retval Name if successful. - * \retval NULL if no method was loaded (shouldn't happen). - */ -const char* fdset_kqueue_method(); - -/*! \brief Exported API. */ -extern struct fdset_backend_t FDSET_KQUEUE; - -#endif /* _KNOTD_FDSET_KQUEUE_H_ */ - -/*! @} */ diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c deleted file mode 100644 index e16ae11..0000000 --- a/src/common/fdset_poll.c +++ /dev/null @@ -1,218 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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, either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> - -#ifdef HAVE_POLL - -#include <stdlib.h> -#include <string.h> -#include <sys/poll.h> -#include <stddef.h> - -#include "common/fdset_poll.h" - -#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ - -struct fdset_t { - fdset_base_t _base; - struct pollfd *fds; - nfds_t nfds; - size_t reserved; - size_t polled; - size_t begin; -}; - -fdset_t *fdset_poll_new() -{ - fdset_t *set = malloc(sizeof(fdset_t)); - if (set != NULL) { - memset(set, 0, sizeof(fdset_t)); - } - - return set; -} - -int fdset_poll_destroy(fdset_t * fdset) -{ - if(fdset == NULL) { - return -1; - } - - /* OK if NULL. */ - free(fdset->fds); - free(fdset); - return 0; -} - -int fdset_poll_add(fdset_t *fdset, int fd, int events) -{ - if (fdset == NULL || fd < 0 || events <= 0) { - return -1; - } - - /* Realloc needed. */ - if (mreserve((char **)&fdset->fds, sizeof(struct pollfd), - fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved) < 0) { - return -1; - } - - /* Append. */ - int nid = fdset->nfds++; - fdset->fds[nid].fd = fd; - fdset->fds[nid].events = POLLIN; - fdset->fds[nid].revents = 0; - return 0; -} - -int fdset_poll_remove(fdset_t *fdset, int fd) -{ - if (fdset == NULL || fd < 0) { - return -1; - } - - /* Find file descriptor. */ - unsigned found = 0; - size_t pos = 0; - for (size_t i = 0; i < fdset->nfds; ++i) { - if (fdset->fds[i].fd == fd) { - found = 1; - pos = i; - break; - } - } - - /* Check. */ - if (!found) { - return -1; - } - - /* Overwrite current item. */ - size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct pollfd); - memmove(fdset->fds + pos, fdset->fds + (pos + 1), remaining); - --fdset->nfds; - - /* Trim excessive memory if possible (retval is not interesting). */ - mreserve((char **)&fdset->fds, sizeof(struct pollfd), fdset->nfds, - OS_FDS_CHUNKSIZE, &fdset->reserved); - - return 0; -} - -int fdset_poll_wait(fdset_t *fdset, int timeout) -{ - if (fdset == NULL || fdset->nfds < 1 || fdset->fds == NULL) { - return -1; - } - - /* Initialize pointers. */ - fdset->polled = 0; - fdset->begin = 0; - - /* Poll for events. */ - int ret = poll(fdset->fds, fdset->nfds, timeout); - if (ret < 0) { - return -1; - } - - /* Set pointers for iterating. */ - fdset->polled = ret; - fdset->begin = 0; - return ret; -} - -int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL) { - return -1; - } - - /* Find first. */ - it->pos = 0; - return fdset_next(fdset, it); -} - -int fdset_poll_end(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL || fdset->nfds < 1) { - return -1; - } - - /* Check for polled events. */ - if (fdset->polled < 1) { - it->fd = -1; - it->pos = 0; - return -1; - } - - /* Trace last matching item from the end. */ - struct pollfd* pfd = fdset->fds + fdset->nfds - 1; - while (pfd != fdset->fds) { - if (pfd->events & pfd->revents) { - it->fd = pfd->fd; - it->pos = pfd - fdset->fds; - return 0; - } - } - - /* No end found, ends on the beginning. */ - it->fd = -1; - it->pos = 0; - return -1; -} - -int fdset_poll_next(fdset_t *fdset, fdset_it_t *it) -{ - if (fdset == NULL || it == NULL || fdset->nfds < 1) { - return -1; - } - - /* Find next with matching flags. */ - for (; it->pos < fdset->nfds; ++it->pos) { - struct pollfd* pfd = fdset->fds + it->pos; - if (pfd->events & pfd->revents) { - it->fd = pfd->fd; - it->events = pfd->revents; - ++it->pos; /* Next will start after current. */ - return 0; - } - } - - /* No matching event found. */ - it->fd = -1; - it->pos = 0; - return -1; -} - -const char* fdset_poll_method() -{ - return "poll"; -} - -/* Package APIs. */ -struct fdset_backend_t FDSET_POLL = { - .fdset_new = fdset_poll_new, - .fdset_destroy = fdset_poll_destroy, - .fdset_add = fdset_poll_add, - .fdset_remove = fdset_poll_remove, - .fdset_wait = fdset_poll_wait, - .fdset_begin = fdset_poll_begin, - .fdset_end = fdset_poll_end, - .fdset_next = fdset_poll_next, - .fdset_method = fdset_poll_method -}; - -#endif diff --git a/src/common/fdset_poll.h b/src/common/fdset_poll.h deleted file mode 100644 index 68e9e69..0000000 --- a/src/common/fdset_poll.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - 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, either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. - */ -/*! - * \file fdset_poll.h - * - * \author Marek Vavrusa <marek.vavrusa@nic.cz> - * - * \brief Wrapper for poll I/O multiplexing. - * - * \addtogroup common_lib - * @{ - */ - -#ifndef _KNOTD_FDSET_POLL_H_ -#define _KNOTD_FDSET_POLL_H_ - -#include "fdset.h" - -/*! - * \brief Create new fdset. - * - * POSIX poll() backend. - * - * \retval Pointer to initialized FDSET structure if successful. - * \retval NULL on error. - */ -fdset_t *fdset_poll_new(); - -/*! - * \brief Destroy FDSET. - * - * \retval 0 if successful. - * \retval -1 on error. - */ -int fdset_poll_destroy(fdset_t * fdset); - -/*! - * \brief Add file descriptor to watched set. - * - * \param fdset Target set. - * \param fd Added file descriptor. - * \param events Mask of watched events. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_poll_add(fdset_t *fdset, int fd, int events); - -/*! - * \brief Remove file descriptor from watched set. - * - * \param fdset Target set. - * \param fd File descriptor to be removed. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_poll_remove(fdset_t *fdset, int fd); - -/*! - * \brief Poll set for new events. - * - * \param fdset Target set. - * \param timeout Timeout (OS_EV_FOREVER, OS_EV_NOWAIT or value in miliseconds). - * - * \retval Number of events if successful. - * \retval -1 on errors. - */ -int fdset_poll_wait(fdset_t *fdset, int timeout); - -/*! - * \brief Set event iterator to the beginning of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Set event iterator to the end of last polled events. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_poll_end(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Set event iterator to the next event. - * - * Event iterator fd will be set to -1 if next event doesn't exist. - * - * \param fdset Target set. - * \param it Event iterator. - * - * \retval 0 if successful. - * \retval -1 on errors. - */ -int fdset_poll_next(fdset_t *fdset, fdset_it_t *it); - -/*! - * \brief Returned name of poll method. - * - * \retval Name if successful. - * \retval NULL if no method was loaded (shouldn't happen). - */ -const char* fdset_poll_method(); - -/*! \brief Exported API. */ -extern struct fdset_backend_t FDSET_POLL; - -#endif /* _KNOTD_FDSET_POLL_H_ */ - -/*! @} */ |