2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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
32 #include <sys/prctl.h>
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>
45 pa_thread_func_t thread_func
;
56 static void thread_free_cb(void *p
) {
61 if (!t
->thread_func
) {
62 /* This is a foreign thread, we need to free the struct */
68 PA_STATIC_TLS_DECLARE(current_thread
, thread_free_cb
);
70 static void* internal_thread_func(void *userdata
) {
71 pa_thread
*t
= userdata
;
75 prctl(PR_SET_NAME
, t
->name
);
76 #elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN)
77 pthread_setname_np(t
->name
);
80 t
->id
= pthread_self();
82 PA_STATIC_TLS_SET(current_thread
, t
);
84 pa_atomic_inc(&t
->running
);
85 t
->thread_func(t
->userdata
);
86 pa_atomic_sub(&t
->running
, 2);
91 pa_thread
* pa_thread_new(const char *name
, pa_thread_func_t thread_func
, void *userdata
) {
94 pa_assert(thread_func
);
96 t
= pa_xnew0(pa_thread
, 1);
97 t
->name
= pa_xstrdup(name
);
98 t
->thread_func
= thread_func
;
99 t
->userdata
= userdata
;
101 if (pthread_create(&t
->id
, NULL
, internal_thread_func
, t
) < 0) {
106 pa_atomic_inc(&t
->running
);
111 int pa_thread_is_running(pa_thread
*t
) {
114 /* Unfortunately there is no way to tell whether a "foreign"
115 * thread is still running. See
116 * http://udrepper.livejournal.com/16844.html for more
118 pa_assert(t
->thread_func
);
120 return pa_atomic_load(&t
->running
) > 0;
123 void pa_thread_free(pa_thread
*t
) {
132 int pa_thread_join(pa_thread
*t
) {
134 pa_assert(t
->thread_func
);
140 return pthread_join(t
->id
, NULL
);
143 pa_thread
* pa_thread_self(void) {
146 if ((t
= PA_STATIC_TLS_GET(current_thread
)))
149 /* This is a foreign thread, let's create a pthread structure to
150 * make sure that we can always return a sensible pointer */
152 t
= pa_xnew0(pa_thread
, 1);
153 t
->id
= pthread_self();
155 pa_atomic_store(&t
->running
, 2);
157 PA_STATIC_TLS_SET(current_thread
, t
);
162 void* pa_thread_get_data(pa_thread
*t
) {
168 void pa_thread_set_data(pa_thread
*t
, void *userdata
) {
171 t
->userdata
= userdata
;
174 void pa_thread_set_name(pa_thread
*t
, const char *name
) {
178 t
->name
= pa_xstrdup(name
);
181 prctl(PR_SET_NAME
, name
);
182 #elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN)
183 pthread_setname_np(name
);
187 const char *pa_thread_get_name(pa_thread
*t
) {
192 t
->name
= pa_xmalloc(17);
194 if (prctl(PR_GET_NAME
, t
->name
) >= 0)
201 #elif defined(HAVE_PTHREAD_GETNAME_NP) && defined(OS_IS_DARWIN)
203 t
->name
= pa_xmalloc0(17);
204 pthread_getname_np(t
->id
, t
->name
, 16);
211 void pa_thread_yield(void) {
212 #ifdef HAVE_PTHREAD_YIELD
215 pa_assert_se(sched_yield() == 0);
219 pa_tls
* pa_tls_new(pa_free_cb_t free_cb
) {
222 t
= pa_xnew(pa_tls
, 1);
224 if (pthread_key_create(&t
->key
, free_cb
) < 0) {
232 void pa_tls_free(pa_tls
*t
) {
235 pa_assert_se(pthread_key_delete(t
->key
) == 0);
239 void *pa_tls_get(pa_tls
*t
) {
242 return pthread_getspecific(t
->key
);
245 void *pa_tls_set(pa_tls
*t
, void *userdata
) {
248 r
= pthread_getspecific(t
->key
);
249 pa_assert_se(pthread_setspecific(t
->key
, userdata
) == 0);