• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
5 
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10 
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <stdio.h>
25 
26 #include <windows.h>
27 
28 #include <pulse/xmalloc.h>
29 #include <pulsecore/once.h>
30 
31 #include "thread.h"
32 
33 struct pa_thread {
34     HANDLE thread;
35     pa_thread_func_t thread_func;
36     void *userdata;
37 };
38 
39 struct pa_tls {
40     DWORD index;
41     pa_free_cb_t free_func;
42 };
43 
44 struct pa_tls_monitor {
45     HANDLE thread;
46     pa_free_cb_t free_func;
47     void *data;
48 };
49 
50 static pa_tls *thread_tls;
51 static pa_once thread_tls_once = PA_ONCE_INIT;
52 static pa_tls *monitor_tls;
53 
thread_tls_once_func(void)54 static void thread_tls_once_func(void) {
55     thread_tls = pa_tls_new(NULL);
56     assert(thread_tls);
57 }
58 
internal_thread_func(LPVOID param)59 static DWORD WINAPI internal_thread_func(LPVOID param) {
60     pa_thread *t = param;
61     assert(t);
62 
63     pa_run_once(&thread_tls_once, thread_tls_once_func);
64     pa_tls_set(thread_tls, t);
65 
66     t->thread_func(t->userdata);
67 
68     return 0;
69 }
70 
pa_thread_new(const char * name,pa_thread_func_t thread_func,void * userdata)71 pa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata) {
72     pa_thread *t;
73     DWORD thread_id;
74 
75     assert(thread_func);
76 
77     t = pa_xnew(pa_thread, 1);
78     t->thread_func = thread_func;
79     t->userdata = userdata;
80 
81     t->thread = CreateThread(NULL, 0, internal_thread_func, t, 0, &thread_id);
82 
83     if (!t->thread) {
84         pa_xfree(t);
85         return NULL;
86     }
87 
88     return t;
89 }
90 
pa_thread_is_running(pa_thread * t)91 int pa_thread_is_running(pa_thread *t) {
92     DWORD code;
93 
94     assert(t);
95 
96     if (!GetExitCodeThread(t->thread, &code))
97         return 0;
98 
99     return code == STILL_ACTIVE;
100 }
101 
pa_thread_free(pa_thread * t)102 void pa_thread_free(pa_thread *t) {
103     assert(t);
104 
105     pa_thread_join(t);
106     CloseHandle(t->thread);
107     pa_xfree(t);
108 }
109 
pa_thread_free_nojoin(pa_thread * t)110 void pa_thread_free_nojoin(pa_thread *t) {
111     pa_assert(t);
112 
113     CloseHandle(t->thread);
114     pa_xfree(t);
115 }
116 
pa_thread_join(pa_thread * t)117 int pa_thread_join(pa_thread *t) {
118     assert(t);
119 
120     if (WaitForSingleObject(t->thread, INFINITE) == WAIT_FAILED)
121         return -1;
122 
123     return 0;
124 }
125 
pa_thread_self(void)126 pa_thread* pa_thread_self(void) {
127     pa_run_once(&thread_tls_once, thread_tls_once_func);
128     return pa_tls_get(thread_tls);
129 }
130 
pa_thread_get_data(pa_thread * t)131 void* pa_thread_get_data(pa_thread *t) {
132     pa_assert(t);
133 
134     return t->userdata;
135 }
136 
pa_thread_set_data(pa_thread * t,void * userdata)137 void pa_thread_set_data(pa_thread *t, void *userdata) {
138     pa_assert(t);
139 
140     t->userdata = userdata;
141 }
142 
pa_thread_set_name(pa_thread * t,const char * name)143 void pa_thread_set_name(pa_thread *t, const char *name) {
144     /* Not implemented */
145 }
146 
pa_thread_get_name(pa_thread * t)147 const char *pa_thread_get_name(pa_thread *t) {
148     /* Not implemented */
149     return NULL;
150 }
151 
pa_thread_yield(void)152 void pa_thread_yield(void) {
153     Sleep(0);
154 }
155 
monitor_thread_func(LPVOID param)156 static DWORD WINAPI monitor_thread_func(LPVOID param) {
157     struct pa_tls_monitor *m = param;
158     assert(m);
159 
160     WaitForSingleObject(m->thread, INFINITE);
161 
162     CloseHandle(m->thread);
163 
164     m->free_func(m->data);
165 
166     pa_xfree(m);
167 
168     return 0;
169 }
170 
pa_tls_new(pa_free_cb_t free_cb)171 pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
172     pa_tls *t;
173 
174     t = pa_xnew(pa_tls, 1);
175     t->index = TlsAlloc();
176     t->free_func = free_cb;
177 
178     if (t->index == TLS_OUT_OF_INDEXES) {
179         pa_xfree(t);
180         return NULL;
181     }
182 
183     return t;
184 }
185 
pa_tls_free(pa_tls * t)186 void pa_tls_free(pa_tls *t) {
187     assert(t);
188 
189     TlsFree(t->index);
190     pa_xfree(t);
191 }
192 
pa_tls_get(pa_tls * t)193 void *pa_tls_get(pa_tls *t) {
194     assert(t);
195 
196     return TlsGetValue(t->index);
197 }
198 
pa_tls_set(pa_tls * t,void * userdata)199 void *pa_tls_set(pa_tls *t, void *userdata) {
200     void *r;
201 
202     assert(t);
203 
204     r = TlsGetValue(t->index);
205 
206     TlsSetValue(t->index, userdata);
207 
208     if (t->free_func) {
209         struct pa_tls_monitor *m;
210 
211         PA_ONCE_BEGIN {
212             monitor_tls = pa_tls_new(NULL);
213             assert(monitor_tls);
214             pa_tls_set(monitor_tls, NULL);
215         } PA_ONCE_END;
216 
217         m = pa_tls_get(monitor_tls);
218         if (!m) {
219             HANDLE thread;
220 
221             m = pa_xnew(struct pa_tls_monitor, 1);
222 
223             DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
224                 GetCurrentProcess(), &m->thread, 0, FALSE,
225                 DUPLICATE_SAME_ACCESS);
226 
227             m->free_func = t->free_func;
228 
229             pa_tls_set(monitor_tls, m);
230 
231             thread = CreateThread(NULL, 0, monitor_thread_func, m, 0, NULL);
232             assert(thread);
233             CloseHandle(thread);
234         }
235 
236         m->data = userdata;
237     }
238 
239     return r;
240 }
241