Browse Source

Many changes in ev, sched, eloop

Serj Kalichev 3 years ago
parent
commit
6a252b36d1
6 changed files with 311 additions and 157 deletions
  1. 27 25
      faux/eloop/eloop.c
  2. 19 17
      faux/sched.h
  3. 144 28
      faux/sched/ev.c
  4. 8 0
      faux/sched/private.h
  5. 87 72
      faux/sched/sched.c
  6. 26 15
      faux/sched/testc_sched.c

+ 27 - 25
faux/eloop/eloop.c

@@ -208,7 +208,7 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop)
 		struct pollfd *pollfd = NULL;
 
 		// Find out next scheduled interval
-		if (faux_sched_next_interval(eloop->sched, &next_interval) < 0)
+		if (!faux_sched_next_interval(eloop->sched, &next_interval))
 			timeout = NULL;
 		else
 			timeout = &next_interval;
@@ -236,16 +236,20 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop)
 
 		// Scheduled event
 		if (0 == sn) {
-			int ev_id = 0; // Event idenftifier
-			faux_eloop_context_t *context = NULL; // Event data
+			faux_ev_t *ev = NULL;
 
 			// Some scheduled events
-			while(faux_sched_pop(eloop->sched, &ev_id, (void **)&context) == 0) {
+			while((ev = faux_sched_pop(eloop->sched))) {
 				faux_eloop_info_sched_t info = {};
-				faux_eloop_cb_f event_cb = NULL;
 				bool_t r = BOOL_TRUE;
-
-				event_cb = context->event_cb;
+				int ev_id = faux_ev_id(ev);
+				faux_eloop_context_t *context =
+					(faux_eloop_context_t *)faux_ev_data(ev);
+				faux_eloop_cb_f event_cb = context->event_cb;
+				void *user_data = context->user_data;
+
+				if (!faux_ev_is_busy(ev))
+					faux_ev_free(ev);
 				if (!event_cb)
 					event_cb = eloop->default_event_cb;
 				if (!event_cb) // Callback is not defined
@@ -254,14 +258,10 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop)
 
 				// Execute callback
 				r = event_cb(eloop, FAUX_ELOOP_SCHED, &info,
-					context->user_data);
+					user_data);
 				// BOOL_FALSE return value means "break the loop"
 				if (!r)
 					stop = BOOL_TRUE;
-
-				// Free non-periodic event's data
-				if (!faux_sched_id_exist(eloop->sched, ev_id))
-					faux_free(context);
 			}
 			continue;
 		}
@@ -516,6 +516,7 @@ bool_t faux_eloop_add_sched_once(faux_eloop_t *eloop, const struct timespec *tim
 	int ev_id, faux_eloop_cb_f event_cb, void *data)
 {
 	faux_eloop_context_t *context = NULL;
+	faux_ev_t *ev = NULL;
 
 	assert(eloop);
 	if (!eloop)
@@ -529,10 +530,11 @@ bool_t faux_eloop_add_sched_once(faux_eloop_t *eloop, const struct timespec *tim
 	if (!context)
 		return BOOL_FALSE;
 
-	if (faux_sched_once(eloop->sched, time, ev_id, context) < 0) {
+	if (!(ev = faux_sched_once(eloop->sched, time, ev_id, context))) {
 		faux_free(context);
 		return BOOL_FALSE;
 	}
+	faux_ev_set_free_data_cb(ev, faux_free);
 
 	return BOOL_TRUE;
 }
@@ -542,6 +544,7 @@ bool_t faux_eloop_add_sched_once_delayed(faux_eloop_t *eloop, const struct times
 	int ev_id, faux_eloop_cb_f event_cb, void *data)
 {
 	faux_eloop_context_t *context = NULL;
+	faux_ev_t *ev = NULL;
 
 	assert(eloop);
 	if (!eloop)
@@ -555,10 +558,11 @@ bool_t faux_eloop_add_sched_once_delayed(faux_eloop_t *eloop, const struct times
 	if (!context)
 		return BOOL_FALSE;
 
-	if (faux_sched_once_delayed(eloop->sched, interval, ev_id, context) < 0) {
+	if (!(ev = faux_sched_once_delayed(eloop->sched, interval, ev_id, context))) {
 		faux_free(context);
 		return BOOL_FALSE;
 	}
+	faux_ev_set_free_data_cb(ev, faux_free);
 
 	return BOOL_TRUE;
 }
@@ -569,6 +573,7 @@ bool_t faux_eloop_add_sched_periodic(faux_eloop_t *eloop, const struct timespec
 	const struct timespec *period, unsigned int cycle_num)
 {
 	faux_eloop_context_t *context = NULL;
+	faux_ev_t *ev = NULL;
 
 	assert(eloop);
 	if (!eloop)
@@ -582,11 +587,12 @@ bool_t faux_eloop_add_sched_periodic(faux_eloop_t *eloop, const struct timespec
 	if (!context)
 		return BOOL_FALSE;
 
-	if (faux_sched_periodic(eloop->sched, time, ev_id, context,
-		period, cycle_num) < 0) {
+	if (!(ev = faux_sched_periodic(eloop->sched, time, ev_id, context,
+		period, cycle_num))) {
 		faux_free(context);
 		return BOOL_FALSE;
 	}
+	faux_ev_set_free_data_cb(ev, faux_free);
 
 	return BOOL_TRUE;
 }
@@ -597,6 +603,7 @@ bool_t faux_eloop_add_sched_periodic_delayed(faux_eloop_t *eloop,
 	const struct timespec *period, unsigned int cycle_num)
 {
 	faux_eloop_context_t *context = NULL;
+	faux_ev_t *ev = NULL;
 
 	assert(eloop);
 	if (!eloop)
@@ -610,11 +617,12 @@ bool_t faux_eloop_add_sched_periodic_delayed(faux_eloop_t *eloop,
 	if (!context)
 		return BOOL_FALSE;
 
-	if (faux_sched_periodic_delayed(eloop->sched, ev_id, context,
-		period, cycle_num) < 0) {
+	if (!(ev = faux_sched_periodic_delayed(eloop->sched, ev_id, context,
+		period, cycle_num))) {
 		faux_free(context);
 		return BOOL_FALSE;
 	}
+	faux_ev_set_free_data_cb(ev, faux_free);
 
 	return BOOL_TRUE;
 }
@@ -622,17 +630,11 @@ bool_t faux_eloop_add_sched_periodic_delayed(faux_eloop_t *eloop,
 
 bool_t faux_eloop_del_sched(faux_eloop_t *eloop, int id)
 {
-	faux_eloop_context_t *context = NULL;
-
 	assert(eloop);
 	if (!eloop)
 		return BOOL_FALSE;
 
-	if (!faux_sched_get_by_id(eloop->sched, id, (void **)&context, NULL))
-		return BOOL_FALSE;
-
-	faux_sched_remove_by_id(eloop->sched, id);
-	faux_free(context);
+	faux_sched_del_by_id(eloop->sched, id);
 
 	return BOOL_TRUE;
 }

+ 19 - 17
faux/sched.h

@@ -25,38 +25,40 @@ typedef faux_list_node_t faux_sched_node_t;
 C_DECL_BEGIN
 
 // Time event
-faux_ev_t *faux_ev_new(const struct timespec *time,
-	int ev_id, void *data, faux_list_free_fn free_data_cb);
+faux_ev_t *faux_ev_new(int ev_id, void *data);
 void faux_ev_free(void *ptr);
+bool_t faux_ev_is_busy(const faux_ev_t *ev);
+void faux_ev_set_free_data_cb(faux_ev_t *ev, faux_list_free_fn free_data_cb);
+bool_t faux_ev_set_time(faux_ev_t *ev, const struct timespec *new_time);
+const struct timespec *faux_ev_time(const faux_ev_t *ev);
 bool_t faux_ev_set_periodic(faux_ev_t *ev,
 	const struct timespec *interval, unsigned int cycle_num);
-bool_t faux_ev_dec_cycles(faux_ev_t *ev, unsigned int *new_cycle_num);
-bool_t faux_ev_reschedule(faux_ev_t *ev, const struct timespec *new_time);
-bool_t faux_ev_reschedule_period(faux_ev_t *ev);
-bool_t faux_ev_time_left(faux_ev_t *ev, struct timespec *left);
+faux_sched_periodic_e faux_ev_is_periodic(const faux_ev_t *ev);
+bool_t faux_ev_time_left(const faux_ev_t *ev, struct timespec *left);
 int faux_ev_id(const faux_ev_t *ev);
 void *faux_ev_data(const faux_ev_t *ev);
-const struct timespec *faux_ev_time(const faux_ev_t *ev);
-faux_sched_periodic_e faux_ev_is_periodic(faux_ev_t *ev);
 
 // Time event scheduler
 faux_sched_t *faux_sched_new(void);
 void faux_sched_free(faux_sched_t *sched);
-int faux_sched_once(
+bool_t faux_sched_add(faux_sched_t *sched, faux_ev_t *ev);
+faux_ev_t *faux_sched_once(
 	faux_sched_t *sched, const struct timespec *time, int ev_id, void *data);
-int faux_sched_once_delayed(faux_sched_t *sched,
+faux_ev_t *faux_sched_once_delayed(faux_sched_t *sched,
 	const struct timespec *interval, int ev_id, void *data);
-int faux_sched_periodic(
+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);
-int faux_sched_periodic_delayed(
+faux_ev_t *faux_sched_periodic_delayed(
 	faux_sched_t *sched, int ev_id, void *data,
 	const struct timespec *period, unsigned int cycle_num);
-int faux_sched_next_interval(faux_sched_t *sched, struct timespec *interval);
-void faux_sched_empty(faux_sched_t *sched);
-int faux_sched_pop(faux_sched_t *sched, int *ev_id, void **data);
-int faux_sched_remove_by_id(faux_sched_t *sched, int id);
-int faux_sched_remove_by_data(faux_sched_t *sched, void *data);
+bool_t faux_sched_next_interval(const faux_sched_t *sched, struct timespec *interval);
+void faux_sched_del_all(faux_sched_t *sched);
+faux_ev_t *faux_sched_pop(faux_sched_t *sched);
+ssize_t faux_sched_del(faux_sched_t *sched, faux_ev_t *ev);
+ssize_t faux_sched_del_by_id(faux_sched_t *sched, int id);
+ssize_t faux_sched_del_by_data(faux_sched_t *sched, void *data);
+
 const struct timespec *faux_sched_time_by_data(faux_sched_t *sched, void *data);
 bool_t faux_sched_id_exist(faux_sched_t *sched, int id);
 bool_t faux_sched_get_by_id(faux_sched_t *sched, int ev_id, void **data,

+ 144 - 28
faux/sched/ev.c

@@ -72,15 +72,30 @@ int faux_ev_compare_data(const void *key, const void *list_item)
 }
 
 
+/** @brief Callback function to compare key and list item by event pointer.
+ *
+ * It's used to search for specified event pointer within schedule list.
+ *
+ * @param [in] key Pointer to key value
+ * @param [in] list_item Pointer to list item.
+ * @return
+ * 1 - not equal
+ * 0 - equal
+ */
+int faux_ev_compare_ptr(const void *key, const void *list_item)
+{
+	return ((key == list_item) ? 0 : 1);
+}
+
+
 /** @brief Allocates and initialize ev object.
  *
- * @param [in] time Time of event.
  * @param [in] ev_id ID of event.
- * @param [in] data Pointer to arbitrary linked data.
+ * @param [in] data Pointer to arbitrary linked data. Can be NULL.
+ * @param [in] free_data_cb Callback to free user data. Can be NULL.
  * @return Allocated and initialized ev object.
  */
-faux_ev_t *faux_ev_new(const struct timespec *time,
-	int ev_id, void *data, faux_list_free_fn free_data_cb)
+faux_ev_t *faux_ev_new(int ev_id, void *data)
 {
 	faux_ev_t *ev = NULL;
 
@@ -92,21 +107,24 @@ faux_ev_t *faux_ev_new(const struct timespec *time,
 	// Initialize
 	ev->id = ev_id;
 	ev->data = data;
-	ev->free_data_cb = free_data_cb;
+	ev->free_data_cb = NULL;
 	ev->periodic = FAUX_SCHED_ONCE; // Not periodic by default
 	ev->cycle_num = 0;
 	faux_nsec_to_timespec(&(ev->period), 0l);
-	faux_ev_reschedule(ev, time);
+	faux_ev_reschedule(ev, FAUX_SCHED_NOW);
+	ev->busy = BOOL_FALSE;
 
 	return ev;
 }
 
 
-/** @brief Frees ev object.
+/** @brief Frees ev object. Forced version.
+ *
+ * Private function. Don't check busy flag.
  *
  * @param [in] ptr Pointer to ev object.
  */
-void faux_ev_free(void *ptr)
+void faux_ev_free_forced(void *ptr)
 {
 	faux_ev_t *ev = (faux_ev_t *)ptr;
 
@@ -117,10 +135,80 @@ void faux_ev_free(void *ptr)
 	faux_free(ev);
 }
 
+/** @brief Frees ev object.
+ *
+ * Doesn't free busy event.
+ *
+ * @param [in] ptr Pointer to ev object.
+ */
+void faux_ev_free(void *ptr)
+{
+	faux_ev_t *ev = (faux_ev_t *)ptr;
+
+	if (!ev)
+		return;
+	if (faux_ev_is_busy(ev))
+		return; // Don't free busy event
+	faux_ev_free_forced(ev);
+}
+
+
+/** @brief Gets busy status of event.
+ *
+ * When event is scheduled then event is "busy". Only scheduler can change
+ * busy status of event. Busy event can't be freed.
+ * Busy event can't be changed.
+ *
+ * @param [in] ev Allocated and initialized event object.
+ * @return BOOL_TRUE - busy, BOOL_FALSE - not busy.
+ */
+bool_t faux_ev_is_busy(const faux_ev_t *ev)
+{
+	assert(ev);
+	if (!ev)
+		return BOOL_FALSE;
+
+	return ev->busy;
+}
+
+
+/** @brief Sets busy flag.
+ *
+ * It's private but not static function. Only scheduler can use this function.
+ * Another code can only get busy status.
+ *
+ * @param [in] ev Allocated and initialized event object.
+ * @param [in] busy New state of busy flag.
+ * @return BOOL_TRUE - busy, BOOL_FALSE - not busy.
+ */
+void faux_ev_set_busy(faux_ev_t *ev, bool_t busy)
+{
+	assert(ev);
+	if (!ev)
+		return;
+
+	ev->busy = busy;
+}
+
+
+/** @brief Sets callback to free user data.
+ *
+ * @param [in] ev Allocated and initialized event object.
+ * @param [in] free_data_cb Function to free user data.
+ */
+void faux_ev_set_free_data_cb(faux_ev_t *ev, faux_list_free_fn free_data_cb)
+{
+	assert(ev);
+	if (!ev)
+		return;
+
+	ev->free_data_cb = free_data_cb;
+}
+
 
 /** @brief Makes event periodic.
  *
- * By default new events are not periodic.
+ * By default new events are not periodic. Doesn't change state of busy object.
  *
  * @param [in] ev Allocated and initialized ev object.
  * @param [in] period Period of periodic event. If NULL then non-periodic event.
@@ -134,6 +222,8 @@ bool_t faux_ev_set_periodic(faux_ev_t *ev,
 	assert(period);
 	if (!ev)
 		return BOOL_FALSE;
+	if (faux_ev_is_busy(ev))
+		return BOOL_FALSE; // Don't change busy event
 	if (!period) {
 		ev->periodic = FAUX_SCHED_ONCE;
 		return BOOL_TRUE;
@@ -155,7 +245,7 @@ bool_t faux_ev_set_periodic(faux_ev_t *ev,
  * @param [in] ev Allocated and initialized ev object.
  * @return FAUX_SCHED_PERIODIC - periodic, FAUX_SCHED_ONCE - non-periodic.
  */
-faux_sched_periodic_e faux_ev_is_periodic(faux_ev_t *ev)
+faux_sched_periodic_e faux_ev_is_periodic(const faux_ev_t *ev)
 {
 	assert(ev);
 	if (!ev)
@@ -168,6 +258,7 @@ faux_sched_periodic_e faux_ev_is_periodic(faux_ev_t *ev)
 /** @brief Decrements number of periodic cycles.
  *
  * On every completed cycle the internal cycles counter must be decremented.
+ * Private function. Only scheduler can use it.
  *
  * @param [in] ev Allocated and initialized ev object.
  * @param [out] new_cycle_num Returns new number of cycles. Can be NULL.
@@ -190,9 +281,46 @@ bool_t faux_ev_dec_cycles(faux_ev_t *ev, unsigned int *new_cycle_num)
 	return BOOL_TRUE;
 }
 
+
+/** Set schedule time of  existent event to specified value.
+ *
+ * It's same as faux_ev_reschedule but checks for busy flag before setting.
+ *
+ * @param [in] ev Allocated and initialized event object.
+ * @param [in] new_time New time of event (FAUX_SCHED_NOW for now).
+ * @return BOOL_TRUE - success, BOOL_FALSE on error.
+ */
+bool_t faux_ev_set_time(faux_ev_t *ev, const struct timespec *new_time)
+{
+	assert(ev);
+	if (!ev)
+		return BOOL_FALSE;
+	if (faux_ev_is_busy(ev))
+		return BOOL_FALSE; // Don't change busy event
+
+	return faux_ev_reschedule(ev, new_time);
+}
+
+
+/** Returns time of event object.
+ *
+ * @param [in] ev Allocated and initialized ev object.
+ * @return Pointer to static timespec.
+ */
+const struct timespec *faux_ev_time(const faux_ev_t *ev)
+{
+	assert(ev);
+	if (!ev)
+		return NULL;
+
+	return &(ev->time);
+}
+
+
 /** Reschedules existent event to newly specified time.
  *
- * Note: faux_ev_new() use it. Be carefull.
+ * Note: faux_ev_new() use it. Be carefull. Same as faux_ev_set_time() but
+ * doesn't check for busy flag. Private function.
  *
  * @param [in] ev Allocated and initialized ev object.
  * @param [in] new_time New time of event (FAUX_SCHED_NOW for now).
@@ -219,6 +347,7 @@ bool_t faux_ev_reschedule(faux_ev_t *ev, const struct timespec *new_time)
  * New scheduled time is calculated as "now" + "period".
  * Function decrements number of cycles. If number of cycles is
  * FAUX_SCHED_INFINITE then number of cycles will not be decremented.
+ * Private function. Only scheduler can use it.
  *
  * @param [in] ev Allocated and initialized ev object.
  * @return BOOL_TRUE - success, BOOL_FALSE on error.
@@ -251,7 +380,7 @@ bool_t faux_ev_reschedule_period(faux_ev_t *ev)
  * @param [out] left Calculated time left.
  * @return BOOL_TRUE - success, BOOL_FALSE on error.
  */
-bool_t faux_ev_time_left(faux_ev_t *ev, struct timespec *left)
+bool_t faux_ev_time_left(const faux_ev_t *ev, struct timespec *left)
 {
 	struct timespec now = {};
 
@@ -261,7 +390,7 @@ bool_t faux_ev_time_left(faux_ev_t *ev, struct timespec *left)
 		return BOOL_FALSE;
 
 	faux_timespec_now(&now);
-	if (faux_timespec_cmp(&now, &(ev->time)) > 0) { // Already happend
+	if (faux_timespec_cmp(&now, &(ev->time)) > 0) { // Already happened
 		faux_nsec_to_timespec(left, 0l);
 		return BOOL_TRUE;
 	}
@@ -286,10 +415,10 @@ int faux_ev_id(const faux_ev_t *ev)
 }
 
 
-/** Returns data pointer of event object.
+/** Returns user data pointer of event object.
  *
  * @param [in] ev Allocated and initialized ev object.
- * @return Data pointer.
+ * @return User data pointer.
  */
 void *faux_ev_data(const faux_ev_t *ev)
 {
@@ -301,16 +430,3 @@ void *faux_ev_data(const faux_ev_t *ev)
 }
 
 
-/** Returns time of event object.
- *
- * @param [in] ev Allocated and initialized ev object.
- * @return Pointer to static timespec.
- */
-const struct timespec *faux_ev_time(const faux_ev_t *ev)
-{
-	assert(ev);
-	if (!ev)
-		return NULL;
-
-	return &(ev->time);
-}

+ 8 - 0
faux/sched/private.h

@@ -12,6 +12,7 @@ struct faux_ev_s {
 	int id; // Type of event
 	void *data; // Arbitrary data linked to event
 	faux_list_free_fn free_data_cb; // Callback to free user data
+	bool_t busy;
 };
 
 
@@ -25,5 +26,12 @@ C_DECL_BEGIN
 int faux_ev_compare(const void *first, const void *second);
 int faux_ev_compare_id(const void *key, const void *list_item);
 int faux_ev_compare_data(const void *key, const void *list_item);
+int faux_ev_compare_ptr(const void *key, const void *list_item);
+
+void faux_ev_free_forced(void *ptr);
+void faux_ev_set_busy(faux_ev_t *ev, bool_t busy);
+bool_t faux_ev_dec_cycles(faux_ev_t *ev, unsigned int *new_cycle_num);
+bool_t faux_ev_reschedule(faux_ev_t *ev, const struct timespec *new_time);
+bool_t faux_ev_reschedule_period(faux_ev_t *ev);
 
 C_DECL_END

+ 87 - 72
faux/sched/sched.c

@@ -44,7 +44,7 @@ faux_sched_t *faux_sched_new(void)
 
 	// Init
 	sched->list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_NONUNIQUE,
-		faux_ev_compare, NULL, faux_ev_free);
+		faux_ev_compare, NULL, faux_ev_free_forced);
 
 	return sched;
 }
@@ -65,28 +65,32 @@ void faux_sched_free(faux_sched_t *sched)
 }
 
 
-/** @brief Internal function to add existent event to scheduling list.
+/** @brief Adds time event (faux_ev_t) to scheduling list.
  *
  * @param [in] sched Allocated and initialized sched object.
- * @param [in] ev Existent ev object.
- * @return 0 - success, < 0 on error.
+ * @param [in] ev Allocated and initialized event object.
+ * @return BOOL_TRUE - success, BOOL_FALSE on error.
  */
-static int _sched_ev(faux_sched_t *sched, faux_ev_t *ev)
+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 -1;
+		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 -1;
+		return BOOL_FALSE;
+	faux_ev_set_busy(ev, BOOL_TRUE);
 
-	return 0;
+	return BOOL_TRUE;
 }
 
+
 /** @brief Internal function to add constructed event to scheduling list.
  *
  * @param [in] sched Allocated and initialized sched object.
@@ -96,27 +100,28 @@ static int _sched_ev(faux_sched_t *sched, faux_ev_t *ev)
  * @param [in] periodic Periodic flag.
  * @param [in] period Periodic interval.
  * @param [in] cycle_num Number of cycles (FAUX_SCHED_INFINITE for infinite).
- * @return 0 - success, < 0 on error.
+ * @return Pointer to newly created faux_ev_t object or NULL on error.
  */
-static int _sched(faux_sched_t *sched, const struct timespec *time,
+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(time, ev_id, data, NULL);
+	ev = faux_ev_new(ev_id, data);
 	assert(ev);
 	if (!ev)
-		return -1;
+		return NULL;
+	faux_ev_set_time(ev, time);
 	if (FAUX_SCHED_PERIODIC == periodic)
 		faux_ev_set_periodic(ev, period, cycle_num);
 
-	if (_sched_ev(sched, ev) < 0) { // Something went wrong
+	if (!faux_sched_add(sched, ev)) { // Something went wrong
 		faux_ev_free(ev);
-		return -1;
+		return NULL;
 	}
 
-	return 0;
+	return ev;
 }
 
 
@@ -126,9 +131,9 @@ static int _sched(faux_sched_t *sched, const struct timespec *time,
  * @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 0 - success, < 0 on error.
+ * @return Pointer to newly created faux_ev_t object or NULL on error.
  */
-int faux_sched_once(
+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,
@@ -145,9 +150,9 @@ int faux_sched_once(
  * @param [in] interval Interval (NULL means "now").
  * @param [in] ev_id Event ID.
  * @param [in] data Pointer to arbitrary data linked to event.
- * @return 0 - success, < 0 on error.
+ * @return Pointer to newly created faux_ev_t object or NULL on error.
  */
-int faux_sched_once_delayed(faux_sched_t *sched,
+faux_ev_t *faux_sched_once_delayed(faux_sched_t *sched,
 	const struct timespec *interval, int ev_id, void *data)
 {
 	struct timespec now = {};
@@ -155,7 +160,7 @@ int faux_sched_once_delayed(faux_sched_t *sched,
 
 	assert(sched);
 	if (!sched)
-		return -1;
+		return NULL;
 
 	if (!interval)
 		return faux_sched_once(sched, FAUX_SCHED_NOW, ev_id, data);
@@ -174,9 +179,9 @@ int faux_sched_once_delayed(faux_sched_t *sched,
  * @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 0 - success, < 0 on error.
+ * @return Pointer to newly created faux_ev_t object or NULL on error.
  */
-int faux_sched_periodic(
+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)
 {
@@ -192,9 +197,9 @@ int faux_sched_periodic(
  * @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 0 - success, < 0 on error.
+ * @return Pointer to newly created faux_ev_t object or NULL on error.
  */
-int faux_sched_periodic_delayed(
+faux_ev_t *faux_sched_periodic_delayed(
 	faux_sched_t *sched, int ev_id, void *data,
 	const struct timespec *period, unsigned int cycle_num)
 {
@@ -204,7 +209,7 @@ int faux_sched_periodic_delayed(
 	assert(sched);
 	assert(period);
 	if (!sched || !period)
-		return -1;
+		return NULL;
 
 	faux_timespec_now(&now);
 	faux_timespec_sum(&plan, &now, period);
@@ -216,13 +221,13 @@ int faux_sched_periodic_delayed(
 /** @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 -1.
+ * If no events was scheduled then return BOOL_FALSE.
  *
  * @param [in] sched Allocated and initialized sched object.
  * @param [out] interval Calculated interval.
- * @return 0 - success, < 0 on error or when there is no scheduled events.
+ * @return BOOL_TRUE - success, BOOL_FALSE on error or there is no scheduled events.
  */
-int faux_sched_next_interval(faux_sched_t *sched, struct timespec *interval)
+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;
@@ -230,17 +235,17 @@ int faux_sched_next_interval(faux_sched_t *sched, struct timespec *interval)
 	assert(sched);
 	assert(interval);
 	if (!sched || !interval)
-		return -1;
+		return BOOL_FALSE;
 
 	iter = faux_list_head(sched->list);
 	if (!iter)
-		return -1;
+		return BOOL_FALSE;
 	ev = (faux_ev_t *)faux_list_data(iter);
 
 	if (!faux_ev_time_left(ev, interval))
-		return -1;
+		return BOOL_FALSE;
 
-	return 0;
+	return BOOL_TRUE;
 }
 
 
@@ -248,7 +253,7 @@ int faux_sched_next_interval(faux_sched_t *sched, struct timespec *interval)
  *
  * @param [in] sched Allocated and initialized sched object.
  */
-void faux_sched_empty(faux_sched_t *sched)
+void faux_sched_del_all(faux_sched_t *sched)
 {
 	assert(sched);
 	if (!sched)
@@ -262,62 +267,62 @@ void faux_sched_empty(faux_sched_t *sched)
  *
  * 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.
- * @param [out] ev_id ID of upcoming event.
- * @param [out] data Data of upcoming event.
- * @return 0 - success, < 0 on error.
+ * @return Event object or NULL on error or there is no already coming events.
  */
-int faux_sched_pop(faux_sched_t *sched, int *ev_id, void **data)
+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 -1;
+		return NULL;
 
 	iter = faux_list_head(sched->list);
 	if (!iter)
-		return -1;
+		return NULL;
 	ev = (faux_ev_t *)faux_list_data(iter);
 	if (!faux_timespec_before_now(faux_ev_time(ev)))
-		return -1; // No events for this time
+		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 (ev_id)
-		*ev_id = faux_ev_id(ev);
-	if (data)
-		*data = faux_ev_data(ev);
+	if (faux_ev_reschedule_period(ev))
+		faux_sched_add(sched, ev);
 
-	if (!faux_ev_reschedule_period(ev)) {
-		faux_ev_free(ev);
-	} else {
-		_sched_ev(sched, ev);
-	}
-
-	return 0;
+	return ev;
 }
 
 
-/** @brief Removes all events with specified ID from list.
+/** @brief Deletes all events with specified value from list.
+ *
+ * Static function.
  *
  * @param [in] sched Allocated and initialized sched object.
- * @param [in] id ID to remove.
+ * @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.
  */
-int faux_sched_remove_by_id(faux_sched_t *sched, int id)
+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;
-	int nodes_deleted = 0;
+	ssize_t nodes_deleted = 0;
 
 	assert(sched);
 	if (!sched)
 		return -1;
 
-	while ((node = faux_list_match_node(sched->list,
-		faux_ev_compare_id, &id, &saved))) {
+	while ((node = faux_list_match_node(sched->list, cmp_f,
+		value, &saved))) {
 		faux_list_del(sched->list, node);
 		nodes_deleted++;
 	}
@@ -326,29 +331,39 @@ int faux_sched_remove_by_id(faux_sched_t *sched, int id)
 }
 
 
-/** @brief Removes all events with specified data pointer from list.
+/** @brief Delete event from list.
  *
  * @param [in] sched Allocated and initialized sched object.
- * @param [in] data Data to search entries to remove.
+ * @param [in] ptr Pointer to event object.
  * @return Number of removed entries or < 0 on error.
  */
-int faux_sched_remove_by_data(faux_sched_t *sched, void *data)
+ssize_t faux_sched_del(faux_sched_t *sched, faux_ev_t *ev)
 {
-	faux_list_node_t *node = NULL;
-	faux_list_node_t *saved = NULL;
-	int nodes_deleted = 0;
+	return faux_sched_del_by_something(sched, ev, faux_ev_compare_ptr);
+}
 
-	assert(sched);
-	if (!sched)
-		return -1;
 
-	while ((node = faux_list_match_node(sched->list,
-		faux_ev_compare_data, data, &saved))) {
-		faux_list_del(sched->list, node);
-		nodes_deleted++;
-	}
+/** @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);
+}
 
-	return nodes_deleted;
+
+/** @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);
 }
 
 

+ 26 - 15
faux/sched/testc_sched.c

@@ -19,6 +19,7 @@ int testc_faux_sched_once(void)
 	int e_id = 0;
 	void *e_str = NULL;
 	struct timespec twait = {};
+	faux_ev_t *ev = NULL;
 
 	faux_nsec_to_timespec(&pol_s, nsec);
 	faux_timespec_now(&now);
@@ -31,11 +32,11 @@ int testc_faux_sched_once(void)
 	// Schedule event
 	faux_sched_once(sched, &t, id, str);
 	// Don't wait so pop must return -1
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0)
+	if (faux_sched_pop(sched))
 		return -1;
 	// Get next event interval. It must be greater than 0 and greater
 	// than full interval (half of second)
-	if (faux_sched_next_interval(sched, &twait) < 0)
+	if (!faux_sched_next_interval(sched, &twait))
 		return -1;
 	if (faux_timespec_cmp(&twait, &(struct timespec){0, 0}) <= 0)
 		return -1;
@@ -43,8 +44,10 @@ int testc_faux_sched_once(void)
 		return -1;
 	// Wait and get event
 	nanosleep(&pol_s, NULL); // wait
-	if (faux_sched_pop(sched, &e_id, &e_str) < 0)
+	if (!(ev = faux_sched_pop(sched)))
 		return -1;
+	e_id = faux_ev_id(ev);
+	e_str = faux_ev_data(ev);
 	if (e_id != id)
 		return -1;
 	if (e_str != str)
@@ -56,8 +59,10 @@ int testc_faux_sched_once(void)
 	nanosleep(&pol_s, NULL); // wait
 	e_id = 0;
 	e_str = NULL;
-	if (faux_sched_pop(sched, &e_id, &e_str) < 0)
+	if (!(ev = faux_sched_pop(sched)))
 		return -1;
+	e_id = faux_ev_id(ev);
+	e_str = faux_ev_data(ev);
 	if (e_id != id)
 		return -1;
 	if (e_str != str)
@@ -80,6 +85,7 @@ int testc_faux_sched_periodic(void)
 	char *str = "test";
 	int e_id = 0;
 	void *e_str = NULL;
+	faux_ev_t *ev = NULL;
 
 	faux_nsec_to_timespec(&pol_s, nsec);
 	faux_timespec_now(&now);
@@ -92,31 +98,33 @@ int testc_faux_sched_periodic(void)
 	// Schedule event
 	faux_sched_periodic_delayed(sched, id, str, &pol_s, 2);
 	// Don't wait so pop must return -1
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0) {
+	if (faux_sched_pop(sched)) {
 		printf("faux_shed_pop: Immediately event\n");
 		return -1;
 	}
 	// Wait and get one event
 	nanosleep(&pol_s, NULL); // wait
-	if (faux_sched_pop(sched, &e_id, &e_str) < 0) {
+	if (!(ev = faux_sched_pop(sched))) {
 		printf("faux_shed_pop: Can't get 1/2 event\n");
 		return -1;
 	}
+	e_id = faux_ev_id(ev);
+	e_str = faux_ev_data(ev);
 	if (e_id != id)
 		return -1;
 	if (e_str != str)
 		return -1;
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0) { // another event?
+	if (faux_sched_pop(sched)) { // another event?
 		printf("faux_shed_pop: Two events at once\n");
 		return -1;
 	}
 	nanosleep(&pol_s, NULL); // wait next time
-	if (faux_sched_pop(sched, &e_id, &e_str) < 0) {
+	if (!faux_sched_pop(sched)) {
 		printf("faux_shed_pop: Can't get 2/2 event\n");
 		return -1;
 	}
 	nanosleep(&pol_s, NULL); // wait third time
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0) { // no events any more
+	if (faux_sched_pop(sched)) { // no events any more
 		printf("faux_shed_pop: The 3/2 event\n");
 		return -1;
 	}
@@ -138,6 +146,7 @@ int testc_faux_sched_infinite(void)
 	char *str = "test";
 	int e_id = 0;
 	void *e_str = NULL;
+	faux_ev_t *ev = NULL;
 
 	faux_nsec_to_timespec(&pol_s, nsec);
 	faux_timespec_now(&now);
@@ -151,32 +160,34 @@ int testc_faux_sched_infinite(void)
 	faux_sched_periodic_delayed(sched, id, str, &pol_s,
 		FAUX_SCHED_INFINITE);
 	// Don't wait so pop must return -1
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0) {
+	if (faux_sched_pop(sched)) {
 		printf("faux_shed_pop: Immediately event\n");
 		return -1;
 	}
 	// Wait and get one event
 	nanosleep(&pol_s, NULL); // wait
-	if (faux_sched_pop(sched, &e_id, &e_str) < 0) {
+	if (!(ev = faux_sched_pop(sched))) {
 		printf("faux_shed_pop: Can't get 1 event\n");
 		return -1;
 	}
+	e_id = faux_ev_id(ev);
+	e_str = faux_ev_data(ev);
 	if (e_id != id)
 		return -1;
 	if (e_str != str)
 		return -1;
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0) { // another event?
+	if (faux_sched_pop(sched)) { // another event?
 		printf("faux_shed_pop: Two events at once\n");
 		return -1;
 	}
 	nanosleep(&pol_s, NULL); // wait next time
-	if (faux_sched_pop(sched, &e_id, &e_str) < 0) {
+	if (!faux_sched_pop(sched)) {
 		printf("faux_shed_pop: Can't get 2 event\n");
 		return -1;
 	}
-	faux_sched_empty(sched); // Empty the list
+	faux_sched_del_all(sched); // Empty the list
 	nanosleep(&pol_s, NULL); // wait third time
-	if (faux_sched_pop(sched, &e_id, &e_str) == 0) {
+	if (faux_sched_pop(sched)) {
 		printf("faux_shed_pop: Event after empty operation\n");
 		return -1;
 	}