ev.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /** @file ev.c
  2. * Single event for scheduling.
  3. */
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #include "private.h"
  9. #include "faux/str.h"
  10. #include "faux/sched.h"
  11. /** @brief Callback function to compare two events by time.
  12. *
  13. * It's used for ordering within schedule list.
  14. *
  15. * @param [in] first First event to compare.
  16. * @param [in] second Second event to compare.
  17. * @return
  18. * > 0 if first > second,
  19. * 0 - equal,
  20. * < 0 if first < second
  21. */
  22. int faux_ev_compare(const void *first, const void *second)
  23. {
  24. const faux_ev_t *f = (const faux_ev_t *)first;
  25. const faux_ev_t *s = (const faux_ev_t *)second;
  26. return faux_timespec_cmp(&(f->time), &(s->time));
  27. }
  28. /** @brief Callback function to compare key and list item by ID.
  29. *
  30. * It's used to search for specified ID within schedule list.
  31. *
  32. * @param [in] key Pointer to key value
  33. * @param [in] list_item Pointer to list item.
  34. * @return
  35. * > 0 if key > list_item,
  36. * 0 - equal,
  37. * < 0 if key < list_item
  38. */
  39. int faux_ev_compare_id(const void *key, const void *list_item)
  40. {
  41. int *f = (int *)key;
  42. const faux_ev_t *s = (const faux_ev_t *)list_item;
  43. return ((*f == s->id) ? 0 : 1);
  44. }
  45. /** @brief Callback function to compare key and list item by data pointer.
  46. *
  47. * It's used to search for specified data pointer within schedule list.
  48. *
  49. * @param [in] key Pointer to key value
  50. * @param [in] list_item Pointer to list item.
  51. * @return
  52. * > 0 if key > list_item,
  53. * 0 - equal,
  54. * < 0 if key < list_item
  55. */
  56. int faux_ev_compare_data(const void *key, const void *list_item)
  57. {
  58. void *f = (void *)key;
  59. const faux_ev_t *s = (const faux_ev_t *)list_item;
  60. return ((f == s->data) ? 0 : 1);
  61. }
  62. /** @brief Allocates and initialize ev object.
  63. *
  64. * @param [in] time Time of event.
  65. * @param [in] ev_id ID of event.
  66. * @param [in] data Pointer to arbitrary linked data.
  67. * @return Allocated and initialized ev object.
  68. */
  69. faux_ev_t *faux_ev_new(const struct timespec *time, int ev_id, void *data)
  70. {
  71. faux_ev_t *ev = NULL;
  72. ev = faux_zmalloc(sizeof(*ev));
  73. assert(ev);
  74. if (!ev)
  75. return NULL;
  76. // Initialize
  77. ev->id = ev_id;
  78. ev->data = data;
  79. ev->periodic = FAUX_SCHED_ONCE; // Not periodic by default
  80. ev->cycle_num = 0;
  81. faux_nsec_to_timespec(&(ev->period), 0l);
  82. faux_ev_reschedule(ev, time);
  83. return ev;
  84. }
  85. /** @brief Frees ev object.
  86. *
  87. * @param [in] ptr Pointer to ev object.
  88. */
  89. void faux_ev_free(void *ptr)
  90. {
  91. faux_ev_t *ev = (faux_ev_t *)ptr;
  92. if (!ev)
  93. return;
  94. faux_free(ev);
  95. }
  96. /** @brief Makes event periodic.
  97. *
  98. * By default new events are not periodic.
  99. *
  100. * @param [in] ev Allocated and initialized ev object.
  101. * @param [in] period Period of periodic event.
  102. * @param [in] cycle_num Number of cycles. FAUX_SHED_INFINITE - infinite.
  103. * @return 0 - success, < 0 on error.
  104. */
  105. int faux_ev_periodic(faux_ev_t *ev,
  106. const struct timespec *period, unsigned int cycle_num)
  107. {
  108. assert(ev);
  109. assert(period);
  110. // When cycle_num == 0 then periodic has no meaning
  111. if (!ev || !period || cycle_num == 0)
  112. return -1;
  113. ev->periodic = FAUX_SCHED_PERIODIC;
  114. ev->cycle_num = cycle_num;
  115. ev->period = *period;
  116. return 0;
  117. }
  118. /** @brief Checks is event periodic.
  119. *
  120. * @param [in] ev Allocated and initialized ev object.
  121. * @return FAUX_SCHED_PERIODIC - periodic, FAUX_SCHED_ONCE - non-periodic.
  122. */
  123. faux_sched_periodic_t faux_ev_is_periodic(faux_ev_t *ev)
  124. {
  125. assert(ev);
  126. if (!ev)
  127. return FAUX_SCHED_ONCE;
  128. return ev->periodic;
  129. }
  130. /** @brief Decrements number of periodic cycles.
  131. *
  132. * On every completed cycle the internal cycles counter must be decremented.
  133. *
  134. * @param [in] ev Allocated and initialized ev object.
  135. * @param [out] new_cycle_num Returns new number of cycles. Can be NULL.
  136. * @return FAUX_SCHED_PERIODIC - periodic, FAUX_SCHED_ONCE - non-periodic.
  137. */
  138. int faux_ev_dec_cycles(faux_ev_t *ev, unsigned int *new_cycle_num)
  139. {
  140. assert(ev);
  141. if (!ev)
  142. return -1;
  143. if (!faux_ev_is_periodic(ev))
  144. return -1; // Non-periodic event
  145. if ((ev->cycle_num != FAUX_SCHED_INFINITE) &&
  146. (ev->cycle_num > 0))
  147. ev->cycle_num--;
  148. if (new_cycle_num)
  149. *new_cycle_num = ev->cycle_num;
  150. return 0;
  151. }
  152. /** Reschedules existent event to newly specified time.
  153. *
  154. * Note: faux_ev_new() use it. Be carefull.
  155. *
  156. * @param [in] ev Allocated and initialized ev object.
  157. * @param [in] new_time New time of event (FAUX_SCHED_NOW for now).
  158. * @return 0 - success, < 0 on error.
  159. */
  160. int faux_ev_reschedule(faux_ev_t *ev, const struct timespec *new_time)
  161. {
  162. assert(ev);
  163. if (!ev)
  164. return -1;
  165. if (new_time) {
  166. ev->time = *new_time;
  167. } else { // Time isn't given so use "NOW"
  168. faux_timespec_now(&(ev->time));
  169. }
  170. return 0;
  171. }
  172. /** Reschedules existent event using period.
  173. *
  174. * New scheduled time is calculated as "now" + "period".
  175. * Function decrements number of cycles. If number of cycles is
  176. * FAUX_SCHED_INFINITE then number of cycles will not be decremented.
  177. *
  178. * @param [in] ev Allocated and initialized ev object.
  179. * @return 0 - success, < 0 on error.
  180. */
  181. int faux_ev_reschedule_period(faux_ev_t *ev)
  182. {
  183. struct timespec new_time = {};
  184. assert(ev);
  185. if (!ev)
  186. return -1;
  187. if (!faux_ev_is_periodic(ev))
  188. return -1;
  189. if (ev->cycle_num <= 1)
  190. return -1; // We don't need to reschedule if last cycle left
  191. faux_timespec_sum(&new_time, &(ev->time), &(ev->period));
  192. faux_ev_reschedule(ev, &new_time);
  193. if (ev->cycle_num != FAUX_SCHED_INFINITE)
  194. faux_ev_dec_cycles(ev, NULL);
  195. return 0;
  196. }
  197. /** @brief Calculates time left from now to the event.
  198. *
  199. * @param [in] ev Allocated and initialized ev object.
  200. * @param [out] left Calculated time left.
  201. * @return 0 - success, < 0 on error.
  202. */
  203. int faux_ev_time_left(faux_ev_t *ev, struct timespec *left)
  204. {
  205. struct timespec now = {};
  206. assert(ev);
  207. assert(left);
  208. if (!ev || !left)
  209. return -1;
  210. faux_timespec_now(&now);
  211. if (faux_timespec_cmp(&now, &(ev->time)) > 0) { // Already happend
  212. faux_nsec_to_timespec(left, 0l);
  213. return 0;
  214. }
  215. faux_timespec_diff(left, &(ev->time), &now);
  216. return 0;
  217. }
  218. /** Returns ID of event object.
  219. *
  220. * @param [in] ev Allocated and initialized ev object.
  221. * @return Event's ID.
  222. */
  223. int faux_ev_id(const faux_ev_t *ev)
  224. {
  225. assert(ev);
  226. if (!ev)
  227. return -1;
  228. return ev->id;
  229. }
  230. /** Returns data pointer of event object.
  231. *
  232. * @param [in] ev Allocated and initialized ev object.
  233. * @return Data pointer.
  234. */
  235. void *faux_ev_data(const faux_ev_t *ev)
  236. {
  237. assert(ev);
  238. if (!ev)
  239. return NULL;
  240. return ev->data;
  241. }
  242. /** Returns time of event object.
  243. *
  244. * @param [in] ev Allocated and initialized ev object.
  245. * @return Pointer to static timespec.
  246. */
  247. const struct timespec *faux_ev_time(const faux_ev_t *ev)
  248. {
  249. assert(ev);
  250. if (!ev)
  251. return NULL;
  252. return &(ev->time);
  253. }