summaryrefslogtreecommitdiffstats
path: root/libcutils/selector.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcutils/selector.c')
-rw-r--r--libcutils/selector.c263
1 files changed, 0 insertions, 263 deletions
diff --git a/libcutils/selector.c b/libcutils/selector.c
deleted file mode 100644
index 3776bbb..0000000
--- a/libcutils/selector.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * 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) {
- ALOGI("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) {
- ALOGI("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));
- }
-
- ALOGD("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)) {
- ALOGD("Selecting fd %d for writing...", selectableFd->fd);
- inSet = true;
- }
- if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
- ALOGD("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)) {
- ALOGD("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);
-
- ALOGD("Entering select().");
-
- // Select file descriptors.
- int result = select(selector->maxFd + 1, &selector->readFds,
- &selector->writeFds, &selector->exceptFds, NULL);
-
- ALOGD("Exiting select().");
-
- setInSelect(selector, false);
-
- if (result == -1) {
- // Abort on everything except EINTR.
- if (errno == EINTR) {
- ALOGI("select() interrupted.");
- } else {
- LOG_ALWAYS_FATAL("select() error: %s",
- strerror(errno));
- }
- } else if (result > 0) {
- fireEvents(selector);
- }
- }
-}