clock_nanosleep.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /* clock_nanosleep - high-resolution sleep with specifiable clock.
  2. Copyright (C) 2002-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <errno.h>
  16. #include <mach.h>
  17. #include <time.h>
  18. #include <unistd.h>
  19. #include <posix-timer.h>
  20. #include <shlib-compat.h>
  21. #include <sysdep-cancel.h>
  22. static int
  23. nanosleep_call (clockid_t clock_id, const struct timespec *req, struct timespec *rem)
  24. {
  25. mach_port_t recv;
  26. struct timespec before;
  27. error_t err;
  28. const mach_msg_timeout_t ms
  29. = req->tv_sec * 1000
  30. + (req->tv_nsec + 999999) / 1000000;
  31. recv = __mach_reply_port ();
  32. if (rem != NULL)
  33. __clock_gettime (clock_id, &before);
  34. int cancel_oldtype = LIBC_CANCEL_ASYNC();
  35. err = __mach_msg (NULL, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT,
  36. 0, 0, recv, ms, MACH_PORT_NULL);
  37. LIBC_CANCEL_RESET (cancel_oldtype);
  38. __mach_port_destroy (mach_task_self (), recv);
  39. if (err == EMACH_RCV_INTERRUPTED)
  40. {
  41. if (rem != NULL)
  42. {
  43. struct timespec after, elapsed;
  44. __clock_gettime (clock_id, &after);
  45. timespec_sub (&elapsed, &after, &before);
  46. timespec_sub (rem, req, &elapsed);
  47. }
  48. return EINTR;
  49. }
  50. return 0;
  51. }
  52. int
  53. __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
  54. struct timespec *rem)
  55. {
  56. if ((clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC)
  57. || req->tv_sec < 0
  58. || !valid_nanoseconds (req->tv_nsec)
  59. || (flags != 0 && flags != TIMER_ABSTIME))
  60. return EINVAL;
  61. struct timespec now;
  62. /* If we got an absolute time, remap it. */
  63. if (flags == TIMER_ABSTIME)
  64. {
  65. long int nsec;
  66. long int sec;
  67. /* Make sure we use safe data types. */
  68. assert (sizeof (sec) >= sizeof (now.tv_sec));
  69. /* Get the current time for this clock. */
  70. if (__clock_gettime (clock_id, &now) != 0)
  71. return errno;
  72. /* Compute the difference. */
  73. nsec = req->tv_nsec - now.tv_nsec;
  74. sec = req->tv_sec - now.tv_sec - (nsec < 0);
  75. if (sec < 0)
  76. /* The time has already elapsed. */
  77. return 0;
  78. now.tv_sec = sec;
  79. now.tv_nsec = nsec + (nsec < 0 ? 1000000000 : 0);
  80. /* From now on this is our time. */
  81. req = &now;
  82. /* Make sure we are not modifying the struct pointed to by REM. */
  83. rem = NULL;
  84. }
  85. return nanosleep_call (clock_id, req, rem);
  86. }
  87. libc_hidden_def (__clock_nanosleep)
  88. versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17);
  89. /* clock_nanosleep moved to libc in version 2.17;
  90. old binaries may expect the symbol version it had in librt. */
  91. #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
  92. strong_alias (__clock_nanosleep, __clock_nanosleep_2);
  93. compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2);
  94. #endif