1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright Collabora Ltd., 2021 4 * 5 * futex cmp requeue test by André Almeida <andrealmeid@collabora.com> 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 97