Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / src / pulse / thread-mainloop.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2006 Lennart Poettering
7   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9   PulseAudio is free software; you can redistribute it and/or modify
10   it under the terms of the GNU Lesser General Public License as published
11   by the Free Software Foundation; either version 2 of the License,
12   or (at your option) any later version.
13
14   PulseAudio is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with PulseAudio; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <assert.h>
30 #include <signal.h>
31 #include <stdio.h>
32
33 #ifdef HAVE_SYS_POLL_H
34 #include <sys/poll.h>
35 #else
36 #include "../pulsecore/poll.h"
37 #endif
38
39 #include <pulse/xmalloc.h>
40
41 #include <pulsecore/log.h>
42 #include <pulsecore/hashmap.h>
43 #include <pulsecore/thread.h>
44 #include <pulsecore/mutex.h>
45
46 #include "mainloop.h"
47 #include "thread-mainloop.h"
48
49 struct pa_threaded_mainloop {
50     pa_mainloop *real_mainloop;
51     int n_waiting;
52
53     pa_thread* thread;
54     pa_mutex* mutex;
55     pa_cond* cond, *accept_cond;
56 };
57
58 static inline int in_worker(pa_threaded_mainloop *m) {
59     return pa_thread_self() == m->thread;
60 }
61
62 static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
63     pa_mutex *mutex = userdata;
64     int r;
65
66     assert(mutex);
67
68     /* Before entering poll() we unlock the mutex, so that
69      * avahi_simple_poll_quit() can succeed from another thread. */
70
71     pa_mutex_unlock(mutex);
72     r = poll(ufds, nfds, timeout);
73     pa_mutex_lock(mutex);
74
75     return r;
76 }
77
78 static void thread(void *userdata) {
79     pa_threaded_mainloop *m = userdata;
80
81 #ifndef OS_IS_WIN32
82     sigset_t mask;
83
84     /* Make sure that signals are delivered to the main thread */
85     sigfillset(&mask);
86     pthread_sigmask(SIG_BLOCK, &mask, NULL);
87 #endif
88
89     pa_mutex_lock(m->mutex);
90
91     pa_mainloop_run(m->real_mainloop, NULL);
92
93     pa_mutex_unlock(m->mutex);
94 }
95
96 pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
97     pa_threaded_mainloop *m;
98
99     m = pa_xnew(pa_threaded_mainloop, 1);
100
101     if (!(m->real_mainloop = pa_mainloop_new())) {
102         pa_xfree(m);
103         return NULL;
104     }
105
106     m->mutex = pa_mutex_new(1);
107     m->cond = pa_cond_new();
108     m->accept_cond = pa_cond_new();
109     m->thread = NULL;
110
111     pa_mainloop_set_poll_func(m->real_mainloop, poll_func, m->mutex);
112
113     m->n_waiting = 0;
114
115     return m;
116 }
117
118 void pa_threaded_mainloop_free(pa_threaded_mainloop* m) {
119     assert(m);
120
121     /* Make sure that this function is not called from the helper thread */
122     assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m));
123
124     pa_threaded_mainloop_stop(m);
125
126     if (m->thread)
127         pa_thread_free(m->thread);
128
129     pa_mainloop_free(m->real_mainloop);
130
131     pa_mutex_free(m->mutex);
132     pa_cond_free(m->cond);
133     pa_cond_free(m->accept_cond);
134
135     pa_xfree(m);
136 }
137
138 int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
139     assert(m);
140
141     assert(!m->thread || !pa_thread_is_running(m->thread));
142
143     if (!(m->thread = pa_thread_new(thread, m)))
144         return -1;
145
146     return 0;
147 }
148
149 void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
150     assert(m);
151
152     if (!m->thread || !pa_thread_is_running(m->thread))
153         return;
154
155     /* Make sure that this function is not called from the helper thread */
156     assert(!in_worker(m));
157
158     pa_mutex_lock(m->mutex);
159     pa_mainloop_quit(m->real_mainloop, 0);
160     pa_mutex_unlock(m->mutex);
161
162     pa_thread_join(m->thread);
163 }
164
165 void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) {
166     assert(m);
167
168     /* Make sure that this function is not called from the helper thread */
169     assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
170
171     pa_mutex_lock(m->mutex);
172 }
173
174 void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) {
175     assert(m);
176
177     /* Make sure that this function is not called from the helper thread */
178     assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
179
180     pa_mutex_unlock(m->mutex);
181 }
182
183 void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) {
184     assert(m);
185
186     pa_cond_signal(m->cond, 1);
187
188     if (wait_for_accept && m->n_waiting > 0)
189         pa_cond_wait(m->accept_cond, m->mutex);
190 }
191
192 void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
193     assert(m);
194
195     /* Make sure that this function is not called from the helper thread */
196     assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
197
198     m->n_waiting ++;
199
200     pa_cond_wait(m->cond, m->mutex);
201
202     assert(m->n_waiting > 0);
203     m->n_waiting --;
204 }
205
206 void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) {
207     assert(m);
208
209     /* Make sure that this function is not called from the helper thread */
210     assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
211
212     pa_cond_signal(m->accept_cond, 0);
213 }
214
215 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
216     assert(m);
217
218     return pa_mainloop_get_retval(m->real_mainloop);
219 }
220
221 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) {
222     assert(m);
223
224     return pa_mainloop_get_api(m->real_mainloop);
225 }