mirror of
git://git.proxmox.com/git/spiceterm.git
synced 2025-01-08 21:18:03 +03:00
use glib event loop
This commit is contained in:
parent
a1cf2514dd
commit
0535e19165
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
|
||||
PROGRAMS=test_display_no_ssl spiceterm
|
||||
|
||||
HEADERS=test_display_base.h basic_event_loop.h ring.h glyphs.h spiceterm.h
|
||||
HEADERS=test_display_base.h basic_event_loop.h glyphs.h spiceterm.h
|
||||
SOURCES=test_display_base.c basic_event_loop.c
|
||||
|
||||
all: ${PROGRAMS}
|
||||
|
@ -7,110 +7,174 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include <spice/macros.h>
|
||||
#include "ring.h"
|
||||
#include "basic_event_loop.h"
|
||||
|
||||
int debug = 0;
|
||||
|
||||
int debug = 1;
|
||||
|
||||
#define DPRINTF(x, format, ...) { \
|
||||
if (x <= debug) { \
|
||||
printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NOT_IMPLEMENTED printf("%s not implemented\n", __func__);
|
||||
static GMainLoop *main_loop;
|
||||
|
||||
static SpiceCoreInterface core;
|
||||
|
||||
typedef struct SpiceTimer {
|
||||
RingItem link;
|
||||
GSource *source;
|
||||
SpiceTimerFunc func;
|
||||
struct timeval tv_start;
|
||||
int ms;
|
||||
void *opaque;
|
||||
} Timer;
|
||||
|
||||
Ring timers;
|
||||
|
||||
static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque)
|
||||
{
|
||||
g_return_val_if_fail(func != NULL, NULL);
|
||||
|
||||
SpiceTimer *timer = g_new0(SpiceTimer, 1);
|
||||
|
||||
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_callback(gpointer data)
|
||||
{
|
||||
tv->tv_usec += 1000 * ms;
|
||||
while (tv->tv_usec >= 1000000) {
|
||||
tv->tv_sec++;
|
||||
tv->tv_usec -= 1000000;
|
||||
}
|
||||
SpiceTimer *timer = (SpiceTimer *)data;
|
||||
g_assert(timer != NULL);
|
||||
g_assert(timer->func != NULL);
|
||||
|
||||
timer->func(timer->opaque);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void timer_start(SpiceTimer *timer, uint32_t ms)
|
||||
{
|
||||
g_assert(ms != 0);
|
||||
gettimeofday(&timer->tv_start, NULL);
|
||||
timer->ms = ms;
|
||||
// already add ms to timer value
|
||||
add_ms_to_timeval(&timer->tv_start, ms);
|
||||
g_return_if_fail(timer != NULL);
|
||||
g_return_if_fail(ms != 0);
|
||||
|
||||
if (timer->source != NULL) {
|
||||
g_source_destroy(timer->source);
|
||||
}
|
||||
|
||||
timer->source = g_timeout_source_new(ms);
|
||||
g_assert(timer->source != NULL);
|
||||
|
||||
g_source_set_callback(timer->source, timer_callback, timer, NULL);
|
||||
|
||||
g_source_attach(timer->source, NULL);
|
||||
}
|
||||
|
||||
static void timer_cancel(SpiceTimer *timer)
|
||||
{
|
||||
g_return_if_fail(timer != NULL);
|
||||
|
||||
if (timer->source != NULL) {
|
||||
g_source_destroy(timer->source);
|
||||
timer->source = NULL;
|
||||
}
|
||||
|
||||
timer->ms = 0;
|
||||
}
|
||||
|
||||
static void timer_remove(SpiceTimer *timer)
|
||||
{
|
||||
ring_remove(&timer->link);
|
||||
g_return_if_fail(timer != NULL);
|
||||
|
||||
timer_cancel(timer);
|
||||
g_free(timer);
|
||||
}
|
||||
|
||||
struct SpiceWatch {
|
||||
RingItem link;
|
||||
GIOChannel *channel;
|
||||
guint evid;
|
||||
int fd;
|
||||
int event_mask;
|
||||
SpiceWatchFunc func;
|
||||
int removed;
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
Ring watches;
|
||||
static gboolean watch_callback(GIOChannel *source, GIOCondition condition, gpointer data)
|
||||
{
|
||||
SpiceWatch *watch = (SpiceWatch *)data;
|
||||
|
||||
int watch_count = 0;
|
||||
g_assert(watch != NULL);
|
||||
g_assert(watch->func != NULL);
|
||||
|
||||
if (condition & G_IO_OUT) {
|
||||
watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
|
||||
}
|
||||
|
||||
if (condition & G_IO_IN) {
|
||||
watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GIOCondition event_mask_to_condition(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 SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
|
||||
{
|
||||
SpiceWatch *watch = g_new0(SpiceWatch, 1);
|
||||
|
||||
DPRINTF(0, "adding %p, fd=%d at %d", watch,
|
||||
fd, watch_count);
|
||||
DPRINTF(0, "adding %p, fd=%d", watch, fd);
|
||||
|
||||
watch->fd = fd;
|
||||
watch->event_mask = event_mask;
|
||||
watch->func = func;
|
||||
watch->opaque = opaque;
|
||||
watch->removed = FALSE;
|
||||
ring_item_init(&watch->link);
|
||||
ring_add(&watches, &watch->link);
|
||||
watch_count++;
|
||||
watch->channel = g_io_channel_unix_new(fd);
|
||||
|
||||
g_assert(watch->channel != NULL);
|
||||
g_io_channel_set_encoding(watch->channel, NULL, NULL);
|
||||
|
||||
GIOCondition condition = event_mask_to_condition(event_mask);
|
||||
watch->evid = g_io_add_watch(watch->channel, condition, watch_callback, watch);
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void watch_update_mask(SpiceWatch *watch, int event_mask)
|
||||
{
|
||||
g_assert(watch != NULL);
|
||||
|
||||
DPRINTF(0, "fd %d to %d", watch->fd, event_mask);
|
||||
|
||||
watch->event_mask = event_mask;
|
||||
|
||||
g_source_remove(watch->evid);
|
||||
|
||||
GIOCondition condition = event_mask_to_condition(event_mask);
|
||||
watch->evid = g_io_add_watch(watch->channel, condition, watch_callback, watch);
|
||||
}
|
||||
|
||||
static void watch_remove(SpiceWatch *watch)
|
||||
{
|
||||
g_assert(watch != NULL);
|
||||
|
||||
DPRINTF(0, "remove %p (fd %d)", watch, watch->fd);
|
||||
watch_count--;
|
||||
watch->removed = TRUE;
|
||||
|
||||
g_source_remove(watch->evid);
|
||||
g_io_channel_unref(watch->channel);
|
||||
|
||||
g_free(watch);
|
||||
}
|
||||
|
||||
static void channel_event(int event, SpiceChannelEventInfo *info)
|
||||
@ -119,139 +183,9 @@ 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;
|
||||
|
||||
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);
|
||||
g_free(watch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_main_loop_run(main_loop);
|
||||
}
|
||||
|
||||
static void ignore_sigpipe(void)
|
||||
@ -266,11 +200,11 @@ static void ignore_sigpipe(void)
|
||||
|
||||
SpiceCoreInterface *basic_event_loop_init(void)
|
||||
{
|
||||
ring_init(&watches);
|
||||
ring_init(&timers);
|
||||
main_loop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
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.base.minor_version = SPICE_INTERFACE_CORE_MINOR;
|
||||
core.timer_add = timer_add;
|
||||
core.timer_start = timer_start;
|
||||
core.timer_cancel = timer_cancel;
|
||||
@ -279,6 +213,8 @@ SpiceCoreInterface *basic_event_loop_init(void)
|
||||
core.watch_update_mask = watch_update_mask;
|
||||
core.watch_remove = watch_remove;
|
||||
core.channel_event = channel_event;
|
||||
|
||||
ignore_sigpipe();
|
||||
|
||||
return &core;
|
||||
}
|
||||
|
170
ring.h
170
ring.h
@ -1,170 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/*
|
||||
Copyright (C) 2009 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_RING2
|
||||
#define _H_RING2
|
||||
|
||||
#include <glib.h>
|
||||
#include <spice/macros.h>
|
||||
//#include "spice_common.h"
|
||||
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
typedef struct Ring RingItem;
|
||||
typedef struct Ring {
|
||||
RingItem *prev;
|
||||
RingItem *next;
|
||||
} Ring;
|
||||
|
||||
static inline void ring_init(Ring *ring)
|
||||
{
|
||||
ring->next = ring->prev = ring;
|
||||
}
|
||||
|
||||
static inline void ring_item_init(RingItem *item)
|
||||
{
|
||||
item->next = item->prev = NULL;
|
||||
}
|
||||
|
||||
static inline int ring_item_is_linked(RingItem *item)
|
||||
{
|
||||
return !!item->next;
|
||||
}
|
||||
|
||||
static inline int ring_is_empty(Ring *ring)
|
||||
{
|
||||
g_assert(ring->next != NULL && ring->prev != NULL);
|
||||
return ring == ring->next;
|
||||
}
|
||||
|
||||
static inline void ring_add(Ring *ring, RingItem *item)
|
||||
{
|
||||
g_assert(ring->next != NULL && ring->prev != NULL);
|
||||
g_assert(item->next == NULL && item->prev == NULL);
|
||||
|
||||
item->next = ring->next;
|
||||
item->prev = ring;
|
||||
ring->next = item->next->prev = item;
|
||||
}
|
||||
|
||||
static inline void ring_add_after(RingItem *item, RingItem *pos)
|
||||
{
|
||||
ring_add(pos, item);
|
||||
}
|
||||
|
||||
static inline void ring_add_before(RingItem *item, RingItem *pos)
|
||||
{
|
||||
ring_add(pos->prev, item);
|
||||
}
|
||||
|
||||
static inline void __ring_remove(RingItem *item)
|
||||
{
|
||||
item->next->prev = item->prev;
|
||||
item->prev->next = item->next;
|
||||
item->prev = item->next = 0;
|
||||
}
|
||||
|
||||
static inline void ring_remove(RingItem *item)
|
||||
{
|
||||
g_assert(item->next != NULL && item->prev != NULL);
|
||||
g_assert(item->next != item);
|
||||
|
||||
__ring_remove(item);
|
||||
}
|
||||
|
||||
static inline RingItem *ring_get_head(Ring *ring)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
g_assert(ring->next != NULL && ring->prev != NULL);
|
||||
|
||||
if (ring_is_empty(ring)) {
|
||||
return NULL;
|
||||
}
|
||||
ret = ring->next;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline RingItem *ring_get_tail(Ring *ring)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
g_assert(ring->next != NULL && ring->prev != NULL);
|
||||
|
||||
if (ring_is_empty(ring)) {
|
||||
return NULL;
|
||||
}
|
||||
ret = ring->prev;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
g_assert(ring->next != NULL && ring->prev != NULL);
|
||||
g_assert(pos);
|
||||
g_assert(pos->next != NULL && pos->prev != NULL);
|
||||
ret = pos->next;
|
||||
return (ret == ring) ? NULL : ret;
|
||||
}
|
||||
|
||||
static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
|
||||
{
|
||||
RingItem *ret;
|
||||
|
||||
g_assert(ring->next != NULL && ring->prev != NULL);
|
||||
g_assert(pos);
|
||||
g_assert(pos->next != NULL && pos->prev != NULL);
|
||||
ret = pos->prev;
|
||||
return (ret == ring) ? NULL : ret;
|
||||
}
|
||||
|
||||
#define RING_FOREACH_SAFE(var, next, ring) \
|
||||
for ((var) = ring_get_head(ring); \
|
||||
(var) && ((next) = ring_next(ring, (var)), 1); \
|
||||
(var) = (next))
|
||||
|
||||
|
||||
#define RING_FOREACH(var, ring) \
|
||||
for ((var) = ring_get_head(ring); \
|
||||
(var); \
|
||||
(var) = ring_next(ring, var))
|
||||
|
||||
#define RING_FOREACH_REVERSED(var, ring) \
|
||||
for ((var) = ring_get_tail(ring); \
|
||||
(var); \
|
||||
(var) = ring_prev(ring, var))
|
||||
|
||||
|
||||
static inline unsigned int ring_get_length(Ring *ring)
|
||||
{
|
||||
RingItem *i;
|
||||
unsigned int ret = 0;
|
||||
|
||||
for (i = ring_get_head(ring);
|
||||
i != NULL;
|
||||
i = ring_next(ring, i))
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SPICE_END_DECLS
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user