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
41 struct mainloop_source_header
{
42 struct pa_mainloop
*mainloop
;
46 struct mainloop_source_io
{
47 struct mainloop_source_header header
;
50 enum pa_mainloop_api_io_events events
;
51 void (*callback
) (struct pa_mainloop_api
*a
, void *id
, int fd
, enum pa_mainloop_api_io_events events
, void *userdata
);
54 struct pollfd
*pollfd
;
57 struct mainloop_source_fixed_or_idle
{
58 struct mainloop_source_header header
;
61 void (*callback
)(struct pa_mainloop_api
*a
, void *id
, void *userdata
);
65 struct mainloop_source_time
{
66 struct mainloop_source_header header
;
69 struct timeval timeval
;
70 void (*callback
)(struct pa_mainloop_api
*a
, void *id
, const struct timeval
*tv
, void *userdata
);
75 struct pa_idxset
*io_sources
, *fixed_sources
, *idle_sources
, *time_sources
;
76 int io_sources_scan_dead
, fixed_sources_scan_dead
, idle_sources_scan_dead
, time_sources_scan_dead
;
78 struct pollfd
*pollfds
;
79 unsigned max_pollfds
, n_pollfds
;
82 int quit
, running
, retval
;
83 struct pa_mainloop_api api
;
86 static void setup_api(struct pa_mainloop
*m
);
88 struct pa_mainloop
*pa_mainloop_new(void) {
89 struct pa_mainloop
*m
;
91 m
= pa_xmalloc(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
);
138 pa_xfree(m
->pollfds
);
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
= pa_xrealloc(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
= pa_xmalloc(sizeof(struct mainloop_source_io
));
353 s
->header
.mainloop
= m
;
358 s
->callback
= callback
;
359 s
->userdata
= userdata
;
362 pa_idxset_put(m
->io_sources
, s
, NULL
);
363 m
->rebuild_pollfds
= 1;
367 static void mainloop_enable_io(struct pa_mainloop_api
*a
, void* id
, enum pa_mainloop_api_io_events events
) {
368 struct pa_mainloop
*m
;
369 struct mainloop_source_io
*s
= id
;
370 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
372 assert(a
== &m
->api
&& s
->header
.mainloop
== m
);
376 s
->pollfd
->events
= ((s
->events
& PA_MAINLOOP_API_IO_EVENT_INPUT
) ? POLLIN
: 0) | ((s
->events
& PA_MAINLOOP_API_IO_EVENT_OUTPUT
) ? POLLOUT
: 0);
379 static void mainloop_cancel_io(struct pa_mainloop_api
*a
, void* id
) {
380 struct pa_mainloop
*m
;
381 struct mainloop_source_io
*s
= id
;
382 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
384 assert(a
== &m
->api
&& s
->header
.mainloop
== m
);
387 m
->io_sources_scan_dead
= 1;
388 m
->rebuild_pollfds
= 1;
392 static void* mainloop_source_fixed(struct pa_mainloop_api
*a
, void (*callback
) (struct pa_mainloop_api
*a
, void *id
, void *userdata
), void *userdata
) {
393 struct pa_mainloop
*m
;
394 struct mainloop_source_fixed_or_idle
*s
;
395 assert(a
&& a
->userdata
&& callback
);
397 assert(a
== &m
->api
);
399 s
= pa_xmalloc(sizeof(struct mainloop_source_fixed_or_idle
));
400 s
->header
.mainloop
= m
;
404 s
->callback
= callback
;
405 s
->userdata
= userdata
;
407 pa_idxset_put(m
->fixed_sources
, s
, NULL
);
411 static void mainloop_enable_fixed(struct pa_mainloop_api
*a
, void* id
, int b
) {
412 struct pa_mainloop
*m
;
413 struct mainloop_source_fixed_or_idle
*s
= id
;
414 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
416 assert(a
== &m
->api
);
421 static void mainloop_cancel_fixed(struct pa_mainloop_api
*a
, void* id
) {
422 struct pa_mainloop
*m
;
423 struct mainloop_source_fixed_or_idle
*s
= id
;
424 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
426 assert(a
== &m
->api
);
429 m
->fixed_sources_scan_dead
= 1;
433 static void* mainloop_source_idle(struct pa_mainloop_api
*a
, void (*callback
) (struct pa_mainloop_api
*a
, void *id
, void *userdata
), void *userdata
) {
434 struct pa_mainloop
*m
;
435 struct mainloop_source_fixed_or_idle
*s
;
436 assert(a
&& a
->userdata
&& callback
);
438 assert(a
== &m
->api
);
440 s
= pa_xmalloc(sizeof(struct mainloop_source_fixed_or_idle
));
441 s
->header
.mainloop
= m
;
445 s
->callback
= callback
;
446 s
->userdata
= userdata
;
448 pa_idxset_put(m
->idle_sources
, s
, NULL
);
452 static void mainloop_cancel_idle(struct pa_mainloop_api
*a
, void* id
) {
453 struct pa_mainloop
*m
;
454 struct mainloop_source_fixed_or_idle
*s
= id
;
455 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
457 assert(a
== &m
->api
);
460 m
->idle_sources_scan_dead
= 1;
464 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
) {
465 struct pa_mainloop
*m
;
466 struct mainloop_source_time
*s
;
467 assert(a
&& a
->userdata
&& callback
);
469 assert(a
== &m
->api
);
471 s
= pa_xmalloc(sizeof(struct mainloop_source_time
));
472 s
->header
.mainloop
= m
;
479 s
->callback
= callback
;
480 s
->userdata
= userdata
;
482 pa_idxset_put(m
->time_sources
, s
, NULL
);
486 static void mainloop_enable_time(struct pa_mainloop_api
*a
, void *id
, const struct timeval
*tv
) {
487 struct pa_mainloop
*m
;
488 struct mainloop_source_time
*s
= id
;
489 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
491 assert(a
== &m
->api
);
500 static void mainloop_cancel_time(struct pa_mainloop_api
*a
, void* id
) {
501 struct pa_mainloop
*m
;
502 struct mainloop_source_time
*s
= id
;
503 assert(a
&& a
->userdata
&& s
&& !s
->header
.dead
);
505 assert(a
== &m
->api
);
508 m
->time_sources_scan_dead
= 1;
512 static void mainloop_quit(struct pa_mainloop_api
*a
, int retval
) {
513 struct pa_mainloop
*m
;
514 assert(a
&& a
->userdata
);
516 assert(a
== &m
->api
);
522 static void setup_api(struct pa_mainloop
*m
) {
526 m
->api
.source_io
= mainloop_source_io
;
527 m
->api
.enable_io
= mainloop_enable_io
;
528 m
->api
.cancel_io
= mainloop_cancel_io
;
530 m
->api
.source_fixed
= mainloop_source_fixed
;
531 m
->api
.enable_fixed
= mainloop_enable_fixed
;
532 m
->api
.cancel_fixed
= mainloop_cancel_fixed
;
534 m
->api
.source_idle
= mainloop_source_idle
;
535 m
->api
.enable_idle
= mainloop_enable_fixed
; /* (!) */
536 m
->api
.cancel_idle
= mainloop_cancel_idle
;
538 m
->api
.source_time
= mainloop_source_time
;
539 m
->api
.enable_time
= mainloop_enable_time
;
540 m
->api
.cancel_time
= mainloop_cancel_time
;
542 m
->api
.quit
= mainloop_quit
;
545 struct pa_mainloop_api
* pa_mainloop_get_api(struct pa_mainloop
*m
) {