diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/net/fd_plan9.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/net/fd_plan9.go')
-rw-r--r-- | src/net/fd_plan9.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go new file mode 100644 index 000000000..5fe8effc2 --- /dev/null +++ b/src/net/fd_plan9.go @@ -0,0 +1,232 @@ +// Copyright 2009 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. + +package net + +import ( + "io" + "os" + "syscall" + "time" +) + +// Network file descritor. +type netFD struct { + // locking/lifetime of sysfd + serialize access to Read and Write methods + fdmu fdMutex + + // immutable until Close + proto string + n string + dir string + ctl, data *os.File + laddr, raddr Addr +} + +var ( + netdir string // default network +) + +func sysInit() { + netdir = "/net" +} + +func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) { + // On plan9, use the relatively inefficient + // goroutine-racing implementation. + return dialChannel(net, ra, dialer, deadline) +} + +func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { + return &netFD{proto: proto, n: name, dir: netdir + "/" + proto + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil +} + +func (fd *netFD) init() error { + // stub for future fd.pd.Init(fd) + return nil +} + +func (fd *netFD) name() string { + var ls, rs string + if fd.laddr != nil { + ls = fd.laddr.String() + } + if fd.raddr != nil { + rs = fd.raddr.String() + } + return fd.proto + ":" + ls + "->" + rs +} + +func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } + +func (fd *netFD) destroy() { + if !fd.ok() { + return + } + err := fd.ctl.Close() + if fd.data != nil { + if err1 := fd.data.Close(); err1 != nil && err == nil { + err = err1 + } + } + fd.ctl = nil + fd.data = nil +} + +// Add a reference to this fd. +// Returns an error if the fd cannot be used. +func (fd *netFD) incref() error { + if !fd.fdmu.Incref() { + return errClosing + } + return nil +} + +// 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() { + 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() + } +} + +func (fd *netFD) Read(b []byte) (n int, err error) { + if !fd.ok() || fd.data == nil { + return 0, syscall.EINVAL + } + if err := fd.readLock(); err != nil { + return 0, err + } + defer fd.readUnlock() + n, err = fd.data.Read(b) + if fd.proto == "udp" && err == io.EOF { + n = 0 + err = nil + } + return +} + +func (fd *netFD) Write(b []byte) (n int, err error) { + if !fd.ok() || fd.data == nil { + return 0, syscall.EINVAL + } + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + return fd.data.Write(b) +} + +func (fd *netFD) closeRead() error { + if !fd.ok() { + return syscall.EINVAL + } + return syscall.EPLAN9 +} + +func (fd *netFD) closeWrite() error { + if !fd.ok() { + return syscall.EINVAL + } + return syscall.EPLAN9 +} + +func (fd *netFD) Close() error { + if !fd.fdmu.IncrefAndClose() { + return errClosing + } + if !fd.ok() { + return syscall.EINVAL + } + err := fd.ctl.Close() + if fd.data != nil { + if err1 := fd.data.Close(); err1 != nil && err == nil { + err = err1 + } + } + fd.ctl = nil + fd.data = nil + return err +} + +// This method is only called via Conn. +func (fd *netFD) dup() (*os.File, error) { + if !fd.ok() || fd.data == nil { + return nil, syscall.EINVAL + } + return fd.file(fd.data, fd.dir+"/data") +} + +func (l *TCPListener) dup() (*os.File, error) { + if !l.fd.ok() { + return nil, syscall.EINVAL + } + return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl") +} + +func (fd *netFD) file(f *os.File, s string) (*os.File, error) { + syscall.ForkLock.RLock() + dfd, err := syscall.Dup(int(f.Fd()), -1) + syscall.ForkLock.RUnlock() + if err != nil { + return nil, &OpError{"dup", s, fd.laddr, err} + } + return os.NewFile(uintptr(dfd), s), nil +} + +func (fd *netFD) setDeadline(t time.Time) error { + return syscall.EPLAN9 +} + +func (fd *netFD) setReadDeadline(t time.Time) error { + return syscall.EPLAN9 +} + +func (fd *netFD) setWriteDeadline(t time.Time) error { + return syscall.EPLAN9 +} + +func setReadBuffer(fd *netFD, bytes int) error { + return syscall.EPLAN9 +} + +func setWriteBuffer(fd *netFD, bytes int) error { + return syscall.EPLAN9 +} + +func skipRawSocketTests() (skip bool, skipmsg string, err error) { + return true, "skipping test on plan9", nil +} |