futex_waitv.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * futex_waitv() test by André Almeida <andrealmeid@collabora.com>
  4. *
  5. * Copyright 2021 Collabora Ltd.
  6. */
  7. #include <errno.h>
  8. #include <error.h>
  9. #include <getopt.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <time.h>
  14. #include <pthread.h>
  15. #include <stdint.h>
  16. #include <sys/shm.h>
  17. #include "futextest.h"
  18. #include "futex2test.h"
  19. #include "logging.h"
  20. #define TEST_NAME "futex-wait"
  21. #define WAKE_WAIT_US 10000
  22. #define NR_FUTEXES 30
  23. static struct futex_waitv waitv[NR_FUTEXES];
  24. u_int32_t futexes[NR_FUTEXES] = {0};
  25. void usage(char *prog)
  26. {
  27. printf("Usage: %s\n", prog);
  28. printf(" -c Use color\n");
  29. printf(" -h Display this help message\n");
  30. printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
  31. VQUIET, VCRITICAL, VINFO);
  32. }
  33. void *waiterfn(void *arg)
  34. {
  35. struct timespec to;
  36. int res;
  37. /* setting absolute timeout for futex2 */
  38. if (clock_gettime(CLOCK_MONOTONIC, &to))
  39. error("gettime64 failed\n", errno);
  40. to.tv_sec++;
  41. res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
  42. if (res < 0) {
  43. ksft_test_result_fail("futex_waitv returned: %d %s\n",
  44. errno, strerror(errno));
  45. } else if (res != NR_FUTEXES - 1) {
  46. ksft_test_result_fail("futex_waitv returned: %d, expecting %d\n",
  47. res, NR_FUTEXES - 1);
  48. }
  49. return NULL;
  50. }
  51. int main(int argc, char *argv[])
  52. {
  53. pthread_t waiter;
  54. int res, ret = RET_PASS;
  55. struct timespec to;
  56. int c, i;
  57. while ((c = getopt(argc, argv, "cht:v:")) != -1) {
  58. switch (c) {
  59. case 'c':
  60. log_color(1);
  61. break;
  62. case 'h':
  63. usage(basename(argv[0]));
  64. exit(0);
  65. case 'v':
  66. log_verbosity(atoi(optarg));
  67. break;
  68. default:
  69. usage(basename(argv[0]));
  70. exit(1);
  71. }
  72. }
  73. ksft_print_header();
  74. ksft_set_plan(7);
  75. ksft_print_msg("%s: Test FUTEX_WAITV\n",
  76. basename(argv[0]));
  77. for (i = 0; i < NR_FUTEXES; i++) {
  78. waitv[i].uaddr = (uintptr_t)&futexes[i];
  79. waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG;
  80. waitv[i].val = 0;
  81. waitv[i].__reserved = 0;
  82. }
  83. /* Private waitv */
  84. if (pthread_create(&waiter, NULL, waiterfn, NULL))
  85. error("pthread_create failed\n", errno);
  86. usleep(WAKE_WAIT_US);
  87. res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, FUTEX_PRIVATE_FLAG);
  88. if (res != 1) {
  89. ksft_test_result_fail("futex_wake private returned: %d %s\n",
  90. res ? errno : res,
  91. res ? strerror(errno) : "");
  92. ret = RET_FAIL;
  93. } else {
  94. ksft_test_result_pass("futex_waitv private\n");
  95. }
  96. /* Shared waitv */
  97. for (i = 0; i < NR_FUTEXES; i++) {
  98. int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
  99. if (shm_id < 0) {
  100. perror("shmget");
  101. exit(1);
  102. }
  103. unsigned int *shared_data = shmat(shm_id, NULL, 0);
  104. *shared_data = 0;
  105. waitv[i].uaddr = (uintptr_t)shared_data;
  106. waitv[i].flags = FUTEX_32;
  107. waitv[i].val = 0;
  108. waitv[i].__reserved = 0;
  109. }
  110. if (pthread_create(&waiter, NULL, waiterfn, NULL))
  111. error("pthread_create failed\n", errno);
  112. usleep(WAKE_WAIT_US);
  113. res = futex_wake(u64_to_ptr(waitv[NR_FUTEXES - 1].uaddr), 1, 0);
  114. if (res != 1) {
  115. ksft_test_result_fail("futex_wake shared returned: %d %s\n",
  116. res ? errno : res,
  117. res ? strerror(errno) : "");
  118. ret = RET_FAIL;
  119. } else {
  120. ksft_test_result_pass("futex_waitv shared\n");
  121. }
  122. for (i = 0; i < NR_FUTEXES; i++)
  123. shmdt(u64_to_ptr(waitv[i].uaddr));
  124. /* Testing a waiter without FUTEX_32 flag */
  125. waitv[0].flags = FUTEX_PRIVATE_FLAG;
  126. if (clock_gettime(CLOCK_MONOTONIC, &to))
  127. error("gettime64 failed\n", errno);
  128. to.tv_sec++;
  129. res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
  130. if (res == EINVAL) {
  131. ksft_test_result_fail("futex_waitv private returned: %d %s\n",
  132. res ? errno : res,
  133. res ? strerror(errno) : "");
  134. ret = RET_FAIL;
  135. } else {
  136. ksft_test_result_pass("futex_waitv without FUTEX_32\n");
  137. }
  138. /* Testing a waiter with an unaligned address */
  139. waitv[0].flags = FUTEX_PRIVATE_FLAG | FUTEX_32;
  140. waitv[0].uaddr = 1;
  141. if (clock_gettime(CLOCK_MONOTONIC, &to))
  142. error("gettime64 failed\n", errno);
  143. to.tv_sec++;
  144. res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
  145. if (res == EINVAL) {
  146. ksft_test_result_fail("futex_wake private returned: %d %s\n",
  147. res ? errno : res,
  148. res ? strerror(errno) : "");
  149. ret = RET_FAIL;
  150. } else {
  151. ksft_test_result_pass("futex_waitv with an unaligned address\n");
  152. }
  153. /* Testing a NULL address for waiters.uaddr */
  154. waitv[0].uaddr = 0x00000000;
  155. if (clock_gettime(CLOCK_MONOTONIC, &to))
  156. error("gettime64 failed\n", errno);
  157. to.tv_sec++;
  158. res = futex_waitv(waitv, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
  159. if (res == EINVAL) {
  160. ksft_test_result_fail("futex_waitv private returned: %d %s\n",
  161. res ? errno : res,
  162. res ? strerror(errno) : "");
  163. ret = RET_FAIL;
  164. } else {
  165. ksft_test_result_pass("futex_waitv NULL address in waitv.uaddr\n");
  166. }
  167. /* Testing a NULL address for *waiters */
  168. if (clock_gettime(CLOCK_MONOTONIC, &to))
  169. error("gettime64 failed\n", errno);
  170. to.tv_sec++;
  171. res = futex_waitv(NULL, NR_FUTEXES, 0, &to, CLOCK_MONOTONIC);
  172. if (res == EINVAL) {
  173. ksft_test_result_fail("futex_waitv private returned: %d %s\n",
  174. res ? errno : res,
  175. res ? strerror(errno) : "");
  176. ret = RET_FAIL;
  177. } else {
  178. ksft_test_result_pass("futex_waitv NULL address in *waiters\n");
  179. }
  180. /* Testing an invalid clockid */
  181. if (clock_gettime(CLOCK_MONOTONIC, &to))
  182. error("gettime64 failed\n", errno);
  183. to.tv_sec++;
  184. res = futex_waitv(NULL, NR_FUTEXES, 0, &to, CLOCK_TAI);
  185. if (res == EINVAL) {
  186. ksft_test_result_fail("futex_waitv private returned: %d %s\n",
  187. res ? errno : res,
  188. res ? strerror(errno) : "");
  189. ret = RET_FAIL;
  190. } else {
  191. ksft_test_result_pass("futex_waitv invalid clockid\n");
  192. }
  193. ksft_print_cnts();
  194. return ret;
  195. }