AZ(sp->obj);
AZ(sp->vcl);
assert(sp->fd >= 0);
+ /*
+ * Set nonblocking in the worker-thread, before passing to the
+ * acceptor thread, to reduce syscall density of the latter.
+ */
+ TCP_nonblocking(sp->fd);
if (vca_act->pass == NULL)
assert(sizeof sp == write(vca_pipes[1], &sp, sizeof sp));
else
w = sp->wrk;
CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
+ /*
+ * Whenever we come in from the acceptor we need to set blocking
+ * mode, but there is no point in setting it when we come from
+ * ESI or when a parked sessions returns.
+ * It would be simpler to do this in the acceptor, but we'd rather
+ * do the syscall in the worker thread.
+ */
+ if (sp->step == STP_FIRST || sp->step == STP_START)
+ TCP_blocking(sp->fd);
+
for (done = 0; !done; ) {
assert(sp->wrk == w);
/*
free(ls);
continue;
}
+ /*
+ * Set nonblocking mode to avoid a race where a client
+ * closes before we call accept(2) and nobody else are in
+ * the listen queue to release us.
+ */
+ TCP_nonblocking(ls->sock);
TCP_filter_http(ls->sock);
good++;
}
#include <netinet/in.h>
#include <errno.h>
-#include <fcntl.h>
+#include <sys/ioctl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#endif
}
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * Functions for controlling NONBLOCK mode.
+ *
+ * We use FIONBIO because it is cheaper than fcntl(2), which requires
+ * us to do two syscalls, one to get and one to set, the latter of
+ * which mucks about a bit before it ends up calling ioctl(FIONBIO),
+ * at least on FreeBSD.
+ */
void
TCP_blocking(int sock)
{
int i;
- i = fcntl(sock, F_GETFL);
- assert(i != -1);
- i &= ~O_NONBLOCK;
- i = fcntl(sock, F_SETFL, i);
- assert(i != -1);
+ i = 0;
+ AZ(ioctl(sock, FIONBIO, &i));
}
void
{
int i;
- i = fcntl(sock, F_GETFL);
- assert(i != -1);
- i |= O_NONBLOCK;
- i = fcntl(sock, F_SETFL, i);
- assert(i != -1);
+ i = 1;
+ AZ(ioctl(sock, FIONBIO, &i));
}