summaryrefslogtreecommitdiffstats
path: root/libs/utils
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-07-07 14:27:31 -0700
committerDianne Hackborn <hackbod@google.com>2010-07-08 11:06:59 -0700
commit85448bbecd4e0909eecfab15b7c3605f114d0427 (patch)
tree3380a9a85e321dc7ee4397dc1b4f22564af117d8 /libs/utils
parentf7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732 (diff)
downloadframeworks_base-85448bbecd4e0909eecfab15b7c3605f114d0427.zip
frameworks_base-85448bbecd4e0909eecfab15b7c3605f114d0427.tar.gz
frameworks_base-85448bbecd4e0909eecfab15b7c3605f114d0427.tar.bz2
Add new glue code for writing native apps.
This factors out the boiler-plate code from the sample app to a common glue code that can be used for everyone writing this style of app: a dedicated app thread that takes care of waiting for events and processing them. As part of doing this, ALooper has a new facility to allow registration of fds that cause ALooper_pollOnce() to return the fd that has data, allowing the app to drive the loop without callbacks. Hopefully this makes some people feel better. :) Also do some other cleanup of the ALooper API, plus some actual documentation. Change-Id: Ic53bd56bdf627e3ba28a3c093faa06a92be522b8
Diffstat (limited to 'libs/utils')
-rw-r--r--libs/utils/PollLoop.cpp93
-rw-r--r--libs/utils/tests/PollLoop_test.cpp78
2 files changed, 99 insertions, 72 deletions
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 58fe141..f740fa0 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -25,8 +25,9 @@ static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;
-PollLoop::PollLoop() :
- mPolling(false), mWaiters(0) {
+PollLoop::PollLoop(bool allowNonCallbacks) :
+ mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
+ mWaiters(0), mPendingFdsPos(0) {
openWakePipe();
}
@@ -106,7 +107,18 @@ void PollLoop::closeWakePipe() {
// method is currently only called by the destructor.
}
-bool PollLoop::pollOnce(int timeoutMillis) {
+int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
+ // If there are still pending fds from the last call, dispatch those
+ // first, to avoid an earlier fd from starving later ones.
+ const size_t pendingFdsCount = mPendingFds.size();
+ if (mPendingFdsPos < pendingFdsCount) {
+ const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
+ mPendingFdsPos++;
+ if (outEvents != NULL) *outEvents = pending.events;
+ if (outData != NULL) *outData = pending.data;
+ return pending.fd;
+ }
+
mLock.lock();
while (mWaiters != 0) {
mResume.wait(mLock);
@@ -114,7 +126,7 @@ bool PollLoop::pollOnce(int timeoutMillis) {
mPolling = true;
mLock.unlock();
- bool result;
+ int32_t result;
size_t requestedCount = mRequestedFds.size();
#if DEBUG_POLL_AND_WAKE
@@ -131,7 +143,7 @@ bool PollLoop::pollOnce(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - timeout", this);
#endif
- result = false;
+ result = POLL_TIMEOUT;
goto Done;
}
@@ -143,7 +155,7 @@ bool PollLoop::pollOnce(int timeoutMillis) {
if (errno != EINTR) {
LOGW("Poll failed with an unexpected error, errno=%d", errno);
}
- result = false;
+ result = POLL_ERROR;
goto Done;
}
@@ -156,38 +168,44 @@ bool PollLoop::pollOnce(int timeoutMillis) {
#endif
mPendingCallbacks.clear();
+ mPendingFds.clear();
+ mPendingFdsPos = 0;
+ if (outEvents != NULL) *outEvents = 0;
+ if (outData != NULL) *outData = NULL;
+
+ result = POLL_CALLBACK;
for (size_t i = 0; i < requestedCount; i++) {
const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
short revents = requestedFd.revents;
if (revents) {
const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
- Callback callback = requestedCallback.callback;
- ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
-
- 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);
+ PendingCallback pending;
+ pending.fd = requestedFd.fd;
+ pending.events = revents;
+ pending.callback = requestedCallback.callback;
+ pending.looperCallback = requestedCallback.looperCallback;
+ pending.data = requestedCallback.data;
+
+ if (pending.callback || pending.looperCallback) {
+ mPendingCallbacks.push(pending);
+ } else if (pending.fd != mWakeReadPipeFd) {
+ if (result == POLL_CALLBACK) {
+ result = pending.fd;
+ if (outEvents != NULL) *outEvents = pending.events;
+ if (outData != NULL) *outData = pending.data;
+ } else {
+ mPendingFds.push(pending);
+ }
} else {
- if (requestedFd.fd == mWakeReadPipeFd) {
#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - awoken", this);
-#endif
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while (nRead == sizeof(buffer));
- } else {
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
- LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
+ LOGD("%p ~ pollOnce - awoken", this);
#endif
- }
+ char buffer[16];
+ ssize_t nRead;
+ do {
+ nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+ } while (nRead == sizeof(buffer));
}
respondedCount -= 1;
@@ -196,7 +214,6 @@ bool PollLoop::pollOnce(int timeoutMillis) {
}
}
}
- result = true;
Done:
mLock.lock();
@@ -206,7 +223,7 @@ Done:
}
mLock.unlock();
- if (result) {
+ if (result == POLL_CALLBACK || result >= 0) {
size_t pendingCount = mPendingCallbacks.size();
for (size_t i = 0; i < pendingCount; i++) {
const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
@@ -247,6 +264,10 @@ void PollLoop::wake() {
}
}
+bool PollLoop::getAllowNonCallbacks() const {
+ return mAllowNonCallbacks;
+}
+
void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
setCallbackCommon(fd, events, callback, NULL, data);
}
@@ -263,12 +284,18 @@ void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
#endif
- if (! events || (! callback && ! looperCallback)) {
- LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
+ if (! events) {
+ LOGE("Invalid attempt to set a callback with no selected poll events.");
removeCallback(fd);
return;
}
+ if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
+ LOGE("Invalid attempt to set NULL callback but not allowed.");
+ removeCallback(fd);
+ return;
+ }
+
wakeAndLock();
struct pollfd requestedFd;
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
index 4848c0f..02f1808 100644
--- a/libs/utils/tests/PollLoop_test.cpp
+++ b/libs/utils/tests/PollLoop_test.cpp
@@ -87,7 +87,7 @@ protected:
sp<PollLoop> mPollLoop;
virtual void SetUp() {
- mPollLoop = new PollLoop();
+ mPollLoop = new PollLoop(false);
}
virtual void TearDown() {
@@ -98,26 +98,26 @@ protected:
TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
}
TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
mPollLoop->wake();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(1000);
+ int32_t result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. zero because wake() was called before waiting";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because loop was awoken";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because loop was awoken";
}
TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
@@ -125,24 +125,24 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyRe
delayedWake->run();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(1000);
+ int32_t result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal wake delay";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because loop was awoken";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because loop was awoken";
}
TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
}
TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
@@ -152,13 +152,13 @@ TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturn
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(0, handler.callbackCount)
<< "callback should not have been invoked because FD was not signalled";
}
@@ -171,13 +171,13 @@ TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCa
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked exactly once";
EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -193,13 +193,13 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeou
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(0, handler.callbackCount)
<< "callback should not have been invoked because FD was not signalled";
}
@@ -212,15 +212,15 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_Imme
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked exactly once";
EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -238,15 +238,15 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_Promp
delayedWriteSignal->run();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(1000);
+ int32_t result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal signal delay";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked exactly once";
EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -264,15 +264,15 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeIn
mPollLoop->removeCallback(pipe.receiveFd);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout because FD was no longer registered";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(0, handler.callbackCount)
<< "callback should not be invoked";
}
@@ -287,15 +287,15 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvoke
pipe.writeSignal();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal zero because FD was already signalled";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked";
@@ -310,8 +310,8 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvoke
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal zero because timeout was zero";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should not be invoked this time";
}
@@ -351,15 +351,15 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeI
pipe.writeSignal(); // would cause FD to be considered signalled
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. zero because FD was already signalled";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(0, handler1.callbackCount)
<< "original handler callback should not be invoked because it was replaced";
EXPECT_EQ(1, handler2.callbackCount)