Switch init to epoll.

Not just because it's what the cool kids are doing --- it also lets us
simplify the inner loop and decouple it from whatever systems want to
be woken to perform some activity if there's data to be read on some fd.

Currently this is just used to clean up the existing signal handling,
keychord, and property service code.

Change-Id: I4d7541a2c4386957ad877df69e3be08b96a7dec5
diff --git a/init/init.cpp b/init/init.cpp
index 4ed23b6..90cbea0 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -25,8 +25,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/epoll.h>
 #include <sys/mount.h>
-#include <sys/poll.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -82,6 +82,17 @@
 
 bool waiting_for_exec = false;
 
+static int epoll_fd = -1;
+
+void register_epoll_handler(int fd, void (*fn)()) {
+    epoll_event ev;
+    ev.events = EPOLLIN;
+    ev.data.ptr = reinterpret_cast<void*>(fn);
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        ERROR("epoll_ctl failed: %s\n", strerror(errno));
+    }
+}
+
 void service::NotifyStateChange(const char* new_state) {
     if (!properties_initialized()) {
         // If properties aren't available yet, we can't set them.
@@ -1037,7 +1048,13 @@
     restorecon("/dev/__properties__");
     restorecon_recursive("/sys");
 
-    signal_init();
+    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+    if (epoll_fd == -1) {
+        ERROR("epoll_create1 failed: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    signal_handler_init();
 
     property_load_boot_defaults();
     start_property_service();
@@ -1071,27 +1088,12 @@
     // Run all property triggers based on current state of the properties.
     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
 
-    size_t fd_count = 0;
-    struct pollfd ufds[3];
-    ufds[fd_count++] = { .fd = get_signal_fd(), .events = POLLIN, .revents = 0 };
-    ufds[fd_count++] = { .fd = get_property_set_fd(), .events = POLLIN, .revents = 0 };
-    // TODO: can we work out when /dev/keychord is first accessible and open this fd then?
-    bool keychord_fd_init = false;
-
     while (true) {
         if (!waiting_for_exec) {
             execute_one_command();
             restart_processes();
         }
 
-        if (!keychord_fd_init && get_keychord_fd() > 0) {
-            ufds[fd_count].fd = get_keychord_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            keychord_fd_init = true;
-        }
-
         int timeout = -1;
         if (process_needs_restart) {
             timeout = (process_needs_restart - gettime()) * 1000;
@@ -1105,24 +1107,12 @@
 
         bootchart_sample(&timeout);
 
-        int nr = TEMP_FAILURE_RETRY(poll(ufds, fd_count, timeout));
-        if (nr <= 0) {
-            if (nr == -1) {
-                ERROR("poll failed: %s\n", strerror(errno));
-            }
-            continue;
-        }
-
-        for (size_t i = 0; i < fd_count; i++) {
-            if (ufds[i].revents & POLLIN) {
-                if (ufds[i].fd == get_property_set_fd()) {
-                    handle_property_set_fd();
-                } else if (ufds[i].fd == get_keychord_fd()) {
-                    handle_keychord();
-                } else if (ufds[i].fd == get_signal_fd()) {
-                    handle_signal();
-                }
-            }
+        epoll_event ev;
+        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+        if (nr == -1) {
+            ERROR("epoll_wait failed: %s\n", strerror(errno));
+        } else if (nr == 1) {
+            ((void (*)()) ev.data.ptr)();
         }
     }
 
diff --git a/init/init.h b/init/init.h
index a104af6..1cabb14 100644
--- a/init/init.h
+++ b/init/init.h
@@ -155,4 +155,6 @@
 
 void zap_stdio(void);
 
+void register_epoll_handler(int fd, void (*fn)());
+
 #endif	/* _INIT_INIT_H */
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 27894a2..10d9573 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -62,37 +62,7 @@
     }
 }
 
-void keychord_init()
-{
-    int fd, ret;
-
-    service_for_each(add_service_keycodes);
-
-    /* nothing to do if no services require keychords */
-    if (!keychords)
-        return;
-
-    fd = open("/dev/keychord", O_RDWR | O_CLOEXEC);
-    if (fd < 0) {
-        ERROR("could not open /dev/keychord\n");
-        return;
-    }
-
-    ret = write(fd, keychords, keychords_length);
-    if (ret != keychords_length) {
-        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
-        close(fd);
-        fd = -1;
-    }
-
-    free(keychords);
-    keychords = 0;
-
-    keychord_fd = fd;
-}
-
-void handle_keychord()
-{
+static void handle_keychord() {
     struct service *svc;
     char adb_enabled[PROP_VALUE_MAX];
     int ret;
@@ -117,7 +87,28 @@
     }
 }
 
-int get_keychord_fd()
-{
-    return keychord_fd;
+void keychord_init() {
+    service_for_each(add_service_keycodes);
+
+    // Nothing to do if no services require keychords.
+    if (!keychords) {
+        return;
+    }
+
+    keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
+    if (keychord_fd == -1) {
+        ERROR("could not open /dev/keychord: %s\n", strerror(errno));
+        return;
+    }
+
+    int ret = write(keychord_fd, keychords, keychords_length);
+    if (ret != keychords_length) {
+        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
+        close(keychord_fd);
+    }
+
+    free(keychords);
+    keychords = nullptr;
+
+    register_epoll_handler(keychord_fd, handle_keychord);
 }
diff --git a/init/keychords.h b/init/keychords.h
index 070b858..d2723b7 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -19,9 +19,7 @@
 
 struct service;
 
-void add_service_keycodes(struct service *svc);
-void keychord_init(void);
-void handle_keychord(void);
-int get_keychord_fd(void);
+void add_service_keycodes(service*);
+void keychord_init();
 
 #endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 94c5fd9..930ef82 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -246,7 +246,7 @@
     return rc;
 }
 
-void handle_property_set_fd()
+static void handle_property_set_fd()
 {
     prop_msg msg;
     int s;
@@ -527,8 +527,6 @@
     }
 
     listen(property_set_fd, 8);
-}
 
-int get_property_set_fd() {
-    return property_set_fd;
+    register_epoll_handler(property_set_fd, handle_property_set_fd);
 }
diff --git a/init/property_service.h b/init/property_service.h
index 825a7dd..a27053d 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -20,7 +20,6 @@
 #include <stddef.h>
 #include <sys/system_properties.h>
 
-extern void handle_property_set_fd(void);
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
@@ -30,7 +29,6 @@
 extern int __property_get(const char *name, char *value);
 extern int property_set(const char *name, const char *value);
 extern bool properties_initialized();
-int get_property_set_fd(void);
 
 #ifndef __clang__
 extern void __property_get_size_error()
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 37d21bc..39a466d 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -147,7 +147,7 @@
     }
 }
 
-void handle_signal() {
+static void handle_signal() {
     // Clear outstanding requests.
     char buf[32];
     read(signal_read_fd, buf, sizeof(buf));
@@ -161,7 +161,7 @@
     }
 }
 
-void signal_init() {
+void signal_handler_init() {
     // Create a signalling mechanism for SIGCHLD.
     int s[2];
     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
@@ -180,8 +180,6 @@
     sigaction(SIGCHLD, &act, 0);
 
     reap_any_outstanding_children();
-}
 
-int get_signal_fd() {
-    return signal_read_fd;
+    register_epoll_handler(signal_read_fd, handle_signal);
 }
diff --git a/init/signal_handler.h b/init/signal_handler.h
index b092ccb..449b4af 100644
--- a/init/signal_handler.h
+++ b/init/signal_handler.h
@@ -17,8 +17,6 @@
 #ifndef _INIT_SIGNAL_HANDLER_H_
 #define _INIT_SIGNAL_HANDLER_H_
 
-void signal_init(void);
-void handle_signal(void);
-int get_signal_fd(void);
+void signal_handler_init(void);
 
 #endif