Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef UTILS_LOOPER_H
     18 #define UTILS_LOOPER_H
     19 
     20 #include <utils/threads.h>
     21 #include <utils/RefBase.h>
     22 #include <utils/KeyedVector.h>
     23 #include <utils/Timers.h>
     24 
     25 #include <android/looper.h>
     26 
     27 // When defined, uses epoll_wait() for polling, otherwise uses poll().
     28 #define LOOPER_USES_EPOLL
     29 
     30 // When defined, logs performance statistics for tuning and debugging purposes.
     31 //#define LOOPER_STATISTICS
     32 
     33 #ifdef LOOPER_USES_EPOLL
     34 #include <sys/epoll.h>
     35 #else
     36 #include <sys/poll.h>
     37 #endif
     38 
     39 /*
     40  * Declare a concrete type for the NDK's looper forward declaration.
     41  */
     42 struct ALooper {
     43 };
     44 
     45 namespace android {
     46 
     47 /**
     48  * A polling loop that supports monitoring file descriptor events, optionally
     49  * using callbacks.  The implementation uses epoll() internally.
     50  *
     51  * A looper can be associated with a thread although there is no requirement that it must be.
     52  */
     53 class Looper : public ALooper, public RefBase {
     54 protected:
     55     virtual ~Looper();
     56 
     57 public:
     58     /**
     59      * Creates a looper.
     60      *
     61      * If allowNonCallbaks is true, the looper will allow file descriptors to be
     62      * registered without associated callbacks.  This assumes that the caller of
     63      * pollOnce() is prepared to handle callback-less events itself.
     64      */
     65     Looper(bool allowNonCallbacks);
     66 
     67     /**
     68      * Returns whether this looper instance allows the registration of file descriptors
     69      * using identifiers instead of callbacks.
     70      */
     71     bool getAllowNonCallbacks() const;
     72 
     73     /**
     74      * Waits for events to be available, with optional timeout in milliseconds.
     75      * Invokes callbacks for all file descriptors on which an event occurred.
     76      *
     77      * If the timeout is zero, returns immediately without blocking.
     78      * If the timeout is negative, waits indefinitely until an event appears.
     79      *
     80      * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
     81      * the timeout expired and no callbacks were invoked and no other file
     82      * descriptors were ready.
     83      *
     84      * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
     85      *
     86      * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
     87      * timeout expired.
     88      *
     89      * Returns ALOOPER_POLL_ERROR if an error occurred.
     90      *
     91      * Returns a value >= 0 containing an identifier if its file descriptor has data
     92      * and it has no callback function (requiring the caller here to handle it).
     93      * In this (and only this) case outFd, outEvents and outData will contain the poll
     94      * events and data associated with the fd, otherwise they will be set to NULL.
     95      *
     96      * This method does not return until it has finished invoking the appropriate callbacks
     97      * for all file descriptors that were signalled.
     98      */
     99     int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
    100     inline int pollOnce(int timeoutMillis) {
    101         return pollOnce(timeoutMillis, NULL, NULL, NULL);
    102     }
    103 
    104     /**
    105      * Like pollOnce(), but performs all pending callbacks until all
    106      * data has been consumed or a file descriptor is available with no callback.
    107      * This function will never return ALOOPER_POLL_CALLBACK.
    108      */
    109     int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
    110     inline int pollAll(int timeoutMillis) {
    111         return pollAll(timeoutMillis, NULL, NULL, NULL);
    112     }
    113 
    114     /**
    115      * Wakes the poll asynchronously.
    116      *
    117      * This method can be called on any thread.
    118      * This method returns immediately.
    119      */
    120     void wake();
    121 
    122     /**
    123      * Adds a new file descriptor to be polled by the looper.
    124      * If the same file descriptor was previously added, it is replaced.
    125      *
    126      * "fd" is the file descriptor to be added.
    127      * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
    128      * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
    129      * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
    130      * "callback" is the function to call when there is an event on the file descriptor.
    131      * "data" is a private data pointer to supply to the callback.
    132      *
    133      * There are two main uses of this function:
    134      *
    135      * (1) If "callback" is non-NULL, then this function will be called when there is
    136      * data on the file descriptor.  It should execute any events it has pending,
    137      * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
    138      *
    139      * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
    140      * when its file descriptor has data available, requiring the caller to take
    141      * care of processing it.
    142      *
    143      * Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
    144      *
    145      * This method can be called on any thread.
    146      * This method may block briefly if it needs to wake the poll.
    147      */
    148     int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data);
    149 
    150     /**
    151      * Removes a previously added file descriptor from the looper.
    152      *
    153      * When this method returns, it is safe to close the file descriptor since the looper
    154      * will no longer have a reference to it.  However, it is possible for the callback to
    155      * already be running or for it to run one last time if the file descriptor was already
    156      * signalled.  Calling code is responsible for ensuring that this case is safely handled.
    157      * For example, if the callback takes care of removing itself during its own execution either
    158      * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
    159      * again at any later time unless registered anew.
    160      *
    161      * Returns 1 if the file descriptor was removed, 0 if none was previously registered.
    162      *
    163      * This method can be called on any thread.
    164      * This method may block briefly if it needs to wake the poll.
    165      */
    166     int removeFd(int fd);
    167 
    168     /**
    169      * Prepares a looper associated with the calling thread, and returns it.
    170      * If the thread already has a looper, it is returned.  Otherwise, a new
    171      * one is created, associated with the thread, and returned.
    172      *
    173      * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
    174      */
    175     static sp<Looper> prepare(int opts);
    176 
    177     /**
    178      * Sets the given looper to be associated with the calling thread.
    179      * If another looper is already associated with the thread, it is replaced.
    180      *
    181      * If "looper" is NULL, removes the currently associated looper.
    182      */
    183     static void setForThread(const sp<Looper>& looper);
    184 
    185     /**
    186      * Returns the looper associated with the calling thread, or NULL if
    187      * there is not one.
    188      */
    189     static sp<Looper> getForThread();
    190 
    191 private:
    192     struct Request {
    193         int fd;
    194         int ident;
    195         ALooper_callbackFunc callback;
    196         void* data;
    197     };
    198 
    199     struct Response {
    200         int events;
    201         Request request;
    202     };
    203 
    204     const bool mAllowNonCallbacks; // immutable
    205 
    206     int mWakeReadPipeFd;  // immutable
    207     int mWakeWritePipeFd; // immutable
    208     Mutex mLock;
    209 
    210 #ifdef LOOPER_USES_EPOLL
    211     int mEpollFd; // immutable
    212 
    213     // Locked list of file descriptor monitoring requests.
    214     KeyedVector<int, Request> mRequests;  // guarded by mLock
    215 #else
    216     // The lock guards state used to track whether there is a poll() in progress and whether
    217     // there are any other threads waiting in wakeAndLock().  The condition variables
    218     // are used to transfer control among these threads such that all waiters are
    219     // serviced before a new poll can begin.
    220     // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
    221     // until mPolling becomes false, then decrements mWaiters again.
    222     // The poll() method blocks on mResume until mWaiters becomes 0, then sets
    223     // mPolling to true, blocks until the poll completes, then resets mPolling to false
    224     // and signals mResume if there are waiters.
    225     bool mPolling;      // guarded by mLock
    226     uint32_t mWaiters;  // guarded by mLock
    227     Condition mAwake;   // guarded by mLock
    228     Condition mResume;  // guarded by mLock
    229 
    230     Vector<struct pollfd> mRequestedFds;  // must hold mLock and mPolling must be false to modify
    231     Vector<Request> mRequests;            // must hold mLock and mPolling must be false to modify
    232 
    233     ssize_t getRequestIndexLocked(int fd);
    234     void wakeAndLock();
    235 #endif
    236 
    237 #ifdef LOOPER_STATISTICS
    238     static const int SAMPLED_WAKE_CYCLES_TO_AGGREGATE = 100;
    239     static const int SAMPLED_POLLS_TO_AGGREGATE = 1000;
    240 
    241     nsecs_t mPendingWakeTime;
    242     int mPendingWakeCount;
    243 
    244     int mSampledWakeCycles;
    245     int mSampledWakeCountSum;
    246     nsecs_t mSampledWakeLatencySum;
    247 
    248     int mSampledPolls;
    249     int mSampledZeroPollCount;
    250     int mSampledZeroPollLatencySum;
    251     int mSampledTimeoutPollCount;
    252     int mSampledTimeoutPollLatencySum;
    253 #endif
    254 
    255     // This state is only used privately by pollOnce and does not require a lock since
    256     // it runs on a single thread.
    257     Vector<Response> mResponses;
    258     size_t mResponseIndex;
    259 
    260     int pollInner(int timeoutMillis);
    261     void awoken();
    262     void pushResponse(int events, const Request& request);
    263 
    264     static void initTLSKey();
    265     static void threadDestructor(void *st);
    266 };
    267 
    268 } // namespace android
    269 
    270 #endif // UTILS_LOOPER_H
    271