ev.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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,
  70. int ev_id, void *data, faux_list_free_fn free_data_cb)
  71. {
  72. faux_ev_t *ev = NULL;
  73. ev = faux_zmalloc(sizeof(*ev));
  74. assert(ev);
  75. if (!ev)
  76. return NULL;
  77. // Initialize
  78. ev->id = ev_id;
  79. ev->data = data;
  80. ev->free_data_cb = free_data_cb;
  81. ev->periodic = FAUX_SCHED_ONCE; // Not periodic by default
  82. ev->cycle_num = 0;
  83. faux_nsec_to_timespec(&(ev->period), 0l);
  84. faux_ev_reschedule(ev, time);
  85. return ev;
  86. }
  87. /** @brief Frees ev object.
  88. *
  89. * @param [in] ptr Pointer to ev object.
  90. */
  91. void faux_ev_free(void *ptr)
  92. {
  93. faux_ev_t *ev = (faux_ev_t *)ptr;
  94. if (!ev)
  95. return;
  96. if (ev->free_data_cb)
  97. ev->free_data_cb(ev->data);
  98. faux_free(ev);
  99. }
  100. /** @brief Makes event periodic.
  101. *
  102. * By default new events are not periodic.
  103. *
  104. * @param [in] ev Allocated and initialized ev object.
  105. * @param [in] period Period of periodic event. If NULL then non-periodic event.
  106. * @param [in] cycle_num Number of cycles. FAUX_SHED_INFINITE - infinite.
  107. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  108. */
  109. bool_t faux_ev_set_periodic(faux_ev_t *ev,
  110. const struct timespec *period, unsigned int cycle_num)
  111. {
  112. assert(ev);
  113. assert(period);
  114. if (!ev)
  115. return BOOL_FALSE;
  116. if (!period) {
  117. ev->periodic = FAUX_SCHED_ONCE;
  118. return BOOL_TRUE;
  119. }
  120. // When cycle_num == 0 then periodic has no meaning
  121. if (0 == cycle_num)
  122. return BOOL_FALSE;
  123. ev->periodic = FAUX_SCHED_PERIODIC;
  124. ev->cycle_num = cycle_num;
  125. ev->period = *period;
  126. return BOOL_TRUE;
  127. }
  128. /** @brief Checks is event periodic.
  129. *
  130. * @param [in] ev Allocated and initialized ev object.
  131. * @return FAUX_SCHED_PERIODIC - periodic, FAUX_SCHED_ONCE - non-periodic.
  132. */
  133. faux_sched_periodic_e faux_ev_is_periodic(faux_ev_t *ev)
  134. {
  135. assert(ev);
  136. if (!ev)
  137. return FAUX_SCHED_ONCE;
  138. return ev->periodic;
  139. }
  140. /** @brief Decrements number of periodic cycles.
  141. *
  142. * On every completed cycle the internal cycles counter must be decremented.
  143. *
  144. * @param [in] ev Allocated and initialized ev object.
  145. * @param [out] new_cycle_num Returns new number of cycles. Can be NULL.
  146. * @return FAUX_SCHED_PERIODIC - periodic, FAUX_SCHED_ONCE - non-periodic.
  147. */
  148. int faux_ev_dec_cycles(faux_ev_t *ev, unsigned int *new_cycle_num)
  149. {
  150. assert(ev);
  151. if (!ev)
  152. return -1;
  153. if (!faux_ev_is_periodic(ev))
  154. return -1; // Non-periodic event
  155. if ((ev->cycle_num != FAUX_SCHED_INFINITE) &&
  156. (ev->cycle_num > 0))
  157. ev->cycle_num--;
  158. if (new_cycle_num)
  159. *new_cycle_num = ev->cycle_num;
  160. return 0;
  161. }
  162. /** Reschedules existent event to newly specified time.
  163. *
  164. * Note: faux_ev_new() use it. Be carefull.
  165. *
  166. * @param [in] ev Allocated and initialized ev object.
  167. * @param [in] new_time New time of event (FAUX_SCHED_NOW for now).
  168. * @return 0 - success, < 0 on error.
  169. */
  170. int faux_ev_reschedule(faux_ev_t *ev, const struct timespec *new_time)
  171. {
  172. assert(ev);
  173. if (!ev)
  174. return -1;
  175. if (new_time) {
  176. ev->time = *new_time;
  177. } else { // Time isn't given so use "NOW"
  178. faux_timespec_now(&(ev->time));
  179. }
  180. return 0;
  181. }
  182. /** Reschedules existent event using period.
  183. *
  184. * New scheduled time is calculated as "now" + "period".
  185. * Function decrements number of cycles. If number of cycles is
  186. * FAUX_SCHED_INFINITE then number of cycles will not be decremented.
  187. *
  188. * @param [in] ev Allocated and initialized ev object.
  189. * @return 0 - success, < 0 on error.
  190. */
  191. int faux_ev_reschedule_period(faux_ev_t *ev)
  192. {
  193. struct timespec new_time = {};
  194. assert(ev);
  195. if (!ev)
  196. return -1;
  197. if (!faux_ev_is_periodic(ev))
  198. return -1;
  199. if (ev->cycle_num <= 1)
  200. return -1; // We don't need to reschedule if last cycle left
  201. faux_timespec_sum(&new_time, &(ev->time), &(ev->period));
  202. faux_ev_reschedule(ev, &new_time);
  203. if (ev->cycle_num != FAUX_SCHED_INFINITE)
  204. faux_ev_dec_cycles(ev, NULL);
  205. return 0;
  206. }
  207. /** @brief Calculates time left from now to the event.
  208. *
  209. * @param [in] ev Allocated and initialized ev object.
  210. * @param [out] left Calculated time left.
  211. * @return 0 - success, < 0 on error.
  212. */
  213. int faux_ev_time_left(faux_ev_t *ev, struct timespec *left)
  214. {
  215. struct timespec now = {};
  216. assert(ev);
  217. assert(left);
  218. if (!ev || !left)
  219. return -1;
  220. faux_timespec_now(&now);
  221. if (faux_timespec_cmp(&now, &(ev->time)) > 0) { // Already happend
  222. faux_nsec_to_timespec(left, 0l);
  223. return 0;
  224. }
  225. faux_timespec_diff(left, &(ev->time), &now);
  226. return 0;
  227. }
  228. /** Returns ID of event object.
  229. *
  230. * @param [in] ev Allocated and initialized ev object.
  231. * @return Event's ID.
  232. */
  233. int faux_ev_id(const faux_ev_t *ev)
  234. {
  235. assert(ev);
  236. if (!ev)
  237. return -1;
  238. return ev->id;
  239. }
  240. /** Returns data pointer of event object.
  241. *
  242. * @param [in] ev Allocated and initialized ev object.
  243. * @return Data pointer.
  244. */
  245. void *faux_ev_data(const faux_ev_t *ev)
  246. {
  247. assert(ev);
  248. if (!ev)
  249. return NULL;
  250. return ev->data;
  251. }
  252. /** Returns time of event object.
  253. *
  254. * @param [in] ev Allocated and initialized ev object.
  255. * @return Pointer to static timespec.
  256. */
  257. const struct timespec *faux_ev_time(const faux_ev_t *ev)
  258. {
  259. assert(ev);
  260. if (!ev)
  261. return NULL;
  262. return &(ev->time);
  263. }