Home | History | Annotate | Line # | Download | only in src
      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 
     31 static 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 */
     40 typedef struct Ring RingItem;
     41 typedef struct Ring {
     42     RingItem *prev;
     43     RingItem *next;
     44 } Ring;
     45 
     46 static inline void ring_init(Ring *ring)
     47 {
     48     ring->next = ring->prev = ring;
     49 }
     50 
     51 static inline void ring_item_init(RingItem *item)
     52 {
     53     item->next = item->prev = NULL;
     54 }
     55 
     56 static inline int ring_item_is_linked(RingItem *item)
     57 {
     58     return !!item->next;
     59 }
     60 
     61 static inline int ring_is_empty(Ring *ring)
     62 {
     63     assert(ring->next != NULL && ring->prev != NULL);
     64     return ring == ring->next;
     65 }
     66 
     67 static 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 
     77 static 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 
     84 static 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 
     92 static 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 
    105 static 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 
    118 static 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 
    129 static 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 
    151 static SpiceCoreInterface core;
    152 
    153 typedef 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 
    159 static 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 
    170 static 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 
    179 static 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 
    185 static void timer_cancel(SpiceTimer *timer)
    186 {
    187     TimerCancel(timer->xorg_timer);
    188 }
    189 
    190 static 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
    197 struct SpiceWatch {
    198     RingItem link;
    199     int fd;
    200     int event_mask;
    201     SpiceWatchFunc func;
    202     void *opaque;
    203     int remove;
    204 };
    205 
    206 Ring watches;
    207 
    208 int watch_count = 0;
    209 
    210 static 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 
    227 static 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 
    233 static 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 
    240 static 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  */
    266 static 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  */
    279 static 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 
    314 static 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 
    329 static 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 
    339 struct SpiceWatch {
    340     int fd;
    341     int event_mask;
    342     SpiceWatchFunc func;
    343     void *opaque;
    344 };
    345 
    346 static 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 
    359 static 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 
    382 static 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 
    399 static 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 
    405 static 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 
    413 static void channel_event(int event, SpiceChannelEventInfo *info)
    414 {
    415     NOT_IMPLEMENTED
    416 }
    417 
    418 
    419 SpiceCoreInterface *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 
    439 void 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