]> code.delx.au - pulseaudio/blob - src/pulsecore/thread-win32.c
Huge trailing whitespace cleanup. Let's keep the tree pure from here on,
[pulseaudio] / src / pulsecore / thread-win32.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
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 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, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27
28 #include <windows.h>
29
30 #include <pulse/xmalloc.h>
31 #include <pulsecore/log.h>
32 #include <pulsecore/once.h>
33
34 #include "thread.h"
35
36 struct pa_thread {
37 HANDLE thread;
38 pa_thread_func_t thread_func;
39 void *userdata;
40 };
41
42 struct pa_tls {
43 DWORD index;
44 pa_free_cb_t free_func;
45 };
46
47 struct pa_tls_monitor {
48 HANDLE thread;
49 pa_free_cb_t free_func;
50 void *data;
51 };
52
53 static pa_tls *thread_tls;
54 static pa_once_t thread_tls_once = PA_ONCE_INIT;
55 static pa_tls *monitor_tls;
56 static pa_once_t monitor_tls_once = PA_ONCE_INIT;
57
58 static void thread_tls_once_func(void) {
59 thread_tls = pa_tls_new(NULL);
60 assert(thread_tls);
61 }
62
63 static DWORD WINAPI internal_thread_func(LPVOID param) {
64 pa_thread *t = param;
65 assert(t);
66
67 pa_once(&thread_tls_once, thread_tls_once_func);
68 pa_tls_set(thread_tls, t);
69
70 t->thread_func(t->userdata);
71
72 return 0;
73 }
74
75 pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
76 pa_thread *t;
77
78 assert(thread_func);
79
80 t = pa_xnew(pa_thread, 1);
81 t->thread_func = thread_func;
82 t->userdata = userdata;
83
84 t->thread = CreateThread(NULL, 0, internal_thread_func, t, 0, NULL);
85
86 if (!t->thread) {
87 pa_xfree(t);
88 return NULL;
89 }
90
91 return t;
92 }
93
94 int pa_thread_is_running(pa_thread *t) {
95 DWORD code;
96
97 assert(t);
98
99 if (!GetExitCodeThread(t->thread, &code))
100 return 0;
101
102 return code == STILL_ACTIVE;
103 }
104
105 void pa_thread_free(pa_thread *t) {
106 assert(t);
107
108 pa_thread_join(t);
109 CloseHandle(t->thread);
110 pa_xfree(t);
111 }
112
113 int pa_thread_join(pa_thread *t) {
114 assert(t);
115
116 if (WaitForSingleObject(t->thread, INFINITE) == WAIT_FAILED)
117 return -1;
118
119 return 0;
120 }
121
122 pa_thread* pa_thread_self(void) {
123 pa_once(&thread_tls_once, thread_tls_once_func);
124 return pa_tls_get(thread_tls);
125 }
126
127 void pa_thread_yield(void) {
128 Sleep(0);
129 }
130
131 static void monitor_tls_once_func(void) {
132 monitor_tls = pa_tls_new(NULL);
133 assert(monitor_tls);
134 pa_tls_set(monitor_tls, NULL);
135 }
136
137 static DWORD WINAPI monitor_thread_func(LPVOID param) {
138 struct pa_tls_monitor *m = param;
139 assert(m);
140
141 WaitForSingleObject(m->thread, INFINITE);
142
143 CloseHandle(m->thread);
144
145 m->free_func(m->data);
146
147 pa_xfree(m);
148
149 return 0;
150 }
151
152 pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
153 pa_tls *t;
154
155 t = pa_xnew(pa_tls, 1);
156 t->index = TlsAlloc();
157 t->free_func = free_cb;
158
159 if (t->index == TLS_OUT_OF_INDEXES) {
160 pa_xfree(t);
161 return NULL;
162 }
163
164 return t;
165 }
166
167 void pa_tls_free(pa_tls *t) {
168 assert(t);
169
170 TlsFree(t->index);
171 pa_xfree(t);
172 }
173
174 void *pa_tls_get(pa_tls *t) {
175 assert(t);
176
177 return TlsGetValue(t->index);
178 }
179
180 void *pa_tls_set(pa_tls *t, void *userdata) {
181 void *r;
182
183 assert(t);
184
185 r = TlsGetValue(t->index);
186
187 TlsSetValue(t->index, userdata);
188
189 if (t->free_func) {
190 struct pa_tls_monitor *m;
191
192 pa_once(&monitor_tls_once, monitor_tls_once_func);
193
194 m = pa_tls_get(monitor_tls);
195 if (!m) {
196 HANDLE thread;
197
198 m = pa_xnew(struct pa_tls_monitor, 1);
199
200 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
201 GetCurrentProcess(), &m->thread, 0, FALSE,
202 DUPLICATE_SAME_ACCESS);
203
204 m->free_func = t->free_func;
205
206 pa_tls_set(monitor_tls, m);
207
208 thread = CreateThread(NULL, 0, monitor_thread_func, m, 0, NULL);
209 assert(thread);
210 CloseHandle(thread);
211 }
212
213 m->data = userdata;
214 }
215
216 return r;
217 }