blob: b7087f83df38feef718f58a4e09108bba8964d05 [file] [log] [blame]
Andreas Huber7d2f7032010-06-07 10:18:57 -07001/*
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//#define LOG_NDEBUG 0
18#define LOG_TAG "ALooper"
19#include <utils/Log.h>
20
21#include <sys/time.h>
22
23#include "ALooper.h"
24
25#include "AHandler.h"
26#include "ALooperRoster.h"
27#include "AMessage.h"
28
29namespace android {
30
31ALooperRoster gLooperRoster;
32
33struct ALooper::LooperThread : public Thread {
Andreas Huber4f104d92010-07-02 08:00:52 -070034 LooperThread(ALooper *looper, bool canCallJava)
35 : Thread(canCallJava),
36 mLooper(looper) {
Andreas Huber7d2f7032010-06-07 10:18:57 -070037 }
38
39 virtual bool threadLoop() {
40 return mLooper->loop();
41 }
42
43protected:
44 virtual ~LooperThread() {}
45
46private:
47 ALooper *mLooper;
48
49 DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
50};
51
52// static
53int64_t ALooper::GetNowUs() {
54 struct timeval tv;
55 gettimeofday(&tv, NULL);
56
57 return (int64_t)tv.tv_sec * 1000000ll + tv.tv_usec;
58}
59
60ALooper::ALooper()
61 : mRunningLocally(false) {
62}
63
64ALooper::~ALooper() {
65 stop();
66}
67
Andreas Huberc4e0b702010-08-27 15:21:07 -070068void ALooper::setName(const char *name) {
69 mName = name;
70}
71
Andreas Huber7d2f7032010-06-07 10:18:57 -070072ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
73 return gLooperRoster.registerHandler(this, handler);
74}
75
76void ALooper::unregisterHandler(handler_id handlerID) {
77 gLooperRoster.unregisterHandler(handlerID);
78}
79
Andreas Huber4e4173b2010-07-22 09:20:13 -070080status_t ALooper::start(
81 bool runOnCallingThread, bool canCallJava, int32_t priority) {
Andreas Huber7d2f7032010-06-07 10:18:57 -070082 if (runOnCallingThread) {
83 {
84 Mutex::Autolock autoLock(mLock);
85
86 if (mThread != NULL || mRunningLocally) {
87 return INVALID_OPERATION;
88 }
89
90 mRunningLocally = true;
91 }
92
93 do {
94 } while (loop());
95
96 return OK;
97 }
98
99 Mutex::Autolock autoLock(mLock);
100
101 if (mThread != NULL || mRunningLocally) {
102 return INVALID_OPERATION;
103 }
104
Andreas Huber4f104d92010-07-02 08:00:52 -0700105 mThread = new LooperThread(this, canCallJava);
Andreas Huber7d2f7032010-06-07 10:18:57 -0700106
Andreas Huberc4e0b702010-08-27 15:21:07 -0700107 status_t err = mThread->run(
108 mName.empty() ? "ALooper" : mName.c_str(), priority);
Andreas Huber7d2f7032010-06-07 10:18:57 -0700109 if (err != OK) {
110 mThread.clear();
111 }
112
113 return err;
114}
115
116status_t ALooper::stop() {
117 sp<LooperThread> thread;
118 bool runningLocally;
119
120 {
121 Mutex::Autolock autoLock(mLock);
122
123 thread = mThread;
124 runningLocally = mRunningLocally;
125 mThread.clear();
126 mRunningLocally = false;
127 }
128
129 if (thread == NULL && !runningLocally) {
130 return INVALID_OPERATION;
131 }
132
133 if (thread != NULL) {
134 thread->requestExit();
135 }
136
137 mQueueChangedCondition.signal();
138
139 if (!runningLocally) {
140 thread->requestExitAndWait();
141 }
142
143 return OK;
144}
145
146void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
147 Mutex::Autolock autoLock(mLock);
148
149 int64_t whenUs;
150 if (delayUs > 0) {
151 whenUs = GetNowUs() + delayUs;
152 } else {
153 whenUs = GetNowUs();
154 }
155
156 List<Event>::iterator it = mEventQueue.begin();
157 while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
158 ++it;
159 }
160
161 Event event;
162 event.mWhenUs = whenUs;
163 event.mMessage = msg;
164
165 if (it == mEventQueue.begin()) {
166 mQueueChangedCondition.signal();
167 }
168
169 mEventQueue.insert(it, event);
170}
171
172bool ALooper::loop() {
173 Event event;
174
175 {
176 Mutex::Autolock autoLock(mLock);
177 if (mThread == NULL && !mRunningLocally) {
178 return false;
179 }
180 if (mEventQueue.empty()) {
181 mQueueChangedCondition.wait(mLock);
182 return true;
183 }
184 int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
185 int64_t nowUs = GetNowUs();
186
187 if (whenUs > nowUs) {
188 int64_t delayUs = whenUs - nowUs;
189 mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
190
191 return true;
192 }
193
194 event = *mEventQueue.begin();
195 mEventQueue.erase(mEventQueue.begin());
196 }
197
198 gLooperRoster.deliverMessage(event.mMessage);
199
200 return true;
201}
202
203} // namespace android