]> code.delx.au - pulseaudio/blob - src/pulsecore/thread-posix.c
Merge remote branch 'mkbosmans/rate-adjustment'
[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/mutex.h>
37 #include <pulsecore/once.h>
38 #include <pulsecore/atomic.h>
39 #include <pulsecore/macro.h>
40
41 #include "thread.h"
42
43 struct pa_thread {
44 pthread_t id;
45 pa_thread_func_t thread_func;
46 void *userdata;
47 pa_atomic_t running;
48 pa_bool_t joined;
49 char *name;
50 };
51
52 struct pa_tls {
53 pthread_key_t key;
54 };
55
56 static void thread_free_cb(void *p) {
57 pa_thread *t = p;
58
59 pa_assert(t);
60
61 if (!t->thread_func) {
62 /* This is a foreign thread, we need to free the struct */
63 pa_xfree(t->name);
64 pa_xfree(t);
65 }
66 }
67
68 PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb);
69
70 static void* internal_thread_func(void *userdata) {
71 pa_thread *t = userdata;
72 pa_assert(t);
73
74 #ifdef __linux__
75 prctl(PR_SET_NAME, 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 int pa_thread_join(pa_thread *t) {
131 pa_assert(t);
132 pa_assert(t->thread_func);
133
134 if (t->joined)
135 return -1;
136
137 t->joined = TRUE;
138 return pthread_join(t->id, NULL);
139 }
140
141 pa_thread* pa_thread_self(void) {
142 pa_thread *t;
143
144 if ((t = PA_STATIC_TLS_GET(current_thread)))
145 return t;
146
147 /* This is a foreign thread, let's create a pthread structure to
148 * make sure that we can always return a sensible pointer */
149
150 t = pa_xnew0(pa_thread, 1);
151 t->id = pthread_self();
152 t->joined = TRUE;
153 pa_atomic_store(&t->running, 2);
154
155 PA_STATIC_TLS_SET(current_thread, t);
156
157 return t;
158 }
159
160 void* pa_thread_get_data(pa_thread *t) {
161 pa_assert(t);
162
163 return t->userdata;
164 }
165
166 void pa_thread_set_data(pa_thread *t, void *userdata) {
167 pa_assert(t);
168
169 t->userdata = userdata;
170 }
171
172 void pa_thread_set_name(pa_thread *t, const char *name) {
173 pa_assert(t);
174
175 pa_xfree(t->name);
176 t->name = pa_xstrdup(name);
177
178 #ifdef __linux__
179 prctl(PR_SET_NAME, name);
180 #endif
181 }
182
183 const char *pa_thread_get_name(pa_thread *t) {
184 pa_assert(t);
185
186 #ifdef __linux__
187 if (!t->name) {
188 t->name = pa_xmalloc(17);
189
190 if (prctl(PR_GET_NAME, t->name) >= 0)
191 t->name[16] = 0;
192 else {
193 pa_xfree(t->name);
194 t->name = NULL;
195 }
196 }
197 #endif
198
199 return t->name;
200 }
201
202 void pa_thread_yield(void) {
203 #ifdef HAVE_PTHREAD_YIELD
204 pthread_yield();
205 #else
206 pa_assert_se(sched_yield() == 0);
207 #endif
208 }
209
210 pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
211 pa_tls *t;
212
213 t = pa_xnew(pa_tls, 1);
214
215 if (pthread_key_create(&t->key, free_cb) < 0) {
216 pa_xfree(t);
217 return NULL;
218 }
219
220 return t;
221 }
222
223 void pa_tls_free(pa_tls *t) {
224 pa_assert(t);
225
226 pa_assert_se(pthread_key_delete(t->key) == 0);
227 pa_xfree(t);
228 }
229
230 void *pa_tls_get(pa_tls *t) {
231 pa_assert(t);
232
233 return pthread_getspecific(t->key);
234 }
235
236 void *pa_tls_set(pa_tls *t, void *userdata) {
237 void *r;
238
239 r = pthread_getspecific(t->key);
240 pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
241 return r;
242 }