153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <pthread.h> 2653a5a1b3Sopenharmony_ci#include <sched.h> 2753a5a1b3Sopenharmony_ci#include <errno.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#ifdef __linux__ 3053a5a1b3Sopenharmony_ci#include <sys/prctl.h> 3153a5a1b3Sopenharmony_ci#endif 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3453a5a1b3Sopenharmony_ci#include <pulsecore/atomic.h> 3553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_ci#include "thread.h" 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_cistruct pa_thread { 4053a5a1b3Sopenharmony_ci pthread_t id; 4153a5a1b3Sopenharmony_ci pa_thread_func_t thread_func; 4253a5a1b3Sopenharmony_ci void *userdata; 4353a5a1b3Sopenharmony_ci pa_atomic_t running; 4453a5a1b3Sopenharmony_ci bool joined; 4553a5a1b3Sopenharmony_ci char *name; 4653a5a1b3Sopenharmony_ci}; 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_cistruct pa_tls { 4953a5a1b3Sopenharmony_ci pthread_key_t key; 5053a5a1b3Sopenharmony_ci}; 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_cistatic void thread_free_cb(void *p) { 5353a5a1b3Sopenharmony_ci pa_thread *t = p; 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci pa_assert(t); 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_ci if (!t->thread_func) { 5853a5a1b3Sopenharmony_ci /* This is a foreign thread, we need to free the struct */ 5953a5a1b3Sopenharmony_ci pa_xfree(t->name); 6053a5a1b3Sopenharmony_ci pa_xfree(t); 6153a5a1b3Sopenharmony_ci } 6253a5a1b3Sopenharmony_ci} 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_ciPA_STATIC_TLS_DECLARE(current_thread, thread_free_cb); 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_cistatic void* internal_thread_func(void *userdata) { 6753a5a1b3Sopenharmony_ci pa_thread *t = userdata; 6853a5a1b3Sopenharmony_ci pa_assert(t); 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci#ifdef __linux__ 7153a5a1b3Sopenharmony_ci prctl(PR_SET_NAME, t->name); 7253a5a1b3Sopenharmony_ci#elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN) 7353a5a1b3Sopenharmony_ci pthread_setname_np(t->name); 7453a5a1b3Sopenharmony_ci#endif 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci t->id = pthread_self(); 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci PA_STATIC_TLS_SET(current_thread, t); 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci pa_atomic_inc(&t->running); 8153a5a1b3Sopenharmony_ci t->thread_func(t->userdata); 8253a5a1b3Sopenharmony_ci pa_atomic_sub(&t->running, 2); 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_ci return NULL; 8553a5a1b3Sopenharmony_ci} 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_cipa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata) { 8853a5a1b3Sopenharmony_ci pa_thread *t; 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_ci pa_assert(thread_func); 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci t = pa_xnew0(pa_thread, 1); 9353a5a1b3Sopenharmony_ci t->name = pa_xstrdup(name); 9453a5a1b3Sopenharmony_ci t->thread_func = thread_func; 9553a5a1b3Sopenharmony_ci t->userdata = userdata; 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { 9853a5a1b3Sopenharmony_ci pa_xfree(t); 9953a5a1b3Sopenharmony_ci return NULL; 10053a5a1b3Sopenharmony_ci } 10153a5a1b3Sopenharmony_ci 10253a5a1b3Sopenharmony_ci pa_atomic_inc(&t->running); 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci return t; 10553a5a1b3Sopenharmony_ci} 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ciint pa_thread_is_running(pa_thread *t) { 10853a5a1b3Sopenharmony_ci pa_assert(t); 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci /* Unfortunately there is no way to tell whether a "foreign" 11153a5a1b3Sopenharmony_ci * thread is still running. See 11253a5a1b3Sopenharmony_ci * http://udrepper.livejournal.com/16844.html for more 11353a5a1b3Sopenharmony_ci * information */ 11453a5a1b3Sopenharmony_ci pa_assert(t->thread_func); 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci return pa_atomic_load(&t->running) > 0; 11753a5a1b3Sopenharmony_ci} 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_civoid pa_thread_free(pa_thread *t) { 12053a5a1b3Sopenharmony_ci pa_assert(t); 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci pa_thread_join(t); 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci pa_xfree(t->name); 12553a5a1b3Sopenharmony_ci pa_xfree(t); 12653a5a1b3Sopenharmony_ci} 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_civoid pa_thread_free_nojoin(pa_thread *t) { 12953a5a1b3Sopenharmony_ci pa_assert(t); 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_ci pa_xfree(t->name); 13253a5a1b3Sopenharmony_ci pa_xfree(t); 13353a5a1b3Sopenharmony_ci} 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_ciint pa_thread_join(pa_thread *t) { 13653a5a1b3Sopenharmony_ci pa_assert(t); 13753a5a1b3Sopenharmony_ci pa_assert(t->thread_func); 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci if (t->joined) 14053a5a1b3Sopenharmony_ci return -1; 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci t->joined = true; 14353a5a1b3Sopenharmony_ci return pthread_join(t->id, NULL); 14453a5a1b3Sopenharmony_ci} 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_cipa_thread* pa_thread_self(void) { 14753a5a1b3Sopenharmony_ci pa_thread *t; 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci if ((t = PA_STATIC_TLS_GET(current_thread))) 15053a5a1b3Sopenharmony_ci return t; 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci /* This is a foreign thread, let's create a pthread structure to 15353a5a1b3Sopenharmony_ci * make sure that we can always return a sensible pointer */ 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci t = pa_xnew0(pa_thread, 1); 15653a5a1b3Sopenharmony_ci t->id = pthread_self(); 15753a5a1b3Sopenharmony_ci t->joined = true; 15853a5a1b3Sopenharmony_ci pa_atomic_store(&t->running, 2); 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci PA_STATIC_TLS_SET(current_thread, t); 16153a5a1b3Sopenharmony_ci 16253a5a1b3Sopenharmony_ci return t; 16353a5a1b3Sopenharmony_ci} 16453a5a1b3Sopenharmony_ci 16553a5a1b3Sopenharmony_civoid* pa_thread_get_data(pa_thread *t) { 16653a5a1b3Sopenharmony_ci pa_assert(t); 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ci return t->userdata; 16953a5a1b3Sopenharmony_ci} 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_civoid pa_thread_set_data(pa_thread *t, void *userdata) { 17253a5a1b3Sopenharmony_ci pa_assert(t); 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci t->userdata = userdata; 17553a5a1b3Sopenharmony_ci} 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_civoid pa_thread_set_name(pa_thread *t, const char *name) { 17853a5a1b3Sopenharmony_ci pa_assert(t); 17953a5a1b3Sopenharmony_ci 18053a5a1b3Sopenharmony_ci pa_xfree(t->name); 18153a5a1b3Sopenharmony_ci t->name = pa_xstrdup(name); 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci#ifdef __linux__ 18453a5a1b3Sopenharmony_ci prctl(PR_SET_NAME, name); 18553a5a1b3Sopenharmony_ci#elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN) 18653a5a1b3Sopenharmony_ci pthread_setname_np(name); 18753a5a1b3Sopenharmony_ci#endif 18853a5a1b3Sopenharmony_ci} 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ciconst char *pa_thread_get_name(pa_thread *t) { 19153a5a1b3Sopenharmony_ci pa_assert(t); 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_ci#ifdef __linux__ 19453a5a1b3Sopenharmony_ci if (!t->name) { 19553a5a1b3Sopenharmony_ci t->name = pa_xmalloc(17); 19653a5a1b3Sopenharmony_ci 19753a5a1b3Sopenharmony_ci if (prctl(PR_GET_NAME, t->name) >= 0) 19853a5a1b3Sopenharmony_ci t->name[16] = 0; 19953a5a1b3Sopenharmony_ci else { 20053a5a1b3Sopenharmony_ci pa_xfree(t->name); 20153a5a1b3Sopenharmony_ci t->name = NULL; 20253a5a1b3Sopenharmony_ci } 20353a5a1b3Sopenharmony_ci } 20453a5a1b3Sopenharmony_ci#elif defined(HAVE_PTHREAD_GETNAME_NP) && defined(OS_IS_DARWIN) 20553a5a1b3Sopenharmony_ci if (!t->name) { 20653a5a1b3Sopenharmony_ci t->name = pa_xmalloc0(17); 20753a5a1b3Sopenharmony_ci pthread_getname_np(t->id, t->name, 16); 20853a5a1b3Sopenharmony_ci } 20953a5a1b3Sopenharmony_ci#endif 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci return t->name; 21253a5a1b3Sopenharmony_ci} 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_civoid pa_thread_yield(void) { 21553a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD_YIELD 21653a5a1b3Sopenharmony_ci pthread_yield(); 21753a5a1b3Sopenharmony_ci#else 21853a5a1b3Sopenharmony_ci pa_assert_se(sched_yield() == 0); 21953a5a1b3Sopenharmony_ci#endif 22053a5a1b3Sopenharmony_ci} 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_cipa_tls* pa_tls_new(pa_free_cb_t free_cb) { 22353a5a1b3Sopenharmony_ci pa_tls *t; 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci t = pa_xnew(pa_tls, 1); 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci if (pthread_key_create(&t->key, free_cb) < 0) { 22853a5a1b3Sopenharmony_ci pa_xfree(t); 22953a5a1b3Sopenharmony_ci return NULL; 23053a5a1b3Sopenharmony_ci } 23153a5a1b3Sopenharmony_ci 23253a5a1b3Sopenharmony_ci return t; 23353a5a1b3Sopenharmony_ci} 23453a5a1b3Sopenharmony_ci 23553a5a1b3Sopenharmony_civoid pa_tls_free(pa_tls *t) { 23653a5a1b3Sopenharmony_ci pa_assert(t); 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci pa_assert_se(pthread_key_delete(t->key) == 0); 23953a5a1b3Sopenharmony_ci pa_xfree(t); 24053a5a1b3Sopenharmony_ci} 24153a5a1b3Sopenharmony_ci 24253a5a1b3Sopenharmony_civoid *pa_tls_get(pa_tls *t) { 24353a5a1b3Sopenharmony_ci pa_assert(t); 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_ci return pthread_getspecific(t->key); 24653a5a1b3Sopenharmony_ci} 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_civoid *pa_tls_set(pa_tls *t, void *userdata) { 24953a5a1b3Sopenharmony_ci void *r; 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci r = pthread_getspecific(t->key); 25253a5a1b3Sopenharmony_ci pa_assert_se(pthread_setspecific(t->key, userdata) == 0); 25353a5a1b3Sopenharmony_ci return r; 25453a5a1b3Sopenharmony_ci} 255