123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- /** @brief Mechanism to shedule events.
- *
- * It's an ordered list of events. Events are ordered by the time. The earlier
- * events are closer to list head. The events can be one-time ("once") and
- * periodic. Periodic events have period and number of cycles (can be infinite).
- * User can schedule events specifying absolute time of future event or interval
- * from now to the moment of event. Periodic events will be rescheduled
- * automatically using specified period.
- *
- * User can get interval from now to next event time. User can get upcoming
- * events one-by-one.
- *
- * Each scheduled event can has arbitrary ID and pointer to arbitrary data
- * linked to this event. The ID can be used for type of event for
- * example or something else. The linked data can be a service structure.
- */
- #include <sys/time.h>
- #include <time.h>
- #include <errno.h>
- #include <stdint.h>
- #include <assert.h>
- #include "private.h"
- #include "faux/faux.h"
- #include "faux/time.h"
- #include "faux/list.h"
- #include "faux/sched.h"
- /** @brief Allocates new sched object.
- *
- * Before working with sched object it must be allocated and initialized.
- *
- * @return Allocated and initialized sched object or NULL on error.
- */
- faux_sched_t *faux_sched_new(void)
- {
- faux_sched_t *sched = NULL;
- sched = faux_zmalloc(sizeof(*sched));
- if (!sched)
- return NULL;
- // Init
- sched->list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_NONUNIQUE,
- faux_ev_compare, NULL, faux_ev_free_forced);
- return sched;
- }
- /** @brief Frees the sched object.
- *
- * After using the sched object must be freed. Function frees object itself
- * and all events stored within sched object.
- */
- void faux_sched_free(faux_sched_t *sched)
- {
- if (!sched)
- return;
- faux_list_free(sched->list);
- faux_free(sched);
- }
- /** @brief Adds time event (faux_ev_t) to scheduling list.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] ev Allocated and initialized event object.
- * @return BOOL_TRUE - success, BOOL_FALSE on error.
- */
- bool_t faux_sched_add(faux_sched_t *sched, faux_ev_t *ev)
- {
- faux_list_node_t *node = NULL;
- assert(sched);
- assert(ev);
- if (!sched || !ev)
- return BOOL_FALSE;
- if (faux_ev_is_busy(ev))
- return BOOL_FALSE; // Don't add busy (already scheduled) event
- node = faux_list_add(sched->list, ev);
- if (!node) // Something went wrong
- return BOOL_FALSE;
- faux_ev_set_busy(ev, BOOL_TRUE);
- return BOOL_TRUE;
- }
- /** @brief Internal function to add constructed event to scheduling list.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] time Absolute time of future event.
- * @param [in] ev_id Event ID.
- * @param [in] data Pointer to arbitrary data linked to event.
- * @param [in] periodic Periodic flag.
- * @param [in] period Periodic interval.
- * @param [in] cycle_num Number of cycles (FAUX_SCHED_INFINITE for infinite).
- * @return Pointer to newly created faux_ev_t object or NULL on error.
- */
- static faux_ev_t *_sched(faux_sched_t *sched, const struct timespec *time,
- int ev_id, void *data, faux_sched_periodic_e periodic,
- const struct timespec *period, unsigned int cycle_num)
- {
- faux_ev_t *ev = NULL;
- ev = faux_ev_new(ev_id, data);
- assert(ev);
- if (!ev)
- return NULL;
- faux_ev_set_time(ev, time);
- if (FAUX_SCHED_PERIODIC == periodic)
- faux_ev_set_periodic(ev, period, cycle_num);
- if (!faux_sched_add(sched, ev)) { // Something went wrong
- faux_ev_free(ev);
- return NULL;
- }
- return ev;
- }
- /** @brief Adds non-periodic event to scheduling list using absolute time.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] time Absolute time of future event (FAUX_SCHED_NOW for now).
- * @param [in] ev_id Event ID.
- * @param [in] data Pointer to arbitrary data linked to event.
- * @return Pointer to newly created faux_ev_t object or NULL on error.
- */
- faux_ev_t *faux_sched_once(
- faux_sched_t *sched, const struct timespec *time, int ev_id, void *data)
- {
- return _sched(sched, time, ev_id, data,
- FAUX_SCHED_ONCE, NULL, 0);
- }
- /** @brief Adds event to scheduling list using interval.
- *
- * Add interval to the list. The absolute time is calculated by
- * adding specified interval to the current absolute time.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] interval Interval (NULL means "now").
- * @param [in] ev_id Event ID.
- * @param [in] data Pointer to arbitrary data linked to event.
- * @return Pointer to newly created faux_ev_t object or NULL on error.
- */
- faux_ev_t *faux_sched_once_delayed(faux_sched_t *sched,
- const struct timespec *interval, int ev_id, void *data)
- {
- struct timespec now = {};
- struct timespec plan = {};
- assert(sched);
- if (!sched)
- return NULL;
- if (!interval)
- return faux_sched_once(sched, FAUX_SCHED_NOW, ev_id, data);
- faux_timespec_now(&now);
- faux_timespec_sum(&plan, &now, interval);
- return faux_sched_once(sched, &plan, ev_id, data);
- }
- /** @brief Adds periodic event to sched list using absolute time for first one.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] time Absolute time of first event.
- * @param [in] ev_id Event ID.
- * @param [in] data Pointer to arbitrary data linked to event.
- * @param [in] period Period of periodic event.
- * @param [in] cycle_num Number of cycles.
- * @return Pointer to newly created faux_ev_t object or NULL on error.
- */
- faux_ev_t *faux_sched_periodic(
- faux_sched_t *sched, const struct timespec *time, int ev_id, void *data,
- const struct timespec *period, unsigned int cycle_num)
- {
- return _sched(sched, time, ev_id, data,
- FAUX_SCHED_PERIODIC, period, cycle_num);
- }
- /** @brief Adds periodic event to sched list using period for first one.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] ev_id Event ID.
- * @param [in] data Pointer to arbitrary data linked to event.
- * @param [in] period Period of periodic event.
- * @param [in] cycle_num Number of cycles.
- * @return Pointer to newly created faux_ev_t object or NULL on error.
- */
- faux_ev_t *faux_sched_periodic_delayed(
- faux_sched_t *sched, int ev_id, void *data,
- const struct timespec *period, unsigned int cycle_num)
- {
- struct timespec now = {};
- struct timespec plan = {};
- assert(sched);
- assert(period);
- if (!sched || !period)
- return NULL;
- faux_timespec_now(&now);
- faux_timespec_sum(&plan, &now, period);
- return faux_sched_periodic(sched, &plan, ev_id, data,
- period, cycle_num);
- }
- /** @brief Returns the interval from current time and next scheduled event.
- *
- * If event is in the past then return null interval.
- * If no events was scheduled then return BOOL_FALSE.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [out] interval Calculated interval.
- * @return BOOL_TRUE - success, BOOL_FALSE on error or there is no scheduled events.
- */
- bool_t faux_sched_next_interval(const faux_sched_t *sched, struct timespec *interval)
- {
- faux_ev_t *ev = NULL;
- faux_list_node_t *iter = NULL;
- assert(sched);
- assert(interval);
- if (!sched || !interval)
- return BOOL_FALSE;
- iter = faux_list_head(sched->list);
- if (!iter)
- return BOOL_FALSE;
- ev = (faux_ev_t *)faux_list_data(iter);
- if (!faux_ev_time_left(ev, interval))
- return BOOL_FALSE;
- return BOOL_TRUE;
- }
- /** @brief Remove all entries from the list.
- *
- * @param [in] sched Allocated and initialized sched object.
- */
- void faux_sched_del_all(faux_sched_t *sched)
- {
- assert(sched);
- if (!sched)
- return;
- faux_list_del_all(sched->list);
- }
- /** @brief Pop already coming events from list.
- *
- * Pop (get and remove from list) timestamp if it's in the past.
- * If the timestamp is in the future then do nothing.
- * The event object can be rescheduled in a case of periodic event or
- * removed from the scheduled list. Removed event must be freed by user.
- * User can inspect event object's busy flag to decide if freeing is needed.
- * If busy flag is BOOL_TRUE then event is rescheduled. If busy flag is
- * BOOL_FALSE then object is ready to be freed.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @return Event object or NULL on error or there is no already coming events.
- */
- faux_ev_t *faux_sched_pop(faux_sched_t *sched)
- {
- faux_list_node_t *iter = NULL;
- faux_ev_t *ev = NULL;
- assert(sched);
- if (!sched)
- return NULL;
- iter = faux_list_head(sched->list);
- if (!iter)
- return NULL;
- ev = (faux_ev_t *)faux_list_data(iter);
- if (!faux_timespec_before_now(faux_ev_time(ev)))
- return NULL; // No events for this time
- faux_list_takeaway(sched->list, iter); // Remove entry from list
- faux_ev_set_busy(ev, BOOL_FALSE);
- if (faux_ev_reschedule_period(ev))
- faux_sched_add(sched, ev);
- return ev;
- }
- /** @brief Deletes all events with specified value from list.
- *
- * Static function.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] value Pointer to key value.
- * @param [in] cmp_f Callback to compare key and entry.
- * @return Number of removed entries or < 0 on error.
- */
- static ssize_t faux_sched_del_by_something(faux_sched_t *sched, void *value,
- faux_list_kcmp_fn cmp_f)
- {
- faux_list_node_t *node = NULL;
- faux_list_node_t *saved = NULL;
- ssize_t nodes_deleted = 0;
- assert(sched);
- if (!sched)
- return -1;
- while ((node = faux_list_match_node(sched->list, cmp_f,
- value, &saved))) {
- faux_list_del(sched->list, node);
- nodes_deleted++;
- }
- return nodes_deleted;
- }
- /** @brief Delete event from list.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] ptr Pointer to event object.
- * @return Number of removed entries or < 0 on error.
- */
- ssize_t faux_sched_del(faux_sched_t *sched, faux_ev_t *ev)
- {
- return faux_sched_del_by_something(sched, ev, faux_ev_compare_ptr);
- }
- /** @brief Deletes all events with specified ID from list.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] id ID to remove.
- * @return Number of removed entries or < 0 on error.
- */
- ssize_t faux_sched_del_by_id(faux_sched_t *sched, int id)
- {
- return faux_sched_del_by_something(sched, &id, faux_ev_compare_id);
- }
- /** @brief Deletes all events with specified data pointer from list.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] data Data to search entries to remove.
- * @return Number of removed entries or < 0 on error.
- */
- ssize_t faux_sched_del_by_data(faux_sched_t *sched, void *data)
- {
- return faux_sched_del_by_something(sched, data, faux_ev_compare_data);
- }
- /** @brief Get scheduled event by specified value.
- *
- * Static function.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] value Value to search for.
- * @param [in] cmp_f Callback to compare key and entry.
- * @param [in,out] saved Iterator.
- * @return Event (faux_ev_t) pointer or NULL on error or not found.
- */
- static faux_ev_t *faux_sched_get_by_something(faux_sched_t *sched, void *value,
- faux_list_kcmp_fn cmp_f, faux_list_node_t **saved)
- {
- faux_list_node_t *node = NULL;
- faux_ev_t *ev = NULL;
- assert(sched);
- if (!sched)
- return NULL;
- node = faux_list_match_node(sched->list, cmp_f, value, saved);
- if (!node)
- return NULL;
- ev = (faux_ev_t *)faux_list_data(node);
- return ev;
- }
- /** @brief Get sched entries with specified event ID.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] ev_id Event ID to search for.
- * @param [in,out] saved Iterator.
- * @return Event (faux_ev_t) pointer or NULL on error or not found.
- */
- faux_ev_t *faux_sched_get_by_id(faux_sched_t *sched, int ev_id,
- faux_list_node_t **saved)
- {
- return faux_sched_get_by_something(sched, &ev_id,
- faux_ev_compare_id, saved);
- }
- /** @brief Get sched entries with specified user data pointer.
- *
- * @param [in] sched Allocated and initialized sched object.
- * @param [in] data Pointer to user data to search for.
- * @param [in,out] saved Iterator.
- * @return Event (faux_ev_t) pointer or NULL on error or not found.
- */
- faux_ev_t *faux_sched_get_by_data(faux_sched_t *sched, void *data,
- faux_list_node_t **saved)
- {
- return faux_sched_get_by_something(sched, data,
- faux_ev_compare_data, saved);
- }
|