Browse Source

time: faux time subsystem

Serj Kalichev 3 years ago
parent
commit
408ca8cc70
6 changed files with 327 additions and 0 deletions
  1. 3 0
      faux/Makefile.am
  2. 5 0
      faux/testc_module/testc_module.c
  3. 29 0
      faux/time.h
  4. 6 0
      faux/time/Makefile.am
  5. 146 0
      faux/time/testc_time.c
  6. 138 0
      faux/time/time.c

+ 3 - 0
faux/Makefile.am

@@ -17,6 +17,7 @@ nobase_include_HEADERS += \
 	faux/ini.h \
 	faux/file.h \
 	faux/argv.h \
+	faux/time.h \
 	faux/testc_helpers.h
 
 EXTRA_DIST += \
@@ -30,6 +31,7 @@ EXTRA_DIST += \
 	faux/ini/Makefile.am \
 	faux/file/Makefile.am \
 	faux/argv/Makefile.am \
+	faux/time/Makefile.am \
 	faux/testc_helpers/Makefile.am
 
 include $(top_srcdir)/faux/base/Makefile.am
@@ -42,6 +44,7 @@ include $(top_srcdir)/faux/list/Makefile.am
 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/testc_helpers/Makefile.am
 
 if TESTC

+ 5 - 0
faux/testc_module/testc_module.c

@@ -20,6 +20,11 @@ const char *testc_module[][2] = {
 	{"testc_faux_argv_parse", "Parse string to arguments"},
 	{"testc_faux_argv_is_continuable", "Is line continuable"},
 
+	// time
+	{"testc_faux_nsec_timespec_conversion", "Converts nsec from/to struct timespec"},
+	{"testc_faux_timespec_diff", "Diff beetween timespec structures"},
+	{"testc_faux_timespec_sum", "Sum of timespec structures"},
+
 	// End of list
 	{NULL, NULL}
 	};

+ 29 - 0
faux/time.h

@@ -0,0 +1,29 @@
+/** @file time.h
+ * @brief Public interface for time service functions.
+ */
+
+#ifndef _faux_time_h
+#define _faux_time_h
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+
+#include <faux/faux.h>
+
+C_DECL_BEGIN
+
+// Operations for struct timespec
+int faux_timespec_cmp(const struct timespec *val1, const struct timespec *val2);
+int faux_timespec_diff(struct timespec *res,
+	const struct timespec *val1, const struct timespec *val2);
+int faux_timespec_sum(struct timespec *res,
+	const struct timespec *val1, const struct timespec *val2);
+
+// Conversations of struct timespec
+uint64_t faux_timespec_to_nsec(const struct timespec *ts);
+void faux_nsec_to_timespec(struct timespec *ts, uint64_t nsec);
+
+C_DECL_END
+
+#endif /* _faux_time_h */

+ 6 - 0
faux/time/Makefile.am

@@ -0,0 +1,6 @@
+libfaux_la_SOURCES += \
+	faux/time/time.c
+
+if TESTC
+libfaux_la_SOURCES += faux/time/testc_time.c
+endif

+ 146 - 0
faux/time/testc_time.c

@@ -0,0 +1,146 @@
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "faux/time.h"
+
+#define TNUM1 3
+int testc_faux_nsec_timespec_conversion(void)
+{
+	uint64_t n[TNUM1] = {
+		123456789l,
+		880123456789l,
+		789000000000l
+		};
+	struct timespec e[TNUM1] = {
+		{.tv_sec = 0, .tv_nsec = 123456789l},
+		{.tv_sec = 880, .tv_nsec = 123456789l},
+		{.tv_sec = 789, .tv_nsec = 0l}
+		};
+	unsigned int i = 0;
+	int ret = 0;
+
+	// From nsec to struct timespec
+	for (i = 0; i < TNUM1; i++) {
+		struct timespec res = {};
+		faux_nsec_to_timespec(&res, n[i]);
+		if (faux_timespec_cmp(&res, &e[i]) != 0) {
+			printf("nsec_to_timespec: Test %u failed\n", i);
+			ret = -1;
+		}
+	}
+
+	// From struct timespec to nsec
+	for (i = 0; i < TNUM1; i++) {
+		uint64_t res = 0;
+		res = faux_timespec_to_nsec(&e[i]);
+		if (res != n[i]) {
+			printf("timespec_to_nsec: Test %u failed\n", i);
+			ret = -1;
+		}
+	}
+
+	return ret;
+}
+
+
+#define TNUM2 2
+int testc_faux_timespec_diff(void)
+{
+	struct timespec val1[TNUM2] = {
+		{.tv_sec = 0, .tv_nsec = 123456789l},
+		{.tv_sec = 880, .tv_nsec = 2l},
+		};
+	struct timespec val2[TNUM2] = {
+		{.tv_sec = 1, .tv_nsec = 123456789l},
+		{.tv_sec = 770, .tv_nsec = 3l},
+		};
+	struct timespec e[TNUM2] = {
+		{.tv_sec = 0, .tv_nsec = 0l},
+		{.tv_sec = 109, .tv_nsec = 999999999l},
+		};
+	int eretval[TNUM2] = {
+		-1,
+		0
+		};
+	int eerrno[TNUM2] = {
+		EOVERFLOW,
+		0
+		};
+	int ret = 0;
+	int i = 0;
+
+	// Diff
+	for (i = 0; i < TNUM2; i++) {
+		struct timespec res = {};
+		int retval = 0;
+		int err = 0;
+		printf("Test %u:\n", i);
+		printf("val1=%ld:%ld, val2=%ld:%ld\n",
+			val1[i].tv_sec, val1[i].tv_nsec,
+			val2[i].tv_sec, val2[i].tv_nsec);
+		retval = faux_timespec_diff(&res, &val1[i], &val2[i]);
+		err = errno;
+		printf("diff=%ld:%ld, etalon=%ld:%ld\n",
+			res.tv_sec, res.tv_nsec,
+			e[i].tv_sec, e[i].tv_nsec);
+		if (faux_timespec_cmp(&res, &e[i]) != 0) {
+			printf("Test %u timespec cmp failed\n", i);
+			ret = -1;
+		}
+		if (retval != eretval[i]) {
+			printf("Test %u retval failed. Actual: %d. Need: %d.\n",
+				i, retval, eretval[i]);
+			ret = -1;
+		}
+		if ((retval < 0) && (err != eerrno[i])) {
+			printf("Test %u errno failed\n", i);
+			ret = -1;
+		}
+	}
+
+	return ret;
+}
+
+#define TNUM3 2
+int testc_faux_timespec_sum(void)
+{
+	struct timespec val1[TNUM3] = {
+		{.tv_sec = 0, .tv_nsec = 123456789l},
+		{.tv_sec = 880, .tv_nsec = 2l},
+		};
+	struct timespec val2[TNUM3] = {
+		{.tv_sec = 1, .tv_nsec = 910000000l},
+		{.tv_sec = 710, .tv_nsec = 8l},
+		};
+	struct timespec e[TNUM3] = {
+		{.tv_sec = 2, .tv_nsec = 33456789l},
+		{.tv_sec = 1590, .tv_nsec = 10l},
+		};
+	int ret = 0;
+	int i = 0;
+
+	// Sum
+	for (i = 0; i < TNUM3; i++) {
+		struct timespec res = {};
+		printf("Test %u:\n", i);
+		printf("val1=%ld:%ld, val2=%ld:%ld\n",
+			val1[i].tv_sec, val1[i].tv_nsec,
+			val2[i].tv_sec, val2[i].tv_nsec);
+		if (faux_timespec_sum(&res, &val1[i], &val2[i]) < 0) {
+			printf("Test %u retval failed\n", i);
+			ret = -1;
+		}
+		printf("sum=%ld:%ld, etalon=%ld:%ld\n",
+			res.tv_sec, res.tv_nsec,
+			e[i].tv_sec, e[i].tv_nsec);
+		if (faux_timespec_cmp(&res, &e[i]) != 0) {
+			printf("Test %u timespec cmp failed\n", i);
+			ret = -1;
+		}
+	}
+
+	return ret;
+}

+ 138 - 0
faux/time/time.c

@@ -0,0 +1,138 @@
+/** @brief Some usefull function to work with time structs.
+ */
+
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "faux/time.h"
+
+
+/** @brief Compares two time (struct timespec) values.
+ *
+ * @param [in] val1 First timespec struct value.
+ * @param [in] val2 Second timespec struct value.
+ * @return 0 if val1==val2, 1 if val1>val2, -1 if val1<val2.
+*/
+int faux_timespec_cmp(const struct timespec *val1, const struct timespec *val2)
+{
+	assert(val1);
+	assert(val2);
+	if (!val1 && !val2)
+		return 0;
+	if (val1 && !val2)
+		return 1;
+	if (!val1 && val2)
+		return -1;
+
+	if (val1->tv_sec > val2->tv_sec)
+		return 1;
+	if (val1->tv_sec < val2->tv_sec)
+		return -1;
+	// Seconds are equal
+
+	if (val1->tv_nsec > val2->tv_nsec)
+		return 1;
+	if (val1->tv_nsec < val2->tv_nsec)
+		return -1;
+	// Nanoseconds are equal too
+
+	return 0;
+}
+
+
+/** @brief Calculates difference between two time (struct timespec) values.
+ *
+ * It implements "res = val1 - val2" function.
+ *
+ * @param [out] res Result of operation.
+ * @param [in] val1 First struct timespec value.
+ * @param [in] val2 Second struct timespec value.
+ * @return 0 - success or -1 on error.
+ * @exception EINVAL Invalid arguments value.
+ * @exception EOVERFLOW If val2>val1.
+ */
+int faux_timespec_diff(struct timespec *res,
+	const struct timespec *val1, const struct timespec *val2)
+{
+	assert(res);
+	assert(val1);
+	assert(val2);
+	if (!res || !val1 || !val2) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (faux_timespec_cmp(val1, val2) < 0) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+
+	res->tv_sec = val1->tv_sec - val2->tv_sec;
+	if (val1->tv_nsec < val2->tv_nsec) {
+		res->tv_sec -= 1;
+		res->tv_nsec = 1000000000l - val2->tv_nsec + val1->tv_nsec;
+	} else {
+		res->tv_nsec = val1->tv_nsec - val2->tv_nsec;
+	}
+
+	return 0;
+}
+
+/** @brief Sum of two time (struct timespec) values.
+ *
+ * Function implements "res = val1 + val2" operation.
+ *
+ * @param [out] res Result of operation.
+ * @param [in] val1 First time value.
+ * @param [in] val2 Second time value.
+ * @return 0 - success or -1 on error.
+ * @exception EINVAL Invalid arguments value.
+ */
+int faux_timespec_sum(struct timespec *res,
+	const struct timespec *val1, const struct timespec *val2)
+{
+	assert(res);
+	assert(val1);
+	assert(val2);
+	if (!res || !val1 || !val2) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	res->tv_sec = val1->tv_sec + val2->tv_sec + ((val1->tv_nsec + val2->tv_nsec) / 1000000000l);
+	res->tv_nsec = (val1->tv_nsec + val2->tv_nsec) % 1000000000l;
+
+	return 0;
+}
+
+/** @brief Converts struct timespec value to nanoseconds.
+ *
+ * @param [in] ts Struct timespec to convert.
+ * @return Number of nanoseconds or 0 if argument is invalid.
+ */
+uint64_t faux_timespec_to_nsec(const struct timespec *ts)
+{
+	assert(ts);
+	if (!ts)
+		return 0;
+
+	return ((uint64_t)ts->tv_sec * 1000000000l) + (uint64_t)ts->tv_nsec;
+}
+
+/** @brief Converts nanoseconds to struct timespec value.
+ *
+ * @param [out] ts Struct timespec pointer to save result of conversion.
+ * @param [in] nsec Time in nanoseconds to convert.
+ */
+void faux_nsec_to_timespec(struct timespec *ts, uint64_t nsec)
+{
+	assert(ts);
+	if (!ts)
+		return;
+
+	ts->tv_sec = (time_t)(nsec / 1000000000l);
+	ts->tv_nsec = (long)(nsec % 1000000000l);
+}