blob: 7e9c4bfe69917ab77958dd0e27b7509c637066c8 [file] [log] [blame]
Andreas Huber20111aa2009-07-14 16:56:47 -07001/*
2 * Copyright (C) 2009 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#undef __STRICT_ANSI__
18#define __STDINT_LIMITS
Marco Nelissen361f4822009-07-16 17:10:51 -070019#define __STDC_LIMIT_MACROS
Andreas Huber20111aa2009-07-14 16:56:47 -070020#include <stdint.h>
21
Andreas Huber874b55f2010-04-12 13:10:20 -070022//#define LOG_NDEBUG 0
Andreas Huber20111aa2009-07-14 16:56:47 -070023#define LOG_TAG "TimedEventQueue"
24#include <utils/Log.h>
Marco Nelissen17e8ad92010-06-15 12:34:50 -070025#include <utils/threads.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070026
Andreas Huber89e69da2009-10-13 10:22:55 -070027#include "include/TimedEventQueue.h"
28
Andreas Huber03f4e142010-03-29 11:52:08 -070029#include <sys/prctl.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070030#include <sys/time.h>
31
James Dongf1d5aa12012-02-06 23:46:37 -080032#include <media/stagefright/foundation/ADebug.h>
Andreas Huberfa0e0332012-10-01 16:03:44 -070033#include <media/stagefright/foundation/ALooper.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070034
35namespace android {
36
37TimedEventQueue::TimedEventQueue()
Andreas Huberbe11f392009-11-17 10:25:01 -080038 : mNextEventID(1),
39 mRunning(false),
Andreas Huber20111aa2009-07-14 16:56:47 -070040 mStopped(false) {
41}
42
43TimedEventQueue::~TimedEventQueue() {
44 stop();
45}
46
47void TimedEventQueue::start() {
48 if (mRunning) {
49 return;
50 }
51
52 mStopped = false;
53
54 pthread_attr_t attr;
55 pthread_attr_init(&attr);
56 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
57
58 pthread_create(&mThread, &attr, ThreadWrapper, this);
59
60 pthread_attr_destroy(&attr);
61
62 mRunning = true;
63}
64
65void TimedEventQueue::stop(bool flush) {
66 if (!mRunning) {
67 return;
68 }
69
70 if (flush) {
71 postEventToBack(new StopEvent);
72 } else {
73 postTimedEvent(new StopEvent, INT64_MIN);
74 }
75
76 void *dummy;
77 pthread_join(mThread, &dummy);
78
79 mQueue.clear();
80
81 mRunning = false;
82}
83
Andreas Huberbe11f392009-11-17 10:25:01 -080084TimedEventQueue::event_id TimedEventQueue::postEvent(const sp<Event> &event) {
Andreas Huber20111aa2009-07-14 16:56:47 -070085 // Reserve an earlier timeslot an INT64_MIN to be able to post
86 // the StopEvent to the absolute head of the queue.
Andreas Huberbe11f392009-11-17 10:25:01 -080087 return postTimedEvent(event, INT64_MIN + 1);
Andreas Huber20111aa2009-07-14 16:56:47 -070088}
89
Andreas Huberbe11f392009-11-17 10:25:01 -080090TimedEventQueue::event_id TimedEventQueue::postEventToBack(
91 const sp<Event> &event) {
92 return postTimedEvent(event, INT64_MAX);
Andreas Huber20111aa2009-07-14 16:56:47 -070093}
94
Andreas Huberbe11f392009-11-17 10:25:01 -080095TimedEventQueue::event_id TimedEventQueue::postEventWithDelay(
Andreas Huber20111aa2009-07-14 16:56:47 -070096 const sp<Event> &event, int64_t delay_us) {
Andreas Huber0c891992009-08-26 14:48:20 -070097 CHECK(delay_us >= 0);
Andreas Huberfa0e0332012-10-01 16:03:44 -070098 return postTimedEvent(event, ALooper::GetNowUs() + delay_us);
Andreas Huber20111aa2009-07-14 16:56:47 -070099}
100
Andreas Huberbe11f392009-11-17 10:25:01 -0800101TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
Andreas Huber20111aa2009-07-14 16:56:47 -0700102 const sp<Event> &event, int64_t realtime_us) {
103 Mutex::Autolock autoLock(mLock);
104
Andreas Huberbe11f392009-11-17 10:25:01 -0800105 event->setEventID(mNextEventID++);
106
Andreas Huber20111aa2009-07-14 16:56:47 -0700107 List<QueueItem>::iterator it = mQueue.begin();
108 while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
109 ++it;
110 }
111
112 QueueItem item;
113 item.event = event;
114 item.realtime_us = realtime_us;
115
116 if (it == mQueue.begin()) {
117 mQueueHeadChangedCondition.signal();
118 }
119
120 mQueue.insert(it, item);
121
122 mQueueNotEmptyCondition.signal();
Andreas Huberbe11f392009-11-17 10:25:01 -0800123
124 return event->eventID();
Andreas Huber20111aa2009-07-14 16:56:47 -0700125}
126
Andreas Huberbe11f392009-11-17 10:25:01 -0800127static bool MatchesEventID(
128 void *cookie, const sp<TimedEventQueue::Event> &event) {
129 TimedEventQueue::event_id *id =
130 static_cast<TimedEventQueue::event_id *>(cookie);
Andreas Huber20111aa2009-07-14 16:56:47 -0700131
Andreas Huberbe11f392009-11-17 10:25:01 -0800132 if (event->eventID() != *id) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700133 return false;
134 }
135
Andreas Huberbe11f392009-11-17 10:25:01 -0800136 *id = 0;
Andreas Huber20111aa2009-07-14 16:56:47 -0700137
138 return true;
139}
140
Andreas Huberbe11f392009-11-17 10:25:01 -0800141bool TimedEventQueue::cancelEvent(event_id id) {
Andreas Huberbfa6b2d2009-11-20 09:32:46 -0800142 if (id == 0) {
143 return false;
144 }
Andreas Huberbe11f392009-11-17 10:25:01 -0800145
146 cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */);
147
148 // if MatchesEventID found a match, it will have set id to 0
149 // (which is not a valid event_id).
150
151 return id == 0;
152}
153
154void TimedEventQueue::cancelEvents(
155 bool (*predicate)(void *cookie, const sp<Event> &event),
156 void *cookie,
157 bool stopAfterFirstMatch) {
158 Mutex::Autolock autoLock(mLock);
159
160 List<QueueItem>::iterator it = mQueue.begin();
161 while (it != mQueue.end()) {
162 if (!(*predicate)(cookie, (*it).event)) {
163 ++it;
164 continue;
165 }
166
167 if (it == mQueue.begin()) {
168 mQueueHeadChangedCondition.signal();
169 }
170
Steve Block3856b092011-10-20 11:56:00 +0100171 ALOGV("cancelling event %d", (*it).event->eventID());
Andreas Huber874b55f2010-04-12 13:10:20 -0700172
Andreas Huberbfa6b2d2009-11-20 09:32:46 -0800173 (*it).event->setEventID(0);
Andreas Huberbe11f392009-11-17 10:25:01 -0800174 it = mQueue.erase(it);
175
176 if (stopAfterFirstMatch) {
177 return;
178 }
179 }
180}
181
Andreas Huber20111aa2009-07-14 16:56:47 -0700182// static
Andreas Huber20111aa2009-07-14 16:56:47 -0700183void *TimedEventQueue::ThreadWrapper(void *me) {
Marco Nelissen0df82fc2010-02-19 15:16:57 -0800184
Glenn Kasten86106f82011-06-14 10:35:34 -0700185 androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
Andreas Huberacb56212010-09-09 16:12:31 -0700186
Andreas Huber20111aa2009-07-14 16:56:47 -0700187 static_cast<TimedEventQueue *>(me)->threadEntry();
188
189 return NULL;
190}
191
192void TimedEventQueue::threadEntry() {
Andreas Huber03f4e142010-03-29 11:52:08 -0700193 prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);
194
Andreas Huber20111aa2009-07-14 16:56:47 -0700195 for (;;) {
Andreas Huber03f4e142010-03-29 11:52:08 -0700196 int64_t now_us = 0;
Andreas Huber20111aa2009-07-14 16:56:47 -0700197 sp<Event> event;
198
199 {
200 Mutex::Autolock autoLock(mLock);
201
202 if (mStopped) {
203 break;
204 }
205
206 while (mQueue.empty()) {
207 mQueueNotEmptyCondition.wait(mLock);
208 }
209
Andreas Huber874b55f2010-04-12 13:10:20 -0700210 event_id eventID = 0;
Andreas Huber20111aa2009-07-14 16:56:47 -0700211 for (;;) {
Andreas Huber03f4e142010-03-29 11:52:08 -0700212 if (mQueue.empty()) {
213 // The only event in the queue could have been cancelled
214 // while we were waiting for its scheduled time.
215 break;
216 }
Andreas Huber874b55f2010-04-12 13:10:20 -0700217
218 List<QueueItem>::iterator it = mQueue.begin();
219 eventID = (*it).event->eventID();
Andreas Huber20111aa2009-07-14 16:56:47 -0700220
Andreas Huberfa0e0332012-10-01 16:03:44 -0700221 now_us = ALooper::GetNowUs();
Andreas Huber20111aa2009-07-14 16:56:47 -0700222 int64_t when_us = (*it).realtime_us;
223
224 int64_t delay_us;
225 if (when_us < 0 || when_us == INT64_MAX) {
226 delay_us = 0;
227 } else {
228 delay_us = when_us - now_us;
229 }
230
231 if (delay_us <= 0) {
232 break;
233 }
234
Andreas Huber03f4e142010-03-29 11:52:08 -0700235 static int64_t kMaxTimeoutUs = 10000000ll; // 10 secs
236 bool timeoutCapped = false;
237 if (delay_us > kMaxTimeoutUs) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000238 ALOGW("delay_us exceeds max timeout: %lld us", delay_us);
Andreas Huber20111aa2009-07-14 16:56:47 -0700239
Andreas Huber03f4e142010-03-29 11:52:08 -0700240 // We'll never block for more than 10 secs, instead
241 // we will split up the full timeout into chunks of
242 // 10 secs at a time. This will also avoid overflow
243 // when converting from us to ns.
244 delay_us = kMaxTimeoutUs;
245 timeoutCapped = true;
246 }
247
248 status_t err = mQueueHeadChangedCondition.waitRelative(
249 mLock, delay_us * 1000ll);
250
251 if (!timeoutCapped && err == -ETIMEDOUT) {
252 // We finally hit the time this event is supposed to
253 // trigger.
Andreas Huberfa0e0332012-10-01 16:03:44 -0700254 now_us = ALooper::GetNowUs();
Andreas Huber20111aa2009-07-14 16:56:47 -0700255 break;
256 }
257 }
258
Andreas Huber874b55f2010-04-12 13:10:20 -0700259 // The event w/ this id may have been cancelled while we're
260 // waiting for its trigger-time, in that case
261 // removeEventFromQueue_l will return NULL.
262 // Otherwise, the QueueItem will be removed
263 // from the queue and the referenced event returned.
264 event = removeEventFromQueue_l(eventID);
Andreas Huber20111aa2009-07-14 16:56:47 -0700265 }
266
Andreas Huber874b55f2010-04-12 13:10:20 -0700267 if (event != NULL) {
268 // Fire event with the lock NOT held.
269 event->fire(this, now_us);
270 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700271 }
272}
273
Andreas Huber874b55f2010-04-12 13:10:20 -0700274sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
275 event_id id) {
276 for (List<QueueItem>::iterator it = mQueue.begin();
277 it != mQueue.end(); ++it) {
278 if ((*it).event->eventID() == id) {
279 sp<Event> event = (*it).event;
280 event->setEventID(0);
281
282 mQueue.erase(it);
283
284 return event;
285 }
286 }
287
Steve Block5ff1dd52012-01-05 23:22:43 +0000288 ALOGW("Event %d was not found in the queue, already cancelled?", id);
Andreas Huber874b55f2010-04-12 13:10:20 -0700289
290 return NULL;
291}
292
Andreas Huber20111aa2009-07-14 16:56:47 -0700293} // namespace android
294