⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 selector.c

📁 Android 一些工具
💻 C
字号:
/* * 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);        }    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -