[lxc-devel] [lxd/master] lxd/events: Fix race condition in event handlers

stgraber on Github lxc-bot at linuxcontainers.org
Wed Sep 6 05:11:38 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 579 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170906/6cb3f7e5/attachment.bin>
-------------- next part --------------
From 602b7292771fd1828a7b566868c2711446485624 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 6 Sep 2017 01:10:22 -0400
Subject: [PATCH] lxd/events: Fix race condition in event handlers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This adds additional locking around the event handler code to ensure
that there is no race between the time where we first fail to send a
message and the time where the listener is removed from the list.

Closes #3770

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/events.go | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/lxd/events.go b/lxd/events.go
index df3bdc600..d7aed0422 100644
--- a/lxd/events.go
+++ b/lxd/events.go
@@ -51,7 +51,8 @@ type eventListener struct {
 	messageTypes []string
 	active       chan bool
 	id           string
-	msgLock      sync.Mutex
+	lock         sync.Mutex
+	done         bool
 }
 
 type eventsServe struct {
@@ -92,13 +93,6 @@ func eventsSocket(r *http.Request, w http.ResponseWriter) error {
 
 	<-listener.active
 
-	eventsLock.Lock()
-	delete(eventListeners, listener.id)
-	eventsLock.Unlock()
-
-	listener.connection.Close()
-	logger.Debugf("Disconnected events listener: %s", listener.id)
-
 	return nil
 }
 
@@ -127,16 +121,32 @@ func eventSend(eventType string, eventMessage interface{}) error {
 		}
 
 		go func(listener *eventListener, body []byte) {
+			// Check that the listener still exists
 			if listener == nil {
 				return
 			}
 
-			listener.msgLock.Lock()
-			err = listener.connection.WriteMessage(websocket.TextMessage, body)
-			listener.msgLock.Unlock()
+			// Ensure there is only a single even going out at the time
+			listener.lock.Lock()
+			defer listener.lock.Unlock()
 
+			// Make sure we're not done already
+			if listener.done {
+				return
+			}
+
+			err = listener.connection.WriteMessage(websocket.TextMessage, body)
 			if err != nil {
+				// Remove the listener from the list
+				eventsLock.Lock()
+				delete(eventListeners, listener.id)
+				eventsLock.Unlock()
+
+				// Disconnect the listener
+				listener.connection.Close()
 				listener.active <- false
+				listener.done = true
+				logger.Debugf("Disconnected events listener: %s", listener.id)
 			}
 		}(listener, body)
 	}


More information about the lxc-devel mailing list