[spice-server,2/2] event-loop: Change internal core interface

Submitted by Frediano Ziglio on Aug. 6, 2019, 2:52 p.m.

Details

Message ID 20190806145250.31813-2-fziglio@redhat.com
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Frediano Ziglio Aug. 6, 2019, 2:52 p.m.
Allow to modify/cancel timers/watches without having to retrieve
the code interface.
This will make sure that you are not using the wrong interface.
Simplify code to deal with timers/watches.
Remove the requirement to have the core interface available
for removing timers/watches.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
---
 server/char-device.c            |  28 ++---
 server/event-loop.c             | 206 ++++++++++++++++++++++++--------
 server/inputs-channel.c         |   6 +-
 server/main-dispatcher.c        |   2 +-
 server/red-channel-client.c     |  43 +++----
 server/red-common.h             |  15 ++-
 server/red-stream-device.c      |   5 +-
 server/red-stream.c             |   2 +-
 server/red-worker.c             |   2 +-
 server/reds.c                   |  69 ++---------
 server/reds.h                   |  12 --
 server/tests/basic-event-loop.c |  35 +-----
 12 files changed, 211 insertions(+), 214 deletions(-)

Patch hide | download patch | download mbox

diff --git a/server/char-device.c b/server/char-device.c
index cfcc29da0..1ac54d5c5 100644
--- a/server/char-device.c
+++ b/server/char-device.c
@@ -163,7 +163,7 @@  static void red_char_device_client_free(RedCharDevice *dev,
 {
     GList *l, *next;
 
-    reds_core_timer_remove(dev->priv->reds, dev_client->wait_for_tokens_timer);
+    red_timer_remove(dev_client->wait_for_tokens_timer);
     dev_client->wait_for_tokens_timer = NULL;
 
     g_queue_free_full(dev_client->send_queue, (GDestroyNotify)red_pipe_item_unref);
@@ -249,8 +249,6 @@  static uint64_t red_char_device_max_send_tokens(RedCharDevice *dev)
 static void red_char_device_add_msg_to_client_queue(RedCharDeviceClient *dev_client,
                                                     RedPipeItem *msg)
 {
-    RedCharDevice *dev = dev_client->dev;
-
     if (g_queue_get_length(dev_client->send_queue) >= dev_client->max_send_queue_size) {
         red_char_device_handle_client_overflow(dev_client);
         return;
@@ -259,8 +257,8 @@  static void red_char_device_add_msg_to_client_queue(RedCharDeviceClient *dev_cli
     red_pipe_item_ref(msg);
     g_queue_push_head(dev_client->send_queue, msg);
     if (!dev_client->wait_for_tokens_started) {
-        reds_core_timer_start(dev->priv->reds, dev_client->wait_for_tokens_timer,
-                              RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT);
+        red_timer_start(dev_client->wait_for_tokens_timer,
+                        RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT);
         dev_client->wait_for_tokens_started = TRUE;
     }
 }
@@ -372,12 +370,12 @@  red_char_device_send_to_client_tokens_absorb(RedCharDevice *dev,
     }
 
     if (red_char_device_can_send_to_client(dev_client)) {
-        reds_core_timer_cancel(dev->priv->reds, dev_client->wait_for_tokens_timer);
+        red_timer_cancel(dev_client->wait_for_tokens_timer);
         dev_client->wait_for_tokens_started = FALSE;
         red_char_device_read_from_device(dev_client->dev);
     } else if (!g_queue_is_empty(dev_client->send_queue)) {
-        reds_core_timer_start(dev->priv->reds, dev_client->wait_for_tokens_timer,
-                              RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT);
+        red_timer_start(dev_client->wait_for_tokens_timer,
+                        RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT);
         dev_client->wait_for_tokens_started = TRUE;
     }
 }
@@ -438,7 +436,7 @@  static int red_char_device_write_to_device(RedCharDevice *dev)
     g_object_ref(dev);
 
     if (dev->priv->write_to_dev_timer) {
-        reds_core_timer_cancel(dev->priv->reds, dev->priv->write_to_dev_timer);
+        red_timer_cancel(dev->priv->write_to_dev_timer);
     }
 
     sif = spice_char_device_get_interface(dev->priv->sin);
@@ -475,8 +473,8 @@  static int red_char_device_write_to_device(RedCharDevice *dev)
     if (dev->priv->running) {
         if (dev->priv->cur_write_buf) {
             if (dev->priv->write_to_dev_timer) {
-                reds_core_timer_start(dev->priv->reds, dev->priv->write_to_dev_timer,
-                                      CHAR_DEVICE_WRITE_TO_TIMEOUT);
+                red_timer_start(dev->priv->write_to_dev_timer,
+                                CHAR_DEVICE_WRITE_TO_TIMEOUT);
             }
         } else {
             spice_assert(g_queue_is_empty(&dev->priv->write_queue));
@@ -493,7 +491,7 @@  static void red_char_device_write_retry(void *opaque)
     RedCharDevice *dev = opaque;
 
     if (dev->priv->write_to_dev_timer) {
-        reds_core_timer_cancel(dev->priv->reds, dev->priv->write_to_dev_timer);
+        red_timer_cancel(dev->priv->write_to_dev_timer);
     }
     red_char_device_write_to_device(dev);
 }
@@ -762,7 +760,7 @@  void red_char_device_stop(RedCharDevice *dev)
     dev->priv->running = FALSE;
     dev->priv->active = FALSE;
     if (dev->priv->write_to_dev_timer) {
-        reds_core_timer_cancel(dev->priv->reds, dev->priv->write_to_dev_timer);
+        red_timer_cancel(dev->priv->write_to_dev_timer);
     }
 }
 
@@ -947,7 +945,7 @@  static void red_char_device_init_device_instance(RedCharDevice *self)
 
     g_return_if_fail(self->priv->reds);
 
-    reds_core_timer_remove(self->priv->reds, self->priv->write_to_dev_timer);
+    red_timer_remove(self->priv->write_to_dev_timer);
     self->priv->write_to_dev_timer = NULL;
 
     if (self->priv->sin == NULL) {
@@ -1037,7 +1035,7 @@  red_char_device_finalize(GObject *object)
 {
     RedCharDevice *self = RED_CHAR_DEVICE(object);
 
-    reds_core_timer_remove(self->priv->reds, self->priv->write_to_dev_timer);
+    red_timer_remove(self->priv->write_to_dev_timer);
     self->priv->write_to_dev_timer = NULL;
 
     write_buffers_queue_free(&self->priv->write_queue);
diff --git a/server/event-loop.c b/server/event-loop.c
index 1ccfd671f..6d2de95f2 100644
--- a/server/event-loop.c
+++ b/server/event-loop.c
@@ -25,28 +25,83 @@ 
 
 #include "red-common.h"
 
+typedef struct SpiceCoreFuncs {
+    void (*timer_start)(SpiceTimer *timer, uint32_t ms);
+    void (*timer_cancel)(SpiceTimer *timer);
+    void (*timer_remove)(SpiceTimer *timer);
+    void (*watch_update_mask)(SpiceWatch *watch, int event_mask);
+    void (*watch_remove)(SpiceWatch *watch);
+} SpiceCoreFuncs;
+
 struct SpiceTimer {
+    const SpiceCoreFuncs *funcs;
+};
+
+struct SpiceWatch {
+    const SpiceCoreFuncs *funcs;
+};
+
+void red_timer_start(SpiceTimer *timer, uint32_t ms)
+{
+    if (timer) {
+        timer->funcs->timer_start(timer, ms);
+    }
+}
+
+void red_timer_cancel(SpiceTimer *timer)
+{
+    if (timer) {
+        timer->funcs->timer_cancel(timer);
+    }
+}
+
+void red_timer_remove(SpiceTimer *timer)
+{
+    if (timer) {
+        timer->funcs->timer_remove(timer);
+    }
+}
+
+void red_watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+    if (watch) {
+        watch->funcs->watch_update_mask(watch, event_mask);
+    }
+}
+
+void red_watch_remove(SpiceWatch *watch)
+{
+    if (watch) {
+        watch->funcs->watch_remove(watch);
+    }
+}
+
+static const SpiceCoreFuncs glib_core_funcs;
+
+typedef struct SpiceTimerGlib {
+    SpiceTimer base;
     GMainContext *context;
     SpiceTimerFunc func;
     void *opaque;
     GSource *source;
-};
+} SpiceTimerGlib;
 
 static SpiceTimer* timer_add(const SpiceCoreInterfaceInternal *iface,
                              SpiceTimerFunc func, void *opaque)
 {
-    SpiceTimer *timer = g_new0(SpiceTimer, 1);
+    SpiceTimerGlib *timer = g_new0(SpiceTimerGlib, 1);
 
+    timer->base.funcs = &glib_core_funcs;
     timer->context = iface->main_context;
     timer->func = func;
     timer->opaque = opaque;
 
-    return timer;
+    return &timer->base;
 }
 
 static gboolean timer_func(gpointer user_data)
 {
-    SpiceTimer *timer = user_data;
+    SpiceTimerGlib *timer = (SpiceTimerGlib*) user_data;
 
     timer->func(timer->opaque);
     /* timer might be free after func(), don't touch */
@@ -54,9 +109,9 @@  static gboolean timer_func(gpointer user_data)
     return FALSE;
 }
 
-static void timer_cancel(const SpiceCoreInterfaceInternal *iface,
-                         SpiceTimer *timer)
+static void timer_cancel(SpiceTimer *timer_base)
 {
+    SpiceTimerGlib *timer = SPICE_UPCAST(SpiceTimerGlib, timer_base);
     if (timer->source) {
         g_source_destroy(timer->source);
         g_source_unref(timer->source);
@@ -64,10 +119,11 @@  static void timer_cancel(const SpiceCoreInterfaceInternal *iface,
     }
 }
 
-static void timer_start(const SpiceCoreInterfaceInternal *iface,
-                        SpiceTimer *timer, uint32_t ms)
+static void timer_start(SpiceTimer *timer_base, uint32_t ms)
 {
-    timer_cancel(iface, timer);
+    timer_cancel(timer_base);
+
+    SpiceTimerGlib *timer = SPICE_UPCAST(SpiceTimerGlib, timer_base);
 
     timer->source = g_timeout_source_new(ms);
     spice_assert(timer->source != NULL);
@@ -77,10 +133,11 @@  static void timer_start(const SpiceCoreInterfaceInternal *iface,
     g_source_attach(timer->source, timer->context);
 }
 
-static void timer_remove(const SpiceCoreInterfaceInternal *iface,
-                         SpiceTimer *timer)
+static void timer_remove(SpiceTimer *timer_base)
 {
-    timer_cancel(iface, timer);
+    timer_cancel(timer_base);
+
+    SpiceTimerGlib *timer = SPICE_UPCAST(SpiceTimerGlib, timer_base);
     spice_assert(timer->source == NULL);
     g_free(timer);
 }
@@ -110,18 +167,19 @@  static int giocondition_to_spice_event(GIOCondition condition)
 }
 
 #ifdef _WIN32
-struct SpiceWatch {
+typedef struct SpiceWatchGlib {
+    SpiceWatch base;
     GMainContext *context;
     void *opaque;
     GSource *source;
     GIOChannel *channel;
     SpiceWatchFunc func;
-};
+} SpiceWatchGlib;
 
 static gboolean watch_func(GIOChannel *source, GIOCondition condition,
                            gpointer data)
 {
-    SpiceWatch *watch = data;
+    SpiceWatchGlib *watch = (SpiceWatchGlib*) data;
     // this works also under Windows despite the name
     int fd = g_io_channel_unix_get_fd(source);
 
@@ -130,9 +188,9 @@  static gboolean watch_func(GIOChannel *source, GIOCondition condition,
     return TRUE;
 }
 
-static void watch_update_mask(const SpiceCoreInterfaceInternal *iface,
-                              SpiceWatch *watch, int event_mask)
+static void watch_update_mask(SpiceWatch *watch_base, int event_mask)
 {
+    SpiceWatchGlib *watch = SPICE_UPCAST(SpiceWatchGlib, watch_base);
     if (watch->source) {
         g_source_destroy(watch->source);
         g_source_unref(watch->source);
@@ -155,26 +213,27 @@  static void watch_update_mask(const SpiceCoreInterfaceInternal *iface,
 static SpiceWatch *watch_add(const SpiceCoreInterfaceInternal *iface,
                              int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
-    SpiceWatch *watch;
+    SpiceWatchGlib *watch;
 
     spice_return_val_if_fail(fd != -1, NULL);
     spice_return_val_if_fail(func != NULL, NULL);
 
-    watch = g_new0(SpiceWatch, 1);
+    watch = g_new0(SpiceWatchGlib, 1);
+    watch->base.funcs = &glib_core_funcs;
     watch->context = iface->main_context;
     watch->channel = g_io_channel_win32_new_socket(fd);
     watch->func = func;
     watch->opaque = opaque;
 
-    watch_update_mask(iface, watch, event_mask);
+    watch_update_mask(&watch->base, event_mask);
 
-    return watch;
+    return &watch->base;
 }
 
-static void watch_remove(const SpiceCoreInterfaceInternal *iface,
-                         SpiceWatch *watch)
+static void watch_remove(SpiceWatch *watch_base)
 {
-    watch_update_mask(iface, watch, 0);
+    SpiceWatchGlib *watch = SPICE_UPCAST(SpiceWatchGlib, watch_base);
+    watch_update_mask(watch_base, 0);
     spice_assert(watch->source == NULL);
 
     g_io_channel_unref(watch->channel);
@@ -183,16 +242,17 @@  static void watch_remove(const SpiceCoreInterfaceInternal *iface,
 
 #else
 
-struct SpiceWatch {
+typedef struct SpiceWatchGlib {
     GSource source;
+    SpiceWatch spice_base;
     gpointer unix_fd;
     int fd;
-};
+} SpiceWatchGlib;
 
 static gboolean
 spice_watch_check(GSource *source)
 {
-    SpiceWatch *watch = SPICE_CONTAINEROF(source, SpiceWatch, source);
+    SpiceWatchGlib *watch = SPICE_CONTAINEROF(source, SpiceWatchGlib, source);
 
     return g_source_query_unix_fd(&watch->source, watch->unix_fd) != 0;
 }
@@ -202,7 +262,7 @@  spice_watch_dispatch(GSource     *source,
                      GSourceFunc  callback,
                      gpointer     user_data)
 {
-    SpiceWatch *watch = SPICE_CONTAINEROF(source, SpiceWatch, source);
+    SpiceWatchGlib *watch = SPICE_CONTAINEROF(source, SpiceWatchGlib, source);
     SpiceWatchFunc func = (SpiceWatchFunc)(void*) callback;
     GIOCondition condition = g_source_query_unix_fd(&watch->source, watch->unix_fd);
 
@@ -217,9 +277,9 @@  static GSourceFuncs spice_watch_funcs = {
     .dispatch = spice_watch_dispatch,
 };
 
-static void watch_update_mask(const SpiceCoreInterfaceInternal *iface,
-                              SpiceWatch *watch, int event_mask)
+static void watch_update_mask(SpiceWatch *watch_base, int event_mask)
 {
+    SpiceWatchGlib *watch = SPICE_CONTAINEROF(watch_base, SpiceWatchGlib, spice_base);
     GIOCondition condition = spice_event_to_giocondition(event_mask);
 
     g_source_modify_unix_fd(&watch->source, watch->unix_fd, condition);
@@ -228,11 +288,14 @@  static void watch_update_mask(const SpiceCoreInterfaceInternal *iface,
 static SpiceWatch *watch_add(const SpiceCoreInterfaceInternal *iface,
                              int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
-    SpiceWatch *watch = (SpiceWatch *) g_source_new(&spice_watch_funcs, sizeof(SpiceWatch));
+    SPICE_VERIFY(SPICE_OFFSETOF(SpiceWatchGlib, source) == 0);
+    SpiceWatchGlib *watch =
+        (SpiceWatchGlib *) g_source_new(&spice_watch_funcs, sizeof(SpiceWatchGlib));
 
     spice_return_val_if_fail(fd != -1, NULL);
     spice_return_val_if_fail(func != NULL, NULL);
 
+    watch->spice_base.funcs = &glib_core_funcs;
     watch->fd = fd;
 
     g_source_set_callback(&watch->source, (GSourceFunc)(void*)(SpiceWatchFunc) func, opaque, NULL);
@@ -242,68 +305,103 @@  static SpiceWatch *watch_add(const SpiceCoreInterfaceInternal *iface,
     GIOCondition condition = spice_event_to_giocondition(event_mask);
     watch->unix_fd = g_source_add_unix_fd(&watch->source, watch->fd, condition);
 
-    return watch;
+    return &watch->spice_base;
 }
 
-static void watch_remove(const SpiceCoreInterfaceInternal *iface,
-                         SpiceWatch *watch)
+static void watch_remove(SpiceWatch *watch_base)
 {
+    SpiceWatchGlib *watch = SPICE_CONTAINEROF(watch_base, SpiceWatchGlib, spice_base);
+
     g_source_remove_unix_fd(&watch->source, watch->unix_fd);
     g_source_destroy(&watch->source);
     g_source_unref(&watch->source);
 }
 #endif
 
-const SpiceCoreInterfaceInternal event_loop_core = {
-    .timer_add = timer_add,
+static const SpiceCoreFuncs glib_core_funcs = {
     .timer_start = timer_start,
     .timer_cancel = timer_cancel,
     .timer_remove = timer_remove,
 
-    .watch_add = watch_add,
     .watch_update_mask = watch_update_mask,
     .watch_remove = watch_remove,
 };
 
+const SpiceCoreInterfaceInternal event_loop_core = {
+    .timer_add = timer_add,
+    .watch_add = watch_add,
+};
+
 /*
  * Adapter for SpiceCodeInterface
  */
 
+static const SpiceCoreFuncs qemu_core_funcs;
+
+typedef struct SpiceTimerQemu {
+    SpiceTimer base;
+    SpiceCoreInterface *core;
+    SpiceTimer *qemu_timer;
+} SpiceTimerQemu;
+
 static SpiceTimer *adapter_timer_add(const SpiceCoreInterfaceInternal *iface, SpiceTimerFunc func, void *opaque)
 {
-    return iface->public_interface->timer_add(func, opaque);
+    SpiceTimerQemu *timer = g_new0(SpiceTimerQemu, 1);
+
+    timer->base.funcs = &qemu_core_funcs;
+    timer->core = iface->public_interface;
+    timer->qemu_timer = timer->core->timer_add(func, opaque);
+    return &timer->base;
 }
 
-static void adapter_timer_start(const SpiceCoreInterfaceInternal *iface, SpiceTimer *timer, uint32_t ms)
+static void adapter_timer_start(SpiceTimer *timer_, uint32_t ms)
 {
-    iface->public_interface->timer_start(timer, ms);
+    SpiceTimerQemu *timer = SPICE_UPCAST(SpiceTimerQemu, timer_);
+    timer->core->timer_start(timer->qemu_timer, ms);
 }
 
-static void adapter_timer_cancel(const SpiceCoreInterfaceInternal *iface, SpiceTimer *timer)
+static void adapter_timer_cancel(SpiceTimer *timer_)
 {
-    iface->public_interface->timer_cancel(timer);
+    SpiceTimerQemu *timer = SPICE_UPCAST(SpiceTimerQemu, timer_);
+    timer->core->timer_cancel(timer->qemu_timer);
 }
 
-static void adapter_timer_remove(const SpiceCoreInterfaceInternal *iface, SpiceTimer *timer)
+static void adapter_timer_remove(SpiceTimer *timer_)
 {
-    iface->public_interface->timer_remove(timer);
+    SpiceTimerQemu *timer = SPICE_UPCAST(SpiceTimerQemu, timer_);
+    timer->core->timer_remove(timer->qemu_timer);
+    g_free(timer);
 }
 
+typedef struct SpiceWatchQemu {
+    SpiceWatch base;
+    SpiceCoreInterface *core;
+    SpiceWatch *qemu_watch;
+} SpiceWatchQemu;
+
 static SpiceWatch *adapter_watch_add(const SpiceCoreInterfaceInternal *iface,
                                      int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
     // note: Qemu API is fine having a SOCKET on Windows
-    return iface->public_interface->watch_add(fd, event_mask, func, opaque);
+    SpiceWatchQemu *watch = g_new0(SpiceWatchQemu, 1);
+
+    watch->base.funcs = &qemu_core_funcs;
+    watch->core = iface->public_interface;
+    watch->qemu_watch = watch->core->watch_add(fd, event_mask, func, opaque);
+    return &watch->base;
 }
 
-static void adapter_watch_update_mask(const SpiceCoreInterfaceInternal *iface, SpiceWatch *watch, int event_mask)
+static void adapter_watch_update_mask(SpiceWatch *watch_, int event_mask)
 {
-    iface->public_interface->watch_update_mask(watch, event_mask);
+    SpiceWatchQemu *watch = SPICE_UPCAST(SpiceWatchQemu, watch_);
+    watch->core->watch_update_mask(watch->qemu_watch, event_mask);
 }
 
-static void adapter_watch_remove(const SpiceCoreInterfaceInternal *iface, SpiceWatch *watch)
+static void adapter_watch_remove(SpiceWatch *watch_)
 {
-    iface->public_interface->watch_remove(watch);
+    SpiceWatchQemu *watch = SPICE_UPCAST(SpiceWatchQemu, watch_);
+    watch->core->watch_remove(watch->qemu_watch);
+    g_free(watch);
 }
 
 static void adapter_channel_event(const SpiceCoreInterfaceInternal *iface, int event, SpiceChannelEventInfo *info)
@@ -312,13 +410,17 @@  static void adapter_channel_event(const SpiceCoreInterfaceInternal *iface, int e
         iface->public_interface->channel_event(event, info);
 }
 
-const SpiceCoreInterfaceInternal core_interface_adapter = {
-    .timer_add = adapter_timer_add,
+static const SpiceCoreFuncs qemu_core_funcs = {
     .timer_start = adapter_timer_start,
     .timer_cancel = adapter_timer_cancel,
     .timer_remove = adapter_timer_remove,
-    .watch_add = adapter_watch_add,
+
     .watch_update_mask = adapter_watch_update_mask,
     .watch_remove = adapter_watch_remove,
+};
+
+const SpiceCoreInterfaceInternal core_interface_adapter = {
+    .timer_add = adapter_timer_add,
+    .watch_add = adapter_watch_add,
     .channel_event = adapter_channel_event,
 };
diff --git a/server/inputs-channel.c b/server/inputs-channel.c
index a1c35565c..280783c17 100644
--- a/server/inputs-channel.c
+++ b/server/inputs-channel.c
@@ -162,8 +162,7 @@  const VDAgentMouseState *inputs_channel_get_mouse_state(InputsChannel *inputs)
 
 static void activate_modifiers_watch(InputsChannel *inputs)
 {
-    SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(RED_CHANNEL(inputs));
-    core->timer_start(core, inputs->key_modifiers_timer, KEY_MODIFIERS_TTL);
+    red_timer_start(inputs->key_modifiers_timer, KEY_MODIFIERS_TTL);
 }
 
 static void kbd_push_scan(SpiceKbdInstance *sin, uint8_t scan)
@@ -600,10 +599,9 @@  static void
 inputs_channel_finalize(GObject *object)
 {
     InputsChannel *self = INPUTS_CHANNEL(object);
-    SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(RED_CHANNEL(self));
 
     inputs_channel_detach_tablet(self, self->tablet);
-    core->timer_remove(core, self->key_modifiers_timer);
+    red_timer_remove(self->key_modifiers_timer);
 
     G_OBJECT_CLASS(inputs_channel_parent_class)->finalize(object);
 }
diff --git a/server/main-dispatcher.c b/server/main-dispatcher.c
index 2ca68a4d1..7579fd379 100644
--- a/server/main-dispatcher.c
+++ b/server/main-dispatcher.c
@@ -288,7 +288,7 @@  static void main_dispatcher_finalize(GObject *object)
 {
     MainDispatcher *self = MAIN_DISPATCHER(object);
 
-    reds_core_watch_remove(self->priv->reds, self->priv->watch);
+    red_watch_remove(self->priv->watch);
     self->priv->watch = NULL;
     G_OBJECT_CLASS(main_dispatcher_parent_class)->finalize(object);
 }
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 337733d5d..d19eafe78 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -216,8 +216,6 @@  typedef struct MarkerPipeItem {
 
 static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t timeout)
 {
-    SpiceCoreInterfaceInternal *core;
-
     if (!rcc->priv->latency_monitor.timer) {
         return;
     }
@@ -226,14 +224,11 @@  static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t
     }
     rcc->priv->latency_monitor.state = PING_STATE_TIMER;
 
-    core = red_channel_get_core_interface(rcc->priv->channel);
-    core->timer_start(core, rcc->priv->latency_monitor.timer, timeout);
+    red_timer_start(rcc->priv->latency_monitor.timer, timeout);
 }
 
 static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
 {
-    SpiceCoreInterfaceInternal *core;
-
     if (!rcc->priv->latency_monitor.timer) {
         return;
     }
@@ -241,8 +236,7 @@  static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
         return;
     }
 
-    core = red_channel_get_core_interface(rcc->priv->channel);
-    core->timer_cancel(core, rcc->priv->latency_monitor.timer);
+    red_timer_cancel(rcc->priv->latency_monitor.timer);
     rcc->priv->latency_monitor.state = PING_STATE_NONE;
 }
 
@@ -332,13 +326,12 @@  red_channel_client_finalize(GObject *object)
 {
     RedChannelClient *self = RED_CHANNEL_CLIENT(object);
 
-    SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(self->priv->channel);
     if (self->priv->latency_monitor.timer) {
-        core->timer_remove(core, self->priv->latency_monitor.timer);
+        red_timer_remove(self->priv->latency_monitor.timer);
         self->priv->latency_monitor.timer = NULL;
     }
     if (self->priv->connectivity_monitor.timer) {
-        core->timer_remove(core, self->priv->connectivity_monitor.timer);
+        red_timer_remove(self->priv->connectivity_monitor.timer);
         self->priv->connectivity_monitor.timer = NULL;
     }
 
@@ -756,7 +749,6 @@  static void red_channel_client_connectivity_timer(void *opaque)
     }
 
     if (is_alive) {
-        SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
         monitor->received_bytes = false;
         monitor->sent_bytes = false;
         if (red_channel_client_is_blocked(rcc) || red_channel_client_waiting_for_ack(rcc)) {
@@ -767,7 +759,7 @@  static void red_channel_client_connectivity_timer(void *opaque)
         } else {
              monitor->state = CONNECTIVITY_STATE_CONNECTED;
         }
-        core->timer_start(core, rcc->priv->connectivity_monitor.timer,
+        red_timer_start(rcc->priv->connectivity_monitor.timer,
                           rcc->priv->connectivity_monitor.timeout);
     } else {
         monitor->state = CONNECTIVITY_STATE_DISCONNECTED;
@@ -806,7 +798,7 @@  void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uin
             core, red_channel_client_connectivity_timer, rcc);
         rcc->priv->connectivity_monitor.timeout = timeout_ms;
         if (!red_client_during_migrate_at_target(rcc->priv->client)) {
-            core->timer_start(core, rcc->priv->connectivity_monitor.timer,
+            red_timer_start(rcc->priv->connectivity_monitor.timer,
                               rcc->priv->connectivity_monitor.timeout);
         }
     }
@@ -964,14 +956,11 @@  cleanup:
 static void
 red_channel_client_watch_update_mask(RedChannelClient *rcc, int event_mask)
 {
-    SpiceCoreInterfaceInternal *core;
-
     if (!rcc->priv->stream->watch) {
         return;
     }
 
-    core = red_channel_get_core_interface(rcc->priv->channel);
-    core->watch_update_mask(core, rcc->priv->stream->watch, event_mask);
+    red_watch_update_mask(rcc->priv->stream->watch, event_mask);
 }
 
 static void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
@@ -981,8 +970,7 @@  static void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
     if (red_client_seamless_migration_done_for_channel(rcc->priv->client)) {
         red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
         if (rcc->priv->connectivity_monitor.timer) {
-            SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
-            core->timer_start(core, rcc->priv->connectivity_monitor.timer,
+            red_timer_start(rcc->priv->connectivity_monitor.timer,
                               rcc->priv->connectivity_monitor.timeout);
         }
     }
@@ -1000,14 +988,13 @@  bool red_channel_client_is_waiting_for_migrate_data(RedChannelClient *rcc)
 
 void red_channel_client_default_migrate(RedChannelClient *rcc)
 {
-    SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
     if (rcc->priv->latency_monitor.timer) {
         red_channel_client_cancel_ping_timer(rcc);
-        core->timer_remove(core, rcc->priv->latency_monitor.timer);
+        red_timer_remove(rcc->priv->latency_monitor.timer);
         rcc->priv->latency_monitor.timer = NULL;
     }
     if (rcc->priv->connectivity_monitor.timer) {
-        core->timer_remove(core, rcc->priv->connectivity_monitor.timer);
+        red_timer_remove(rcc->priv->connectivity_monitor.timer);
         rcc->priv->connectivity_monitor.timer = NULL;
     }
     red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_MIGRATE);
@@ -1024,8 +1011,7 @@  void red_channel_client_destroy(RedChannelClient *rcc)
 void red_channel_client_shutdown(RedChannelClient *rcc)
 {
     if (rcc->priv->stream && rcc->priv->stream->watch) {
-        SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
-        core->watch_remove(core, rcc->priv->stream->watch);
+        red_watch_remove(rcc->priv->stream->watch);
         rcc->priv->stream->watch = NULL;
         shutdown(rcc->priv->stream->socket, SHUT_RDWR);
     }
@@ -1719,22 +1705,21 @@  static void red_channel_client_on_disconnect(RedChannelClient *rcc)
 void red_channel_client_disconnect(RedChannelClient *rcc)
 {
     RedChannel *channel = rcc->priv->channel;
-    SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(channel);
 
     if (!red_channel_client_is_connected(rcc)) {
         return;
     }
     red_channel_client_pipe_clear(rcc);
     if (rcc->priv->stream->watch) {
-        core->watch_remove(core, rcc->priv->stream->watch);
+        red_watch_remove(rcc->priv->stream->watch);
         rcc->priv->stream->watch = NULL;
     }
     if (rcc->priv->latency_monitor.timer) {
-        core->timer_remove(core, rcc->priv->latency_monitor.timer);
+        red_timer_remove(rcc->priv->latency_monitor.timer);
         rcc->priv->latency_monitor.timer = NULL;
     }
     if (rcc->priv->connectivity_monitor.timer) {
-        core->timer_remove(core, rcc->priv->connectivity_monitor.timer);
+        red_timer_remove(rcc->priv->connectivity_monitor.timer);
         rcc->priv->connectivity_monitor.timer = NULL;
     }
     red_channel_remove_client(channel, rcc);
diff --git a/server/red-common.h b/server/red-common.h
index 22ea8fc37..4b2e9f87c 100644
--- a/server/red-common.h
+++ b/server/red-common.h
@@ -40,17 +40,20 @@ 
 #define SPICE_UPCAST(type, ptr) \
     (verify_expr(SPICE_OFFSETOF(type, base) == 0,SPICE_CONTAINEROF(ptr, type, base)))
 
+SPICE_BEGIN_DECLS
+
+void red_timer_start(SpiceTimer *timer, uint32_t ms);
+void red_timer_cancel(SpiceTimer *timer);
+void red_timer_remove(SpiceTimer *timer);
+void red_watch_update_mask(SpiceWatch *watch, int event_mask);
+void red_watch_remove(SpiceWatch *watch);
+
 typedef struct SpiceCoreInterfaceInternal SpiceCoreInterfaceInternal;
 
 struct SpiceCoreInterfaceInternal {
     SpiceTimer *(*timer_add)(const SpiceCoreInterfaceInternal *iface, SpiceTimerFunc func, void *opaque);
-    void (*timer_start)(const SpiceCoreInterfaceInternal *iface, SpiceTimer *timer, uint32_t ms);
-    void (*timer_cancel)(const SpiceCoreInterfaceInternal *iface, SpiceTimer *timer);
-    void (*timer_remove)(const SpiceCoreInterfaceInternal *iface, SpiceTimer *timer);
 
     SpiceWatch *(*watch_add)(const SpiceCoreInterfaceInternal *iface, int fd, int event_mask, SpiceWatchFunc func, void *opaque);
-    void (*watch_update_mask)(const SpiceCoreInterfaceInternal *iface, SpiceWatch *watch, int event_mask);
-    void (*watch_remove)(const SpiceCoreInterfaceInternal *iface, SpiceWatch *watch);
 
     void (*channel_event)(const SpiceCoreInterfaceInternal *iface, int event, SpiceChannelEventInfo *info);
 
@@ -126,4 +129,6 @@  typedef struct GListIter {
     { return G_TYPE_INSTANCE_GET_CLASS(obj, \
              module_obj_name ## _get_type(), ModuleObjName ## Class); }
 
+SPICE_END_DECLS
+
 #endif /* RED_COMMON_H_ */
diff --git a/server/red-stream-device.c b/server/red-stream-device.c
index 620e581ef..44d9cd09d 100644
--- a/server/red-stream-device.c
+++ b/server/red-stream-device.c
@@ -120,7 +120,7 @@  stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
         if (!dev->close_timer) {
             dev->close_timer = reds_core_timer_add(reds, close_timer_func, dev);
         }
-        reds_core_timer_start(reds, dev->close_timer, 0);
+        red_timer_start(dev->close_timer, 0);
         return false;
     }
 
@@ -649,8 +649,7 @@  stream_device_dispose(GObject *object)
 {
     StreamDevice *dev = STREAM_DEVICE(object);
 
-    RedsState *reds = red_char_device_get_server(RED_CHAR_DEVICE(dev));
-    reds_core_timer_remove(reds, dev->close_timer);
+    red_timer_remove(dev->close_timer);
 
     if (dev->stream_channel) {
         // close all current connections and drop the reference
diff --git a/server/red-stream.c b/server/red-stream.c
index 04be3af37..aec482fb8 100644
--- a/server/red-stream.c
+++ b/server/red-stream.c
@@ -213,7 +213,7 @@  static ssize_t stream_ssl_read_cb(RedStream *s, void *buf, size_t size)
 void red_stream_remove_watch(RedStream* s)
 {
     if (s->watch) {
-        s->priv->core->watch_remove(s->priv->core, s->watch);
+        red_watch_remove(s->watch);
         s->watch = NULL;
     }
 }
diff --git a/server/red-worker.c b/server/red-worker.c
index 98a4a9dc3..12a8e7398 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1185,7 +1185,7 @@  void red_worker_free(RedWorker *worker)
     worker->display_channel = NULL;
 
     if (worker->dispatch_watch) {
-        worker->core.watch_remove(&worker->core, worker->dispatch_watch);
+        red_watch_remove(worker->dispatch_watch);
     }
 
     g_main_context_unref(worker->core.main_context);
diff --git a/server/reds.c b/server/reds.c
index f432f55a4..96dd58433 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -410,7 +410,7 @@  static void reds_mig_cleanup(RedsState *reds)
         reds->mig_inprogress = FALSE;
         reds->mig_wait_connect = FALSE;
         reds->mig_wait_disconnect = FALSE;
-        reds_core_timer_cancel(reds, reds->mig_timer);
+        red_timer_cancel(reds->mig_timer);
         reds_mig_cleanup_wait_disconnect(reds);
     }
 }
@@ -2429,7 +2429,6 @@  static void reds_handle_new_link(RedLinkInfo *link)
 static void reds_handle_ssl_accept(int fd, int event, void *data)
 {
     RedLinkInfo *link = (RedLinkInfo *)data;
-    RedsState *reds = link->reds;
     RedStreamSslStatus return_code = red_stream_ssl_accept(link->stream);
 
     switch (return_code) {
@@ -2437,12 +2436,10 @@  static void reds_handle_ssl_accept(int fd, int event, void *data)
             reds_link_free(link);
             return;
         case RED_STREAM_SSL_STATUS_WAIT_FOR_READ:
-            reds_core_watch_update_mask(reds, link->stream->watch,
-                                        SPICE_WATCH_EVENT_READ);
+            red_watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_READ);
             return;
         case RED_STREAM_SSL_STATUS_WAIT_FOR_WRITE:
-            reds_core_watch_update_mask(reds, link->stream->watch,
-                                        SPICE_WATCH_EVENT_WRITE);
+            red_watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_WRITE);
             return;
         case RED_STREAM_SSL_STATUS_OK:
             red_stream_remove_watch(link->stream);
@@ -2702,7 +2699,7 @@  void reds_set_client_mm_time_latency(RedsState *reds, RedClient *client, uint32_
 static void reds_cleanup_net(SpiceServer *reds)
 {
     if (reds->listen_socket != -1) {
-       reds_core_watch_remove(reds, reds->listen_watch);
+       red_watch_remove(reds->listen_watch);
        if (reds->config->spice_listen_socket_fd != reds->listen_socket) {
           socket_close(reds->listen_socket);
        }
@@ -2710,7 +2707,7 @@  static void reds_cleanup_net(SpiceServer *reds)
        reds->listen_socket = -1;
     }
     if (reds->secure_listen_socket != -1) {
-       reds_core_watch_remove(reds, reds->secure_listen_watch);
+       red_watch_remove(reds->secure_listen_watch);
        socket_close(reds->secure_listen_socket);
        reds->secure_listen_watch = NULL;
        reds->secure_listen_socket = -1;
@@ -3031,7 +3028,7 @@  static void reds_mig_started(RedsState *reds)
 
     reds->mig_inprogress = TRUE;
     reds->mig_wait_connect = TRUE;
-    reds_core_timer_start(reds, reds->mig_timer, MIGRATE_TIMEOUT);
+    red_timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
 }
 
 static void reds_mig_fill_wait_disconnect(RedsState *reds)
@@ -3046,7 +3043,7 @@  static void reds_mig_fill_wait_disconnect(RedsState *reds)
     }
     reds->mig_wait_connect = FALSE;
     reds->mig_wait_disconnect = TRUE;
-    reds_core_timer_start(reds, reds->mig_timer, MIGRATE_TIMEOUT);
+    red_timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
 }
 
 static void reds_mig_cleanup_wait_disconnect(RedsState *reds)
@@ -3863,7 +3860,7 @@  SPICE_GNUC_VISIBLE void spice_server_destroy(SpiceServer *reds)
     if (reds->main_channel) {
         red_channel_destroy(RED_CHANNEL(reds->main_channel));
     }
-    reds_core_timer_remove(reds, reds->mig_timer);
+    red_timer_remove(reds->mig_timer);
 
     if (reds->ctx) {
         SSL_CTX_free(reds->ctx);
@@ -4437,24 +4434,6 @@  SpiceWatch *reds_core_watch_add(RedsState *reds,
    return reds->core.watch_add(&reds->core, fd, event_mask, func, opaque);
 }
 
-void reds_core_watch_update_mask(RedsState *reds,
-                                 SpiceWatch *watch,
-                                 int event_mask)
-{
-   g_return_if_fail(reds != NULL);
-   g_return_if_fail(reds->core.watch_update_mask != NULL);
-
-   reds->core.watch_update_mask(&reds->core, watch, event_mask);
-}
-
-void reds_core_watch_remove(RedsState *reds, SpiceWatch *watch)
-{
-   g_return_if_fail(reds != NULL);
-   g_return_if_fail(reds->core.watch_remove != NULL);
-
-   reds->core.watch_remove(&reds->core, watch);
-}
-
 SpiceTimer *reds_core_timer_add(RedsState *reds,
                                 SpiceTimerFunc func,
                                 void *opaque)
@@ -4466,38 +4445,6 @@  SpiceTimer *reds_core_timer_add(RedsState *reds,
 
 }
 
-void reds_core_timer_start(RedsState *reds,
-                           SpiceTimer *timer,
-                           uint32_t ms)
-{
-   g_return_if_fail(reds != NULL);
-   g_return_if_fail(reds->core.timer_start != NULL);
-
-   return reds->core.timer_start(&reds->core, timer, ms);
-}
-
-void reds_core_timer_cancel(RedsState *reds,
-                            SpiceTimer *timer)
-{
-   g_return_if_fail(reds != NULL);
-   g_return_if_fail(reds->core.timer_cancel != NULL);
-
-   return reds->core.timer_cancel(&reds->core, timer);
-}
-
-void reds_core_timer_remove(RedsState *reds,
-                            SpiceTimer *timer)
-{
-    if (timer == NULL) {
-        return;
-    }
-
-    g_return_if_fail(reds != NULL);
-    g_return_if_fail(reds->core.timer_remove != NULL);
-
-    reds->core.timer_remove(&reds->core, timer);
-}
-
 void reds_update_client_mouse_allowed(RedsState *reds)
 {
     int allow_now = FALSE;
diff --git a/server/reds.h b/server/reds.h
index e3355f817..e2b6904ab 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -115,20 +115,8 @@  SpiceWatch *reds_core_watch_add(RedsState *reds,
                                 int fd, int event_mask,
                                 SpiceWatchFunc func,
                                 void *opaque);
-void reds_core_watch_update_mask(RedsState *reds,
-                                 SpiceWatch *watch,
-                                 int event_mask);
-void reds_core_watch_remove(RedsState *reds, SpiceWatch *watch);
-
 SpiceTimer *reds_core_timer_add(RedsState *reds,
                                 SpiceTimerFunc func,
                                 void *opaque);
-void reds_core_timer_start(RedsState *reds,
-                           SpiceTimer *timer,
-                           uint32_t ms);
-void reds_core_timer_cancel(RedsState *reds,
-                            SpiceTimer *timer);
-void reds_core_timer_remove(RedsState *reds,
-                            SpiceTimer *timer);
 
 #endif /* REDS_H_ */
diff --git a/server/tests/basic-event-loop.c b/server/tests/basic-event-loop.c
index e331e8522..70c9a4df5 100644
--- a/server/tests/basic-event-loop.c
+++ b/server/tests/basic-event-loop.c
@@ -83,48 +83,23 @@  static SpiceTimer* base_timer_add(SpiceTimerFunc func, void *opaque)
     return base_core_interface.timer_add(&base_core_interface, func, opaque);
 }
 
-static void base_timer_start(SpiceTimer *timer, uint32_t ms)
-{
-    base_core_interface.timer_start(&base_core_interface, timer, ms);
-}
-
-static void base_timer_cancel(SpiceTimer *timer)
-{
-    base_core_interface.timer_cancel(&base_core_interface, timer);
-}
-
-static void base_timer_remove(SpiceTimer *timer)
-{
-    base_core_interface.timer_remove(&base_core_interface, timer);
-}
-
 static SpiceWatch *base_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
     return base_core_interface.watch_add(&base_core_interface, fd, event_mask, func, opaque);
 }
 
-static void base_watch_update_mask(SpiceWatch *watch, int event_mask)
-{
-    base_core_interface.watch_update_mask(&base_core_interface, watch, event_mask);
-}
-
-static void base_watch_remove(SpiceWatch *watch)
-{
-    base_core_interface.watch_remove(&base_core_interface, watch);
-}
-
 static SpiceCoreInterface core = {
     .base = {
         .major_version = SPICE_INTERFACE_CORE_MAJOR,
         .minor_version = SPICE_INTERFACE_CORE_MINOR,
     },
     .timer_add = base_timer_add,
-    .timer_start = base_timer_start,
-    .timer_cancel = base_timer_cancel,
-    .timer_remove = base_timer_remove,
+    .timer_start = red_timer_start,
+    .timer_cancel = red_timer_cancel,
+    .timer_remove = red_timer_remove,
     .watch_add = base_watch_add,
-    .watch_update_mask = base_watch_update_mask,
-    .watch_remove = base_watch_remove,
+    .watch_update_mask = red_watch_update_mask,
+    .watch_remove = red_watch_remove,
     .channel_event = event_loop_channel_event,
 };