]> Kevux Git Server - fll/commitdiff
Feature: Add missing signal functions f_signal_action(), f_signal_pause(), and f_sign...
authorKevin Day <thekevinday@gmail.com>
Wed, 20 Jul 2022 03:19:51 +0000 (22:19 -0500)
committerKevin Day <thekevinday@gmail.com>
Wed, 20 Jul 2022 03:19:51 +0000 (22:19 -0500)
The f_signal_pause() just calls pause() and returns F_none.
The return value of pause() is meaningless if I am understanding the man pages correctly.
It should always return -1 and then sets errno despite this not being an actual error.

14 files changed:
level_0/f_signal/c/signal.c
level_0/f_signal/c/signal.h
level_0/f_signal/data/build/settings-mocks
level_0/f_signal/data/build/settings-tests
level_0/f_signal/tests/unit/c/mock-signal.c
level_0/f_signal/tests/unit/c/mock-signal.h
level_0/f_signal/tests/unit/c/test-signal-action.c [new file with mode: 0644]
level_0/f_signal/tests/unit/c/test-signal-action.h [new file with mode: 0644]
level_0/f_signal/tests/unit/c/test-signal-pause.c [new file with mode: 0644]
level_0/f_signal/tests/unit/c/test-signal-pause.h [new file with mode: 0644]
level_0/f_signal/tests/unit/c/test-signal-suspend.c [new file with mode: 0644]
level_0/f_signal/tests/unit/c/test-signal-suspend.h [new file with mode: 0644]
level_0/f_signal/tests/unit/c/test-signal.c
level_0/f_signal/tests/unit/c/test-signal.h

index 664d4b322bd34337eb8fdc00f9b913e03d48bb08..06d9e767c7300a28549c2f154ab273386f5a6fb5 100644 (file)
@@ -4,6 +4,23 @@
 extern "C" {
 #endif
 
+#ifndef _di_f_signal_action_
+  f_status_t f_signal_action(const f_signal_t signal, const struct sigaction * const action, struct sigaction *previous) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!action && !previous) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (sigaction(signal.id, action, previous) == -1) {
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_signal_action_
+
 #ifndef _di_f_signal_close_
   f_status_t f_signal_close(f_signal_t * const signal) {
     #ifndef _di_level_0_parameter_checking_
@@ -71,6 +88,15 @@ extern "C" {
   }
 #endif // _di_f_signal_open_
 
+#ifndef _di_f_signal_pause_
+  f_status_t f_signal_pause(void) {
+
+    pause();
+
+    return F_none;
+  }
+#endif // _di_f_signal_pause_
+
 #ifndef _di_f_signal_queue_
   f_status_t f_signal_queue(const pid_t id, const int signal, const union sigval value) {
 
@@ -244,6 +270,25 @@ extern "C" {
   }
 #endif // _di_f_signal_set_has_
 
+#ifndef _di_f_signal_suspend_
+  f_status_t f_signal_suspend(const sigset_t * const mask) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!mask) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    const int result = sigsuspend(mask);
+
+    if (result == -1) {
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == EINTR) return F_status_set_error(F_interrupt);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_signal_suspend_
+
 #ifndef _di_f_signal_wait_
   f_status_t f_signal_wait(const sigset_t * const set, siginfo_t * const information) {
 
index 6285271b0a986945e4975412636a78ad8ba0e90b..c868866a324d77d1376b75acf6165adf976e0a4d 100644 (file)
@@ -29,6 +29,33 @@ extern "C" {
 #endif
 
 /**
+ * Get or set the signal action handlers.
+ *
+ * @param signal
+ *   The signal settings.
+ * @param action
+ *   (optional) The signal action to use.
+ *   Set to NULL to not use.
+ *   Both action and previous may not be NULL.
+ * @param previous
+ *   (optional) The previous signal action.
+ *   Set to NULL to not use.
+ *
+ * @return
+ *   F_none on success but no signal found.
+ *
+ *   F_buffer (with error bit) if the buffer is invalid (action or previous point to invalid memory).
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see sigaction()
+ */
+#ifndef _di_f_signal_action_
+  extern f_status_t f_signal_action(const f_signal_t signal, const struct sigaction * const action, struct sigaction *previous);
+#endif // _di_f_signal_action_
+
+/**
  * Close an open signal descriptor.
  *
  * The signal.id is set to 0 on success.
@@ -39,6 +66,7 @@ extern "C" {
  * @return
  *   F_none on success.
  *   F_data_not on success, but no descriptor was provided to close.
+ *
  *   F_descriptor (with error bit) if id is an invalid descriptor.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
  *   F_input_output (with error bit) if an I/O error occurred.
@@ -109,6 +137,18 @@ extern "C" {
 #endif // _di_f_signal_open_
 
 /**
+ * Pause the current process until a signal is received.
+ *
+ * @return
+ *   The received signal.
+ *
+ * @see pause()
+ */
+#ifndef _di_f_signal_pause_
+  extern f_status_t f_signal_pause(void);
+#endif // _di_f_signal_pause_
+
+/**
  * Send the signal and value to the given process.
  *
  * @param id
@@ -297,6 +337,26 @@ extern "C" {
 #endif // _di_f_signal_set_has_
 
 /**
+ * Suspend the current process until one of the provided signals is received.
+ *
+ * @param mask
+ *   The signal mask.
+ *
+ * @return
+ *   F_none on success but no signal found.
+ *
+ *   F_buffer (with error bit) if the mask is pointing to invalid memory.
+ *   F_interrupt (with error bit) when program received an interrupt signal, halting operation.
+ *
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see sigsuspend()
+ */
+#ifndef _di_f_signal_suspend_
+  extern f_status_t f_signal_suspend(const sigset_t * const mask);
+#endif // _di_f_signal_suspend_
+
+/**
  * Wait until any signal in a set of signals is received.
  *
  * @param set
index 7d519758a9acb17538f7dc1f470901d22cf2dfa1..7d16e7ef79c09818f0f9e694391a9379563a9687 100644 (file)
@@ -60,8 +60,10 @@ flags_library -fPIC
 # Inject mocks.
 flags -Wl,--wrap=close
 flags -Wl,--wrap=kill
+flags -Wl,--wrap=pause
 flags -Wl,--wrap=poll
 flags -Wl,--wrap=read
+flags -Wl,--wrap=sigaction
 flags -Wl,--wrap=sigaddset
 flags -Wl,--wrap=sigdelset
 flags -Wl,--wrap=sigemptyset
@@ -70,5 +72,6 @@ flags -Wl,--wrap=sigismember
 flags -Wl,--wrap=signalfd
 flags -Wl,--wrap=sigprocmask
 flags -Wl,--wrap=sigqueue
+flags -Wl,--wrap=sigsuspend
 flags -Wl,--wrap=sigtimedwait
 flags -Wl,--wrap=sigwaitinfo
index bc5af73fe18cace7767c57cb742dec74a370b257..81937d1c0f7cc18dda9cd396b92cae32c3a99e75 100644 (file)
@@ -25,7 +25,7 @@ build_language c
 build_libraries -lc -lcmocka
 build_libraries-individual -lf_memory -lf_string -lf_signal
 
-build_sources_program test-signal-close.c test-signal-mask.c test-signal-open.c test-signal-queue.c test-signal-read.c test-signal-send.c test-signal-set_add.c test-signal-set_delete.c test-signal-set_empty.c test-signal-set_fill.c test-signal-set_has.c test-signal-wait.c test-signal-wait_until.c
+build_sources_program test-signal-action.c test-signal-close.c test-signal-mask.c test-signal-open.c test-signal-pause.c test-signal-queue.c test-signal-read.c test-signal-send.c test-signal-set_add.c test-signal-set_delete.c test-signal-set_empty.c test-signal-set_fill.c test-signal-set_has.c test-signal-suspend.c test-signal-wait.c test-signal-wait_until.c
 build_sources_program test-signal.c
 
 build_script no
index 6bf897874ea73a4f75fb09e97b1bdc3ad3d6a3a1..c6eb63b0624fe138cfb1bafaac50f1f506a029cb 100644 (file)
@@ -4,6 +4,19 @@
 extern "C" {
 #endif
 
+int __wrap_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) {
+
+  const bool failure = mock_type(bool);
+
+  if (failure) {
+    errno = mock_type(int);
+
+    return -1;
+  }
+
+  return 0;
+}
+
 int __wrap_close(int fd) {
 
   const bool failure = mock_type(bool);
@@ -30,6 +43,11 @@ int __wrap_kill(pid_t pid, int sig) {
   return 0;
 }
 
+int __wrap_pause(void) {
+
+  return -1;
+}
+
 int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
 
   const bool failure = mock_type(bool);
@@ -162,6 +180,19 @@ int __wrap_sigqueue(pid_t pid, int sig, const union sigval value) {
   return 0;
 }
 
+int __wrap_sigsuspend(const sigset_t *mask) {
+
+  const bool failure = mock_type(bool);
+
+  if (failure) {
+    errno = mock_type(int);
+
+    return -1;
+  }
+
+  return 0;
+}
+
 int __wrap_sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) {
 
   const bool failure = mock_type(bool);
index 24725779169dd20b49e53eaeca71f4bc7cd81ab5..cd27025621952fb24b85f7840d7a9fb201017d02 100644 (file)
@@ -28,8 +28,10 @@ extern "C" {
 
 const static int mock_errno_generic = 32767;
 
+extern int __wrap_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
 extern int __wrap_close(int fd);
 extern int __wrap_kill(pid_t pid, int sig);
+extern int __wrap_pause(void);
 extern int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout);
 extern ssize_t __wrap_read(int fd, void *buf, size_t count);
 extern int __wrap_sigaddset(sigset_t *set, int signum);
@@ -40,6 +42,7 @@ extern int __wrap_sigismember(const sigset_t *set, int signum);
 extern int __wrap_signalfd(int fd, const sigset_t *mask, int flags);
 extern int __wrap_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
 extern int __wrap_sigqueue(pid_t pid, int sig, const union sigval value);
+extern int __wrap_sigsuspend(const sigset_t *mask);
 extern int __wrap_sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout);
 extern int __wrap_sigwaitinfo(const sigset_t *set, siginfo_t *info);
 
diff --git a/level_0/f_signal/tests/unit/c/test-signal-action.c b/level_0/f_signal/tests/unit/c/test-signal-action.c
new file mode 100644 (file)
index 0000000..5e8ffab
--- /dev/null
@@ -0,0 +1,111 @@
+#include "test-signal.h"
+#include "test-signal-action.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_signal_action__fails(void **state) {
+
+  f_signal_t signal = f_signal_t_initialize;
+
+  struct sigaction action;
+  struct sigaction previous;
+
+  memset(&action, 0, sizeof(struct sigaction));
+  memset(&previous, 0, sizeof(struct sigaction));
+
+  {
+    int errnos[] = {
+      EFAULT,
+      EINVAL,
+      mock_errno_generic,
+    };
+
+    f_status_t statuss[] = {
+      F_buffer,
+      F_parameter,
+      F_failure,
+    };
+
+    for (int i = 0; i < 3; ++i) {
+
+      will_return(__wrap_sigaction, true);
+      will_return(__wrap_sigaction, errnos[i]);
+
+      const f_status_t status = f_signal_action(signal, &action, 0);
+
+      assert_int_equal(status, F_status_set_error(statuss[i]));
+    } // for
+
+    for (int i = 0; i < 3; ++i) {
+
+      will_return(__wrap_sigaction, true);
+      will_return(__wrap_sigaction, errnos[i]);
+
+      const f_status_t status = f_signal_action(signal, 0, &previous);
+
+      assert_int_equal(status, F_status_set_error(statuss[i]));
+    } // for
+
+    for (int i = 0; i < 3; ++i) {
+
+      will_return(__wrap_sigaction, true);
+      will_return(__wrap_sigaction, errnos[i]);
+
+      const f_status_t status = f_signal_action(signal, &action, &previous);
+
+      assert_int_equal(status, F_status_set_error(statuss[i]));
+    } // for
+  }
+}
+
+void test__f_signal_action__parameter_checking(void **state) {
+
+  f_signal_t signal = f_signal_t_initialize;
+
+  {
+    const f_status_t status = f_signal_action(signal, 0, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_signal_action__works(void **state) {
+
+  f_signal_t signal = f_signal_t_initialize;
+
+  struct sigaction action;
+  struct sigaction previous;
+
+  memset(&action, 0, sizeof(struct sigaction));
+  memset(&previous, 0, sizeof(struct sigaction));
+
+  {
+    will_return(__wrap_sigaction, false);
+
+    const f_status_t status = f_signal_action(signal, &action, 0);
+
+    assert_int_equal(status, F_none);
+  }
+
+  {
+    will_return(__wrap_sigaction, false);
+
+    const f_status_t status = f_signal_action(signal, 0, &previous);
+
+    assert_int_equal(status, F_none);
+  }
+
+  {
+    will_return(__wrap_sigaction, false);
+
+    const f_status_t status = f_signal_action(signal, &action, &previous);
+
+    assert_int_equal(status, F_none);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_signal/tests/unit/c/test-signal-action.h b/level_0/f_signal/tests/unit/c/test-signal-action.h
new file mode 100644 (file)
index 0000000..23eda75
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Signal
+ * API Version: 0.6
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the signal project.
+ */
+#ifndef _TEST__F_signal_action_h
+#define _TEST__F_signal_action_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_signal_action()
+ */
+extern void test__f_signal_action__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_signal_action()
+ */
+extern void test__f_signal_action__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_signal_action()
+ */
+extern void test__f_signal_action__works(void **state);
+
+#endif // _TEST__F_signal_action_h
diff --git a/level_0/f_signal/tests/unit/c/test-signal-pause.c b/level_0/f_signal/tests/unit/c/test-signal-pause.c
new file mode 100644 (file)
index 0000000..582616b
--- /dev/null
@@ -0,0 +1,19 @@
+#include "test-signal.h"
+#include "test-signal-pause.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_signal_pause__works(void **state) {
+
+  {
+    const f_status_t status = f_signal_pause();
+
+    assert_int_equal(status, F_none);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_signal/tests/unit/c/test-signal-pause.h b/level_0/f_signal/tests/unit/c/test-signal-pause.h
new file mode 100644 (file)
index 0000000..3a4fd73
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Signal
+ * API Version: 0.6
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the signal project.
+ */
+#ifndef _TEST__F_signal_pause_h
+#define _TEST__F_signal_pause_h
+
+/**
+ * Test that function works.
+ *
+ * @see f_signal_pause()
+ */
+extern void test__f_signal_pause__works(void **state);
+
+#endif // _TEST__F_signal_pause_h
diff --git a/level_0/f_signal/tests/unit/c/test-signal-suspend.c b/level_0/f_signal/tests/unit/c/test-signal-suspend.c
new file mode 100644 (file)
index 0000000..232a465
--- /dev/null
@@ -0,0 +1,65 @@
+#include "test-signal.h"
+#include "test-signal-suspend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_signal_suspend__fails(void **state) {
+
+  sigset_t set;
+
+  memset(&set, 0, sizeof(sigset_t));
+
+  {
+    int errnos[] = {
+      EFAULT,
+      EINTR,
+      mock_errno_generic,
+    };
+
+    f_status_t statuss[] = {
+      F_buffer,
+      F_interrupt,
+      F_failure,
+    };
+
+    for (int i = 0; i < 3; ++i) {
+
+      will_return(__wrap_sigsuspend, true);
+      will_return(__wrap_sigsuspend, errnos[i]);
+
+      const f_status_t status = f_signal_suspend(&set);
+
+      assert_int_equal(status, F_status_set_error(statuss[i]));
+    } // for
+  }
+}
+
+void test__f_signal_suspend__parameter_checking(void **state) {
+
+  {
+    const f_status_t status = f_signal_suspend(0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_signal_suspend__works(void **state) {
+
+  {
+    sigset_t set;
+
+    memset(&set, 0, sizeof(sigset_t));
+
+    will_return(__wrap_sigsuspend, false);
+
+    const f_status_t status = f_signal_suspend(&set);
+
+    assert_int_equal(status, F_none);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_signal/tests/unit/c/test-signal-suspend.h b/level_0/f_signal/tests/unit/c/test-signal-suspend.h
new file mode 100644 (file)
index 0000000..80c0f05
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Signal
+ * API Version: 0.6
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the signal project.
+ */
+#ifndef _TEST__F_signal_suspend_h
+#define _TEST__F_signal_suspend_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_signal_suspend()
+ */
+extern void test__f_signal_suspend__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_signal_suspend()
+ */
+extern void test__f_signal_suspend__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_signal_suspend()
+ */
+extern void test__f_signal_suspend__works(void **state);
+
+#endif // _TEST__F_signal_suspend_h
index c49b5ded02803482182d5eb9a3ba242828aa38be..6e61a621743ac5d3c882facc947127ed6567e4ec 100644 (file)
@@ -19,6 +19,9 @@ int setdown(void **state) {
 int main(void) {
 
   const struct CMUnitTest tests[] = {
+    cmocka_unit_test(test__f_signal_action__fails),
+    cmocka_unit_test(test__f_signal_action__works),
+
     cmocka_unit_test(test__f_signal_close__fails),
     cmocka_unit_test(test__f_signal_close__works),
 
@@ -28,6 +31,8 @@ int main(void) {
     cmocka_unit_test(test__f_signal_open__fails),
     cmocka_unit_test(test__f_signal_open__works),
 
+    cmocka_unit_test(test__f_signal_pause__works),
+
     cmocka_unit_test(test__f_signal_queue__fails),
     cmocka_unit_test(test__f_signal_queue__works),
 
@@ -52,6 +57,9 @@ int main(void) {
     cmocka_unit_test(test__f_signal_set_has__fails),
     cmocka_unit_test(test__f_signal_set_has__works),
 
+    cmocka_unit_test(test__f_signal_suspend__fails),
+    cmocka_unit_test(test__f_signal_suspend__works),
+
     cmocka_unit_test(test__f_signal_wait__fails),
     cmocka_unit_test(test__f_signal_wait__works),
 
@@ -59,9 +67,11 @@ int main(void) {
     cmocka_unit_test(test__f_signal_wait_until__works),
 
     #ifndef _di_level_0_parameter_checking_
+      cmocka_unit_test(test__f_signal_action__parameter_checking),
       cmocka_unit_test(test__f_signal_close__parameter_checking),
       cmocka_unit_test(test__f_signal_mask__parameter_checking),
       cmocka_unit_test(test__f_signal_open__parameter_checking),
+      // f_signal_pause() doesn't use parameter checking.
       // f_signal_queue() doesn't use parameter checking.
       cmocka_unit_test(test__f_signal_read__parameter_checking),
       // f_signal_send() doesn't use parameter checking.
@@ -70,6 +80,7 @@ int main(void) {
       cmocka_unit_test(test__f_signal_set_empty__parameter_checking),
       cmocka_unit_test(test__f_signal_set_fill__parameter_checking),
       cmocka_unit_test(test__f_signal_set_has__parameter_checking),
+      cmocka_unit_test(test__f_signal_suspend__parameter_checking),
       // f_signal_wait() doesn't use parameter checking.
       // f_signal_wait_until() doesn't use parameter checking.
     #endif // _di_level_0_parameter_checking_
index 51b7023d7ffacdff8e4d3354a4c237f0c51e959d..b37e83ef362705952243d486805bd726396fbbf7 100644 (file)
 #include "mock-signal.h"
 
 // Test includes.
+#include "test-signal-action.h"
 #include "test-signal-close.h"
 #include "test-signal-mask.h"
 #include "test-signal-open.h"
+#include "test-signal-pause.h"
 #include "test-signal-queue.h"
 #include "test-signal-read.h"
 #include "test-signal-send.h"
@@ -37,6 +39,7 @@
 #include "test-signal-set_empty.h"
 #include "test-signal-set_fill.h"
 #include "test-signal-set_has.h"
+#include "test-signal-suspend.h"
 #include "test-signal-wait.h"
 #include "test-signal-wait_until.h"