1 /*
2 * Copyright (C) 2018 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
18 #include <media/TimeCheck.h>
19
20 namespace android {
21
22 /* static */
getTimeCheckThread()23 sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
24 {
25 static sp<TimeCheck::TimeCheckThread> sTimeCheckThread = new TimeCheck::TimeCheckThread();
26 return sTimeCheckThread;
27 }
28
TimeCheck(const char * tag,uint32_t timeoutMs)29 TimeCheck::TimeCheck(const char *tag, uint32_t timeoutMs)
30 : mEndTimeNs(getTimeCheckThread()->startMonitoring(tag, timeoutMs))
31 {
32 }
33
~TimeCheck()34 TimeCheck::~TimeCheck() {
35 getTimeCheckThread()->stopMonitoring(mEndTimeNs);
36 }
37
~TimeCheckThread()38 TimeCheck::TimeCheckThread::~TimeCheckThread()
39 {
40 AutoMutex _l(mMutex);
41 requestExit();
42 mMonitorRequests.clear();
43 mCond.signal();
44 }
45
startMonitoring(const char * tag,uint32_t timeoutMs)46 nsecs_t TimeCheck::TimeCheckThread::startMonitoring(const char *tag, uint32_t timeoutMs) {
47 Mutex::Autolock _l(mMutex);
48 nsecs_t endTimeNs = systemTime() + milliseconds(timeoutMs);
49 for (; mMonitorRequests.indexOfKey(endTimeNs) >= 0; ++endTimeNs);
50 mMonitorRequests.add(endTimeNs, tag);
51 mCond.signal();
52 return endTimeNs;
53 }
54
stopMonitoring(nsecs_t endTimeNs)55 void TimeCheck::TimeCheckThread::stopMonitoring(nsecs_t endTimeNs) {
56 Mutex::Autolock _l(mMutex);
57 mMonitorRequests.removeItem(endTimeNs);
58 mCond.signal();
59 }
60
threadLoop()61 bool TimeCheck::TimeCheckThread::threadLoop()
62 {
63 status_t status = TIMED_OUT;
64 const char *tag;
65 {
66 AutoMutex _l(mMutex);
67
68 if (exitPending()) {
69 return false;
70 }
71
72 nsecs_t endTimeNs = INT64_MAX;
73 // KeyedVector mMonitorRequests is ordered so take first entry as next timeout
74 if (mMonitorRequests.size() != 0) {
75 endTimeNs = mMonitorRequests.keyAt(0);
76 tag = mMonitorRequests.valueAt(0);
77 }
78
79 const nsecs_t waitTimeNs = endTimeNs - systemTime();
80 if (waitTimeNs > 0) {
81 status = mCond.waitRelative(mMutex, waitTimeNs);
82 }
83 }
84 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
85 return true;
86 }
87
88 }; // namespace android
89