core: call pa_sink_get_latency_within_thread() instead of going directly via process_...
[pulseaudio-mirror.git] / src / pulsecore / thread-posix.c
blobfdab270f06a80181b759f2b44ac95a82942a4fa5
1 /***
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
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <pthread.h>
28 #include <sched.h>
29 #include <errno.h>
31 #include <pulse/xmalloc.h>
32 #include <pulsecore/mutex.h>
33 #include <pulsecore/once.h>
34 #include <pulsecore/atomic.h>
35 #include <pulsecore/macro.h>
37 #include "thread.h"
39 struct pa_thread {
40 pthread_t id;
41 pa_thread_func_t thread_func;
42 void *userdata;
43 pa_atomic_t running;
44 pa_bool_t joined;
47 struct pa_tls {
48 pthread_key_t key;
51 static void thread_free_cb(void *p) {
52 pa_thread *t = p;
54 pa_assert(t);
56 if (!t->thread_func)
57 /* This is a foreign thread, we need to free the struct */
58 pa_xfree(t);
61 PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb);
63 static void* internal_thread_func(void *userdata) {
64 pa_thread *t = userdata;
65 pa_assert(t);
67 t->id = pthread_self();
69 PA_STATIC_TLS_SET(current_thread, t);
71 pa_atomic_inc(&t->running);
72 t->thread_func(t->userdata);
73 pa_atomic_sub(&t->running, 2);
75 return NULL;
78 pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
79 pa_thread *t;
81 pa_assert(thread_func);
83 t = pa_xnew(pa_thread, 1);
84 t->thread_func = thread_func;
85 t->userdata = userdata;
86 t->joined = FALSE;
87 pa_atomic_store(&t->running, 0);
89 if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) {
90 pa_xfree(t);
91 return NULL;
94 pa_atomic_inc(&t->running);
96 return t;
99 int pa_thread_is_running(pa_thread *t) {
100 pa_assert(t);
102 /* Unfortunately there is no way to tell whether a "foreign"
103 * thread is still running. See
104 * http://udrepper.livejournal.com/16844.html for more
105 * information */
106 pa_assert(t->thread_func);
108 return pa_atomic_load(&t->running) > 0;
111 void pa_thread_free(pa_thread *t) {
112 pa_assert(t);
114 pa_thread_join(t);
115 pa_xfree(t);
118 int pa_thread_join(pa_thread *t) {
119 pa_assert(t);
120 pa_assert(t->thread_func);
122 if (t->joined)
123 return -1;
125 t->joined = TRUE;
126 return pthread_join(t->id, NULL);
129 pa_thread* pa_thread_self(void) {
130 pa_thread *t;
132 if ((t = PA_STATIC_TLS_GET(current_thread)))
133 return t;
135 /* This is a foreign thread, let's create a pthread structure to
136 * make sure that we can always return a sensible pointer */
138 t = pa_xnew(pa_thread, 1);
139 t->id = pthread_self();
140 t->thread_func = NULL;
141 t->userdata = NULL;
142 t->joined = TRUE;
143 pa_atomic_store(&t->running, 2);
145 PA_STATIC_TLS_SET(current_thread, t);
147 return t;
150 void* pa_thread_get_data(pa_thread *t) {
151 pa_assert(t);
153 return t->userdata;
156 void pa_thread_set_data(pa_thread *t, void *userdata) {
157 pa_assert(t);
159 t->userdata = userdata;
162 void pa_thread_yield(void) {
163 #ifdef HAVE_PTHREAD_YIELD
164 pthread_yield();
165 #else
166 pa_assert_se(sched_yield() == 0);
167 #endif
170 pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
171 pa_tls *t;
173 t = pa_xnew(pa_tls, 1);
175 if (pthread_key_create(&t->key, free_cb) < 0) {
176 pa_xfree(t);
177 return NULL;
180 return t;
183 void pa_tls_free(pa_tls *t) {
184 pa_assert(t);
186 pa_assert_se(pthread_key_delete(t->key) == 0);
187 pa_xfree(t);
190 void *pa_tls_get(pa_tls *t) {
191 pa_assert(t);
193 return pthread_getspecific(t->key);
196 void *pa_tls_set(pa_tls *t, void *userdata) {
197 void *r;
199 r = pthread_getspecific(t->key);
200 pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
201 return r;