diff options
Diffstat (limited to 'libgo/go/net/fd_unix.go')
-rw-r--r-- | libgo/go/net/fd_unix.go | 238 |
1 files changed, 145 insertions, 93 deletions
diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go index 8c59bff989c..4911ab0abe3 100644 --- a/libgo/go/net/fd_unix.go +++ b/libgo/go/net/fd_unix.go @@ -2,70 +2,59 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd package net import ( "io" "os" - "sync" + "runtime" + "sync/atomic" "syscall" "time" ) // Network file descriptor. type netFD struct { - // locking/lifetime of sysfd - sysmu sync.Mutex - sysref int - - // must lock both sysmu and pollDesc to write - // can lock either to read - closing bool + // locking/lifetime of sysfd + serialize access to Read and Write methods + fdmu fdMutex // immutable until Close sysfd int family int sotype int isConnected bool - sysfile *os.File net string laddr Addr raddr Addr - // serialize access to Read and Write methods - rio, wio sync.Mutex - // wait server pd pollDesc } -func resolveAndDial(net, addr string, localAddr Addr, deadline time.Time) (Conn, error) { - ra, err := resolveAddr("dial", net, addr, deadline) - if err != nil { - return nil, err - } - return dial(net, addr, localAddr, ra, deadline) +func sysInit() { } -func newFD(fd, family, sotype int, net string) (*netFD, error) { - netfd := &netFD{ - sysfd: fd, - family: family, - sotype: sotype, - net: net, - } - if err := netfd.pd.Init(netfd); err != nil { - return nil, err +func dial(network string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) { + return dialer(deadline) +} + +func newFD(sysfd, family, sotype int, net string) (*netFD, error) { + return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil +} + +func (fd *netFD) init() error { + if err := fd.pd.Init(fd); err != nil { + return err } - return netfd, nil + return nil } func (fd *netFD) setAddr(laddr, raddr Addr) { fd.laddr = laddr fd.raddr = raddr - fd.sysfile = os.NewFile(uintptr(fd.sysfd), fd.net) + runtime.SetFinalizer(fd, (*netFD).Close) } func (fd *netFD) name() string { @@ -80,8 +69,9 @@ func (fd *netFD) name() string { } func (fd *netFD) connect(la, ra syscall.Sockaddr) error { - fd.wio.Lock() - defer fd.wio.Unlock() + // Do not need to call fd.writeLock here, + // because fd is not yet accessible to user, + // so no concurrent operations are possible. if err := fd.pd.PrepareWrite(); err != nil { return err } @@ -100,48 +90,69 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error { return nil } +func (fd *netFD) destroy() { + // Poller may want to unregister fd in readiness notification mechanism, + // so this must be executed before closesocket. + fd.pd.Close() + closesocket(fd.sysfd) + fd.sysfd = -1 + runtime.SetFinalizer(fd, nil) +} + // Add a reference to this fd. -// If closing==true, pollDesc must be locked; mark the fd as closing. // Returns an error if the fd cannot be used. -func (fd *netFD) incref(closing bool) error { - fd.sysmu.Lock() - if fd.closing { - fd.sysmu.Unlock() +func (fd *netFD) incref() error { + if !fd.fdmu.Incref() { return errClosing } - fd.sysref++ - if closing { - fd.closing = true - } - fd.sysmu.Unlock() return nil } -// Remove a reference to this FD and close if we've been asked to do so (and -// there are no references left. +// Remove a reference to this FD and close if we've been asked to do so +// (and there are no references left). func (fd *netFD) decref() { - fd.sysmu.Lock() - fd.sysref-- - if fd.closing && fd.sysref == 0 { - // Poller may want to unregister fd in readiness notification mechanism, - // so this must be executed before sysfile.Close(). - fd.pd.Close() - if fd.sysfile != nil { - fd.sysfile.Close() - fd.sysfile = nil - } else { - closesocket(fd.sysfd) - } - fd.sysfd = -1 + if fd.fdmu.Decref() { + fd.destroy() + } +} + +// Add a reference to this fd and lock for reading. +// Returns an error if the fd cannot be used. +func (fd *netFD) readLock() error { + if !fd.fdmu.RWLock(true) { + return errClosing + } + return nil +} + +// Unlock for reading and remove a reference to this FD. +func (fd *netFD) readUnlock() { + if fd.fdmu.RWUnlock(true) { + fd.destroy() + } +} + +// Add a reference to this fd and lock for writing. +// Returns an error if the fd cannot be used. +func (fd *netFD) writeLock() error { + if !fd.fdmu.RWLock(false) { + return errClosing + } + return nil +} + +// Unlock for writing and remove a reference to this FD. +func (fd *netFD) writeUnlock() { + if fd.fdmu.RWUnlock(false) { + fd.destroy() } - fd.sysmu.Unlock() } func (fd *netFD) Close() error { fd.pd.Lock() // needed for both fd.incref(true) and pollDesc.Evict - if err := fd.incref(true); err != nil { + if !fd.fdmu.IncrefAndClose() { fd.pd.Unlock() - return err + return errClosing } // Unblock any I/O. Once it all unblocks and returns, // so that it cannot be referring to fd.sysfd anymore, @@ -158,7 +169,7 @@ func (fd *netFD) Close() error { } func (fd *netFD) shutdown(how int) error { - if err := fd.incref(false); err != nil { + if err := fd.incref(); err != nil { return err } defer fd.decref() @@ -178,12 +189,10 @@ func (fd *netFD) CloseWrite() error { } func (fd *netFD) Read(p []byte) (n int, err error) { - fd.rio.Lock() - defer fd.rio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.readLock(); err != nil { return 0, err } - defer fd.decref() + defer fd.readUnlock() if err := fd.pd.PrepareRead(); err != nil { return 0, &OpError{"read", fd.net, fd.raddr, err} } @@ -207,12 +216,10 @@ func (fd *netFD) Read(p []byte) (n int, err error) { } func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { - fd.rio.Lock() - defer fd.rio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.readLock(); err != nil { return 0, nil, err } - defer fd.decref() + defer fd.readUnlock() if err := fd.pd.PrepareRead(); err != nil { return 0, nil, &OpError{"read", fd.net, fd.laddr, err} } @@ -236,12 +243,10 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { } func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { - fd.rio.Lock() - defer fd.rio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.readLock(); err != nil { return 0, 0, 0, nil, err } - defer fd.decref() + defer fd.readUnlock() if err := fd.pd.PrepareRead(); err != nil { return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err} } @@ -272,12 +277,10 @@ func chkReadErr(n int, err error, fd *netFD) error { } func (fd *netFD) Write(p []byte) (nn int, err error) { - fd.wio.Lock() - defer fd.wio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.writeLock(); err != nil { return 0, err } - defer fd.decref() + defer fd.writeUnlock() if err := fd.pd.PrepareWrite(); err != nil { return 0, &OpError{"write", fd.net, fd.raddr, err} } @@ -311,12 +314,10 @@ func (fd *netFD) Write(p []byte) (nn int, err error) { } func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { - fd.wio.Lock() - defer fd.wio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.writeLock(); err != nil { return 0, err } - defer fd.decref() + defer fd.writeUnlock() if err := fd.pd.PrepareWrite(); err != nil { return 0, &OpError{"write", fd.net, fd.raddr, err} } @@ -338,12 +339,10 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { } func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { - fd.wio.Lock() - defer fd.wio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.writeLock(); err != nil { return 0, 0, err } - defer fd.decref() + defer fd.writeUnlock() if err := fd.pd.PrepareWrite(); err != nil { return 0, 0, &OpError{"write", fd.net, fd.raddr, err} } @@ -366,12 +365,10 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob } func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) { - fd.rio.Lock() - defer fd.rio.Unlock() - if err := fd.incref(false); err != nil { + if err := fd.readLock(); err != nil { return nil, err } - defer fd.decref() + defer fd.readUnlock() var s int var rsa syscall.Sockaddr @@ -399,20 +396,68 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e closesocket(s) return nil, err } + if err = netfd.init(); err != nil { + fd.Close() + return nil, err + } lsa, _ := syscall.Getsockname(netfd.sysfd) netfd.setAddr(toAddr(lsa), toAddr(rsa)) return netfd, nil } -func (fd *netFD) dup() (f *os.File, err error) { +// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used. +// If the kernel doesn't support it, this is set to 0. +var tryDupCloexec = int32(1) + +func dupCloseOnExec(fd int) (newfd int, err error) { + if atomic.LoadInt32(&tryDupCloexec) == 1 && syscall.F_DUPFD_CLOEXEC != 0 { + r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0) + if runtime.GOOS == "darwin" && e1 == syscall.EBADF { + // On OS X 10.6 and below (but we only support + // >= 10.6), F_DUPFD_CLOEXEC is unsupported + // and fcntl there falls back (undocumented) + // to doing an ioctl instead, returning EBADF + // in this case because fd is not of the + // expected device fd type. Treat it as + // EINVAL instead, so we fall back to the + // normal dup path. + // TODO: only do this on 10.6 if we can detect 10.6 + // cheaply. + e1 = syscall.EINVAL + } + switch e1 { + case 0: + return int(r0), nil + case syscall.EINVAL: + // Old kernel. Fall back to the portable way + // from now on. + atomic.StoreInt32(&tryDupCloexec, 0) + default: + return -1, e1 + } + } + return dupCloseOnExecOld(fd) +} + +// dupCloseOnExecUnixOld is the traditional way to dup an fd and +// set its O_CLOEXEC bit, using two system calls. +func dupCloseOnExecOld(fd int) (newfd int, err error) { syscall.ForkLock.RLock() - ns, err := syscall.Dup(fd.sysfd) + defer syscall.ForkLock.RUnlock() + newfd, err = syscall.Dup(fd) + if err != nil { + return -1, err + } + syscall.CloseOnExec(newfd) + return +} + +func (fd *netFD) dup() (f *os.File, err error) { + ns, err := dupCloseOnExec(fd.sysfd) if err != nil { syscall.ForkLock.RUnlock() return nil, &OpError{"dup", fd.net, fd.laddr, err} } - syscall.CloseOnExec(ns) - syscall.ForkLock.RUnlock() // We want blocking mode for the new fd, hence the double negative. // This also puts the old fd into blocking mode, meaning that @@ -428,3 +473,10 @@ func (fd *netFD) dup() (f *os.File, err error) { func closesocket(s int) error { return syscall.Close(s) } + +func skipRawSocketTests() (skip bool, skipmsg string, err error) { + if os.Getuid() != 0 { + return true, "skipping test; must be root", nil + } + return false, "", nil +} |