source: roaraudio/libroarpulse/mainloop.c @ 3493:92c9d034acbd

Last change on this file since 3493:92c9d034acbd was 3493:92c9d034acbd, checked in by phi, 14 years ago

define some consts for non poll() enabled systems

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