]> Kevux Git Server - fll/commitdiff
Feature: Add f_time_sleep_spec() for providing nanosleep().
authorKevin Day <kevin@kevux.org>
Fri, 26 Apr 2024 03:44:51 +0000 (22:44 -0500)
committerKevin Day <kevin@kevux.org>
Fri, 26 Apr 2024 03:44:51 +0000 (22:44 -0500)
level_0/f_time/c/time.c
level_0/f_time/c/time.h
level_0/f_time/data/build/settings-mocks
level_0/f_time/data/build/settings-tests
level_0/f_time/tests/unit/c/mock-time.c
level_0/f_time/tests/unit/c/mock-time.h
level_0/f_time/tests/unit/c/test-time-sleep_spec.c [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time-sleep_spec.h [new file with mode: 0644]
level_0/f_time/tests/unit/c/test-time.c
level_0/f_time/tests/unit/c/test-time.h

index 41b7549715f56e6075f30dcb3867a8b95f007fb2..be6be8779ed4c3cb7a0177a7dd618e530d783c89 100644 (file)
@@ -115,6 +115,21 @@ extern "C" {
   }
 #endif // _di_f_time_of_day_set_
 
+#ifndef _di_f_time_sleep_spec_
+  f_status_t f_time_sleep_spec(const f_time_spec_t time, f_time_spec_t * const remaining) {
+
+    if (nanosleep(&time, remaining) == -1) {
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == EINTR) return F_interrupt;
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_okay;
+  }
+#endif // _di_f_time_sleep_spec_
+
 #ifndef _di_f_time_spec_millisecond_
   extern f_status_t f_time_spec_millisecond(const f_number_unsigned_t second, const f_number_unsigned_t millisecond, f_time_spec_t * const time) {
     #ifndef _di_level_0_parameter_checking_
index 84fc4870bbab0b0f9295170b33f338c90a9a05e8..b7bfe3628b1cd367fda7afd8324e1d6fb9b98ff9 100644 (file)
@@ -173,6 +173,30 @@ extern "C" {
 #endif // _di_f_time_of_day_set_
 
 /**
+ * Sleep a given amount of time specified by the f_time_spec_t.
+ *
+ * @param time
+ *   The time to sleep (in seconds and nanoseconds).
+ * @param remaining
+ *   (optional) Contains the remaining time if stopped on interrupt.
+ *   Set to NULL to not use.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_interrupt if interrupted by a signal.
+ *
+ *   F_buffer (with error bit) if failed to copy data from user space.
+ *   F_parameter (with error bit) if a parameter is invalid (such as tv_nsec is not in range 0 to 999999999 or tv_sec is negative).
+ *
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see nanosleep()
+ */
+#ifndef _di_f_time_sleep_spec_
+  extern f_status_t f_time_sleep_spec(const f_time_spec_t time, f_time_spec_t * const remaining);
+#endif // _di_f_time_sleep_spec_
+
+/**
  * Create a timespec representing the given seconds and milliseconds.
  *
  * The "f_time_spec_t" may have different lengths and so this function provides overflow and underflow protection.
index c9281a12607f1efd25651a55fc024870e0d3030f..5929c49c53584a57569900aa29d145bff48e2166 100644 (file)
@@ -71,5 +71,6 @@ flags -Wl,--wrap=f_string_append
 flags -Wl,--wrap=gettimeofday
 flags -Wl,--wrap=gmtime_r
 flags -Wl,--wrap=localtime_r
+flags -Wl,--wrap=nanosleep
 flags -Wl,--wrap=settimeofday
 flags -Wl,--wrap=time
index f46307c478497d1ee2fa1b0bddb2cb2f22136572..d1afe9b772b1f1bd02c572f95d0ee4b6a6411c5a 100644 (file)
@@ -28,7 +28,7 @@ build_libraries-individual -lf_memory -lf_string -lf_time
 build_sources_program test-time-calendar_string.c test-time-calendar_string_part.c test-time-epoch_get.c
 build_sources_program test-time-of_day_get.c test-time-of_day_set.c
 build_sources_program test-time-local_get.c test-time-utc_get.c
-build_sources_program test-time-spec_millisecond.c test-time-spec_nanosecond.c
+build_sources_program test-time-sleep_spec.c test-time-spec_millisecond.c test-time-spec_nanosecond.c
 build_sources_program test-time.c
 
 build_script no
index 49a2a66ff2d34ea6d84e2a782ae6f026be060b31..72cf1ea0f7bcc6f5126cc2501175dfeb41a19dd2 100644 (file)
@@ -117,6 +117,23 @@ struct tm *__wrap_localtime_r(const time_t *timep, struct tm *result) {
   return res;
 }
 
+int __wrap_nanosleep(const struct timespec *req, struct timespec *rem) {
+
+  const bool failure = mock_type(bool);
+
+  if (failure) {
+    errno = mock_type(int);
+
+    return -1;
+  }
+
+  if (rem) {
+    *rem = *mock_type(struct timespec *);
+  }
+
+  return 0;
+}
+
 int __wrap_settimeofday(const struct timeval *tv, const struct timezone *tz) {
 
   const bool failure = mock_type(bool);
index 6cd8cbb9be5055d5f12061ec3d7369415bee573a..3681a3b1912c4d78a59cdc1b685a4c20db4580bc 100644 (file)
@@ -17,6 +17,7 @@
 #include <setjmp.h>
 #include <stdint.h>
 #include <string.h>
+#include <time.h>
 
 // cmocka includes.
 #include <cmocka.h>
@@ -42,6 +43,7 @@ extern char *__wrap_ctime_r(const time_t *timep, char *buf);
 extern int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz);
 extern struct tm *__wrap_gmtime_r(const time_t *timep, struct tm *result);
 extern struct tm *__wrap_localtime_r(const time_t *timep, struct tm *result);
+extern int __wrap_nanosleep(const struct timespec *req, struct timespec *rem);
 extern int __wrap_settimeofday(const struct timeval *tv, const struct timezone *tz);
 extern time_t __wrap_time(time_t *tloc);
 
diff --git a/level_0/f_time/tests/unit/c/test-time-sleep_spec.c b/level_0/f_time/tests/unit/c/test-time-sleep_spec.c
new file mode 100644 (file)
index 0000000..37d529e
--- /dev/null
@@ -0,0 +1,68 @@
+#include "test-time.h"
+#include "test-time-sleep_spec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_time_sleep_spec__fails(void **state) {
+
+  const f_time_spec_t spec = f_time_spec_t_initialize;
+
+  {
+    int errnos[] = {
+      EFAULT,
+      EINTR,
+      EINVAL,
+      mock_errno_generic,
+    };
+
+    f_status_t statuss[] = {
+      F_status_set_error(F_buffer),
+      F_interrupt,
+      F_status_set_error(F_parameter),
+      F_status_set_error(F_failure),
+    };
+
+    for (int i = 0; i < 4; ++i) {
+
+      will_return(__wrap_nanosleep, true);
+      will_return(__wrap_nanosleep, errnos[i]);
+
+      const f_status_t status = f_time_sleep_spec(spec, 0);
+
+      assert_int_equal(status, statuss[i]);
+    } // for
+  }
+}
+
+void test__f_time_sleep_spec__works(void **state) {
+
+  const f_time_spec_t spec = { .tv_sec = 1, .tv_nsec = 1 };
+  const f_time_spec_t expect = { .tv_sec = 3, .tv_nsec = 4 };
+
+  {
+    will_return(__wrap_nanosleep, false);
+
+    const f_status_t status = f_time_sleep_spec(spec, 0);
+
+    assert_int_equal(status, F_okay);
+  }
+
+  {
+    f_time_spec_t remaining = f_time_spec_t_initialize;
+
+    will_return(__wrap_nanosleep, false);
+    will_return(__wrap_nanosleep, &expect);
+
+    const f_status_t status = f_time_sleep_spec(spec, &remaining);
+
+    assert_int_equal(status, F_okay);
+    assert_int_equal(remaining.tv_sec, expect.tv_sec);
+    assert_int_equal(remaining.tv_nsec, expect.tv_nsec);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_time/tests/unit/c/test-time-sleep_spec.h b/level_0/f_time/tests/unit/c/test-time-sleep_spec.h
new file mode 100644 (file)
index 0000000..c66a655
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Time
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the time project.
+ */
+#ifndef _TEST__F_time_sleep_spec_h
+#define _TEST__F_time_sleep_spec_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_time_sleep_spec()
+ */
+extern void test__f_time_sleep_spec__fails(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_time_sleep_spec()
+ */
+extern void test__f_time_sleep_spec__works(void **state);
+
+#endif // _TEST__F_time_sleep_spec_h
index d578958e3ab835e82bad8843ac6302b2040ac01e..e2fe635e264febbab9f645c0f09a34749c7558df 100644 (file)
@@ -25,6 +25,7 @@ int main(void) {
     cmocka_unit_test(test__f_time_local_get__fails),
     cmocka_unit_test(test__f_time_of_day_get__fails),
     cmocka_unit_test(test__f_time_of_day_set__fails),
+    cmocka_unit_test(test__f_time_sleep_spec__fails),
     cmocka_unit_test(test__f_time_utc_get__fails),
 
     cmocka_unit_test(test__f_time_calendar_string__works),
@@ -33,6 +34,7 @@ int main(void) {
     cmocka_unit_test(test__f_time_local_get__works),
     cmocka_unit_test(test__f_time_of_day_get__works),
     cmocka_unit_test(test__f_time_of_day_set__works),
+    cmocka_unit_test(test__f_time_sleep_spec__works),
     cmocka_unit_test(test__f_time_utc_get__works),
 
     cmocka_unit_test(test__f_time_spec_millisecond__number_overflow),
@@ -50,9 +52,10 @@ int main(void) {
       cmocka_unit_test(test__f_time_local_get__parameter_checking),
       cmocka_unit_test(test__f_time_of_day_get__parameter_checking),
       // f_time_of_day_set() doesn't use parameter checking.
-      cmocka_unit_test(test__f_time_utc_get__parameter_checking),
+      // f_time_sleep_spec() doesn't use parameter checking.
       cmocka_unit_test(test__f_time_spec_millisecond__parameter_checking),
       cmocka_unit_test(test__f_time_spec_nanosecond__parameter_checking),
+      cmocka_unit_test(test__f_time_utc_get__parameter_checking),
     #endif // _di_level_0_parameter_checking_
   };
 
index 3c3eae6e4912e5d3b0b78e87aa6d7aa9da88a1da..787929fcdc6284f963806f3d85448b429182802e 100644 (file)
@@ -33,6 +33,7 @@
 #include "test-time-of_day_get.h"
 #include "test-time-of_day_set.h"
 #include "test-time-utc_get.h"
+#include "test-time-sleep_spec.h"
 #include "test-time-spec_millisecond.h"
 #include "test-time-spec_nanosecond.h"