source: roaraudio/libroarpulse/mainloop.c @ 4960:60cdebcb83ef

Last change on this file since 4960:60cdebcb83ef was 4708:c9d40761088a, checked in by phi, 13 years ago

updated copyright statements

File size: 9.9 KB
RevLine 
[3460]1//mainloop.c:
2
3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
[3460]5 *  The code (may) include prototypes and comments (and maybe
6 *  other code fragements) from libpulse*. They are mostly copyrighted by:
7 *  Lennart Poettering <poettering@users.sourceforge.net> and
8 *  Pierre Ossman <drzeus@drzeus.cx>
9 *
10 *  This file is part of libroarpulse a part of RoarAudio,
11 *  a cross-platform sound system for both, home and professional use.
12 *  See README for details.
13 *
14 *  This file is free software; you can redistribute it and/or modify
15 *  it under the terms of the GNU General Public License version 3
16 *  as published by the Free Software Foundation.
17 *
18 *  RoarAudio is distributed in the hope that it will be useful,
19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *  GNU General Public License for more details.
22 *
23 *  You should have received a copy of the GNU General Public License
24 *  along with this software; see the file COPYING.  If not, write to
[3517]25 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26 *  Boston, MA 02110-1301, USA.
[3460]27 *
28 *  NOTE for everyone want's to change something and send patches:
29 *  read README and HACKING! There a addition information on
30 *  the license of this document you need to read before you send
31 *  any patches.
32 *
33 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
34 *  or libpulse*:
35 *  The libs libroaresd, libroararts and libroarpulse link this libroar
36 *  and are therefore GPL. Because of this it may be illigal to use
37 *  them with any software that uses libesd, libartsc or libpulse*.
38 */
39
40#include <libroarpulse/libroarpulse.h>
[3490]41#ifdef ROAR_HAVE_H_POLL
[3469]42#include <poll.h>
[3490]43#endif
[3460]44
[3468]45#define MAX_IO_EVENTS    8
46
[3490]47#ifndef ROAR_HAVE_H_POLL
48struct pollfd {
49 int fd;
50 short events, revents;
51};
[3492]52
53typedef int nfds_t;
[3493]54
55#define POLLIN          0x001           /* There is data to read.  */
56#define POLLPRI         0x002           /* There is urgent data to read.  */
57#define POLLOUT         0x004           /* Writing now will not block.  */
58
59#define POLLERR         0x008           /* Error condition.  */
60#define POLLHUP         0x010           /* Hung up.  */
[3490]61#endif
62
[3468]63struct pa_io_event {
64 int used;
65 pa_mainloop_api *api;
66 int fd;
67 pa_io_event_flags_t events;
68 pa_io_event_cb_t cb;
69 void *userdata;
70 pa_io_event_destroy_cb_t destroy;
71};
72
[3462]73struct pa_mainloop {
74 pa_mainloop_api api;
75 pa_poll_func    poll_func;
76 void          * poll_userdata;
[3469]77 int             poll_timeout;
[3462]78 int             quit;
79 int             quitval;
[3468]80 pa_io_event     io_event[MAX_IO_EVENTS];
[3469]81 struct pollfd   pollfd[MAX_IO_EVENTS];
82 nfds_t          pollfds;
[3462]83};
84
[3468]85// IO EVENTS:
86static void _roar_pa_io_enable(pa_io_event* e, pa_io_event_flags_t events);
87
88/** Create a new IO event source object */
89static pa_io_event* _roar_pa_io_new(pa_mainloop_api*a, int fd,
90                                    pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) {
91 pa_mainloop * mainloop = a->userdata;
92 pa_io_event * ret = NULL;
93 int i;
94
95 for (i = 0; i < MAX_IO_EVENTS; i++) {
96  if ( mainloop->io_event[i].used == 0 ) {
97   ret = &(mainloop->io_event[i]);
98  }
99 }
100
101 if ( ret == NULL )
102  return NULL;
103
104 ret->used = 1;
105
106 ret->api      = a;
107 ret->fd       = fd;
108 ret->cb       = cb;
109 ret->userdata = userdata;
110
111 // Callbacks:
112 ret->destroy  = NULL;
113
114 _roar_pa_io_enable(ret, events);
115
116 return ret;
117}
118/** Enable or disable IO events on this object */
119static void _roar_pa_io_enable(pa_io_event* e, pa_io_event_flags_t events) {
120 if ( e == NULL )
121  return;
122
123 e->events = events;
124}
125
126/** Free a IO event source object */
127static void _roar_pa_io_free(pa_io_event* e) {
128 if ( e == NULL )
129  return;
130
131 if ( e->destroy != NULL )
132  e->destroy(e->api, e, e->userdata);
133
134 e->used = 0;
135}
136/** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */
137static void _roar_pa_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) {
138 if ( e == NULL )
139  return;
140
141 e->destroy = cb;
142}
143
144
145
146// API:
[3463]147
[3483]148void _roar_pa_mainloop_quit(pa_mainloop_api*a, int retval) {
149 pa_mainloop * m = a->userdata;
150 pa_mainloop_quit(m, retval);
151}
152
[3461]153/** Allocate a new main loop object */
[3462]154pa_mainloop *pa_mainloop_new(void) {
155 pa_mainloop * m = roar_mm_malloc(sizeof(pa_mainloop));
156
[3472]157 ROAR_DBG("pa_mainloop_new() = ?");
158
[3462]159 if ( m == NULL )
160  return NULL;
161
162 memset(m, 0, sizeof(pa_mainloop));
163
[3468]164 m->api.userdata       = m;
[3483]165
166 m->api.quit           = _roar_pa_mainloop_quit;
167
[3468]168 m->api.io_new         = _roar_pa_io_new;
169 m->api.io_enable      = _roar_pa_io_enable;
170 m->api.io_free        = _roar_pa_io_free;
171 m->api.io_set_destroy = _roar_pa_io_set_destroy;
[3462]172
[3472]173 ROAR_DBG("pa_mainloop_new() = %p", m);
[3462]174 return m;
175}
[3461]176
177/** Free a main loop object */
[3462]178void pa_mainloop_free(pa_mainloop* m) {
[3472]179 ROAR_DBG("pa_mainloop_free(m=%p) = ?", m);
180
[3462]181 if ( m == NULL )
182  return;
183
184 roar_mm_free(m);
[3472]185
186 ROAR_DBG("pa_mainloop_free(m=%p) = (void)", m);
[3462]187}
[3461]188
189/** Prepare for a single iteration of the main loop. Returns a negative value
190on error or exit request. timeout specifies a maximum timeout for the subsequent
191poll, or -1 for blocking behaviour. .*/
[3462]192int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
[3469]193 short events;
194 int i;
195
[3481]196 ROAR_DBG("pa_mainloop_prepare(m=%p, timeout=%i) = ?", m, timeout);
197
[3462]198 if ( m == NULL )
199  return -1;
200
201 if ( m->quit )
202  return -2;
203
[3469]204 m->pollfds = 0;
205
206 for (i = 0; i < MAX_IO_EVENTS; i++) {
207  if ( m->io_event[i].used ) {
208   events = 0;
209
210   if ( m->io_event[i].events & PA_IO_EVENT_INPUT )
211    events |= POLLIN;
212
213   if ( m->io_event[i].events & PA_IO_EVENT_OUTPUT )
214    events |= POLLOUT;
215
216   if ( m->io_event[i].events & PA_IO_EVENT_HANGUP )
217    events |= POLLHUP;
218
219   if ( m->io_event[i].events & PA_IO_EVENT_ERROR )
220    events |= POLLERR;
221
222   if ( events == 0 )
223    continue;
224
225   m->pollfd[m->pollfds].fd     = m->io_event[i].fd;
226   m->pollfd[m->pollfds].events = events;
227   m->pollfds++;
228  }
229 }
230
231 m->poll_timeout = timeout;
232
[3481]233 ROAR_DBG("pa_mainloop_prepare(m=%p, timeout=%i) = 0", m, timeout);
[3469]234 return 0;
[3462]235}
[3461]236
237/** Execute the previously prepared poll. Returns a negative value on error.*/
[3462]238int pa_mainloop_poll(pa_mainloop *m) {
[3469]239 int ret;
[3481]240 int alive = 1;
241
242 ROAR_DBG("pa_mainloop_poll(m=%p) = ?", m);
[3469]243
[3462]244 if ( m == NULL )
245  return -1;
246
247 if ( m->quit )
248  return -2;
249
[3481]250 while (alive) {
251  if ( m->poll_func != NULL ) {
252   ret = m->poll_func(m->pollfd, m->pollfds, m->poll_timeout, m->poll_userdata);
253  } else {
[3490]254#ifdef ROAR_HAVE_H_POLL
[3481]255   ret = poll(m->pollfd, m->pollfds, m->poll_timeout);
[3490]256#else
257   ret = -1;
258#endif
[3481]259  }
260
261  if ( ret != -1 || ( errno != EAGAIN && errno != EINTR ) ) {
262   alive = 0;
263  }
[3469]264 }
265
[3481]266 ROAR_DBG("pa_mainloop_poll(m=%p) = %i", m, ret);
[3469]267 return ret;
[3462]268}
[3461]269
270/** Dispatch timeout, io and deferred events from the previously executed poll. Returns
271a negative value on error. On success returns the number of source dispatched. */
[3462]272int pa_mainloop_dispatch(pa_mainloop *m) {
[3469]273 pa_io_event_flags_t events;
274 int count = 0;
[3481]275 int i, h;
[3469]276
[3481]277 ROAR_DBG("pa_mainloop_dispatch(m=%p) = ?", m);
[3469]278
[3462]279 if ( m == NULL )
280  return -1;
281
282 if ( m->quit )
283  return -2;
284
[3469]285 for (i = 0; i < m->pollfds; i++) {
286  if ( m->pollfd[i].revents != 0 ) {
287   for (h = 0; h < MAX_IO_EVENTS; h++) {
288    if ( m->io_event[h].fd == m->pollfd[i].fd ) {
289     events = PA_IO_EVENT_NULL;
290
291     if ( m->pollfd[i].revents & POLLIN )
292      events |= PA_IO_EVENT_INPUT;
293
294     if ( m->pollfd[i].revents & POLLOUT )
295      events |= PA_IO_EVENT_OUTPUT;
296
297     if ( m->pollfd[i].revents & POLLHUP )
298      events |= PA_IO_EVENT_HANGUP;
299
300     if ( m->pollfd[i].revents & POLLERR )
301      events |= PA_IO_EVENT_ERROR;
302
303     if ( m->io_event[h].cb != NULL )
304      m->io_event[h].cb(&(m->api), &(m->io_event[h]), m->pollfd[i].fd, events, m->io_event[h].userdata);
305
306     count++;
307    }
308   }
309  }
310 }
311
[3481]312 ROAR_DBG("pa_mainloop_dispatch(m=%p) = %i", m, count);
[3469]313 return count;
[3462]314}
[3461]315
316/** Return the return value as specified with the main loop's quit() routine. */
[3462]317int pa_mainloop_get_retval(pa_mainloop *m) {
318 if ( m == NULL )
319  return -1;
320
321 return m->quitval;
322}
[3461]323
324/** Run a single iteration of the main loop. This is a convenience function
325for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch().
326Returns a negative value on error or exit request. If block is nonzero,
327block for events if none are queued. Optionally return the return value as
328specified with the main loop's quit() routine in the integer variable retval points
329to. On success returns the number of sources dispatched in this iteration. */
[3462]330int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
331 int r;
332
[3472]333 ROAR_DBG("pa_mainloop_iterate(m=%p, block=%i, retval=%p) = ?", m, block, retval);
334
[3462]335 if ( m == NULL )
336  return -1;
337
338 r = pa_mainloop_prepare(m, block ? -1 : 0);
339
[3472]340 if ( r >= 0 )
[3462]341  r = pa_mainloop_poll(m);
342
343 if ( r > 0 )
344  r = pa_mainloop_dispatch(m);
345
346 if ( r == -2 && retval != NULL ) {
347  *retval = m->quitval;
348 }
349
[3472]350 ROAR_DBG("pa_mainloop_iterate(m=%p, block=%i, retval=%p) = %i", m, block, retval, r);
[3462]351 return r;
352}
[3461]353
354/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */
[3462]355int pa_mainloop_run(pa_mainloop *m, int *retval) {
356 int r = 1;
357
[3472]358 ROAR_DBG("pa_mainloop_run(m=%p, retval=%p) = ?", m, retval);
359
[3462]360 if ( m == NULL )
361  return -1;
362
363 while (!(m->quit) && r > 0) {
364  r = pa_mainloop_iterate(m, 1, retval);
365 }
366
[3472]367 ROAR_DBG("pa_mainloop_run(m=%p, retval=%p): r=%i", m, retval, r);
368
[3462]369 if ( r == -2 )
370  return 1;
371
372 if ( r < 0 )
373  return -1;
374
375 return 0;
376}
[3461]377
378/** Return the abstract main loop abstraction layer vtable for this main loop. */
[3462]379pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) {
380 if ( m == NULL )
381  return NULL;
382
383 return &(m->api);
384}
[3461]385
386/** Shutdown the main loop */
[3462]387void pa_mainloop_quit(pa_mainloop *m, int r) {
388 if ( m == NULL )
389  return;
390
391 m->quitval = r;
392 m->quit    = 1;
393}
[3461]394
395/** Interrupt a running poll (for threaded systems) */
396void pa_mainloop_wakeup(pa_mainloop *m);
397
[3462]398/** Change the poll() implementation */
399void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
400 if ( m == NULL )
401  return;
[3461]402
[3462]403 m->poll_func     = poll_func;
404 m->poll_userdata = userdata;
405}
[3461]406
[3460]407//ll
Note: See TracBrowser for help on using the repository browser.