]> Cypherpunks repositories - gostls13.git/commitdiff
net, syscall: use accept4 and SOCK_CLOEXEC on Linux
authorIan Lance Taylor <iant@golang.org>
Mon, 28 Jan 2013 16:54:15 +0000 (08:54 -0800)
committerIan Lance Taylor <iant@golang.org>
Mon, 28 Jan 2013 16:54:15 +0000 (08:54 -0800)
R=golang-dev, bradfitz, mikioh.mikioh, dave, minux.ma
CC=golang-dev
https://golang.org/cl/7227043

src/pkg/net/fd_unix.go
src/pkg/net/file_unix.go
src/pkg/net/sock_cloexec.go [new file with mode: 0644]
src/pkg/net/sock_posix.go
src/pkg/net/sys_cloexec.go [new file with mode: 0644]
src/pkg/syscall/syscall_linux.go
src/pkg/syscall/syscall_linux_386.go
src/pkg/syscall/syscall_linux_amd64.go
src/pkg/syscall/syscall_linux_arm.go
src/pkg/syscall/zsyscall_linux_amd64.go
src/pkg/syscall/zsyscall_linux_arm.go

index cfe6df2130814cb32018d9a1453746a6e941c10c..e9d2e4165f135ebaf11dc36382283c48d136b355 100644 (file)
@@ -298,9 +298,6 @@ func dialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
 }
 
 func newFD(fd, family, sotype int, net string) (*netFD, error) {
-       if err := syscall.SetNonblock(fd, true); err != nil {
-               return nil, err
-       }
        netfd := &netFD{
                sysfd:  fd,
                family: family,
@@ -615,16 +612,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
        }
        defer fd.decref()
 
-       // See ../syscall/exec_unix.go for description of ForkLock.
-       // It is okay to hold the lock across syscall.Accept
-       // because we have put fd.sysfd into non-blocking mode.
        var s int
        var rsa syscall.Sockaddr
        for {
-               syscall.ForkLock.RLock()
-               s, rsa, err = syscall.Accept(fd.sysfd)
+               s, rsa, err = accept(fd.sysfd)
                if err != nil {
-                       syscall.ForkLock.RUnlock()
                        if err == syscall.EAGAIN {
                                if err = fd.pollServer.WaitRead(fd); err == nil {
                                        continue
@@ -638,8 +630,6 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
                }
                break
        }
-       syscall.CloseOnExec(s)
-       syscall.ForkLock.RUnlock()
 
        if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
                closesocket(s)
index 0a640801779aec445bbb9efbeba3c95830d1adf9..4c8403e40631ad89750b0c27361d877ffd958451 100644 (file)
@@ -20,6 +20,10 @@ func newFileFD(f *os.File) (*netFD, error) {
        }
        syscall.CloseOnExec(fd)
        syscall.ForkLock.RUnlock()
+       if err = syscall.SetNonblock(fd, true); err != nil {
+               closesocket(fd)
+               return nil, err
+       }
 
        sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
        if err != nil {
diff --git a/src/pkg/net/sock_cloexec.go b/src/pkg/net/sock_cloexec.go
new file mode 100644 (file)
index 0000000..e2a5ef7
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements sysSocket and accept for platforms that
+// provide a fast path for setting SetNonblock and CloseOnExec.
+
+// +build linux
+
+package net
+
+import "syscall"
+
+// Wrapper around the socket system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func sysSocket(f, t, p int) (int, error) {
+       s, err := syscall.Socket(f, t|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, p)
+       // The SOCK_NONBLOCK and SOCK_CLOEXEC flags were introduced in
+       // Linux 2.6.27.  If we get an EINVAL error, fall back to
+       // using socket without them.
+       if err == nil || err != syscall.EINVAL {
+               return s, err
+       }
+
+       // See ../syscall/exec_unix.go for description of ForkLock.
+       syscall.ForkLock.RLock()
+       s, err = syscall.Socket(f, t, p)
+       if err == nil {
+               syscall.CloseOnExec(s)
+       }
+       syscall.ForkLock.RUnlock()
+       if err != nil {
+               return -1, err
+       }
+       if err = syscall.SetNonblock(s, true); err != nil {
+               syscall.Close(s)
+               return -1, err
+       }
+       return s, nil
+}
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(fd int) (int, syscall.Sockaddr, error) {
+       nfd, sa, err := syscall.Accept4(fd, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+       // The accept4 system call was introduced in Linux 2.6.28.  If
+       // we get an ENOSYS error, fall back to using accept.
+       if err == nil || err != syscall.ENOSYS {
+               return nfd, sa, err
+       }
+
+       // See ../syscall/exec_unix.go for description of ForkLock.
+       // It is okay to hold the lock across syscall.Accept
+       // because we have put fd.sysfd into non-blocking mode.
+       syscall.ForkLock.RLock()
+       nfd, sa, err = syscall.Accept(fd)
+       if err == nil {
+               syscall.CloseOnExec(nfd)
+       }
+       syscall.ForkLock.RUnlock()
+       if err != nil {
+               return -1, nil, err
+       }
+       if err = syscall.SetNonblock(nfd, true); err != nil {
+               syscall.Close(nfd)
+               return -1, nil, err
+       }
+       return nfd, sa, nil
+}
index 12015ef0acdf4861d3b7a9da1f40b6bc5005d556..9cd149e466b381237ff75af45a152f01ab45e25d 100644 (file)
@@ -17,15 +17,10 @@ var listenerBacklog = maxListenerBacklog()
 
 // Generic socket creation.
 func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
-       // See ../syscall/exec_unix.go for description of ForkLock.
-       syscall.ForkLock.RLock()
-       s, err := syscall.Socket(f, t, p)
+       s, err := sysSocket(f, t, p)
        if err != nil {
-               syscall.ForkLock.RUnlock()
                return nil, err
        }
-       syscall.CloseOnExec(s)
-       syscall.ForkLock.RUnlock()
 
        if err = setDefaultSockopts(s, f, t, ipv6only); err != nil {
                closesocket(s)
diff --git a/src/pkg/net/sys_cloexec.go b/src/pkg/net/sys_cloexec.go
new file mode 100644 (file)
index 0000000..75d5688
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements sysSocket and accept for platforms that do not
+// provide a fast path for setting SetNonblock and CloseOnExec.
+
+// +build darwin freebsd netbsd openbsd
+
+package net
+
+import "syscall"
+
+// Wrapper around the socket system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func sysSocket(f, t, p int) (int, error) {
+       // See ../syscall/exec_unix.go for description of ForkLock.
+       syscall.ForkLock.RLock()
+       s, err := syscall.Socket(f, t, p)
+       if err == nil {
+               syscall.CloseOnExec(s)
+       }
+       syscall.ForkLock.RUnlock()
+       if err != nil {
+               return -1, err
+       }
+       if err = syscall.SetNonblock(s, true); err != nil {
+               syscall.Close(s)
+               return -1, err
+       }
+       return s, nil
+}
+
+// Wrapper around the accept system call that marks the returned file
+// descriptor as nonblocking and close-on-exec.
+func accept(fd int) (int, syscall.Sockaddr, error) {
+       // See ../syscall/exec_unix.go for description of ForkLock.
+       // It is okay to hold the lock across syscall.Accept
+       // because we have put fd.sysfd into non-blocking mode.
+       syscall.ForkLock.RLock()
+       nfd, sa, err := syscall.Accept(fd)
+       if err == nil {
+               syscall.CloseOnExec(nfd)
+       }
+       syscall.ForkLock.RUnlock()
+       if err != nil {
+               return -1, nil, err
+       }
+       if err = syscall.SetNonblock(nfd, true); err != nil {
+               syscall.Close(nfd)
+               return -1, nil, err
+       }
+       return nfd, sa, nil
+}
index f44fb48fa78d97885cc7737366f44b715db2cb92..40e9ed04b153e7f65018dcc44037c26e6f5bbed3 100644 (file)
@@ -427,6 +427,21 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
        return
 }
 
+func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
+       var rsa RawSockaddrAny
+       var len _Socklen = SizeofSockaddrAny
+       nfd, err = accept4(fd, &rsa, &len, flags)
+       if err != nil {
+               return
+       }
+       sa, err = anyToSockaddr(&rsa)
+       if err != nil {
+               Close(nfd)
+               nfd = 0
+       }
+       return
+}
+
 func Getsockname(fd int) (sa Sockaddr, err error) {
        var rsa RawSockaddrAny
        var len _Socklen = SizeofSockaddrAny
index 58bc9b53f1adf36323bc7ca111bb0bebc110fc36..a0ded43dcf0b84c2afef860ca7d9a8adc5590422 100644 (file)
@@ -164,6 +164,9 @@ const (
        _GETSOCKOPT  = 15
        _SENDMSG     = 16
        _RECVMSG     = 17
+       _ACCEPT4     = 18
+       _RECVMMSG    = 19
+       _SENDMMSG    = 20
 )
 
 func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
@@ -177,6 +180,14 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
        return
 }
 
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+       fd, e := socketcall(_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+       if e != 0 {
+               err = e
+       }
+       return
+}
+
 func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
        _, e := rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
        if e != 0 {
index b0d236cdc1da16eabdb16006202bdda55ccbb86a..f4b73b20e63ebaef949a996f14e8dfe6bf0ab14e 100644 (file)
@@ -39,6 +39,7 @@ package syscall
 //sys  SyncFileRange(fd int, off int64, n int64, flags int) (err error)
 //sys  Truncate(path string, length int64) (err error)
 //sys  accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys  accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
 //sys  bind(s int, addr uintptr, addrlen _Socklen) (err error)
 //sys  connect(s int, addr uintptr, addrlen _Socklen) (err error)
 //sysnb        getgroups(n int, list *_Gid_t) (nn int, err error)
index f2859cfaf2eba051aa3c33f8cab3ed38a4506926..7839d528827568b0e78ccaffda5ec498556bf684 100644 (file)
@@ -28,6 +28,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
 
 //sys  accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys  accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
 //sys  bind(s int, addr uintptr, addrlen _Socklen) (err error)
 //sys  connect(s int, addr uintptr, addrlen _Socklen) (err error)
 //sysnb        getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
index 3cdc1873b8988df5ce94a076a8baa95a7169b7db..43f24e7731d76ed2952f54dab59151e193772731 100644 (file)
@@ -1721,6 +1721,17 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+       r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+       fd = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
        _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
        if e1 != 0 {
index db17d968230ad992f92ab3429e272119442b810d..804821eb3fc3caffaae0cc0da6ddff29c24f810c 100644 (file)
@@ -1341,6 +1341,17 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+       r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+       fd = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
        _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
        if e1 != 0 {