| 1 | |
| 2 | |
| 3 | * Copyright Collabora Ltd., 2021
|
| 4 | *
|
| 5 | * futex cmp requeue test by André Almeida <[email protected]>
|
| 6 |
|
| 7 |
|
| 8 | #include <limits.h>
|
| 9 | #include <pthread.h>
|
| 10 | #include <string.h>
|
| 11 |
|
| 12 | #include "futextest.h"
|
| 13 | #include "futex_thread.h"
|
| 14 | #include "kselftest_harness.h"
|
| 15 |
|
| 16 | struct waiter_args {
|
| 17 | struct __test_metadata *_metadata;
|
| 18 | unsigned int n_threads;
|
| 19 | };
|
| 20 |
|
| 21 | volatile futex_t *f1;
|
| 22 |
|
| 23 | static int waiterfn(void *arg)
|
| 24 | {
|
| 25 | struct __test_metadata *_metadata;
|
| 26 | struct waiter_args *wargs = arg;
|
| 27 | struct timespec to = { };
|
| 28 | int res;
|
| 29 |
|
| 30 | _metadata = wargs->_metadata;
|
| 31 | to.tv_sec = (wargs->n_threads + 1) * WAIT_FOR_THREAD_SECS;
|
| 32 |
|
| 33 | res = futex_wait(f1, *f1, &to, 0);
|
| 34 | if (res) {
|
| 35 | EXPECT_EQ(res, 0)
|
| 36 | TH_LOG("waiter failed errno %d: %s", errno, strerror(errno));
|
| 37 | }
|
| 38 |
|
| 39 | return 0;
|
| 40 | }
|
| 41 |
|
| 42 | TEST(requeue_single)
|
| 43 | {
|
| 44 | struct waiter_args wargs = { ._metadata = _metadata, .n_threads = 1 };
|
| 45 | struct futex_thread waiter;
|
| 46 | volatile futex_t _f1 = 0;
|
| 47 | volatile futex_t f2 = 0;
|
| 48 |
|
| 49 | f1 = &_f1;
|
| 50 |
|
| 51 | |
| 52 | * Requeue a waiter from f1 to f2, and wake f2.
|
| 53 |
|
| 54 | ASSERT_EQ(futex_thread_create(&waiter, waiterfn, &wargs), 0)
|
| 55 | TH_LOG("pthread_create failed");
|
| 56 |
|
| 57 | ASSERT_EQ(futex_wait_for_thread(&waiter, _metadata), 0)
|
| 58 | TH_LOG("Wait for thread failed");
|
| 59 |
|
| 60 | EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 0, 1, 0), 1);
|
| 61 | EXPECT_EQ(futex_wake(&f2, 1, 0), 1);
|
| 62 |
|
| 63 | EXPECT_EQ(futex_thread_destroy(&waiter), 0);
|
| 64 | }
|
| 65 |
|
| 66 | TEST(requeue_multiple)
|
| 67 | {
|
| 68 | struct waiter_args wargs = { ._metadata = _metadata, .n_threads = 10 };
|
| 69 | struct futex_thread waiter[10];
|
| 70 | volatile futex_t _f1 = 0;
|
| 71 | volatile futex_t f2 = 0;
|
| 72 |
|
| 73 | f1 = &_f1;
|
| 74 |
|
| 75 | |
| 76 | * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
|
| 77 | * At futex_wake, wake INT_MAX (should be exactly 7).
|
| 78 |
|
| 79 | for (int i = 0; i < 10; i++) {
|
| 80 | ASSERT_EQ(futex_thread_create(&waiter[i], waiterfn, &wargs), 0)
|
| 81 | TH_LOG("pthread_create failed for waiter %d", i);
|
| 82 | }
|
| 83 |
|
| 84 | for (int i = 0; i < 10; i++) {
|
| 85 | ASSERT_EQ(futex_wait_for_thread(&waiter[i], _metadata), 0)
|
| 86 | TH_LOG("Wait for waiter thread %d failed", i);
|
| 87 | }
|
| 88 |
|
| 89 | EXPECT_EQ(futex_cmp_requeue(f1, 0, &f2, 3, 7, 0), 10);
|
| 90 | EXPECT_EQ(futex_wake(&f2, INT_MAX, 0), 7);
|
| 91 |
|
| 92 | for (int i = 0; i < 10; i++)
|
| 93 | EXPECT_EQ(futex_thread_destroy(&waiter[i]), 0);
|
| 94 | }
|
| 95 |
|
| 96 | TEST_HARNESS_MAIN
|