source: roaraudio/libroarpulse/mainloop.c @ 3483:1eaad4fca752

Last change on this file since 3483:1eaad4fca752 was 3483:1eaad4fca752, checked in by phi, 14 years ago

wrote _roar_pa_mainloop_quit()... everything is now working fine

File size: 9.4 KB
Line 
1//mainloop.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
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
25 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 *  NOTE for everyone want's to change something and send patches:
28 *  read README and HACKING! There a addition information on
29 *  the license of this document you need to read before you send
30 *  any patches.
31 *
32 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
33 *  or libpulse*:
34 *  The libs libroaresd, libroararts and libroarpulse link this libroar
35 *  and are therefore GPL. Because of this it may be illigal to use
36 *  them with any software that uses libesd, libartsc or libpulse*.
37 */
38
39#include <libroarpulse/libroarpulse.h>
40#include <poll.h>
41
42#define MAX_IO_EVENTS    8
43
44struct pa_io_event {
45 int used;
46 pa_mainloop_api *api;
47 int fd;
48 pa_io_event_flags_t events;
49 pa_io_event_cb_t cb;
50 void *userdata;
51 pa_io_event_destroy_cb_t destroy;
52};
53
54struct pa_mainloop {
55 pa_mainloop_api api;
56 pa_poll_func    poll_func;
57 void          * poll_userdata;
58 int             poll_timeout;
59 int             quit;
60 int             quitval;
61 pa_io_event     io_event[MAX_IO_EVENTS];
62 struct pollfd   pollfd[MAX_IO_EVENTS];
63 nfds_t          pollfds;
64};
65
66// IO EVENTS:
67static void _roar_pa_io_enable(pa_io_event* e, pa_io_event_flags_t events);
68
69/** Create a new IO event source object */
70static pa_io_event* _roar_pa_io_new(pa_mainloop_api*a, int fd,
71                                    pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) {
72 pa_mainloop * mainloop = a->userdata;
73 pa_io_event * ret = NULL;
74 int i;
75
76 for (i = 0; i < MAX_IO_EVENTS; i++) {
77  if ( mainloop->io_event[i].used == 0 ) {
78   ret = &(mainloop->io_event[i]);
79  }
80 }
81
82 if ( ret == NULL )
83  return NULL;
84
85 ret->used = 1;
86
87 ret->api      = a;
88 ret->fd       = fd;
89 ret->cb       = cb;
90 ret->userdata = userdata;
91
92 // Callbacks:
93 ret->destroy  = NULL;
94
95 _roar_pa_io_enable(ret, events);
96
97 return ret;
98}
99/** Enable or disable IO events on this object */
100static void _roar_pa_io_enable(pa_io_event* e, pa_io_event_flags_t events) {
101 if ( e == NULL )
102  return;
103
104 e->events = events;
105}
106
107/** Free a IO event source object */
108static void _roar_pa_io_free(pa_io_event* e) {
109 if ( e == NULL )
110  return;
111
112 if ( e->destroy != NULL )
113  e->destroy(e->api, e, e->userdata);
114
115 e->used = 0;
116}
117/** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */
118static void _roar_pa_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) {
119 if ( e == NULL )
120  return;
121
122 e->destroy = cb;
123}
124
125
126
127// API:
128
129void _roar_pa_mainloop_quit(pa_mainloop_api*a, int retval) {
130 pa_mainloop * m = a->userdata;
131 pa_mainloop_quit(m, retval);
132}
133
134/** Allocate a new main loop object */
135pa_mainloop *pa_mainloop_new(void) {
136 pa_mainloop * m = roar_mm_malloc(sizeof(pa_mainloop));
137
138 ROAR_DBG("pa_mainloop_new() = ?");
139
140 if ( m == NULL )
141  return NULL;
142
143 memset(m, 0, sizeof(pa_mainloop));
144
145 m->api.userdata       = m;
146
147 m->api.quit           = _roar_pa_mainloop_quit;
148
149 m->api.io_new         = _roar_pa_io_new;
150 m->api.io_enable      = _roar_pa_io_enable;
151 m->api.io_free        = _roar_pa_io_free;
152 m->api.io_set_destroy = _roar_pa_io_set_destroy;
153
154 ROAR_DBG("pa_mainloop_new() = %p", m);
155 return m;
156}
157
158/** Free a main loop object */
159void pa_mainloop_free(pa_mainloop* m) {
160 ROAR_DBG("pa_mainloop_free(m=%p) = ?", m);
161
162 if ( m == NULL )
163  return;
164
165 roar_mm_free(m);
166
167 ROAR_DBG("pa_mainloop_free(m=%p) = (void)", m);
168}
169
170/** Prepare for a single iteration of the main loop. Returns a negative value
171on error or exit request. timeout specifies a maximum timeout for the subsequent
172poll, or -1 for blocking behaviour. .*/
173int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
174 short events;
175 int i;
176
177 ROAR_DBG("pa_mainloop_prepare(m=%p, timeout=%i) = ?", m, timeout);
178
179 if ( m == NULL )
180  return -1;
181
182 if ( m->quit )
183  return -2;
184
185 m->pollfds = 0;
186
187 for (i = 0; i < MAX_IO_EVENTS; i++) {
188  if ( m->io_event[i].used ) {
189   events = 0;
190
191   if ( m->io_event[i].events & PA_IO_EVENT_INPUT )
192    events |= POLLIN;
193
194   if ( m->io_event[i].events & PA_IO_EVENT_OUTPUT )
195    events |= POLLOUT;
196
197   if ( m->io_event[i].events & PA_IO_EVENT_HANGUP )
198    events |= POLLHUP;
199
200   if ( m->io_event[i].events & PA_IO_EVENT_ERROR )
201    events |= POLLERR;
202
203   if ( events == 0 )
204    continue;
205
206   m->pollfd[m->pollfds].fd     = m->io_event[i].fd;
207   m->pollfd[m->pollfds].events = events;
208   m->pollfds++;
209  }
210 }
211
212 m->poll_timeout = timeout;
213
214 ROAR_DBG("pa_mainloop_prepare(m=%p, timeout=%i) = 0", m, timeout);
215 return 0;
216}
217
218/** Execute the previously prepared poll. Returns a negative value on error.*/
219int pa_mainloop_poll(pa_mainloop *m) {
220 int ret;
221 int alive = 1;
222
223 ROAR_DBG("pa_mainloop_poll(m=%p) = ?", m);
224
225 if ( m == NULL )
226  return -1;
227
228 if ( m->quit )
229  return -2;
230
231 while (alive) {
232  if ( m->poll_func != NULL ) {
233   ret = m->poll_func(m->pollfd, m->pollfds, m->poll_timeout, m->poll_userdata);
234  } else {
235   ret = poll(m->pollfd, m->pollfds, m->poll_timeout);
236  }
237
238  if ( ret != -1 || ( errno != EAGAIN && errno != EINTR ) ) {
239   alive = 0;
240  }
241 }
242
243 ROAR_DBG("pa_mainloop_poll(m=%p) = %i", m, ret);
244 return ret;
245}
246
247/** Dispatch timeout, io and deferred events from the previously executed poll. Returns
248a negative value on error. On success returns the number of source dispatched. */
249int pa_mainloop_dispatch(pa_mainloop *m) {
250 pa_io_event_flags_t events;
251 int count = 0;
252 int i, h;
253
254 ROAR_DBG("pa_mainloop_dispatch(m=%p) = ?", m);
255
256 if ( m == NULL )
257  return -1;
258
259 if ( m->quit )
260  return -2;
261
262 for (i = 0; i < m->pollfds; i++) {
263  if ( m->pollfd[i].revents != 0 ) {
264   for (h = 0; h < MAX_IO_EVENTS; h++) {
265    if ( m->io_event[h].fd == m->pollfd[i].fd ) {
266     events = PA_IO_EVENT_NULL;
267
268     if ( m->pollfd[i].revents & POLLIN )
269      events |= PA_IO_EVENT_INPUT;
270
271     if ( m->pollfd[i].revents & POLLOUT )
272      events |= PA_IO_EVENT_OUTPUT;
273
274     if ( m->pollfd[i].revents & POLLHUP )
275      events |= PA_IO_EVENT_HANGUP;
276
277     if ( m->pollfd[i].revents & POLLERR )
278      events |= PA_IO_EVENT_ERROR;
279
280     if ( m->io_event[h].cb != NULL )
281      m->io_event[h].cb(&(m->api), &(m->io_event[h]), m->pollfd[i].fd, events, m->io_event[h].userdata);
282
283     count++;
284    }
285   }
286  }
287 }
288
289 ROAR_DBG("pa_mainloop_dispatch(m=%p) = %i", m, count);
290 return count;
291}
292
293/** Return the return value as specified with the main loop's quit() routine. */
294int pa_mainloop_get_retval(pa_mainloop *m) {
295 if ( m == NULL )
296  return -1;
297
298 return m->quitval;
299}
300
301/** Run a single iteration of the main loop. This is a convenience function
302for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch().
303Returns a negative value on error or exit request. If block is nonzero,
304block for events if none are queued. Optionally return the return value as
305specified with the main loop's quit() routine in the integer variable retval points
306to. On success returns the number of sources dispatched in this iteration. */
307int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
308 int r;
309
310 ROAR_DBG("pa_mainloop_iterate(m=%p, block=%i, retval=%p) = ?", m, block, retval);
311
312 if ( m == NULL )
313  return -1;
314
315 r = pa_mainloop_prepare(m, block ? -1 : 0);
316
317 if ( r >= 0 )
318  r = pa_mainloop_poll(m);
319
320 if ( r > 0 )
321  r = pa_mainloop_dispatch(m);
322
323 if ( r == -2 && retval != NULL ) {
324  *retval = m->quitval;
325 }
326
327 ROAR_DBG("pa_mainloop_iterate(m=%p, block=%i, retval=%p) = %i", m, block, retval, r);
328 return r;
329}
330
331/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */
332int pa_mainloop_run(pa_mainloop *m, int *retval) {
333 int r = 1;
334
335 ROAR_DBG("pa_mainloop_run(m=%p, retval=%p) = ?", m, retval);
336
337 if ( m == NULL )
338  return -1;
339
340 while (!(m->quit) && r > 0) {
341  r = pa_mainloop_iterate(m, 1, retval);
342 }
343
344 ROAR_DBG("pa_mainloop_run(m=%p, retval=%p): r=%i", m, retval, r);
345
346 if ( r == -2 )
347  return 1;
348
349 if ( r < 0 )
350  return -1;
351
352 return 0;
353}
354
355/** Return the abstract main loop abstraction layer vtable for this main loop. */
356pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) {
357 if ( m == NULL )
358  return NULL;
359
360 return &(m->api);
361}
362
363/** Shutdown the main loop */
364void pa_mainloop_quit(pa_mainloop *m, int r) {
365 if ( m == NULL )
366  return;
367
368 m->quitval = r;
369 m->quit    = 1;
370}
371
372/** Interrupt a running poll (for threaded systems) */
373void pa_mainloop_wakeup(pa_mainloop *m);
374
375/** Change the poll() implementation */
376void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
377 if ( m == NULL )
378  return;
379
380 m->poll_func     = poll_func;
381 m->poll_userdata = userdata;
382}
383
384//ll
Note: See TracBrowser for help on using the repository browser.