Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b06cca62 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Replace epoll() with poll() and rename PollLoop to Looper." into gingerbread

parents 959d007a 59abe7e0
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ namespace android {

class ISensorEventConnection;
class Sensor;
class PollLoop;
class Looper;

// ----------------------------------------------------------------------------

@@ -69,11 +69,11 @@ public:
    status_t disableSensor(int32_t handle) const;

private:
    sp<PollLoop> getPollLoop() const;
    sp<Looper> getLooper() const;
    sp<ISensorEventConnection> mSensorEventConnection;
    sp<SensorChannel> mSensorChannel;
    mutable Mutex mLock;
    mutable sp<PollLoop> mPollLoop;
    mutable sp<Looper> mLooper;
};

// ----------------------------------------------------------------------------
+4 −4
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/PollLoop.h>
#include <utils/Looper.h>
#include <utils/Pool.h>

#include <stddef.h>
@@ -826,7 +826,7 @@ private:
    Mutex mLock;

    Allocator mAllocator;
    sp<PollLoop> mPollLoop;
    sp<Looper> mLooper;

    EventEntry* mPendingEvent;
    Queue<EventEntry> mInboundQueue;
@@ -837,7 +837,7 @@ private:
    void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
            nsecs_t* nextWakeupTime);

    // Enqueues an inbound event.  Returns true if mPollLoop->wake() should be called.
    // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
    bool enqueueInboundEventLocked(EventEntry* entry);

    // App switch latency optimization.
@@ -1010,7 +1010,7 @@ private:
    void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
            bool broken);
    void drainOutboundQueueLocked(Connection* connection, DispatchEntry* firstDispatchEntryToDrain);
    static bool handleReceiveCallback(int receiveFd, int events, void* data);
    static int handleReceiveCallback(int receiveFd, int events, void* data);

    // Preempting input dispatch.
    bool preemptInputDispatchInnerLocked();
+0 −1
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
#include <semaphore.h>
#include <ui/Input.h>
#include <utils/Errors.h>
#include <utils/PollLoop.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
+210 −0
Original line number Diff line number Diff line
@@ -14,81 +14,88 @@
 * limitations under the License.
 */

#ifndef UTILS_POLL_LOOP_H
#define UTILS_POLL_LOOP_H
#ifndef UTILS_LOOPER_H
#define UTILS_LOOPER_H

#include <utils/Vector.h>
#include <utils/threads.h>

#include <sys/poll.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>

#include <android/looper.h>

struct ALooper : public android::RefBase {
protected:
    virtual ~ALooper() { }

public:
    ALooper() { }
/*
 * Declare a concrete type for the NDK's looper forward declaration.
 */
struct ALooper {
};

namespace android {

/**
 * A basic file descriptor polling loop based on poll() with callbacks.
 * A polling loop that supports monitoring file descriptor events, optionally
 * using callbacks.  The implementation uses epoll() internally.
 *
 * A looper can be associated with a thread although there is no requirement that it must be.
 */
class PollLoop : public ALooper {
class Looper : public ALooper, public RefBase {
protected:
    virtual ~PollLoop();
    virtual ~Looper();

public:
    PollLoop(bool allowNonCallbacks);

    /**
     * A callback that it to be invoked when an event occurs on a file descriptor.
     * Specifies the events that were triggered and the user data provided when the
     * callback was set.
     * Creates a looper.
     *
     * Returns true if the callback should be kept, false if it should be removed automatically
     * after the callback returns.
     * If allowNonCallbaks is true, the looper will allow file descriptors to be
     * registered without associated callbacks.  This assumes that the caller of
     * pollOnce() is prepared to handle callback-less events itself.
     */
    typedef bool (*Callback)(int fd, int events, void* data);
    Looper(bool allowNonCallbacks);

    enum {
        POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
        POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
        POLL_ERROR = ALOOPER_POLL_ERROR,
    };
    /**
     * Returns whether this looper instance allows the registration of file descriptors
     * using identifiers instead of callbacks.
     */
    bool getAllowNonCallbacks() const;

    /**
     * Performs a single call to poll() with optional timeout in milliseconds.
     * Waits for events to be available, with optional timeout in milliseconds.
     * Invokes callbacks for all file descriptors on which an event occurred.
     *
     * If the timeout is zero, returns immediately without blocking.
     * If the timeout is negative, waits indefinitely until awoken.
     * If the timeout is negative, waits indefinitely until an event appears.
     *
     * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
     * the timeout expired and no callbacks were invoked and no other file
     * descriptors were ready.
     *
     * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
     * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
     *
     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
     * timeout expired.
     *
     * Returns ALOPER_POLL_ERROR if an error occurred.
     * Returns ALOOPER_POLL_ERROR if an error occurred.
     *
     * Returns a value >= 0 containing a file descriptor if it has data
     * Returns a value >= 0 containing an identifier if its file descriptor has data
     * and it has no callback function (requiring the caller here to handle it).
     * In this (and only this) case outEvents and outData will contain the poll
     * events and data associated with the fd.
     * In this (and only this) case outFd, outEvents and outData will contain the poll
     * events and data associated with the fd, otherwise they will be set to NULL.
     *
     * This method must only be called on the thread owning the PollLoop.
     * This method blocks until either a file descriptor is signalled, a timeout occurs,
     * or wake() is called.
     * This method does not return until it has finished invoking the appropriate callbacks
     * for all file descriptors that were signalled.
     */
    int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
    int pollOnce(int timeoutMillis,
            int* outFd = NULL, int* outEvents = NULL, void** outData = NULL);

    /**
     * Like pollOnce(), but performs all pending callbacks until all
     * data has been consumed or a file descriptor is available with no callback.
     * This function will never return ALOOPER_POLL_CALLBACK.
     */
    int pollAll(int timeoutMillis,
            int* outFd = NULL, int* outEvents = NULL, void** outData = NULL);

    /**
     * Wakes the loop asynchronously.
     * Wakes the poll asynchronously.
     *
     * This method can be called on any thread.
     * This method returns immediately.
@@ -96,124 +103,108 @@ public:
    void wake();

    /**
     * Control whether this PollLoop instance allows using IDs instead
     * of callbacks.
     */
    bool getAllowNonCallbacks() const;
    
    /**
     * Sets the callback for a file descriptor, replacing the existing one, if any.
     * It is an error to call this method with events == 0 or callback == NULL.
     * Adds a new file descriptor to be polled by the looper.
     * If the same file descriptor was previously added, it is replaced.
     *
     * Note that a callback can be invoked with the POLLERR, POLLHUP or POLLNVAL events
     * even if it is not explicitly requested when registered.
     * "fd" is the file descriptor to be added.
     * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
     * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
     * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
     * "callback" is the function to call when there is an event on the file descriptor.
     * "data" is a private data pointer to supply to the callback.
     *
     * There are two main uses of this function:
     *
     * (1) If "callback" is non-NULL, then this function will be called when there is
     * data on the file descriptor.  It should execute any events it has pending,
     * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
     *
     * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
     * when its file descriptor has data available, requiring the caller to take
     * care of processing it.
     *
     * Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
     *
     * This method can be called on any thread.
     * This method may block briefly if it needs to wake the poll loop.
     */
    void setCallback(int fd, int ident, int events, Callback callback, void* data = NULL);

    /**
     * Convenience for above setCallback when ident is not used.  In this case
     * the ident is set to POLL_CALLBACK.
     */
    void setCallback(int fd, int events, Callback callback, void* data = NULL);
    
    /**
     * Like setCallback(), but for the NDK callback function.
     * This method may block briefly if it needs to wake the poll.
     */
    void setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
            void* data);
    int addFd(int fd, int ident,
            int events, ALooper_callbackFunc callback, void* data = NULL);

    /**
     * Removes the callback for a file descriptor, if one exists.
     * Removes a previously added file descriptor from the looper.
     *
     * When this method returns, it is safe to close the file descriptor since the poll loop
     * When this method returns, it is safe to close the file descriptor since the looper
     * will no longer have a reference to it.  However, it is possible for the callback to
     * already be running or for it to run one last time if the file descriptor was already
     * signalled.  Calling code is responsible for ensuring that this case is safely handled.
     * For example, if the callback takes care of removing itself during its own execution either
     * by returning false or calling this method, then it can be guaranteed to not be invoked
     * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
     * again at any later time unless registered anew.
     *
     * Returns 1 if the file descriptor was removed, 0 if none was previously registered.
     *
     * This method can be called on any thread.
     * This method may block briefly if it needs to wake the poll loop.
     * This method may block briefly if it needs to wake the poll.
     */
    int removeFd(int fd);

    /**
     * Prepares a looper associated with the calling thread, and returns it.
     * If the thread already has a looper, it is returned.  Otherwise, a new
     * one is created, associated with the thread, and returned.
     *
     * Returns true if a callback was actually removed, false if none was registered.
     * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
     */
    bool removeCallback(int fd);
    static sp<Looper> prepare(int opts);

    /**
     * Set the given PollLoop to be associated with the
     * calling thread.  There must be a 1:1 relationship between
     * PollLoop and thread.
     * Sets the given looper to be associated with the calling thread.
     * If another looper is already associated with the thread, it is replaced.
     *
     * If "looper" is NULL, removes the currently associated looper.
     */
    static void setForThread(const sp<PollLoop>& pollLoop);
    static void setForThread(const sp<Looper>& looper);

    /**
     * Return the PollLoop associated with the calling thread.
     * Returns the looper associated with the calling thread, or NULL if
     * there is not one.
     */
    static sp<PollLoop> getForThread();
    static sp<Looper> getForThread();

private:
    struct RequestedCallback {
        Callback callback;
        ALooper_callbackFunc* looperCallback;
    struct Request {
        int fd;
        int ident;
        ALooper_callbackFunc callback;
        void* data;
    };

    struct PendingCallback {
        int fd;
        int ident;
    struct Response {
        int events;
        Callback callback;
        ALooper_callbackFunc* looperCallback;
        void* data;
        Request request;
    };

    const bool mAllowNonCallbacks; // immutable

    int mEpollFd; // immutable
    int mWakeReadPipeFd;  // immutable
    int mWakeWritePipeFd; // immutable

    // The lock guards state used to track whether there is a poll() in progress and whether
    // there are any other threads waiting in wakeAndLock().  The condition variables
    // are used to transfer control among these threads such that all waiters are
    // serviced before a new poll can begin.
    // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
    // until mPolling becomes false, then decrements mWaiters again.
    // The poll() method blocks on mResume until mWaiters becomes 0, then sets
    // mPolling to true, blocks until the poll completes, then resets mPolling to false
    // and signals mResume if there are waiters.
    // Locked list of file descriptor monitoring requests.
    Mutex mLock;
    bool mPolling;      // guarded by mLock
    uint32_t mWaiters;  // guarded by mLock
    Condition mAwake;   // guarded by mLock
    Condition mResume;  // guarded by mLock

    // The next two vectors are only mutated when mPolling is false since they must
    // not be changed while the poll() system call is in progress.  To mutate these
    // vectors, the poll() must first be awoken then the lock acquired.
    Vector<struct pollfd> mRequestedFds;
    Vector<RequestedCallback> mRequestedCallbacks;
    KeyedVector<int, Request> mRequests;

    // This state is only used privately by pollOnce and does not require a lock since
    // it runs on a single thread.
    Vector<PendingCallback> mPendingCallbacks;
    Vector<PendingCallback> mPendingFds;
    size_t mPendingFdsPos;
    Vector<Response> mResponses;
    size_t mResponseIndex;

    void openWakePipe();
    void closeWakePipe();
    int pollInner(int timeoutMillis);

    void setCallbackCommon(int fd, int ident, int events, Callback callback,
            ALooper_callbackFunc* looperCallback, void* data);
    ssize_t getRequestIndexLocked(int fd);
    void wakeAndLock();
    static void threadDestructor(void *st);
};

} // namespace android

#endif // UTILS_POLL_LOOP_H
#endif // UTILS_LOOPER_H
+11 −11
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@

#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/PollLoop.h>
#include <utils/Looper.h>

#include <gui/Sensor.h>
#include <gui/SensorChannel.h>
@@ -81,28 +81,28 @@ ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
    return size;
}

sp<PollLoop> SensorEventQueue::getPollLoop() const
sp<Looper> SensorEventQueue::getLooper() const
{
    Mutex::Autolock _l(mLock);
    if (mPollLoop == 0) {
        mPollLoop = new PollLoop(true);
        mPollLoop->setCallback(getFd(), getFd(), POLLIN, NULL, NULL);
    if (mLooper == 0) {
        mLooper = new Looper(true);
        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
    }
    return mPollLoop;
    return mLooper;
}

status_t SensorEventQueue::waitForEvent() const
{
    const int fd = getFd();
    sp<PollLoop> pollLoop(getPollLoop());
    int32_t result = pollLoop->pollOnce(-1, NULL, NULL);
    return (result == fd) ? NO_ERROR : -1;
    sp<Looper> looper(getLooper());
    int32_t result = looper->pollOnce(-1);
    return (result == fd) ? status_t(NO_ERROR) : status_t(-1);
}

status_t SensorEventQueue::wake() const
{
    sp<PollLoop> pollLoop(getPollLoop());
    pollLoop->wake();
    sp<Looper> looper(getLooper());
    looper->wake();
    return NO_ERROR;
}

Loading