add asynchronous inter-thread notification API
[profile/ivi/pulseaudio.git] / src / pulsecore / anotify.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5  
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   PulseAudio 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   Lesser General Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29
30 #include <pulse/xmalloc.h>
31
32 #include "anotify.h"
33
34 #define EVENTS_MAX 16
35
36 struct pa_anotify {
37     pa_mainloop_api *api;
38     pa_anotify_cb_t callback;
39     void *userdata;
40     int fds[2];
41     pa_io_event *io_event;
42     pa_defer_event *defer_event;
43
44     uint8_t queued_events[EVENTS_MAX];
45     unsigned n_queued_events, queue_index;
46 };
47
48 static void dispatch_event(pa_anotify *a) {
49     assert(a);
50     assert(a->queue_index < a->n_queued_events);
51     
52     a->callback(a->queued_events[a->queue_index++], a->userdata);
53
54     if (a->queue_index >= a->n_queued_events) {
55         a->n_queued_events = 0;
56         a->queue_index = 0;
57
58         a->api->io_enable(a->io_event, PA_IO_EVENT_INPUT);
59         a->api->defer_enable(a->defer_event, 0);
60     } else {
61         a->api->io_enable(a->io_event, 0);
62         a->api->defer_enable(a->defer_event, 1);
63     }
64 }
65
66 static void io_callback(
67         pa_mainloop_api *api,
68         pa_io_event *e,
69         int fd,
70         pa_io_event_flags_t events,
71         void *userdata) {
72     
73     pa_anotify *a = userdata;
74     ssize_t r;
75
76     assert(a);
77     assert(events == PA_IO_EVENT_INPUT);
78     assert(a->n_queued_events == 0);
79     
80     r = read(fd, a->queued_events, sizeof(a->queued_events));
81     assert(r > 0);
82
83     a->n_queued_events = (unsigned) r;
84     a->queue_index = 0;
85
86     /* Only dispatch a single event */
87     dispatch_event(a);
88 }
89
90 static void defer_callback(pa_mainloop_api *api, pa_defer_event *e, void *userdata) {
91     pa_anotify *a = userdata;
92     assert(a);
93
94     dispatch_event(a);
95 }
96
97 pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata) {
98     pa_anotify *a;
99     
100     assert(api);
101     assert(cb);
102
103     a = pa_xnew(pa_anotify, 1);
104
105     if (pipe(a->fds) < 0) {
106         pa_xfree(a);
107         return NULL;
108     }
109     
110     a->api = api;
111     a->callback = cb;
112     a->userdata = userdata;
113
114     a->io_event = api->io_new(api, a->fds[0], PA_IO_EVENT_INPUT, io_callback, a);
115     a->defer_event = api->defer_new(api, defer_callback, a);
116     a->api->defer_enable(a->defer_event, 0);
117
118     a->n_queued_events = 0;
119
120     return a;
121 }
122
123 void pa_anotify_free(pa_anotify *a) {
124     assert(a);
125
126     a->api->io_free(a->io_event);
127     a->api->defer_free(a->defer_event);
128
129     if (a->fds[0] >= 0)
130         close(a->fds[0]);
131     if (a->fds[1] >= 0)
132         close(a->fds[1]);
133     
134     pa_xfree(a);
135 }
136
137 int pa_anotify_signal(pa_anotify *a, uint8_t event) {
138     ssize_t r;
139     assert(a);
140
141     r = write(a->fds[1], &event, 1);
142     return r != 1 ? -1 : 0;
143 }