init: Introduce Epoll::SetFirstCallback()

Prepare for optimizing Epoll::Wait() by moving the
ReapAnyOutstandingChildren() call into Epoll::Wait(). No functionality
is changed.

Bug: 213617178
Change-Id: I280ea0069ed29cf323e4177ec500b30b900f7c8d
Signed-off-by: Bart Van Assche <bvanassche@google.com>
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 0580f86..24d356d 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -75,6 +75,10 @@
     return {};
 }
 
+void Epoll::SetFirstCallback(std::function<void()> first_callback) {
+    first_callback_ = std::move(first_callback);
+}
+
 Result<std::vector<std::shared_ptr<Epoll::Handler>>> Epoll::Wait(
         std::optional<std::chrono::milliseconds> timeout) {
     int timeout_ms = -1;
@@ -87,6 +91,9 @@
     if (num_events == -1) {
         return ErrnoError() << "epoll_wait failed";
     }
+    if (num_events > 0 && first_callback_) {
+        first_callback_();
+    }
     std::vector<std::shared_ptr<Handler>> pending_functions;
     for (int i = 0; i < num_events; ++i) {
         auto& info = *reinterpret_cast<Info*>(ev[i].data.ptr);
diff --git a/init/epoll.h b/init/epoll.h
index f58ae8d..e26e319 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -42,6 +42,7 @@
     Result<void> Open();
     Result<void> RegisterHandler(int fd, Handler handler, uint32_t events = EPOLLIN);
     Result<void> UnregisterHandler(int fd);
+    void SetFirstCallback(std::function<void()> first_callback);
     Result<std::vector<std::shared_ptr<Handler>>> Wait(
             std::optional<std::chrono::milliseconds> timeout);
 
@@ -53,6 +54,7 @@
 
     android::base::unique_fd epoll_fd_;
     std::map<int, Info> epoll_handlers_;
+    std::function<void()> first_callback_;
 };
 
 }  // namespace init
diff --git a/init/init.cpp b/init/init.cpp
index ce668d7..cd0ee58 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -1061,6 +1061,11 @@
         PLOG(FATAL) << result.error();
     }
 
+    // We always reap children before responding to the other pending functions. This is to
+    // prevent a race where other daemons see that a service has exited and ask init to
+    // start it again via ctl.start before init has reaped it.
+    epoll.SetFirstCallback(ReapAnyOutstandingChildren);
+
     InstallSignalFdHandler(&epoll);
     InstallInitNotifier(&epoll);
     StartPropertyService(&property_fd);
@@ -1176,10 +1181,6 @@
         if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
         } else if (!pending_functions->empty()) {
-            // We always reap children before responding to the other pending functions. This is to
-            // prevent a race where other daemons see that a service has exited and ask init to
-            // start it again via ctl.start before init has reaped it.
-            ReapAnyOutstandingChildren();
             for (const auto& function : *pending_functions) {
                 (*function)();
             }