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