auto import from //depot/cupcake/@135843
diff --git a/libcutils/selector.c b/libcutils/selector.c
new file mode 100644
index 0000000..9436393
--- /dev/null
+++ b/libcutils/selector.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "selector"
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/array.h>
+#include <cutils/selector.h>
+
+#include "loghack.h"
+
+struct Selector {
+    Array* selectableFds;
+    bool looping;
+    fd_set readFds;
+    fd_set writeFds;
+    fd_set exceptFds;
+    int maxFd;
+    int wakeupPipe[2];
+    SelectableFd* wakeupFd;
+
+    bool inSelect;
+    pthread_mutex_t inSelectLock; 
+};
+
+/** Reads and ignores wake up data. */ 
+static void eatWakeupData(SelectableFd* wakeupFd) {
+    static char garbage[64];
+    if (read(wakeupFd->fd, garbage, sizeof(garbage)) < 0) {
+        if (errno == EINTR) {
+            LOGI("read() interrupted.");    
+        } else {
+            LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
+        }
+    }
+}
+
+static void setInSelect(Selector* selector, bool inSelect) {
+    pthread_mutex_lock(&selector->inSelectLock);
+    selector->inSelect = inSelect;
+    pthread_mutex_unlock(&selector->inSelectLock);
+}
+
+static bool isInSelect(Selector* selector) {
+    pthread_mutex_lock(&selector->inSelectLock);
+    bool inSelect = selector->inSelect;
+    pthread_mutex_unlock(&selector->inSelectLock);
+    return inSelect;
+}
+
+void selectorWakeUp(Selector* selector) {
+    if (!isInSelect(selector)) {
+        // We only need to write wake-up data if we're blocked in select().
+        return;
+    }
+    
+    static char garbage[1];
+    if (write(selector->wakeupPipe[1], garbage, sizeof(garbage)) < 0) {
+        if (errno == EINTR) {
+            LOGI("read() interrupted.");    
+        } else {
+            LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
+        }
+    }
+}
+
+Selector* selectorCreate(void) {
+    Selector* selector = calloc(1, sizeof(Selector));
+    if (selector == NULL) {
+        LOG_ALWAYS_FATAL("malloc() error.");
+    }
+    selector->selectableFds = arrayCreate();
+    
+    // Set up wake-up pipe.
+    if (pipe(selector->wakeupPipe) < 0) {
+        LOG_ALWAYS_FATAL("pipe() error: %s", strerror(errno));
+    }
+    
+    LOGD("Wakeup fd: %d", selector->wakeupPipe[0]);
+    
+    SelectableFd* wakeupFd = selectorAdd(selector, selector->wakeupPipe[0]);
+    if (wakeupFd == NULL) {
+        LOG_ALWAYS_FATAL("malloc() error.");
+    }
+    wakeupFd->onReadable = &eatWakeupData; 
+    
+    pthread_mutex_init(&selector->inSelectLock, NULL);
+
+    return selector;
+}
+
+SelectableFd* selectorAdd(Selector* selector, int fd) {
+    assert(selector != NULL);
+
+    SelectableFd* selectableFd = calloc(1, sizeof(SelectableFd));
+    if (selectableFd != NULL) {
+        selectableFd->selector = selector;
+        selectableFd->fd = fd;
+    
+        arrayAdd(selector->selectableFds, selectableFd);
+    }
+
+    return selectableFd;
+}
+
+/**
+ * Adds an fd to the given set if the callback is non-null. Returns true
+ * if the fd was added.
+ */
+static inline bool maybeAdd(SelectableFd* selectableFd,
+        void (*callback)(SelectableFd*), fd_set* fdSet) {
+    if (callback != NULL) {
+        FD_SET(selectableFd->fd, fdSet);
+        return true;
+    }
+    return false;
+}
+
+/**
+ * Removes stale file descriptors and initializes file descriptor sets.
+ */
+static void prepareForSelect(Selector* selector) {
+    fd_set* exceptFds = &selector->exceptFds;
+    fd_set* readFds = &selector->readFds;
+    fd_set* writeFds = &selector->writeFds;
+    
+    FD_ZERO(exceptFds);
+    FD_ZERO(readFds);
+    FD_ZERO(writeFds);
+
+    Array* selectableFds = selector->selectableFds;
+    int i = 0;
+    selector->maxFd = 0;
+    int size = arraySize(selectableFds);
+    while (i < size) {
+        SelectableFd* selectableFd = arrayGet(selectableFds, i);
+        if (selectableFd->remove) {
+            // This descriptor should be removed.
+            arrayRemove(selectableFds, i);
+            size--;
+            if (selectableFd->onRemove != NULL) {
+                selectableFd->onRemove(selectableFd);
+            }
+            free(selectableFd);
+        } else {
+            if (selectableFd->beforeSelect != NULL) {
+                selectableFd->beforeSelect(selectableFd);
+            }
+            
+            bool inSet = false;
+            if (maybeAdd(selectableFd, selectableFd->onExcept, exceptFds)) {
+            	LOGD("Selecting fd %d for writing...", selectableFd->fd);
+                inSet = true;
+            }
+            if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
+            	LOGD("Selecting fd %d for reading...", selectableFd->fd);
+                inSet = true;
+            }
+            if (maybeAdd(selectableFd, selectableFd->onWritable, writeFds)) {
+                inSet = true;
+            }
+
+            if (inSet) {
+                // If the fd is in a set, check it against max.
+                int fd = selectableFd->fd;
+                if (fd > selector->maxFd) {
+                    selector->maxFd = fd;
+                }
+            }
+            
+            // Move to next descriptor.
+            i++;
+        }
+    }
+}
+
+/**
+ * Invokes a callback if the callback is non-null and the fd is in the given
+ * set.
+ */
+static inline void maybeInvoke(SelectableFd* selectableFd,
+        void (*callback)(SelectableFd*), fd_set* fdSet) {
+	if (callback != NULL && !selectableFd->remove && 
+            FD_ISSET(selectableFd->fd, fdSet)) {
+		LOGD("Selected fd %d.", selectableFd->fd);
+        callback(selectableFd);
+    }
+}
+
+/**
+ * Notifies user if file descriptors are readable or writable, or if
+ * out-of-band data is present.
+ */
+static void fireEvents(Selector* selector) {
+    Array* selectableFds = selector->selectableFds;
+    int size = arraySize(selectableFds);
+    int i;
+    for (i = 0; i < size; i++) {
+        SelectableFd* selectableFd = arrayGet(selectableFds, i);
+        maybeInvoke(selectableFd, selectableFd->onExcept,
+                &selector->exceptFds);
+        maybeInvoke(selectableFd, selectableFd->onReadable,
+                &selector->readFds);
+        maybeInvoke(selectableFd, selectableFd->onWritable,
+                &selector->writeFds);
+    }
+}
+
+void selectorLoop(Selector* selector) {
+    // Make sure we're not already looping.
+    if (selector->looping) {
+        LOG_ALWAYS_FATAL("Already looping.");
+    }
+    selector->looping = true;
+    
+    while (true) {
+        setInSelect(selector, true);
+        
+        prepareForSelect(selector);
+
+        LOGD("Entering select().");
+        
+        // Select file descriptors.
+        int result = select(selector->maxFd + 1, &selector->readFds, 
+                &selector->writeFds, &selector->exceptFds, NULL);
+        
+        LOGD("Exiting select().");
+        
+        setInSelect(selector, false);
+        
+        if (result == -1) {
+            // Abort on everything except EINTR.
+            if (errno == EINTR) {
+                LOGI("select() interrupted.");    
+            } else {
+                LOG_ALWAYS_FATAL("select() error: %s", 
+                        strerror(errno));
+            }
+        } else if (result > 0) {
+            fireEvents(selector);
+        }
+    }
+}