diff options
| author | 2010-07-02 18:52:01 -0700 | |
|---|---|---|
| committer | 2010-07-02 18:57:02 -0700 | |
| commit | efa10850665c8d60e562f3a488ae65e225614707 (patch) | |
| tree | 716669410b52fd7dc61aa72926b729c891876c1d | |
| parent | bf83375c73f0dcde5d97b36273e3fd971411e866 (diff) | |
Add new native Looper API.
This allows us to avoid exposing the file descriptor of
the event queue; instead, you attach an event queue to
a looper. This will also should allow native apps to be
written without the need for a separate thread, by attaching
the event queue to the main thread's looper and scheduling
their own messages there.
Change-Id: I38489282635895ae2cbfacb88599c1b1cad9b239
| -rw-r--r-- | include/ui/InputTransport.h | 5 | ||||
| -rw-r--r-- | include/utils/PollLoop.h | 34 | ||||
| -rw-r--r-- | libs/utils/PollLoop.cpp | 68 |
3 files changed, 102 insertions, 5 deletions
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h index 2dfe2a866e..11714d5362 100644 --- a/include/ui/InputTransport.h +++ b/include/ui/InputTransport.h @@ -33,6 +33,7 @@ #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> @@ -345,11 +346,15 @@ public: android::status_t consume(android::InputEvent** event); + void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; } + const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; } + virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0; private: android::InputConsumer mConsumer; android::PreallocatedInputEventFactory mInputEventFactory; + android::sp<android::PollLoop> mPollLoop; }; #endif // _UI_INPUT_TRANSPORT_H diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h index a95fb171cf..b3651caeac 100644 --- a/include/utils/PollLoop.h +++ b/include/utils/PollLoop.h @@ -22,12 +22,22 @@ #include <sys/poll.h> +#include <android/looper.h> + +struct ALooper : public android::RefBase { +protected: + virtual ~ALooper() { } + +public: + ALooper() { } +}; + namespace android { /** * A basic file descriptor polling loop based on poll() with callbacks. */ -class PollLoop : public RefBase { +class PollLoop : public ALooper { protected: virtual ~PollLoop(); @@ -83,6 +93,11 @@ public: void setCallback(int fd, int events, Callback callback, void* data = NULL); /** + * Like setCallback(), but for the NDK callback function. + */ + void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, void* data); + + /** * Removes the callback for a file descriptor, if one exists. * * When this method returns, it is safe to close the file descriptor since the poll loop @@ -100,9 +115,22 @@ public: */ bool removeCallback(int fd); + /** + * Set the given PollLoop to be associated with the + * calling thread. There must be a 1:1 relationship between + * PollLoop and thread. + */ + static void setForThread(const sp<PollLoop>& pollLoop); + + /** + * Return the PollLoop associated with the calling thread. + */ + static sp<PollLoop> getForThread(); + private: struct RequestedCallback { Callback callback; + ALooper_callbackFunc* looperCallback; void* data; }; @@ -110,6 +138,7 @@ private: int fd; int events; Callback callback; + ALooper_callbackFunc* looperCallback; void* data; }; @@ -130,8 +159,11 @@ private: void openWakePipe(); void closeWakePipe(); + void setCallbackCommon(int fd, int events, Callback callback, + ALooper_callbackFunc* looperCallback, void* data); ssize_t getRequestIndexLocked(int fd); void wakeAndLock(); + static void threadDestructor(void *st); }; } // namespace android diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp index 20a4d1385b..58fe1411d9 100644 --- a/libs/utils/PollLoop.cpp +++ b/libs/utils/PollLoop.cpp @@ -21,6 +21,10 @@ namespace android { +static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; +static bool gHaveTLS = false; +static pthread_key_t gTLS = 0; + PollLoop::PollLoop() : mPolling(false), mWaiters(0) { openWakePipe(); @@ -30,6 +34,41 @@ PollLoop::~PollLoop() { closeWakePipe(); } +void PollLoop::threadDestructor(void *st) { + PollLoop* const self = static_cast<PollLoop*>(st); + if (self != NULL) { + self->decStrong((void*)threadDestructor); + } +} + +void PollLoop::setForThread(const sp<PollLoop>& pollLoop) { + sp<PollLoop> old = getForThread(); + + if (pollLoop != NULL) { + pollLoop->incStrong((void*)threadDestructor); + } + + pthread_setspecific(gTLS, pollLoop.get()); + + if (old != NULL) { + old->decStrong((void*)threadDestructor); + } +} + +sp<PollLoop> PollLoop::getForThread() { + if (!gHaveTLS) { + pthread_mutex_lock(&gTLSMutex); + if (pthread_key_create(&gTLS, threadDestructor) != 0) { + pthread_mutex_unlock(&gTLSMutex); + return NULL; + } + gHaveTLS = true; + pthread_mutex_unlock(&gTLSMutex); + } + + return (PollLoop*)pthread_getspecific(gTLS); +} + void PollLoop::openWakePipe() { int wakeFds[2]; int result = pipe(wakeFds); @@ -54,6 +93,7 @@ void PollLoop::openWakePipe() { RequestedCallback requestedCallback; requestedCallback.callback = NULL; + requestedCallback.looperCallback = NULL; requestedCallback.data = NULL; mRequestedCallbacks.insertAt(requestedCallback, 0); } @@ -123,12 +163,14 @@ bool PollLoop::pollOnce(int timeoutMillis) { if (revents) { const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i); Callback callback = requestedCallback.callback; + ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback; - if (callback) { + if (callback || looperCallback) { PendingCallback pendingCallback; pendingCallback.fd = requestedFd.fd; pendingCallback.events = requestedFd.revents; pendingCallback.callback = callback; + pendingCallback.looperCallback = looperCallback; pendingCallback.data = requestedCallback.data; mPendingCallbacks.push(pendingCallback); } else { @@ -172,8 +214,14 @@ Done: LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd); #endif - bool keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events, - pendingCallback.data); + bool keep = true; + if (pendingCallback.callback != NULL) { + keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events, + pendingCallback.data); + } else { + keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events, + pendingCallback.data) != 0; + } if (! keep) { removeCallback(pendingCallback.fd); } @@ -200,11 +248,22 @@ void PollLoop::wake() { } void PollLoop::setCallback(int fd, int events, Callback callback, void* data) { + setCallbackCommon(fd, events, callback, NULL, data); +} + +void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, + void* data) { + setCallbackCommon(fd, events, NULL, callback, data); +} + +void PollLoop::setCallbackCommon(int fd, int events, Callback callback, + ALooper_callbackFunc* looperCallback, void* data) { + #if DEBUG_CALLBACKS LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events); #endif - if (! events || ! callback) { + if (! events || (! callback && ! looperCallback)) { LOGE("Invalid attempt to set a callback with no selected poll events or no callback."); removeCallback(fd); return; @@ -218,6 +277,7 @@ void PollLoop::setCallback(int fd, int events, Callback callback, void* data) { RequestedCallback requestedCallback; requestedCallback.callback = callback; + requestedCallback.looperCallback = looperCallback; requestedCallback.data = data; ssize_t index = getRequestIndexLocked(fd); |