153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <stdio.h>
2553a5a1b3Sopenharmony_ci
2653a5a1b3Sopenharmony_ci#include <windows.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2953a5a1b3Sopenharmony_ci#include <pulsecore/once.h>
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#include "thread.h"
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_cistruct pa_thread {
3453a5a1b3Sopenharmony_ci    HANDLE thread;
3553a5a1b3Sopenharmony_ci    pa_thread_func_t thread_func;
3653a5a1b3Sopenharmony_ci    void *userdata;
3753a5a1b3Sopenharmony_ci};
3853a5a1b3Sopenharmony_ci
3953a5a1b3Sopenharmony_cistruct pa_tls {
4053a5a1b3Sopenharmony_ci    DWORD index;
4153a5a1b3Sopenharmony_ci    pa_free_cb_t free_func;
4253a5a1b3Sopenharmony_ci};
4353a5a1b3Sopenharmony_ci
4453a5a1b3Sopenharmony_cistruct pa_tls_monitor {
4553a5a1b3Sopenharmony_ci    HANDLE thread;
4653a5a1b3Sopenharmony_ci    pa_free_cb_t free_func;
4753a5a1b3Sopenharmony_ci    void *data;
4853a5a1b3Sopenharmony_ci};
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_cistatic pa_tls *thread_tls;
5153a5a1b3Sopenharmony_cistatic pa_once thread_tls_once = PA_ONCE_INIT;
5253a5a1b3Sopenharmony_cistatic pa_tls *monitor_tls;
5353a5a1b3Sopenharmony_ci
5453a5a1b3Sopenharmony_cistatic void thread_tls_once_func(void) {
5553a5a1b3Sopenharmony_ci    thread_tls = pa_tls_new(NULL);
5653a5a1b3Sopenharmony_ci    assert(thread_tls);
5753a5a1b3Sopenharmony_ci}
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_cistatic DWORD WINAPI internal_thread_func(LPVOID param) {
6053a5a1b3Sopenharmony_ci    pa_thread *t = param;
6153a5a1b3Sopenharmony_ci    assert(t);
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci    pa_run_once(&thread_tls_once, thread_tls_once_func);
6453a5a1b3Sopenharmony_ci    pa_tls_set(thread_tls, t);
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_ci    t->thread_func(t->userdata);
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ci    return 0;
6953a5a1b3Sopenharmony_ci}
7053a5a1b3Sopenharmony_ci
7153a5a1b3Sopenharmony_cipa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata) {
7253a5a1b3Sopenharmony_ci    pa_thread *t;
7353a5a1b3Sopenharmony_ci    DWORD thread_id;
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci    assert(thread_func);
7653a5a1b3Sopenharmony_ci
7753a5a1b3Sopenharmony_ci    t = pa_xnew(pa_thread, 1);
7853a5a1b3Sopenharmony_ci    t->thread_func = thread_func;
7953a5a1b3Sopenharmony_ci    t->userdata = userdata;
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_ci    t->thread = CreateThread(NULL, 0, internal_thread_func, t, 0, &thread_id);
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_ci    if (!t->thread) {
8453a5a1b3Sopenharmony_ci        pa_xfree(t);
8553a5a1b3Sopenharmony_ci        return NULL;
8653a5a1b3Sopenharmony_ci    }
8753a5a1b3Sopenharmony_ci
8853a5a1b3Sopenharmony_ci    return t;
8953a5a1b3Sopenharmony_ci}
9053a5a1b3Sopenharmony_ci
9153a5a1b3Sopenharmony_ciint pa_thread_is_running(pa_thread *t) {
9253a5a1b3Sopenharmony_ci    DWORD code;
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci    assert(t);
9553a5a1b3Sopenharmony_ci
9653a5a1b3Sopenharmony_ci    if (!GetExitCodeThread(t->thread, &code))
9753a5a1b3Sopenharmony_ci        return 0;
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ci    return code == STILL_ACTIVE;
10053a5a1b3Sopenharmony_ci}
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_civoid pa_thread_free(pa_thread *t) {
10353a5a1b3Sopenharmony_ci    assert(t);
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    pa_thread_join(t);
10653a5a1b3Sopenharmony_ci    CloseHandle(t->thread);
10753a5a1b3Sopenharmony_ci    pa_xfree(t);
10853a5a1b3Sopenharmony_ci}
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_civoid pa_thread_free_nojoin(pa_thread *t) {
11153a5a1b3Sopenharmony_ci    pa_assert(t);
11253a5a1b3Sopenharmony_ci
11353a5a1b3Sopenharmony_ci    CloseHandle(t->thread);
11453a5a1b3Sopenharmony_ci    pa_xfree(t);
11553a5a1b3Sopenharmony_ci}
11653a5a1b3Sopenharmony_ci
11753a5a1b3Sopenharmony_ciint pa_thread_join(pa_thread *t) {
11853a5a1b3Sopenharmony_ci    assert(t);
11953a5a1b3Sopenharmony_ci
12053a5a1b3Sopenharmony_ci    if (WaitForSingleObject(t->thread, INFINITE) == WAIT_FAILED)
12153a5a1b3Sopenharmony_ci        return -1;
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    return 0;
12453a5a1b3Sopenharmony_ci}
12553a5a1b3Sopenharmony_ci
12653a5a1b3Sopenharmony_cipa_thread* pa_thread_self(void) {
12753a5a1b3Sopenharmony_ci    pa_run_once(&thread_tls_once, thread_tls_once_func);
12853a5a1b3Sopenharmony_ci    return pa_tls_get(thread_tls);
12953a5a1b3Sopenharmony_ci}
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_civoid* pa_thread_get_data(pa_thread *t) {
13253a5a1b3Sopenharmony_ci    pa_assert(t);
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci    return t->userdata;
13553a5a1b3Sopenharmony_ci}
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_civoid pa_thread_set_data(pa_thread *t, void *userdata) {
13853a5a1b3Sopenharmony_ci    pa_assert(t);
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci    t->userdata = userdata;
14153a5a1b3Sopenharmony_ci}
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_civoid pa_thread_set_name(pa_thread *t, const char *name) {
14453a5a1b3Sopenharmony_ci    /* Not implemented */
14553a5a1b3Sopenharmony_ci}
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_ciconst char *pa_thread_get_name(pa_thread *t) {
14853a5a1b3Sopenharmony_ci    /* Not implemented */
14953a5a1b3Sopenharmony_ci    return NULL;
15053a5a1b3Sopenharmony_ci}
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_civoid pa_thread_yield(void) {
15353a5a1b3Sopenharmony_ci    Sleep(0);
15453a5a1b3Sopenharmony_ci}
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_cistatic DWORD WINAPI monitor_thread_func(LPVOID param) {
15753a5a1b3Sopenharmony_ci    struct pa_tls_monitor *m = param;
15853a5a1b3Sopenharmony_ci    assert(m);
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci    WaitForSingleObject(m->thread, INFINITE);
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci    CloseHandle(m->thread);
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci    m->free_func(m->data);
16553a5a1b3Sopenharmony_ci
16653a5a1b3Sopenharmony_ci    pa_xfree(m);
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ci    return 0;
16953a5a1b3Sopenharmony_ci}
17053a5a1b3Sopenharmony_ci
17153a5a1b3Sopenharmony_cipa_tls* pa_tls_new(pa_free_cb_t free_cb) {
17253a5a1b3Sopenharmony_ci    pa_tls *t;
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci    t = pa_xnew(pa_tls, 1);
17553a5a1b3Sopenharmony_ci    t->index = TlsAlloc();
17653a5a1b3Sopenharmony_ci    t->free_func = free_cb;
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_ci    if (t->index == TLS_OUT_OF_INDEXES) {
17953a5a1b3Sopenharmony_ci        pa_xfree(t);
18053a5a1b3Sopenharmony_ci        return NULL;
18153a5a1b3Sopenharmony_ci    }
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_ci    return t;
18453a5a1b3Sopenharmony_ci}
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_civoid pa_tls_free(pa_tls *t) {
18753a5a1b3Sopenharmony_ci    assert(t);
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci    TlsFree(t->index);
19053a5a1b3Sopenharmony_ci    pa_xfree(t);
19153a5a1b3Sopenharmony_ci}
19253a5a1b3Sopenharmony_ci
19353a5a1b3Sopenharmony_civoid *pa_tls_get(pa_tls *t) {
19453a5a1b3Sopenharmony_ci    assert(t);
19553a5a1b3Sopenharmony_ci
19653a5a1b3Sopenharmony_ci    return TlsGetValue(t->index);
19753a5a1b3Sopenharmony_ci}
19853a5a1b3Sopenharmony_ci
19953a5a1b3Sopenharmony_civoid *pa_tls_set(pa_tls *t, void *userdata) {
20053a5a1b3Sopenharmony_ci    void *r;
20153a5a1b3Sopenharmony_ci
20253a5a1b3Sopenharmony_ci    assert(t);
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    r = TlsGetValue(t->index);
20553a5a1b3Sopenharmony_ci
20653a5a1b3Sopenharmony_ci    TlsSetValue(t->index, userdata);
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci    if (t->free_func) {
20953a5a1b3Sopenharmony_ci        struct pa_tls_monitor *m;
21053a5a1b3Sopenharmony_ci
21153a5a1b3Sopenharmony_ci        PA_ONCE_BEGIN {
21253a5a1b3Sopenharmony_ci            monitor_tls = pa_tls_new(NULL);
21353a5a1b3Sopenharmony_ci            assert(monitor_tls);
21453a5a1b3Sopenharmony_ci            pa_tls_set(monitor_tls, NULL);
21553a5a1b3Sopenharmony_ci        } PA_ONCE_END;
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_ci        m = pa_tls_get(monitor_tls);
21853a5a1b3Sopenharmony_ci        if (!m) {
21953a5a1b3Sopenharmony_ci            HANDLE thread;
22053a5a1b3Sopenharmony_ci
22153a5a1b3Sopenharmony_ci            m = pa_xnew(struct pa_tls_monitor, 1);
22253a5a1b3Sopenharmony_ci
22353a5a1b3Sopenharmony_ci            DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
22453a5a1b3Sopenharmony_ci                GetCurrentProcess(), &m->thread, 0, FALSE,
22553a5a1b3Sopenharmony_ci                DUPLICATE_SAME_ACCESS);
22653a5a1b3Sopenharmony_ci
22753a5a1b3Sopenharmony_ci            m->free_func = t->free_func;
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci            pa_tls_set(monitor_tls, m);
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci            thread = CreateThread(NULL, 0, monitor_thread_func, m, 0, NULL);
23253a5a1b3Sopenharmony_ci            assert(thread);
23353a5a1b3Sopenharmony_ci            CloseHandle(thread);
23453a5a1b3Sopenharmony_ci        }
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci        m->data = userdata;
23753a5a1b3Sopenharmony_ci    }
23853a5a1b3Sopenharmony_ci
23953a5a1b3Sopenharmony_ci    return r;
24053a5a1b3Sopenharmony_ci}
241