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