Support multiple on_change callbacks in subprocess

Also, refactor to not require an EventLoop object.

Change-Id: I346d9cee1fe60e8ade8e527c09df031aa3c3cc39
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/starter/subprocess.cc b/aos/starter/subprocess.cc
index b7a1cf6..b1320f4 100644
--- a/aos/starter/subprocess.cc
+++ b/aos/starter/subprocess.cc
@@ -77,15 +77,24 @@
 
 SignalListener::SignalListener(aos::ShmEventLoop *loop,
                                std::function<void(signalfd_siginfo)> callback)
-    : SignalListener(loop, callback,
+    : SignalListener(loop->epoll(), std::move(callback)) {}
+
+SignalListener::SignalListener(aos::internal::EPoll *epoll,
+                               std::function<void(signalfd_siginfo)> callback)
+    : SignalListener(epoll, callback,
                      {SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,
                       SIGPIPE, SIGTERM, SIGBUS, SIGXCPU, SIGCHLD}) {}
 
 SignalListener::SignalListener(aos::ShmEventLoop *loop,
                                std::function<void(signalfd_siginfo)> callback,
                                std::initializer_list<unsigned int> signals)
-    : loop_(loop), callback_(std::move(callback)), signalfd_(signals) {
-  loop->epoll()->OnReadable(signalfd_.fd(), [this] {
+    : SignalListener(loop->epoll(), std::move(callback), std::move(signals)) {}
+
+SignalListener::SignalListener(aos::internal::EPoll *epoll,
+                               std::function<void(signalfd_siginfo)> callback,
+                               std::initializer_list<unsigned int> signals)
+    : epoll_(epoll), callback_(std::move(callback)), signalfd_(signals) {
+  epoll_->OnReadable(signalfd_.fd(), [this] {
     signalfd_siginfo info = signalfd_.Read();
 
     if (info.ssi_signo == 0) {
@@ -97,7 +106,7 @@
   });
 }
 
-SignalListener::~SignalListener() { loop_->epoll()->DeleteFd(signalfd_.fd()); }
+SignalListener::~SignalListener() { epoll_->DeleteFd(signalfd_.fd()); }
 
 Application::Application(std::string_view name,
                          std::string_view executable_name,
@@ -123,7 +132,7 @@
       pipe_timer_(event_loop_->AddTimer([this]() { FetchOutputs(); })),
       child_status_handler_(
           event_loop_->AddTimer([this]() { MaybeHandleSignal(); })),
-      on_change_(on_change),
+      on_change_({on_change}),
       quiet_flag_(quiet_flag) {
   event_loop_->OnRun([this]() {
     // Every second poll to check if the child is dead. This is used as a
@@ -205,7 +214,7 @@
       stdout_pipes_.write.reset();
       stderr_pipes_.write.reset();
     }
-    on_change_();
+    OnChange();
     return;
   }
 
@@ -343,7 +352,7 @@
       stop_timer_->Schedule(event_loop_->monotonic_now() +
                             std::chrono::seconds(1));
       queue_restart_ = restart;
-      on_change_();
+      OnChange();
       break;
     }
     case aos::starter::State::WAITING: {
@@ -354,7 +363,7 @@
         DoStart();
       } else {
         status_ = aos::starter::State::STOPPED;
-        on_change_();
+        OnChange();
       }
       break;
     }
@@ -384,7 +393,7 @@
                            std::chrono::seconds(3));
   start_timer_->Disable();
   stop_timer_->Disable();
-  on_change_();
+  OnChange();
 }
 
 std::vector<char *> Application::CArgs() {
@@ -553,7 +562,7 @@
         QueueStart();
       } else {
         status_ = aos::starter::State::STOPPED;
-        on_change_();
+        OnChange();
       }
       break;
     }
@@ -571,7 +580,7 @@
         QueueStart();
       } else {
         status_ = aos::starter::State::STOPPED;
-        on_change_();
+        OnChange();
       }
       break;
     }
@@ -584,7 +593,7 @@
       // Disable force stop timer since the process already died
       stop_timer_->Disable();
 
-      on_change_();
+      OnChange();
       if (terminating_) {
         return true;
       }
@@ -606,4 +615,10 @@
   return false;
 }
 
+void Application::OnChange() {
+  for (auto &fn : on_change_) {
+    fn();
+  }
+}
+
 }  // namespace aos::starter
diff --git a/aos/starter/subprocess.h b/aos/starter/subprocess.h
index 60732c3..ff62117 100644
--- a/aos/starter/subprocess.h
+++ b/aos/starter/subprocess.h
@@ -21,14 +21,19 @@
  public:
   SignalListener(aos::ShmEventLoop *loop,
                  std::function<void(signalfd_siginfo)> callback);
+  SignalListener(aos::internal::EPoll *epoll,
+                 std::function<void(signalfd_siginfo)> callback);
   SignalListener(aos::ShmEventLoop *loop,
                  std::function<void(signalfd_siginfo)> callback,
                  std::initializer_list<unsigned int> signals);
+  SignalListener(aos::internal::EPoll *epoll,
+                 std::function<void(signalfd_siginfo)> callback,
+                 std::initializer_list<unsigned int> signals);
 
   ~SignalListener();
 
  private:
-  aos::ShmEventLoop *loop_;
+  aos::internal::EPoll *epoll_;
   std::function<void(signalfd_siginfo)> callback_;
   aos::ipc_lib::SignalFd signalfd_;
 
@@ -91,6 +96,13 @@
 
   void Terminate();
 
+  // Adds a callback which gets notified when the application changes state.
+  // This is in addition to any existing callbacks and doesn't replace any of
+  // them.
+  void AddOnChange(std::function<void()> fn) {
+    on_change_.emplace_back(std::move(fn));
+  }
+
   void set_args(std::vector<std::string> args);
   void set_capture_stdout(bool capture);
   void set_capture_stderr(bool capture);
@@ -127,6 +139,8 @@
 
   void QueueStart();
 
+  void OnChange();
+
   // Copy flatbuffer vector of strings to vector of std::string.
   static std::vector<std::string> FbsVectorToVector(
       const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> &v);
@@ -178,7 +192,7 @@
   aos::TimerHandler *start_timer_, *restart_timer_, *stop_timer_, *pipe_timer_,
       *child_status_handler_;
 
-  std::function<void()> on_change_;
+  std::vector<std::function<void()>> on_change_;
 
   std::unique_ptr<MemoryCGroup> memory_cgroup_;