[virt-tools-list] [virt-viewer v2 01/13] events: ensure event callbacks are threadsafe

Fabiano Fidêncio fidencio at redhat.com
Wed Jul 22 08:04:28 UTC 2015


Take a global lock whenever changing any event callbacks to ensure
thread safety.

Based on commit f1fe67da2dac6a249f796535b8dbd155d5741ad7 from
libvirt-glib.
Original author: Daniel P. Berrange <berrange at redhat.com>

Related to: rhbz#1243228
---
 src/virt-viewer-events.c | 84 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 66 insertions(+), 18 deletions(-)

diff --git a/src/virt-viewer-events.c b/src/virt-viewer-events.c
index 3b5a136..b0a84ba 100644
--- a/src/virt-viewer-events.c
+++ b/src/virt-viewer-events.c
@@ -33,6 +33,9 @@
 #include <libvirt/libvirt.h>
 
 #include "virt-viewer-events.h"
+#include "virt-glib-compat.h"
+
+static GMutex *eventlock = NULL;
 
 struct virt_viewer_events_handle
 {
@@ -85,6 +88,9 @@ int virt_viewer_events_add_handle(int fd,
 {
     struct virt_viewer_events_handle *data;
     GIOCondition cond = 0;
+    int ret;
+
+    g_mutex_lock(eventlock);
 
     handles = g_realloc(handles, sizeof(*handles)*(nhandles+1));
     data = g_malloc(sizeof(*data));
@@ -117,7 +123,11 @@ int virt_viewer_events_add_handle(int fd,
 
     handles[nhandles++] = data;
 
-    return data->watch;
+    ret = data->watch;
+
+    g_mutex_unlock(eventlock);
+
+    return ret;
 }
 
 static struct virt_viewer_events_handle *
@@ -135,17 +145,21 @@ static void
 virt_viewer_events_update_handle(int watch,
                                  int events)
 {
-    struct virt_viewer_events_handle *data = virt_viewer_events_find_handle(watch);
+    struct virt_viewer_events_handle *data;
+
+    g_mutex_lock(eventlock);
+
+    data = virt_viewer_events_find_handle(watch);
 
     if (!data) {
         g_debug("Update for missing handle watch %d", watch);
-        return;
+        goto cleanup;
     }
 
     if (events) {
         GIOCondition cond = 0;
         if (events == data->events)
-            return;
+            goto cleanup;
 
         if (data->source)
             g_source_remove(data->source);
@@ -162,12 +176,15 @@ virt_viewer_events_update_handle(int watch,
         data->events = events;
     } else {
         if (!data->source)
-            return;
+            goto cleanup;
 
         g_source_remove(data->source);
         data->source = 0;
         data->events = 0;
     }
+
+cleanup:
+    g_mutex_unlock(eventlock);
 }
 
 
@@ -190,24 +207,33 @@ virt_viewer_events_cleanup_handle(gpointer user_data)
 static int
 virt_viewer_events_remove_handle(int watch)
 {
-    struct virt_viewer_events_handle *data = virt_viewer_events_find_handle(watch);
+    struct virt_viewer_events_handle *data;
+    int ret = -1;
+
+    g_mutex_lock(eventlock);
+
+    data = virt_viewer_events_find_handle(watch);
 
     if (!data) {
         g_debug("Remove of missing watch %d", watch);
-        return -1;
+        goto cleanup;
     }
 
     g_debug("Remove handle %d %d", watch, data->fd);
 
     if (!data->source)
-        return -1;
+        goto cleanup;
 
     g_source_remove(data->source);
     data->source = 0;
     data->events = 0;
 
     g_idle_add(virt_viewer_events_cleanup_handle, data);
-    return 0;
+    ret = 0;
+
+cleanup:
+    g_mutex_unlock(eventlock);
+    return ret;
 }
 
 struct virt_viewer_events_timeout
@@ -242,6 +268,9 @@ virt_viewer_events_add_timeout(int interval,
                                virFreeCallback ff)
 {
     struct virt_viewer_events_timeout *data;
+    int ret;
+
+    g_mutex_lock(eventlock);
 
     timeouts = g_realloc(timeouts, sizeof(*timeouts)*(ntimeouts+1));
     data = g_malloc(sizeof(*data));
@@ -261,7 +290,11 @@ virt_viewer_events_add_timeout(int interval,
 
     g_debug("Add timeout %p %d %p %p %d", data, interval, cb, opaque, data->timer);
 
-    return data->timer;
+    ret = data->timer;
+
+    g_mutex_unlock(eventlock);
+
+    return ret;
 }
 
 
@@ -281,18 +314,21 @@ static void
 virt_viewer_events_update_timeout(int timer,
                                   int interval)
 {
-    struct virt_viewer_events_timeout *data = virt_viewer_events_find_timeout(timer);
+    struct virt_viewer_events_timeout *data;
 
+    g_mutex_lock(eventlock);
+
+    data = virt_viewer_events_find_timeout(timer);
     if (!data) {
         g_debug("Update of missing timer %d", timer);
-        return;
+        goto cleanup;
     }
 
     g_debug("Update timeout %p %d %d", data, timer, interval);
 
     if (interval >= 0) {
         if (data->source)
-            return;
+            goto cleanup;
 
         data->interval = interval;
         data->source = g_timeout_add(data->interval,
@@ -300,11 +336,14 @@ virt_viewer_events_update_timeout(int timer,
                                      data);
     } else {
         if (!data->source)
-            return;
+            goto cleanup;
 
         g_source_remove(data->source);
         data->source = 0;
     }
+
+cleanup:
+    g_mutex_unlock(eventlock);
 }
 
 
@@ -327,27 +366,36 @@ virt_viewer_events_cleanup_timeout(gpointer user_data)
 static int
 virt_viewer_events_remove_timeout(int timer)
 {
-    struct virt_viewer_events_timeout *data = virt_viewer_events_find_timeout(timer);
+    struct virt_viewer_events_timeout *data;
+    int ret = -1;
 
+    g_mutex_lock(eventlock);
+
+    data = virt_viewer_events_find_timeout(timer);
     if (!data) {
         g_debug("Remove of missing timer %d", timer);
-        return -1;
+        goto cleanup;
     }
 
     g_debug("Remove timeout %p %d", data, timer);
 
     if (!data->source)
-        return -1;
+        goto cleanup;
 
     g_source_remove(data->source);
     data->source = 0;
 
     g_idle_add(virt_viewer_events_cleanup_timeout, data);
-    return 0;
+    ret = 0;
+
+cleanup:
+    g_mutex_unlock(eventlock);
+    return ret;
 }
 
 
 void virt_viewer_events_register(void) {
+    eventlock = g_mutex_new();
     virEventRegisterImpl(virt_viewer_events_add_handle,
                          virt_viewer_events_update_handle,
                          virt_viewer_events_remove_handle,
-- 
2.4.4




More information about the virt-tools-list mailing list