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

Commit dc543aec authored by Jeff Brown's avatar Jeff Brown Committed by Android Git Automerger
Browse files

am 14bc6b5d: am 09340a4b: Merge "Replace epoll() with poll() and rename...

am 14bc6b5d: am 09340a4b: Merge "Replace epoll() with poll() and rename PollLoop to Looper." into gingerbread

Merge commit '14bc6b5d0677e5c454a67775c852f90389bb4567'

* commit '14bc6b5d0677e5c454a67775c852f90389bb4567':
  Replace epoll() with poll() and rename PollLoop to Looper.
parents c479e18d 4f5d8bf9
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