Skip to content

Commit

Permalink
Reduce the number of system calls for accept (#769)
Browse files Browse the repository at this point in the history
Use accept4 to avoid 2 fcntl system calls.

accept4 accepts flags to tell to create the file descriptor in
non blocking mode. This way we don't need to set it later with
Unix.set_nonblock.

Also, since we know that all the calls to accept will be on
non blocking sockets we can avoid releasing the runtime lock.
  • Loading branch information
aantron authored Mar 5, 2020
1 parent 6489ad3 commit f4557e8
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/unix/config/discover.ml
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,24 @@ struct
}
|}
}

let () = feature {
pretty_name = "accept4";
macro_name = "HAVE_ACCEPT4";
detect = fun context ->
skip_if_windows context @@ fun () ->
compiles context {|
#define _GNU_SOURCE
#include <sys/socket.h>
#include <stddef.h>

int main()
{
accept4(0, NULL, 0, 0);
return 0;
}
|}
}
end


Expand Down
1 change: 1 addition & 0 deletions src/unix/dune
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
unix_unlink_job
unix_somaxconn
windows_somaxconn
unix_accept4
)
(install_c_headers lwt_features lwt_config lwt_unix)
(c_flags -I. (:include unix_c_flags.sexp))
Expand Down
17 changes: 14 additions & 3 deletions src/unix/lwt_unix.cppo.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1643,8 +1643,20 @@ let socketpair dom typ proto =
let (s1, s2) = do_socketpair dom typ proto in
(mk_ch ~blocking:false s1, mk_ch ~blocking:false s2)

external accept4 :
close_on_exec:bool -> nonblock:bool -> Unix.file_descr ->
Unix.file_descr * Unix.sockaddr = "lwt_unix_accept4"

let accept_and_set_nonblock ch_fd =
if Lwt_config._HAVE_ACCEPT4 then
let (fd, addr) = accept4 ~close_on_exec:false ~nonblock:true ch_fd in
(mk_ch ~blocking:false ~set_flags:false fd, addr)
else
let (fd, addr) = Unix.accept ch_fd in
(mk_ch ~blocking:false fd, addr)

let accept ch =
wrap_syscall Read ch (fun _ -> let (fd, addr) = Unix.accept ch.fd in (mk_ch ~blocking:false fd, addr))
wrap_syscall Read ch (fun _ -> accept_and_set_nonblock ch.fd)

let accept_n ch n =
let l = ref [] in
Expand All @@ -1656,8 +1668,7 @@ let accept_n ch n =
try
for _i = 1 to n do
if blocking && not (unix_readable ch.fd) then raise Retry;
let fd, addr = Unix.accept ch.fd in
l := (mk_ch ~blocking:false fd, addr) :: !l
l := accept_and_set_nonblock ch.fd :: !l
done
with
| (Unix.Unix_error((Unix.EAGAIN | Unix.EWOULDBLOCK | Unix.EINTR), _, _) | Retry) when !l <> [] ->
Expand Down
45 changes: 45 additions & 0 deletions src/unix/unix_c/unix_accept4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* This file is part of Lwt, released under the MIT license. See LICENSE.md for
details, or visit https://github.com/ocsigen/lwt/blob/master/LICENSE.md. */



#include "lwt_config.h"

#ifdef HAVE_ACCEPT4

#define _GNU_SOURCE
#include <caml/alloc.h>
#include <caml/memory.h>
#include <caml/unixsupport.h>
#include <caml/socketaddr.h>

CAMLprim value lwt_unix_accept4(value vcloexec, value vnonblock, value vsock)
{
CAMLparam3(vcloexec, vnonblock, vsock);
CAMLlocal2(vaddr, res);

union sock_addr_union addr;
socklen_param_type addr_len;
int cloexec = Int_val(vcloexec) ? SOCK_CLOEXEC : 0;
int nonblock = Int_val(vnonblock) ? SOCK_NONBLOCK : 0;
addr_len = sizeof(addr);

int fd =
accept4(Int_val(vsock), &addr.s_gen, &addr_len, cloexec | nonblock);
if (fd == -1)
uerror("accept", Nothing);

vaddr = alloc_sockaddr(&addr, addr_len, fd);
res = caml_alloc_small(2, 0);
Field(res, 0) = Val_int(fd);
Field(res, 1) = vaddr;

CAMLreturn(res);
}

#else

#include "lwt_unix.h"
LWT_NOT_AVAILABLE3(unix_accept4)

#endif

0 comments on commit f4557e8

Please sign in to comment.