]> code.delx.au - pulseaudio/blob - src/mainloop.c
main part of the native protocol
[pulseaudio] / src / mainloop.c
1 #include <stdio.h>
2 #include <signal.h>
3 #include <unistd.h>
4 #include <sys/poll.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <errno.h>
10
11 #include "mainloop.h"
12 #include "util.h"
13 #include "idxset.h"
14
15 struct mainloop_source_header {
16 struct pa_mainloop *mainloop;
17 int dead;
18 };
19
20 struct mainloop_source_io {
21 struct mainloop_source_header header;
22
23 int fd;
24 enum pa_mainloop_api_io_events events;
25 void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata);
26 void *userdata;
27
28 struct pollfd *pollfd;
29 };
30
31 struct mainloop_source_fixed_or_idle {
32 struct mainloop_source_header header;
33 int enabled;
34
35 void (*callback)(struct pa_mainloop_api*a, void *id, void *userdata);
36 void *userdata;
37 };
38
39 struct mainloop_source_time {
40 struct mainloop_source_header header;
41 int enabled;
42
43 struct timeval timeval;
44 void (*callback)(struct pa_mainloop_api*a, void *id, const struct timeval*tv, void *userdata);
45 void *userdata;
46 };
47
48 struct pa_mainloop {
49 struct idxset *io_sources, *fixed_sources, *idle_sources, *time_sources;
50 int io_sources_scan_dead, fixed_sources_scan_dead, idle_sources_scan_dead, time_sources_scan_dead;
51
52 struct pollfd *pollfds;
53 unsigned max_pollfds, n_pollfds;
54 int rebuild_pollfds;
55
56 int quit, running, retval;
57 struct pa_mainloop_api api;
58 };
59
60 static void setup_api(struct pa_mainloop *m);
61
62 struct pa_mainloop *pa_mainloop_new(void) {
63 struct pa_mainloop *m;
64
65 m = malloc(sizeof(struct pa_mainloop));
66 assert(m);
67
68 m->io_sources = idxset_new(NULL, NULL);
69 m->fixed_sources = idxset_new(NULL, NULL);
70 m->idle_sources = idxset_new(NULL, NULL);
71 m->time_sources = idxset_new(NULL, NULL);
72
73 assert(m->io_sources && m->fixed_sources && m->idle_sources && m->time_sources);
74
75 m->io_sources_scan_dead = m->fixed_sources_scan_dead = m->idle_sources_scan_dead = m->time_sources_scan_dead = 0;
76
77 m->pollfds = NULL;
78 m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0;
79
80 m->quit = m->running = m->retval = 0;
81
82 setup_api(m);
83
84 return m;
85 }
86
87 static int foreach(void *p, uint32_t index, int *del, void*userdata) {
88 struct mainloop_source_header *h = p;
89 int *all = userdata;
90 assert(p && del && all);
91
92 if (*all || h->dead) {
93 free(h);
94 *del = 1;
95 }
96
97 return 0;
98 };
99
100 void pa_mainloop_free(struct pa_mainloop* m) {
101 int all = 1;
102 assert(m);
103 idxset_foreach(m->io_sources, foreach, &all);
104 idxset_foreach(m->fixed_sources, foreach, &all);
105 idxset_foreach(m->idle_sources, foreach, &all);
106 idxset_foreach(m->time_sources, foreach, &all);
107
108 idxset_free(m->io_sources, NULL, NULL);
109 idxset_free(m->fixed_sources, NULL, NULL);
110 idxset_free(m->idle_sources, NULL, NULL);
111 idxset_free(m->time_sources, NULL, NULL);
112
113 free(m->pollfds);
114 free(m);
115 }
116
117 static void scan_dead(struct pa_mainloop *m) {
118 int all = 0;
119 assert(m);
120 if (m->io_sources_scan_dead)
121 idxset_foreach(m->io_sources, foreach, &all);
122 if (m->fixed_sources_scan_dead)
123 idxset_foreach(m->fixed_sources, foreach, &all);
124 if (m->idle_sources_scan_dead)
125 idxset_foreach(m->idle_sources, foreach, &all);
126 if (m->time_sources_scan_dead)
127 idxset_foreach(m->time_sources, foreach, &all);
128 }
129
130 static void rebuild_pollfds(struct pa_mainloop *m) {
131 struct mainloop_source_io*s;
132 struct pollfd *p;
133 uint32_t index = IDXSET_INVALID;
134 unsigned l;
135
136 l = idxset_ncontents(m->io_sources);
137 if (m->max_pollfds < l) {
138 m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*l);
139 m->max_pollfds = l;
140 }
141
142 m->n_pollfds = 0;
143 p = m->pollfds;
144 for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) {
145 if (s->header.dead) {
146 s->pollfd = NULL;
147 continue;
148 }
149
150 s->pollfd = p;
151 p->fd = s->fd;
152 p->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0);
153 p->revents = 0;
154
155 p++;
156 m->n_pollfds++;
157 }
158 }
159
160 static void dispatch_pollfds(struct pa_mainloop *m) {
161 uint32_t index = IDXSET_INVALID;
162 struct mainloop_source_io *s;
163
164 for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) {
165 if (s->header.dead || !s->events || !s->pollfd || !s->pollfd->revents)
166 continue;
167
168 assert(s->pollfd->revents <= s->pollfd->events && s->pollfd->fd == s->fd && s->callback);
169 s->callback(&m->api, s, s->fd, ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata);
170 }
171 }
172
173 static void run_fixed_or_idle(struct pa_mainloop *m, struct idxset *i) {
174 uint32_t index = IDXSET_INVALID;
175 struct mainloop_source_fixed_or_idle *s;
176
177 for (s = idxset_first(i, &index); s; s = idxset_next(i, &index)) {
178 if (s->header.dead || !s->enabled)
179 continue;
180
181 assert(s->callback);
182 s->callback(&m->api, s, s->userdata);
183 }
184 }
185
186 static int calc_next_timeout(struct pa_mainloop *m) {
187 uint32_t index = IDXSET_INVALID;
188 struct mainloop_source_time *s;
189 struct timeval now;
190 int t = -1;
191
192 if (idxset_isempty(m->time_sources))
193 return -1;
194
195 gettimeofday(&now, NULL);
196
197 for (s = idxset_first(m->time_sources, &index); s; s = idxset_next(m->time_sources, &index)) {
198 int tmp;
199
200 if (s->header.dead || !s->enabled)
201 continue;
202
203 if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec))
204 return 0;
205
206 tmp = (s->timeval.tv_sec - now.tv_sec)*1000;
207
208 if (s->timeval.tv_usec > now.tv_usec)
209 tmp += (s->timeval.tv_usec - now.tv_usec)/1000;
210 else
211 tmp -= (now.tv_usec - s->timeval.tv_usec)/1000;
212
213 if (tmp == 0)
214 return 0;
215 else if (tmp < t)
216 t = tmp;
217 }
218
219 return t;
220 }
221
222 static void dispatch_timeout(struct pa_mainloop *m) {
223 uint32_t index = IDXSET_INVALID;
224 struct mainloop_source_time *s;
225 struct timeval now;
226 assert(m);
227
228 if (idxset_isempty(m->time_sources))
229 return;
230
231 gettimeofday(&now, NULL);
232 for (s = idxset_first(m->time_sources, &index); s; s = idxset_next(m->time_sources, &index)) {
233
234 if (s->header.dead || !s->enabled)
235 continue;
236
237 if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) {
238 assert(s->callback);
239
240 s->enabled = 0;
241 s->callback(&m->api, s, &s->timeval, s->userdata);
242 }
243 }
244 }
245
246 static int any_idle_sources(struct pa_mainloop *m) {
247 struct mainloop_source_fixed_or_idle *s;
248 uint32_t index;
249 assert(m);
250
251 for (s = idxset_first(m->idle_sources, &index); s; s = idxset_next(m->idle_sources, &index))
252 if (!s->header.dead && s->enabled)
253 return 1;
254
255 return 0;
256 }
257
258 int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) {
259 int r, idle;
260 assert(m && !m->running);
261
262 if(m->quit) {
263 if (retval)
264 *retval = m->retval;
265 return 1;
266 }
267
268 m->running = 1;
269
270 scan_dead(m);
271 run_fixed_or_idle(m, m->fixed_sources);
272
273 if (m->rebuild_pollfds) {
274 rebuild_pollfds(m);
275 m->rebuild_pollfds = 0;
276 }
277
278 idle = any_idle_sources(m);
279
280 do {
281 int t;
282
283 if (!block || idle)
284 t = 0;
285 else
286 t = calc_next_timeout(m);
287
288 r = poll(m->pollfds, m->n_pollfds, t);
289 } while (r < 0 && errno == EINTR);
290
291 dispatch_timeout(m);
292
293 if (r > 0)
294 dispatch_pollfds(m);
295 else if (r == 0 && idle)
296 run_fixed_or_idle(m, m->idle_sources);
297 else if (r < 0)
298 fprintf(stderr, "select(): %s\n", strerror(errno));
299
300 m->running = 0;
301 return r < 0 ? -1 : 0;
302 }
303
304 int pa_mainloop_run(struct pa_mainloop *m, int *retval) {
305 int r;
306 while ((r = pa_mainloop_iterate(m, 1, retval)) == 0);
307 return r;
308 }
309
310 void pa_mainloop_quit(struct pa_mainloop *m, int r) {
311 assert(m);
312 m->quit = r;
313 }
314
315 /* IO sources */
316 static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) {
317 struct pa_mainloop *m;
318 struct mainloop_source_io *s;
319 assert(a && a->userdata && fd >= 0 && callback);
320 m = a->userdata;
321 assert(a == &m->api);
322
323 s = malloc(sizeof(struct mainloop_source_io));
324 assert(s);
325 s->header.mainloop = m;
326 s->header.dead = 0;
327
328 s->fd = fd;
329 s->events = events;
330 s->callback = callback;
331 s->userdata = userdata;
332 s->pollfd = NULL;
333
334 idxset_put(m->io_sources, s, NULL);
335 m->rebuild_pollfds = 1;
336 return s;
337 }
338
339 static void mainloop_enable_io(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events) {
340 struct pa_mainloop *m;
341 struct mainloop_source_io *s = id;
342 assert(a && a->userdata && s && !s->header.dead);
343 m = a->userdata;
344 assert(a == &m->api && s->header.mainloop == m);
345
346 s->events = events;
347 if (s->pollfd)
348 s->pollfd->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0);
349 }
350
351 static void mainloop_cancel_io(struct pa_mainloop_api*a, void* id) {
352 struct pa_mainloop *m;
353 struct mainloop_source_io *s = id;
354 assert(a && a->userdata && s && !s->header.dead);
355 m = a->userdata;
356 assert(a == &m->api && s->header.mainloop == m);
357
358 s->header.dead = 1;
359 m->io_sources_scan_dead = 1;
360 }
361
362 /* Fixed sources */
363 static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) {
364 struct pa_mainloop *m;
365 struct mainloop_source_fixed_or_idle *s;
366 assert(a && a->userdata && callback);
367 m = a->userdata;
368 assert(a == &m->api);
369
370 s = malloc(sizeof(struct mainloop_source_fixed_or_idle));
371 assert(s);
372 s->header.mainloop = m;
373 s->header.dead = 0;
374
375 s->enabled = 1;
376 s->callback = callback;
377 s->userdata = userdata;
378
379 idxset_put(m->fixed_sources, s, NULL);
380 return s;
381 }
382
383 static void mainloop_enable_fixed(struct pa_mainloop_api*a, void* id, int b) {
384 struct pa_mainloop *m;
385 struct mainloop_source_fixed_or_idle *s = id;
386 assert(a && a->userdata && s && !s->header.dead);
387 m = a->userdata;
388 assert(a == &m->api);
389
390 s->enabled = b;
391 }
392
393 static void mainloop_cancel_fixed(struct pa_mainloop_api*a, void* id) {
394 struct pa_mainloop *m;
395 struct mainloop_source_fixed_or_idle *s = id;
396 assert(a && a->userdata && s && !s->header.dead);
397 m = a->userdata;
398 assert(a == &m->api);
399
400 s->header.dead = 1;
401 m->fixed_sources_scan_dead = 1;
402 }
403
404 /* Idle sources */
405 static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) {
406 struct pa_mainloop *m;
407 struct mainloop_source_fixed_or_idle *s;
408 assert(a && a->userdata && callback);
409 m = a->userdata;
410 assert(a == &m->api);
411
412 s = malloc(sizeof(struct mainloop_source_fixed_or_idle));
413 assert(s);
414 s->header.mainloop = m;
415 s->header.dead = 0;
416
417 s->enabled = 1;
418 s->callback = callback;
419 s->userdata = userdata;
420
421 idxset_put(m->idle_sources, s, NULL);
422 return s;
423 }
424
425 static void mainloop_cancel_idle(struct pa_mainloop_api*a, void* id) {
426 struct pa_mainloop *m;
427 struct mainloop_source_fixed_or_idle *s = id;
428 assert(a && a->userdata && s && !s->header.dead);
429 m = a->userdata;
430 assert(a == &m->api);
431
432 s->header.dead = 1;
433 m->idle_sources_scan_dead = 1;
434 }
435
436 /* Time sources */
437 static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata) {
438 struct pa_mainloop *m;
439 struct mainloop_source_time *s;
440 assert(a && a->userdata && callback);
441 m = a->userdata;
442 assert(a == &m->api);
443
444 s = malloc(sizeof(struct mainloop_source_time));
445 assert(s);
446 s->header.mainloop = m;
447 s->header.dead = 0;
448
449 s->enabled = !!tv;
450 if (tv)
451 s->timeval = *tv;
452
453 s->callback = callback;
454 s->userdata = userdata;
455
456 idxset_put(m->time_sources, s, NULL);
457 return s;
458 }
459
460 static void mainloop_enable_time(struct pa_mainloop_api*a, void *id, const struct timeval *tv) {
461 struct pa_mainloop *m;
462 struct mainloop_source_time *s = id;
463 assert(a && a->userdata && s && !s->header.dead);
464 m = a->userdata;
465 assert(a == &m->api);
466
467 if (tv) {
468 s->enabled = 1;
469 s->timeval = *tv;
470 } else
471 s->enabled = 0;
472 }
473
474 static void mainloop_cancel_time(struct pa_mainloop_api*a, void* id) {
475 struct pa_mainloop *m;
476 struct mainloop_source_time *s = id;
477 assert(a && a->userdata && s && !s->header.dead);
478 m = a->userdata;
479 assert(a == &m->api);
480
481 s->header.dead = 1;
482 m->time_sources_scan_dead = 1;
483
484 }
485
486 static void mainloop_quit(struct pa_mainloop_api*a, int retval) {
487 struct pa_mainloop *m;
488 assert(a && a->userdata);
489 m = a->userdata;
490 assert(a == &m->api);
491
492 m->quit = 1;
493 m->retval = retval;
494 }
495
496 static void setup_api(struct pa_mainloop *m) {
497 assert(m);
498
499 m->api.userdata = m;
500 m->api.source_io = mainloop_source_io;
501 m->api.enable_io = mainloop_enable_io;
502 m->api.cancel_io = mainloop_cancel_io;
503
504 m->api.source_fixed = mainloop_source_fixed;
505 m->api.enable_fixed = mainloop_enable_fixed;
506 m->api.cancel_fixed = mainloop_cancel_fixed;
507
508 m->api.source_idle = mainloop_source_idle;
509 m->api.enable_idle = mainloop_enable_fixed; /* (!) */
510 m->api.cancel_idle = mainloop_cancel_idle;
511
512 m->api.source_time = mainloop_source_time;
513 m->api.enable_time = mainloop_enable_time;
514 m->api.cancel_time = mainloop_cancel_time;
515
516 m->api.quit = mainloop_quit;
517 }
518
519 struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) {
520 assert(m);
521 return &m->api;
522 }
523