timeout.c 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Timeout API for single-threaded programs that use blocking
  3. * syscalls (read/write/send/recv/connect/accept).
  4. *
  5. * Copyright (C) 2017 Red Hat, Inc.
  6. *
  7. * Author: Stefan Hajnoczi <stefanha@redhat.com>
  8. */
  9. /* Use the following pattern:
  10. *
  11. * timeout_begin(TIMEOUT);
  12. * do {
  13. * ret = accept(...);
  14. * timeout_check("accept");
  15. * } while (ret < 0 && ret == EINTR);
  16. * timeout_end();
  17. */
  18. #include <stdlib.h>
  19. #include <stdbool.h>
  20. #include <unistd.h>
  21. #include <stdio.h>
  22. #include <time.h>
  23. #include "timeout.h"
  24. static volatile bool timeout;
  25. /* SIGALRM handler function. Do not use sleep(2), alarm(2), or
  26. * setitimer(2) while using this API - they may interfere with each
  27. * other.
  28. *
  29. * If you need to sleep, please use timeout_sleep() provided by this API.
  30. */
  31. void sigalrm(int signo)
  32. {
  33. timeout = true;
  34. }
  35. /* Start a timeout. Call timeout_check() to verify that the timeout hasn't
  36. * expired. timeout_end() must be called to stop the timeout. Timeouts cannot
  37. * be nested.
  38. */
  39. void timeout_begin(unsigned int seconds)
  40. {
  41. alarm(seconds);
  42. }
  43. /* Exit with an error message if the timeout has expired */
  44. void timeout_check(const char *operation)
  45. {
  46. if (timeout) {
  47. fprintf(stderr, "%s timed out\n", operation);
  48. exit(EXIT_FAILURE);
  49. }
  50. }
  51. /* Stop a timeout */
  52. void timeout_end(void)
  53. {
  54. alarm(0);
  55. timeout = false;
  56. }
  57. /* Sleep in a timeout section.
  58. *
  59. * nanosleep(2) can be used with this API since POSIX.1 explicitly
  60. * specifies that it does not interact with signals.
  61. */
  62. int timeout_usleep(useconds_t usec)
  63. {
  64. struct timespec ts = {
  65. .tv_sec = usec / 1000000,
  66. .tv_nsec = (usec % 1000000) * 1000,
  67. };
  68. return nanosleep(&ts, NULL);
  69. }