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