MEDIUM: fd: add fd_poll_{recv,send} for use when explicit polling is required

The old EV_FD_SET() macro was confusing, as it would enable receipt but there
was no way to indicate that EAGAIN was received, hence the recently added
FD_WAIT_* flags. They're not enough as we're still facing a conflict between
EV_FD_* and FD_WAIT_*. So let's offer I/O functions what they need to explicitly
request polling.
diff --git a/include/proto/fd.h b/include/proto/fd.h
index 072d3f6..bfce120 100644
--- a/include/proto/fd.h
+++ b/include/proto/fd.h
@@ -83,6 +83,11 @@
 	cur_poller.clr(fd, DIR_RD);
 }
 
+static inline void fd_poll_recv(int fd)
+{
+	cur_poller.wai(fd, DIR_RD);
+}
+
 static inline void fd_want_send(int fd)
 {
 	cur_poller.set(fd, DIR_WR);
@@ -93,6 +98,11 @@
 	cur_poller.clr(fd, DIR_WR);
 }
 
+static inline void fd_poll_send(int fd)
+{
+	cur_poller.wai(fd, DIR_WR);
+}
+
 static inline void fd_stop_both(int fd)
 {
 	cur_poller.rem(fd);
diff --git a/include/types/fd.h b/include/types/fd.h
index 2e350b8..c6e47f2 100644
--- a/include/types/fd.h
+++ b/include/types/fd.h
@@ -100,6 +100,7 @@
 	int  REGPRM2 (*is_set)(const int fd, int dir);       /* check if <fd> is being polled for dir <dir> */
 	void REGPRM2    (*set)(const int fd, int dir);       /* set   polling on <fd> for <dir> */
 	void REGPRM2    (*clr)(const int fd, int dir);       /* clear polling on <fd> for <dir> */
+	void REGPRM2    (*wai)(const int fd, int dir);       /* wait for polling on <fd> for <dir> */
 	void REGPRM1    (*rem)(const int fd);                /* remove any polling on <fd> */
 	void REGPRM1    (*clo)(const int fd);                /* mark <fd> as closed */
     	void REGPRM2   (*poll)(struct poller *p, int exp);   /* the poller itself */
diff --git a/src/ev_epoll.c b/src/ev_epoll.c
index 6c8408b..a566917 100644
--- a/src/ev_epoll.c
+++ b/src/ev_epoll.c
@@ -396,6 +396,7 @@
 
 	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;
diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
index 4bfbf1b..e771c33 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -274,6 +274,7 @@
 
 	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;
diff --git a/src/ev_poll.c b/src/ev_poll.c
index f72dfe2..b05fec1 100644
--- a/src/ev_poll.c
+++ b/src/ev_poll.c
@@ -230,6 +230,7 @@
 	p->poll = _do_poll;
 	p->is_set = __fd_is_set;
 	p->set = __fd_set;
+	p->wai = __fd_set;
 	p->clr = __fd_clr;
 	p->clo = p->rem = __fd_rem;
 }
diff --git a/src/ev_select.c b/src/ev_select.c
index cf45262..100bc57 100644
--- a/src/ev_select.c
+++ b/src/ev_select.c
@@ -227,6 +227,7 @@
 	p->poll = _do_poll;
 	p->is_set = __fd_is_set;
 	p->set = __fd_set;
+	p->wai = __fd_set;
 	p->clr = __fd_clr;
 	p->clo = p->rem = __fd_rem;
 }
diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c
index 62ee115..506ab31 100644
--- a/src/ev_sepoll.c
+++ b/src/ev_sepoll.c
@@ -215,6 +215,26 @@
  * Don't worry about the strange constructs in __fd_set/__fd_clr, they are
  * designed like this in order to reduce the number of jumps (verified).
  */
+REGPRM2 static void __fd_wai(const int fd, int dir)
+{
+	unsigned int i;
+
+#if DEBUG_DEV
+	if (!fdtab[fd].owner) {
+		fprintf(stderr, "sepoll.fd_wai called on closed fd #%d.\n", fd);
+		ABORT_NOW();
+	}
+#endif
+	i = ((unsigned)fdtab[fd].spec.e >> dir) & FD_EV_MASK_DIR;
+
+	if (!(i & FD_EV_IN_SL)) {
+		if (i == FD_EV_WAIT)
+			return; /* already in desired state */
+		alloc_spec_entry(fd); /* need a spec entry */
+	}
+	fdtab[fd].spec.e ^= (i ^ (unsigned int)FD_EV_IN_PL) << dir;
+}
+
 REGPRM2 static void __fd_set(const int fd, int dir)
 {
 	unsigned int i;
@@ -592,6 +612,7 @@
 
 	p->is_set  = __fd_is_set;
 	p->set = __fd_set;
+	p->wai = __fd_wai;
 	p->clr = __fd_clr;
 	p->rem = __fd_rem;
 	p->clo = __fd_clo;