ev.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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 Callback function to compare key and list item by event pointer.
  63. *
  64. * It's used to search for specified event pointer within schedule list.
  65. *
  66. * @param [in] key Pointer to key value
  67. * @param [in] list_item Pointer to list item.
  68. * @return
  69. * 1 - not equal
  70. * 0 - equal
  71. */
  72. int faux_ev_compare_ptr(const void *key, const void *list_item)
  73. {
  74. return ((key == list_item) ? 0 : 1);
  75. }
  76. /** @brief Allocates and initialize ev object.
  77. *
  78. * @param [in] ev_id ID of event.
  79. * @param [in] data Pointer to arbitrary linked data. Can be NULL.
  80. * @param [in] free_data_cb Callback to free user data. Can be NULL.
  81. * @return Allocated and initialized ev object.
  82. */
  83. faux_ev_t *faux_ev_new(int ev_id, void *data)
  84. {
  85. faux_ev_t *ev = NULL;
  86. ev = faux_zmalloc(sizeof(*ev));
  87. assert(ev);
  88. if (!ev)
  89. return NULL;
  90. // Initialize
  91. ev->id = ev_id;
  92. ev->data = data;
  93. ev->free_data_cb = NULL;
  94. ev->periodic = FAUX_SCHED_ONCE; // Not periodic by default
  95. ev->cycle_num = 0;
  96. faux_nsec_to_timespec(&(ev->period), 0l);
  97. faux_ev_reschedule(ev, FAUX_SCHED_NOW);
  98. ev->busy = BOOL_FALSE;
  99. return ev;
  100. }
  101. /** @brief Frees ev object. Forced version.
  102. *
  103. * Private function. Don't check busy flag.
  104. *
  105. * @param [in] ptr Pointer to ev object.
  106. */
  107. void faux_ev_free_forced(void *ptr)
  108. {
  109. faux_ev_t *ev = (faux_ev_t *)ptr;
  110. if (!ev)
  111. return;
  112. if (ev->free_data_cb)
  113. ev->free_data_cb(ev->data);
  114. faux_free(ev);
  115. }
  116. /** @brief Frees ev object.
  117. *
  118. * Doesn't free busy event.
  119. *
  120. * @param [in] ptr Pointer to ev object.
  121. */
  122. void faux_ev_free(void *ptr)
  123. {
  124. faux_ev_t *ev = (faux_ev_t *)ptr;
  125. if (!ev)
  126. return;
  127. if (faux_ev_is_busy(ev))
  128. return; // Don't free busy event
  129. faux_ev_free_forced(ev);
  130. }
  131. /** @brief Gets busy status of event.
  132. *
  133. * When event is scheduled then event is "busy". Only scheduler can change
  134. * busy status of event. Busy event can't be freed.
  135. * Busy event can't be changed.
  136. *
  137. * @param [in] ev Allocated and initialized event object.
  138. * @return BOOL_TRUE - busy, BOOL_FALSE - not busy.
  139. */
  140. bool_t faux_ev_is_busy(const faux_ev_t *ev)
  141. {
  142. assert(ev);
  143. if (!ev)
  144. return BOOL_FALSE;
  145. return ev->busy;
  146. }
  147. /** @brief Sets busy flag.
  148. *
  149. * It's private but not static function. Only scheduler can use this function.
  150. * Another code can only get busy status.
  151. *
  152. * @param [in] ev Allocated and initialized event object.
  153. * @param [in] busy New state of busy flag.
  154. * @return BOOL_TRUE - busy, BOOL_FALSE - not busy.
  155. */
  156. void faux_ev_set_busy(faux_ev_t *ev, bool_t busy)
  157. {
  158. assert(ev);
  159. if (!ev)
  160. return;
  161. ev->busy = busy;
  162. }
  163. /** @brief Sets callback to free user data.
  164. *
  165. * @param [in] ev Allocated and initialized event object.
  166. * @param [in] free_data_cb Function to free user data.
  167. */
  168. void faux_ev_set_free_data_cb(faux_ev_t *ev, faux_list_free_fn free_data_cb)
  169. {
  170. assert(ev);
  171. if (!ev)
  172. return;
  173. ev->free_data_cb = free_data_cb;
  174. }
  175. /** @brief Makes event periodic.
  176. *
  177. * By default new events are not periodic. Doesn't change state of busy object.
  178. *
  179. * @param [in] ev Allocated and initialized ev object.
  180. * @param [in] period Period of periodic event. If NULL then non-periodic event.
  181. * @param [in] cycle_num Number of cycles. FAUX_SHED_INFINITE - infinite.
  182. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  183. */
  184. bool_t faux_ev_set_periodic(faux_ev_t *ev,
  185. const struct timespec *period, unsigned int cycle_num)
  186. {
  187. assert(ev);
  188. assert(period);
  189. if (!ev)
  190. return BOOL_FALSE;
  191. if (faux_ev_is_busy(ev))
  192. return BOOL_FALSE; // Don't change busy event
  193. if (!period) {
  194. ev->periodic = FAUX_SCHED_ONCE;
  195. return BOOL_TRUE;
  196. }
  197. // When cycle_num == 0 then periodic has no meaning
  198. if (0 == cycle_num)
  199. return BOOL_FALSE;
  200. ev->periodic = FAUX_SCHED_PERIODIC;
  201. ev->cycle_num = cycle_num;
  202. ev->period = *period;
  203. return BOOL_TRUE;
  204. }
  205. /** @brief Checks is event periodic.
  206. *
  207. * @param [in] ev Allocated and initialized ev object.
  208. * @return FAUX_SCHED_PERIODIC - periodic, FAUX_SCHED_ONCE - non-periodic.
  209. */
  210. faux_sched_periodic_e faux_ev_is_periodic(const faux_ev_t *ev)
  211. {
  212. assert(ev);
  213. if (!ev)
  214. return FAUX_SCHED_ONCE;
  215. return ev->periodic;
  216. }
  217. /** @brief Decrements number of periodic cycles.
  218. *
  219. * On every completed cycle the internal cycles counter must be decremented.
  220. * Private function. Only scheduler can use it.
  221. *
  222. * @param [in] ev Allocated and initialized ev object.
  223. * @param [out] new_cycle_num Returns new number of cycles. Can be NULL.
  224. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  225. */
  226. bool_t faux_ev_dec_cycles(faux_ev_t *ev, unsigned int *new_cycle_num)
  227. {
  228. assert(ev);
  229. if (!ev)
  230. return BOOL_FALSE;
  231. if (!faux_ev_is_periodic(ev))
  232. return BOOL_FALSE; // Non-periodic event
  233. if ((ev->cycle_num != FAUX_SCHED_INFINITE) &&
  234. (ev->cycle_num > 0))
  235. ev->cycle_num--;
  236. if (new_cycle_num)
  237. *new_cycle_num = ev->cycle_num;
  238. return BOOL_TRUE;
  239. }
  240. /** Set schedule time of existent event to specified value.
  241. *
  242. * It's same as faux_ev_reschedule but checks for busy flag before setting.
  243. *
  244. * @param [in] ev Allocated and initialized event object.
  245. * @param [in] new_time New time of event (FAUX_SCHED_NOW for now).
  246. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  247. */
  248. bool_t faux_ev_set_time(faux_ev_t *ev, const struct timespec *new_time)
  249. {
  250. assert(ev);
  251. if (!ev)
  252. return BOOL_FALSE;
  253. if (faux_ev_is_busy(ev))
  254. return BOOL_FALSE; // Don't change busy event
  255. return faux_ev_reschedule(ev, new_time);
  256. }
  257. /** Returns time of event object.
  258. *
  259. * @param [in] ev Allocated and initialized ev object.
  260. * @return Pointer to static timespec.
  261. */
  262. const struct timespec *faux_ev_time(const faux_ev_t *ev)
  263. {
  264. assert(ev);
  265. if (!ev)
  266. return NULL;
  267. return &(ev->time);
  268. }
  269. /** Reschedules existent event to newly specified time.
  270. *
  271. * Note: faux_ev_new() use it. Be carefull. Same as faux_ev_set_time() but
  272. * doesn't check for busy flag. Private function.
  273. *
  274. * @param [in] ev Allocated and initialized ev object.
  275. * @param [in] new_time New time of event (FAUX_SCHED_NOW for now).
  276. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  277. */
  278. bool_t faux_ev_reschedule(faux_ev_t *ev, const struct timespec *new_time)
  279. {
  280. assert(ev);
  281. if (!ev)
  282. return BOOL_FALSE;
  283. if (new_time) {
  284. ev->time = *new_time;
  285. } else { // Time isn't given so use "NOW"
  286. faux_timespec_now(&(ev->time));
  287. }
  288. return BOOL_TRUE;
  289. }
  290. /** Reschedules existent event using period.
  291. *
  292. * New scheduled time is calculated as "now" + "period".
  293. * Function decrements number of cycles. If number of cycles is
  294. * FAUX_SCHED_INFINITE then number of cycles will not be decremented.
  295. * Private function. Only scheduler can use it.
  296. *
  297. * @param [in] ev Allocated and initialized ev object.
  298. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  299. */
  300. bool_t faux_ev_reschedule_period(faux_ev_t *ev)
  301. {
  302. struct timespec new_time = {};
  303. assert(ev);
  304. if (!ev)
  305. return BOOL_FALSE;
  306. if (!faux_ev_is_periodic(ev))
  307. return BOOL_FALSE;
  308. if (ev->cycle_num <= 1)
  309. return BOOL_FALSE; // We don't need to reschedule if last cycle left
  310. faux_timespec_sum(&new_time, &(ev->time), &(ev->period));
  311. faux_ev_reschedule(ev, &new_time);
  312. if (ev->cycle_num != FAUX_SCHED_INFINITE)
  313. faux_ev_dec_cycles(ev, NULL);
  314. return BOOL_TRUE;
  315. }
  316. /** @brief Calculates time left from now to the event.
  317. *
  318. * @param [in] ev Allocated and initialized ev object.
  319. * @param [out] left Calculated time left.
  320. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  321. */
  322. bool_t faux_ev_time_left(const faux_ev_t *ev, struct timespec *left)
  323. {
  324. struct timespec now = {};
  325. assert(ev);
  326. assert(left);
  327. if (!ev || !left)
  328. return BOOL_FALSE;
  329. faux_timespec_now(&now);
  330. if (faux_timespec_cmp(&now, &(ev->time)) > 0) { // Already happened
  331. faux_nsec_to_timespec(left, 0l);
  332. return BOOL_TRUE;
  333. }
  334. faux_timespec_diff(left, &(ev->time), &now);
  335. return BOOL_TRUE;
  336. }
  337. /** Returns ID of event object.
  338. *
  339. * @param [in] ev Allocated and initialized ev object.
  340. * @return Event's ID.
  341. */
  342. int faux_ev_id(const faux_ev_t *ev)
  343. {
  344. assert(ev);
  345. if (!ev)
  346. return -1;
  347. return ev->id;
  348. }
  349. /** Returns user data pointer of event object.
  350. *
  351. * @param [in] ev Allocated and initialized ev object.
  352. * @return User data pointer.
  353. */
  354. void *faux_ev_data(const faux_ev_t *ev)
  355. {
  356. assert(ev);
  357. if (!ev)
  358. return NULL;
  359. return ev->data;
  360. }