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