1/* 2 * Copyright 2011 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22#ifdef HAVE_CONFIG_H 23#include "config.h" 24#endif 25 26#include <sys/time.h> 27 28#include <spice.h> 29#include "spiceqxl_main_loop.h" 30 31static int spiceqxl_main_loop_debug = 0; 32 33#define DPRINTF(x, format, ...) { \ 34 if (x <= spiceqxl_main_loop_debug) { \ 35 printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \ 36 } \ 37} 38 39/* From ring.h */ 40typedef struct Ring RingItem; 41typedef struct Ring { 42 RingItem *prev; 43 RingItem *next; 44} Ring; 45 46static inline void ring_init(Ring *ring) 47{ 48 ring->next = ring->prev = ring; 49} 50 51static inline void ring_item_init(RingItem *item) 52{ 53 item->next = item->prev = NULL; 54} 55 56static inline int ring_item_is_linked(RingItem *item) 57{ 58 return !!item->next; 59} 60 61static inline int ring_is_empty(Ring *ring) 62{ 63 assert(ring->next != NULL && ring->prev != NULL); 64 return ring == ring->next; 65} 66 67static inline void ring_add(Ring *ring, RingItem *item) 68{ 69 assert(ring->next != NULL && ring->prev != NULL); 70 assert(item->next == NULL && item->prev == NULL); 71 72 item->next = ring->next; 73 item->prev = ring; 74 ring->next = item->next->prev = item; 75} 76 77static inline void __ring_remove(RingItem *item) 78{ 79 item->next->prev = item->prev; 80 item->prev->next = item->next; 81 item->prev = item->next = 0; 82} 83 84static inline void ring_remove(RingItem *item) 85{ 86 assert(item->next != NULL && item->prev != NULL); 87 assert(item->next != item); 88 89 __ring_remove(item); 90} 91 92static inline RingItem *ring_get_head(Ring *ring) 93{ 94 RingItem *ret; 95 96 assert(ring->next != NULL && ring->prev != NULL); 97 98 if (ring_is_empty(ring)) { 99 return NULL; 100 } 101 ret = ring->next; 102 return ret; 103} 104 105static inline RingItem *ring_get_tail(Ring *ring) 106{ 107 RingItem *ret; 108 109 assert(ring->next != NULL && ring->prev != NULL); 110 111 if (ring_is_empty(ring)) { 112 return NULL; 113 } 114 ret = ring->prev; 115 return ret; 116} 117 118static inline RingItem *ring_next(Ring *ring, RingItem *pos) 119{ 120 RingItem *ret; 121 122 assert(ring->next != NULL && ring->prev != NULL); 123 assert(pos); 124 assert(pos->next != NULL && pos->prev != NULL); 125 ret = pos->next; 126 return (ret == ring) ? NULL : ret; 127} 128 129static inline RingItem *ring_prev(Ring *ring, RingItem *pos) 130{ 131 RingItem *ret; 132 133 assert(ring->next != NULL && ring->prev != NULL); 134 assert(pos); 135 assert(pos->next != NULL && pos->prev != NULL); 136 ret = pos->prev; 137 return (ret == ring) ? NULL : ret; 138} 139 140#define RING_FOREACH_SAFE(var, next, ring) \ 141 for ((var) = ring_get_head(ring), \ 142 (next) = (var) ? ring_next(ring, (var)) : NULL; \ 143 (var); \ 144 (var) = (next), \ 145 (next) = (var) ? ring_next(ring, (var)) : NULL) 146 147/**/ 148 149#define NOT_IMPLEMENTED printf("%s not implemented\n", __func__); 150 151static SpiceCoreInterface core; 152 153typedef struct SpiceTimer { 154 OsTimerPtr xorg_timer; 155 SpiceTimerFunc func; 156 void *opaque; // also stored in xorg_timer, but needed for timer_start 157} Timer; 158 159static CARD32 xorg_timer_callback( 160 OsTimerPtr xorg_timer, 161 CARD32 time, 162 pointer arg) 163{ 164 SpiceTimer *timer = (SpiceTimer*)arg; 165 166 timer->func(timer->opaque); 167 return 0; // if non zero xorg does a TimerSet, we don't want that. 168} 169 170static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque) 171{ 172 SpiceTimer *timer = calloc(sizeof(SpiceTimer), 1); 173 174 timer->func = func; 175 timer->opaque = opaque; 176 return timer; 177} 178 179static void timer_start(SpiceTimer *timer, uint32_t ms) 180{ 181 timer->xorg_timer = TimerSet(timer->xorg_timer, 0 /* flags */, 182 ms, xorg_timer_callback, timer); 183} 184 185static void timer_cancel(SpiceTimer *timer) 186{ 187 TimerCancel(timer->xorg_timer); 188} 189 190static void timer_remove(SpiceTimer *timer) 191{ 192 TimerFree(timer->xorg_timer); 193 free(timer); 194} 195 196#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23 197struct SpiceWatch { 198 RingItem link; 199 int fd; 200 int event_mask; 201 SpiceWatchFunc func; 202 void *opaque; 203 int remove; 204}; 205 206Ring watches; 207 208int watch_count = 0; 209 210static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) 211{ 212 SpiceWatch *watch = xnfalloc(sizeof(SpiceWatch)); 213 214 DPRINTF(0, "adding %p, fd=%d at %d", watch, 215 fd, watch_count); 216 watch->fd = fd; 217 watch->event_mask = event_mask; 218 watch->func = func; 219 watch->opaque = opaque; 220 watch->remove = FALSE; 221 ring_item_init(&watch->link); 222 ring_add(&watches, &watch->link); 223 watch_count++; 224 return watch; 225} 226 227static void watch_update_mask(SpiceWatch *watch, int event_mask) 228{ 229 DPRINTF(0, "fd %d to %d", watch->fd, event_mask); 230 watch->event_mask = event_mask; 231} 232 233static void watch_remove(SpiceWatch *watch) 234{ 235 DPRINTF(0, "remove %p (fd %d)", watch, watch->fd); 236 watch->remove = TRUE; 237 watch_count--; 238} 239 240static int set_watch_fds(fd_set *rfds, fd_set *wfds) 241{ 242 SpiceWatch *watch; 243 RingItem *link; 244 RingItem *next; 245 int max_fd = -1; 246 247 RING_FOREACH_SAFE(link, next, &watches) { 248 watch = (SpiceWatch*)link; 249 if (watch->event_mask & SPICE_WATCH_EVENT_READ) { 250 FD_SET(watch->fd, rfds); 251 max_fd = watch->fd > max_fd ? watch->fd : max_fd; 252 } 253 if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) { 254 FD_SET(watch->fd, wfds); 255 max_fd = watch->fd > max_fd ? watch->fd : max_fd; 256 } 257 } 258 return max_fd; 259} 260 261/* 262 * called just before the X server goes into select() 263 * readmask is just an fdset on linux, but something totally different on windows (etc). 264 * DIX has a comment about it using a special type to hide this (so we break that here) 265 */ 266static void xspice_block_handler(pointer data, OSTimePtr timeout, pointer readmask) 267{ 268 /* set all our fd's */ 269 set_watch_fds((fd_set*)readmask, (fd_set*)readmask); 270} 271 272/* 273 * xserver only calls wakeup_handler with the read fd_set, so we 274 * must either patch it or do a polling select ourselves, this is the 275 * latter approach. Since we are already doing a polling select, we 276 * already select on all (we could avoid selecting on the read since 277 * that *is* actually taken care of by the wakeup handler). 278 */ 279static void select_and_check_watches(void) 280{ 281 fd_set rfds, wfds; 282 int max_fd = -1; 283 SpiceWatch *watch; 284 RingItem *link; 285 RingItem *next; 286 struct timeval timeout; 287 int retval; 288 289 FD_ZERO(&rfds); 290 FD_ZERO(&wfds); 291 max_fd = set_watch_fds(&rfds, &wfds); 292 watch = (SpiceWatch*)watches.next; 293 timeout.tv_sec = timeout.tv_usec = 0; 294 retval = select(max_fd + 1, &rfds, &wfds, NULL, &timeout); 295 if (retval > 0) { 296 RING_FOREACH_SAFE(link, next, &watches) { 297 watch = (SpiceWatch*)link; 298 if (!watch->remove && (watch->event_mask & SPICE_WATCH_EVENT_READ) 299 && FD_ISSET(watch->fd, &rfds)) { 300 watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque); 301 } 302 if (!watch->remove && (watch->event_mask & SPICE_WATCH_EVENT_WRITE) 303 && FD_ISSET(watch->fd, &wfds)) { 304 watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque); 305 } 306 if (watch->remove) { 307 ring_remove(&watch->link); 308 free(watch); 309 } 310 } 311 } 312} 313 314static int no_write_watches(Ring *w) 315{ 316 SpiceWatch *watch; 317 RingItem *link; 318 RingItem *next; 319 320 RING_FOREACH_SAFE(link, next, w) { 321 watch = (SpiceWatch*)link; 322 if (!watch->remove && (watch->event_mask & SPICE_WATCH_EVENT_WRITE)) 323 return 0; 324 } 325 326 return 1; 327} 328 329static void xspice_wakeup_handler(pointer data, int nfds, pointer readmask) 330{ 331 if (!nfds && no_write_watches(&watches)) { 332 return; 333 } 334 select_and_check_watches(); 335} 336 337#else /* GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23 */ 338 339struct SpiceWatch { 340 int fd; 341 int event_mask; 342 SpiceWatchFunc func; 343 void *opaque; 344}; 345 346static void watch_fd_notified(int fd, int xevents, void *data) 347{ 348 SpiceWatch *watch = (SpiceWatch *)data; 349 350 if ((watch->event_mask & SPICE_WATCH_EVENT_READ) && (xevents & X_NOTIFY_READ)) { 351 watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque); 352 } 353 354 if ((watch->event_mask & SPICE_WATCH_EVENT_WRITE) && (xevents & X_NOTIFY_WRITE)) { 355 watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque); 356 } 357} 358 359static int watch_update_mask_internal(SpiceWatch *watch, int event_mask) 360{ 361 int x_event_mask = 0; 362 363 SetNotifyFd(watch->fd, NULL, X_NOTIFY_NONE, NULL); 364 watch->event_mask = 0; 365 366 if (event_mask & SPICE_WATCH_EVENT_READ) { 367 x_event_mask |= X_NOTIFY_READ; 368 } 369 if (event_mask & SPICE_WATCH_EVENT_WRITE) { 370 x_event_mask |= X_NOTIFY_WRITE; 371 } 372 if (x_event_mask == 0) { 373 DPRINTF(0, "Unexpected watch event_mask: %i", event_mask); 374 return -1; 375 } 376 SetNotifyFd(watch->fd, watch_fd_notified, x_event_mask, watch); 377 watch->event_mask = event_mask; 378 379 return 0; 380} 381 382static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) 383{ 384 SpiceWatch *watch = xnfalloc(sizeof(SpiceWatch)); 385 386 DPRINTF(0, "adding %p, fd=%d", watch, fd); 387 388 watch->fd = fd; 389 watch->func = func; 390 watch->opaque = opaque; 391 if (watch_update_mask_internal(watch, event_mask) != 0) { 392 free(watch); 393 return NULL; 394 } 395 396 return watch; 397} 398 399static void watch_update_mask(SpiceWatch *watch, int event_mask) 400{ 401 DPRINTF(0, "fd %d to %d", watch->fd, event_mask); 402 watch_update_mask_internal(watch, event_mask); 403} 404 405static void watch_remove(SpiceWatch *watch) 406{ 407 DPRINTF(0, "remove %p (fd %d)", watch, watch->fd); 408 RemoveNotifyFd(watch->fd); 409 free(watch); 410} 411#endif 412 413static void channel_event(int event, SpiceChannelEventInfo *info) 414{ 415 NOT_IMPLEMENTED 416} 417 418 419SpiceCoreInterface *basic_event_loop_init(void) 420{ 421#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23 422 ring_init(&watches); 423#endif 424 bzero(&core, sizeof(core)); 425 core.base.major_version = SPICE_INTERFACE_CORE_MAJOR; 426 core.base.minor_version = SPICE_INTERFACE_CORE_MINOR; // anything less than 3 and channel_event isn't called 427 core.timer_add = timer_add; 428 core.timer_start = timer_start; 429 core.timer_cancel = timer_cancel; 430 core.timer_remove = timer_remove; 431 core.watch_add = watch_add; 432 core.watch_update_mask = watch_update_mask; 433 core.watch_remove = watch_remove; 434 core.channel_event = channel_event; 435 return &core; 436} 437 438 439void xspice_register_handlers(void) 440{ 441#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23 442 RegisterBlockAndWakeupHandlers(xspice_block_handler, xspice_wakeup_handler, 0); 443#endif 444} 445