MAJOR: polling: replace epoll with sepoll and remove sepoll

Now that all pollers make use of speculative I/O, there is no point
having two epoll implementations, so replace epoll with the sepoll code
and remove sepoll which has just become the standard epoll method.
diff --git a/Makefile b/Makefile
index 9641732..f13848c 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,6 @@
 #   USE_POLL             : enable poll(). Automatic.
 #   USE_PRIVATE_CACHE    : disable shared memory cache of ssl sessions.
 #   USE_REGPARM          : enable regparm optimization. Recommended on x86.
-#   USE_SEPOLL           : enable speculative epoll(). Automatic.
 #   USE_STATIC_PCRE      : enable static libpcre. Recommended.
 #   USE_TPROXY           : enable transparent proxy. Automatic.
 #   USE_LINUX_TPROXY     : enable full transparent proxy. Automatic.
@@ -216,7 +215,6 @@
   USE_NETFILTER   = implicit
   USE_POLL        = implicit
   USE_EPOLL       = implicit
-  USE_SEPOLL      = implicit
   USE_MY_EPOLL    = implicit
   USE_TPROXY      = implicit
   USE_LIBCRYPT    = implicit
@@ -227,7 +225,6 @@
   USE_NETFILTER   = implicit
   USE_POLL        = implicit
   USE_EPOLL       = implicit
-  USE_SEPOLL      = implicit
   USE_TPROXY      = implicit
   USE_LIBCRYPT    = implicit
   USE_FUTEX       = implicit
@@ -238,7 +235,6 @@
   USE_NETFILTER   = implicit
   USE_POLL        = implicit
   USE_EPOLL       = implicit
-  USE_SEPOLL      = implicit
   USE_TPROXY      = implicit
   USE_LIBCRYPT    = implicit
   USE_LINUX_SPLICE= implicit
@@ -424,12 +420,6 @@
 BUILD_OPTIONS  += $(call ignore_implicit,USE_EPOLL)
 endif
 
-ifneq ($(USE_SEPOLL),)
-OPTIONS_CFLAGS += -DENABLE_SEPOLL
-OPTIONS_OBJS   += src/ev_sepoll.o
-BUILD_OPTIONS  += $(call ignore_implicit,USE_SEPOLL)
-endif
-
 ifneq ($(USE_MY_EPOLL),)
 OPTIONS_CFLAGS += -DUSE_MY_EPOLL
 BUILD_OPTIONS  += $(call ignore_implicit,USE_MY_EPOLL)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index dfb37ae..b503720 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -461,7 +461,6 @@
    - noepoll
    - nokqueue
    - nopoll
-   - nosepoll
    - nosplice
    - spread-checks
    - tune.bufsize
@@ -708,7 +707,7 @@
 noepoll
   Disables the use of the "epoll" event polling system on Linux. It is
   equivalent to the command-line argument "-de". The next polling system
-  used will generally be "poll". See also "nosepoll", and "nopoll".
+  used will generally be "poll". See also "nopoll".
 
 nokqueue
   Disables the use of the "kqueue" event polling system on BSD. It is
@@ -719,13 +718,7 @@
   Disables the use of the "poll" event polling system. It is equivalent to the
   command-line argument "-dp". The next polling system used will be "select".
   It should never be needed to disable "poll" since it's available on all
-  platforms supported by HAProxy. See also "nosepoll", and "nopoll" and
-  "nokqueue".
-
-nosepoll
-  Disables the use of the "speculative epoll" event polling system on Linux. It
-  is equivalent to the command-line argument "-ds". The next polling system
-  used will generally be "epoll". See also "nosepoll", and "nopoll".
+  platforms supported by HAProxy. See also "nokqueue" and "noepoll".
 
 nosplice
   Disables the use of kernel tcp splicing between sockets on Linux. It is
diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt
index 6a7aa01..3d2a2be 100644
--- a/doc/haproxy-en.txt
+++ b/doc/haproxy-en.txt
@@ -62,7 +62,6 @@
     -s shows statistics (only if compiled in)
     -l shows even more statistics (implies '-s')
     -dk disables use of kqueue()
-    -ds disables use of speculative epoll()
     -de disables use of epoll()
     -dp disables use of poll()
     -db disables background mode (stays in foreground, useful for debugging)
@@ -130,7 +129,6 @@
   - daemon
   - debug
   - nokqueue
-  - nosepoll
   - noepoll
   - nopoll
   - quiet
@@ -357,8 +355,8 @@
 Haproxy will use kqueue() or speculative epoll() when available, then epoll(),
 and will fall back to poll(), then to select(). However, if for any reason you
 need to disable epoll() or poll() (eg. because of a bug or just to compare
-performance), new global options have been created for this matter : 'nosepoll',
-'nokqueue', 'noepoll' and 'nopoll'.
+performance), new global options have been created for this matter : 'nopoll',
+'nokqueue', and 'noepoll'.
 
 Example :
 ---------
@@ -378,7 +376,7 @@
 To make debugging easier, the '-de' runtime argument disables epoll support,
 the '-dp' argument disables poll support, '-dk' disables kqueue and '-ds'
 disables speculative epoll(). They are respectively equivalent to 'noepoll',
-'nopoll', 'nokqueue' and 'nosepoll'.
+'nopoll', and 'nokqueue'.
 
 
 2) Declaration of a listening service
diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt
index 89df8cb..87bb972 100644
--- a/doc/haproxy-fr.txt
+++ b/doc/haproxy-fr.txt
@@ -137,7 +137,6 @@
   - daemon
   - debug
   - nokqueue
-  - nosepoll
   - noepoll
   - nopoll
   - quiet
@@ -384,7 +383,7 @@
 Cependant, si pour une raison quelconque il s'avérait nécessaire de désactiver
 epoll() ou poll() (p.ex: à cause d'un bug ou juste pour comparer les
 performances), de nouvelles options globales ont été ajoutées dans ce but :
-'nosepoll', 'nokqueue', 'noepoll' et 'nopoll'.
+'nokqueue', 'noepoll' et 'nopoll'.
 
 Exemple :
 ---------
@@ -403,7 +402,7 @@
 Afin de simplifier la résolution de problèmes, le paramètre '-de' en ligne de
 commande désactive epoll(), le paramètre '-dp' désactive poll(), '-dk' kqueue()
 et '-ds' désactive speculative epoll(). Ils sont respectivement équivalents à
-'noepoll', 'nopoll', 'nokqueue' et 'nosepoll'.
+'noepoll', 'nopoll', et 'nokqueue'.
 
 
 2) Définition d'un service en écoute
diff --git a/include/common/epoll.h b/include/common/epoll.h
index 4953230..cc395cd 100644
--- a/include/common/epoll.h
+++ b/include/common/epoll.h
@@ -2,7 +2,7 @@
  * include/common/epoll.h
  * epoll definitions for older libc.
  *
- * Copyright (C) 2000-2011 Willy Tarreau - w@1wt.eu
+ * Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,7 +29,7 @@
 #ifndef _COMMON_EPOLL_H
 #define _COMMON_EPOLL_H
 
-#if defined (__linux__) && (defined(ENABLE_EPOLL) || defined(ENABLE_SEPOLL))
+#if defined (__linux__) && defined(ENABLE_EPOLL)
 
 #ifndef USE_MY_EPOLL
 #include <sys/epoll.h>
@@ -94,7 +94,7 @@
 
 #endif /* USE_MY_EPOLL */
 
-#endif /* __linux__ && (ENABLE_EPOLL || ENABLE_SEPOLL) */
+#endif /* __linux__ && ENABLE_EPOLL */
 
 #endif /* _COMMON_EPOLL_H */
 
diff --git a/include/types/global.h b/include/types/global.h
index 6b267fb..9d2eedf 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -2,7 +2,7 @@
  * include/types/global.h
  * Global variables.
  *
- * Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
+ * Copyright (C) 2000-2012 Willy Tarreau - w@1wt.eu
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -54,9 +54,8 @@
 #define GTUNE_USE_POLL           (1<<1)
 #define GTUNE_USE_EPOLL          (1<<2)
 #define GTUNE_USE_KQUEUE         (1<<3)
-#define GTUNE_USE_SEPOLL         (1<<4)
 /* platform-specific options */
-#define GTUNE_USE_SPLICE         (1<<5)
+#define GTUNE_USE_SPLICE         (1<<4)
 
 /* Access level for a stats socket */
 #define ACCESS_LVL_NONE     0
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 6a4e0bb..6c58e43 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -514,9 +514,6 @@
 	else if (!strcmp(args[0], "noepoll")) {
 		global.tune.options &= ~GTUNE_USE_EPOLL;
 	}
-	else if (!strcmp(args[0], "nosepoll")) {
-		global.tune.options &= ~GTUNE_USE_SEPOLL;
-	}
 	else if (!strcmp(args[0], "nokqueue")) {
 		global.tune.options &= ~GTUNE_USE_KQUEUE;
 	}
diff --git a/src/ev_epoll.c b/src/ev_epoll.c
index 90769c1..62718d6 100644
--- a/src/ev_epoll.c
+++ b/src/ev_epoll.c
@@ -1,13 +1,12 @@
 /*
- * FD polling functions for linux epoll()
+ * FD polling functions for Linux epoll
  *
- * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
  *
  * 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
  * 2 of the License, or (at your option) any later version.
- *
  */
 
 #include <unistd.h>
@@ -16,37 +15,21 @@
 
 #include <common/compat.h>
 #include <common/config.h>
+#include <common/debug.h>
 #include <common/epoll.h>
 #include <common/standard.h>
 #include <common/ticks.h>
 #include <common/time.h>
 #include <common/tools.h>
 
-#include <types/fd.h>
 #include <types/global.h>
 
+#include <proto/fd.h>
 #include <proto/signal.h>
 #include <proto/task.h>
 
-/* This is what we store in a list. It consists in old values and fds to detect changes. */
-struct fd_chg {
-	unsigned int prev:2;	// previous state mask. New one is in fd_evts.
-	unsigned int fd:30;	// file descriptor
-};
-
-static int nbchanges = 0;		// number of changes pending
-static struct fd_chg *chg_list = NULL;	// list of changes
-static struct fd_chg **chg_ptr = NULL;	// per-fd changes
-
-/* Each 32-bit word contains 2-bit descriptors of the latest state for 16 FDs :
- *   desc = (u32 >> (2*fd)) & 3
- *   desc = 0 : FD not set
- *          1 : WRITE not set, READ set
- *          2 : WRITE set, READ not set
- *          3 : WRITE set, READ set
- */
 
-static uint32_t *fd_evts;
+static int absmaxevents = 0;    // absolute maximum amounts of polled events
 
 /* private data */
 static struct epoll_event *epoll_events;
@@ -57,190 +40,102 @@
  */
 static struct epoll_event ev;
 
-/* converts a direction to a single bitmask.
- *  0 => 1
- *  1 => 2
- */
-#define DIR2MSK(dir) ((dir) + 1)
-
-/* converts an FD to an fd_evts offset and to a bit shift */
-#define FD2OFS(fd)   ((uint32_t)(fd) >> 4)
-#define FD2BIT(fd)   (((uint32_t)(fd) & 0xF) << 1)
-#define FD2MSK(fd)   (3 << FD2BIT(fd))
-
 /*
- * Returns non-zero if direction <dir> is already set for <fd>.
+ * speculative epoll() poller
  */
-REGPRM2 static int __fd_is_set(const int fd, int dir)
-{
-	return (fd_evts[FD2OFS(fd)] >> FD2BIT(fd)) & DIR2MSK(dir);
-}
-
-/*
- * Adds, mods or deletes <fd> according to current status and to new desired
- * mask <dmask> :
- *
- *    0 = nothing
- *    1 = EPOLLIN
- *    2 = EPOLLOUT
- *    3 = EPOLLIN | EPOLLOUT
- *
- */
-static int dmsk2event[4] = { 0, EPOLLIN, EPOLLOUT, EPOLLIN | EPOLLOUT };
-
-
-REGPRM2 static void fd_flush_changes()
+REGPRM2 static void _do_poll(struct poller *p, int exp)
 {
-	uint32_t ofs;
-	int opcode;
-	int prev, next;
-	int chg, fd;
+	int status, eo, en;
+	int fd, opcode;
+	int count;
+	int updt_idx;
+	int wait_time;
 
-	for (chg = 0; chg < nbchanges; chg++) {
-		prev = chg_list[chg].prev;
-		fd = chg_list[chg].fd;
-		chg_ptr[fd] = NULL;
+	/* first, scan the update list to find changes */
+	for (updt_idx = 0; updt_idx < fd_nbupdt; updt_idx++) {
+		fd = fd_updt[updt_idx];
+		en = fdtab[fd].spec_e & 15;  /* new events */
+		eo = fdtab[fd].spec_e >> 4;  /* previous events */
 
-		ofs = FD2OFS(fd);
-		next = (fd_evts[ofs] >> FD2BIT(fd)) & 3;
+		if (fdtab[fd].owner && (eo ^ en)) {
+			if ((eo ^ en) & FD_EV_POLLED_RW) {
+				/* poll status changed */
+				if ((en & FD_EV_POLLED_RW) == 0) {
+					/* fd removed from poll list */
+					opcode = EPOLL_CTL_DEL;
+				}
+				else if ((eo & FD_EV_POLLED_RW) == 0) {
+					/* new fd in the poll list */
+					opcode = EPOLL_CTL_ADD;
+				}
+				else {
+					/* fd status changed */
+					opcode = EPOLL_CTL_MOD;
+				}
 
-		if (prev == next)
-			/* if the value was unchanged, do nothing */
-			continue;
+				/* construct the epoll events based on new state */
+				ev.events = 0;
+				if (en & FD_EV_POLLED_R)
+					ev.events |= EPOLLIN;
 
-		ev.events = dmsk2event[next];
-		ev.data.fd = fd;
+				if (en & FD_EV_POLLED_W)
+					ev.events |= EPOLLOUT;
 
-		if (prev) {
-			if (!next) {
-				/* we want to delete it now */
-				opcode = EPOLL_CTL_DEL;
-			} else {
-				/* we want to switch it */
-				opcode = EPOLL_CTL_MOD;
+				ev.data.fd = fd;
+				epoll_ctl(epoll_fd, opcode, fd, &ev);
 			}
-		} else {
-			/* the FD did not exist, let's add it */
-			opcode = EPOLL_CTL_ADD;
-		}
-
-		epoll_ctl(epoll_fd, opcode, fd, &ev);
-	}
-	nbchanges = 0;
-}
-
-REGPRM2 static void alloc_chg_list(const int fd, int old_evt)
-{
-	struct fd_chg *ptr;
-
-	if (unlikely(chg_ptr[fd] != NULL))
-		return;
-
-#if LIMIT_NUMBER_OF_CHANGES
-	if (nbchanges > 2)
-		fd_flush_changes();
-#endif
-
-	ptr = &chg_list[nbchanges++];
-	chg_ptr[fd] = ptr;
-	ptr->fd = fd;
-	ptr->prev = old_evt;
-}
-
-REGPRM2 static void __fd_set(const int fd, int dir)
-{
-	uint32_t ofs = FD2OFS(fd);
-	uint32_t dmsk = DIR2MSK(dir);
-	uint32_t old_evt;
-
-	old_evt = fd_evts[ofs] >> FD2BIT(fd);
-	old_evt &= 3;
-	if (unlikely(old_evt & dmsk))
-		return;
-
-	alloc_chg_list(fd, old_evt);
-	dmsk <<= FD2BIT(fd);
-	fd_evts[ofs] |= dmsk;
-}
-
-REGPRM2 static void __fd_clr(const int fd, int dir)
-{
-	uint32_t ofs = FD2OFS(fd);
-	uint32_t dmsk = DIR2MSK(dir);
-	uint32_t old_evt;
-
-	old_evt = fd_evts[ofs] >> FD2BIT(fd);
-	old_evt &= 3;
-	if (unlikely(!(old_evt & dmsk)))
-		return;
-
-	alloc_chg_list(fd, old_evt);
-	dmsk <<= FD2BIT(fd);
-	fd_evts[ofs] &= ~dmsk;
-}
-
-REGPRM1 static void __fd_rem(int fd)
-{
-	uint32_t ofs = FD2OFS(fd);
-	uint32_t old_evt;
 
-	old_evt = fd_evts[ofs] >> FD2BIT(fd);
-	old_evt &= 3;
+			fdtab[fd].spec_e = (en << 4) + en;  /* save new events */
 
-	if (unlikely(!old_evt))
-		return;
-
-	alloc_chg_list(fd, old_evt);
-	fd_evts[ofs] &= ~FD2MSK(fd);
-}
+			if (!(en & FD_EV_ACTIVE_RW)) {
+				/* This fd doesn't use any active entry anymore, we can
+				 * kill its entry.
+				 */
+				release_spec_entry(fd);
+			}
+			else if ((en & ~eo) & FD_EV_ACTIVE_RW) {
+				/* we need a new spec entry now */
+				alloc_spec_entry(fd);
+			}
 
-/*
- * On valid epoll() implementations, a call to close() automatically removes
- * the fds. This means that the FD will appear as previously unset.
- */
-REGPRM1 static void __fd_clo(int fd)
-{
-	struct fd_chg *ptr;
-	fd_evts[FD2OFS(fd)] &= ~FD2MSK(fd);
-	ptr = chg_ptr[fd];
-	if (ptr) {
-		ptr->prev = 0;
-		chg_ptr[fd] = NULL;
+		}
+		fdtab[fd].updated = 0;
+		fdtab[fd].new = 0;
 	}
-}
-
-/*
- * epoll() poller
- */
-REGPRM2 static void _do_poll(struct poller *p, int exp)
-{
-	int status;
-	int fd;
-	int count;
-	int wait_time;
+	fd_nbupdt = 0;
 
-	if (likely(nbchanges))
-		fd_flush_changes();
+	/* compute the epoll_wait() timeout */
 
-	/* now let's wait for events */
-	if (run_queue || signal_queue_len)
-		wait_time = 0;
-	else if (!exp)
-		wait_time = MAX_DELAY_MS;
-	else if (tick_is_expired(exp, now_ms))
+	if (fd_nbspec || run_queue || signal_queue_len) {
+		/* Maybe we still have events in the spec list, or there are
+		 * some tasks left pending in the run_queue, so we must not
+		 * wait in epoll() otherwise we would delay their delivery by
+		 * the next timeout.
+		 */
 		wait_time = 0;
+	}
 	else {
-		wait_time = TICKS_TO_MS(tick_remain(now_ms, exp)) + 1;
-		if (wait_time > MAX_DELAY_MS)
+		if (!exp)
 			wait_time = MAX_DELAY_MS;
+		else if (tick_is_expired(exp, now_ms))
+			wait_time = 0;
+		else {
+			wait_time = TICKS_TO_MS(tick_remain(now_ms, exp)) + 1;
+			if (wait_time > MAX_DELAY_MS)
+				wait_time = MAX_DELAY_MS;
+		}
 	}
 
+	/* now let's wait for polled events */
+
 	fd = MIN(maxfd, global.tune.maxpollevents);
 	gettimeofday(&before_poll, NULL);
 	status = epoll_wait(epoll_fd, epoll_events, fd, wait_time);
 	tv_update_date(wait_time, status);
 	measure_idle();
 
+	/* process polled events */
+
 	for (count = 0; count < status; count++) {
 		int e = epoll_events[count].events;
 		fd = epoll_events[count].data.fd;
@@ -259,53 +154,84 @@
 			((e & EPOLLERR) ? FD_POLL_ERR : 0) |
 			((e & EPOLLHUP) ? FD_POLL_HUP : 0);
 
+		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev) {
+			int new_updt, old_updt = fd_nbupdt; /* Save number of updates to detect creation of new FDs. */
+
-		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev)
+			/* Mark the events as speculative before processing
+			 * them so that if nothing can be done we don't need
+			 * to poll again.
+			 */
+			if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
+				fd_ev_set(fd, DIR_RD);
+
+			if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR))
+				fd_ev_set(fd, DIR_WR);
+
 			fdtab[fd].iocb(fd);
+
+			/* One or more fd might have been created during the iocb().
+			 * This mainly happens with new incoming connections that have
+			 * just been accepted, so we'd like to process them immediately
+			 * for better efficiency. Second benefit, if at the end the fds
+			 * are disabled again, we can safely destroy their update entry
+			 * to reduce the scope of later scans. This is the reason we
+			 * scan the new entries backwards.
+			 */
+
+			for (new_updt = fd_nbupdt; new_updt > old_updt; new_updt--) {
+				fd = fd_updt[new_updt - 1];
+				if (!fdtab[fd].new)
+					continue;
+
+				fdtab[fd].new = 0;
+				fdtab[fd].ev &= FD_POLL_STICKY;
+
+				if ((fdtab[fd].spec_e & FD_EV_STATUS_R) == FD_EV_ACTIVE_R)
+					fdtab[fd].ev |= FD_POLL_IN;
+
+				if ((fdtab[fd].spec_e & FD_EV_STATUS_W) == FD_EV_ACTIVE_W)
+					fdtab[fd].ev |= FD_POLL_OUT;
+
+				if (fdtab[fd].ev && fdtab[fd].iocb && fdtab[fd].owner)
+					fdtab[fd].iocb(fd);
+
+				/* we can remove this update entry if it's the last one and is
+				 * unused, otherwise we don't touch anything.
+				 */
+				if (new_updt == fd_nbupdt && fdtab[fd].spec_e == 0) {
+					fdtab[fd].updated = 0;
+					fd_nbupdt--;
+				}
+			}
+		}
 	}
+
+	/* the caller will take care of speculative events */
 }
 
 /*
- * Initialization of the epoll() poller.
+ * Initialization of the speculative epoll() poller.
  * Returns 0 in case of failure, non-zero in case of success. If it fails, it
  * disables the poller by setting its pref to 0.
  */
 REGPRM1 static int _do_init(struct poller *p)
 {
-	__label__ fail_chg_ptr, fail_chg_list, fail_fdevt, fail_ee, fail_fd;
-	int fd_set_bytes;
-
 	p->private = NULL;
-	fd_set_bytes = 4 * (global.maxsock + 15) / 16;
 
 	epoll_fd = epoll_create(global.maxsock + 1);
 	if (epoll_fd < 0)
 		goto fail_fd;
 
+	/* See comments at the top of the file about this formula. */
+	absmaxevents = MAX(global.tune.maxpollevents, global.maxsock);
 	epoll_events = (struct epoll_event*)
-		calloc(1, sizeof(struct epoll_event) * global.tune.maxpollevents);
+		calloc(1, sizeof(struct epoll_event) * absmaxevents);
 
 	if (epoll_events == NULL)
 		goto fail_ee;
 
-	if ((fd_evts = (uint32_t *)calloc(1, fd_set_bytes)) == NULL)
-		goto fail_fdevt;
-
-	chg_list = (struct fd_chg *)calloc(1, sizeof(struct fd_chg) * global.maxsock);
-	if (chg_list == NULL)
-		goto fail_chg_list;
-
-	chg_ptr = (struct fd_chg **)calloc(1, sizeof(struct fd_chg*) * global.maxsock);
-	if (chg_ptr == NULL)
-		goto fail_chg_ptr;
-
 	return 1;
 
- fail_chg_ptr:
-	free(chg_list);
- fail_chg_list:
-	free(fd_evts);
- fail_fdevt:
-	free(epoll_events);
  fail_ee:
 	close(epoll_fd);
 	epoll_fd = -1;
@@ -315,16 +241,11 @@
 }
 
 /*
- * Termination of the epoll() poller.
+ * Termination of the speculative epoll() poller.
  * Memory is released and the poller is marked as unselectable.
  */
 REGPRM1 static void _do_term(struct poller *p)
 {
-	fd_flush_changes();
-
-	free(chg_ptr);
-	free(chg_list);
-	free(fd_evts);
 	free(epoll_events);
 
 	if (epoll_fd >= 0) {
@@ -332,11 +253,7 @@
 		epoll_fd = -1;
 	}
 
-	chg_ptr = NULL;
-	chg_list = NULL;
-	fd_evts = NULL;
 	epoll_events = NULL;
-
 	p->private = NULL;
 	p->pref = 0;
 }
@@ -398,12 +315,12 @@
 	p->poll = _do_poll;
 	p->fork = _do_fork;
 
-	p->is_set  = __fd_is_set;
-	p->set = __fd_set;
-	p->wai = __fd_set;
-	p->clr = __fd_clr;
-	p->rem = __fd_rem;
-	p->clo = __fd_clo;
+	p->is_set  = NULL;
+	p->set = NULL;
+	p->wai = NULL;
+	p->clr = NULL;
+	p->rem = NULL;
+	p->clo = NULL;
 }
 
 
diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c
deleted file mode 100644
index 71e4014..0000000
--- a/src/ev_sepoll.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * FD polling functions for Speculative I/O combined with Linux epoll()
- *
- * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
- *
- * 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
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <common/compat.h>
-#include <common/config.h>
-#include <common/debug.h>
-#include <common/epoll.h>
-#include <common/standard.h>
-#include <common/ticks.h>
-#include <common/time.h>
-#include <common/tools.h>
-
-#include <types/global.h>
-
-#include <proto/fd.h>
-#include <proto/signal.h>
-#include <proto/task.h>
-
-
-static int absmaxevents = 0;    // absolute maximum amounts of polled events
-
-/* private data */
-static struct epoll_event *epoll_events;
-static int epoll_fd;
-
-/* This structure may be used for any purpose. Warning! do not use it in
- * recursive functions !
- */
-static struct epoll_event ev;
-
-/*
- * speculative epoll() poller
- */
-REGPRM2 static void _do_poll(struct poller *p, int exp)
-{
-	int status, eo, en;
-	int fd, opcode;
-	int count;
-	int updt_idx;
-	int wait_time;
-
-	/* first, scan the update list to find changes */
-	for (updt_idx = 0; updt_idx < fd_nbupdt; updt_idx++) {
-		fd = fd_updt[updt_idx];
-		en = fdtab[fd].spec_e & 15;  /* new events */
-		eo = fdtab[fd].spec_e >> 4;  /* previous events */
-
-		if (fdtab[fd].owner && (eo ^ en)) {
-			if ((eo ^ en) & FD_EV_POLLED_RW) {
-				/* poll status changed */
-				if ((en & FD_EV_POLLED_RW) == 0) {
-					/* fd removed from poll list */
-					opcode = EPOLL_CTL_DEL;
-				}
-				else if ((eo & FD_EV_POLLED_RW) == 0) {
-					/* new fd in the poll list */
-					opcode = EPOLL_CTL_ADD;
-				}
-				else {
-					/* fd status changed */
-					opcode = EPOLL_CTL_MOD;
-				}
-
-				/* construct the epoll events based on new state */
-				ev.events = 0;
-				if (en & FD_EV_POLLED_R)
-					ev.events |= EPOLLIN;
-
-				if (en & FD_EV_POLLED_W)
-					ev.events |= EPOLLOUT;
-
-				ev.data.fd = fd;
-				epoll_ctl(epoll_fd, opcode, fd, &ev);
-			}
-
-			fdtab[fd].spec_e = (en << 4) + en;  /* save new events */
-
-			if (!(en & FD_EV_ACTIVE_RW)) {
-				/* This fd doesn't use any active entry anymore, we can
-				 * kill its entry.
-				 */
-				release_spec_entry(fd);
-			}
-			else if ((en & ~eo) & FD_EV_ACTIVE_RW) {
-				/* we need a new spec entry now */
-				alloc_spec_entry(fd);
-			}
-
-		}
-		fdtab[fd].updated = 0;
-		fdtab[fd].new = 0;
-	}
-	fd_nbupdt = 0;
-
-	/* compute the epoll_wait() timeout */
-
-	if (fd_nbspec || run_queue || signal_queue_len) {
-		/* Maybe we still have events in the spec list, or there are
-		 * some tasks left pending in the run_queue, so we must not
-		 * wait in epoll() otherwise we would delay their delivery by
-		 * the next timeout.
-		 */
-		wait_time = 0;
-	}
-	else {
-		if (!exp)
-			wait_time = MAX_DELAY_MS;
-		else if (tick_is_expired(exp, now_ms))
-			wait_time = 0;
-		else {
-			wait_time = TICKS_TO_MS(tick_remain(now_ms, exp)) + 1;
-			if (wait_time > MAX_DELAY_MS)
-				wait_time = MAX_DELAY_MS;
-		}
-	}
-
-	/* now let's wait for polled events */
-
-	fd = MIN(maxfd, global.tune.maxpollevents);
-	gettimeofday(&before_poll, NULL);
-	status = epoll_wait(epoll_fd, epoll_events, fd, wait_time);
-	tv_update_date(wait_time, status);
-	measure_idle();
-
-	/* process polled events */
-
-	for (count = 0; count < status; count++) {
-		int e = epoll_events[count].events;
-		fd = epoll_events[count].data.fd;
-
-		if (!fdtab[fd].owner)
-			continue;
-
-		/* it looks complicated but gcc can optimize it away when constants
-		 * have same values.
-		 */
-		fdtab[fd].ev &= FD_POLL_STICKY;
-		fdtab[fd].ev |=
-			((e & EPOLLIN ) ? FD_POLL_IN  : 0) |
-			((e & EPOLLPRI) ? FD_POLL_PRI : 0) |
-			((e & EPOLLOUT) ? FD_POLL_OUT : 0) |
-			((e & EPOLLERR) ? FD_POLL_ERR : 0) |
-			((e & EPOLLHUP) ? FD_POLL_HUP : 0);
-
-		if (fdtab[fd].iocb && fdtab[fd].owner && fdtab[fd].ev) {
-			int new_updt, old_updt = fd_nbupdt; /* Save number of updates to detect creation of new FDs. */
-
-			/* Mark the events as speculative before processing
-			 * them so that if nothing can be done we don't need
-			 * to poll again.
-			 */
-			if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
-				fd_ev_set(fd, DIR_RD);
-
-			if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR))
-				fd_ev_set(fd, DIR_WR);
-
-			fdtab[fd].iocb(fd);
-
-			/* One or more fd might have been created during the iocb().
-			 * This mainly happens with new incoming connections that have
-			 * just been accepted, so we'd like to process them immediately
-			 * for better efficiency. Second benefit, if at the end the fds
-			 * are disabled again, we can safely destroy their update entry
-			 * to reduce the scope of later scans. This is the reason we
-			 * scan the new entries backwards.
-			 */
-
-			for (new_updt = fd_nbupdt; new_updt > old_updt; new_updt--) {
-				fd = fd_updt[new_updt - 1];
-				if (!fdtab[fd].new)
-					continue;
-
-				fdtab[fd].new = 0;
-				fdtab[fd].ev &= FD_POLL_STICKY;
-
-				if ((fdtab[fd].spec_e & FD_EV_STATUS_R) == FD_EV_ACTIVE_R)
-					fdtab[fd].ev |= FD_POLL_IN;
-
-				if ((fdtab[fd].spec_e & FD_EV_STATUS_W) == FD_EV_ACTIVE_W)
-					fdtab[fd].ev |= FD_POLL_OUT;
-
-				if (fdtab[fd].ev && fdtab[fd].iocb && fdtab[fd].owner)
-					fdtab[fd].iocb(fd);
-
-				/* we can remove this update entry if it's the last one and is
-				 * unused, otherwise we don't touch anything.
-				 */
-				if (new_updt == fd_nbupdt && fdtab[fd].spec_e == 0) {
-					fdtab[fd].updated = 0;
-					fd_nbupdt--;
-				}
-			}
-		}
-	}
-
-	/* the caller will take care of speculative events */
-}
-
-/*
- * Initialization of the speculative epoll() poller.
- * Returns 0 in case of failure, non-zero in case of success. If it fails, it
- * disables the poller by setting its pref to 0.
- */
-REGPRM1 static int _do_init(struct poller *p)
-{
-	p->private = NULL;
-
-	epoll_fd = epoll_create(global.maxsock + 1);
-	if (epoll_fd < 0)
-		goto fail_fd;
-
-	/* See comments at the top of the file about this formula. */
-	absmaxevents = MAX(global.tune.maxpollevents, global.maxsock);
-	epoll_events = (struct epoll_event*)
-		calloc(1, sizeof(struct epoll_event) * absmaxevents);
-
-	if (epoll_events == NULL)
-		goto fail_ee;
-
-	return 1;
-
- fail_ee:
-	close(epoll_fd);
-	epoll_fd = -1;
- fail_fd:
-	p->pref = 0;
-	return 0;
-}
-
-/*
- * Termination of the speculative epoll() poller.
- * Memory is released and the poller is marked as unselectable.
- */
-REGPRM1 static void _do_term(struct poller *p)
-{
-	free(epoll_events);
-
-	if (epoll_fd >= 0) {
-		close(epoll_fd);
-		epoll_fd = -1;
-	}
-
-	epoll_events = NULL;
-	p->private = NULL;
-	p->pref = 0;
-}
-
-/*
- * Check that the poller works.
- * Returns 1 if OK, otherwise 0.
- */
-REGPRM1 static int _do_test(struct poller *p)
-{
-	int fd;
-
-	fd = epoll_create(global.maxsock + 1);
-	if (fd < 0)
-		return 0;
-	close(fd);
-	return 1;
-}
-
-/*
- * Recreate the epoll file descriptor after a fork(). Returns 1 if OK,
- * otherwise 0. It will ensure that all processes will not share their
- * epoll_fd. Some side effects were encountered because of this, such
- * as epoll_wait() returning an FD which was previously deleted.
- */
-REGPRM1 static int _do_fork(struct poller *p)
-{
-	if (epoll_fd >= 0)
-		close(epoll_fd);
-	epoll_fd = epoll_create(global.maxsock + 1);
-	if (epoll_fd < 0)
-		return 0;
-	return 1;
-}
-
-/*
- * It is a constructor, which means that it will automatically be called before
- * main(). This is GCC-specific but it works at least since 2.95.
- * Special care must be taken so that it does not need any uninitialized data.
- */
-__attribute__((constructor))
-static void _do_register(void)
-{
-	struct poller *p;
-
-	if (nbpollers >= MAX_POLLERS)
-		return;
-
-	epoll_fd = -1;
-	p = &pollers[nbpollers++];
-
-	p->name = "sepoll";
-	p->pref = 400;
-	p->private = NULL;
-
-	p->test = _do_test;
-	p->init = _do_init;
-	p->term = _do_term;
-	p->poll = _do_poll;
-	p->fork = _do_fork;
-
-	p->is_set  = NULL;
-	p->set = NULL;
-	p->wai = NULL;
-	p->clr = NULL;
-	p->rem = NULL;
-	p->clo = NULL;
-}
-
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- */
diff --git a/src/haproxy.c b/src/haproxy.c
index 1bb65c1..32db281 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -308,9 +308,6 @@
 #if defined(ENABLE_EPOLL)
 		"        -de disables epoll() usage even when available\n"
 #endif
-#if defined(ENABLE_SEPOLL)
-		"        -ds disables speculative epoll() usage even when available\n"
-#endif
 #if defined(ENABLE_KQUEUE)
 		"        -dk disables kqueue() usage even when available\n"
 #endif
@@ -476,9 +473,6 @@
 #if defined(ENABLE_EPOLL)
 	global.tune.options |= GTUNE_USE_EPOLL;
 #endif
-#if defined(ENABLE_SEPOLL)
-	global.tune.options |= GTUNE_USE_SEPOLL;
-#endif
 #if defined(ENABLE_KQUEUE)
 	global.tune.options |= GTUNE_USE_KQUEUE;
 #endif
@@ -512,10 +506,6 @@
 			else if (*flag == 'd' && flag[1] == 'e')
 				global.tune.options &= ~GTUNE_USE_EPOLL;
 #endif
-#if defined(ENABLE_SEPOLL)
-			else if (*flag == 'd' && flag[1] == 's')
-				global.tune.options &= ~GTUNE_USE_SEPOLL;
-#endif
 #if defined(ENABLE_POLL)
 			else if (*flag == 'd' && flag[1] == 'p')
 				global.tune.options &= ~GTUNE_USE_POLL;
@@ -792,9 +782,6 @@
 	if (!(global.tune.options & GTUNE_USE_EPOLL))
 		disable_poller("epoll");
 
-	if (!(global.tune.options & GTUNE_USE_SEPOLL))
-		disable_poller("sepoll");
-
 	if (!(global.tune.options & GTUNE_USE_POLL))
 		disable_poller("poll");