]> git.proxmox.com Git - spiceterm.git/blame - basic_event_loop.c
protect command ring with mutex
[spiceterm.git] / basic_event_loop.c
CommitLineData
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
13int 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
23static SpiceCoreInterface core;
24
25typedef struct SpiceTimer {
26 RingItem link;
27 SpiceTimerFunc func;
28 struct timeval tv_start;
29 int ms;
30 void *opaque;
31} Timer;
32
33Ring timers;
34
35static 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
45static 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
54static 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
63static void timer_cancel(SpiceTimer *timer)
64{
65 timer->ms = 0;
66}
67
68static void timer_remove(SpiceTimer *timer)
69{
70 ring_remove(&timer->link);
71}
72
73struct SpiceWatch {
74 RingItem link;
75 int fd;
76 int event_mask;
77 SpiceWatchFunc func;
78 int removed;
79 void *opaque;
80};
81
82Ring watches;
83
84int watch_count = 0;
85
86static 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
103static 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
109static 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
116static 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
122SpiceTimer *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
141struct timeval now;
142
143void 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
157void 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
163void 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
183void 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
257static 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
267SpiceCoreInterface *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}