Improve performance of accepting incoming connections.

- Removes the accept() loop, as that doesn't measurably improve performance in practice. This also gives each connection the possibility to perform initial I/O before more concurrency is generated by accepting the next connection.

- Uses SOCK_NONBLOCK in conjunction with socket() and accept4() to save one additional syscall per connection.
This commit is contained in:
Sönke Ludwig 2017-09-02 15:40:07 +02:00
parent fc5df2f949
commit 07baa0f612
No known key found for this signature in database
GPG key ID: D95E8DB493EE314C

View file

@ -21,6 +21,11 @@ version (Posix) {
version (linux) enum SO_REUSEPORT = 15; version (linux) enum SO_REUSEPORT = 15;
else enum SO_REUSEPORT = 0x200; else enum SO_REUSEPORT = 0x200;
} }
version (linux) {
extern (C) int accept4(int sockfd, sockaddr *addr, socklen_t *addrlen, int flags) nothrow @nogc;
static if (!is(typeof(SOCK_NONBLOCK)))
enum SOCK_NONBLOCK = 0x800;
}
version (Windows) { version (Windows) {
import core.sys.windows.windows; import core.sys.windows.windows;
import core.sys.windows.winsock2; import core.sys.windows.winsock2;
@ -180,14 +185,17 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
private void onAccept(FD listenfd) private void onAccept(FD listenfd)
{ {
foreach (i; 0 .. 20) {
sock_t sockfd; sock_t sockfd;
sockaddr_storage addr; sockaddr_storage addr;
socklen_t addr_len = addr.sizeof; socklen_t addr_len = addr.sizeof;
version (linux) {
() @trusted { sockfd = accept4(cast(sock_t)listenfd, () @trusted { return cast(sockaddr*)&addr; } (), &addr_len, SOCK_NONBLOCK); } ();
if (sockfd == -1) return;
} else {
() @trusted { sockfd = accept(cast(sock_t)listenfd, () @trusted { return cast(sockaddr*)&addr; } (), &addr_len); } (); () @trusted { sockfd = accept(cast(sock_t)listenfd, () @trusted { return cast(sockaddr*)&addr; } (), &addr_len); } ();
if (sockfd == -1) break; if (sockfd == -1) return;
setSocketNonBlocking(cast(SocketFD)sockfd); setSocketNonBlocking(cast(SocketFD)sockfd);
}
auto fd = cast(StreamSocketFD)sockfd; auto fd = cast(StreamSocketFD)sockfd;
m_loop.initFD(fd, FDFlags.none); m_loop.initFD(fd, FDFlags.none);
m_loop.m_fds[fd].specific = StreamSocketSlot.init; m_loop.m_fds[fd].specific = StreamSocketSlot.init;
@ -199,7 +207,6 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
scope RefAddress addrc = new RefAddress(() @trusted { return cast(sockaddr*)&addr; } (), addr_len); scope RefAddress addrc = new RefAddress(() @trusted { return cast(sockaddr*)&addr; } (), addr_len);
m_loop.m_fds[listenfd].streamListen.acceptCallback(cast(StreamListenSocketFD)listenfd, fd, addrc); m_loop.m_fds[listenfd].streamListen.acceptCallback(cast(StreamListenSocketFD)listenfd, fd, addrc);
} }
}
ConnectionState getConnectionState(StreamSocketFD sock) ConnectionState getConnectionState(StreamSocketFD sock)
{ {
@ -737,9 +744,14 @@ final class PosixEventDriverSockets(Loop : PosixEventLoop) : EventDriverSockets
private sock_t createSocket(AddressFamily family, int type) private sock_t createSocket(AddressFamily family, int type)
{ {
sock_t sock; sock_t sock;
version (linux) {
() @trusted { sock = socket(family, type | SOCK_NONBLOCK, 0); } ();
if (sock == -1) return -1;
} else {
() @trusted { sock = socket(family, type, 0); } (); () @trusted { sock = socket(family, type, 0); } ();
if (sock == -1) return -1; if (sock == -1) return -1;
setSocketNonBlocking(cast(SocketFD)sock); setSocketNonBlocking(cast(SocketFD)sock);
}
return sock; return sock;
} }
} }