]> code.delx.au - pulseaudio/blob - src/pulsecore/thread-posix.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[pulseaudio] / src / pulsecore / thread-posix.c
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 #include <pthread.h>
28 #include <sched.h>
29 #include <errno.h>
30
31 #ifdef __linux__
32 #include <sys/prctl.h>
33 #endif
34
35 #include <pulse/xmalloc.h>
36 #include <pulsecore/atomic.h>
37 #include <pulsecore/macro.h>
38
39 #include "thread.h"
40
41 struct pa_thread {
42 pthread_t id;
43 pa_thread_func_t thread_func;
44 void *userdata;
45 pa_atomic_t running;
46 bool joined;
47 char *name;
48 };
49
50 struct pa_tls {
51 pthread_key_t key;
52 };
53
54 static void thread_free_cb(void *p) {
55 pa_thread *t = p;
56
57 pa_assert(t);
58
59 if (!t->thread_func) {
60 /* This is a foreign thread, we need to free the struct */
61 pa_xfree(t->name);
62 pa_xfree(t);
63 }
64 }
65
66 PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb);
67
68 static void* internal_thread_func(void *userdata) {
69 pa_thread *t = userdata;
70 pa_assert(t);
71
72 #ifdef __linux__
73 prctl(PR_SET_NAME, t->name);
74 #elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN)
75 pthread_setname_np(t->name);
76 #endif
77
78 t->id = pthread_self();
79
80 PA_STATIC_TLS_SET(current_thread, t);
81
82 pa_atomic_inc(&t->running);
83 t->thread_func(t->userdata);
84 pa_atomic_sub(&t->running, 2);
85
86 return NULL;
87 }
88
89 pa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata) {
90 pa_thread *t;
91
92 pa_assert(thread_func);
93
94 t = pa_xnew0(pa_thread, 1);
95 t->name = pa_xstrdup(name);
96 t->thread_func = thread_func;
97 t->userdata = userdata;
98
99 if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) {
100 pa_xfree(t);
101 return NULL;
102 }
103
104 pa_atomic_inc(&t->running);
105
106 return t;
107 }
108
109 int pa_thread_is_running(pa_thread *t) {
110 pa_assert(t);
111
112 /* Unfortunately there is no way to tell whether a "foreign"
113 * thread is still running. See
114 * http://udrepper.livejournal.com/16844.html for more
115 * information */
116 pa_assert(t->thread_func);
117
118 return pa_atomic_load(&t->running) > 0;
119 }
120
121 void pa_thread_free(pa_thread *t) {
122 pa_assert(t);
123
124 pa_thread_join(t);
125
126 pa_xfree(t->name);
127 pa_xfree(t);
128 }
129
130 void pa_thread_free_nojoin(pa_thread *t) {
131 pa_assert(t);
132
133 pa_xfree(t->name);
134 pa_xfree(t);
135 }
136
137 int pa_thread_join(pa_thread *t) {
138 pa_assert(t);
139 pa_assert(t->thread_func);
140
141 if (t->joined)
142 return -1;
143
144 t->joined = true;
145 return pthread_join(t->id, NULL);
146 }
147
148 pa_thread* pa_thread_self(void) {
149 pa_thread *t;
150
151 if ((t = PA_STATIC_TLS_GET(current_thread)))
152 return t;
153
154 /* This is a foreign thread, let's create a pthread structure to
155 * make sure that we can always return a sensible pointer */
156
157 t = pa_xnew0(pa_thread, 1);
158 t->id = pthread_self();
159 t->joined = true;
160 pa_atomic_store(&t->running, 2);
161
162 PA_STATIC_TLS_SET(current_thread, t);
163
164 return t;
165 }
166
167 void* pa_thread_get_data(pa_thread *t) {
168 pa_assert(t);
169
170 return t->userdata;
171 }
172
173 void pa_thread_set_data(pa_thread *t, void *userdata) {
174 pa_assert(t);
175
176 t->userdata = userdata;
177 }
178
179 void pa_thread_set_name(pa_thread *t, const char *name) {
180 pa_assert(t);
181
182 pa_xfree(t->name);
183 t->name = pa_xstrdup(name);
184
185 #ifdef __linux__
186 prctl(PR_SET_NAME, name);
187 #elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN)
188 pthread_setname_np(name);
189 #endif
190 }
191
192 const char *pa_thread_get_name(pa_thread *t) {
193 pa_assert(t);
194
195 #ifdef __linux__
196 if (!t->name) {
197 t->name = pa_xmalloc(17);
198
199 if (prctl(PR_GET_NAME, t->name) >= 0)
200 t->name[16] = 0;
201 else {
202 pa_xfree(t->name);
203 t->name = NULL;
204 }
205 }
206 #elif defined(HAVE_PTHREAD_GETNAME_NP) && defined(OS_IS_DARWIN)
207 if (!t->name) {
208 t->name = pa_xmalloc0(17);
209 pthread_getname_np(t->id, t->name, 16);
210 }
211 #endif
212
213 return t->name;
214 }
215
216 void pa_thread_yield(void) {
217 #ifdef HAVE_PTHREAD_YIELD
218 pthread_yield();
219 #else
220 pa_assert_se(sched_yield() == 0);
221 #endif
222 }
223
224 pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
225 pa_tls *t;
226
227 t = pa_xnew(pa_tls, 1);
228
229 if (pthread_key_create(&t->key, free_cb) < 0) {
230 pa_xfree(t);
231 return NULL;
232 }
233
234 return t;
235 }
236
237 void pa_tls_free(pa_tls *t) {
238 pa_assert(t);
239
240 pa_assert_se(pthread_key_delete(t->key) == 0);
241 pa_xfree(t);
242 }
243
244 void *pa_tls_get(pa_tls *t) {
245 pa_assert(t);
246
247 return pthread_getspecific(t->key);
248 }
249
250 void *pa_tls_set(pa_tls *t, void *userdata) {
251 void *r;
252
253 r = pthread_getspecific(t->key);
254 pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
255 return r;
256 }