futex.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <sched.h>
  4. #include <linux/unistd.h>
  5. #include <linux/futex.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <sys/syscall.h>
  9. #include <sys/types.h>
  10. #include <sys/wait.h>
  11. #include <time.h>
  12. #include <unistd.h>
  13. #include "log.h"
  14. #include "timens.h"
  15. #define NSEC_PER_SEC 1000000000ULL
  16. static int run_test(int clockid)
  17. {
  18. int futex_op = FUTEX_WAIT_BITSET;
  19. struct timespec timeout, end;
  20. int val = 0;
  21. if (clockid == CLOCK_REALTIME)
  22. futex_op |= FUTEX_CLOCK_REALTIME;
  23. clock_gettime(clockid, &timeout);
  24. timeout.tv_nsec += NSEC_PER_SEC / 10; // 100ms
  25. if (timeout.tv_nsec > NSEC_PER_SEC) {
  26. timeout.tv_sec++;
  27. timeout.tv_nsec -= NSEC_PER_SEC;
  28. }
  29. if (syscall(__NR_futex, &val, futex_op, 0,
  30. &timeout, 0, FUTEX_BITSET_MATCH_ANY) >= 0) {
  31. ksft_test_result_fail("futex didn't return ETIMEDOUT\n");
  32. return 1;
  33. }
  34. if (errno != ETIMEDOUT) {
  35. ksft_test_result_fail("futex didn't return ETIMEDOUT: %s\n",
  36. strerror(errno));
  37. return 1;
  38. }
  39. clock_gettime(clockid, &end);
  40. if (end.tv_sec < timeout.tv_sec ||
  41. (end.tv_sec == timeout.tv_sec && end.tv_nsec < timeout.tv_nsec)) {
  42. ksft_test_result_fail("futex slept less than 100ms\n");
  43. return 1;
  44. }
  45. ksft_test_result_pass("futex with the %d clockid\n", clockid);
  46. return 0;
  47. }
  48. int main(int argc, char *argv[])
  49. {
  50. int status, len, fd;
  51. char buf[4096];
  52. pid_t pid;
  53. struct timespec mtime_now;
  54. nscheck();
  55. ksft_set_plan(2);
  56. clock_gettime(CLOCK_MONOTONIC, &mtime_now);
  57. if (unshare_timens())
  58. return 1;
  59. len = snprintf(buf, sizeof(buf), "%d %d 0",
  60. CLOCK_MONOTONIC, 70 * 24 * 3600);
  61. fd = open("/proc/self/timens_offsets", O_WRONLY);
  62. if (fd < 0)
  63. return pr_perror("/proc/self/timens_offsets");
  64. if (write(fd, buf, len) != len)
  65. return pr_perror("/proc/self/timens_offsets");
  66. close(fd);
  67. pid = fork();
  68. if (pid < 0)
  69. return pr_perror("Unable to fork");
  70. if (pid == 0) {
  71. int ret = 0;
  72. ret |= run_test(CLOCK_REALTIME);
  73. ret |= run_test(CLOCK_MONOTONIC);
  74. if (ret)
  75. ksft_exit_fail();
  76. ksft_exit_pass();
  77. return 0;
  78. }
  79. if (waitpid(pid, &status, 0) != pid)
  80. return pr_perror("Unable to wait the child process");
  81. if (WIFEXITED(status))
  82. return WEXITSTATUS(status);
  83. return 1;
  84. }