Merge pull request #65 from darrenstahlmsft/waitGroup

Prevent adding to a sync.WaitGroup that has a waiter
This commit is contained in:
John Starks
2017-08-04 13:09:54 -07:00
committed by GitHub
2 changed files with 11 additions and 1 deletions
+8
View File
@@ -78,6 +78,7 @@ func initIo() {
type win32File struct { type win32File struct {
handle syscall.Handle handle syscall.Handle
wg sync.WaitGroup wg sync.WaitGroup
wgLock sync.RWMutex
closing atomicBool closing atomicBool
readDeadline deadlineHandler readDeadline deadlineHandler
writeDeadline deadlineHandler writeDeadline deadlineHandler
@@ -114,14 +115,18 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
// closeHandle closes the resources associated with a Win32 handle // closeHandle closes the resources associated with a Win32 handle
func (f *win32File) closeHandle() { func (f *win32File) closeHandle() {
f.wgLock.Lock()
// Atomically set that we are closing, releasing the resources only once. // Atomically set that we are closing, releasing the resources only once.
if !f.closing.swap(true) { if !f.closing.swap(true) {
f.wgLock.Unlock()
// cancel all IO and wait for it to complete // cancel all IO and wait for it to complete
cancelIoEx(f.handle, nil) cancelIoEx(f.handle, nil)
f.wg.Wait() f.wg.Wait()
// at this point, no new IO can start // at this point, no new IO can start
syscall.Close(f.handle) syscall.Close(f.handle)
f.handle = 0 f.handle = 0
} else {
f.wgLock.Unlock()
} }
} }
@@ -134,10 +139,13 @@ func (f *win32File) Close() error {
// prepareIo prepares for a new IO operation. // prepareIo prepares for a new IO operation.
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. // The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
func (f *win32File) prepareIo() (*ioOperation, error) { func (f *win32File) prepareIo() (*ioOperation, error) {
f.wgLock.RLock()
if f.closing.isSet() { if f.closing.isSet() {
f.wgLock.RUnlock()
return nil, ErrFileClosed return nil, ErrFileClosed
} }
f.wg.Add(1) f.wg.Add(1)
f.wgLock.RUnlock()
c := &ioOperation{} c := &ioOperation{}
c.ch = make(chan ioResult) c.ch = make(chan ioResult)
return c, nil return c, nil
+3 -1
View File
@@ -367,11 +367,11 @@ func TestEchoWithMessaging(t *testing.T) {
OutputBufferSize: 65536, OutputBufferSize: 65536,
} }
l, err := ListenPipe(testPipeName, &c) l, err := ListenPipe(testPipeName, &c)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer l.Close() defer l.Close()
listenerDone := make(chan bool) listenerDone := make(chan bool)
clientDone := make(chan bool) clientDone := make(chan bool)
go func() { go func() {
@@ -380,6 +380,8 @@ func TestEchoWithMessaging(t *testing.T) {
if e != nil { if e != nil {
t.Fatal(e) t.Fatal(e)
} }
defer conn.Close()
time.Sleep(500 * time.Millisecond) // make *sure* we don't begin to read before eof signal is sent time.Sleep(500 * time.Millisecond) // make *sure* we don't begin to read before eof signal is sent
io.Copy(conn, conn) io.Copy(conn, conn)
conn.(CloseWriter).CloseWrite() conn.(CloseWriter).CloseWrite()