4 This file is part of polypaudio.
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
40 struct mainloop_source_header
{
41 struct pa_mainloop
*mainloop
;
45 struct mainloop_source_io
{
46 struct mainloop_source_header header
;
49 enum pa_mainloop_api_io_events events
;
50 void (*callback
) (struct pa_mainloop_api
*a
, void *id
, int fd
, enum pa_mainloop_api_io_events events
, void *userdata
);
53 struct pollfd
*pollfd
;
56 struct mainloop_source_fixed_or_idle
{
57 struct mainloop_source_header header
;
60 void (*callback
)(struct pa_mainloop_api
*a
, void *id
, void *userdata
);
64 struct mainloop_source_time
{
65 struct mainloop_source_header header
;
68 struct timeval timeval
;
69 void (*callback
)(struct pa_mainloop_api
*a
, void *id
, const struct timeval
*tv
, void *userdata
);
74 struct pa_idxset
*io_sources
, *fixed_sources
, *idle_sources
, *time_sources
;
75 int io_sources_scan_dead
, fixed_sources_scan_dead
, idle_sources_scan_dead
, time_sources_scan_dead
;
77 struct pollfd
*pollfds
;
78 unsigned max_pollfds
, n_pollfds
;
81 int quit
, running
, retval
;
82 struct pa_mainloop_api api
;
85 static void setup_api(struct pa_mainloop
*m
);
87 struct pa_mainloop
*pa_mainloop_new(void) {
88 struct pa_mainloop
*m
;
90 m
= malloc(sizeof(struct pa_mainloop
));
93 m
->io_sources
= pa_idxset_new(NULL
, NULL
);
94 m
->fixed_sources
= pa_idxset_new(NULL
, NULL
);
95 m
->idle_sources
= pa_idxset_new(NULL
, NULL
);
96 m
->time_sources
= pa_idxset_new(NULL
, NULL
);
98 assert(m
->io_sources
&& m
->fixed_sources
&& m
->idle_sources
&& m
->time_sources
);
100 m
->io_sources_scan_dead
= m
->fixed_sources_scan_dead
= m
->idle_sources_scan_dead
= m
->time_sources_scan_dead
= 0;
103 m
->max_pollfds
= m
->n_pollfds
= m
->rebuild_pollfds
= 0;
105 m
->quit
= m
->running
= m
->retval
= 0;
112 static int foreach(void *p
, uint32_t index
, int *del
, void*userdata
) {
113 struct mainloop_source_header
*h
= p
;
115 assert(p
&& del
&& all
);
117 if (*all
|| h
->dead
) {
125 void pa_mainloop_free(struct pa_mainloop
* m
) {
128 pa_idxset_foreach(m
->io_sources
, foreach
, &all
);
129 pa_idxset_foreach(m
->fixed_sources
, foreach
, &all
);
130 pa_idxset_foreach(m
->idle_sources
, foreach
, &all
);
131 pa_idxset_foreach(m
->time_sources
, foreach
, &all
);
133 pa_idxset_free(m
->io_sources
, NULL
, NULL
);
134 pa_idxset_free(m
->fixed_sources
, NULL
, NULL
);
135 pa_idxset_free(m
->idle_sources
, NULL
, NULL
);
136 pa_idxset_free(m
->time_sources
, NULL
, NULL
);
142 static void scan_dead(struct pa_mainloop
*m
) {
145 if (m
->io_sources_scan_dead
)
146 pa_idxset_foreach(m
->io_sources
, foreach
, &all
);
147 if (m
->fixed_sources_scan_dead
)
148 pa_idxset_foreach(m
->fixed_sources
, foreach
, &all
);
149 if (m
->idle_sources_scan_dead
)
150 pa_idxset_foreach(m
->idle_sources
, foreach
, &all
);
151 if (m
->time_sources_scan_dead
)
152 pa_idxset_foreach(m
->time_sources
, foreach
, &all
);
155 static void rebuild_pollfds(struct pa_mainloop
*m
) {
156 struct mainloop_source_io
*s
;
158 uint32_t index
= PA_IDXSET_INVALID
;
161 l
= pa_idxset_ncontents(m
->io_sources
);
162 if (m
->max_pollfds
< l
) {
163 m
->pollfds
= realloc(m
->pollfds
, sizeof(struct pollfd
)*l
);
169 for (s
= pa_idxset_first(m
->io_sources
, &index
); s
; s
= pa_idxset_next(m
->io_sources
, &index
)) {
170 if (s
->header
.dead
) {
177 p
->events
= ((s
->events
& PA_MAINLOOP_API_IO_EVENT_INPUT
) ? POLLIN
: 0) | ((s
->events
& PA_MAINLOOP_API_IO_EVENT_OUTPUT
) ? POLLOUT
: 0);
185 static void dispatch_pollfds(struct pa_mainloop
*m
) {
186 uint32_t index
= PA_IDXSET_INVALID
;
187 struct mainloop_source_io
*s
;
189 for (s
= pa_idxset_first(m
->io_sources
, &index
); s
; s
= pa_idxset_next(m
->io_sources
, &index
)) {
190 if (s
->header
.dead
|| !s
->pollfd
|| !s
->pollfd
->revents
)
193 assert(s
->pollfd
->fd
== s
->fd
&& s
->callback
);
194 s
->callback(&m
->api
, s
, s
->fd
,
195 ((s
->pollfd
->revents
& POLLHUP
) ? PA_MAINLOOP_API_IO_EVENT_HUP
: 0) |
196 ((s
->pollfd
->revents
& POLLIN
) ? PA_MAINLOOP_API_IO_EVENT_INPUT
: 0) |
197 ((s
->pollfd
->revents
& POLLOUT
) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT
: 0), s
->userdata
);
198 s
->pollfd
->revents
= 0;
202 static void run_fixed_or_idle(struct pa_mainloop
*m
, struct pa_idxset
*i
) {
203 uint32_t index
= PA_IDXSET_INVALID
;
204 struct mainloop_source_fixed_or_idle
*s
;
206 for (s
= pa_idxset_first(i
, &index
); s
; s
= pa_idxset_next(i
, &index
)) {
207 if (s
->header
.dead
|| !s
->enabled
)
211 s
->callback(&m
->api
, s
, s
->userdata
);
215 static int calc_next_timeout(struct pa_mainloop
*m
) {
216 uint32_t index
= PA_IDXSET_INVALID
;
217 struct mainloop_source_time
*s
;
221 if (pa_idxset_isempty(m
->time_sources
))
224 gettimeofday(&now
, NULL
);
226 for (s
= pa_idxset_first(m
->time_sources
, &index
); s
; s
= pa_idxset_next(m
->time_sources
, &index
)) {
229 if (s
->header
.dead
|| !s
->enabled
)
232 if (s
->timeval
.tv_sec
< now
.tv_sec
|| (s
->timeval
.tv_sec
== now
.tv_sec
&& s
->timeval
.tv_usec
<= now
.tv_usec
))
235 tmp
= (s
->timeval
.tv_sec
- now
.tv_sec
)*1000;
237 if (s
->timeval
.tv_usec
> now
.tv_usec
)
238 tmp
+= (s
->timeval
.tv_usec
- now
.tv_usec
)/1000;
240 tmp
-= (now
.tv_usec
- s
->timeval
.tv_usec
)/1000;
244 else if (t
== -1 || tmp
< t
)
251 static void dispatch_timeout(struct pa_mainloop
*m
) {
252 uint32_t index
= PA_IDXSET_INVALID
;
253 struct mainloop_source_time
*s
;
257 if (pa_idxset_isempty(m
->time_sources
))
260 gettimeofday(&now
, NULL
);
261 for (s
= pa_idxset_first(m
->time_sources
, &index
); s
; s
= pa_idxset_next(m
->time_sources
, &index
)) {
263 if (s
->header
.dead
|| !s
->enabled
)
266 if (s
->timeval
.tv_sec
< now
.tv_sec
|| (s
->timeval
.tv_sec
== now
.tv_sec
&& s
->timeval
.tv_usec
<= now
.tv_usec
)) {
270 s
->callback(&m
->api
, s
, &s
->timeval
, s
->userdata
);
275 static int any_idle_sources(struct pa_mainloop
*m
) {
276 struct mainloop_source_fixed_or_idle
*s
;
280 for (s
= pa_idxset_first(m
->idle_sources
, &index
); s
; s
= pa_idxset_next(m
->idle_sources
, &index
))
281 if (!s
->header
.dead
&& s
->enabled
)
287 int pa_mainloop_iterate(struct pa_mainloop
*m
, int block
, int *retval
) {
289 assert(m
&& !m
->running
);
300 run_fixed_or_idle(m
, m
->fixed_sources
);
302 if (m
->rebuild_pollfds
) {
304 m
->rebuild_pollfds
= 0;
307 idle
= any_idle_sources(m
);
315 t
= calc_next_timeout(m
);
317 r
= poll(m
->pollfds
, m
->n_pollfds
, t
);
318 } while (r
< 0 && errno
== EINTR
);
324 else if (r
== 0 && idle
)
325 run_fixed_or_idle(m
, m
->idle_sources
);
327 fprintf(stderr
, "select(): %s\n", strerror(errno
));
330 return r
< 0 ? -1 : 0;
333 int pa_mainloop_run(struct pa_mainloop
*m
, int *retval
) {
335 while ((r
= pa_mainloop_iterate(m
, 1, retval
)) == 0);
339 void pa_mainloop_quit(struct pa_mainloop
*m
, int r
) {
345 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
) {
346 struct pa_mainloop
*m
;
347 struct mainloop_source_io
*s
;
348 assert(a
&& a
->userdata
&& fd
>= 0 && callback
);
350 assert(a
== &m
->api
);
352 s
= malloc(sizeof(struct mainloop_source_io
));
354 s
->header
.mainloop
= m
;
359 s
->callback
= callback
;
360 s
->userdata
= userdata
;
363 pa_idxset_put(m
->io_sources
, s
, NULL
);
364 m
->rebuild_pollfds
= 1;
368 static void mainloop_enable_io(struct pa_mainloop_api
*a
, void* id
, enum pa_mainloop_api_io_events events
) {
369 struct pa_mainloop
*m
;
370 struct mainloop_source_io
*s
= id
;
371 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
373 assert(a
== &m
->api
&& s
->header
.mainloop
== m
);
377 s
->pollfd
->events
= ((s
->events
& PA_MAINLOOP_API_IO_EVENT_INPUT
) ? POLLIN
: 0) | ((s
->events
& PA_MAINLOOP_API_IO_EVENT_OUTPUT
) ? POLLOUT
: 0);
380 static void mainloop_cancel_io(struct pa_mainloop_api
*a
, void* id
) {
381 struct pa_mainloop
*m
;
382 struct mainloop_source_io
*s
= id
;
383 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
385 assert(a
== &m
->api
&& s
->header
.mainloop
== m
);
388 m
->io_sources_scan_dead
= 1;
389 m
->rebuild_pollfds
= 1;
393 static void* mainloop_source_fixed(struct pa_mainloop_api
*a
, void (*callback
) (struct pa_mainloop_api
*a
, void *id
, void *userdata
), void *userdata
) {
394 struct pa_mainloop
*m
;
395 struct mainloop_source_fixed_or_idle
*s
;
396 assert(a
&& a
->userdata
&& callback
);
398 assert(a
== &m
->api
);
400 s
= malloc(sizeof(struct mainloop_source_fixed_or_idle
));
402 s
->header
.mainloop
= m
;
406 s
->callback
= callback
;
407 s
->userdata
= userdata
;
409 pa_idxset_put(m
->fixed_sources
, s
, NULL
);
413 static void mainloop_enable_fixed(struct pa_mainloop_api
*a
, void* id
, int b
) {
414 struct pa_mainloop
*m
;
415 struct mainloop_source_fixed_or_idle
*s
= id
;
416 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
418 assert(a
== &m
->api
);
423 static void mainloop_cancel_fixed(struct pa_mainloop_api
*a
, void* id
) {
424 struct pa_mainloop
*m
;
425 struct mainloop_source_fixed_or_idle
*s
= id
;
426 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
428 assert(a
== &m
->api
);
431 m
->fixed_sources_scan_dead
= 1;
435 static void* mainloop_source_idle(struct pa_mainloop_api
*a
, void (*callback
) (struct pa_mainloop_api
*a
, void *id
, void *userdata
), void *userdata
) {
436 struct pa_mainloop
*m
;
437 struct mainloop_source_fixed_or_idle
*s
;
438 assert(a
&& a
->userdata
&& callback
);
440 assert(a
== &m
->api
);
442 s
= malloc(sizeof(struct mainloop_source_fixed_or_idle
));
444 s
->header
.mainloop
= m
;
448 s
->callback
= callback
;
449 s
->userdata
= userdata
;
451 pa_idxset_put(m
->idle_sources
, s
, NULL
);
455 static void mainloop_cancel_idle(struct pa_mainloop_api
*a
, void* id
) {
456 struct pa_mainloop
*m
;
457 struct mainloop_source_fixed_or_idle
*s
= id
;
458 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
460 assert(a
== &m
->api
);
463 m
->idle_sources_scan_dead
= 1;
467 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
) {
468 struct pa_mainloop
*m
;
469 struct mainloop_source_time
*s
;
470 assert(a
&& a
->userdata
&& callback
);
472 assert(a
== &m
->api
);
474 s
= malloc(sizeof(struct mainloop_source_time
));
476 s
->header
.mainloop
= m
;
483 s
->callback
= callback
;
484 s
->userdata
= userdata
;
486 pa_idxset_put(m
->time_sources
, s
, NULL
);
490 static void mainloop_enable_time(struct pa_mainloop_api
*a
, void *id
, const struct timeval
*tv
) {
491 struct pa_mainloop
*m
;
492 struct mainloop_source_time
*s
= id
;
493 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
495 assert(a
== &m
->api
);
504 static void mainloop_cancel_time(struct pa_mainloop_api
*a
, void* id
) {
505 struct pa_mainloop
*m
;
506 struct mainloop_source_time
*s
= id
;
507 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
509 assert(a
== &m
->api
);
512 m
->time_sources_scan_dead
= 1;
516 static void mainloop_quit(struct pa_mainloop_api
*a
, int retval
) {
517 struct pa_mainloop
*m
;
518 assert(a
&& a
->userdata
);
520 assert(a
== &m
->api
);
526 static void setup_api(struct pa_mainloop
*m
) {
530 m
->api
.source_io
= mainloop_source_io
;
531 m
->api
.enable_io
= mainloop_enable_io
;
532 m
->api
.cancel_io
= mainloop_cancel_io
;
534 m
->api
.source_fixed
= mainloop_source_fixed
;
535 m
->api
.enable_fixed
= mainloop_enable_fixed
;
536 m
->api
.cancel_fixed
= mainloop_cancel_fixed
;
538 m
->api
.source_idle
= mainloop_source_idle
;
539 m
->api
.enable_idle
= mainloop_enable_fixed
; /* (!) */
540 m
->api
.cancel_idle
= mainloop_cancel_idle
;
542 m
->api
.source_time
= mainloop_source_time
;
543 m
->api
.enable_time
= mainloop_enable_time
;
544 m
->api
.cancel_time
= mainloop_cancel_time
;
546 m
->api
.quit
= mainloop_quit
;
549 struct pa_mainloop_api
* pa_mainloop_get_api(struct pa_mainloop
*m
) {