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