events: ensure event callbacks are threadsafe

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@redhat.com>

Related to: rhbz#1243228
This commit is contained in:
Fabiano Fidêncio 2015-07-22 02:48:05 +02:00
parent 3cbb6232f3
commit 8a2420ecdf

View File

@ -34,6 +34,8 @@
#include "virt-viewer-events.h"
static GMutex *eventlock = NULL;
struct virt_viewer_events_handle
{
int watch;
@ -85,6 +87,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 +122,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 +144,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 +175,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 +206,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 +267,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 +289,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 +313,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 +335,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 +365,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,