periodic.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* Copyright (c) 2015-2019, 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 "core/or/or.h"
  13. #include "lib/evloop/compat_libevent.h"
  14. #include "app/config/config.h"
  15. #include "core/mainloop/mainloop.h"
  16. #include "core/mainloop/periodic.h"
  17. #include "lib/evloop/compat_libevent.h"
  18. /** We disable any interval greater than this number of seconds, on the
  19. * grounds that it is probably an absolute time mistakenly passed in as a
  20. * relative time.
  21. */
  22. static const int MAX_INTERVAL = 10 * 365 * 86400;
  23. /** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
  24. * now. */
  25. static void
  26. periodic_event_set_interval(periodic_event_item_t *event,
  27. time_t next_interval)
  28. {
  29. tor_assert(next_interval < MAX_INTERVAL);
  30. struct timeval tv;
  31. tv.tv_sec = next_interval;
  32. tv.tv_usec = 0;
  33. mainloop_event_schedule(event->ev, &tv);
  34. }
  35. /** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
  36. * event that needs to be called */
  37. static void
  38. periodic_event_dispatch(mainloop_event_t *ev, void *data)
  39. {
  40. periodic_event_item_t *event = data;
  41. tor_assert(ev == event->ev);
  42. time_t now = time(NULL);
  43. update_current_time(now);
  44. const or_options_t *options = get_options();
  45. // log_debug(LD_GENERAL, "Dispatching %s", event->name);
  46. int r = event->fn(now, options);
  47. int next_interval = 0;
  48. if (!periodic_event_is_enabled(event)) {
  49. /* The event got disabled from inside its callback, or before: no need to
  50. * reschedule. */
  51. return;
  52. }
  53. /* update the last run time if action was taken */
  54. if (r==0) {
  55. log_err(LD_BUG, "Invalid return value for periodic event from %s.",
  56. event->name);
  57. tor_assert(r != 0);
  58. } else if (r > 0) {
  59. event->last_action_time = now;
  60. /* If the event is meant to happen after ten years, that's likely
  61. * a bug, and somebody gave an absolute time rather than an interval.
  62. */
  63. tor_assert(r < MAX_INTERVAL);
  64. next_interval = r;
  65. } else {
  66. /* no action was taken, it is likely a precondition failed,
  67. * we should reschedule for next second incase the precondition
  68. * passes then */
  69. next_interval = 1;
  70. }
  71. // log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
  72. // next_interval);
  73. struct timeval tv = { next_interval , 0 };
  74. mainloop_event_schedule(ev, &tv);
  75. }
  76. /** Schedules <b>event</b> to run as soon as possible from now. */
  77. void
  78. periodic_event_reschedule(periodic_event_item_t *event)
  79. {
  80. /* Don't reschedule a disabled event. */
  81. if (periodic_event_is_enabled(event)) {
  82. periodic_event_set_interval(event, 1);
  83. }
  84. }
  85. /** Initializes the libevent backend for a periodic event. */
  86. void
  87. periodic_event_setup(periodic_event_item_t *event)
  88. {
  89. if (event->ev) { /* Already setup? This is a bug */
  90. log_err(LD_BUG, "Initial dispatch should only be done once.");
  91. tor_assert(0);
  92. }
  93. event->ev = mainloop_event_new(periodic_event_dispatch,
  94. event);
  95. tor_assert(event->ev);
  96. }
  97. /** Handles initial dispatch for periodic events. It should happen 1 second
  98. * after the events are created to mimic behaviour before #3199's refactor */
  99. void
  100. periodic_event_launch(periodic_event_item_t *event)
  101. {
  102. if (! event->ev) { /* Not setup? This is a bug */
  103. log_err(LD_BUG, "periodic_event_launch without periodic_event_setup");
  104. tor_assert(0);
  105. }
  106. /* Event already enabled? This is a bug */
  107. if (periodic_event_is_enabled(event)) {
  108. log_err(LD_BUG, "periodic_event_launch on an already enabled event");
  109. tor_assert(0);
  110. }
  111. // Initial dispatch
  112. event->enabled = 1;
  113. periodic_event_dispatch(event->ev, event);
  114. }
  115. /** Release all storage associated with <b>event</b> */
  116. void
  117. periodic_event_destroy(periodic_event_item_t *event)
  118. {
  119. if (!event)
  120. return;
  121. mainloop_event_free(event->ev);
  122. event->last_action_time = 0;
  123. }
  124. /** Enable the given event by setting its "enabled" flag and scheduling it to
  125. * run immediately in the event loop. This can be called for an event that is
  126. * already enabled. */
  127. void
  128. periodic_event_enable(periodic_event_item_t *event)
  129. {
  130. tor_assert(event);
  131. /* Safely and silently ignore if this event is already enabled. */
  132. if (periodic_event_is_enabled(event)) {
  133. return;
  134. }
  135. tor_assert(event->ev);
  136. event->enabled = 1;
  137. mainloop_event_activate(event->ev);
  138. }
  139. /** Disable the given event which means the event is destroyed and then the
  140. * event's enabled flag is unset. This can be called for an event that is
  141. * already disabled. */
  142. void
  143. periodic_event_disable(periodic_event_item_t *event)
  144. {
  145. tor_assert(event);
  146. /* Safely and silently ignore if this event is already disabled. */
  147. if (!periodic_event_is_enabled(event)) {
  148. return;
  149. }
  150. mainloop_event_cancel(event->ev);
  151. event->enabled = 0;
  152. }
  153. /**
  154. * Disable an event, then schedule it to run once.
  155. * Do nothing if the event was already disabled.
  156. */
  157. void
  158. periodic_event_schedule_and_disable(periodic_event_item_t *event)
  159. {
  160. tor_assert(event);
  161. if (!periodic_event_is_enabled(event))
  162. return;
  163. periodic_event_disable(event);
  164. mainloop_event_activate(event->ev);
  165. }