9 #include <spice/macros.h>
11 #include "basic_event_loop.h"
15 #define DPRINTF(x, format, ...) { \
17 printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
21 #define NOT_IMPLEMENTED printf("%s not implemented\n", __func__);
23 static SpiceCoreInterface core
;
25 typedef struct SpiceTimer
{
28 struct timeval tv_start
;
35 static SpiceTimer
* timer_add(SpiceTimerFunc func
, void *opaque
)
37 SpiceTimer
*timer
= calloc(sizeof(SpiceTimer
), 1);
40 timer
->opaque
= opaque
;
41 ring_add(&timers
, &timer
->link
);
45 static void add_ms_to_timeval(struct timeval
*tv
, int ms
)
47 tv
->tv_usec
+= 1000 * ms
;
48 while (tv
->tv_usec
>= 1000000) {
50 tv
->tv_usec
-= 1000000;
54 static void timer_start(SpiceTimer
*timer
, uint32_t ms
)
57 gettimeofday(&timer
->tv_start
, NULL
);
59 // already add ms to timer value
60 add_ms_to_timeval(&timer
->tv_start
, ms
);
63 static void timer_cancel(SpiceTimer
*timer
)
68 static void timer_remove(SpiceTimer
*timer
)
70 ring_remove(&timer
->link
);
86 static SpiceWatch
*watch_add(int fd
, int event_mask
, SpiceWatchFunc func
, void *opaque
)
88 SpiceWatch
*watch
= malloc(sizeof(SpiceWatch
));
90 DPRINTF(0, "adding %p, fd=%d at %d", watch
,
93 watch
->event_mask
= event_mask
;
95 watch
->opaque
= opaque
;
96 watch
->removed
= FALSE
;
97 ring_item_init(&watch
->link
);
98 ring_add(&watches
, &watch
->link
);
103 static void watch_update_mask(SpiceWatch
*watch
, int event_mask
)
105 DPRINTF(0, "fd %d to %d", watch
->fd
, event_mask
);
106 watch
->event_mask
= event_mask
;
109 static void watch_remove(SpiceWatch
*watch
)
111 DPRINTF(0, "remove %p (fd %d)", watch
, watch
->fd
);
113 watch
->removed
= TRUE
;
116 static void channel_event(int event
, SpiceChannelEventInfo
*info
)
118 DPRINTF(0, "channel event con, type, id, event: %ld, %d, %d, %d",
119 info
->connection_id
, info
->type
, info
->id
, event
);
122 SpiceTimer
*get_next_timer(void)
124 SpiceTimer
*next
, *min
;
126 if (ring_is_empty(&timers
)) {
129 min
= next
= (SpiceTimer
*)ring_get_head(&timers
);
130 while ((next
=(SpiceTimer
*)ring_next(&timers
, &next
->link
)) != NULL
) {
132 (next
->tv_start
.tv_sec
< min
->tv_start
.tv_sec
||
133 (next
->tv_start
.tv_sec
== min
->tv_start
.tv_sec
&&
134 next
->tv_start
.tv_usec
< min
->tv_start
.tv_usec
))) {
143 void tv_b_minus_a_return_le_zero(struct timeval
*a
, struct timeval
*b
, struct timeval
*dest
)
145 dest
->tv_usec
= b
->tv_usec
- a
->tv_usec
;
146 dest
->tv_sec
= b
->tv_sec
- a
->tv_sec
;
147 while (dest
->tv_usec
< 0) {
148 dest
->tv_usec
+= 1000000;
151 if (dest
->tv_sec
< 0) {
157 void calc_next_timeout(SpiceTimer
*next
, struct timeval
*timeout
)
159 gettimeofday(&now
, NULL
);
160 tv_b_minus_a_return_le_zero(&now
, &next
->tv_start
, timeout
);
163 void timeout_timers(void)
169 next
= (SpiceTimer
*)ring_get_head(&timers
);
170 while (next
!= NULL
) {
171 tv_b_minus_a_return_le_zero(&now
, &next
->tv_start
, &left
);
172 if (next
->ms
&& left
.tv_usec
== 0 && left
.tv_sec
== 0) {
174 DPRINTF(2, "calling timer");
176 next
->func(next
->opaque
);
178 next
= (SpiceTimer
*)ring_next(&timers
, &next
->link
);
180 DPRINTF(2, "called %d timers", count
);
183 void basic_event_loop_mainloop(void)
190 SpiceTimer
*next_timer
;
193 struct timeval next_timer_timeout
;
194 struct timeval
*timeout
;
200 RING_FOREACH_SAFE(link
, next
, &watches
) {
201 watch
= (SpiceWatch
*)link
;
202 if (watch
->removed
) {
205 if (watch
->event_mask
& SPICE_WATCH_EVENT_READ
) {
206 FD_SET(watch
->fd
, &rfds
);
207 max_fd
= watch
->fd
> max_fd
? watch
->fd
: max_fd
;
209 if (watch
->event_mask
& SPICE_WATCH_EVENT_WRITE
) {
210 FD_SET(watch
->fd
, &wfds
);
211 max_fd
= watch
->fd
> max_fd
? watch
->fd
: max_fd
;
215 if ((next_timer
= get_next_timer()) != NULL
) {
216 calc_next_timeout(next_timer
, &next_timer_timeout
);
217 timeout
= &next_timer_timeout
;
218 DPRINTF(2, "timeout of %zd.%06zd",
219 timeout
->tv_sec
, timeout
->tv_usec
);
223 DPRINTF(1, "watching %d fds", i
);
224 retval
= select(max_fd
+ 1, &rfds
, &wfds
, NULL
, timeout
);
225 if (timeout
!= NULL
) {
226 calc_next_timeout(next_timer
, &next_timer_timeout
);
227 if (next_timer_timeout
.tv_sec
== 0 &&
228 next_timer_timeout
.tv_usec
== 0) {
233 printf("error in select - exiting\n");
237 RING_FOREACH_SAFE(link
, next
, &watches
) {
238 watch
= SPICE_CONTAINEROF(link
, SpiceWatch
, link
);
239 if (!watch
->removed
&& (watch
->event_mask
& SPICE_WATCH_EVENT_READ
)
240 && FD_ISSET(watch
->fd
, &rfds
)) {
241 watch
->func(watch
->fd
, SPICE_WATCH_EVENT_READ
, watch
->opaque
);
243 if (!watch
->removed
&& (watch
->event_mask
& SPICE_WATCH_EVENT_WRITE
)
244 && FD_ISSET(watch
->fd
, &wfds
)) {
245 watch
->func(watch
->fd
, SPICE_WATCH_EVENT_WRITE
, watch
->opaque
);
247 if (watch
->removed
) {
248 printf("freeing watch %p\n", watch
);
249 ring_remove(&watch
->link
);
257 static void ignore_sigpipe(void)
259 struct sigaction act
;
261 memset(&act
, 0, sizeof(act
));
262 sigfillset(&act
.sa_mask
);
263 act
.sa_handler
= SIG_IGN
;
264 sigaction(SIGPIPE
, &act
, NULL
);
267 SpiceCoreInterface
*basic_event_loop_init(void)
271 memset(&core
, 0, sizeof(core
));
272 core
.base
.major_version
= SPICE_INTERFACE_CORE_MAJOR
;
273 core
.base
.minor_version
= SPICE_INTERFACE_CORE_MINOR
; // anything less then 3 and channel_event isn't called
274 core
.timer_add
= timer_add
;
275 core
.timer_start
= timer_start
;
276 core
.timer_cancel
= timer_cancel
;
277 core
.timer_remove
= timer_remove
;
278 core
.watch_add
= watch_add
;
279 core
.watch_update_mask
= watch_update_mask
;
280 core
.watch_remove
= watch_remove
;
281 core
.channel_event
= channel_event
;