summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dianne Hackborn <hackbod@google.com> 2010-07-02 18:52:01 -0700
committer Dianne Hackborn <hackbod@google.com> 2010-07-02 18:57:02 -0700
commitefa10850665c8d60e562f3a488ae65e225614707 (patch)
tree716669410b52fd7dc61aa72926b729c891876c1d
parentbf83375c73f0dcde5d97b36273e3fd971411e866 (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.h5
-rw-r--r--include/utils/PollLoop.h34
-rw-r--r--libs/utils/PollLoop.cpp68
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);