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 33struct pa_thread { 34 HANDLE thread; 35 pa_thread_func_t thread_func; 36 void *userdata; 37}; 38 39struct pa_tls { 40 DWORD index; 41 pa_free_cb_t free_func; 42}; 43 44struct pa_tls_monitor { 45 HANDLE thread; 46 pa_free_cb_t free_func; 47 void *data; 48}; 49 50static pa_tls *thread_tls; 51static pa_once thread_tls_once = PA_ONCE_INIT; 52static pa_tls *monitor_tls; 53 54static void thread_tls_once_func(void) { 55 thread_tls = pa_tls_new(NULL); 56 assert(thread_tls); 57} 58 59static 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 71pa_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 91int 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 102void 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 110void pa_thread_free_nojoin(pa_thread *t) { 111 pa_assert(t); 112 113 CloseHandle(t->thread); 114 pa_xfree(t); 115} 116 117int 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 126pa_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 131void* pa_thread_get_data(pa_thread *t) { 132 pa_assert(t); 133 134 return t->userdata; 135} 136 137void pa_thread_set_data(pa_thread *t, void *userdata) { 138 pa_assert(t); 139 140 t->userdata = userdata; 141} 142 143void pa_thread_set_name(pa_thread *t, const char *name) { 144 /* Not implemented */ 145} 146 147const char *pa_thread_get_name(pa_thread *t) { 148 /* Not implemented */ 149 return NULL; 150} 151 152void pa_thread_yield(void) { 153 Sleep(0); 154} 155 156static 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 171pa_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 186void pa_tls_free(pa_tls *t) { 187 assert(t); 188 189 TlsFree(t->index); 190 pa_xfree(t); 191} 192 193void *pa_tls_get(pa_tls *t) { 194 assert(t); 195 196 return TlsGetValue(t->index); 197} 198 199void *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