Make fd management more robust and easier to debug. Also some micro-optimisations.
diff --git a/haproxy.c b/haproxy.c
index cc83f93..bad84a0 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -1974,6 +1974,12 @@
fdtab[fd].state = FD_STCONN; /* connection in progress */
FD_SET(fd, StaticWriteEvent); /* for connect status */
+#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
+ if (PrevReadEvent) {
+ assert(!(FD_ISSET(fd, PrevReadEvent)));
+ assert(!(FD_ISSET(fd, PrevWriteEvent)));
+ }
+#endif
fd_insert(fd);
@@ -2875,14 +2881,17 @@
int event_srv_chk_w(int fd) {
struct task *t = fdtab[fd].owner;
struct server *s = t->context;
-
int skerr;
socklen_t lskerr = sizeof(skerr);
- getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
- /* in case of TCP only, this tells us if the connection succeeded */
- if (skerr)
+ skerr = 1;
+ if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
+ || (skerr != 0)) {
+ /* in case of TCP only, this tells us if the connection failed */
s->result = -1;
+ fdtab[fd].state = FD_STERROR;
+ FD_CLR(fd, StaticWriteEvent);
+ }
else if (s->result != -1) {
/* we don't want to mark 'UP' a server on which we detected an error earlier */
if (s->proxy->options & PR_O_HTTP_CHK) {
@@ -2900,8 +2909,10 @@
FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
return 0;
}
- else
+ else {
s->result = -1;
+ FD_CLR(fd, StaticWriteEvent);
+ }
}
else {
/* good TCP connection is enough */
@@ -2924,28 +2935,31 @@
int len, result;
struct task *t = fdtab[fd].owner;
struct server *s = t->context;
+ int skerr;
+ socklen_t lskerr = sizeof(skerr);
result = len = -1;
-#ifndef MSG_NOSIGNAL
- {
- int skerr;
- socklen_t lskerr = sizeof(skerr);
- getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
- if (!skerr)
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
+ if (!skerr) {
+#ifndef MSG_NOSIGNAL
len = recv(fd, reply, sizeof(reply), 0);
- }
#else
- /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
- * but the connection was closed on the remote end. Fortunately, recv still
- * works correctly and we don't need to do the getsockopt() on linux.
- */
- len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
+ /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
+ * but the connection was closed on the remote end. Fortunately, recv still
+ * works correctly and we don't need to do the getsockopt() on linux.
+ */
+ len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
#endif
- if ((len >= sizeof("HTTP/1.0 000")) &&
- !memcmp(reply, "HTTP/1.", 7) &&
- (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
- result = 1;
+
+ if ((len >= sizeof("HTTP/1.0 000")) &&
+ !memcmp(reply, "HTTP/1.", 7) &&
+ (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
+ result = 1;
+ }
+
+ if (result == -1)
+ fdtab[fd].state = FD_STERROR;
if (s->result != -1)
s->result = result;
@@ -5106,6 +5120,9 @@
fdtab[fd].write = &event_srv_chk_w;
fdtab[fd].state = FD_STCONN; /* connection in progress */
FD_SET(fd, StaticWriteEvent); /* for connect status */
+#ifdef DEBUG_FULL
+ assert (!FD_ISSET(fd, StaticReadEvent));
+#endif
fd_insert(fd);
/* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
tv_delayfrom(&t->expire, &now, s->inter);
@@ -5426,21 +5443,19 @@
for (count = 0; count < status; count++) {
fd = epoll_events[count].data.fd;
-
- if (fdtab[fd].state == FD_STCLOSE)
- continue;
-
- if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP )) {
- if (FD_ISSET(fd, StaticReadEvent))
- fdtab[fd].read(fd);
+
+ if (FD_ISSET(fd, StaticReadEvent)) {
+ if (fdtab[fd].state == FD_STCLOSE)
+ continue;
+ if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
+ fdtab[fd].read(fd);
}
-
- if (fdtab[fd].state == FD_STCLOSE)
- continue;
-
- if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP )) {
- if (FD_ISSET(fd, StaticWriteEvent))
- fdtab[fd].write(fd);
+
+ if (FD_ISSET(fd, StaticWriteEvent)) {
+ if (fdtab[fd].state == FD_STCLOSE)
+ continue;
+ if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
+ fdtab[fd].write(fd);
}
}
}
@@ -5552,20 +5567,18 @@
/* ok, we found one active fd */
status--;
- if (fdtab[fd].state == FD_STCLOSE)
- continue;
-
- if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP )) {
- if (FD_ISSET(fd, StaticReadEvent))
- fdtab[fd].read(fd);
+ if (FD_ISSET(fd, StaticReadEvent)) {
+ if (fdtab[fd].state == FD_STCLOSE)
+ continue;
+ if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
+ fdtab[fd].read(fd);
}
- if (fdtab[fd].state == FD_STCLOSE)
- continue;
-
- if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP )) {
- if (FD_ISSET(fd, StaticWriteEvent))
- fdtab[fd].write(fd);
+ if (FD_ISSET(fd, StaticWriteEvent)) {
+ if (fdtab[fd].state == FD_STCLOSE)
+ continue;
+ if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
+ fdtab[fd].write(fd);
}
}
}
@@ -5681,14 +5694,17 @@
/* if we specify read first, the accepts and zero reads will be
* seen first. Moreover, system buffers will be flushed faster.
*/
- if (fdtab[fd].state == FD_STCLOSE)
- continue;
-
- if (FD_ISSET(fd, ReadEvent))
- fdtab[fd].read(fd);
+ if (FD_ISSET(fd, ReadEvent)) {
+ if (fdtab[fd].state == FD_STCLOSE)
+ continue;
+ fdtab[fd].read(fd);
+ }
- if (FD_ISSET(fd, WriteEvent))
- fdtab[fd].write(fd);
+ if (FD_ISSET(fd, WriteEvent)) {
+ if (fdtab[fd].state == FD_STCLOSE)
+ continue;
+ fdtab[fd].write(fd);
+ }
}
}
else {