runner: syncronize shimListener connChan access

Concurrent writes and closes on a channel are a data race. The
shimListener connChan is written to by the shimDispatcher and closed by
the shimListener such that the operations can happen concurrently.

There is already a lock on shimListener to set the error and close the
channel, so reuse that lock to syncronize the writes to the channel as
well. This is slightly slower, but that should be fine. Ideally the
write and close operations would be more tightly coupled, but that would
require a more significant refactor, the shape of which is not obvious.

Change-Id: I534aebacaa3c99a18d34858fa1ca7686727fdada
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/88907
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/shim_dispatcher.go b/ssl/test/runner/shim_dispatcher.go
index 4fd421f..04303e6 100644
--- a/ssl/test/runner/shim_dispatcher.go
+++ b/ssl/test/runner/shim_dispatcher.go
@@ -113,7 +113,16 @@
 		return fmt.Errorf("shim ID %d not found", shimID)
 	}
 
+	// Concurrent channel writes and closes can cause data races. Locking
+	// ensures that the channel is not closed while we are writing to it. This
+	// is slightly slower, but that should be fine.
+	shim.lock.Lock()
+	defer shim.lock.Unlock()
+	if shim.err != nil {
+		return fmt.Errorf("shim ID %d has been closed", shimID)
+	}
 	shim.connChan <- conn
+
 	return nil
 }