]> git.proxmox.com Git - spiceterm.git/blob - basic_event_loop.c
code cleanup
[spiceterm.git] / basic_event_loop.c
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 {
37 SpiceTimer *timer = g_new0(SpiceTimer, 1);
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 {
88 SpiceWatch *watch = g_new0(SpiceWatch, 1);
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);
250 g_free(watch);
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 }