1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <inttypes.h>
6 #include <limits.h>
7 #include <sched.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <threads.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <unittest/unittest.h>
15 #include <zircon/syscalls.h>
16 #include <zircon/threads.h>
17 #include <zircon/time.h>
18 #include <zircon/types.h>
19 
TestFutexWaitValueMismatch()20 static bool TestFutexWaitValueMismatch() {
21     BEGIN_TEST;
22     int32_t futex_value = 123;
23     zx_status_t rc = zx_futex_wait(&futex_value, futex_value + 1,
24                                          ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
25     ASSERT_EQ(rc, ZX_ERR_BAD_STATE, "Futex wait should have reurned bad state");
26     END_TEST;
27 }
28 
TestFutexWaitTimeout()29 static bool TestFutexWaitTimeout() {
30     BEGIN_TEST;
31     int32_t futex_value = 123;
32     zx_status_t rc = zx_futex_wait(&futex_value, futex_value, ZX_HANDLE_INVALID, 0);
33     ASSERT_EQ(rc, ZX_ERR_TIMED_OUT, "Futex wait should have reurned timeout");
34     END_TEST;
35 }
36 
37 // This test checks that the timeout in futex_wait() is respected
TestFutexWaitTimeoutElapsed()38 static bool TestFutexWaitTimeoutElapsed() {
39     BEGIN_TEST;
40     int32_t futex_value = 0;
41     constexpr zx_duration_t kRelativeDeadline = ZX_MSEC(500);
42     for (int i = 0; i < 5; ++i) {
43         zx_time_t now = zx_clock_get_monotonic();
44         zx_status_t rc = zx_futex_wait(&futex_value, 0, ZX_HANDLE_INVALID,
45                                        zx_deadline_after(kRelativeDeadline));
46         ASSERT_EQ(rc, ZX_ERR_TIMED_OUT, "wait should time out");
47         zx_duration_t elapsed = zx_time_sub_time(zx_clock_get_monotonic(), now);
48         if (elapsed < kRelativeDeadline) {
49             unittest_printf("\nelapsed %" PRIu64
50                             " < kRelativeDeadline: %" PRIu64 "\n",
51                             elapsed, kRelativeDeadline);
52             EXPECT_TRUE(false, "wait returned early");
53         }
54     }
55     END_TEST;
56 }
57 
58 
TestFutexWaitBadAddress()59 static bool TestFutexWaitBadAddress() {
60     BEGIN_TEST;
61     // Check that the wait address is checked for validity.
62     zx_status_t rc = zx_futex_wait(nullptr, 123, ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
63     ASSERT_EQ(rc, ZX_ERR_INVALID_ARGS, "Futex wait should have reurned invalid_arg");
64     END_TEST;
65 }
66 
67 // Poll until the kernel says that the given thread is blocked on a futex.
wait_until_blocked_on_some_futex(zx_handle_t thread)68 static bool wait_until_blocked_on_some_futex(zx_handle_t thread) {
69     for (;;) {
70         zx_info_thread_t info;
71         ASSERT_EQ(zx_object_get_info(thread, ZX_INFO_THREAD, &info,
72                                      sizeof(info), nullptr, nullptr), ZX_OK);
73         if (info.state == ZX_THREAD_STATE_RUNNING) {
74             zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
75             continue;
76         }
77         ASSERT_EQ(info.state, ZX_THREAD_STATE_BLOCKED_FUTEX);
78         return true;
79     }
80 }
81 
82 // This starts a thread which waits on a futex.  We can do futex_wake()
83 // operations and then test whether or not this thread has been woken up.
84 class TestThread {
85 public:
TestThread(volatile int32_t * futex_addr,zx_duration_t timeout_in_us=ZX_TIME_INFINITE)86     TestThread(volatile int32_t* futex_addr,
87                zx_duration_t timeout_in_us = ZX_TIME_INFINITE)
88         : futex_addr_(futex_addr),
89           timeout_in_ns_(timeout_in_us) {
90         auto ret = thrd_create_with_name(&thread_, wakeup_test_thread, this, "wakeup_test_thread");
91         EXPECT_EQ(ret, thrd_success, "Error during thread creation");
92         while (state_ == STATE_STARTED) {
93             sched_yield();
94         }
95         // Note that this could fail if futex_wait() gets a spurious wakeup.
96         EXPECT_EQ(state_, STATE_ABOUT_TO_WAIT, "wrong state");
97 
98         // We should only do this after state_ is STATE_ABOUT_TO_WAIT,
99         // otherwise it could return when the thread has temporarily
100         // blocked on a libc-internal futex.
101         EXPECT_TRUE(wait_until_blocked_on_some_futex(get_thread_handle()));
102 
103         // This could also fail if futex_wait() gets a spurious wakeup.
104         EXPECT_EQ(state_, STATE_ABOUT_TO_WAIT, "wrong state");
105     }
106 
107     TestThread(const TestThread &) = delete;
108     TestThread& operator=(const TestThread &) = delete;
109 
~TestThread()110     ~TestThread() {
111         if (handle_ != ZX_HANDLE_INVALID) {
112             // kill_thread() was used, so the thrd_t is in undefined state.
113             // Use the kernel handle to ensure the thread has died.
114             EXPECT_EQ(zx_object_wait_one(handle_, ZX_THREAD_TERMINATED,
115                                          ZX_TIME_INFINITE, NULL), ZX_OK,
116                       "zx_object_wait_one failed on killed thread");
117             EXPECT_EQ(zx_handle_close(handle_), ZX_OK,
118                       "zx_handle_close failed on killed thread's handle");
119             // The thrd_t and state associated with it is leaked at this point.
120         } else {
121             EXPECT_EQ(thrd_join(thread_, NULL), thrd_success,
122                       "thrd_join failed");
123         }
124     }
125 
assert_thread_woken()126     void assert_thread_woken() {
127         while (state_ == STATE_ABOUT_TO_WAIT) {
128             sched_yield();
129         }
130         EXPECT_EQ(state_, STATE_WAIT_RETURNED, "wrong state");
131     }
132 
assert_thread_not_woken()133     void assert_thread_not_woken() {
134         EXPECT_EQ(state_, STATE_ABOUT_TO_WAIT, "wrong state");
135     }
136 
wait_for_timeout()137     bool wait_for_timeout() {
138         ASSERT_EQ(state_, STATE_ABOUT_TO_WAIT, "wrong state");
139         while (state_ == STATE_ABOUT_TO_WAIT) {
140             struct timespec wait_time = {0, 50 * 1000000 /* nanoseconds */};
141             ASSERT_EQ(nanosleep(&wait_time, NULL), 0, "Error during sleep");
142         }
143         EXPECT_EQ(state_, STATE_WAIT_RETURNED, "wrong state");
144         return true;
145     }
146 
kill_thread()147     void kill_thread() {
148         EXPECT_EQ(handle_, ZX_HANDLE_INVALID, "kill_thread called twice??");
149         EXPECT_EQ(zx_handle_duplicate(thrd_get_zx_handle(thread_),
150                                       ZX_RIGHT_SAME_RIGHTS, &handle_),
151                   ZX_OK, "zx_handle_duplicate failed on thread handle");
152         EXPECT_EQ(zx_task_kill(handle_), ZX_OK, "zx_task_kill() failed");
153     }
154 
get_thread_handle()155     zx_handle_t get_thread_handle() {
156         return thrd_get_zx_handle(thread_);
157     }
158 
159 private:
wakeup_test_thread(void * thread_arg)160     static int wakeup_test_thread(void* thread_arg) {
161         TestThread* thread = reinterpret_cast<TestThread*>(thread_arg);
162         thread->state_ = STATE_ABOUT_TO_WAIT;
163         zx_time_t deadline = thread->timeout_in_ns_ == ZX_TIME_INFINITE ? ZX_TIME_INFINITE :
164                 zx_deadline_after(thread->timeout_in_ns_);
165         zx_status_t rc = zx_futex_wait(const_cast<int32_t*>(thread->futex_addr_),
166                                        *thread->futex_addr_, ZX_HANDLE_INVALID, deadline);
167         if (thread->timeout_in_ns_ == ZX_TIME_INFINITE) {
168             EXPECT_EQ(rc, ZX_OK, "Error while wait");
169         } else {
170             EXPECT_EQ(rc, ZX_ERR_TIMED_OUT, "wait should have timedout");
171         }
172         thread->state_ = STATE_WAIT_RETURNED;
173         return 0;
174     }
175 
176     thrd_t thread_;
177     volatile int32_t* futex_addr_;
178     zx_duration_t timeout_in_ns_;
179     zx_handle_t handle_ = ZX_HANDLE_INVALID;
180     volatile enum {
181         STATE_STARTED = 100,
182         STATE_ABOUT_TO_WAIT = 200,
183         STATE_WAIT_RETURNED = 300,
184     } state_ = STATE_STARTED;
185 };
186 
check_futex_wake(volatile int32_t * futex_addr,int nwake)187 void check_futex_wake(volatile int32_t* futex_addr, int nwake) {
188     zx_status_t rc = zx_futex_wake(const_cast<int32_t*>(futex_addr), nwake);
189     EXPECT_EQ(rc, ZX_OK, "error during futex wait");
190 }
191 
192 // Test that we can wake up a single thread.
TestFutexWakeup()193 bool TestFutexWakeup() {
194     BEGIN_TEST;
195     volatile int32_t futex_value = 1;
196     TestThread thread(&futex_value);
197     check_futex_wake(&futex_value, INT_MAX);
198     thread.assert_thread_woken();
199     END_TEST;
200 }
201 
202 // Test that we can wake up multiple threads, and that futex_wake() heeds
203 // the wakeup limit.
TestFutexWakeupLimit()204 bool TestFutexWakeupLimit() {
205     BEGIN_TEST;
206     volatile int32_t futex_value = 1;
207     TestThread thread1(&futex_value);
208     TestThread thread2(&futex_value);
209     TestThread thread3(&futex_value);
210     TestThread thread4(&futex_value);
211     check_futex_wake(&futex_value, 2);
212     // Test that threads are woken up in the order that they were added to
213     // the wait queue.  This is not necessarily true for the Linux
214     // implementation of futexes, but it is true for Zircon's
215     // implementation.
216     thread1.assert_thread_woken();
217     thread2.assert_thread_woken();
218     thread3.assert_thread_not_woken();
219     thread4.assert_thread_not_woken();
220 
221     // Clean up: Wake the remaining threads so that they can exit.
222     check_futex_wake(&futex_value, INT_MAX);
223     thread3.assert_thread_woken();
224     thread4.assert_thread_woken();
225     END_TEST;
226 }
227 
228 // Check that futex_wait() and futex_wake() heed their address arguments
229 // properly.  A futex_wait() call on one address should not be woken by a
230 // futex_wake() call on another address.
TestFutexWakeupAddress()231 bool TestFutexWakeupAddress() {
232     BEGIN_TEST;
233     volatile int32_t futex_value1 = 1;
234     volatile int32_t futex_value2 = 1;
235     volatile int32_t dummy_addr = 1;
236     TestThread thread1(&futex_value1);
237     TestThread thread2(&futex_value2);
238 
239     check_futex_wake(&dummy_addr, INT_MAX);
240     thread1.assert_thread_not_woken();
241     thread2.assert_thread_not_woken();
242 
243     check_futex_wake(&futex_value1, INT_MAX);
244     thread1.assert_thread_woken();
245     thread2.assert_thread_not_woken();
246 
247     // Clean up: Wake the remaining thread so that it can exit.
248     check_futex_wake(&futex_value2, INT_MAX);
249     thread2.assert_thread_woken();
250     END_TEST;
251 }
252 
253 // Check that when futex_wait() times out, it removes the thread from
254 // the futex wait queue.
TestFutexUnqueuedOnTimeout()255 bool TestFutexUnqueuedOnTimeout() {
256     BEGIN_TEST;
257     volatile int32_t futex_value = 1;
258     zx_status_t rc = zx_futex_wait(const_cast<int32_t*>(&futex_value),
259                                    futex_value, ZX_HANDLE_INVALID, zx_deadline_after(1));
260     ASSERT_EQ(rc, ZX_ERR_TIMED_OUT, "wait should have timedout");
261     TestThread thread(&futex_value);
262     // If the earlier futex_wait() did not remove itself from the wait
263     // queue properly, the following futex_wake() call will attempt to wake
264     // a thread that is no longer waiting, rather than waking the child
265     // thread.
266     check_futex_wake(&futex_value, 1);
267     thread.assert_thread_woken();
268     END_TEST;
269 }
270 
271 // This tests for a specific bug in list handling.
TestFutexUnqueuedOnTimeout_2()272 bool TestFutexUnqueuedOnTimeout_2() {
273     BEGIN_TEST;
274     volatile int32_t futex_value = 10;
275     TestThread thread1(&futex_value);
276     TestThread thread2(&futex_value, ZX_MSEC(200));
277     ASSERT_TRUE(thread2.wait_for_timeout());
278     // With the bug present, thread2 was removed but the futex wait queue's
279     // tail pointer still points to thread2.  When another thread is
280     // enqueued, it gets added to the thread2 node and lost.
281 
282     TestThread thread3(&futex_value);
283     check_futex_wake(&futex_value, 2);
284     thread1.assert_thread_woken();
285     thread3.assert_thread_woken();
286     END_TEST;
287 }
288 
289 // This tests for a specific bug in list handling.
TestFutexUnqueuedOnTimeout_3()290 bool TestFutexUnqueuedOnTimeout_3() {
291     BEGIN_TEST;
292     volatile int32_t futex_value = 10;
293     TestThread thread1(&futex_value, ZX_MSEC(400));
294     TestThread thread2(&futex_value);
295     TestThread thread3(&futex_value);
296     ASSERT_TRUE(thread1.wait_for_timeout());
297     // With the bug present, thread1 was removed but the futex wait queue
298     // is set to the thread2 node, which has an invalid (null) tail
299     // pointer.  When another thread is enqueued, we get a null pointer
300     // dereference or an assertion failure.
301 
302     TestThread thread4(&futex_value);
303     check_futex_wake(&futex_value, 3);
304     thread2.assert_thread_woken();
305     thread3.assert_thread_woken();
306     thread4.assert_thread_woken();
307     END_TEST;
308 }
309 
TestFutexRequeueValueMismatch()310 bool TestFutexRequeueValueMismatch() {
311     BEGIN_TEST;
312     int32_t futex_value1 = 100;
313     int32_t futex_value2 = 200;
314     zx_status_t rc = zx_futex_requeue(&futex_value1, 1, futex_value1 + 1,
315                                             &futex_value2, 1, ZX_HANDLE_INVALID);
316     ASSERT_EQ(rc, ZX_ERR_BAD_STATE, "requeue should have returned bad state");
317     END_TEST;
318 }
319 
TestFutexRequeueSameAddr()320 bool TestFutexRequeueSameAddr() {
321     BEGIN_TEST;
322     int32_t futex_value = 100;
323     zx_status_t rc = zx_futex_requeue(&futex_value, 1, futex_value,
324                                             &futex_value, 1, ZX_HANDLE_INVALID);
325     ASSERT_EQ(rc, ZX_ERR_INVALID_ARGS, "requeue should have returned invalid args");
326     END_TEST;
327 }
328 
329 // Test that futex_requeue() can wake up some threads and requeue others.
TestFutexRequeue()330 bool TestFutexRequeue() {
331     BEGIN_TEST;
332     volatile int32_t futex_value1 = 100;
333     volatile int32_t futex_value2 = 200;
334     TestThread thread1(&futex_value1);
335     TestThread thread2(&futex_value1);
336     TestThread thread3(&futex_value1);
337     TestThread thread4(&futex_value1);
338     TestThread thread5(&futex_value1);
339     TestThread thread6(&futex_value1);
340 
341     zx_status_t rc = zx_futex_requeue(
342         const_cast<int32_t*>(&futex_value1), 3, futex_value1,
343         const_cast<int32_t*>(&futex_value2), 2, ZX_HANDLE_INVALID);
344     ASSERT_EQ(rc, ZX_OK, "Error in requeue");
345     // 3 of the threads should have been woken.
346     thread1.assert_thread_woken();
347     thread2.assert_thread_woken();
348     thread3.assert_thread_woken();
349     thread4.assert_thread_not_woken();
350     thread5.assert_thread_not_woken();
351     thread6.assert_thread_not_woken();
352 
353     // Since 2 of the threads should have been requeued, waking all the
354     // threads on futex_value2 should wake 2 threads.
355     check_futex_wake(&futex_value2, INT_MAX);
356     thread4.assert_thread_woken();
357     thread5.assert_thread_woken();
358     thread6.assert_thread_not_woken();
359 
360     // Clean up: Wake the remaining thread so that it can exit.
361     check_futex_wake(&futex_value1, 1);
362     thread6.assert_thread_woken();
363     END_TEST;
364 }
365 
366 // Test the case where futex_wait() times out after having been moved to a
367 // different queue by futex_requeue().  Check that futex_wait() removes
368 // itself from the correct queue in that case.
TestFutexRequeueUnqueuedOnTimeout()369 bool TestFutexRequeueUnqueuedOnTimeout() {
370     BEGIN_TEST;
371     zx_duration_t timeout_in_ns = ZX_MSEC(300);
372     volatile int32_t futex_value1 = 100;
373     volatile int32_t futex_value2 = 200;
374     TestThread thread1(&futex_value1, timeout_in_ns);
375     zx_status_t rc = zx_futex_requeue(
376         const_cast<int32_t*>(&futex_value1), 0, futex_value1,
377         const_cast<int32_t*>(&futex_value2), INT_MAX, ZX_HANDLE_INVALID);
378     ASSERT_EQ(rc, ZX_OK, "Error in requeue");
379     TestThread thread2(&futex_value2);
380     // thread1 and thread2 should now both be waiting on futex_value2.
381 
382     ASSERT_TRUE(thread1.wait_for_timeout());
383     thread2.assert_thread_not_woken();
384     // thread1 should have removed itself from futex_value2's wait queue,
385     // so only thread2 should be waiting on futex_value2.  We can test that
386     // by doing futex_wake() with count=1.
387 
388     check_futex_wake(&futex_value2, 1);
389     thread2.assert_thread_woken();
390     END_TEST;
391 }
392 
393 // Test that we can successfully kill a thread that is waiting on a futex,
394 // and that we can join the thread afterwards.  This checks that waiting on
395 // a futex does not leave the thread in an unkillable state.
TestFutexThreadKilled()396 bool TestFutexThreadKilled() {
397     BEGIN_TEST;
398     volatile int32_t futex_value = 1;
399     // Note: TestThread will ensure the kernel thread died, though
400     // it's not possible to thrd_join after killing the thread.
401     TestThread thread(&futex_value);
402     thread.kill_thread();
403 
404     // Check that the futex_wait() syscall does not return control to
405     // userland before the thread gets killed.
406     struct timespec wait_time = {0, 10 * 1000000 /* nanoseconds */};
407     ASSERT_EQ(nanosleep(&wait_time, NULL), 0, "Error during sleep");
408     thread.assert_thread_not_woken();
409 
410     END_TEST;
411 }
412 
413 // Test that the futex_wait() syscall is restarted properly if the thread
414 // calling it gets suspended and resumed.  (This tests for a bug where the
415 // futex_wait() syscall would return ZX_ERR_TIMED_OUT and not get restarted by
416 // the syscall wrapper in the VDSO.)
TestFutexThreadSuspended()417 static bool TestFutexThreadSuspended() {
418     BEGIN_TEST;
419     volatile int32_t futex_value = 1;
420     TestThread thread(&futex_value);
421 
422     zx_handle_t suspend_token = ZX_HANDLE_INVALID;
423     ASSERT_EQ(zx_task_suspend_token(thread.get_thread_handle(),
424                                     &suspend_token), ZX_OK);
425     // Wait some time for the thread suspension to take effect.
426     struct timespec wait_time = {0, 10 * 1000000 /* nanoseconds */};
427     ASSERT_EQ(nanosleep(&wait_time, NULL), 0, "Error during sleep");
428 
429     ASSERT_EQ(zx_handle_close(suspend_token), ZX_OK);
430     // Wait some time for the thread to resume and execute.
431     ASSERT_EQ(nanosleep(&wait_time, NULL), 0, "Error during sleep");
432 
433     thread.assert_thread_not_woken();
434     check_futex_wake(&futex_value, 1);
435     thread.assert_thread_woken();
436 
437     END_TEST;
438 }
439 
440 // Test that misaligned pointers cause futex syscalls to return a failure.
TestFutexMisaligned()441 static bool TestFutexMisaligned() {
442     BEGIN_TEST;
443 
444     // Make sure the whole thing is aligned, so the 'futex' member will
445     // definitely be misaligned.
446     alignas(zx_futex_t) struct {
447         uint8_t misalign;
448         zx_futex_t futex[2];
449     } __attribute__((packed)) buffer;
450     zx_futex_t* const futex = &buffer.futex[0];
451     zx_futex_t* const futex_2 = &buffer.futex[1];
452     ASSERT_GT(alignof(zx_futex_t), 1);
453     ASSERT_NE((uintptr_t)futex % alignof(zx_futex_t), 0);
454     ASSERT_NE((uintptr_t)futex_2 % alignof(zx_futex_t), 0);
455 
456     // zx_futex_requeue might check the waited-for value before it
457     // checks the second futex's alignment, so make sure the call is
458     // valid other than the alignment.  (Also don't ask anybody to
459     // look at uninitialized stack space!)
460     memset(&buffer, 0, sizeof(buffer));
461 
462     ASSERT_EQ(zx_futex_wait(futex, 0, ZX_HANDLE_INVALID, ZX_TIME_INFINITE), ZX_ERR_INVALID_ARGS);
463     ASSERT_EQ(zx_futex_wake(futex, 1), ZX_ERR_INVALID_ARGS);
464     ASSERT_EQ(zx_futex_requeue(futex, 1, 0, futex_2, 1, ZX_HANDLE_INVALID), ZX_ERR_INVALID_ARGS);
465 
466     END_TEST;
467 }
468 
log(const char * str)469 static void log(const char* str) {
470     zx_time_t now = zx_clock_get_monotonic();
471     unittest_printf("[%08" PRIu64 ".%08" PRIu64 "]: %s",
472                     now / 1000000000, now % 1000000000, str);
473 }
474 
475 class Event {
476 public:
Event()477     Event()
478         : signaled_(0) {}
479 
wait()480     void wait() {
481         if (signaled_ == 0) {
482             zx_futex_wait(&signaled_, signaled_, ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
483         }
484     }
485 
signal()486     void signal() {
487         if (signaled_ == 0) {
488             signaled_ = 1;
489             zx_futex_wake(&signaled_, UINT32_MAX);
490         }
491     }
492 
493 private:
494     int32_t signaled_;
495 };
496 
497 static Event event;
498 
signal_thread1(void * arg)499 static int signal_thread1(void* arg) {
500     log("thread 1 waiting on event\n");
501     event.wait();
502     log("thread 1 done\n");
503     return 0;
504 }
505 
signal_thread2(void * arg)506 static int signal_thread2(void* arg) {
507     log("thread 2 waiting on event\n");
508     event.wait();
509     log("thread 2 done\n");
510     return 0;
511 }
512 
signal_thread3(void * arg)513 static int signal_thread3(void* arg) {
514     log("thread 3 waiting on event\n");
515     event.wait();
516     log("thread 3 done\n");
517     return 0;
518 }
519 
TestEventSignaling()520 static bool TestEventSignaling() {
521     BEGIN_TEST;
522     thrd_t thread1, thread2, thread3;
523 
524     log("starting signal threads\n");
525     thrd_create_with_name(&thread1, signal_thread1, NULL, "thread 1");
526     thrd_create_with_name(&thread2, signal_thread2, NULL, "thread 2");
527     thrd_create_with_name(&thread3, signal_thread3, NULL, "thread 3");
528 
529     zx_nanosleep(zx_deadline_after(ZX_MSEC(300)));
530     log("signaling event\n");
531     event.signal();
532 
533     log("joining signal threads\n");
534     thrd_join(thread1, NULL);
535     log("signal_thread 1 joined\n");
536     thrd_join(thread2, NULL);
537     log("signal_thread 2 joined\n");
538     thrd_join(thread3, NULL);
539     log("signal_thread 3 joined\n");
540     END_TEST;
541 }
542 
543 BEGIN_TEST_CASE(futex_tests)
544 RUN_TEST(TestFutexWaitValueMismatch);
545 RUN_TEST(TestFutexWaitTimeout);
546 RUN_TEST(TestFutexWaitTimeoutElapsed);
547 RUN_TEST(TestFutexWaitBadAddress);
548 RUN_TEST(TestFutexWakeup);
549 RUN_TEST(TestFutexWakeupLimit);
550 RUN_TEST(TestFutexWakeupAddress);
551 RUN_TEST(TestFutexUnqueuedOnTimeout);
552 RUN_TEST(TestFutexUnqueuedOnTimeout_2);
553 RUN_TEST(TestFutexUnqueuedOnTimeout_3);
554 RUN_TEST(TestFutexRequeueValueMismatch);
555 RUN_TEST(TestFutexRequeueSameAddr);
556 RUN_TEST(TestFutexRequeue);
557 RUN_TEST(TestFutexRequeueUnqueuedOnTimeout);
558 RUN_TEST(TestFutexThreadKilled);
559 RUN_TEST(TestFutexThreadSuspended);
560 RUN_TEST(TestFutexMisaligned);
561 RUN_TEST(TestEventSignaling);
END_TEST_CASE(futex_tests)562 END_TEST_CASE(futex_tests)
563 
564 #ifndef BUILD_COMBINED_TESTS
565 int main(int argc, char** argv) {
566     bool success = unittest_run_all_tests(argc, argv);
567     return success ? 0 : -1;
568 }
569 #endif
570