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
+};