]> code.delx.au - pulseaudio/blob - src/pulsecore/thread-posix.c
Merge dead branch 'lennart'
[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 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 #include <pulse/xmalloc.h>
32 #include <pulsecore/mutex.h>
33 #include <pulsecore/once.h>
34 #include <pulsecore/atomic.h>
35 #include <pulsecore/macro.h>
36
37 #include "thread.h"
38
39 struct pa_thread {
40 pthread_t id;
41 pa_thread_func_t thread_func;
42 void *userdata;
43 pa_atomic_t running;
44 };
45
46 struct pa_tls {
47 pthread_key_t key;
48 };
49
50 static void thread_free_cb(void *p) {
51 pa_thread *t = p;
52
53 pa_assert(t);
54
55 if (!t->thread_func)
56 /* This is a foreign thread, we need to free the struct */
57 pa_xfree(t);
58 }
59
60 PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb);
61
62 static void* internal_thread_func(void *userdata) {
63 pa_thread *t = userdata;
64 pa_assert(t);
65
66 t->id = pthread_self();
67
68 PA_STATIC_TLS_SET(current_thread, t);
69
70 pa_atomic_inc(&t->running);
71 t->thread_func(t->userdata);
72 pa_atomic_sub(&t->running, 2);
73
74 return NULL;
75 }
76
77 pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
78 pa_thread *t;
79
80 pa_assert(thread_func);
81
82 t = pa_xnew(pa_thread, 1);
83 t->thread_func = thread_func;
84 t->userdata = userdata;
85 pa_atomic_store(&t->running, 0);
86
87 if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) {
88 pa_xfree(t);
89 return NULL;
90 }
91
92 pa_atomic_inc(&t->running);
93
94 return t;
95 }
96
97 int pa_thread_is_running(pa_thread *t) {
98 pa_assert(t);
99
100 /* Unfortunately there is no way to tell whether a "foreign"
101 * thread is still running. See
102 * http://udrepper.livejournal.com/16844.html for more
103 * information */
104 pa_assert(t->thread_func);
105
106 return pa_atomic_load(&t->running) > 0;
107 }
108
109 void pa_thread_free(pa_thread *t) {
110 pa_assert(t);
111
112 pa_thread_join(t);
113 pa_xfree(t);
114 }
115
116 int pa_thread_join(pa_thread *t) {
117 pa_assert(t);
118
119 return pthread_join(t->id, NULL);
120 }
121
122 pa_thread* pa_thread_self(void) {
123 pa_thread *t;
124
125 if ((t = PA_STATIC_TLS_GET(current_thread)))
126 return t;
127
128 /* This is a foreign thread, let's create a pthread structure to
129 * make sure that we can always return a sensible pointer */
130
131 t = pa_xnew(pa_thread, 1);
132 t->id = pthread_self();
133 t->thread_func = NULL;
134 t->userdata = NULL;
135 pa_atomic_store(&t->running, 2);
136
137 PA_STATIC_TLS_SET(current_thread, t);
138
139 return t;
140 }
141
142 void* pa_thread_get_data(pa_thread *t) {
143 pa_assert(t);
144
145 return t->userdata;
146 }
147
148 void pa_thread_set_data(pa_thread *t, void *userdata) {
149 pa_assert(t);
150
151 t->userdata = userdata;
152 }
153
154 void pa_thread_yield(void) {
155 #ifdef HAVE_PTHREAD_YIELD
156 pthread_yield();
157 #else
158 pa_assert_se(sched_yield() == 0);
159 #endif
160 }
161
162 pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
163 pa_tls *t;
164
165 t = pa_xnew(pa_tls, 1);
166
167 if (pthread_key_create(&t->key, free_cb) < 0) {
168 pa_xfree(t);
169 return NULL;
170 }
171
172 return t;
173 }
174
175 void pa_tls_free(pa_tls *t) {
176 pa_assert(t);
177
178 pa_assert_se(pthread_key_delete(t->key) == 0);
179 pa_xfree(t);
180 }
181
182 void *pa_tls_get(pa_tls *t) {
183 pa_assert(t);
184
185 return pthread_getspecific(t->key);
186 }
187
188 void *pa_tls_set(pa_tls *t, void *userdata) {
189 void *r;
190
191 r = pthread_getspecific(t->key);
192 pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
193 return r;
194 }
195