ALooper.cpp revision 42d7f83904b8a91ce33e87a44de109572679ac1f
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//#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 { 34 LooperThread(ALooper *looper, bool canCallJava) 35 : Thread(canCallJava), 36 mLooper(looper) { 37 } 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 68ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) { 69 return gLooperRoster.registerHandler(this, handler); 70} 71 72void ALooper::unregisterHandler(handler_id handlerID) { 73 gLooperRoster.unregisterHandler(handlerID); 74} 75 76status_t ALooper::start(bool runOnCallingThread, bool canCallJava) { 77 if (runOnCallingThread) { 78 { 79 Mutex::Autolock autoLock(mLock); 80 81 if (mThread != NULL || mRunningLocally) { 82 return INVALID_OPERATION; 83 } 84 85 mRunningLocally = true; 86 } 87 88 do { 89 } while (loop()); 90 91 return OK; 92 } 93 94 Mutex::Autolock autoLock(mLock); 95 96 if (mThread != NULL || mRunningLocally) { 97 return INVALID_OPERATION; 98 } 99 100 mThread = new LooperThread(this, canCallJava); 101 102 status_t err = mThread->run("ALooper"); 103 if (err != OK) { 104 mThread.clear(); 105 } 106 107 return err; 108} 109 110status_t ALooper::stop() { 111 sp<LooperThread> thread; 112 bool runningLocally; 113 114 { 115 Mutex::Autolock autoLock(mLock); 116 117 thread = mThread; 118 runningLocally = mRunningLocally; 119 mThread.clear(); 120 mRunningLocally = false; 121 } 122 123 if (thread == NULL && !runningLocally) { 124 return INVALID_OPERATION; 125 } 126 127 if (thread != NULL) { 128 thread->requestExit(); 129 } 130 131 mQueueChangedCondition.signal(); 132 133 if (!runningLocally) { 134 thread->requestExitAndWait(); 135 } 136 137 return OK; 138} 139 140void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) { 141 Mutex::Autolock autoLock(mLock); 142 143 int64_t whenUs; 144 if (delayUs > 0) { 145 whenUs = GetNowUs() + delayUs; 146 } else { 147 whenUs = GetNowUs(); 148 } 149 150 List<Event>::iterator it = mEventQueue.begin(); 151 while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) { 152 ++it; 153 } 154 155 Event event; 156 event.mWhenUs = whenUs; 157 event.mMessage = msg; 158 159 if (it == mEventQueue.begin()) { 160 mQueueChangedCondition.signal(); 161 } 162 163 mEventQueue.insert(it, event); 164} 165 166bool ALooper::loop() { 167 Event event; 168 169 { 170 Mutex::Autolock autoLock(mLock); 171 if (mThread == NULL && !mRunningLocally) { 172 return false; 173 } 174 if (mEventQueue.empty()) { 175 mQueueChangedCondition.wait(mLock); 176 return true; 177 } 178 int64_t whenUs = (*mEventQueue.begin()).mWhenUs; 179 int64_t nowUs = GetNowUs(); 180 181 if (whenUs > nowUs) { 182 int64_t delayUs = whenUs - nowUs; 183 mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll); 184 185 return true; 186 } 187 188 event = *mEventQueue.begin(); 189 mEventQueue.erase(mEventQueue.begin()); 190 } 191 192 gLooperRoster.deliverMessage(event.mMessage); 193 194 return true; 195} 196 197} // namespace android 198