sched.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /** @brief Mechanism to shedule events.
  2. */
  3. #include <sys/time.h>
  4. #include <time.h>
  5. #include <errno.h>
  6. #include <stdint.h>
  7. #include <assert.h>
  8. #include "private.h"
  9. #include "faux/faux.h"
  10. #include "faux/time.h"
  11. #include "faux/list.h"
  12. #include "faux/sched.h"
  13. /** @brief Allocates new sched (SCHedule EVent) object.
  14. *
  15. * Before working with sched object it must be allocated and initialized.
  16. *
  17. * @return Allocated and initialized sched object or NULL on error.
  18. */
  19. faux_sched_t *faux_sched_new(void)
  20. {
  21. faux_sched_t *sched = NULL;
  22. sched = faux_zmalloc(sizeof(*sched));
  23. if (!sched)
  24. return NULL;
  25. // Init
  26. sched->list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_NONUNIQUE,
  27. faux_ev_compare, NULL, faux_ev_free);
  28. return sched;
  29. }
  30. /** @brief Frees the sched object.
  31. *
  32. * After using the sched object must be freed. Function frees object itself
  33. * and all events stored within sched object.
  34. */
  35. void faux_sched_free(faux_sched_t *sched)
  36. {
  37. assert(sched);
  38. if (!sched)
  39. return;
  40. faux_list_free(sched->list);
  41. faux_free(sched);
  42. }
  43. static int _sched_ev(faux_sched_t *sched, faux_ev_t *ev)
  44. {
  45. faux_list_node_t *node = NULL;
  46. assert(sched);
  47. assert(ev);
  48. if (!sched || !ev)
  49. return -1;
  50. node = faux_list_add(sched->list, ev);
  51. if (!node) // Something went wrong
  52. return -1;
  53. return 0;
  54. }
  55. /** @brief Internal function to add event to scheduling list.
  56. *
  57. * @param [in] sched Allocated and initialized sched object.
  58. * @param [in] time Absolute time of future event.
  59. * @param [in] ev_id Event ID.
  60. * @param [in] data Pointer to arbitrary data linked to event.
  61. * @param [in] periodic Periodic flag.
  62. * @param [in] period Periodic interval.
  63. * @param [in] cycles_num Number of cycles (FAUX_SCHED_CYCLES_INFINITE for infinite).
  64. * @return 0 - success, < 0 on error.
  65. */
  66. static int _sched(faux_sched_t *sched, const struct timespec *time,
  67. int ev_id, void *data, faux_sched_periodic_t periodic,
  68. const struct timespec *period, int cycles_num)
  69. {
  70. faux_ev_t *ev = NULL;
  71. ev = faux_ev_new(time, ev_id, data);
  72. assert(ev);
  73. if (!ev)
  74. return -1;
  75. if (FAUX_SCHED_PERIODIC == periodic)
  76. faux_ev_periodic(ev, period, cycles_num);
  77. if (_sched_ev(sched, ev) < 0) { // Something went wrong
  78. faux_ev_free(ev);
  79. return -1;
  80. }
  81. return 0;
  82. }
  83. /** @brief Adds non-periodic event to scheduling list using absolute time.
  84. *
  85. * @param [in] sched Allocated and initialized sched object.
  86. * @param [in] time Absolute time of future event.
  87. * @param [in] ev_id Event ID.
  88. * @param [in] data Pointer to arbitrary data linked to event.
  89. * @return 0 - success, < 0 on error.
  90. */
  91. int faux_sched_once(
  92. faux_sched_t *sched, const struct timespec *time, int ev_id, void *data)
  93. {
  94. return _sched(sched, time, ev_id, data,
  95. FAUX_SCHED_ONCE, NULL, 0);
  96. }
  97. /** @brief Adds event to scheduling list using interval.
  98. *
  99. * Add interval to the list. The absolute time is calculated by
  100. * adding specified interval to the current absolute time.
  101. *
  102. * @param [in] sched Allocated and initialized sched object.
  103. * @param [in] interval Interval (NULL means "now").
  104. * @param [in] ev_id Event ID.
  105. * @param [in] data Pointer to arbitrary data linked to event.
  106. * @return 0 - success, < 0 on error.
  107. */
  108. int faux_sched_once_delayed(faux_sched_t *sched,
  109. const struct timespec *interval, int ev_id, void *data)
  110. {
  111. struct timespec t = {};
  112. struct timespec plan = {};
  113. assert(sched);
  114. if (!sched)
  115. return -1;
  116. if (!interval)
  117. return faux_sched_once(sched, FAUX_SCHED_NOW, ev_id, data);
  118. clock_gettime(FAUX_SCHED_CLOCK_SOURCE, &t);
  119. faux_timespec_sum(&plan, &t, interval);
  120. return faux_sched_once(sched, &plan, ev_id, data);
  121. }
  122. /** @brief Adds periodic event to sched list using absolute time for first one.
  123. *
  124. * @param [in] sched Allocated and initialized sched object.
  125. * @param [in] time Absolute time of first event.
  126. * @param [in] ev_id Event ID.
  127. * @param [in] data Pointer to arbitrary data linked to event.
  128. * @param [in] period Period of periodic event.
  129. * @param [in] cycle_num Number of cycles.
  130. * @return 0 - success, < 0 on error.
  131. */
  132. int faux_sched_periodic(
  133. faux_sched_t *sched, const struct timespec *time, int ev_id, void *data,
  134. const struct timespec *period, int cycle_num)
  135. {
  136. return _sched(sched, time, ev_id, data,
  137. FAUX_SCHED_ONCE, period, cycle_num);
  138. }
  139. /** @brief Adds periodic event to sched list using period for first one.
  140. *
  141. * @param [in] sched Allocated and initialized sched object.
  142. * @param [in] ev_id Event ID.
  143. * @param [in] data Pointer to arbitrary data linked to event.
  144. * @param [in] period Period of periodic event.
  145. * @param [in] cycle_num Number of cycles.
  146. * @return 0 - success, < 0 on error.
  147. */
  148. int faux_sched_periodic_delayed(
  149. faux_sched_t *sched, int ev_id, void *data,
  150. const struct timespec *period, int cycle_num)
  151. {
  152. struct timespec t = {};
  153. struct timespec plan = {};
  154. assert(sched);
  155. assert(period);
  156. if (!sched || !period)
  157. return -1;
  158. clock_gettime(FAUX_SCHED_CLOCK_SOURCE, &t);
  159. faux_timespec_sum(&plan, &t, period);
  160. return faux_sched_periodic(sched, &plan, ev_id, data,
  161. period, cycle_num);
  162. }
  163. /** @brief Returns the interval from current time and next scheduled event.
  164. *
  165. * If event is in the past then return null interval.
  166. * If no events was scheduled then return -1.
  167. */
  168. int faux_sched_next_interval(faux_sched_t *sched, struct timespec *interval)
  169. {
  170. faux_ev_t *ev = NULL;
  171. faux_list_node_t *iter = NULL;
  172. assert(sched);
  173. assert(interval);
  174. if (!sched || !interval)
  175. return -1;
  176. iter = faux_list_head(sched->list);
  177. if (!iter)
  178. return -1;
  179. ev = (faux_ev_t *)faux_list_data(iter);
  180. return faux_ev_time_left(ev, interval);
  181. }
  182. /** @brief Remove all entries from the list.
  183. *
  184. *
  185. */
  186. void faux_sched_empty(faux_sched_t *sched)
  187. {
  188. assert(sched);
  189. if (!sched)
  190. return;
  191. faux_list_empty(sched->list);
  192. }
  193. /** @brief Pop already coming events from list.
  194. *
  195. * Pop (get and remove from list) timestamp if it's in the past.
  196. * If the timestamp is in the future then do nothing.
  197. */
  198. int faux_sched_pop(faux_sched_t *sched, int *ev_id, void **data)
  199. {
  200. struct timespec now = {};
  201. faux_list_node_t *iter = NULL;
  202. faux_ev_t *ev = NULL;
  203. assert(sched);
  204. if (!sched)
  205. return -1;
  206. iter = faux_list_head(sched->list);
  207. if (!iter)
  208. return -1;
  209. ev = (faux_ev_t *)faux_list_data(iter);
  210. clock_gettime(FAUX_SCHED_CLOCK_SOURCE, &now);
  211. if (faux_timespec_cmp(faux_ev_time(ev), &now) > 0)
  212. return -1; // No events for this time
  213. faux_list_takeaway(sched->list, iter); // Remove entry from list
  214. if (ev_id)
  215. *ev_id = faux_ev_id(ev);
  216. if (data)
  217. *data = faux_ev_data(ev);
  218. if (faux_ev_reschedule_interval(ev) < 0) {
  219. faux_ev_free(ev);
  220. } else {
  221. _sched_ev(sched, ev);
  222. }
  223. return 0;
  224. }
  225. #if 0
  226. /* Remove all timestamps with specified ID from the list. */
  227. void remove_ev(lub_list_t *list, int id)
  228. {
  229. lub_list_node_t *iter = lub_list__get_head(list);
  230. if (!iter)
  231. return;
  232. while (iter) {
  233. lub_list_node_t *node = iter;
  234. sched_t *tmp = (sched_t *)lub_list_node__get_data(node);
  235. iter = lub_list_iterator_next(node);
  236. if (tmp->id == id) {
  237. lub_list_del(list, node);
  238. lub_list_node_free(node);
  239. free(tmp);
  240. }
  241. }
  242. }
  243. #endif