From 0bdfcfaa33b4945fdfd6ff9ea82bf3c5aa63848d Mon Sep 17 00:00:00 2001 From: Robert Obryk Date: Sat, 30 Mar 2013 14:37:06 +0100 Subject: [PATCH] Make writeBroadcaster safe for concurrent use. --- utils.go | 12 +++++++++++- utils_test.go | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/utils.go b/utils.go index fbbad34081..f6afb9f23c 100644 --- a/utils.go +++ b/utils.go @@ -213,15 +213,21 @@ func (r *bufReader) Close() error { } type writeBroadcaster struct { + mu sync.Mutex writers *list.List } func (w *writeBroadcaster) AddWriter(writer io.WriteCloser) { + w.mu.Lock() w.writers.PushBack(writer) + w.mu.Unlock() } // FIXME: Is that function used? +// FIXME: This relies on the concrete writer type used having equality operator func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) { + w.mu.Lock() + defer w.mu.Unlock() for e := w.writers.Front(); e != nil; e = e.Next() { v := e.Value.(io.Writer) if v == writer { @@ -232,6 +238,8 @@ func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) { } func (w *writeBroadcaster) Write(p []byte) (n int, err error) { + w.mu.Lock() + defer w.mu.Unlock() failed := []*list.Element{} for e := w.writers.Front(); e != nil; e = e.Next() { writer := e.Value.(io.Writer) @@ -249,6 +257,8 @@ func (w *writeBroadcaster) Write(p []byte) (n int, err error) { } func (w *writeBroadcaster) Close() error { + w.mu.Lock() + defer w.mu.Unlock() for e := w.writers.Front(); e != nil; e = e.Next() { writer := e.Value.(io.WriteCloser) writer.Close() @@ -258,5 +268,5 @@ func (w *writeBroadcaster) Close() error { } func newWriteBroadcaster() *writeBroadcaster { - return &writeBroadcaster{list.New()} + return &writeBroadcaster{writers: list.New()} } diff --git a/utils_test.go b/utils_test.go index dbdcda434c..c32b7bc7f9 100644 --- a/utils_test.go +++ b/utils_test.go @@ -124,3 +124,25 @@ func TestWriteBroadcaster(t *testing.T) { writer.Close() } + +type devNullCloser int + +func (d devNullCloser) Close() error { + return nil +} + +func (d devNullCloser) Write(buf []byte) (int, error) { + return len(buf), nil +} + +// This test checks for races. It is only useful when run with the race detector. +func TestRaceWriteBroadcaster(t *testing.T) { + writer := newWriteBroadcaster() + c := make(chan bool) + go func() { + writer.AddWriter(devNullCloser(0)) + c <- true + }() + writer.Write([]byte("hello")) + <-c +}