diff --git a/Knot.files b/Knot.files index e21fa6cd3f01d39c77ab4cb53db76aabe05ed467..788baf4debe16af94793da0abba4a9530609f952 100644 --- a/Knot.files +++ b/Knot.files @@ -109,7 +109,9 @@ src/common/WELL1024a.c src/common/WELL1024a.h src/common/fdset.h src/common/fdset.c +src/common/fdset_poll.h src/common/fdset_poll.c +src/common/fdset_epoll.h src/common/fdset_epoll.c src/zcompile/parser-descriptor.h src/zcompile/parser-descriptor.c diff --git a/src/Makefile.am b/src/Makefile.am index 2f651c1e4280f9127efec1bb4c2aeb77194eea14..f9ae2a09388b15ea9246d7699a993127b61c96e4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -179,8 +179,12 @@ libknots_la_SOURCES = \ common/errors.c \ common/WELL1024a.h \ common/WELL1024a.c \ - common/fdset.h \ - common/fdset.c + common/fdset.h \ + common/fdset.c \ + common/fdset_poll.h \ + common/fdset_poll.c \ + common/fdset_epoll.h \ + common/fdset_epoll.c libknotd_la_SOURCES = \ knot/stat/gatherer.c \ diff --git a/src/common/fdset.c b/src/common/fdset.c index fd875745bf0df1cd0437515752ae1ad1e9d01b6f..203b4244ac590cfca4b45f6da4677ae3cd8e51dd 100644 --- a/src/common/fdset.c +++ b/src/common/fdset.c @@ -1,35 +1,59 @@ -#include "fdset.h" +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* Required for RTLD_DEFAULT. */ +#endif + +#include <dlfcn.h> +#include <string.h> +#include <stdio.h> +#include "common/fdset.h" #include "config.h" -/* Attempt to use epoll_wait(). */ +struct fdset_backend_t _fdset_backend = { +}; + +/*! \brief Set backend implementation. */ +static void fdset_set_backend(struct fdset_backend_t *backend) { + memcpy(&_fdset_backend, backend, sizeof(struct fdset_backend_t)); +} + +/* Linux epoll API. */ #ifdef HAVE_EPOLL_WAIT - #include "fdset_epoll.c" -#else - /* Attempt to use kqueue(). */ - #ifdef HAVE_KQUEUE - #warning "fdset: kqueue backend N/A, fallback to poll()" - #include "fdset_poll.c" - #else - /* poll() API */ - #ifdef HAVE_POLL - #include "fdset_poll.c" - #else - #error "fdset: no socket polling API found" - #endif /* HAVE_POLL */ - #endif /* HAVE_KQUEUE */ + #include "common/fdset_epoll.h" #endif /* HAVE_EPOLL_WAIT */ -/*! \todo Implement switchable backends on run-time. */ -///*! \brief Bootstrap polling subsystem (it is called automatically). */ -//#include <stdio.h> -//#define _GNU_SOURCE /* Required for RTLD_DEFAULT. */ -//#include <dlfcn.h> -//void __attribute__ ((constructor)) fdset_init() -//{ -// int poll_ok = dlsym(RTLD_DEFAULT, "poll") != 0; -// int epoll_ok = dlsym(RTLD_DEFAULT, "epoll_wait") != 0; -// int kqueue_ok = dlsym(RTLD_DEFAULT, "kqueue") != 0; - -// fprintf(stderr, "using polling subsystem %s (poll %d epoll %d kqueue %d)\n", -// fdset_method(), poll_ok, epoll_ok, kqueue_ok); -//} +/* BSD kqueue API */ +#ifdef HAVE_KQUEUE + #warning "fixme: missing kqueue backend" + //#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() +{ + /* Preference: epoll */ + if (dlsym(RTLD_DEFAULT, "epoll_wait") != 0) { + fdset_set_backend(&_fdset_epoll); + return; + } + + /* Preference: kqueue */ +// if (dlsym(RTLD_DEFAULT, "kqueue") != 0) { +// fdset_set_backend(&_fdset_kqueue); +// return; +// } + + /* Preference: poll */ + if (dlsym(RTLD_DEFAULT, "poll") != 0) { + fdset_set_backend(&_fdset_poll); + return; + } + + /* This shouldn't happen. */ + fprintf(stderr, "fdset: fatal error - no valid fdset backend found\n"); + return; +} diff --git a/src/common/fdset.h b/src/common/fdset.h index 500f5d6018545b3a7e748c41ff479fd671213417..c8a88177b84ad0d301fdc888acaec1b08b948471 100644 --- a/src/common/fdset.h +++ b/src/common/fdset.h @@ -37,6 +37,30 @@ typedef struct fdset_it_t { size_t pos; /* Internal usage. */ } fdset_it_t; +/*! + * \brief File descriptor set implementation backend. + * \notice 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 (*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 + */ +struct fdset_backend_t _fdset_backend; + /*! * \brief Create new fdset. * @@ -45,7 +69,9 @@ typedef struct fdset_it_t { * \retval Pointer to initialized FDSET structure if successful. * \retval NULL on error. */ -fdset_t *fdset_new(); +static inline fdset_t *fdset_new() { + return _fdset_backend.fdset_new(); +} /*! * \brief Destroy FDSET. @@ -53,7 +79,9 @@ fdset_t *fdset_new(); * \retval 0 if successful. * \retval -1 on error. */ -int fdset_destroy(fdset_t * fdset); +static inline int fdset_destroy(fdset_t * fdset) { + return _fdset_backend.fdset_destroy(fdset); +} /*! * \brief Add file descriptor to watched set. @@ -65,7 +93,10 @@ int fdset_destroy(fdset_t * fdset); * \retval 0 if successful. * \retval -1 on errors. */ -int fdset_add(fdset_t *fdset, int fd, int events); +static inline int fdset_add(fdset_t *fdset, int fd, int events) { + return _fdset_backend.fdset_add(fdset, fd, events); +} + /*! * \brief Remove file descriptor from watched set. @@ -76,7 +107,9 @@ int fdset_add(fdset_t *fdset, int fd, int events); * \retval 0 if successful. * \retval -1 on errors. */ -int fdset_remove(fdset_t *fdset, int fd); +static inline int fdset_remove(fdset_t *fdset, int fd) { + return _fdset_backend.fdset_remove(fdset, fd); +} /*! * \brief Poll set for new events. @@ -88,7 +121,9 @@ int fdset_remove(fdset_t *fdset, int fd); * * \todo Timeout. */ -int fdset_wait(fdset_t *fdset); +static inline int fdset_wait(fdset_t *fdset) { + return _fdset_backend.fdset_wait(fdset); +} /*! * \brief Set event iterator to the beginning of last polled events. @@ -99,7 +134,9 @@ int fdset_wait(fdset_t *fdset); * \retval 0 if successful. * \retval -1 on errors. */ -int fdset_begin(fdset_t *fdset, fdset_it_t *it); +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. @@ -110,7 +147,9 @@ int fdset_begin(fdset_t *fdset, fdset_it_t *it); * \retval 0 if successful. * \retval -1 on errors. */ -int fdset_end(fdset_t *fdset, fdset_it_t *it); +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. @@ -123,7 +162,9 @@ int fdset_end(fdset_t *fdset, fdset_it_t *it); * \retval 0 if successful. * \retval -1 on errors. */ -int fdset_next(fdset_t *fdset, fdset_it_t *it); +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. @@ -131,7 +172,9 @@ int fdset_next(fdset_t *fdset, fdset_it_t *it); * \retval Name if successful. * \retval NULL if no method was loaded (shouldn't happen). */ -const char* fdset_method(); +static inline const char* fdset_method() { + return _fdset_backend.fdset_method(); +} #endif /* _KNOTD_FDSET_H_ */ diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c index 6067770bcdc205f06b8a07b830158fba39a3cd65..368643a83268f13b4062add7886c407ee6714905 100644 --- a/src/common/fdset_epoll.c +++ b/src/common/fdset_epoll.c @@ -16,7 +16,7 @@ struct fdset_t { size_t polled; }; -fdset_t *fdset_new() +fdset_t *fdset_epoll_new() { fdset_t *set = malloc(sizeof(fdset_t)); if (!set) { @@ -32,7 +32,7 @@ fdset_t *fdset_new() return set; } -int fdset_destroy(fdset_t * fdset) +int fdset_epoll_destroy(fdset_t * fdset) { if(!fdset) { return -1; @@ -47,7 +47,7 @@ int fdset_destroy(fdset_t * fdset) return 0; } -int fdset_add(fdset_t *fdset, int fd, int events) +int fdset_epoll_add(fdset_t *fdset, int fd, int events) { if (!fdset || fd < 0 || events <= 0) { return -1; @@ -84,7 +84,7 @@ int fdset_add(fdset_t *fdset, int fd, int events) return 0; } -int fdset_remove(fdset_t *fdset, int fd) +int fdset_epoll_remove(fdset_t *fdset, int fd) { if (!fdset || fd < 0) { return -1; @@ -104,7 +104,7 @@ int fdset_remove(fdset_t *fdset, int fd) return 0; } -int fdset_wait(fdset_t *fdset) +int fdset_epoll_wait(fdset_t *fdset) { if (!fdset || fdset->nfds < 1 || !fdset->events) { return -1; @@ -124,7 +124,7 @@ int fdset_wait(fdset_t *fdset) return nfds; } -int fdset_begin(fdset_t *fdset, fdset_it_t *it) +int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it) { if (!fdset || !it) { return -1; @@ -135,7 +135,7 @@ int fdset_begin(fdset_t *fdset, fdset_it_t *it) return fdset_next(fdset, it); } -int fdset_end(fdset_t *fdset, fdset_it_t *it) +int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it) { if (!fdset || !it || fdset->nfds < 1) { return -1; @@ -156,7 +156,7 @@ int fdset_end(fdset_t *fdset, fdset_it_t *it) return -1; } -int fdset_next(fdset_t *fdset, fdset_it_t *it) +int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it) { if (!fdset || !it || fdset->nfds < 1) { return -1; @@ -174,7 +174,20 @@ int fdset_next(fdset_t *fdset, fdset_it_t *it) return 0; } -const char* fdset_method() +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 +}; diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c index d7f2035c9b607d629295525e5f8b1186eddeec4f..f26b4cd8b83d4f9783666e2f85a3d4f03fec16a9 100644 --- a/src/common/fdset_poll.c +++ b/src/common/fdset_poll.c @@ -3,7 +3,7 @@ #include <sys/poll.h> #include <stddef.h> -#include "fdset.h" +#include "common/fdset_poll.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. */ @@ -16,7 +16,7 @@ struct fdset_t { size_t begin; }; -fdset_t *fdset_new() +fdset_t *fdset_poll_new() { fdset_t *set = malloc(sizeof(fdset_t)); if (!set) { @@ -28,7 +28,7 @@ fdset_t *fdset_new() return set; } -int fdset_destroy(fdset_t * fdset) +int fdset_poll_destroy(fdset_t * fdset) { if(!fdset) { return -1; @@ -42,7 +42,7 @@ int fdset_destroy(fdset_t * fdset) return 0; } -int fdset_add(fdset_t *fdset, int fd, int events) +int fdset_poll_add(fdset_t *fdset, int fd, int events) { if (!fdset || fd < 0 || events <= 0) { return -1; @@ -72,7 +72,7 @@ int fdset_add(fdset_t *fdset, int fd, int events) return 0; } -int fdset_remove(fdset_t *fdset, int fd) +int fdset_poll_remove(fdset_t *fdset, int fd) { if (!fdset || fd < 0) { return -1; @@ -104,7 +104,7 @@ int fdset_remove(fdset_t *fdset, int fd) return 0; } -int fdset_wait(fdset_t *fdset) +int fdset_poll_wait(fdset_t *fdset) { if (!fdset || fdset->nfds < 1 || !fdset->fds) { return -1; @@ -126,7 +126,7 @@ int fdset_wait(fdset_t *fdset) return ret; } -int fdset_begin(fdset_t *fdset, fdset_it_t *it) +int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it) { if (!fdset || !it) { return -1; @@ -137,7 +137,7 @@ int fdset_begin(fdset_t *fdset, fdset_it_t *it) return fdset_next(fdset, it); } -int fdset_end(fdset_t *fdset, fdset_it_t *it) +int fdset_poll_end(fdset_t *fdset, fdset_it_t *it) { if (!fdset || !it || fdset->nfds < 1) { return -1; @@ -166,7 +166,7 @@ int fdset_end(fdset_t *fdset, fdset_it_t *it) return -1; } -int fdset_next(fdset_t *fdset, fdset_it_t *it) +int fdset_poll_next(fdset_t *fdset, fdset_it_t *it) { if (!fdset || !it || fdset->nfds < 1) { return -1; @@ -189,7 +189,20 @@ int fdset_next(fdset_t *fdset, fdset_it_t *it) return -1; } -const char* fdset_method() +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 +};