On Solaris the libgo networking library uses select. This patch implements some fixes for that code. The Close method is changed to actually do something; this is mainly for testing purposes. More importantly, when a socket is closed, the select needs to be restarted so that the callers see the close. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r fd46f2eb83d3 libgo/go/net/fd_bsd.go --- a/libgo/go/net/fd_bsd.go Tue Feb 05 15:57:40 2013 -0800 +++ b/libgo/go/net/fd_bsd.go Wed Feb 06 14:36:13 2013 -0800 @@ -64,7 +64,7 @@ return false, nil } -func (p *pollster) DelFD(fd int, mode int) { +func (p *pollster) DelFD(fd int, mode int) bool { // pollServer is locked. var kmode int @@ -77,6 +77,7 @@ // EV_DELETE - delete event from kqueue list syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE) syscall.Kevent(p.kq, p.kbuf[:], nil, nil) + return false } func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { diff -r fd46f2eb83d3 libgo/go/net/fd_linux.go --- a/libgo/go/net/fd_linux.go Tue Feb 05 15:57:40 2013 -0800 +++ b/libgo/go/net/fd_linux.go Wed Feb 06 14:36:13 2013 -0800 @@ -114,7 +114,7 @@ } } -func (p *pollster) DelFD(fd int, mode int) { +func (p *pollster) DelFD(fd int, mode int) bool { // pollServer is locked. if mode == 'r' { @@ -133,6 +133,7 @@ i++ } } + return false } func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { diff -r fd46f2eb83d3 libgo/go/net/fd_select.go --- a/libgo/go/net/fd_select.go Tue Feb 05 15:57:40 2013 -0800 +++ b/libgo/go/net/fd_select.go Wed Feb 06 14:36:13 2013 -0800 @@ -7,6 +7,7 @@ package net import ( + "errors" "os" "syscall" ) @@ -17,6 +18,7 @@ readyReadFds, readyWriteFds *syscall.FdSet nReady int lastFd int + closed bool } func newpollster() (p *pollster, err error) { @@ -35,6 +37,10 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) { // pollServer is locked. + if p.closed { + return false, errors.New("pollster closed") + } + if mode == 'r' { syscall.FDSet(fd, p.readFds) } else { @@ -52,19 +58,23 @@ return true, nil } -func (p *pollster) DelFD(fd int, mode int) { +func (p *pollster) DelFD(fd int, mode int) bool { // pollServer is locked. + if p.closed { + return false + } + if mode == 'r' { if !syscall.FDIsSet(fd, p.readFds) { print("Select unexpected fd=", fd, " for read\n") - return + return false } syscall.FDClr(fd, p.readFds) } else { if !syscall.FDIsSet(fd, p.writeFds) { print("Select unexpected fd=", fd, " for write\n") - return + return false } syscall.FDClr(fd, p.writeFds) } @@ -73,6 +83,8 @@ syscall.FDClr(fd, p.repeatFds) // We don't worry about maxFd here. + + return true } func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { @@ -89,6 +101,10 @@ var e error var tmpReadFds, tmpWriteFds syscall.FdSet for { + if p.closed { + return -1, 0, errors.New("pollster closed") + } + // Temporary syscall.FdSet's into which the values are copied // because select mutates the values. tmpReadFds = *p.readFds @@ -161,5 +177,6 @@ } func (p *pollster) Close() error { + p.closed = true return nil } diff -r fd46f2eb83d3 libgo/go/net/fd_unix.go --- a/libgo/go/net/fd_unix.go Tue Feb 05 15:57:40 2013 -0800 +++ b/libgo/go/net/fd_unix.go Wed Feb 06 14:36:13 2013 -0800 @@ -110,16 +110,24 @@ // any I/O running on fd. The caller must have locked // pollserver. func (s *pollServer) Evict(fd *netFD) { + doWakeup := false if s.pending[fd.sysfd<<1] == fd { s.WakeFD(fd, 'r', errClosing) - s.poll.DelFD(fd.sysfd, 'r') + if s.poll.DelFD(fd.sysfd, 'r') { + doWakeup = true + } delete(s.pending, fd.sysfd<<1) } if s.pending[fd.sysfd<<1|1] == fd { s.WakeFD(fd, 'w', errClosing) - s.poll.DelFD(fd.sysfd, 'w') + if s.poll.DelFD(fd.sysfd, 'w') { + doWakeup = true + } delete(s.pending, fd.sysfd<<1|1) } + if doWakeup { + s.Wakeup() + } } var wakeupbuf [1]byte