]>
Commit | Line | Data |
---|---|---|
cc04455b DM |
1 | #include <stdlib.h> |
2 | #include <stdio.h> | |
3 | #include <sys/time.h> | |
4 | #include <signal.h> | |
5 | #include <string.h> | |
6 | ||
7 | #include <glib.h> | |
8 | ||
9 | #include <spice/macros.h> | |
10 | #include "ring.h" | |
11 | #include "basic_event_loop.h" | |
12 | ||
13 | int debug = 0; | |
14 | ||
15 | #define DPRINTF(x, format, ...) { \ | |
16 | if (x <= debug) { \ | |
17 | printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \ | |
18 | } \ | |
19 | } | |
20 | ||
21 | #define NOT_IMPLEMENTED printf("%s not implemented\n", __func__); | |
22 | ||
23 | static SpiceCoreInterface core; | |
24 | ||
25 | typedef struct SpiceTimer { | |
26 | RingItem link; | |
27 | SpiceTimerFunc func; | |
28 | struct timeval tv_start; | |
29 | int ms; | |
30 | void *opaque; | |
31 | } Timer; | |
32 | ||
33 | Ring timers; | |
34 | ||
35 | static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque) | |
36 | { | |
db8e5ef8 | 37 | SpiceTimer *timer = g_new0(SpiceTimer, 1); |
cc04455b DM |
38 | |
39 | timer->func = func; | |
40 | timer->opaque = opaque; | |
41 | ring_add(&timers, &timer->link); | |
42 | return timer; | |
43 | } | |
44 | ||
45 | static void add_ms_to_timeval(struct timeval *tv, int ms) | |
46 | { | |
47 | tv->tv_usec += 1000 * ms; | |
48 | while (tv->tv_usec >= 1000000) { | |
49 | tv->tv_sec++; | |
50 | tv->tv_usec -= 1000000; | |
51 | } | |
52 | } | |
53 | ||
54 | static void timer_start(SpiceTimer *timer, uint32_t ms) | |
55 | { | |
56 | g_assert(ms != 0); | |
57 | gettimeofday(&timer->tv_start, NULL); | |
58 | timer->ms = ms; | |
59 | // already add ms to timer value | |
60 | add_ms_to_timeval(&timer->tv_start, ms); | |
61 | } | |
62 | ||
63 | static void timer_cancel(SpiceTimer *timer) | |
64 | { | |
65 | timer->ms = 0; | |
66 | } | |
67 | ||
68 | static void timer_remove(SpiceTimer *timer) | |
69 | { | |
70 | ring_remove(&timer->link); | |
71 | } | |
72 | ||
73 | struct SpiceWatch { | |
74 | RingItem link; | |
75 | int fd; | |
76 | int event_mask; | |
77 | SpiceWatchFunc func; | |
78 | int removed; | |
79 | void *opaque; | |
80 | }; | |
81 | ||
82 | Ring watches; | |
83 | ||
84 | int watch_count = 0; | |
85 | ||
86 | static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) | |
87 | { | |
db8e5ef8 | 88 | SpiceWatch *watch = g_new0(SpiceWatch, 1); |
cc04455b DM |
89 | |
90 | DPRINTF(0, "adding %p, fd=%d at %d", watch, | |
91 | fd, watch_count); | |
92 | watch->fd = fd; | |
93 | watch->event_mask = event_mask; | |
94 | watch->func = func; | |
95 | watch->opaque = opaque; | |
96 | watch->removed = FALSE; | |
97 | ring_item_init(&watch->link); | |
98 | ring_add(&watches, &watch->link); | |
99 | watch_count++; | |
100 | return watch; | |
101 | } | |
102 | ||
103 | static void watch_update_mask(SpiceWatch *watch, int event_mask) | |
104 | { | |
105 | DPRINTF(0, "fd %d to %d", watch->fd, event_mask); | |
106 | watch->event_mask = event_mask; | |
107 | } | |
108 | ||
109 | static void watch_remove(SpiceWatch *watch) | |
110 | { | |
111 | DPRINTF(0, "remove %p (fd %d)", watch, watch->fd); | |
112 | watch_count--; | |
113 | watch->removed = TRUE; | |
114 | } | |
115 | ||
116 | static void channel_event(int event, SpiceChannelEventInfo *info) | |
117 | { | |
118 | DPRINTF(0, "channel event con, type, id, event: %ld, %d, %d, %d", | |
119 | info->connection_id, info->type, info->id, event); | |
120 | } | |
121 | ||
122 | SpiceTimer *get_next_timer(void) | |
123 | { | |
124 | SpiceTimer *next, *min; | |
125 | ||
126 | if (ring_is_empty(&timers)) { | |
127 | return NULL; | |
128 | } | |
129 | min = next = (SpiceTimer*)ring_get_head(&timers); | |
130 | while ((next=(SpiceTimer*)ring_next(&timers, &next->link)) != NULL) { | |
131 | if (next->ms && | |
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))) { | |
135 | min = next; | |
136 | } | |
137 | } | |
138 | return min; | |
139 | } | |
140 | ||
141 | struct timeval now; | |
142 | ||
143 | void tv_b_minus_a_return_le_zero(struct timeval *a, struct timeval *b, struct timeval *dest) | |
144 | { | |
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; | |
149 | dest->tv_sec--; | |
150 | } | |
151 | if (dest->tv_sec < 0) { | |
152 | dest->tv_sec = 0; | |
153 | dest->tv_usec = 0; | |
154 | } | |
155 | } | |
156 | ||
157 | void calc_next_timeout(SpiceTimer *next, struct timeval *timeout) | |
158 | { | |
159 | gettimeofday(&now, NULL); | |
160 | tv_b_minus_a_return_le_zero(&now, &next->tv_start, timeout); | |
161 | } | |
162 | ||
163 | void timeout_timers(void) | |
164 | { | |
165 | SpiceTimer *next; | |
166 | struct timeval left; | |
167 | int count = 0; | |
168 | ||
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) { | |
173 | count++; | |
174 | DPRINTF(2, "calling timer"); | |
175 | next->ms = 0; | |
176 | next->func(next->opaque); | |
177 | } | |
178 | next = (SpiceTimer*)ring_next(&timers, &next->link); | |
179 | } | |
180 | DPRINTF(2, "called %d timers", count); | |
181 | } | |
182 | ||
183 | void basic_event_loop_mainloop(void) | |
184 | { | |
185 | fd_set rfds, wfds; | |
186 | int max_fd = -1; | |
187 | int i; | |
188 | int retval; | |
189 | SpiceWatch *watch; | |
190 | SpiceTimer *next_timer; | |
191 | RingItem *link; | |
192 | RingItem *next; | |
193 | struct timeval next_timer_timeout; | |
194 | struct timeval *timeout; | |
195 | ||
196 | while (1) { | |
197 | FD_ZERO(&rfds); | |
198 | FD_ZERO(&wfds); | |
199 | i = 0; | |
200 | RING_FOREACH_SAFE(link, next, &watches) { | |
201 | watch = (SpiceWatch*)link; | |
202 | if (watch->removed) { | |
203 | continue; | |
204 | } | |
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; | |
208 | } | |
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; | |
212 | } | |
213 | i++; | |
214 | } | |
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); | |
220 | } else { | |
221 | timeout = NULL; | |
222 | } | |
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) { | |
229 | timeout_timers(); | |
230 | } | |
231 | } | |
232 | if (retval == -1) { | |
233 | printf("error in select - exiting\n"); | |
234 | abort(); | |
235 | } | |
236 | if (retval) { | |
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); | |
242 | } | |
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); | |
246 | } | |
247 | if (watch->removed) { | |
248 | printf("freeing watch %p\n", watch); | |
249 | ring_remove(&watch->link); | |
db8e5ef8 | 250 | g_free(watch); |
cc04455b DM |
251 | } |
252 | } | |
253 | } | |
254 | } | |
255 | } | |
256 | ||
257 | static void ignore_sigpipe(void) | |
258 | { | |
259 | struct sigaction act; | |
260 | ||
261 | memset(&act, 0, sizeof(act)); | |
262 | sigfillset(&act.sa_mask); | |
263 | act.sa_handler = SIG_IGN; | |
264 | sigaction(SIGPIPE, &act, NULL); | |
265 | } | |
266 | ||
267 | SpiceCoreInterface *basic_event_loop_init(void) | |
268 | { | |
269 | ring_init(&watches); | |
270 | ring_init(&timers); | |
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; | |
282 | ignore_sigpipe(); | |
283 | return &core; | |
284 | } |