Branch data Line data Source code
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/atomic.h>
37 : : #include <pulsecore/macro.h>
38 : :
39 : : #include "thread.h"
40 : :
41 : : struct pa_thread {
42 : : pthread_t id;
43 : : pa_thread_func_t thread_func;
44 : : void *userdata;
45 : : pa_atomic_t running;
46 : : pa_bool_t joined;
47 : : char *name;
48 : : };
49 : :
50 : : struct pa_tls {
51 : : pthread_key_t key;
52 : : };
53 : :
54 : 49163 : static void thread_free_cb(void *p) {
55 : 49163 : pa_thread *t = p;
56 : :
57 [ - + ]: 49163 : pa_assert(t);
58 : :
59 [ - + ]: 49163 : if (!t->thread_func) {
60 : : /* This is a foreign thread, we need to free the struct */
61 : 0 : pa_xfree(t->name);
62 : 0 : pa_xfree(t);
63 : : }
64 : 49163 : }
65 : :
66 [ - + ][ # # ]: 50558 : PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb);
[ # # ][ # # ]
67 : :
68 : 50012 : static void* internal_thread_func(void *userdata) {
69 : 50012 : pa_thread *t = userdata;
70 [ - + ]: 50012 : pa_assert(t);
71 : :
72 : : #ifdef __linux__
73 : 50012 : prctl(PR_SET_NAME, t->name);
74 : : #elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN)
75 : : pthread_setname_np(t->name);
76 : : #endif
77 : :
78 : 50020 : t->id = pthread_self();
79 : :
80 : : PA_STATIC_TLS_SET(current_thread, t);
81 : :
82 : 50016 : pa_atomic_inc(&t->running);
83 : 50016 : t->thread_func(t->userdata);
84 : 47570 : pa_atomic_sub(&t->running, 2);
85 : :
86 : 47570 : return NULL;
87 : : }
88 : :
89 : 50029 : pa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata) {
90 : : pa_thread *t;
91 : :
92 [ - + ]: 50029 : pa_assert(thread_func);
93 : :
94 : 50029 : t = pa_xnew0(pa_thread, 1);
95 : 50029 : t->name = pa_xstrdup(name);
96 : 50029 : t->thread_func = thread_func;
97 : 50029 : t->userdata = userdata;
98 : :
99 [ - + ]: 50029 : if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) {
100 : 0 : pa_xfree(t);
101 : 0 : return NULL;
102 : : }
103 : :
104 : 50029 : pa_atomic_inc(&t->running);
105 : :
106 : 50029 : return t;
107 : : }
108 : :
109 : 7 : int pa_thread_is_running(pa_thread *t) {
110 [ - + ]: 7 : 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 [ - + ]: 7 : pa_assert(t->thread_func);
117 : :
118 : 7 : return pa_atomic_load(&t->running) > 0;
119 : : }
120 : :
121 : 50029 : void pa_thread_free(pa_thread *t) {
122 [ - + ]: 50029 : pa_assert(t);
123 : :
124 : 50029 : pa_thread_join(t);
125 : :
126 : 50029 : pa_xfree(t->name);
127 : 50029 : pa_xfree(t);
128 : 50029 : }
129 : :
130 : 100034 : int pa_thread_join(pa_thread *t) {
131 [ - + ]: 100034 : pa_assert(t);
132 [ - + ]: 100034 : pa_assert(t->thread_func);
133 : :
134 [ + + ]: 100034 : if (t->joined)
135 : : return -1;
136 : :
137 : 50029 : t->joined = TRUE;
138 : 100034 : return pthread_join(t->id, NULL);
139 : : }
140 : :
141 : 507 : pa_thread* pa_thread_self(void) {
142 : : pa_thread *t;
143 : :
144 [ + + ]: 507 : 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 : 1 : t = pa_xnew0(pa_thread, 1);
151 : 1 : t->id = pthread_self();
152 : 1 : t->joined = TRUE;
153 : 1 : pa_atomic_store(&t->running, 2);
154 : :
155 : : PA_STATIC_TLS_SET(current_thread, t);
156 : :
157 : 507 : return t;
158 : : }
159 : :
160 : 50500 : void* pa_thread_get_data(pa_thread *t) {
161 [ - + ]: 50500 : pa_assert(t);
162 : :
163 : 50500 : return t->userdata;
164 : : }
165 : :
166 : 0 : void pa_thread_set_data(pa_thread *t, void *userdata) {
167 [ # # ]: 0 : pa_assert(t);
168 : :
169 : 0 : t->userdata = userdata;
170 : 0 : }
171 : :
172 : 0 : void pa_thread_set_name(pa_thread *t, const char *name) {
173 [ # # ]: 0 : pa_assert(t);
174 : :
175 : 0 : pa_xfree(t->name);
176 : 0 : t->name = pa_xstrdup(name);
177 : :
178 : : #ifdef __linux__
179 : 0 : prctl(PR_SET_NAME, name);
180 : : #elif defined(HAVE_PTHREAD_SETNAME_NP) && defined(OS_IS_DARWIN)
181 : : pthread_setname_np(name);
182 : : #endif
183 : 0 : }
184 : :
185 : 0 : const char *pa_thread_get_name(pa_thread *t) {
186 [ # # ]: 0 : pa_assert(t);
187 : :
188 : : #ifdef __linux__
189 [ # # ]: 0 : if (!t->name) {
190 : 0 : t->name = pa_xmalloc(17);
191 : :
192 [ # # ]: 0 : if (prctl(PR_GET_NAME, t->name) >= 0)
193 : 0 : t->name[16] = 0;
194 : : else {
195 : 0 : pa_xfree(t->name);
196 : 0 : t->name = NULL;
197 : : }
198 : : }
199 : : #elif defined(HAVE_PTHREAD_GETNAME_NP) && defined(OS_IS_DARWIN)
200 : : if (!t->name) {
201 : : t->name = pa_xmalloc0(17);
202 : : pthread_getname_np(t->id, t->name, 16);
203 : : }
204 : : #endif
205 : :
206 : 0 : return t->name;
207 : : }
208 : :
209 : 2435819 : void pa_thread_yield(void) {
210 : : #ifdef HAVE_PTHREAD_YIELD
211 : : pthread_yield();
212 : : #else
213 [ - + ]: 2435819 : pa_assert_se(sched_yield() == 0);
214 : : #endif
215 : 2216644 : }
216 : :
217 : 7 : pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
218 : : pa_tls *t;
219 : :
220 : 7 : t = pa_xnew(pa_tls, 1);
221 : :
222 [ - + ]: 7 : if (pthread_key_create(&t->key, free_cb) < 0) {
223 : 0 : pa_xfree(t);
224 : 7 : return NULL;
225 : : }
226 : :
227 : : return t;
228 : : }
229 : :
230 : 1 : void pa_tls_free(pa_tls *t) {
231 [ - + ]: 1 : pa_assert(t);
232 : :
233 [ - + ]: 1 : pa_assert_se(pthread_key_delete(t->key) == 0);
234 : 1 : pa_xfree(t);
235 : 1 : }
236 : :
237 : 767 : void *pa_tls_get(pa_tls *t) {
238 [ - + ]: 767 : pa_assert(t);
239 : :
240 : 767 : return pthread_getspecific(t->key);
241 : : }
242 : :
243 : 50041 : void *pa_tls_set(pa_tls *t, void *userdata) {
244 : : void *r;
245 : :
246 : 50041 : r = pthread_getspecific(t->key);
247 [ - + ]: 50039 : pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
248 : 50035 : return r;
249 : : }
|