#define EV_FD_CLO(fd) (cur_poller.clo(fd))
-/* recomputes the maxfd limit from the fd */
+/* Prepares <fd> for being polled */
static inline void fd_insert(int fd)
{
+ fdtab[fd].ev = 0;
if (fd + 1 > maxfd)
maxfd = fd + 1;
}
DIR_SIZE
};
-
+/*
+ * FD_POLL_IN remains set as long as some data is pending for read.
+ * FD_POLL_OUT remains set as long as the fd accepts to write data.
+ * FD_POLL_ERR and FD_POLL_ERR remain set forever (until processed).
+ */
#define FD_POLL_IN 0x01
#define FD_POLL_PRI 0x02
#define FD_POLL_OUT 0x04
#define FD_POLL_ERR 0x08
#define FD_POLL_HUP 0x10
-#define FD_POLL_ANY 0x1F
-#define FD_POLL_RD (FD_POLL_IN | FD_POLL_ERR | FD_POLL_HUP)
-#define FD_POLL_WR (FD_POLL_OUT | FD_POLL_ERR | FD_POLL_HUP)
+#define FD_POLL_DATA (FD_POLL_IN | FD_POLL_OUT)
+#define FD_POLL_STICKY (FD_POLL_ERR | FD_POLL_HUP)
/* info about one given fd */
struct fdtab {
task_wakeup(t);
out_nowake:
EV_FD_CLR(fd, DIR_WR); /* nothing more to write */
- fdtab[fd].ev &= ~FD_POLL_WR;
+ fdtab[fd].ev &= ~FD_POLL_OUT;
return 1;
out_poll:
/* The connection is still pending. We'll have to poll it
* before attempting to go further. */
- fdtab[fd].ev &= ~FD_POLL_WR;
+ fdtab[fd].ev &= ~FD_POLL_OUT;
return 0;
out_error:
s->result |= SRV_CHK_ERROR;
#endif
if (unlikely(len < 0 && errno == EAGAIN)) {
/* we want some polling to happen first */
- fdtab[fd].ev &= ~FD_POLL_RD;
+ fdtab[fd].ev &= ~FD_POLL_IN;
return 0;
}
EV_FD_CLR(fd, DIR_RD);
task_wakeup(t);
- fdtab[fd].ev &= ~FD_POLL_RD;
+ fdtab[fd].ev &= ~FD_POLL_IN;
return 1;
}
fdtab[fd].peeraddr = (struct sockaddr *)&sa;
fdtab[fd].peerlen = sizeof(sa);
fdtab[fd].state = FD_STCONN; /* connection in progress */
- fdtab[fd].ev = 0;
EV_FD_SET(fd, DIR_WR); /* for connect status */
#ifdef DEBUG_FULL
assert (!EV_FD_ISSET(fd, DIR_RD));
fdtab[cfd].cb[DIR_WR].b = s->rep;
fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
fdtab[cfd].peerlen = sizeof(s->cli_addr);
- fdtab[cfd].ev = 0;
if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
(p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK))) {
#include <common/compat.h>
#include <common/config.h>
+#include <common/debug.h>
#include <common/standard.h>
#include <common/time.h>
#include <common/tools.h>
* the WAIT status.
*/
- fdtab[fd].ev = 0;
+ fdtab[fd].ev &= FD_POLL_STICKY;
if ((eo & FD_EV_MASK_R) == FD_EV_SPEC_R) {
/* The owner is interested in reading from this FD */
if (fdtab[fd].state != FD_STCLOSE && fdtab[fd].state != FD_STERROR) {
/* it looks complicated but gcc can optimize it away when constants
* have same values.
*/
- fdtab[fd].ev =
+ DPRINTF(stderr, "%s:%d: fd=%d, ev=0x%08x, e=0x%08x\n",
+ __FUNCTION__, __LINE__,
+ fd, fdtab[fd].ev, e);
+
+ 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) |
if ((fd_list[fd].e & FD_EV_MASK_R) == FD_EV_WAIT_R) {
if (fdtab[fd].state == FD_STCLOSE || fdtab[fd].state == FD_STERROR)
continue;
- if (fdtab[fd].ev & (FD_POLL_RD|FD_POLL_HUP|FD_POLL_ERR))
+ if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
fdtab[fd].cb[DIR_RD].f(fd);
}
if ((fd_list[fd].e & FD_EV_MASK_W) == FD_EV_WAIT_W) {
if (fdtab[fd].state == FD_STCLOSE || fdtab[fd].state == FD_STERROR)
continue;
- if (fdtab[fd].ev & (FD_POLL_WR|FD_POLL_ERR))
+ if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR))
fdtab[fd].cb[DIR_WR].f(fd);
}
}
fdtab[fd].peeraddr = NULL;
fdtab[fd].peerlen = 0;
fdtab[fd].listener = NULL;
- fdtab[fd].ev = 0;
tcp_return:
if (msg && errlen)
strlcpy2(errmsg, msg, errlen);
fdtab[fd].peeraddr = NULL;
fdtab[fd].peerlen = 0;
fdtab[fd].listener = NULL;
- fdtab[fd].ev = 0;
return ERR_NONE;
}
fdtab[cfd].cb[DIR_WR].b = s->rep;
fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
fdtab[cfd].peerlen = sizeof(s->cli_addr);
- fdtab[cfd].ev = 0;
-
tv_eternity(&s->req->rex);
tv_eternity(&s->req->wex);
#include <common/compat.h>
#include <common/config.h>
+#include <common/debug.h>
#include <common/standard.h>
#include <common/time.h>
* otherwise.
*/
int stream_sock_read(int fd) {
- __label__ out_eternity, out_wakeup, out_error;
+ __label__ out_eternity, out_wakeup, out_shutdown_r, out_error;
struct buffer *b = fdtab[fd].cb[DIR_RD].b;
int ret, max, retval;
int read_poll = MAX_READ_POLL_LOOPS;
#ifdef DEBUG_FULL
- fprintf(stderr,"stream_sock_read : fd=%d, owner=%p\n", fd, fdtab[fd].owner);
+ fprintf(stderr,"stream_sock_read : fd=%d, ev=0x%02x, owner=%p\n", fd, fdtab[fd].ev, fdtab[fd].owner);
#endif
retval = 1;
- if (unlikely(fdtab[fd].ev & FD_POLL_HUP)) {
- /* connection closed */
- b->flags |= BF_READ_NULL;
- goto out_eternity;
- }
- else if (unlikely(fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR))) {
+ /* stop immediately on errors */
+ if (fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR))
goto out_error;
- }
+
+ /* stop here if we reached the end of data */
+ if ((fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP)) == FD_POLL_HUP)
+ goto out_shutdown_r;
while (1) {
/*
/* if too many bytes were missing from last read, it means that
* it's pointless trying to read again because the system does
- * not have them in buffers.
+ * not have them in buffers. BTW, if FD_POLL_HUP was present,
+ * it means that we have reached the end and that the connection
+ * is closed.
*/
- if (ret < max)
+ if (ret < max) {
+ if (fdtab[fd].ev & FD_POLL_HUP)
+ goto out_shutdown_r;
break;
+ }
/* generally if we read something smaller than 1 or 2 MSS,
* it means that it's not worth trying to read again. It may
}
else if (ret == 0) {
/* connection closed */
- b->flags |= BF_READ_NULL;
- goto out_eternity;
+ goto out_shutdown_r;
}
else if (errno == EAGAIN) {
/* Ignore EAGAIN but inform the poller that there is
out_wakeup:
if (b->flags & BF_READ_STATUS)
task_wakeup(fdtab[fd].owner);
- fdtab[fd].ev &= ~FD_POLL_RD;
+ fdtab[fd].ev &= ~FD_POLL_IN;
return retval;
+ out_shutdown_r:
+ fdtab[fd].ev &= ~FD_POLL_HUP;
+ b->flags |= BF_READ_NULL;
+ goto out_eternity;
+
out_error:
/* There was an error. we must wakeup the task. No need to clear
* the events, the task will do it.
*/
fdtab[fd].state = FD_STERROR;
+ fdtab[fd].ev &= ~FD_POLL_STICKY;
b->flags |= BF_READ_ERROR;
goto out_eternity;
}
#endif
retval = 1;
- if (unlikely(fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR)))
+ if (fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR))
goto out_error;
while (1) {
out_wakeup:
if (b->flags & BF_WRITE_STATUS)
task_wakeup(fdtab[fd].owner);
- fdtab[fd].ev &= ~FD_POLL_WR;
+ fdtab[fd].ev &= ~FD_POLL_OUT;
return retval;
out_error:
* the events, the task will do it.
*/
fdtab[fd].state = FD_STERROR;
+ fdtab[fd].ev &= ~FD_POLL_STICKY;
b->flags |= BF_WRITE_ERROR;
goto out_eternity;