daemon: add nice value in service file to improve performance
[platform/upstream/pulseaudio.git] / src / pulsecore / thread-win32.c
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
54 static void thread_tls_once_func(void) {
55     thread_tls = pa_tls_new(NULL);
56     assert(thread_tls);
57 }
58
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
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
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
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
110 void pa_thread_free_nojoin(pa_thread *t) {
111     pa_assert(t);
112
113     CloseHandle(t->thread);
114     pa_xfree(t);
115 }
116
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
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
131 void* pa_thread_get_data(pa_thread *t) {
132     pa_assert(t);
133
134     return t->userdata;
135 }
136
137 void pa_thread_set_data(pa_thread *t, void *userdata) {
138     pa_assert(t);
139
140     t->userdata = userdata;
141 }
142
143 void pa_thread_set_name(pa_thread *t, const char *name) {
144     /* Not implemented */
145 }
146
147 const char *pa_thread_get_name(pa_thread *t) {
148     /* Not implemented */
149     return NULL;
150 }
151
152 void pa_thread_yield(void) {
153     Sleep(0);
154 }
155
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
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
186 void pa_tls_free(pa_tls *t) {
187     assert(t);
188
189     TlsFree(t->index);
190     pa_xfree(t);
191 }
192
193 void *pa_tls_get(pa_tls *t) {
194     assert(t);
195
196     return TlsGetValue(t->index);
197 }
198
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 }