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