From d41b42a65d5c90c8067cca069524f07350a44cb4 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 25 Apr 2012 04:26:12 +0000 Subject: [PATCH] PR go/52583 net: Solaris fixes. In particular fix fd_select.go to handle the case where a file descriptor is closed by one goroutine while another goroutine is waiting for it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@186801 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgo/Makefile.am | 6 +-- libgo/Makefile.in | 6 +-- libgo/go/net/dial_test.go | 2 +- libgo/go/net/fd_select.go | 22 +++++++++- libgo/go/net/multicast_test.go | 2 +- libgo/go/net/sock_solaris.go | 47 ++++++++++++++++++++ libgo/go/net/sockoptip_solaris.go | 90 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 libgo/go/net/sock_solaris.go create mode 100644 libgo/go/net/sockoptip_solaris.go diff --git a/libgo/Makefile.am b/libgo/Makefile.am index a56d2e8..074d664 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -654,9 +654,9 @@ go_net_sockoptip_file = go/net/sockoptip_linux.go else if LIBGO_IS_SOLARIS go_net_cgo_file = go/net/cgo_linux.go -go_net_sock_file = go/net/sock_linux.go -go_net_sockopt_file = go/net/sockopt_linux.go -go_net_sockoptip_file = go/net/sockoptip_linux.go +go_net_sock_file = go/net/sock_solaris.go +go_net_sockopt_file = go/net/sockopt_bsd.go +go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_solaris.go else if LIBGO_IS_FREEBSD go_net_cgo_file = go/net/cgo_bsd.go diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 32c5afc..bbec292 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -1019,17 +1019,17 @@ go_mime_files = \ @LIBGO_IS_LINUX_TRUE@go_net_cgo_file = go/net/cgo_linux.go @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go @LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go -@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_linux.go +@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_solaris.go @LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go @LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go @LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go -@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockopt_file = go/net/sockopt_linux.go +@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockopt_file = go/net/sockopt_bsd.go @LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockopt_file = go/net/sockopt_linux.go @LIBGO_IS_LINUX_TRUE@go_net_sockopt_file = go/net/sockopt_linux.go @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_netbsd.go @LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_freebsd.go -@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockoptip_file = go/net/sockoptip_linux.go +@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_solaris.go @LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockoptip_file = go/net/sockoptip_linux.go @LIBGO_IS_LINUX_TRUE@go_net_sockoptip_file = go/net/sockoptip_linux.go @LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go index 7212087..63b91b3 100644 --- a/libgo/go/net/dial_test.go +++ b/libgo/go/net/dial_test.go @@ -130,7 +130,7 @@ func TestSelfConnect(t *testing.T) { n = 1000 } switch runtime.GOOS { - case "darwin", "freebsd", "openbsd", "windows": + case "darwin", "freebsd", "openbsd", "solaris", "windows": // Non-Linux systems take a long time to figure // out that there is nothing listening on localhost. n = 100 diff --git a/libgo/go/net/fd_select.go b/libgo/go/net/fd_select.go index 39c8f27..22db1cb 100644 --- a/libgo/go/net/fd_select.go +++ b/libgo/go/net/fd_select.go @@ -102,7 +102,27 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro break } } - if e != nil { + if e == syscall.EBADF { + // Some file descriptor has been closed. + tmpReadFds = syscall.FdSet{} + tmpWriteFds = syscall.FdSet{} + n = 0 + for i := 0; i < p.maxFd+1; i++ { + if syscall.FDIsSet(i, p.readFds) { + var s syscall.Stat_t + if syscall.Fstat(i, &s) == syscall.EBADF { + syscall.FDSet(i, &tmpReadFds) + n++ + } + } else if syscall.FDIsSet(i, p.writeFds) { + var s syscall.Stat_t + if syscall.Fstat(i, &s) == syscall.EBADF { + syscall.FDSet(i, &tmpWriteFds) + n++ + } + } + } + } else if e != nil { return -1, 0, os.NewSyscallError("select", e) } if n == 0 { diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go index 67261b1..50c0f0a 100644 --- a/libgo/go/net/multicast_test.go +++ b/libgo/go/net/multicast_test.go @@ -46,7 +46,7 @@ var multicastListenerTests = []struct { // listener with same address family, same group address and same port. func TestMulticastListener(t *testing.T) { switch runtime.GOOS { - case "netbsd", "openbsd", "plan9", "windows": + case "netbsd", "openbsd", "plan9", "solaris", "windows": t.Logf("skipping test on %q", runtime.GOOS) return case "linux": diff --git a/libgo/go/net/sock_solaris.go b/libgo/go/net/sock_solaris.go new file mode 100644 index 0000000..ad639cc --- /dev/null +++ b/libgo/go/net/sock_solaris.go @@ -0,0 +1,47 @@ +// Copyright 2012 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. + +// +build solaris + +// Sockets for Solaris + +package net + +import ( + "syscall" +) + +func maxListenerBacklog() int { + // The kernel does not track the limit. + return syscall.SOMAXCONN +} + +func listenerSockaddr(s, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) { + a := toAddr(la) + if a == nil { + return la, nil + } + switch v := a.(type) { + case *TCPAddr, *UnixAddr: + err := setDefaultListenerSockopts(s) + if err != nil { + return nil, err + } + case *UDPAddr: + if v.IP.IsMulticast() { + err := setDefaultMulticastSockopts(s) + if err != nil { + return nil, err + } + switch f { + case syscall.AF_INET: + v.IP = IPv4zero + case syscall.AF_INET6: + v.IP = IPv6unspecified + } + return v.sockaddr(f) + } + } + return la, nil +} diff --git a/libgo/go/net/sockoptip_solaris.go b/libgo/go/net/sockoptip_solaris.go new file mode 100644 index 0000000..538ef0d --- /dev/null +++ b/libgo/go/net/sockoptip_solaris.go @@ -0,0 +1,90 @@ +// Copyright 2011 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. + +// IP-level socket options for Solaris + +package net + +import ( + "os" + "syscall" +) + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + if err := fd.incref(false); err != nil { + return nil, err + } + defer fd.decref() + a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3])) +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + ip, err := interfaceToIPv4Addr(ifi) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + var x [4]byte + copy(x[:], ip.To4()) + if err := fd.incref(false); err != nil { + return err + } + defer fd.decref() + err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + if err := fd.incref(false); err != nil { + return false, err + } + defer fd.decref() + v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + if err := fd.incref(false); err != nil { + return err + } + defer fd.decref() + err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + if err := fd.incref(false); err != nil { + return false, err + } + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + if err := fd.incref(false); err != nil { + return err + } + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} -- 2.7.4