153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
553a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
653a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
753a5a1b3Sopenharmony_ci  or (at your option) any later version.
853a5a1b3Sopenharmony_ci
953a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1053a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1153a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1253a5a1b3Sopenharmony_ci  General Public License for more details.
1353a5a1b3Sopenharmony_ci
1453a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1553a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1653a5a1b3Sopenharmony_ci***/
1753a5a1b3Sopenharmony_ci
1853a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
1953a5a1b3Sopenharmony_ci#include <config.h>
2053a5a1b3Sopenharmony_ci#endif
2153a5a1b3Sopenharmony_ci
2253a5a1b3Sopenharmony_ci#include <check.h>
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2553a5a1b3Sopenharmony_ci#include <pulsecore/thread.h>
2653a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
2753a5a1b3Sopenharmony_ci#include <pulsecore/mutex.h>
2853a5a1b3Sopenharmony_ci#include <pulsecore/once.h>
2953a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3053a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_cistatic pa_mutex *mutex = NULL;
3353a5a1b3Sopenharmony_cistatic pa_cond *cond1 = NULL, *cond2 = NULL;
3453a5a1b3Sopenharmony_cistatic pa_tls *tls = NULL;
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_cistatic int magic_number = 0;
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci#define THREADS_MAX 20
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_cistatic void once_func(void) {
4153a5a1b3Sopenharmony_ci    pa_log("once!");
4253a5a1b3Sopenharmony_ci}
4353a5a1b3Sopenharmony_ci
4453a5a1b3Sopenharmony_cistatic pa_once once = PA_ONCE_INIT;
4553a5a1b3Sopenharmony_ci
4653a5a1b3Sopenharmony_cistatic void thread_func(void *data) {
4753a5a1b3Sopenharmony_ci    pa_tls_set(tls, data);
4853a5a1b3Sopenharmony_ci
4953a5a1b3Sopenharmony_ci    pa_log_info("thread_func() for %s starting...", (char*) pa_tls_get(tls));
5053a5a1b3Sopenharmony_ci
5153a5a1b3Sopenharmony_ci    pa_mutex_lock(mutex);
5253a5a1b3Sopenharmony_ci
5353a5a1b3Sopenharmony_ci    for (;;) {
5453a5a1b3Sopenharmony_ci        int k, n;
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_ci        pa_log_info("%s waiting ...", (char*) pa_tls_get(tls));
5753a5a1b3Sopenharmony_ci
5853a5a1b3Sopenharmony_ci        for (;;) {
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci            if (magic_number < 0)
6153a5a1b3Sopenharmony_ci                goto quit;
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci            if (magic_number != 0)
6453a5a1b3Sopenharmony_ci                break;
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_ci            pa_cond_wait(cond1, mutex);
6753a5a1b3Sopenharmony_ci        }
6853a5a1b3Sopenharmony_ci
6953a5a1b3Sopenharmony_ci        k = magic_number;
7053a5a1b3Sopenharmony_ci        magic_number = 0;
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_ci        pa_mutex_unlock(mutex);
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_ci        pa_run_once(&once, once_func);
7553a5a1b3Sopenharmony_ci
7653a5a1b3Sopenharmony_ci        pa_cond_signal(cond2, 0);
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ci        pa_log_info("%s got number %i", (char*) pa_tls_get(tls), k);
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci        /* Spin! */
8153a5a1b3Sopenharmony_ci        for (n = 0; n < k; n++)
8253a5a1b3Sopenharmony_ci            pa_thread_yield();
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci        pa_mutex_lock(mutex);
8553a5a1b3Sopenharmony_ci    }
8653a5a1b3Sopenharmony_ci
8753a5a1b3Sopenharmony_ciquit:
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci    pa_mutex_unlock(mutex);
9053a5a1b3Sopenharmony_ci
9153a5a1b3Sopenharmony_ci    pa_log_info("thread_func() for %s done...", (char*) pa_tls_get(tls));
9253a5a1b3Sopenharmony_ci}
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ciSTART_TEST (thread_test) {
9553a5a1b3Sopenharmony_ci    int i, k;
9653a5a1b3Sopenharmony_ci    pa_thread* t[THREADS_MAX];
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci    if (!getenv("MAKE_CHECK"))
9953a5a1b3Sopenharmony_ci        pa_log_set_level(PA_LOG_DEBUG);
10053a5a1b3Sopenharmony_ci
10153a5a1b3Sopenharmony_ci    mutex = pa_mutex_new(false, false);
10253a5a1b3Sopenharmony_ci    cond1 = pa_cond_new();
10353a5a1b3Sopenharmony_ci    cond2 = pa_cond_new();
10453a5a1b3Sopenharmony_ci    tls = pa_tls_new(pa_xfree);
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci    for (i = 0; i < THREADS_MAX; i++) {
10753a5a1b3Sopenharmony_ci        t[i] = pa_thread_new("test", thread_func, pa_sprintf_malloc("Thread #%i", i+1));
10853a5a1b3Sopenharmony_ci        fail_unless(t[i] != 0);
10953a5a1b3Sopenharmony_ci    }
11053a5a1b3Sopenharmony_ci
11153a5a1b3Sopenharmony_ci    pa_mutex_lock(mutex);
11253a5a1b3Sopenharmony_ci
11353a5a1b3Sopenharmony_ci    pa_log("loop-init");
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci    for (k = 0; k < 100; k++) {
11653a5a1b3Sopenharmony_ci        pa_assert(magic_number == 0);
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci        /* There's a thread waiting for us to change magic_number to a non-zero
11953a5a1b3Sopenharmony_ci         * value. The "+ 1" part ensures that we don't accidentally set
12053a5a1b3Sopenharmony_ci         * magic_number to zero here. */
12153a5a1b3Sopenharmony_ci        magic_number = (int) rand() % 0x10000 + 1;
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci        pa_log_info("iteration %i (%i)", k, magic_number);
12453a5a1b3Sopenharmony_ci
12553a5a1b3Sopenharmony_ci        pa_cond_signal(cond1, 0);
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_ci        pa_cond_wait(cond2, mutex);
12853a5a1b3Sopenharmony_ci    }
12953a5a1b3Sopenharmony_ci
13053a5a1b3Sopenharmony_ci    pa_log("loop-exit");
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_ci    magic_number = -1;
13353a5a1b3Sopenharmony_ci    pa_cond_signal(cond1, 1);
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_ci    pa_mutex_unlock(mutex);
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_ci    for (i = 0; i < THREADS_MAX; i++)
13853a5a1b3Sopenharmony_ci        pa_thread_free(t[i]);
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci    pa_mutex_free(mutex);
14153a5a1b3Sopenharmony_ci    pa_cond_free(cond1);
14253a5a1b3Sopenharmony_ci    pa_cond_free(cond2);
14353a5a1b3Sopenharmony_ci    pa_tls_free(tls);
14453a5a1b3Sopenharmony_ci}
14553a5a1b3Sopenharmony_ciEND_TEST
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_ciint main(int argc, char *argv[]) {
14853a5a1b3Sopenharmony_ci    int failed = 0;
14953a5a1b3Sopenharmony_ci    Suite *s;
15053a5a1b3Sopenharmony_ci    TCase *tc;
15153a5a1b3Sopenharmony_ci    SRunner *sr;
15253a5a1b3Sopenharmony_ci
15353a5a1b3Sopenharmony_ci    s = suite_create("Thread");
15453a5a1b3Sopenharmony_ci    tc = tcase_create("thread");
15553a5a1b3Sopenharmony_ci    tcase_add_test(tc, thread_test);
15653a5a1b3Sopenharmony_ci    tcase_set_timeout(tc, 60 * 60);
15753a5a1b3Sopenharmony_ci    suite_add_tcase(s, tc);
15853a5a1b3Sopenharmony_ci
15953a5a1b3Sopenharmony_ci    sr = srunner_create(s);
16053a5a1b3Sopenharmony_ci    srunner_run_all(sr, CK_NORMAL);
16153a5a1b3Sopenharmony_ci    failed = srunner_ntests_failed(sr);
16253a5a1b3Sopenharmony_ci    srunner_free(sr);
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci    return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
16553a5a1b3Sopenharmony_ci}
166