diff options
Diffstat (limited to 'server/tests/basic_event_loop.c')
-rw-r--r-- | server/tests/basic_event_loop.c | 320 |
1 files changed, 275 insertions, 45 deletions
diff --git a/server/tests/basic_event_loop.c b/server/tests/basic_event_loop.c index 14dec512..f6570ff5 100644 --- a/server/tests/basic_event_loop.c +++ b/server/tests/basic_event_loop.c @@ -1,89 +1,287 @@ #include <stdlib.h> #include <stdio.h> +#include <sys/time.h> +#include "test_util.h" #include "basic_event_loop.h" +int debug = 0; + +#define DPRINTF(x, format, ...) { \ + if (x <= 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 { + RingItem link; + SpiceTimerFunc func; + struct timeval tv_start; + int ms; + void *opaque; +} Timer; + +Ring timers; + static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque) { - NOT_IMPLEMENTED + SpiceTimer *timer = calloc(sizeof(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) +{ + tv->tv_usec += 1000 * ms; + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } } static void timer_start(SpiceTimer *timer, uint32_t ms) { - NOT_IMPLEMENTED + gettimeofday(&timer->tv_start, NULL); + timer->ms = ms; + // already add ms to timer value + add_ms_to_timeval(&timer->tv_start, ms); + ASSERT(timer->ms); } static void timer_cancel(SpiceTimer *timer) { - NOT_IMPLEMENTED + timer->ms = 0; } static void timer_remove(SpiceTimer *timer) { - NOT_IMPLEMENTED + ring_remove(&timer->link); } struct SpiceWatch { - int id; -}; - -typedef struct Watch { - SpiceWatch id; + RingItem link; int fd; int event_mask; SpiceWatchFunc func; void *opaque; -} Watch; + int remove; +}; + +Ring watches; -Watch watches[100]; int watch_count = 0; -int next_id = 1; static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) { - watches[watch_count].fd = fd; - watches[watch_count].event_mask = event_mask; - watches[watch_count].func = func; - watches[watch_count].opaque = opaque; - watches[watch_count].id.id = next_id++; - return &watches[watch_count++].id; + 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) { - int i; - Watch *my_watch; - - for (i = 0 ; i < watch_count; ++i) { - if (watches[i].id.id == watch->id) { - my_watch = &watches[i]; - if (my_watch->event_mask != event_mask) { - my_watch->event_mask = event_mask; - } - return; - } - } + DPRINTF(0, "fd %d to %d", watch->fd, event_mask); + watch->event_mask = event_mask; } static void watch_remove(SpiceWatch *watch) { - int i; + DPRINTF(0, "remove %p (fd %d)", watch, watch->fd); + ring_remove(&watch->link); + watch->remove = TRUE; + watch_count--; +} - for (i = 0 ; i < watch_count ; ++i) { - if (watches[i].id.id == watch->id) { - watches[i] = watches[--watch_count]; - return; +static void channel_event(int event, SpiceChannelEventInfo *info) +{ + NOT_IMPLEMENTED +} + +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; } -static void channel_event(int event, SpiceChannelEventInfo *info) +struct timeval now; + +void tv_b_minus_a_return_le_zero(struct timeval *a, struct timeval *b, struct timeval *dest) { - NOT_IMPLEMENTED + 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() +{ + 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(1, "calling timer"); + next->func(next->opaque); + } + next = (SpiceTimer*)ring_next(&timers, &next->link); + } + DPRINTF(1, "called %d timers", count); } void basic_event_loop_mainloop(void) @@ -92,12 +290,20 @@ void basic_event_loop_mainloop(void) 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); - for (i = 0 ; i < watch_count; ++i) { - Watch* watch = &watches[i]; + watch = (SpiceWatch*)watches.next; + i = 0; + 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; @@ -106,21 +312,43 @@ void basic_event_loop_mainloop(void) 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(1, "timeout of %d.%06d", + 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(); + } } - retval = select(max_fd + 1, &rfds, &wfds, NULL, NULL); if (retval == -1) { printf("error in select - exiting\n"); - exit(-1); + abort(); } if (retval) { - for (i = 0 ; i < watch_count; ++i) { - Watch* watch = &watches[i]; - if ((watch->event_mask & SPICE_WATCH_EVENT_READ) && FD_ISSET(watch->fd, &rfds)) { + 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->event_mask & SPICE_WATCH_EVENT_WRITE) && FD_ISSET(watch->fd, &wfds)) { + 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) { + free(watch); + } } } } @@ -128,6 +356,8 @@ void basic_event_loop_mainloop(void) SpiceCoreInterface *basic_event_loop_init(void) { + ring_init(&watches); + ring_init(&timers); 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 |