diff options
Diffstat (limited to 'src/pkg/net/fd_plan9.go')
-rw-r--r-- | src/pkg/net/fd_plan9.go | 115 |
1 files changed, 108 insertions, 7 deletions
diff --git a/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go index acc829402..5fe8effc2 100644 --- a/src/pkg/net/fd_plan9.go +++ b/src/pkg/net/fd_plan9.go @@ -13,12 +13,23 @@ import ( // Network file descritor. type netFD struct { - proto, name, dir string - ctl, data *os.File - laddr, raddr Addr + // 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) { @@ -27,16 +38,99 @@ func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline ti return dialChannel(net, ra, dialer, deadline) } -func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) *netFD { - return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, data, laddr, raddr} +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 @@ -49,17 +143,21 @@ 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 { +func (fd *netFD) closeRead() error { if !fd.ok() { return syscall.EINVAL } return syscall.EPLAN9 } -func (fd *netFD) CloseWrite() error { +func (fd *netFD) closeWrite() error { if !fd.ok() { return syscall.EINVAL } @@ -67,6 +165,9 @@ func (fd *netFD) CloseWrite() error { } func (fd *netFD) Close() error { + if !fd.fdmu.IncrefAndClose() { + return errClosing + } if !fd.ok() { return syscall.EINVAL } |