periodic.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /* Copyright (c) 2015-2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file periodic.c
  5. *
  6. * \brief Generic backend for handling periodic events.
  7. *
  8. * The events in this module are used by main.c to track items that need
  9. * to fire once every N seconds, possibly picking a new interval each time
  10. * that they fire. See periodic_events[] in main.c for examples.
  11. */
  12. #include "or.h"
  13. #include "compat_libevent.h"
  14. #include "config.h"
  15. #include "periodic.h"
  16. /** We disable any interval greater than this number of seconds, on the
  17. * grounds that it is probably an absolute time mistakenly passed in as a
  18. * relative time.
  19. */
  20. static const int MAX_INTERVAL = 10 * 365 * 86400;
  21. /** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
  22. * now. */
  23. static void
  24. periodic_event_set_interval(periodic_event_item_t *event,
  25. time_t next_interval)
  26. {
  27. tor_assert(next_interval < MAX_INTERVAL);
  28. struct timeval tv;
  29. tv.tv_sec = next_interval;
  30. tv.tv_usec = 0;
  31. mainloop_event_schedule(event->ev, &tv);
  32. }
  33. /** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
  34. * event that needs to be called */
  35. static void
  36. periodic_event_dispatch(mainloop_event_t *ev, void *data)
  37. {
  38. periodic_event_item_t *event = data;
  39. tor_assert(ev == event->ev);
  40. time_t now = time(NULL);
  41. const or_options_t *options = get_options();
  42. // log_debug(LD_GENERAL, "Dispatching %s", event->name);
  43. int r = event->fn(now, options);
  44. int next_interval = 0;
  45. /* update the last run time if action was taken */
  46. if (r==0) {
  47. log_err(LD_BUG, "Invalid return value for periodic event from %s.",
  48. event->name);
  49. tor_assert(r != 0);
  50. } else if (r > 0) {
  51. event->last_action_time = now;
  52. /* If the event is meant to happen after ten years, that's likely
  53. * a bug, and somebody gave an absolute time rather than an interval.
  54. */
  55. tor_assert(r < MAX_INTERVAL);
  56. next_interval = r;
  57. } else {
  58. /* no action was taken, it is likely a precondition failed,
  59. * we should reschedule for next second incase the precondition
  60. * passes then */
  61. next_interval = 1;
  62. }
  63. // log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
  64. // next_interval);
  65. struct timeval tv = { next_interval , 0 };
  66. mainloop_event_schedule(ev, &tv);
  67. }
  68. /** Schedules <b>event</b> to run as soon as possible from now. */
  69. void
  70. periodic_event_reschedule(periodic_event_item_t *event)
  71. {
  72. periodic_event_set_interval(event, 1);
  73. }
  74. /** Initializes the libevent backend for a periodic event. */
  75. void
  76. periodic_event_setup(periodic_event_item_t *event)
  77. {
  78. if (event->ev) { /* Already setup? This is a bug */
  79. log_err(LD_BUG, "Initial dispatch should only be done once.");
  80. tor_assert(0);
  81. }
  82. event->ev = mainloop_event_new(periodic_event_dispatch,
  83. event);
  84. tor_assert(event->ev);
  85. }
  86. /** Handles initial dispatch for periodic events. It should happen 1 second
  87. * after the events are created to mimic behaviour before #3199's refactor */
  88. void
  89. periodic_event_launch(periodic_event_item_t *event)
  90. {
  91. if (! event->ev) { /* Not setup? This is a bug */
  92. log_err(LD_BUG, "periodic_event_launch without periodic_event_setup");
  93. tor_assert(0);
  94. }
  95. // Initial dispatch
  96. periodic_event_dispatch(event->ev, event);
  97. }
  98. /** Release all storage associated with <b>event</b> */
  99. void
  100. periodic_event_destroy(periodic_event_item_t *event)
  101. {
  102. if (!event)
  103. return;
  104. mainloop_event_free(event->ev);
  105. event->last_action_time = 0;
  106. }