1/*** 2 This file is part of PulseAudio. 3 4 PulseAudio is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as published 6 by the Free Software Foundation; either version 2.1 of the License, 7 or (at your option) any later version. 8 9 PulseAudio is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public License 15 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 16***/ 17 18#ifdef HAVE_CONFIG_H 19#include <config.h> 20#endif 21 22#include <check.h> 23 24#include <pulse/xmalloc.h> 25#include <pulsecore/thread.h> 26#include <pulsecore/macro.h> 27#include <pulsecore/mutex.h> 28#include <pulsecore/once.h> 29#include <pulsecore/log.h> 30#include <pulsecore/core-util.h> 31 32static pa_mutex *mutex = NULL; 33static pa_cond *cond1 = NULL, *cond2 = NULL; 34static pa_tls *tls = NULL; 35 36static int magic_number = 0; 37 38#define THREADS_MAX 20 39 40static void once_func(void) { 41 pa_log("once!"); 42} 43 44static pa_once once = PA_ONCE_INIT; 45 46static void thread_func(void *data) { 47 pa_tls_set(tls, data); 48 49 pa_log_info("thread_func() for %s starting...", (char*) pa_tls_get(tls)); 50 51 pa_mutex_lock(mutex); 52 53 for (;;) { 54 int k, n; 55 56 pa_log_info("%s waiting ...", (char*) pa_tls_get(tls)); 57 58 for (;;) { 59 60 if (magic_number < 0) 61 goto quit; 62 63 if (magic_number != 0) 64 break; 65 66 pa_cond_wait(cond1, mutex); 67 } 68 69 k = magic_number; 70 magic_number = 0; 71 72 pa_mutex_unlock(mutex); 73 74 pa_run_once(&once, once_func); 75 76 pa_cond_signal(cond2, 0); 77 78 pa_log_info("%s got number %i", (char*) pa_tls_get(tls), k); 79 80 /* Spin! */ 81 for (n = 0; n < k; n++) 82 pa_thread_yield(); 83 84 pa_mutex_lock(mutex); 85 } 86 87quit: 88 89 pa_mutex_unlock(mutex); 90 91 pa_log_info("thread_func() for %s done...", (char*) pa_tls_get(tls)); 92} 93 94START_TEST (thread_test) { 95 int i, k; 96 pa_thread* t[THREADS_MAX]; 97 98 if (!getenv("MAKE_CHECK")) 99 pa_log_set_level(PA_LOG_DEBUG); 100 101 mutex = pa_mutex_new(false, false); 102 cond1 = pa_cond_new(); 103 cond2 = pa_cond_new(); 104 tls = pa_tls_new(pa_xfree); 105 106 for (i = 0; i < THREADS_MAX; i++) { 107 t[i] = pa_thread_new("test", thread_func, pa_sprintf_malloc("Thread #%i", i+1)); 108 fail_unless(t[i] != 0); 109 } 110 111 pa_mutex_lock(mutex); 112 113 pa_log("loop-init"); 114 115 for (k = 0; k < 100; k++) { 116 pa_assert(magic_number == 0); 117 118 /* There's a thread waiting for us to change magic_number to a non-zero 119 * value. The "+ 1" part ensures that we don't accidentally set 120 * magic_number to zero here. */ 121 magic_number = (int) rand() % 0x10000 + 1; 122 123 pa_log_info("iteration %i (%i)", k, magic_number); 124 125 pa_cond_signal(cond1, 0); 126 127 pa_cond_wait(cond2, mutex); 128 } 129 130 pa_log("loop-exit"); 131 132 magic_number = -1; 133 pa_cond_signal(cond1, 1); 134 135 pa_mutex_unlock(mutex); 136 137 for (i = 0; i < THREADS_MAX; i++) 138 pa_thread_free(t[i]); 139 140 pa_mutex_free(mutex); 141 pa_cond_free(cond1); 142 pa_cond_free(cond2); 143 pa_tls_free(tls); 144} 145END_TEST 146 147int main(int argc, char *argv[]) { 148 int failed = 0; 149 Suite *s; 150 TCase *tc; 151 SRunner *sr; 152 153 s = suite_create("Thread"); 154 tc = tcase_create("thread"); 155 tcase_add_test(tc, thread_test); 156 tcase_set_timeout(tc, 60 * 60); 157 suite_add_tcase(s, tc); 158 159 sr = srunner_create(s); 160 srunner_run_all(sr, CK_NORMAL); 161 failed = srunner_ntests_failed(sr); 162 srunner_free(sr); 163 164 return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 165} 166