source: roaraudio/libroarpulse/mainloop.c @ 3469:3082508bf5a4

Last change on this file since 3469:3082508bf5a4 was 3469:3082508bf5a4, checked in by phi, 14 years ago

wrote most of the mainloop logic

File size: 8.3 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
129/** Allocate a new main loop object */
130pa_mainloop *pa_mainloop_new(void) {
131 pa_mainloop * m = roar_mm_malloc(sizeof(pa_mainloop));
132
133 if ( m == NULL )
134  return NULL;
135
136 memset(m, 0, sizeof(pa_mainloop));
137
138 m->api.userdata       = m;
139 m->api.io_new         = _roar_pa_io_new;
140 m->api.io_enable      = _roar_pa_io_enable;
141 m->api.io_free        = _roar_pa_io_free;
142 m->api.io_set_destroy = _roar_pa_io_set_destroy;
143
144 return m;
145}
146
147/** Free a main loop object */
148void pa_mainloop_free(pa_mainloop* m) {
149 if ( m == NULL )
150  return;
151
152 roar_mm_free(m);
153}
154
155/** Prepare for a single iteration of the main loop. Returns a negative value
156on error or exit request. timeout specifies a maximum timeout for the subsequent
157poll, or -1 for blocking behaviour. .*/
158int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
159 short events;
160 int i;
161
162 if ( m == NULL )
163  return -1;
164
165 if ( m->quit )
166  return -2;
167
168 m->pollfds = 0;
169
170 for (i = 0; i < MAX_IO_EVENTS; i++) {
171  if ( m->io_event[i].used ) {
172   events = 0;
173
174   if ( m->io_event[i].events & PA_IO_EVENT_INPUT )
175    events |= POLLIN;
176
177   if ( m->io_event[i].events & PA_IO_EVENT_OUTPUT )
178    events |= POLLOUT;
179
180   if ( m->io_event[i].events & PA_IO_EVENT_HANGUP )
181    events |= POLLHUP;
182
183   if ( m->io_event[i].events & PA_IO_EVENT_ERROR )
184    events |= POLLERR;
185
186   if ( events == 0 )
187    continue;
188
189   m->pollfd[m->pollfds].fd     = m->io_event[i].fd;
190   m->pollfd[m->pollfds].events = events;
191   m->pollfds++;
192  }
193 }
194
195 m->poll_timeout = timeout;
196
197 return 0;
198}
199
200/** Execute the previously prepared poll. Returns a negative value on error.*/
201int pa_mainloop_poll(pa_mainloop *m) {
202 int ret;
203
204 if ( m == NULL )
205  return -1;
206
207 if ( m->quit )
208  return -2;
209
210 if ( m->poll_func != NULL ) {
211  ret = m->poll_func(m->pollfd, m->pollfds, m->poll_timeout, m->poll_userdata);
212 } else {
213  ret = poll(m->pollfd, m->pollfds, m->poll_timeout);
214 }
215
216 return ret;
217}
218
219/** Dispatch timeout, io and deferred events from the previously executed poll. Returns
220a negative value on error. On success returns the number of source dispatched. */
221int pa_mainloop_dispatch(pa_mainloop *m) {
222 pa_io_event_flags_t events;
223 int count = 0;
224
225 int i, h;
226
227 if ( m == NULL )
228  return -1;
229
230 if ( m->quit )
231  return -2;
232
233 for (i = 0; i < m->pollfds; i++) {
234  if ( m->pollfd[i].revents != 0 ) {
235   for (h = 0; h < MAX_IO_EVENTS; h++) {
236    if ( m->io_event[h].fd == m->pollfd[i].fd ) {
237     events = PA_IO_EVENT_NULL;
238
239     if ( m->pollfd[i].revents & POLLIN )
240      events |= PA_IO_EVENT_INPUT;
241
242     if ( m->pollfd[i].revents & POLLOUT )
243      events |= PA_IO_EVENT_OUTPUT;
244
245     if ( m->pollfd[i].revents & POLLHUP )
246      events |= PA_IO_EVENT_HANGUP;
247
248     if ( m->pollfd[i].revents & POLLERR )
249      events |= PA_IO_EVENT_ERROR;
250
251     if ( m->io_event[h].cb != NULL )
252      m->io_event[h].cb(&(m->api), &(m->io_event[h]), m->pollfd[i].fd, events, m->io_event[h].userdata);
253
254     count++;
255    }
256   }
257  }
258 }
259
260 return count;
261}
262
263/** Return the return value as specified with the main loop's quit() routine. */
264int pa_mainloop_get_retval(pa_mainloop *m) {
265 if ( m == NULL )
266  return -1;
267
268 return m->quitval;
269}
270
271/** Run a single iteration of the main loop. This is a convenience function
272for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch().
273Returns a negative value on error or exit request. If block is nonzero,
274block for events if none are queued. Optionally return the return value as
275specified with the main loop's quit() routine in the integer variable retval points
276to. On success returns the number of sources dispatched in this iteration. */
277int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
278 int r;
279
280 if ( m == NULL )
281  return -1;
282
283 r = pa_mainloop_prepare(m, block ? -1 : 0);
284
285 if ( r > 0 )
286  r = pa_mainloop_poll(m);
287
288 if ( r > 0 )
289  r = pa_mainloop_dispatch(m);
290
291 if ( r == -2 && retval != NULL ) {
292  *retval = m->quitval;
293 }
294
295 return r;
296}
297
298/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */
299int pa_mainloop_run(pa_mainloop *m, int *retval) {
300 int r = 1;
301
302 if ( m == NULL )
303  return -1;
304
305 while (!(m->quit) && r > 0) {
306  r = pa_mainloop_iterate(m, 1, retval);
307 }
308
309 if ( r == -2 )
310  return 1;
311
312 if ( r < 0 )
313  return -1;
314
315 return 0;
316}
317
318/** Return the abstract main loop abstraction layer vtable for this main loop. */
319pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) {
320 if ( m == NULL )
321  return NULL;
322
323 return &(m->api);
324}
325
326/** Shutdown the main loop */
327void pa_mainloop_quit(pa_mainloop *m, int r) {
328 if ( m == NULL )
329  return;
330
331 m->quitval = r;
332 m->quit    = 1;
333}
334
335/** Interrupt a running poll (for threaded systems) */
336void pa_mainloop_wakeup(pa_mainloop *m);
337
338/** Change the poll() implementation */
339void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
340 if ( m == NULL )
341  return;
342
343 m->poll_func     = poll_func;
344 m->poll_userdata = userdata;
345}
346
347//ll
Note: See TracBrowser for help on using the repository browser.