1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define LOG_TAG "selector"
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <assert.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <pthread.h>
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/types.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/array.h>
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/selector.h>
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "loghack.h"
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct Selector {
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Array* selectableFds;
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool looping;
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd_set readFds;
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd_set writeFds;
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd_set exceptFds;
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int maxFd;
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int wakeupPipe[2];
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* wakeupFd;
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool inSelect;
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_t inSelectLock;
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Reads and ignores wake up data. */
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void eatWakeupData(SelectableFd* wakeupFd) {
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    static char garbage[64];
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (read(wakeupFd->fd, garbage, sizeof(garbage)) < 0) {
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (errno == EINTR) {
51fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block            ALOGI("read() interrupted.");
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void setInSelect(Selector* selector, bool inSelect) {
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_lock(&selector->inSelectLock);
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    selector->inSelect = inSelect;
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_unlock(&selector->inSelectLock);
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool isInSelect(Selector* selector) {
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_lock(&selector->inSelectLock);
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool inSelect = selector->inSelect;
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_unlock(&selector->inSelectLock);
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return inSelect;
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid selectorWakeUp(Selector* selector) {
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!isInSelect(selector)) {
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // We only need to write wake-up data if we're blocked in select().
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    static char garbage[1];
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (write(selector->wakeupPipe[1], garbage, sizeof(garbage)) < 0) {
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (errno == EINTR) {
80fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block            ALOGI("read() interrupted.");
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source ProjectSelector* selectorCreate(void) {
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Selector* selector = calloc(1, sizeof(Selector));
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (selector == NULL) {
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() error.");
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    selector->selectableFds = arrayCreate();
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Set up wake-up pipe.
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (pipe(selector->wakeupPipe) < 0) {
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("pipe() error: %s", strerror(errno));
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
998d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Wakeup fd: %d", selector->wakeupPipe[0]);
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* wakeupFd = selectorAdd(selector, selector->wakeupPipe[0]);
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (wakeupFd == NULL) {
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() error.");
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    wakeupFd->onReadable = &eatWakeupData;
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_init(&selector->inSelectLock, NULL);
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return selector;
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source ProjectSelectableFd* selectorAdd(Selector* selector, int fd) {
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    assert(selector != NULL);
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* selectableFd = calloc(1, sizeof(SelectableFd));
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (selectableFd != NULL) {
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        selectableFd->selector = selector;
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        selectableFd->fd = fd;
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        arrayAdd(selector->selectableFds, selectableFd);
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return selectableFd;
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Adds an fd to the given set if the callback is non-null. Returns true
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * if the fd was added.
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic inline bool maybeAdd(SelectableFd* selectableFd,
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        void (*callback)(SelectableFd*), fd_set* fdSet) {
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (callback != NULL) {
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        FD_SET(selectableFd->fd, fdSet);
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return true;
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return false;
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Removes stale file descriptors and initializes file descriptor sets.
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void prepareForSelect(Selector* selector) {
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd_set* exceptFds = &selector->exceptFds;
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd_set* readFds = &selector->readFds;
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd_set* writeFds = &selector->writeFds;
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    FD_ZERO(exceptFds);
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    FD_ZERO(readFds);
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    FD_ZERO(writeFds);
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Array* selectableFds = selector->selectableFds;
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i = 0;
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    selector->maxFd = 0;
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int size = arraySize(selectableFds);
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (i < size) {
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        SelectableFd* selectableFd = arrayGet(selectableFds, i);
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (selectableFd->remove) {
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // This descriptor should be removed.
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            arrayRemove(selectableFds, i);
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            size--;
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (selectableFd->onRemove != NULL) {
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                selectableFd->onRemove(selectableFd);
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            free(selectableFd);
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (selectableFd->beforeSelect != NULL) {
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                selectableFd->beforeSelect(selectableFd);
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            bool inSet = false;
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (maybeAdd(selectableFd, selectableFd->onExcept, exceptFds)) {
1728d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block                ALOGD("Selecting fd %d for writing...", selectableFd->fd);
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                inSet = true;
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
1768d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block                ALOGD("Selecting fd %d for reading...", selectableFd->fd);
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                inSet = true;
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (maybeAdd(selectableFd, selectableFd->onWritable, writeFds)) {
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                inSet = true;
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (inSet) {
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                // If the fd is in a set, check it against max.
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                int fd = selectableFd->fd;
186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (fd > selector->maxFd) {
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    selector->maxFd = fd;
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // Move to next descriptor.
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            i++;
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Invokes a callback if the callback is non-null and the fd is in the given
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * set.
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic inline void maybeInvoke(SelectableFd* selectableFd,
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        void (*callback)(SelectableFd*), fd_set* fdSet) {
2038d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    if (callback != NULL && !selectableFd->remove &&
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            FD_ISSET(selectableFd->fd, fdSet)) {
2058d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Selected fd %d.", selectableFd->fd);
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        callback(selectableFd);
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Notifies user if file descriptors are readable or writable, or if
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * out-of-band data is present.
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void fireEvents(Selector* selector) {
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Array* selectableFds = selector->selectableFds;
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int size = arraySize(selectableFds);
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (i = 0; i < size; i++) {
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        SelectableFd* selectableFd = arrayGet(selectableFds, i);
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        maybeInvoke(selectableFd, selectableFd->onExcept,
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                &selector->exceptFds);
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        maybeInvoke(selectableFd, selectableFd->onReadable,
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                &selector->readFds);
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        maybeInvoke(selectableFd, selectableFd->onWritable,
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                &selector->writeFds);
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid selectorLoop(Selector* selector) {
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make sure we're not already looping.
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (selector->looping) {
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("Already looping.");
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    selector->looping = true;
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (true) {
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        setInSelect(selector, true);
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        prepareForSelect(selector);
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2418d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Entering select().");
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Select file descriptors.
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        int result = select(selector->maxFd + 1, &selector->readFds,
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                &selector->writeFds, &selector->exceptFds, NULL);
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2478d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Exiting select().");
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        setInSelect(selector, false);
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (result == -1) {
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // Abort on everything except EINTR.
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (errno == EINTR) {
254fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block                ALOGI("select() interrupted.");
255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                LOG_ALWAYS_FATAL("select() error: %s",
257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                        strerror(errno));
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else if (result > 0) {
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            fireEvents(selector);
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
264