Accept4 should be used in nginx( linux platform)

Hi igor.

The accept4() system call is available starting with Linux 2.6.28;
support
in glibc is available starting with version 2.10. It can transport the
O_NONBLOCK flags in accept, and in nginx( in linux) after accept fd,
call fcntl(twice) set fd to O_NONBLOCK.

And so if use accept4, this will be to save twice systemcall,
therefore i suggest
nginx(in linux platform) should use accept4.

void
ngx_event_accept(ngx_event_t ev)
{

/
replace by s = accept4(lc->fd, (struct sockaddr *) sa, &socklen,
O_NONBLOCK); */
s = accept(lc->fd, (struct sockaddr *) sa, &socklen);

if (!(ngx_event_flags &
(NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
//if use accept4,this will removed.
if (ngx_nonblocking(s) == -1) {
ngx_log_error(NGX_LOG_ALERT, ev->log,
ngx_socket_errno,
ngx_nonblocking_n " failed");
ngx_close_accepted_connection(c);
return;
}
}

thanks!


博观约取

豆瓣:www.douban.com/people/mustang/

blog: www.pagefault.info

twitter: www.twitter.com/minibobo

Hello!

On Sun, Nov 07, 2010 at 10:30:41PM +0800, BoBo wrote:

The accept4() system call is available starting with Linux 2.6.28; support
in glibc is available starting with version 2.10. It can transport the
O_NONBLOCK flags in accept, and in nginx( in linux) after accept fd,
call fcntl(twice) set fd to O_NONBLOCK.

And so if use accept4, this will be to save twice systemcall,
therefore i suggest
nginx(in linux platform) should use accept4.

Yes, this make sense for Linux as it has no inheritance for
O_NONBLOCK from listening socket. Care to provide patch?

Just random implementation thoughs: probably emulating
NGX_HAVE_INHERITED_NONBLOCK via accept4() is a right way to go.

Maxim D.

this patch suit for nginx-0.8.53, and i test in my arch linux. Thanks.

diff -Naur nginx-0.8.53/auto/os/features
nginx-0.8.53_accpet4/auto/os/features
— nginx-0.8.53/auto/os/features 2010-07-05 21:49:16.000000000 +0800
+++ nginx-0.8.53_accpet4/auto/os/features 2010-11-08 00:20:28.126666705
+0800
@@ -352,3 +352,12 @@
fi
fi
fi
+
+ngx_feature=“accept4()”
+ngx_feature_name=“NGX_HAVE_ACCEPT4”
+ngx_feature_run=no
+ngx_feature_incs=“#include <sys/socket.h>”
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test=“accept4(0, NULL, NULL, SOCK_NONBLOCK)”
+. auto/feature
diff -Naur nginx-0.8.53/src/event/ngx_event_accept.c
nginx-0.8.53_accpet4/src/event/ngx_event_accept.c
— nginx-0.8.53/src/event/ngx_event_accept.c 2009-11-02
03:29:49.000000000
+0800
+++ nginx-0.8.53_accpet4/src/event/ngx_event_accept.c 2010-11-08
00:27:21.630000043 +0800
@@ -45,8 +45,12 @@

 do {
     socklen = NGX_SOCKADDRLEN;

+#if (NGX_HAVE_ACCEPT4)

  •    s = accept4(lc->fd, (struct sockaddr *) sa, &socklen,
    

SOCK_NONBLOCK);
+#else
s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
+#endif

     if (s == -1) {
         err = ngx_socket_errno;

@@ -115,9 +119,9 @@
ngx_close_accepted_connection(c);
return;
}

+#ifndef NGX_HAVE_ACCEPT4
/* set a blocking mode for aio and non-blocking mode for others
*/

     if (ngx_inherited_nonblocking) {
         if (ngx_event_flags & NGX_USE_AIO_EVENT) {
             if (ngx_blocking(s) == -1) {

@@ -138,7 +142,8 @@
}
}
}

+#endif
+
*log = ls->log;

     c->recv = ngx_recv;

On Sun, Nov 7, 2010 at 11:12 PM, Maxim D. [email protected]
wrote:

And so if use accept4, this will be to save twice systemcall,


nginx mailing list
[email protected]
nginx Info Page


博观约取

豆瓣:www.douban.com/people/mustang/

blog: www.pagefault.info

twitter: www.twitter.com/minibobo

thank you!

On Mon, Nov 8, 2010 at 1:34 AM, Maxim D. [email protected] wrote:

+0800
+ngx_feature_libs=
+ngx_feature_test=“accept4(0, NULL, NULL, SOCK_NONBLOCK)”
+. auto/feature

What happens when host has new glibc but old kernel? I assume
this test would succeed, but accept4() call will fail with ENOSYS.

Another question to consider is what to do with packages built on
host with accept4() but used on hosts without. Probably some
runtime fallback to usual accept() is needed.

thank you,I will test this situation.

     socklen = NGX_SOCKADDRLEN;
         err = ngx_socket_errno;

@@ -115,9 +119,9 @@
ngx_close_accepted_connection(c);
return;
}

Stray -/+ probably indicate some unrelated whitespace changes
(though patch seems to be corrupted by MUA anyway).

this is my mistake.

     }

+#endif

This part is wrong: with socket AIO sockets should be set to
blocking mode. The same code path as with
ngx_inherited_nonblocking should be followed.

in linux platform , NGX_HAVE_INHERITED_NONBLOCK is 0, and in
ngx_os_init:

#if (NGX_HAVE_INHERITED_NONBLOCK)
ngx_inherited_nonblocking = 1;
#else
ngx_inherited_nonblocking = 0;
#endif


博观约取

豆瓣:www.douban.com/people/mustang/

blog: www.pagefault.info

twitter: www.twitter.com/minibobo

Hello!

On Mon, Nov 08, 2010 at 12:33:04AM +0800, BoBo wrote:

fi
+
+ngx_feature=“accept4()”
+ngx_feature_name=“NGX_HAVE_ACCEPT4”
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test=“accept4(0, NULL, NULL, SOCK_NONBLOCK)”
+. auto/feature

What happens when host has new glibc but old kernel? I assume
this test would succeed, but accept4() call will fail with ENOSYS.

Another question to consider is what to do with packages built on
host with accept4() but used on hosts without. Probably some
runtime fallback to usual accept() is needed.

@@ -115,9 +119,9 @@
ngx_close_accepted_connection©;
return;
}

Stray -/+ probably indicate some unrelated whitespace changes
(though patch seems to be corrupted by MUA anyway).

+#endif

This part is wrong: with socket AIO sockets should be set to
blocking mode. The same code path as with
ngx_inherited_nonblocking should be followed.

Maxim D.

Hello!

On Mon, Nov 08, 2010 at 01:55:31AM +0800, Simon L. wrote:

[…]

     }

#if (NGX_HAVE_INHERITED_NONBLOCK)
ngx_inherited_nonblocking = 1;
#else
ngx_inherited_nonblocking = 0;
#endif

Yes. And the suggestion is to emulate NGX_HAVE_INHERITED_NONBLOCK
with accept4(): inherited nonblock means that socket returned by
accept() already has O_NONBLOCK set, so we don’t need to set it
(but may want to clear if we need blocking socket for some reason,
e.g. for socket AIO). With accept4() we basically get the same
situation.

Maxim D.

I use centos 5.5 system and I can not test accept4() in this. I don’t
want to use a custom kernel and I’m not sure if I can compile a custom
kernel myself.

So, can anyone tell me how much performance gain occour with accept4()
over accept() on linux system?

Posted at Nginx Forum: