Make signalfd wrapper more robust

I realized afterwards it's only used in tests, but whatever.

Change-Id: I23f654a0119faefec6a3888dc7d7c8ba38cf1b4f
diff --git a/aos/ipc_lib/signalfd_test.cc b/aos/ipc_lib/signalfd_test.cc
new file mode 100644
index 0000000..b4fe74b
--- /dev/null
+++ b/aos/ipc_lib/signalfd_test.cc
@@ -0,0 +1,76 @@
+#include "aos/ipc_lib/signalfd.h"
+
+#include "gtest/gtest.h"
+#include "glog/logging.h"
+#include "aos/testing/test_logging.h"
+
+namespace aos {
+namespace ipc_lib {
+namespace testing {
+
+// Tests in this file use separate threads to isolate all manipulation of signal
+// masks between test cases.
+
+// Verify that SignalFd will leave signals unblocked if we ask it to.
+TEST(SignalFdTest, LeaveSignalBlocked) {
+  ::aos::testing::EnableTestLogging();
+  std::thread thread([]() {
+    {
+      sigset_t test_mask;
+      CHECK_EQ(0, sigemptyset(&test_mask));
+      CHECK_EQ(0, sigaddset(&test_mask, SIGUSR1));
+      PCHECK(sigprocmask(SIG_BLOCK, &test_mask, nullptr) == 0);
+    }
+    SignalFd({SIGUSR1});
+    {
+      sigset_t blocked_now;
+      PCHECK(sigprocmask(SIG_BLOCK, nullptr, &blocked_now) == 0);
+      ASSERT_TRUE(sigismember(&blocked_now, SIGUSR1));
+    }
+  });
+  thread.join();
+}
+
+// Verify that SignalFd actually blocks the requested signals, and unblocks them
+// afterwards.
+TEST(SignalFdTest, BlockSignal) {
+  ::aos::testing::EnableTestLogging();
+  std::thread thread([]() {
+    {
+      sigset_t blocked_now;
+      PCHECK(sigprocmask(SIG_BLOCK, nullptr, &blocked_now) == 0);
+      ASSERT_FALSE(sigismember(&blocked_now, SIGUSR1));
+    }
+    {
+      SignalFd signalfd({SIGUSR1});
+      sigset_t blocked_now;
+      PCHECK(sigprocmask(SIG_BLOCK, nullptr, &blocked_now) == 0);
+      ASSERT_TRUE(sigismember(&blocked_now, SIGUSR1));
+    }
+    {
+      sigset_t blocked_now;
+      PCHECK(sigprocmask(SIG_BLOCK, nullptr, &blocked_now) == 0);
+      ASSERT_FALSE(sigismember(&blocked_now, SIGUSR1));
+    }
+  });
+  thread.join();
+}
+
+// Verify that SignalFd responds correctly when some other code unblocks one of
+// its signals.
+TEST(SignalFdDeathTest, ExternalUnblockSignal) {
+  ::aos::testing::EnableTestLogging();
+  EXPECT_DEATH(
+      {
+        SignalFd signalfd({SIGUSR1});
+        sigset_t test_mask;
+        CHECK_EQ(0, sigemptyset(&test_mask));
+        CHECK_EQ(0, sigaddset(&test_mask, SIGUSR1));
+        PCHECK(sigprocmask(SIG_UNBLOCK, &test_mask, nullptr) == 0);
+      },
+      "Some other code unblocked one or more of our signals");
+}
+
+}  // namespace testing
+}  // namespace ipc_lib
+}  // namespace aos