Commit 6c92a6e0 authored by Alon Levy's avatar Alon Levy

xspice: init spice server, add main loop

Initialize a SpiceServer instance, and implement SpiceCoreInterface,
that is fd read, write notification and watchs (timers).

The SpiceServer instance creation is wrapped in xspice_get_spice_server to allow
access from the pointer and keyboard drivers introduced later.

The fd implementation is off because Xserver doesn't allow us to be
notified on write unblock, only read. Workaround is to poll.
parent 2e869f64
......@@ -63,6 +63,7 @@ spiceqxl_drv_la_SOURCES = \
qxl.h \
spiceqxl_io_port.c \
spiceqxl_driver.c \
spiceqxl_main_loop.c \
qxl_driver.c \
qxl_image.c \
qxl_surface.c \
......
......@@ -28,6 +28,9 @@
#include <stdint.h>
#include <spice/qxl_dev.h>
#ifdef XSPICE
#include <spice.h>
#endif
#include "compiler.h"
#include "xf86.h"
......@@ -186,6 +189,7 @@ struct _qxl_screen_t
#ifdef XSPICE
/* XSpice specific */
struct QXLRom shadow_rom; /* Parameter RAM */
SpiceServer * spice_server;
#endif /* XSPICE */
};
......@@ -389,6 +393,9 @@ static inline void ioport_write(qxl_screen_t *qxl, int port, int val)
#define NUM_SURFACES 1024
/* initializes if required and returns the server singleton */
SpiceServer *xspice_get_spice_server(void);
#endif /* XSPICE */
#endif // QXL_H
......@@ -39,6 +39,7 @@
#ifdef XSPICE
#include "spiceqxl_driver.h"
#include "spiceqxl_main_loop.h"
#endif /* XSPICE */
#if 0
......@@ -883,6 +884,37 @@ setup_uxa (qxl_screen_t *qxl, ScreenPtr screen)
return TRUE;
}
#ifdef XSPICE
SpiceServer *xspice_get_spice_server(void)
{
static SpiceServer *spice_server;
if (!spice_server) {
spice_server = spice_server_new();
}
return spice_server;
}
static void
spiceqxl_screen_init(int scrnIndex, ScrnInfoPtr pScrn, qxl_screen_t *qxl)
{
SpiceCoreInterface *core;
// Init spice
if (!qxl->spice_server) {
qxl->spice_server = xspice_get_spice_server();
// some common initialization for all display tests
spice_server_set_port(qxl->spice_server, qxl->options[OPTION_SPICE_PORT].value.num);
spice_server_set_noauth(qxl->spice_server); // TODO - take this from config
// TODO - parse rest of parameters (streaming, compression, jpeg, etc.) from config
core = basic_event_loop_init();
spice_server_init(qxl->spice_server, core);
}
qxl->spice_server = qxl->spice_server;
}
#endif
static Bool
qxl_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
......@@ -898,6 +930,9 @@ qxl_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
if (!qxl_map_memory(qxl, scrnIndex))
return FALSE;
#ifdef XSPICE
spiceqxl_screen_init(scrnIndex, pScrn, qxl);
#endif
ram_header = (void *)((unsigned long)qxl->ram + (unsigned long)qxl->rom->ram_header_offset);
printf ("ram_header at %d\n", qxl->rom->ram_header_offset);
......
#include <sys/time.h>
#include <spice.h>
#include "spiceqxl_main_loop.h"
static int spiceqxl_main_loop_debug = 0;
#define DPRINTF(x, format, ...) { \
if (x <= spiceqxl_main_loop_debug) { \
printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
} \
}
/* From ring.h */
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)
{
assert(ring->next != NULL && ring->prev != NULL);
return ring == ring->next;
}
static inline void ring_add(Ring *ring, RingItem *item)
{
assert(ring->next != NULL && ring->prev != NULL);
assert(item->next == NULL && item->prev == NULL);
item->next = ring->next;
item->prev = ring;
ring->next = item->next->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)
{
assert(item->next != NULL && item->prev != NULL);
assert(item->next != item);
__ring_remove(item);
}
static inline RingItem *ring_get_head(Ring *ring)
{
RingItem *ret;
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;
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;
assert(ring->next != NULL && ring->prev != NULL);
assert(pos);
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;
assert(ring->next != NULL && ring->prev != NULL);
assert(pos);
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), \
(next) = (var) ? ring_next(ring, (var)) : NULL; \
(var); \
(var) = (next), \
(next) = (var) ? ring_next(ring, (var)) : NULL)
/**/
#define NOT_IMPLEMENTED printf("%s not implemented\n", __func__);
static SpiceCoreInterface core;
typedef struct SpiceTimer {
OsTimerPtr xorg_timer;
SpiceTimerFunc func;
void *opaque; // also stored in xorg_timer, but needed for timer_start
} Timer;
static CARD32 xorg_timer_callback(
OsTimerPtr xorg_timer,
CARD32 time,
pointer arg)
{
SpiceTimer *timer = (SpiceTimer*)arg;
timer->func(timer->opaque);
return 0; // if non zero xorg does a TimerSet, we don't want that.
}
static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque)
{
SpiceTimer *timer = calloc(sizeof(SpiceTimer), 1);
timer->xorg_timer = TimerSet(NULL, 0, 1e9 /* TODO: infinity? */, xorg_timer_callback, timer);
timer->func = func;
timer->opaque = opaque;
return timer;
}
static void timer_start(SpiceTimer *timer, uint32_t ms)
{
TimerSet(timer->xorg_timer, 0 /* flags */, ms, xorg_timer_callback, timer);
}
static void timer_cancel(SpiceTimer *timer)
{
TimerCancel(timer->xorg_timer);
}
static void timer_remove(SpiceTimer *timer)
{
TimerFree(timer->xorg_timer);
free(timer);
}
struct SpiceWatch {
RingItem link;
int fd;
int event_mask;
SpiceWatchFunc func;
void *opaque;
int remove;
};
Ring watches;
int watch_count = 0;
static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
{
SpiceWatch *watch = malloc(sizeof(SpiceWatch));
DPRINTF(0, "adding %p, fd=%d at %d", watch,
fd, watch_count);
watch->fd = fd;
watch->event_mask = event_mask;
watch->func = func;
watch->opaque = opaque;
watch->remove = 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;
}
static void watch_remove(SpiceWatch *watch)
{
DPRINTF(0, "remove %p (fd %d)", watch, watch->fd);
watch->remove = TRUE;
watch_count--;
}
static void channel_event(int event, SpiceChannelEventInfo *info)
{
NOT_IMPLEMENTED
}
static int set_watch_fds(fd_set *rfds, fd_set *wfds)
{
SpiceWatch *watch;
RingItem *link;
RingItem *next;
int max_fd = -1;
RING_FOREACH_SAFE(link, next, &watches) {
watch = (SpiceWatch*)link;
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;
}
}
return max_fd;
}
/*
* called just before the X server goes into select()
* readmask is just an fdset on linux, but something totally different on windows (etc).
* DIX has a comment about it using a special type to hide this (so we break that here)
*/
static void xspice_block_handler(pointer data, OSTimePtr timeout, pointer readmask)
{
/* set all our fd's */
set_watch_fds((fd_set*)readmask, (fd_set*)readmask);
}
/*
* xserver only calles wakeup_handler with the read fd_set, so we
* must either patch it or do a polling select ourselves, this is the
* later approach. Since we are already doing a polling select, we
* already select on all (we could avoid selecting on the read since
* that *is* actually taken care of by the wakeup handler).
*/
static void select_and_check_watches(void)
{
fd_set rfds, wfds;
int max_fd = -1;
SpiceWatch *watch;
RingItem *link;
RingItem *next;
struct timeval timeout;
int retval;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
max_fd = set_watch_fds(&rfds, &wfds);
watch = (SpiceWatch*)watches.next;
timeout.tv_sec = timeout.tv_usec = 0;
retval = select(max_fd + 1, &rfds, &wfds, NULL, &timeout);
if (retval) {
RING_FOREACH_SAFE(link, next, &watches) {
watch = (SpiceWatch*)link;
if ((watch->event_mask & SPICE_WATCH_EVENT_READ)
&& FD_ISSET(watch->fd, &rfds)) {
watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
}
if (!watch->remove && (watch->event_mask & SPICE_WATCH_EVENT_WRITE)
&& FD_ISSET(watch->fd, &wfds)) {
watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
}
if (watch->remove) {
ring_remove(&watch->link);
free(watch);
}
}
}
}
static void xspice_wakeup_handler(pointer data, int nfds, pointer readmask)
{
if (!nfds) {
return;
}
select_and_check_watches();
}
SpiceCoreInterface *basic_event_loop_init(void)
{
ring_init(&watches);
bzero(&core, 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;
RegisterBlockAndWakeupHandlers(xspice_block_handler, xspice_wakeup_handler, 0);
return &core;
}
#ifndef QXL_MAIN_LOOP_H
#define QXL_MAIN_LOOP_H
#include "qxl.h"
#include <spice.h>
SpiceCoreInterface *basic_event_loop_init(void);
void basic_event_loop_mainloop(void);
#endif // QXL_MAIN_LOOP_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment