}
}
+// readWriteLock adds a reference to fd and locks fd for reading and writing.
+// It returns an error when fd cannot be used for reading and writing.
+func (fd *FD) readWriteLock() error {
+ if !fd.fdmu.rwlock(true) || !fd.fdmu.rwlock(false) {
+ return errClosing(fd.isFile)
+ }
+ return nil
+}
+
+// readWriteUnlock removes a reference from fd and unlocks fd for reading and writing.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *FD) readWriteUnlock() {
+ fd.fdmu.rwunlock(true)
+ fd.fdmu.rwunlock(false)
+}
+
// closing returns true if fd is closing.
func (fd *FD) closing() bool {
return atomic.LoadUint64(&fd.fdmu.state)&mutexClosed != 0
// I/O poller.
pd pollDesc
- // Used to implement pread/pwrite.
- l sync.Mutex
-
// The file offset for the next read or write.
// Overlapped IO operations don't use the real file pointer,
// so we need to keep track of the offset ourselves.
}
// setOffset sets the offset fields of the overlapped object
-// to the given offset. The fd.l lock must be held.
+// to the given offset. The fd read/write lock must be held.
//
// Overlapped IO operations don't update the offset fields
// of the overlapped object nor the file pointer automatically,
// Read implements io.Reader.
func (fd *FD) Read(buf []byte) (int, error) {
- if err := fd.readLock(); err != nil {
- return 0, err
- }
- defer fd.readUnlock()
if fd.kind == kindFile {
- fd.l.Lock()
- defer fd.l.Unlock()
+ if err := fd.readWriteLock(); err != nil {
+ return 0, err
+ }
+ defer fd.readWriteUnlock()
+ } else {
+ if err := fd.readLock(); err != nil {
+ return 0, err
+ }
+ defer fd.readUnlock()
}
if len(buf) > maxRW {
// Pread does not work with pipes
return 0, syscall.ESPIPE
}
- // Call incref, not readLock, because since pread specifies the
- // offset it is independent from other reads.
- if err := fd.incref(); err != nil {
+
+ if err := fd.readWriteLock(); err != nil {
return 0, err
}
- defer fd.decref()
+ defer fd.readWriteUnlock()
if len(b) > maxRW {
b = b[:maxRW]
}
- fd.l.Lock()
- defer fd.l.Unlock()
if fd.isBlocking {
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
if err != nil {
// Write implements io.Writer.
func (fd *FD) Write(buf []byte) (int, error) {
- if err := fd.writeLock(); err != nil {
- return 0, err
- }
- defer fd.writeUnlock()
if fd.kind == kindFile {
- fd.l.Lock()
- defer fd.l.Unlock()
+ if err := fd.readWriteLock(); err != nil {
+ return 0, err
+ }
+ defer fd.readWriteUnlock()
+ } else {
+ if err := fd.writeLock(); err != nil {
+ return 0, err
+ }
+ defer fd.writeUnlock()
}
var ntotal int
// Pwrite does not work with pipes
return 0, syscall.ESPIPE
}
- // Call incref, not writeLock, because since pwrite specifies the
- // offset it is independent from other writes.
- if err := fd.incref(); err != nil {
+
+ if err := fd.readWriteLock(); err != nil {
return 0, err
}
- defer fd.decref()
+ defer fd.readWriteUnlock()
- fd.l.Lock()
- defer fd.l.Unlock()
if fd.isBlocking {
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
if err != nil {
if fd.kind == kindPipe {
return 0, syscall.ESPIPE
}
- if err := fd.incref(); err != nil {
+ if err := fd.readWriteLock(); err != nil {
return 0, err
}
- defer fd.decref()
-
- fd.l.Lock()
- defer fd.l.Unlock()
+ defer fd.readWriteUnlock()
if !fd.isBlocking && whence == io.SeekCurrent {
// Windows doesn't keep the file pointer for overlapped file handles.