futex_requeue.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. #include <pthread.h>
  8. #include <limits.h>
  9. #include "logging.h"
  10. #include "futextest.h"
  11. #define TEST_NAME "futex-requeue"
  12. #define timeout_ns 30000000
  13. #define WAKE_WAIT_US 10000
  14. volatile futex_t *f1;
  15. void usage(char *prog)
  16. {
  17. printf("Usage: %s\n", prog);
  18. printf(" -c Use color\n");
  19. printf(" -h Display this help message\n");
  20. printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
  21. VQUIET, VCRITICAL, VINFO);
  22. }
  23. void *waiterfn(void *arg)
  24. {
  25. struct timespec to;
  26. to.tv_sec = 0;
  27. to.tv_nsec = timeout_ns;
  28. if (futex_wait(f1, *f1, &to, 0))
  29. printf("waiter failed errno %d\n", errno);
  30. return NULL;
  31. }
  32. int main(int argc, char *argv[])
  33. {
  34. pthread_t waiter[10];
  35. int res, ret = RET_PASS;
  36. int c, i;
  37. volatile futex_t _f1 = 0;
  38. volatile futex_t f2 = 0;
  39. f1 = &_f1;
  40. while ((c = getopt(argc, argv, "cht:v:")) != -1) {
  41. switch (c) {
  42. case 'c':
  43. log_color(1);
  44. break;
  45. case 'h':
  46. usage(basename(argv[0]));
  47. exit(0);
  48. case 'v':
  49. log_verbosity(atoi(optarg));
  50. break;
  51. default:
  52. usage(basename(argv[0]));
  53. exit(1);
  54. }
  55. }
  56. ksft_print_header();
  57. ksft_set_plan(2);
  58. ksft_print_msg("%s: Test futex_requeue\n",
  59. basename(argv[0]));
  60. /*
  61. * Requeue a waiter from f1 to f2, and wake f2.
  62. */
  63. if (pthread_create(&waiter[0], NULL, waiterfn, NULL))
  64. error("pthread_create failed\n", errno);
  65. usleep(WAKE_WAIT_US);
  66. info("Requeuing 1 futex from f1 to f2\n");
  67. res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0);
  68. if (res != 1) {
  69. ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
  70. res ? errno : res,
  71. res ? strerror(errno) : "");
  72. ret = RET_FAIL;
  73. }
  74. info("Waking 1 futex at f2\n");
  75. res = futex_wake(&f2, 1, 0);
  76. if (res != 1) {
  77. ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
  78. res ? errno : res,
  79. res ? strerror(errno) : "");
  80. ret = RET_FAIL;
  81. } else {
  82. ksft_test_result_pass("futex_requeue simple succeeds\n");
  83. }
  84. /*
  85. * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
  86. * At futex_wake, wake INT_MAX (should be exactly 7).
  87. */
  88. for (i = 0; i < 10; i++) {
  89. if (pthread_create(&waiter[i], NULL, waiterfn, NULL))
  90. error("pthread_create failed\n", errno);
  91. }
  92. usleep(WAKE_WAIT_US);
  93. info("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n");
  94. res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0);
  95. if (res != 10) {
  96. ksft_test_result_fail("futex_requeue many returned: %d %s\n",
  97. res ? errno : res,
  98. res ? strerror(errno) : "");
  99. ret = RET_FAIL;
  100. }
  101. info("Waking INT_MAX futexes at f2\n");
  102. res = futex_wake(&f2, INT_MAX, 0);
  103. if (res != 7) {
  104. ksft_test_result_fail("futex_requeue many returned: %d %s\n",
  105. res ? errno : res,
  106. res ? strerror(errno) : "");
  107. ret = RET_FAIL;
  108. } else {
  109. ksft_test_result_pass("futex_requeue many succeeds\n");
  110. }
  111. ksft_print_cnts();
  112. return ret;
  113. }