Browse code

Make writeBroadcaster safe for concurrent use.

Robert Obryk authored on 2013/03/30 22:37:06
Showing 2 changed files
... ...
@@ -213,15 +213,21 @@ func (r *bufReader) Close() error {
213 213
 }
214 214
 
215 215
 type writeBroadcaster struct {
216
+	mu      sync.Mutex
216 217
 	writers *list.List
217 218
 }
218 219
 
219 220
 func (w *writeBroadcaster) AddWriter(writer io.WriteCloser) {
221
+	w.mu.Lock()
220 222
 	w.writers.PushBack(writer)
223
+	w.mu.Unlock()
221 224
 }
222 225
 
223 226
 // FIXME: Is that function used?
227
+// FIXME: This relies on the concrete writer type used having equality operator
224 228
 func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) {
229
+	w.mu.Lock()
230
+	defer w.mu.Unlock()
225 231
 	for e := w.writers.Front(); e != nil; e = e.Next() {
226 232
 		v := e.Value.(io.Writer)
227 233
 		if v == writer {
... ...
@@ -232,6 +238,8 @@ func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) {
232 232
 }
233 233
 
234 234
 func (w *writeBroadcaster) Write(p []byte) (n int, err error) {
235
+	w.mu.Lock()
236
+	defer w.mu.Unlock()
235 237
 	failed := []*list.Element{}
236 238
 	for e := w.writers.Front(); e != nil; e = e.Next() {
237 239
 		writer := e.Value.(io.Writer)
... ...
@@ -249,6 +257,8 @@ func (w *writeBroadcaster) Write(p []byte) (n int, err error) {
249 249
 }
250 250
 
251 251
 func (w *writeBroadcaster) Close() error {
252
+	w.mu.Lock()
253
+	defer w.mu.Unlock()
252 254
 	for e := w.writers.Front(); e != nil; e = e.Next() {
253 255
 		writer := e.Value.(io.WriteCloser)
254 256
 		writer.Close()
... ...
@@ -258,5 +268,5 @@ func (w *writeBroadcaster) Close() error {
258 258
 }
259 259
 
260 260
 func newWriteBroadcaster() *writeBroadcaster {
261
-	return &writeBroadcaster{list.New()}
261
+	return &writeBroadcaster{writers: list.New()}
262 262
 }
... ...
@@ -124,3 +124,25 @@ func TestWriteBroadcaster(t *testing.T) {
124 124
 
125 125
 	writer.Close()
126 126
 }
127
+
128
+type devNullCloser int
129
+
130
+func (d devNullCloser) Close() error {
131
+	return nil
132
+}
133
+
134
+func (d devNullCloser) Write(buf []byte) (int, error) {
135
+	return len(buf), nil
136
+}
137
+
138
+// This test checks for races. It is only useful when run with the race detector.
139
+func TestRaceWriteBroadcaster(t *testing.T) {
140
+	writer := newWriteBroadcaster()
141
+	c := make(chan bool)
142
+	go func() {
143
+		writer.AddWriter(devNullCloser(0))
144
+		c <- true
145
+	}()
146
+	writer.Write([]byte("hello"))
147
+	<-c
148
+}