]> code.delx.au - pulseaudio/blob - src/polyp/thread-mainloop.c
62813acd3a3199ce36526d10c05c3fc640accb02
[pulseaudio] / src / polyp / thread-mainloop.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio 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 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; 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 <signal.h>
28 #include <stdio.h>
29
30 #ifdef HAVE_SYS_POLL_H
31 #include <sys/poll.h>
32 #else
33 #include "../polypcore/poll.h"
34 #endif
35
36 #ifdef HAVE_PTHREAD
37 #include <pthread.h>
38 #endif
39
40 #include <polypcore/xmalloc.h>
41
42 #include "mainloop.h"
43 #include "thread-mainloop.h"
44
45 #ifndef OS_IS_WIN32
46
47 struct pa_threaded_mainloop {
48 pa_mainloop *real_mainloop;
49 pthread_t thread_id;
50 pthread_mutex_t mutex;
51 int n_waiting;
52 pthread_cond_t cond, release_cond;
53 int thread_running;
54 };
55
56 static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
57 pthread_mutex_t *mutex = userdata;
58 int r;
59
60 assert(mutex);
61
62 /* Before entering poll() we unlock the mutex, so that
63 * avahi_simple_poll_quit() can succeed from another thread. */
64
65 pthread_mutex_unlock(mutex);
66 r = poll(ufds, nfds, timeout);
67 pthread_mutex_lock(mutex);
68
69 return r;
70 }
71
72 static void* thread(void *userdata){
73 pa_threaded_mainloop *m = userdata;
74 sigset_t mask;
75
76 /* Make sure that signals are delivered to the main thread */
77 sigfillset(&mask);
78 pthread_sigmask(SIG_BLOCK, &mask, NULL);
79
80 pthread_mutex_lock(&m->mutex);
81 pa_mainloop_run(m->real_mainloop, NULL);
82 pthread_mutex_unlock(&m->mutex);
83
84 return NULL;
85 }
86
87 pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
88 pa_threaded_mainloop *m;
89 pthread_mutexattr_t a;
90
91 m = pa_xnew(pa_threaded_mainloop, 1);
92
93 if (!(m->real_mainloop = pa_mainloop_new())) {
94 pa_xfree(m);
95 return NULL;
96 }
97
98 pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex);
99
100 pthread_mutexattr_init(&a);
101 pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
102 pthread_mutex_init(&m->mutex, &a);
103 pthread_mutexattr_destroy(&a);
104
105 pthread_cond_init(&m->cond, NULL);
106 pthread_cond_init(&m->release_cond, NULL);
107 m->thread_running = 0;
108 m->n_waiting = 0;
109
110 return m;
111 }
112
113 void pa_threaded_mainloop_free(pa_threaded_mainloop* m) {
114 assert(m);
115
116 /* Make sure that this function is not called from the helper thread */
117 assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id));
118
119 if (m->thread_running)
120 pa_threaded_mainloop_stop(m);
121
122 if (m->real_mainloop)
123 pa_mainloop_free(m->real_mainloop);
124
125 pthread_mutex_destroy(&m->mutex);
126 pthread_cond_destroy(&m->cond);
127 pthread_cond_destroy(&m->release_cond);
128
129 pa_xfree(m);
130 }
131
132 int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
133 assert(m);
134
135 assert(!m->thread_running);
136
137 pthread_mutex_lock(&m->mutex);
138
139 if (pthread_create(&m->thread_id, NULL, thread, m) < 0) {
140 pthread_mutex_unlock(&m->mutex);
141 return -1;
142 }
143
144 m->thread_running = 1;
145
146 pthread_mutex_unlock(&m->mutex);
147
148 return 0;
149 }
150
151 void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
152 assert(m);
153
154 if (!m->thread_running)
155 return;
156
157 /* Make sure that this function is not called from the helper thread */
158 assert(!pthread_equal(pthread_self(), m->thread_id));
159
160 pthread_mutex_lock(&m->mutex);
161 pa_mainloop_quit(m->real_mainloop, 0);
162 pthread_mutex_unlock(&m->mutex);
163
164 pthread_join(m->thread_id, NULL);
165 m->thread_running = 0;
166
167 return;
168 }
169
170 void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) {
171 assert(m);
172
173 /* Make sure that this function is not called from the helper thread */
174 assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id));
175
176 pthread_mutex_lock(&m->mutex);
177 }
178
179 void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) {
180 assert(m);
181
182 /* Make sure that this function is not called from the helper thread */
183 assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id));
184
185 pthread_mutex_unlock(&m->mutex);
186 }
187
188 void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) {
189 assert(m);
190
191 pthread_cond_broadcast(&m->cond);
192
193 if (wait_for_release && m->n_waiting > 0)
194 pthread_cond_wait(&m->release_cond, &m->mutex);
195 }
196
197 void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
198 assert(m);
199
200 /* Make sure that this function is not called from the helper thread */
201 assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id));
202
203 m->n_waiting ++;
204 pthread_cond_wait(&m->cond, &m->mutex);
205 assert(m->n_waiting > 0);
206 m->n_waiting --;
207 pthread_cond_signal(&m->release_cond);
208 }
209
210 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
211 assert(m);
212
213 return pa_mainloop_get_retval(m->real_mainloop);
214 }
215
216 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) {
217 assert(m);
218
219 return pa_mainloop_get_api(m->real_mainloop);
220 }
221
222 #else /* OS_IS_WIN32 */
223
224 // FIXME: Use Win32 primitives
225
226 #endif /* OS_IS_WIN32 */