tests: use glib main loop

This commit is contained in:
Marc-André Lureau 2013-08-27 14:06:42 +02:00 committed by Frediano Ziglio
parent 87c4def087
commit f3179ef791
2 changed files with 97 additions and 190 deletions

View File

@ -1,6 +1,7 @@
NULL =
AM_CPPFLAGS = \
$(GLIB2_CFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/common \
-I$(top_srcdir)/server \
@ -18,6 +19,7 @@ AM_CPPFLAGS += -DAUTOMATED_TESTS
endif
LDADD = \
$(GLIB2_LIBS) \
$(top_builddir)/spice-common/common/libspice-common.la \
$(top_builddir)/server/libspice-server.la \
$(GLIB2_LIBS) \

View File

@ -4,6 +4,7 @@
#include <sys/time.h>
#include <signal.h>
#include <string.h>
#include <glib.h>
#include "spice/macros.h"
#include "common/ring.h"
@ -20,17 +21,12 @@ int debug = 0;
#define NOT_IMPLEMENTED printf("%s not implemented\n", __func__);
static SpiceCoreInterface core;
typedef struct SpiceTimer {
RingItem link;
SpiceTimerFunc func;
struct timeval tv_start;
int ms;
void *opaque;
} Timer;
Ring timers;
guint source_id;
} SpiceTimer;
static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque)
{
@ -38,79 +34,113 @@ static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque)
timer->func = func;
timer->opaque = opaque;
ring_add(&timers, &timer->link);
return timer;
}
static void add_ms_to_timeval(struct timeval *tv, int ms)
static gboolean timer_func(gpointer user_data)
{
tv->tv_usec += 1000 * ms;
while (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
SpiceTimer *timer = user_data;
static void timer_start(SpiceTimer *timer, uint32_t ms)
{
ASSERT(ms);
gettimeofday(&timer->tv_start, NULL);
timer->ms = ms;
// already add ms to timer value
add_ms_to_timeval(&timer->tv_start, ms);
timer->source_id = 0;
timer->func(timer->opaque);
/* timer might be free after func(), don't touch */
return FALSE;
}
static void timer_cancel(SpiceTimer *timer)
{
timer->ms = 0;
if (timer->source_id == 0)
return;
g_source_remove(timer->source_id);
timer->source_id = 0;
}
static void timer_start(SpiceTimer *timer, uint32_t ms)
{
timer_cancel(timer);
timer->source_id = g_timeout_add(ms, timer_func, timer);
}
static void timer_remove(SpiceTimer *timer)
{
ring_remove(&timer->link);
timer_cancel(timer);
g_free(timer);
}
struct SpiceWatch {
RingItem link;
int fd;
int event_mask;
SpiceWatchFunc func;
int removed;
typedef struct SpiceWatch {
void *opaque;
};
guint source_id;
GIOChannel *channel;
SpiceWatchFunc func;
} SpiceWatch;
Ring watches;
static GIOCondition spice_event_to_condition(int event_mask)
{
GIOCondition condition = 0;
int watch_count = 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 condition_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;
}
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, condition_to_spice_event(condition), watch->opaque);
return TRUE;
}
static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
{
SpiceWatch *watch = malloc(sizeof(SpiceWatch));
SpiceWatch *watch;
GIOCondition condition = spice_event_to_condition(event_mask);
DPRINTF(0, "adding %p, fd=%d at %d", watch,
fd, watch_count);
watch->fd = fd;
watch->event_mask = event_mask;
watch = g_new(SpiceWatch, 1);
watch->channel = g_io_channel_unix_new(fd);
watch->source_id = g_io_add_watch(watch->channel, condition, watch_func, watch);
watch->func = func;
watch->opaque = opaque;
watch->removed = FALSE;
ring_item_init(&watch->link);
ring_add(&watches, &watch->link);
watch_count++;
return watch;
}
static void watch_update_mask(SpiceWatch *watch, int event_mask)
{
DPRINTF(0, "fd %d to %d", watch->fd, event_mask);
watch->event_mask = event_mask;
GIOCondition condition = spice_event_to_condition(event_mask);
g_source_remove(watch->source_id);
if (condition != 0)
watch->source_id = g_io_add_watch(watch->channel, condition, watch_func, watch);
}
static void watch_remove(SpiceWatch *watch)
{
DPRINTF(0, "remove %p (fd %d)", watch, watch->fd);
watch_count--;
watch->removed = TRUE;
g_source_remove(watch->source_id);
g_io_channel_unref(watch->channel);
g_free(watch);
}
static void channel_event(int event, SpiceChannelEventInfo *info)
@ -119,139 +149,12 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
info->connection_id, info->type, info->id, event);
}
SpiceTimer *get_next_timer(void)
{
SpiceTimer *next, *min;
if (ring_is_empty(&timers)) {
return NULL;
}
min = next = (SpiceTimer*)ring_get_head(&timers);
while ((next=(SpiceTimer*)ring_next(&timers, &next->link)) != NULL) {
if (next->ms &&
(next->tv_start.tv_sec < min->tv_start.tv_sec ||
(next->tv_start.tv_sec == min->tv_start.tv_sec &&
next->tv_start.tv_usec < min->tv_start.tv_usec))) {
min = next;
}
}
return min;
}
struct timeval now;
void tv_b_minus_a_return_le_zero(struct timeval *a, struct timeval *b, struct timeval *dest)
{
dest->tv_usec = b->tv_usec - a->tv_usec;
dest->tv_sec = b->tv_sec - a->tv_sec;
while (dest->tv_usec < 0) {
dest->tv_usec += 1000000;
dest->tv_sec--;
}
if (dest->tv_sec < 0) {
dest->tv_sec = 0;
dest->tv_usec = 0;
}
}
void calc_next_timeout(SpiceTimer *next, struct timeval *timeout)
{
gettimeofday(&now, NULL);
tv_b_minus_a_return_le_zero(&now, &next->tv_start, timeout);
}
void timeout_timers(void)
{
SpiceTimer *next;
struct timeval left;
int count = 0;
next = (SpiceTimer*)ring_get_head(&timers);
while (next != NULL) {
tv_b_minus_a_return_le_zero(&now, &next->tv_start, &left);
if (next->ms && left.tv_usec == 0 && left.tv_sec == 0) {
count++;
DPRINTF(2, "calling timer");
next->ms = 0;
next->func(next->opaque);
}
next = (SpiceTimer*)ring_next(&timers, &next->link);
}
DPRINTF(2, "called %d timers", count);
}
void basic_event_loop_mainloop(void)
{
fd_set rfds, wfds;
int max_fd = -1;
int i;
int retval;
SpiceWatch *watch;
SpiceTimer *next_timer;
RingItem *link;
RingItem *next;
struct timeval next_timer_timeout;
struct timeval *timeout;
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
while (1) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
i = 0;
RING_FOREACH_SAFE(link, next, &watches) {
watch = (SpiceWatch*)link;
if (watch->removed) {
continue;
}
if (watch->event_mask & SPICE_WATCH_EVENT_READ) {
FD_SET(watch->fd, &rfds);
max_fd = watch->fd > max_fd ? watch->fd : max_fd;
}
if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
FD_SET(watch->fd, &wfds);
max_fd = watch->fd > max_fd ? watch->fd : max_fd;
}
i++;
}
if ((next_timer = get_next_timer()) != NULL) {
calc_next_timeout(next_timer, &next_timer_timeout);
timeout = &next_timer_timeout;
DPRINTF(2, "timeout of %zd.%06zd",
timeout->tv_sec, timeout->tv_usec);
} else {
timeout = NULL;
}
DPRINTF(1, "watching %d fds", i);
retval = select(max_fd + 1, &rfds, &wfds, NULL, timeout);
if (timeout != NULL) {
calc_next_timeout(next_timer, &next_timer_timeout);
if (next_timer_timeout.tv_sec == 0 &&
next_timer_timeout.tv_usec == 0) {
timeout_timers();
}
}
if (retval == -1) {
printf("error in select - exiting\n");
abort();
}
if (retval) {
RING_FOREACH_SAFE(link, next, &watches) {
watch = SPICE_CONTAINEROF(link, SpiceWatch, link);
if (!watch->removed && (watch->event_mask & SPICE_WATCH_EVENT_READ)
&& FD_ISSET(watch->fd, &rfds)) {
watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
}
if (!watch->removed && (watch->event_mask & SPICE_WATCH_EVENT_WRITE)
&& FD_ISSET(watch->fd, &wfds)) {
watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
}
if (watch->removed) {
printf("freeing watch %p\n", watch);
ring_remove(&watch->link);
free(watch);
}
}
}
}
g_main_loop_run(loop);
g_main_loop_unref(loop);
}
static void ignore_sigpipe(void)
@ -264,21 +167,23 @@ static void ignore_sigpipe(void)
sigaction(SIGPIPE, &act, NULL);
}
static SpiceCoreInterface core = {
.base = {
.major_version = SPICE_INTERFACE_CORE_MAJOR,
.minor_version = SPICE_INTERFACE_CORE_MINOR,
},
.timer_add = timer_add,
.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,
.channel_event = channel_event,
};
SpiceCoreInterface *basic_event_loop_init(void)
{
ring_init(&watches);
ring_init(&timers);
memset(&core, 0, sizeof(core));
core.base.major_version = SPICE_INTERFACE_CORE_MAJOR;
core.base.minor_version = SPICE_INTERFACE_CORE_MINOR; // anything less then 3 and channel_event isn't called
core.timer_add = timer_add;
core.timer_start = timer_start;
core.timer_cancel = timer_cancel;
core.timer_remove = timer_remove;
core.watch_add = watch_add;
core.watch_update_mask = watch_update_mask;
core.watch_remove = watch_remove;
core.channel_event = channel_event;
ignore_sigpipe();
return &core;
}