1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <gtest/gtest.h>
30 
31 #if __has_include(<threads.h>)
32 
33 #define HAVE_THREADS_H
34 #include <threads.h>
35 
36 static int g_call_once_call_count;
37 
increment_call_count()38 static void increment_call_count() {
39   ++g_call_once_call_count;
40 }
41 
42 static int g_dtor_call_count;
43 
tss_dtor(void * ptr)44 static void tss_dtor(void* ptr) {
45   ++g_dtor_call_count;
46   free(ptr);
47 }
48 
return_arg(void * arg)49 static int return_arg(void* arg) {
50   return static_cast<int>(reinterpret_cast<uintptr_t>(arg));
51 }
52 
exit_arg(void * arg)53 static int exit_arg(void* arg) {
54   thrd_exit(static_cast<int>(reinterpret_cast<uintptr_t>(arg)));
55 }
56 
57 #endif
58 
59 #include <time.h>
60 
61 #include <thread>
62 
63 #include <android-base/silent_death_test.h>
64 
65 #include "SignalUtils.h"
66 
TEST(threads,call_once)67 TEST(threads, call_once) {
68 #if !defined(HAVE_THREADS_H)
69   GTEST_SKIP() << "<threads.h> unavailable";
70 #else
71   once_flag flag = ONCE_FLAG_INIT;
72   call_once(&flag, increment_call_count);
73   call_once(&flag, increment_call_count);
74   std::thread([&flag] {
75     call_once(&flag, increment_call_count);
76   }).join();
77   ASSERT_EQ(1, g_call_once_call_count);
78 #endif
79 }
80 
TEST(threads,cnd_broadcast__cnd_wait)81 TEST(threads, cnd_broadcast__cnd_wait) {
82 #if !defined(HAVE_THREADS_H)
83   GTEST_SKIP() << "<threads.h> unavailable";
84 #else
85   mtx_t m;
86   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain));
87 
88   cnd_t c;
89   ASSERT_EQ(thrd_success, cnd_init(&c));
90 
91   std::atomic_int i = 0;
92 
93   auto waiter = [&c, &i, &m] {
94     ASSERT_EQ(thrd_success, mtx_lock(&m));
95     while (i != 1) ASSERT_EQ(thrd_success, cnd_wait(&c, &m));
96     ASSERT_EQ(thrd_success, mtx_unlock(&m));
97   };
98   std::thread t1(waiter);
99   std::thread t2(waiter);
100   std::thread t3(waiter);
101 
102   ASSERT_EQ(thrd_success, mtx_lock(&m));
103   i = 1;
104   ASSERT_EQ(thrd_success, mtx_unlock(&m));
105 
106   ASSERT_EQ(thrd_success, cnd_broadcast(&c));
107 
108   t1.join();
109   t2.join();
110   t3.join();
111 
112   mtx_destroy(&m);
113   cnd_destroy(&c);
114 #endif
115 }
116 
TEST(threads,cnd_init__cnd_destroy)117 TEST(threads, cnd_init__cnd_destroy) {
118 #if !defined(HAVE_THREADS_H)
119   GTEST_SKIP() << "<threads.h> unavailable";
120 #else
121   cnd_t c;
122   ASSERT_EQ(thrd_success, cnd_init(&c));
123   cnd_destroy(&c);
124 #endif
125 }
126 
TEST(threads,cnd_signal__cnd_wait)127 TEST(threads, cnd_signal__cnd_wait) {
128 #if !defined(HAVE_THREADS_H)
129   GTEST_SKIP() << "<threads.h> unavailable";
130 #else
131   mtx_t m;
132   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain));
133   cnd_t c;
134   ASSERT_EQ(thrd_success, cnd_init(&c));
135 
136   std::atomic_int count = 0;
137   auto waiter = [&c, &m, &count] {
138     ASSERT_EQ(thrd_success, mtx_lock(&m));
139     ASSERT_EQ(thrd_success, cnd_wait(&c, &m));
140     ASSERT_EQ(thrd_success, mtx_unlock(&m));
141     ++count;
142   };
143   std::thread t1(waiter);
144   std::thread t2(waiter);
145   std::thread t3(waiter);
146 
147   // This is inherently racy, but attempts to distinguish between cnd_signal and
148   // cnd_broadcast.
149   usleep(100000);
150   ASSERT_EQ(thrd_success, cnd_signal(&c));
151   while (count == 0) {
152   }
153   usleep(100000);
154   ASSERT_EQ(1, count);
155 
156   ASSERT_EQ(thrd_success, cnd_signal(&c));
157   while (count == 1) {
158   }
159   usleep(100000);
160   ASSERT_EQ(2, count);
161 
162   ASSERT_EQ(thrd_success, cnd_signal(&c));
163   while (count == 2) {
164   }
165   usleep(100000);
166   ASSERT_EQ(3, count);
167 
168   t1.join();
169   t2.join();
170   t3.join();
171 
172   mtx_destroy(&m);
173   cnd_destroy(&c);
174 #endif
175 }
176 
TEST(threads,cnd_timedwait_timedout)177 TEST(threads, cnd_timedwait_timedout) {
178 #if !defined(HAVE_THREADS_H)
179   GTEST_SKIP() << "<threads.h> unavailable";
180 #else
181   mtx_t m;
182   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_timed));
183   ASSERT_EQ(thrd_success, mtx_lock(&m));
184 
185   cnd_t c;
186   ASSERT_EQ(thrd_success, cnd_init(&c));
187 
188   timespec ts = {};
189   ASSERT_EQ(thrd_timedout, cnd_timedwait(&c, &m, &ts));
190 #endif
191 }
192 
TEST(threads,cnd_timedwait)193 TEST(threads, cnd_timedwait) {
194 #if !defined(HAVE_THREADS_H)
195   GTEST_SKIP() << "<threads.h> unavailable";
196 #else
197   mtx_t m;
198   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_timed));
199 
200   cnd_t c;
201   ASSERT_EQ(thrd_success, cnd_init(&c));
202 
203   std::atomic_bool done = false;
204   std::thread t([&c, &m, &done] {
205     ASSERT_EQ(thrd_success, mtx_lock(&m));
206 
207     // cnd_timewait's time is *absolute*.
208     timespec ts;
209     ASSERT_EQ(TIME_UTC, timespec_get(&ts, TIME_UTC));
210     ts.tv_sec += 666;
211 
212     ASSERT_EQ(thrd_success, cnd_timedwait(&c, &m, &ts));
213     done = true;
214     ASSERT_EQ(thrd_success, mtx_unlock(&m));
215   });
216 
217   while (!done) ASSERT_EQ(thrd_success, cnd_signal(&c));
218 
219   t.join();
220 #endif
221 }
222 
TEST(threads,mtx_init)223 TEST(threads, mtx_init) {
224 #if !defined(HAVE_THREADS_H)
225   GTEST_SKIP() << "<threads.h> unavailable";
226 #else
227   mtx_t m;
228   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain));
229   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_timed));
230   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain | mtx_recursive));
231   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_timed | mtx_recursive));
232   ASSERT_EQ(thrd_error, mtx_init(&m, 123));
233   ASSERT_EQ(thrd_error, mtx_init(&m, mtx_recursive));
234 #endif
235 }
236 
TEST(threads,mtx_destroy)237 TEST(threads, mtx_destroy) {
238 #if !defined(HAVE_THREADS_H)
239   GTEST_SKIP() << "<threads.h> unavailable";
240 #else
241   mtx_t m;
242   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain));
243   mtx_destroy(&m);
244 #endif
245 }
246 
TEST(threads,mtx_lock_plain)247 TEST(threads, mtx_lock_plain) {
248 #if !defined(HAVE_THREADS_H)
249   GTEST_SKIP() << "<threads.h> unavailable";
250 #else
251   mtx_t m;
252   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain));
253 
254   ASSERT_EQ(thrd_success, mtx_lock(&m));
255   ASSERT_EQ(thrd_busy, mtx_trylock(&m));
256   ASSERT_EQ(thrd_success, mtx_unlock(&m));
257 
258   mtx_destroy(&m);
259 #endif
260 }
261 
TEST(threads,mtx_lock_recursive)262 TEST(threads, mtx_lock_recursive) {
263 #if !defined(HAVE_THREADS_H)
264   GTEST_SKIP() << "<threads.h> unavailable";
265 #else
266   mtx_t m;
267   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain | mtx_recursive));
268 
269   ASSERT_EQ(thrd_success, mtx_lock(&m));
270   ASSERT_EQ(thrd_success, mtx_trylock(&m));
271   ASSERT_EQ(thrd_success, mtx_unlock(&m));
272   ASSERT_EQ(thrd_success, mtx_unlock(&m));
273 
274   mtx_destroy(&m);
275 #endif
276 }
277 
TEST(threads,mtx_timedlock)278 TEST(threads, mtx_timedlock) {
279 #if !defined(HAVE_THREADS_H)
280   GTEST_SKIP() << "<threads.h> unavailable";
281 #else
282   mtx_t m;
283   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_timed));
284 
285   timespec ts = {};
286   ASSERT_EQ(thrd_success, mtx_timedlock(&m, &ts));
287 
288   std::thread([&m] {
289     timespec ts = { .tv_nsec = 500000 };
290     ASSERT_EQ(thrd_timedout, mtx_timedlock(&m, &ts));
291   }).join();
292 
293   ASSERT_EQ(thrd_success, mtx_unlock(&m));
294   mtx_destroy(&m);
295 #endif
296 }
297 
298 
TEST(threads,mtx_unlock)299 TEST(threads, mtx_unlock) {
300 #if !defined(HAVE_THREADS_H)
301   GTEST_SKIP() << "<threads.h> unavailable";
302 #else
303   mtx_t m;
304   ASSERT_EQ(thrd_success, mtx_init(&m, mtx_plain));
305   ASSERT_EQ(thrd_success, mtx_lock(&m));
306   std::thread([&m] {
307     ASSERT_EQ(thrd_busy, mtx_trylock(&m));
308   }).join();
309   ASSERT_EQ(thrd_success, mtx_unlock(&m));
310   std::thread([&m] {
311     ASSERT_EQ(thrd_success, mtx_trylock(&m));
312   }).join();
313 #endif
314 }
315 
TEST(threads,thrd_current__thrd_equal)316 TEST(threads, thrd_current__thrd_equal) {
317 #if !defined(HAVE_THREADS_H)
318   GTEST_SKIP() << "<threads.h> unavailable";
319 #else
320   thrd_t t1 = thrd_current();
321   // (As a side-effect, this demonstrates interoperability with std::thread.)
322   std::thread([&t1] {
323     thrd_t t2 = thrd_current();
324     ASSERT_FALSE(thrd_equal(t1, t2));
325     thrd_t t2_2 = thrd_current();
326     ASSERT_TRUE(thrd_equal(t2, t2_2));
327   }).join();
328   thrd_t t1_2 = thrd_current();
329   ASSERT_TRUE(thrd_equal(t1, t1_2));
330 #endif
331 }
332 
TEST(threads,thrd_create__thrd_detach)333 TEST(threads, thrd_create__thrd_detach) {
334 #if !defined(HAVE_THREADS_H)
335   GTEST_SKIP() << "<threads.h> unavailable";
336 #else
337   thrd_t t;
338   ASSERT_EQ(thrd_success, thrd_create(&t, exit_arg, reinterpret_cast<void*>(1)));
339   ASSERT_EQ(thrd_success, thrd_detach(t));
340 #endif
341 }
342 
TEST(threads,thrd_create__thrd_exit)343 TEST(threads, thrd_create__thrd_exit) {
344 #if !defined(HAVE_THREADS_H)
345   GTEST_SKIP() << "<threads.h> unavailable";
346 #else
347   // Similar to the thrd_join test, but with a function that calls thrd_exit
348   // instead.
349   thrd_t t;
350   int result;
351   ASSERT_EQ(thrd_success, thrd_create(&t, exit_arg, reinterpret_cast<void*>(1)));
352   ASSERT_EQ(thrd_success, thrd_join(t, &result));
353   ASSERT_EQ(1, result);
354 
355   ASSERT_EQ(thrd_success, thrd_create(&t, exit_arg, reinterpret_cast<void*>(2)));
356   ASSERT_EQ(thrd_success, thrd_join(t, &result));
357   ASSERT_EQ(2, result);
358 
359   // The `result` argument can be null if you don't care...
360   ASSERT_EQ(thrd_success, thrd_create(&t, exit_arg, reinterpret_cast<void*>(3)));
361   ASSERT_EQ(thrd_success, thrd_join(t, nullptr));
362 #endif
363 }
364 
365 using threads_DeathTest = SilentDeathTest;
366 
TEST(threads_DeathTest,thrd_exit_main_thread)367 TEST(threads_DeathTest, thrd_exit_main_thread) {
368 #if !defined(HAVE_THREADS_H)
369   GTEST_SKIP() << "<threads.h> unavailable";
370 #else
371   // "The program terminates normally after the last thread has been terminated.
372   // The behavior is as if the program called the exit function with the status
373   // EXIT_SUCCESS at thread termination time." (ISO/IEC 9899:2018)
374   ASSERT_EXIT(thrd_exit(12), ::testing::ExitedWithCode(EXIT_SUCCESS), "");
375 #endif
376 }
377 
TEST(threads,thrd_create__thrd_join)378 TEST(threads, thrd_create__thrd_join) {
379 #if !defined(HAVE_THREADS_H)
380   GTEST_SKIP() << "<threads.h> unavailable";
381 #else
382   // Similar to the thrd_exit test, but with a function that calls return
383   // instead.
384   thrd_t t;
385   int result;
386   ASSERT_EQ(thrd_success, thrd_create(&t, return_arg, reinterpret_cast<void*>(1)));
387   ASSERT_EQ(thrd_success, thrd_join(t, &result));
388   ASSERT_EQ(1, result);
389 
390   ASSERT_EQ(thrd_success, thrd_create(&t, return_arg, reinterpret_cast<void*>(2)));
391   ASSERT_EQ(thrd_success, thrd_join(t, &result));
392   ASSERT_EQ(2, result);
393 
394   // The `result` argument can be null if you don't care...
395   ASSERT_EQ(thrd_success, thrd_create(&t, return_arg, reinterpret_cast<void*>(3)));
396   ASSERT_EQ(thrd_success, thrd_join(t, nullptr));
397 #endif
398 }
399 
TEST(threads,thrd_sleep_signal)400 TEST(threads, thrd_sleep_signal) {
401 #if !defined(HAVE_THREADS_H)
402   GTEST_SKIP() << "<threads.h> unavailable";
403 #else
404   ScopedSignalHandler ssh{SIGALRM, [](int) {}};
405   std::thread t([] {
406     timespec long_time = { .tv_sec = 666 };
407     timespec remaining = {};
408     ASSERT_EQ(-1, thrd_sleep(&long_time, &remaining));
409     uint64_t t = remaining.tv_sec * 1000000000 + remaining.tv_nsec;
410     ASSERT_LE(t, 666ULL * 1000000000);
411   });
412   usleep(100000); // 0.1s
413   pthread_kill(t.native_handle(), SIGALRM);
414   t.join();
415 #endif
416 }
417 
TEST(threads,thrd_sleep_signal_nullptr)418 TEST(threads, thrd_sleep_signal_nullptr) {
419 #if !defined(HAVE_THREADS_H)
420   GTEST_SKIP() << "<threads.h> unavailable";
421 #else
422   ScopedSignalHandler ssh{SIGALRM, [](int) {}};
423   std::thread t([] {
424     timespec long_time = { .tv_sec = 666 };
425     ASSERT_EQ(-1, thrd_sleep(&long_time, nullptr));
426   });
427   usleep(100000); // 0.1s
428   pthread_kill(t.native_handle(), SIGALRM);
429   t.join();
430 #endif
431 }
432 
TEST(threads,thrd_sleep_error)433 TEST(threads, thrd_sleep_error) {
434 #if !defined(HAVE_THREADS_H)
435   GTEST_SKIP() << "<threads.h> unavailable";
436 #else
437   timespec invalid = { .tv_sec = -1 };
438   ASSERT_EQ(-2, thrd_sleep(&invalid, nullptr));
439 #endif
440 }
441 
TEST(threads,thrd_yield)442 TEST(threads, thrd_yield) {
443 #if !defined(HAVE_THREADS_H)
444   GTEST_SKIP() << "<threads.h> unavailable";
445 #else
446   thrd_yield();
447 #endif
448 }
449 
TEST(threads,TSS_DTOR_ITERATIONS_macro)450 TEST(threads, TSS_DTOR_ITERATIONS_macro) {
451 #if !defined(HAVE_THREADS_H)
452   GTEST_SKIP() << "<threads.h> unavailable";
453 #else
454   ASSERT_EQ(PTHREAD_DESTRUCTOR_ITERATIONS, TSS_DTOR_ITERATIONS);
455 #endif
456 }
457 
TEST(threads,tss_create)458 TEST(threads, tss_create) {
459 #if !defined(HAVE_THREADS_H)
460   GTEST_SKIP() << "<threads.h> unavailable";
461 #else
462   tss_t key;
463   ASSERT_EQ(thrd_success, tss_create(&key, nullptr));
464   tss_delete(key);
465 #endif
466 }
467 
TEST(threads,tss_create_dtor)468 TEST(threads, tss_create_dtor) {
469 #if !defined(HAVE_THREADS_H)
470   GTEST_SKIP() << "<threads.h> unavailable";
471 #else
472   tss_dtor_t dtor = tss_dtor;
473   tss_t key;
474   ASSERT_EQ(thrd_success, tss_create(&key, dtor));
475 
476   ASSERT_EQ(thrd_success, tss_set(key, strdup("hello")));
477   std::thread([&key] {
478     ASSERT_EQ(thrd_success, tss_set(key, strdup("world")));
479   }).join();
480   // Thread exit calls the destructor...
481   ASSERT_EQ(1, g_dtor_call_count);
482 
483   // "[A call to tss_set] will not invoke the destructor associated with the
484   // key on the value being replaced" (ISO/IEC 9899:2018).
485   g_dtor_call_count = 0;
486   ASSERT_EQ(thrd_success, tss_set(key, strdup("hello")));
487   ASSERT_EQ(0, g_dtor_call_count);
488 
489   // "Calling tss_delete will not result in the invocation of any
490   // destructors" (ISO/IEC 9899:2018).
491   // The destructor for "hello" won't be called until *this* thread exits.
492   g_dtor_call_count = 0;
493   tss_delete(key);
494   ASSERT_EQ(0, g_dtor_call_count);
495 #endif
496 }
497 
TEST(threads,tss_get__tss_set)498 TEST(threads, tss_get__tss_set) {
499 #if !defined(HAVE_THREADS_H)
500   GTEST_SKIP() << "<threads.h> unavailable";
501 #else
502   tss_t key;
503   ASSERT_EQ(thrd_success, tss_create(&key, nullptr));
504 
505   ASSERT_EQ(thrd_success, tss_set(key, const_cast<char*>("hello")));
506   ASSERT_STREQ("hello", reinterpret_cast<char*>(tss_get(key)));
507   std::thread([&key] {
508       ASSERT_EQ(nullptr, tss_get(key));
509       ASSERT_EQ(thrd_success, tss_set(key, const_cast<char*>("world")));
510       ASSERT_STREQ("world", reinterpret_cast<char*>(tss_get(key)));
511   }).join();
512   ASSERT_STREQ("hello", reinterpret_cast<char*>(tss_get(key)));
513 
514   tss_delete(key);
515 #endif
516 }
517