[Spice-devel] [PATCH v2] worker: use glib main loop
Jonathon Jongsma
jjongsma at redhat.com
Thu Dec 10 12:42:48 PST 2015
From: Marc-André Lureau <marcandre.lureau at gmail.com>
Use the glib mainloop instead of writing our own. The glib loop is both
cleaner to use and is more extensible. It is also very mature and
reduces the maintenance burden on the spice server.
Signed-off-by: Jonathon Jongsma <jjongsma at redhat.com>
---
Changes since last version:
- expanded commit log
- changed function name to red_worker_get_main_context(). Could also be called
_get_event_context()
- retained one comment that had been deleted and deleted one confusing comment
that was added.
- removed unnecessary debug statement addition
- Changed abort() to exit()
server/Makefile.am | 2 -
server/red-worker.c | 354 ++++++++++++++++++++++++++++-----------------
server/red-worker.h | 1 +
server/spice_timer_queue.c | 273 ----------------------------------
server/spice_timer_queue.h | 43 ------
5 files changed, 223 insertions(+), 450 deletions(-)
delete mode 100644 server/spice_timer_queue.c
delete mode 100644 server/spice_timer_queue.h
diff --git a/server/Makefile.am b/server/Makefile.am
index d4fc972..88825d8 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -121,8 +121,6 @@ libspice_server_la_SOURCES = \
spice.h \
stat.h \
spicevmc.c \
- spice_timer_queue.c \
- spice_timer_queue.h \
zlib-encoder.c \
zlib-encoder.h \
image-cache.h \
diff --git a/server/red-worker.c b/server/red-worker.c
index baa8458..78ae462 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -49,30 +49,22 @@
#include "spice.h"
#include "red-worker.h"
-#include "spice_timer_queue.h"
#include "cursor-channel.h"
#include "tree.h"
#define CMD_RING_POLL_TIMEOUT 10 //milli
#define CMD_RING_POLL_RETRIES 200
-#define MAX_EVENT_SOURCES 20
#define INF_EVENT_WAIT ~0
-struct SpiceWatch {
- struct RedWorker *worker;
- SpiceWatchFunc watch_func;
- void *watch_func_opaque;
-};
-
struct RedWorker {
pthread_t thread;
clockid_t clockid;
QXLInstance *qxl;
RedDispatcher *red_dispatcher;
int running;
- struct pollfd poll_fds[MAX_EVENT_SOURCES];
- struct SpiceWatch watches[MAX_EVENT_SOURCES];
+
+ GMainContext *main_context;
unsigned int event_timeout;
DisplayChannel *display_channel;
@@ -99,6 +91,13 @@ struct RedWorker {
FILE *record_fd;
};
+GMainContext* red_worker_get_main_context(RedWorker *worker)
+{
+ spice_return_val_if_fail(worker, NULL);
+
+ return worker->main_context;
+}
+
QXLInstance* red_worker_get_qxl(RedWorker *worker)
{
spice_return_val_if_fail(worker != NULL, NULL);
@@ -510,81 +509,161 @@ static int common_channel_config_socket(RedChannelClient *rcc)
return TRUE;
}
-static void worker_watch_update_mask(SpiceWatch *watch, int event_mask)
+typedef struct SpiceTimer {
+ SpiceTimerFunc func;
+ void *opaque;
+ guint source_id;
+} SpiceTimer;
+
+static SpiceTimer* worker_timer_add(SpiceTimerFunc func, void *opaque)
{
- struct RedWorker *worker;
- int i;
+ SpiceTimer *timer = g_new0(SpiceTimer, 1);
+
+ timer->func = func;
+ timer->opaque = opaque;
- if (!watch) {
+ return timer;
+}
+
+static gboolean worker_timer_func(gpointer user_data)
+{
+ SpiceTimer *timer = user_data;
+
+ timer->source_id = 0;
+ timer->func(timer->opaque);
+ /* timer might be free after func(), don't touch */
+
+ return FALSE;
+}
+
+static void worker_timer_cancel(SpiceTimer *timer)
+{
+ if (timer->source_id == 0)
return;
- }
- worker = watch->worker;
- i = watch - worker->watches;
+ g_source_remove(timer->source_id);
+ timer->source_id = 0;
+}
+
+static void worker_timer_start(SpiceTimer *timer, uint32_t ms)
+{
+ worker_timer_cancel(timer);
- worker->poll_fds[i].events = 0;
- if (event_mask & SPICE_WATCH_EVENT_READ) {
- worker->poll_fds[i].events |= POLLIN;
- }
- if (event_mask & SPICE_WATCH_EVENT_WRITE) {
- worker->poll_fds[i].events |= POLLOUT;
+ timer->source_id = g_timeout_add(ms, worker_timer_func, timer);
+}
+
+static void worker_timer_remove(SpiceTimer *timer)
+{
+ worker_timer_cancel(timer);
+ g_free(timer);
+}
+
+static GIOCondition spice_event_to_giocondition(int event_mask)
+{
+ GIOCondition condition = 0;
+
+ if (event_mask & SPICE_WATCH_EVENT_READ)
+ condition |= G_IO_IN;
+ if (event_mask & SPICE_WATCH_EVENT_WRITE)
+ condition |= G_IO_OUT;
+
+ return condition;
+}
+
+static int giocondition_to_spice_event(GIOCondition condition)
+{
+ int event = 0;
+
+ if (condition & G_IO_IN)
+ event |= SPICE_WATCH_EVENT_READ;
+ if (condition & G_IO_OUT)
+ event |= SPICE_WATCH_EVENT_WRITE;
+
+ return event;
+}
+
+struct SpiceWatch {
+ GIOChannel *channel;
+ GSource *source;
+ RedChannelClient *rcc;
+ SpiceWatchFunc func;
+};
+
+static gboolean watch_func(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ SpiceWatch *watch = data;
+ int fd = g_io_channel_unix_get_fd(source);
+
+ watch->func(fd, giocondition_to_spice_event(condition), watch->rcc);
+
+ return TRUE;
+}
+
+static void worker_watch_update_mask(SpiceWatch *watch, int events)
+{
+ RedWorker *worker;
+
+ spice_return_if_fail(watch != NULL);
+ worker = SPICE_CONTAINEROF(watch->rcc->channel, CommonChannel, base)->worker;
+
+ if (watch->source) {
+ g_source_destroy(watch->source);
+ watch->source = NULL;
}
+
+ if (!events)
+ return;
+
+ watch->source = g_io_create_watch(watch->channel, spice_event_to_giocondition(events));
+ g_source_set_callback(watch->source, (GSourceFunc)watch_func, watch, NULL);
+ g_source_attach(watch->source, worker->main_context);
}
-static SpiceWatch *worker_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+static SpiceWatch* worker_watch_add(int fd, int events, SpiceWatchFunc func, void *opaque)
{
/* Since we are a channel core implementation, we always get called from
red_channel_client_create(), so opaque always is our rcc */
RedChannelClient *rcc = opaque;
- struct RedWorker *worker;
- int i;
+ RedWorker *worker;
+ SpiceWatch *watch;
+
+ spice_return_val_if_fail(rcc != NULL, NULL);
+ spice_return_val_if_fail(fd != -1, NULL);
+ spice_return_val_if_fail(func != NULL, NULL);
/* Since we are called from red_channel_client_create()
CommonChannelClient->worker has not been set yet! */
worker = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base)->worker;
+ spice_return_val_if_fail(worker != NULL, NULL);
+ spice_return_val_if_fail(worker->main_context != NULL, NULL);
- /* Search for a free slot in our poll_fds & watches arrays */
- for (i = 0; i < MAX_EVENT_SOURCES; i++) {
- if (worker->poll_fds[i].fd == -1) {
- break;
- }
- }
- if (i == MAX_EVENT_SOURCES) {
- spice_warning("could not add a watch for channel type %u id %u",
- rcc->channel->type, rcc->channel->id);
- return NULL;
- }
+ watch = g_new0(SpiceWatch, 1);
+ watch->channel = g_io_channel_unix_new(fd);
+ watch->rcc = rcc;
+ watch->func = func;
- worker->poll_fds[i].fd = fd;
- worker->watches[i].worker = worker;
- worker->watches[i].watch_func = func;
- worker->watches[i].watch_func_opaque = opaque;
- worker_watch_update_mask(&worker->watches[i], event_mask);
+ worker_watch_update_mask(watch, events);
- return &worker->watches[i];
+ return watch;
}
static void worker_watch_remove(SpiceWatch *watch)
{
- if (!watch) {
- return;
- }
+ spice_return_if_fail(watch != NULL);
- /* Note we don't touch the poll_fd here, to avoid the
- poll_fds/watches table entry getting re-used in the same
- red_worker_main loop over the fds as it is removed.
+ if (watch->source)
+ g_source_destroy(watch->source);
- This is done because re-using it while events were pending on
- the fd previously occupying the slot would lead to incorrectly
- calling the watch_func for the new fd. */
- memset(watch, 0, sizeof(SpiceWatch));
+ g_io_channel_unref(watch->channel);
+ g_free(watch);
}
-SpiceCoreInterface worker_core = {
- .timer_add = spice_timer_queue_add,
- .timer_start = spice_timer_set,
- .timer_cancel = spice_timer_cancel,
- .timer_remove = spice_timer_remove,
+static const SpiceCoreInterface worker_core = {
+ .timer_add = worker_timer_add,
+ .timer_start = worker_timer_start,
+ .timer_cancel = worker_timer_cancel,
+ .timer_remove = worker_timer_remove,
.watch_update_mask = worker_watch_update_mask,
.watch_add = worker_watch_add,
@@ -1527,24 +1606,90 @@ static void register_callbacks(Dispatcher *dispatcher)
-static void handle_dev_input(int fd, int event, void *opaque)
+static gboolean worker_dispatcher_cb(GIOChannel *source, GIOCondition condition,
+ gpointer data)
{
- RedWorker *worker = opaque;
+ RedWorker *worker = data;
dispatcher_handle_recv_read(red_dispatcher_get_dispatcher(worker->red_dispatcher));
+
+ return TRUE;
+}
+
+typedef struct RedWorkerSource {
+ GSource source;
+ RedWorker *worker;
+} RedWorkerSource;
+
+static gboolean worker_source_prepare(GSource *source, gint *p_timeout)
+{
+ RedWorkerSource *wsource = (RedWorkerSource *)source;
+ RedWorker *worker = wsource->worker;
+ unsigned int timeout;
+
+ timeout = MIN(worker->event_timeout,
+ display_channel_get_streams_timeout(worker->display_channel));
+
+ *p_timeout = (timeout == INF_EVENT_WAIT) ? -1 : timeout;
+ if (*p_timeout == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean worker_source_check(GSource *source)
+{
+ RedWorkerSource *wsource = (RedWorkerSource *)source;
+ RedWorker *worker = wsource->worker;
+
+ return worker->running /* TODO && worker->pending_process */;
+}
+
+static gboolean worker_source_dispatch(GSource *source, GSourceFunc callback,
+ gpointer user_data)
+{
+ RedWorkerSource *wsource = (RedWorkerSource *)source;
+ RedWorker *worker = wsource->worker;
+ DisplayChannel *display = worker->display_channel;
+ int ring_is_empty;
+
+ /* during migration, in the dest, the display channel can be initialized
+ while the global lz data not since migrate data msg hasn't been
+ received yet */
+ /* FIXME: why is this here, and not in display_channel_create */
+ display_channel_free_glz_drawables_to_free(display);
+
+ /* FIXME: could use its own source */
+ stream_timeout(display);
+
+ worker->event_timeout = INF_EVENT_WAIT;
+ red_process_cursor(worker, MAX_PIPE_SIZE, &ring_is_empty);
+ red_process_display(worker, MAX_PIPE_SIZE, &ring_is_empty);
+
+ /* FIXME: remove me? that should be handled by watch out condition */
+ red_push(worker);
+
+ return TRUE;
}
+/* cannot be const */
+static GSourceFuncs worker_source_funcs = {
+ .prepare = worker_source_prepare,
+ .check = worker_source_check,
+ .dispatch = worker_source_dispatch,
+};
+
RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
{
QXLDevInitInfo init_info;
RedWorker *worker;
Dispatcher *dispatcher;
- int i;
const char *record_filename;
qxl->st->qif->get_init_info(qxl, &init_info);
worker = spice_new0(RedWorker, 1);
+ worker->main_context = g_main_context_new();
record_filename = getenv("SPICE_WORKER_RECORD_FILENAME");
if (record_filename) {
@@ -1578,15 +1723,18 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
worker->wakeup_counter = stat_add_counter(worker->stat, "wakeups", TRUE);
worker->command_counter = stat_add_counter(worker->stat, "commands", TRUE);
#endif
- for (i = 0; i < MAX_EVENT_SOURCES; i++) {
- worker->poll_fds[i].fd = -1;
- }
- worker->poll_fds[0].fd = dispatcher_get_recv_fd(dispatcher);
- worker->poll_fds[0].events = POLLIN;
- worker->watches[0].worker = worker;
- worker->watches[0].watch_func = handle_dev_input;
- worker->watches[0].watch_func_opaque = worker;
+ GIOChannel *channel = g_io_channel_unix_new(dispatcher_get_recv_fd(dispatcher));
+ GSource *source = g_io_create_watch(channel, G_IO_IN);
+ g_source_set_callback(source, (GSourceFunc)worker_dispatcher_cb, worker, NULL);
+ g_source_attach(source, worker->main_context);
+ g_source_unref(source);
+
+ source = g_source_new(&worker_source_funcs, sizeof(RedWorkerSource));
+ RedWorkerSource *wsource = (RedWorkerSource *)source;
+ wsource->worker = worker;
+ g_source_attach(source, worker->main_context);
+ g_source_unref(source);
memslot_info_init(&worker->mem_slots,
init_info.num_memslots_groups,
@@ -1615,10 +1763,6 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
spice_assert(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW &&
MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure wakeup by ack message
- if (!spice_timer_queue_create()) {
- spice_error("failed to create timer queue");
- }
-
if (pthread_getcpuclockid(pthread_self(), &worker->clockid)) {
spice_warning("getcpuclockid failed");
}
@@ -1626,66 +1770,12 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
RED_CHANNEL(worker->cursor_channel)->thread_id = pthread_self();
RED_CHANNEL(worker->display_channel)->thread_id = pthread_self();
- for (;;) {
- int i, num_events;
- unsigned int timeout;
-
- timeout = spice_timer_queue_get_timeout_ms();
- worker->event_timeout = MIN(timeout, worker->event_timeout);
- timeout = display_channel_get_streams_timeout(worker->display_channel);
- worker->event_timeout = MIN(timeout, worker->event_timeout);
- num_events = poll(worker->poll_fds, MAX_EVENT_SOURCES, worker->event_timeout);
- stream_timeout(worker->display_channel);
- spice_timer_queue_cb();
-
- if (worker->display_channel) {
- /* during migration, in the dest, the display channel can be initialized
- while the global lz data not since migrate data msg hasn't been
- received yet */
- display_channel_free_glz_drawables_to_free(worker->display_channel);
- }
-
- worker->event_timeout = INF_EVENT_WAIT;
- if (num_events == -1) {
- if (errno != EINTR) {
- spice_error("poll failed, %s", strerror(errno));
- }
- }
-
- for (i = 0; i < MAX_EVENT_SOURCES; i++) {
- /* The watch may have been removed by the watch-func from
- another fd (ie a disconnect through the dispatcher),
- in this case watch_func is NULL. */
- if (worker->poll_fds[i].revents && worker->watches[i].watch_func) {
- int events = 0;
- if (worker->poll_fds[i].revents & POLLIN) {
- events |= SPICE_WATCH_EVENT_READ;
- }
- if (worker->poll_fds[i].revents & POLLOUT) {
- events |= SPICE_WATCH_EVENT_WRITE;
- }
- worker->watches[i].watch_func(worker->poll_fds[i].fd, events,
- worker->watches[i].watch_func_opaque);
- }
- }
-
- /* Clear the poll_fd for any removed watches, see the comment in
- watch_remove for why we don't do this there. */
- for (i = 0; i < MAX_EVENT_SOURCES; i++) {
- if (!worker->watches[i].watch_func) {
- worker->poll_fds[i].fd = -1;
- }
- }
-
- if (worker->running) {
- int ring_is_empty;
- red_process_cursor(worker, MAX_PIPE_SIZE, &ring_is_empty);
- red_process_display(worker, MAX_PIPE_SIZE, &ring_is_empty);
- }
- red_push(worker);
- }
+ GMainLoop *loop = g_main_loop_new(worker->main_context, FALSE);
+ g_main_loop_run(loop);
+ g_main_loop_unref(loop);
- spice_warn_if_reached();
+ /* FIXME: free worker, and join threads */
+ exit(0);
}
bool red_worker_run(RedWorker *worker)
diff --git a/server/red-worker.h b/server/red-worker.h
index 44f35f7..73a9b90 100644
--- a/server/red-worker.h
+++ b/server/red-worker.h
@@ -97,6 +97,7 @@ bool red_worker_run(RedWorker *worker);
QXLInstance* red_worker_get_qxl(RedWorker *worker);
RedChannel* red_worker_get_cursor_channel(RedWorker *worker);
RedChannel* red_worker_get_display_channel(RedWorker *worker);
+GMainContext* red_worker_get_main_context(RedWorker *worker);
clockid_t red_worker_get_clockid(RedWorker *worker);
RedMemSlotInfo* red_worker_get_memslot(RedWorker *worker);
diff --git a/server/spice_timer_queue.c b/server/spice_timer_queue.c
deleted file mode 100644
index 60017cc..0000000
--- a/server/spice_timer_queue.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- Copyright (C) 2013 Red Hat, Inc.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <pthread.h>
-#include "red-common.h"
-#include "spice_timer_queue.h"
-#include "common/ring.h"
-
-static Ring timer_queue_list;
-static int queue_count = 0;
-static pthread_mutex_t queue_list_lock = PTHREAD_MUTEX_INITIALIZER;
-
-static void spice_timer_queue_init(void)
-{
- ring_init(&timer_queue_list);
-}
-
-struct SpiceTimer {
- RingItem link;
- RingItem active_link;
-
- SpiceTimerFunc func;
- void *opaque;
-
- SpiceTimerQueue *queue;
-
- int is_active;
- uint32_t ms;
- uint64_t expiry_time;
-};
-
-struct SpiceTimerQueue {
- RingItem link;
- pthread_t thread;
- Ring timers;
- Ring active_timers;
-};
-
-static SpiceTimerQueue *spice_timer_queue_find(void)
-{
- pthread_t self = pthread_self();
- RingItem *queue_item;
-
- RING_FOREACH(queue_item, &timer_queue_list) {
- SpiceTimerQueue *queue = SPICE_CONTAINEROF(queue_item, SpiceTimerQueue, link);
-
- if (pthread_equal(self, queue->thread) != 0) {
- return queue;
- }
- }
-
- return NULL;
-}
-
-static SpiceTimerQueue *spice_timer_queue_find_with_lock(void)
-{
- SpiceTimerQueue *queue;
-
- pthread_mutex_lock(&queue_list_lock);
- queue = spice_timer_queue_find();
- pthread_mutex_unlock(&queue_list_lock);
- return queue;
-}
-
-int spice_timer_queue_create(void)
-{
- SpiceTimerQueue *queue;
-
- pthread_mutex_lock(&queue_list_lock);
- if (queue_count == 0) {
- spice_timer_queue_init();
- }
-
- if (spice_timer_queue_find() != NULL) {
- spice_printerr("timer queue was already created for the thread");
- return FALSE;
- }
-
- queue = spice_new0(SpiceTimerQueue, 1);
- queue->thread = pthread_self();
- ring_init(&queue->timers);
- ring_init(&queue->active_timers);
-
- ring_add(&timer_queue_list, &queue->link);
- queue_count++;
-
- pthread_mutex_unlock(&queue_list_lock);
-
- return TRUE;
-}
-
-void spice_timer_queue_destroy(void)
-{
- RingItem *item;
- SpiceTimerQueue *queue;
-
- pthread_mutex_lock(&queue_list_lock);
- queue = spice_timer_queue_find();
-
- spice_assert(queue != NULL);
-
- while ((item = ring_get_head(&queue->timers))) {
- SpiceTimer *timer;
-
- timer = SPICE_CONTAINEROF(item, SpiceTimer, link);
- spice_timer_remove(timer);
- }
-
- ring_remove(&queue->link);
- free(queue);
- queue_count--;
-
- pthread_mutex_unlock(&queue_list_lock);
-}
-
-SpiceTimer *spice_timer_queue_add(SpiceTimerFunc func, void *opaque)
-{
- SpiceTimer *timer = spice_new0(SpiceTimer, 1);
- SpiceTimerQueue *queue = spice_timer_queue_find_with_lock();
-
- spice_assert(queue != NULL);
-
- ring_item_init(&timer->link);
- ring_item_init(&timer->active_link);
-
- timer->opaque = opaque;
- timer->func = func;
- timer->queue = queue;
-
- ring_add(&queue->timers, &timer->link);
-
- return timer;
-}
-
-static void _spice_timer_set(SpiceTimer *timer, uint32_t ms, uint64_t now)
-{
- RingItem *next_item;
- SpiceTimerQueue *queue;
-
- if (timer->is_active) {
- spice_timer_cancel(timer);
- }
-
- queue = timer->queue;
- timer->expiry_time = now + ms;
- timer->ms = ms;
-
- RING_FOREACH(next_item, &queue->active_timers) {
- SpiceTimer *next_timer = SPICE_CONTAINEROF(next_item, SpiceTimer, active_link);
-
- if (timer->expiry_time <= next_timer->expiry_time) {
- break;
- }
- }
-
- if (next_item) {
- ring_add_before(&timer->active_link, next_item);
- } else {
- ring_add_before(&timer->active_link, &queue->active_timers);
- }
- timer->is_active = TRUE;
-}
-
-void spice_timer_set(SpiceTimer *timer, uint32_t ms)
-{
- struct timespec now;
-
- spice_assert(pthread_equal(timer->queue->thread, pthread_self()) != 0);
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- _spice_timer_set(timer, ms,
- (uint64_t)now.tv_sec * 1000 + (now.tv_nsec / 1000 / 1000));
-}
-
-void spice_timer_cancel(SpiceTimer *timer)
-{
- spice_assert(pthread_equal(timer->queue->thread, pthread_self()) != 0);
-
- if (!ring_item_is_linked(&timer->active_link)) {
- spice_assert(!timer->is_active);
- return;
- }
-
- spice_assert(timer->is_active);
- ring_remove(&timer->active_link);
- timer->is_active = FALSE;
-}
-
-void spice_timer_remove(SpiceTimer *timer)
-{
- spice_assert(timer->queue);
- spice_assert(ring_item_is_linked(&timer->link));
- spice_assert(pthread_equal(timer->queue->thread, pthread_self()) != 0);
-
- if (timer->is_active) {
- spice_assert(ring_item_is_linked(&timer->active_link));
- ring_remove(&timer->active_link);
- }
- ring_remove(&timer->link);
- free(timer);
-}
-
-unsigned int spice_timer_queue_get_timeout_ms(void)
-{
- struct timespec now;
- int64_t now_ms;
- RingItem *head;
- SpiceTimer *head_timer;
- SpiceTimerQueue *queue = spice_timer_queue_find_with_lock();
-
- spice_assert(queue != NULL);
-
- if (ring_is_empty(&queue->active_timers)) {
- return -1;
- }
-
- head = ring_get_head(&queue->active_timers);
- head_timer = SPICE_CONTAINEROF(head, SpiceTimer, active_link);
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- now_ms = ((int64_t)now.tv_sec * 1000) + (now.tv_nsec / 1000 / 1000);
-
- return MAX(0, ((int64_t)head_timer->expiry_time - now_ms));
-}
-
-
-void spice_timer_queue_cb(void)
-{
- struct timespec now;
- uint64_t now_ms;
- RingItem *head;
- SpiceTimerQueue *queue = spice_timer_queue_find_with_lock();
-
- spice_assert(queue != NULL);
-
- if (ring_is_empty(&queue->active_timers)) {
- return;
- }
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- now_ms = ((uint64_t)now.tv_sec * 1000) + (now.tv_nsec / 1000 / 1000);
-
- while ((head = ring_get_head(&queue->active_timers))) {
- SpiceTimer *timer = SPICE_CONTAINEROF(head, SpiceTimer, active_link);
-
- if (timer->expiry_time > now_ms) {
- break;
- } else {
- /* Remove active timer before calling the timer function.
- * Timer function could delete the timer making the timer
- * pointer point to freed data.
- */
- spice_timer_cancel(timer);
- timer->func(timer->opaque);
- /* timer could now be invalid ! */
- }
- }
-}
diff --git a/server/spice_timer_queue.h b/server/spice_timer_queue.h
deleted file mode 100644
index a84f6cd..0000000
--- a/server/spice_timer_queue.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright (C) 2013 Red Hat, Inc.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _H_SPICE_TIMER_QUEUE
-#define _H_SPICE_TIMER_QUEUE
-
-#include <stdint.h>
-#include "spice.h"
-
-typedef struct SpiceTimerQueue SpiceTimerQueue;
-
-/* create/destroy a timer queue for the current thread.
- * In order to execute the timers functions, spice_timer_queue_cb should be called
- * periodically, according to spice_timer_queue_get_timeout_ms */
-int spice_timer_queue_create(void);
-void spice_timer_queue_destroy(void);
-
-SpiceTimer *spice_timer_queue_add(SpiceTimerFunc func, void *opaque);
-void spice_timer_set(SpiceTimer *timer, uint32_t ms);
-void spice_timer_cancel(SpiceTimer *timer);
-void spice_timer_remove(SpiceTimer *timer);
-
-/* returns the time left till the earliest timer in the queue expires.
- * returns (unsigned)-1 if there are no active timers */
-unsigned int spice_timer_queue_get_timeout_ms(void);
-/* call the timeout callbacks of all the expired timers */
-void spice_timer_queue_cb(void);
-
-#endif
--
2.4.3
More information about the Spice-devel
mailing list