sched.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /** @brief Mechanism to shedule events.
  2. *
  3. * It's an ordered list of events. Events are ordered by the time. The earlier
  4. * events are closer to list head. The events can be one-time ("once") and
  5. * periodic. Periodic events have period and number of cycles (can be infinite).
  6. * User can schedule events specifying absolute time of future event or interval
  7. * from now to the moment of event. Periodic events will be rescheduled
  8. * automatically using specified period.
  9. *
  10. * User can get interval from now to next event time. User can get upcoming
  11. * events one-by-one.
  12. *
  13. * Each scheduled event can has arbitrary ID and pointer to arbitrary data
  14. * linked to this event. The ID can be used for type of event for
  15. * example or something else. The linked data can be a service structure.
  16. */
  17. #include <sys/time.h>
  18. #include <time.h>
  19. #include <errno.h>
  20. #include <stdint.h>
  21. #include <assert.h>
  22. #include "private.h"
  23. #include "faux/faux.h"
  24. #include "faux/time.h"
  25. #include "faux/list.h"
  26. #include "faux/sched.h"
  27. /** @brief Allocates new sched object.
  28. *
  29. * Before working with sched object it must be allocated and initialized.
  30. *
  31. * @return Allocated and initialized sched object or NULL on error.
  32. */
  33. faux_sched_t *faux_sched_new(void)
  34. {
  35. faux_sched_t *sched = NULL;
  36. sched = faux_zmalloc(sizeof(*sched));
  37. if (!sched)
  38. return NULL;
  39. // Init
  40. sched->list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_NONUNIQUE,
  41. faux_ev_compare, NULL, faux_ev_free);
  42. return sched;
  43. }
  44. /** @brief Frees the sched object.
  45. *
  46. * After using the sched object must be freed. Function frees object itself
  47. * and all events stored within sched object.
  48. */
  49. void faux_sched_free(faux_sched_t *sched)
  50. {
  51. assert(sched);
  52. if (!sched)
  53. return;
  54. faux_list_free(sched->list);
  55. faux_free(sched);
  56. }
  57. /** @brief Internal function to add existent event to scheduling list.
  58. *
  59. * @param [in] sched Allocated and initialized sched object.
  60. * @param [in] ev Existent ev object.
  61. * @return 0 - success, < 0 on error.
  62. */
  63. static int _sched_ev(faux_sched_t *sched, faux_ev_t *ev)
  64. {
  65. faux_list_node_t *node = NULL;
  66. assert(sched);
  67. assert(ev);
  68. if (!sched || !ev)
  69. return -1;
  70. node = faux_list_add(sched->list, ev);
  71. if (!node) // Something went wrong
  72. return -1;
  73. return 0;
  74. }
  75. /** @brief Internal function to add constructed event to scheduling list.
  76. *
  77. * @param [in] sched Allocated and initialized sched object.
  78. * @param [in] time Absolute time of future event.
  79. * @param [in] ev_id Event ID.
  80. * @param [in] data Pointer to arbitrary data linked to event.
  81. * @param [in] periodic Periodic flag.
  82. * @param [in] period Periodic interval.
  83. * @param [in] cycle_num Number of cycles (FAUX_SCHED_INFINITE for infinite).
  84. * @return 0 - success, < 0 on error.
  85. */
  86. static int _sched(faux_sched_t *sched, const struct timespec *time,
  87. int ev_id, void *data, faux_sched_periodic_t periodic,
  88. const struct timespec *period, unsigned int cycle_num)
  89. {
  90. faux_ev_t *ev = NULL;
  91. ev = faux_ev_new(time, ev_id, data);
  92. assert(ev);
  93. if (!ev)
  94. return -1;
  95. if (FAUX_SCHED_PERIODIC == periodic)
  96. faux_ev_periodic(ev, period, cycle_num);
  97. if (_sched_ev(sched, ev) < 0) { // Something went wrong
  98. faux_ev_free(ev);
  99. return -1;
  100. }
  101. return 0;
  102. }
  103. /** @brief Adds non-periodic event to scheduling list using absolute time.
  104. *
  105. * @param [in] sched Allocated and initialized sched object.
  106. * @param [in] time Absolute time of future event (FAUX_SCHED_NOW for now).
  107. * @param [in] ev_id Event ID.
  108. * @param [in] data Pointer to arbitrary data linked to event.
  109. * @return 0 - success, < 0 on error.
  110. */
  111. int faux_sched_once(
  112. faux_sched_t *sched, const struct timespec *time, int ev_id, void *data)
  113. {
  114. return _sched(sched, time, ev_id, data,
  115. FAUX_SCHED_ONCE, NULL, 0);
  116. }
  117. /** @brief Adds event to scheduling list using interval.
  118. *
  119. * Add interval to the list. The absolute time is calculated by
  120. * adding specified interval to the current absolute time.
  121. *
  122. * @param [in] sched Allocated and initialized sched object.
  123. * @param [in] interval Interval (NULL means "now").
  124. * @param [in] ev_id Event ID.
  125. * @param [in] data Pointer to arbitrary data linked to event.
  126. * @return 0 - success, < 0 on error.
  127. */
  128. int faux_sched_once_delayed(faux_sched_t *sched,
  129. const struct timespec *interval, int ev_id, void *data)
  130. {
  131. struct timespec now = {};
  132. struct timespec plan = {};
  133. assert(sched);
  134. if (!sched)
  135. return -1;
  136. if (!interval)
  137. return faux_sched_once(sched, FAUX_SCHED_NOW, ev_id, data);
  138. faux_timespec_now(&now);
  139. faux_timespec_sum(&plan, &now, interval);
  140. return faux_sched_once(sched, &plan, ev_id, data);
  141. }
  142. /** @brief Adds periodic event to sched list using absolute time for first one.
  143. *
  144. * @param [in] sched Allocated and initialized sched object.
  145. * @param [in] time Absolute time of first event.
  146. * @param [in] ev_id Event ID.
  147. * @param [in] data Pointer to arbitrary data linked to event.
  148. * @param [in] period Period of periodic event.
  149. * @param [in] cycle_num Number of cycles.
  150. * @return 0 - success, < 0 on error.
  151. */
  152. int faux_sched_periodic(
  153. faux_sched_t *sched, const struct timespec *time, int ev_id, void *data,
  154. const struct timespec *period, unsigned int cycle_num)
  155. {
  156. return _sched(sched, time, ev_id, data,
  157. FAUX_SCHED_PERIODIC, period, cycle_num);
  158. }
  159. /** @brief Adds periodic event to sched list using period for first one.
  160. *
  161. * @param [in] sched Allocated and initialized sched object.
  162. * @param [in] ev_id Event ID.
  163. * @param [in] data Pointer to arbitrary data linked to event.
  164. * @param [in] period Period of periodic event.
  165. * @param [in] cycle_num Number of cycles.
  166. * @return 0 - success, < 0 on error.
  167. */
  168. int faux_sched_periodic_delayed(
  169. faux_sched_t *sched, int ev_id, void *data,
  170. const struct timespec *period, unsigned int cycle_num)
  171. {
  172. struct timespec now = {};
  173. struct timespec plan = {};
  174. assert(sched);
  175. assert(period);
  176. if (!sched || !period)
  177. return -1;
  178. faux_timespec_now(&now);
  179. faux_timespec_sum(&plan, &now, period);
  180. return faux_sched_periodic(sched, &plan, ev_id, data,
  181. period, cycle_num);
  182. }
  183. /** @brief Returns the interval from current time and next scheduled event.
  184. *
  185. * If event is in the past then return null interval.
  186. * If no events was scheduled then return -1.
  187. *
  188. * @param [in] sched Allocated and initialized sched object.
  189. * @param [out] interval Calculated interval.
  190. * @return 0 - success, < 0 on error or when there is no scheduled events.
  191. */
  192. int faux_sched_next_interval(faux_sched_t *sched, struct timespec *interval)
  193. {
  194. faux_ev_t *ev = NULL;
  195. faux_list_node_t *iter = NULL;
  196. assert(sched);
  197. assert(interval);
  198. if (!sched || !interval)
  199. return -1;
  200. iter = faux_list_head(sched->list);
  201. if (!iter)
  202. return -1;
  203. ev = (faux_ev_t *)faux_list_data(iter);
  204. return faux_ev_time_left(ev, interval);
  205. }
  206. /** @brief Remove all entries from the list.
  207. *
  208. * @param [in] sched Allocated and initialized sched object.
  209. */
  210. void faux_sched_empty(faux_sched_t *sched)
  211. {
  212. assert(sched);
  213. if (!sched)
  214. return;
  215. faux_list_empty(sched->list);
  216. }
  217. /** @brief Pop already coming events from list.
  218. *
  219. * Pop (get and remove from list) timestamp if it's in the past.
  220. * If the timestamp is in the future then do nothing.
  221. *
  222. * @param [in] sched Allocated and initialized sched object.
  223. * @param [out] ev_id ID of upcoming event.
  224. * @param [out] data Data of upcoming event.
  225. * @return 0 - success, < 0 on error.
  226. */
  227. int faux_sched_pop(faux_sched_t *sched, int *ev_id, void **data)
  228. {
  229. faux_list_node_t *iter = NULL;
  230. faux_ev_t *ev = NULL;
  231. assert(sched);
  232. if (!sched)
  233. return -1;
  234. iter = faux_list_head(sched->list);
  235. if (!iter)
  236. return -1;
  237. ev = (faux_ev_t *)faux_list_data(iter);
  238. if (!faux_timespec_before_now(faux_ev_time(ev)))
  239. return -1; // No events for this time
  240. faux_list_takeaway(sched->list, iter); // Remove entry from list
  241. if (ev_id)
  242. *ev_id = faux_ev_id(ev);
  243. if (data)
  244. *data = faux_ev_data(ev);
  245. if (faux_ev_reschedule_period(ev) < 0) {
  246. faux_ev_free(ev);
  247. } else {
  248. _sched_ev(sched, ev);
  249. }
  250. return 0;
  251. }
  252. /** @brief Removes all events with specified ID from list.
  253. *
  254. * @param [in] sched Allocated and initialized sched object.
  255. * @param [in] id ID to remove.
  256. * @return Number of removed entries.
  257. */
  258. int faux_sched_remove_by_id(faux_sched_t *sched, int id)
  259. {
  260. faux_list_node_t *node = NULL;
  261. faux_list_node_t *saved = NULL;
  262. int nodes_deleted = 0;
  263. assert(sched);
  264. if (!sched)
  265. return -1;
  266. while ((node = faux_list_match_node(sched->list,
  267. faux_ev_compare_id, &id, &saved))) {
  268. faux_list_del(sched->list, node);
  269. nodes_deleted++;
  270. }
  271. return nodes_deleted;
  272. }
  273. /** @brief Removes all events with specified data pointer from list.
  274. *
  275. * @param [in] sched Allocated and initialized sched object.
  276. * @param [in] data Data to search entries to remove.
  277. * @return Number of removed entries.
  278. */
  279. int faux_sched_remove_by_data(faux_sched_t *sched, void *data)
  280. {
  281. faux_list_node_t *node = NULL;
  282. faux_list_node_t *saved = NULL;
  283. int nodes_deleted = 0;
  284. assert(sched);
  285. if (!sched)
  286. return -1;
  287. while ((node = faux_list_match_node(sched->list,
  288. faux_ev_compare_id, data, &saved))) {
  289. faux_list_del(sched->list, node);
  290. nodes_deleted++;
  291. }
  292. return nodes_deleted;
  293. }