Browse Source

schev: Unfinished work on new subsystem schev

Serj Kalichev 3 years ago
parent
commit
4ab7633a37
6 changed files with 336 additions and 0 deletions
  1. 3 0
      faux/Makefile.am
  2. 28 0
      faux/schev.h
  3. 7 0
      faux/schev/Makefile.am
  4. 147 0
      faux/schev/ev.c
  5. 36 0
      faux/schev/private.h
  6. 115 0
      faux/schev/schev.c

+ 3 - 0
faux/Makefile.am

@@ -18,6 +18,7 @@ nobase_include_HEADERS += \
 	faux/file.h \
 	faux/argv.h \
 	faux/time.h \
+	faux/schev.h \
 	faux/testc_helpers.h
 
 EXTRA_DIST += \
@@ -32,6 +33,7 @@ EXTRA_DIST += \
 	faux/file/Makefile.am \
 	faux/argv/Makefile.am \
 	faux/time/Makefile.am \
+	faux/schev/Makefile.am \
 	faux/testc_helpers/Makefile.am
 
 include $(top_srcdir)/faux/base/Makefile.am
@@ -45,6 +47,7 @@ include $(top_srcdir)/faux/ini/Makefile.am
 include $(top_srcdir)/faux/file/Makefile.am
 include $(top_srcdir)/faux/argv/Makefile.am
 include $(top_srcdir)/faux/time/Makefile.am
+include $(top_srcdir)/faux/schev/Makefile.am
 include $(top_srcdir)/faux/testc_helpers/Makefile.am
 
 if TESTC

+ 28 - 0
faux/schev.h

@@ -0,0 +1,28 @@
+/** @file event.h
+ * @brief Public interface for event schedule functions.
+ */
+
+#ifndef _faux_schev_h
+#define _faux_schev_h
+
+#include <faux/faux.h>
+#include <faux/time.h>
+
+#define FAUX_SCHEV_NOW NULL
+
+typedef enum {
+	FAUX_SCHEV_PERIODIC = BOOL_TRUE,
+	FAUX_SCHEV_ONCE = BOOL_FALSE
+	} faux_schev_periodic_t;
+
+typedef struct faux_ev_s faux_ev_t;
+typedef struct faux_schev_s faux_schev_t;
+typedef faux_list_node_t faux_schev_node_t;
+
+
+C_DECL_BEGIN
+
+
+C_DECL_END
+
+#endif /* _faux_schev_h */

+ 7 - 0
faux/schev/Makefile.am

@@ -0,0 +1,7 @@
+libfaux_la_SOURCES += \
+	faux/schev/ev.c \
+	faux/schev/schev.c
+
+#if TESTC
+#libfaux_la_SOURCES += faux/event/testc_event.c
+#endif

+ 147 - 0
faux/schev/ev.c

@@ -0,0 +1,147 @@
+/** @file ev.c
+ * Single event for scheduling.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "private.h"
+#include "faux/str.h"
+#include "faux/schev.h"
+
+int faux_ev_compare(const void *first, const void *second)
+{
+	const faux_ev_t *f = (const faux_ev_t *)first;
+	const faux_ev_t *s = (const faux_ev_t *)second;
+
+	return faux_timespec_cmp(&f->time, &s->time);
+}
+
+
+int faux_ev_compare_id(const void *key, const void *list_item)
+{
+	int *f = (int *)key;
+	const faux_ev_t *s = (const faux_ev_t *)list_item;
+
+	return ((*f == s->id) ? 0 : 1);
+}
+
+
+int faux_ev_compare_data(const void *key, const void *list_item)
+{
+	void *f = (void *)key;
+	const faux_ev_t *s = (const faux_ev_t *)list_item;
+
+	return ((f == s->data) ? 0 : 1);
+}
+
+
+faux_ev_t *faux_ev_new(const struct timespec *time, int ev_id, void *data)
+{
+	faux_ev_t *ev = NULL;
+
+	ev = faux_zmalloc(sizeof(*ev));
+	assert(ev);
+	if (!ev)
+		return NULL;
+
+	// Initialize
+	if (time) {
+		ev->time = *time;
+	} else {
+		struct timespec t = {};
+		clock_gettime(FAUX_SCHEV_CLOCK_SOURCE, &t);
+		ev->time = t;
+	}
+	ev->id = ev_id;
+	ev->data = data;
+	ev->periodic = FAUX_SCHEV_ONCE; // Not periodic by default
+	ev->cycles_num = 0;
+	faux_nsec_to_timespec(&ev->interval, 0l);
+
+	return ev;
+}
+
+
+void faux_ev_free(void *ptr)
+{
+	faux_ev_t *ev = (faux_ev_t *)ptr;
+
+	if (!ev)
+		return;
+	faux_free(ev);
+}
+
+
+int faux_ev_periodic(faux_ev_t *schev,
+	struct timespec *interval, int cycles_num)
+{
+	assert(schev);
+	assert(interval);
+	// When cycles_num == 0 then periodic has no meaning
+	if (!schev || !interval || cycles_num == 0)
+		return -1;
+
+	schev->periodic = FAUX_SCHEV_PERIODIC;
+	schev->cycles_num = cycles_num;
+	schev->interval = *interval;
+
+	return 0;
+}
+
+
+faux_schev_periodic_t faux_ev_is_periodic(faux_ev_t *schev)
+{
+	assert(schev);
+	if (!schev)
+		return FAUX_SCHEV_ONCE;
+
+	return schev->periodic;
+}
+
+int faux_ev_dec_cycles(faux_ev_t *schev, int *new_cycles_num)
+{
+	assert(schev);
+	if (!schev)
+		return -1;
+	if (schev->periodic != FAUX_SCHEV_PERIODIC)
+		return -1; // Non-periodic event
+	if ((schev->cycles_num != FAUX_SCHEV_CYCLES_INFINITE) &&
+		(schev->cycles_num > 0))
+		schev->cycles_num--;
+
+	if (new_cycles_num)
+		*new_cycles_num = schev->cycles_num;
+
+	return 0;
+}
+
+int faux_ev_id(const faux_ev_t *ev)
+{
+	assert(ev);
+	if (!ev)
+		return -1;
+
+	return ev->id;
+}
+
+
+void *faux_ev_data(const faux_ev_t *ev)
+{
+	assert(ev);
+	if (!ev)
+		return NULL;
+
+	return ev->data;
+}
+
+
+const struct timespec *faux_ev_time(const faux_ev_t *ev)
+{
+	assert(ev);
+	if (!ev)
+		return NULL;
+
+	return &ev->time;
+}

+ 36 - 0
faux/schev/private.h

@@ -0,0 +1,36 @@
+#include "faux/faux.h"
+#include "faux/list.h"
+#include "faux/time.h"
+#include "faux/schev.h"
+
+#define FAUX_SCHEV_CLOCK_SOURCE CLOCK_MONOTONIC
+
+#define FAUX_SCHEV_CYCLES_INFINITE (-1)
+
+struct faux_ev_s {
+	struct timespec time; // Planned time of event
+	struct timespec interval; // Time interval for periodic event
+	int cycles_num; // Number of cycles for periodic event
+	faux_schev_periodic_t periodic; // Periodic flag
+	int id; // Type of event
+	void *data; // Arbitrary data linked to event
+};
+
+struct faux_schev_s {
+	faux_list_t *list;
+};
+
+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);
+
+faux_ev_t *faux_ev_new(const struct timespec *time, int ev_id, void *data);
+void faux_ev_free(void *ptr);
+
+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);
+
+C_DECL_END

+ 115 - 0
faux/schev/schev.c

@@ -0,0 +1,115 @@
+/** @brief Mechanism to shedule events.
+ */
+
+#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/schev.h"
+
+
+/** @brief Allocates new schev (SCHedule EVent) object.
+ *
+ * Before working with schev object it must be allocated and initialized.
+ *
+ * @return Allocated and initialized schev object or NULL on error.
+ */
+faux_schev_t *faux_schev_new(void)
+{
+	faux_schev_t *schev = NULL;
+
+	schev = faux_zmalloc(sizeof(*schev));
+	if (!schev)
+		return NULL;
+
+	// Init
+	schev->list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_NONUNIQUE,
+		faux_ev_compare, NULL, faux_ev_free);
+
+	return schev;
+}
+
+
+/** @brief Frees the schev object.
+ *
+ * After using the schev object must be freed. Function frees object itself
+ * and all events stored within schev object.
+ */
+void faux_schev_free(faux_schev_t *schev)
+{
+	assert(schev);
+	if (!schev)
+		return;
+
+	faux_list_free(schev->list);
+	faux_free(schev);
+}
+
+
+/** @brief Adds event to scheduling list using absolute time.
+ *
+ * @param [in] sched Allocated and initialized sched object.
+ * @param [in] time Absolute time of future event.
+ * @param [in] Event ID.
+ * @param [in] Pointer to arbitrary data linked to event.
+ * @return 0 - success, < 0 on error.
+ */
+int faux_schev_schedule(
+	faux_schev_t *schev, const struct timespec *time, int ev_id, void *data)
+{
+	faux_ev_t *ev = NULL;
+	faux_list_node_t *node = NULL;
+
+	assert(schev);
+	if (!schev)
+		return -1;
+
+	ev = faux_ev_new(time, ev_id, data);
+	assert(ev);
+	if (!ev)
+		return -1;
+
+	node = faux_list_add(schev->list, ev);
+	if (!node) { // Something went wrong
+		faux_ev_free(ev);
+		return -1;
+	}
+
+	return 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] Event ID.
+ * @param [in] Pointer to arbitrary data linked to event.
+ * @return 0 - success, < 0 on error.
+ */
+int faux_schev_schedule_interval(faux_schev_t *schev,
+	const struct timespec *interval, int ev_id, void *data)
+{
+	struct timespec t = {};
+	struct timespec plan = {};
+
+	assert(schev);
+	if (!schev)
+		return -1;
+
+	if (!interval)
+		return faux_schev_schedule(schev, FAUX_SCHEV_NOW, ev_id, data);
+	clock_gettime(FAUX_SCHEV_CLOCK_SOURCE, &t);
+	faux_timespec_sum(&plan, &t, interval);
+
+	return faux_schev_schedule(schev, &plan, ev_id, data);
+}