fix data races around use of l.closed

fixes #1
This commit is contained in:
Naitik Shah 2013-03-27 18:29:36 -07:00
parent 3efb5417dc
commit 40271cd1a7

View File

@ -59,7 +59,6 @@ type Listener interface {
// A goroutine based counter that provides graceful Close for listeners. // A goroutine based counter that provides graceful Close for listeners.
type listener struct { type listener struct {
FileListener FileListener
closed bool // Indicates we're already closed.
closeRequest chan bool // Send a bool here to indicate we want to Close. closeRequest chan bool // Send a bool here to indicate we want to Close.
allClosed chan bool // Receive from here will indicate a clean Close. allClosed chan bool // Receive from here will indicate a clean Close.
counter chan bool // Use the inc/dec counters. counter chan bool // Use the inc/dec counters.
@ -94,7 +93,7 @@ func (l *listener) enabler() {
for { for {
select { select {
case <-l.closeRequest: case <-l.closeRequest:
l.closed = true l.closeRequest = nil
case change = <-l.counter: case change = <-l.counter:
if change == inc { if change == inc {
counter++ counter++
@ -102,19 +101,20 @@ func (l *listener) enabler() {
counter-- counter--
} }
} }
if l.closed && counter == 0 { if l.closeRequest == nil && counter == 0 {
l.allClosed <- true close(l.allClosed)
break break
} }
} }
} }
func (l *listener) CloseRequest() { func (l *listener) CloseRequest() {
if l.closed == true { select {
case l.closeRequest <- true:
<-l.allClosed
case <-l.allClosed:
return return
} }
l.closeRequest <- true
<-l.allClosed
} }
func (l *listener) Close() error { func (l *listener) Close() error {
@ -123,21 +123,23 @@ func (l *listener) Close() error {
} }
func (l *listener) Accept() (net.Conn, error) { func (l *listener) Accept() (net.Conn, error) {
if l.closed == true { select {
case <-l.allClosed:
return nil, ErrAlreadyClosed return nil, ErrAlreadyClosed
} default:
c, err := l.FileListener.Accept() c, err := l.FileListener.Accept()
if err != nil { if err != nil {
if strings.HasSuffix(err.Error(), errClosed) { if strings.HasSuffix(err.Error(), errClosed) {
return nil, ErrAlreadyClosed return nil, ErrAlreadyClosed
}
return nil, err
} }
return nil, err l.counter <- inc
return conn{
Conn: c,
counter: l.counter,
}, nil
} }
l.counter <- inc
return conn{
Conn: c,
counter: l.counter,
}, nil
} }
// Wait for signals to gracefully terminate or restart the process. // Wait for signals to gracefully terminate or restart the process.