From: Andy Pan Date: Sun, 2 Jun 2024 06:40:42 +0000 (+0800) Subject: socket: use SOCK_NONBLOCK to eliminate extra system call X-Git-Tag: curl-8_9_0~305 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3392f0f97efdd854961df4756313e9af765a5e3f;p=thirdparty%2Fcurl.git socket: use SOCK_NONBLOCK to eliminate extra system call Every time function `cf_socket_open()` is called to create a socket, `curlx_nonblock()` is called to make that socket non-blocking. And `curlx_nonblock()` will cost us 1 or 2 system calls (2 for `fcntl()`, 1 for `ioctl()`, etc.), meanwhile, tucking `SOCK_NONBLOCK` and `SOCK_CLOEXEC` into the `type` argument for `socket()` is widely supported across UNIX-like OS: Linux, *BSD, Solaris, etc. With that ability, we can save 1 or 2 system calls on each socket. Another change in this PR is to eliminate the redundant `curlx_nonblock()` call on the socket in `cf_udp_setup_quic()` as that socket created by `cf_socket_open()` is already non-blocking. Ref: https://man7.org/linux/man-pages/man2/socket.2.html https://man.freebsd.org/cgi/man.cgi?socket(2) https://man.dragonflybsd.org/?command=socket§ion=2 https://man.netbsd.org/socket.2 https://man.openbsd.org/socket https://docs.oracle.com/cd/E88353_01/html/E37843/socket-3c.html https://illumos.org/man/3SOCKET/socket ... Closes #13855 --- diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 9ec4968743..22827d3753 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1016,7 +1016,20 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf, (void)data; DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD); ctx->started_at = Curl_now(); +#ifdef SOCK_NONBLOCK + /* Don't tuck SOCK_NONBLOCK into socktype when opensocket callback is set + * because we wouldn't know how socketype is about to be used in the + * callback, SOCK_NONBLOCK might get factored out before calling socket(). + */ + if(!data->set.fopensocket) + ctx->addr.socktype |= SOCK_NONBLOCK; +#endif result = socket_open(data, &ctx->addr, &ctx->sock); +#ifdef SOCK_NONBLOCK + /* Restore the socktype after the socket is created. */ + if(!data->set.fopensocket) + ctx->addr.socktype &= ~SOCK_NONBLOCK; +#endif if(result) goto out; @@ -1087,8 +1100,14 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf, } #endif +#ifndef SOCK_NONBLOCK /* set socket non-blocking */ (void)curlx_nonblock(ctx->sock, TRUE); +#else + if(data->set.fopensocket) + /* set socket non-blocking */ + (void)curlx_nonblock(ctx->sock, TRUE); +#endif ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM); out: if(result) { @@ -1681,7 +1700,7 @@ out: } static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_socket_ctx *ctx = cf->ctx; int rc; @@ -1707,7 +1726,11 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf, ctx->sock, ctx->ip.local_ip, ctx->ip.local_port, ctx->ip.remote_ip, ctx->ip.remote_port); - (void)curlx_nonblock(ctx->sock, TRUE); + /* Currently, cf->ctx->sock is always non-blocking because the only + * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the + * non-blocking socket created by cf_socket_open() to it. Thus, we + * don't need to call curlx_nonblock() in cf_udp_setup_quic() anymore. + */ switch(ctx->addr.family) { #if defined(__linux__) && defined(IP_MTU_DISCOVER) case AF_INET: {