瀏覽代碼

daemon/logger: fix races in channel close

it's actually not okay to do such trick from multiple goroutines

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Alexander Morozov 9 年之前
父節點
當前提交
378f0657f9
共有 2 個文件被更改,包括 11 次插入12 次删除
  1. 7 8
      daemon/logger/copier.go
  2. 4 4
      daemon/logger/logger.go

+ 7 - 8
daemon/logger/copier.go

@@ -14,10 +14,11 @@ import (
 // Writes are concurrent, so you need implement some sync in your logger
 type Copier struct {
 	// srcs is map of name -> reader pairs, for example "stdout", "stderr"
-	srcs     map[string]io.Reader
-	dst      Logger
-	copyJobs sync.WaitGroup
-	closed   chan struct{}
+	srcs      map[string]io.Reader
+	dst       Logger
+	copyJobs  sync.WaitGroup
+	closeOnce sync.Once
+	closed    chan struct{}
 }
 
 // NewCopier creates a new Copier
@@ -74,9 +75,7 @@ func (c *Copier) Wait() {
 
 // Close closes the copier
 func (c *Copier) Close() {
-	select {
-	case <-c.closed:
-	default:
+	c.closeOnce.Do(func() {
 		close(c.closed)
-	}
+	})
 }

+ 4 - 4
daemon/logger/logger.go

@@ -11,6 +11,7 @@ import (
 	"errors"
 	"sort"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/docker/docker/pkg/jsonlog"
@@ -83,6 +84,7 @@ type LogWatcher struct {
 	Msg chan *Message
 	// For sending error messages that occur while while reading logs.
 	Err           chan error
+	closeOnce     sync.Once
 	closeNotifier chan struct{}
 }
 
@@ -98,11 +100,9 @@ func NewLogWatcher() *LogWatcher {
 // Close notifies the underlying log reader to stop.
 func (w *LogWatcher) Close() {
 	// only close if not already closed
-	select {
-	case <-w.closeNotifier:
-	default:
+	w.closeOnce.Do(func() {
 		close(w.closeNotifier)
-	}
+	})
 }
 
 // WatchClose returns a channel receiver that receives notification