Patchwork libgo patch committed: Fix net package for Solaris

login
register
mail settings
Submitter Ian Taylor
Date April 25, 2012, 4:26 a.m.
Message ID <mcr4ns8tp0t.fsf@dhcp-172-18-216-180.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/154790/
State New
Headers show

Comments

Ian Taylor - April 25, 2012, 4:26 a.m.
This patch to libgo fixes the net package to work correctly on Solaris.
The main fix is to the select code, to fix the case where one goroutine
closes a file descriptor while another goroutine is waiting for I/O on
the descriptor.  Bootstrapped and ran Go testsuite on
sparc-sun-solaris2.11.  Committed to mainline and 4.7 branch.

Ian

Patch

diff -r 19c80c28161e libgo/Makefile.am
--- a/libgo/Makefile.am	Tue Apr 24 13:11:46 2012 -0700
+++ b/libgo/Makefile.am	Tue Apr 24 20:10:20 2012 -0700
@@ -654,9 +654,9 @@ 
 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 -r 19c80c28161e libgo/Makefile.in
--- a/libgo/Makefile.in	Tue Apr 24 13:11:46 2012 -0700
+++ b/libgo/Makefile.in	Tue Apr 24 20:10:20 2012 -0700
@@ -1019,17 +1019,17 @@ 
 @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 -r 19c80c28161e libgo/go/net/dial_test.go
--- a/libgo/go/net/dial_test.go	Tue Apr 24 13:11:46 2012 -0700
+++ b/libgo/go/net/dial_test.go	Tue Apr 24 20:10:20 2012 -0700
@@ -130,7 +130,7 @@ 
 		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 -r 19c80c28161e libgo/go/net/fd_select.go
--- a/libgo/go/net/fd_select.go	Tue Apr 24 13:11:46 2012 -0700
+++ b/libgo/go/net/fd_select.go	Tue Apr 24 20:10:20 2012 -0700
@@ -102,7 +102,27 @@ 
 				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 -r 19c80c28161e libgo/go/net/multicast_test.go
--- a/libgo/go/net/multicast_test.go	Tue Apr 24 13:11:46 2012 -0700
+++ b/libgo/go/net/multicast_test.go	Tue Apr 24 20:10:20 2012 -0700
@@ -46,7 +46,7 @@ 
 // 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 -r 19c80c28161e libgo/go/net/sock_solaris.go
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/net/sock_solaris.go	Tue Apr 24 20:10:20 2012 -0700
@@ -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 -r 19c80c28161e libgo/go/net/sockoptip_solaris.go
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/net/sockoptip_solaris.go	Tue Apr 24 20:10:20 2012 -0700
@@ -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
+}