1/* 2 * Copyright (C) 2011 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#include "CallbackProtector.h" 18#include "sllog.h" 19 20#include <media/stagefright/foundation/ADebug.h> 21 22//-------------------------------------------------------------------------------------------------- 23namespace android { 24 25 26CallbackProtector::CallbackProtector() : RefBase(), 27 mSafeToEnterCb(true), 28 mCbCount(0) 29#ifdef USE_DEBUG 30 , mCallbackThread((pthread_t) NULL), 31 mCallbackTid(0), 32 mRequesterThread((pthread_t) NULL), 33 mRequesterTid(0) 34#endif 35{ 36} 37 38 39CallbackProtector::~CallbackProtector() { 40 Mutex::Autolock _l(mLock); 41 if (mCbCount) { 42 SL_LOGE("Callback protector detected an active callback after destroy"); 43 } 44 45} 46 47 48// static 49bool CallbackProtector::enterCbIfOk(const sp<CallbackProtector> &protector) { 50 if (protector != 0) { 51 return protector->enterCb(); 52 } else { 53 SL_LOGE("Callback protector is missing"); 54 return false; 55 } 56} 57 58 59bool CallbackProtector::enterCb() { 60 Mutex::Autolock _l(mLock); 61 if (mSafeToEnterCb) { 62 mCbCount++; 63#ifdef USE_DEBUG 64 if (mCbCount > 1) { 65 SL_LOGV("Callback protector allowed multiple or nested callback entry: %u", mCbCount); 66 } else { 67 mCallbackThread = pthread_self(); 68 mCallbackTid = gettid(); 69 } 70#endif 71 } else { 72#ifdef USE_DEBUG 73 SL_LOGV("Callback protector denied callback entry by thread %p tid %d during destroy" 74 " requested by thread %p tid %d", 75 (void *) pthread_self(), gettid(), 76 (void *) mRequesterThread, mRequesterTid); 77#else 78 SL_LOGV("Callback protector denied callback entry during destroy"); 79#endif 80 } 81 return mSafeToEnterCb; 82} 83 84 85void CallbackProtector::exitCb() { 86 Mutex::Autolock _l(mLock); 87 88 CHECK(mCbCount > 0); 89 mCbCount--; 90 91 if (mCbCount == 0) { 92 if (!mSafeToEnterCb) { 93#ifdef USE_DEBUG 94 SL_LOGV("Callback protector detected return from callback by thread %p tid %d during" 95 " destroy requested by thread %p tid %d", 96 (void *) mCallbackThread, mCallbackTid, 97 (void *) mRequesterThread, mRequesterTid); 98#else 99 SL_LOGV("Callback protector detected return from callback during destroy"); 100#endif 101 mCbExitedCondition.broadcast(); 102 } 103#ifdef USE_DEBUG 104 mCallbackThread = (pthread_t) NULL; 105 mCallbackTid = 0; 106#endif 107 } 108} 109 110 111void CallbackProtector::requestCbExitAndWait() { 112 Mutex::Autolock _l(mLock); 113 mSafeToEnterCb = false; 114#ifdef USE_DEBUG 115 mRequesterThread = pthread_self(); 116 mRequesterTid = gettid(); 117#endif 118 while (mCbCount) { 119#ifdef USE_DEBUG 120 SL_LOGV("Callback protector detected in-progress callback by thread %p tid %d during" 121 " blocking destroy requested by thread %p tid %d", 122 (void *) mCallbackThread, mCallbackTid, 123 (void *) pthread_self(), gettid()); 124#else 125 SL_LOGV("Callback protector detected in-progress callback during blocking destroy"); 126#endif 127 mCbExitedCondition.wait(mLock); 128 } 129} 130 131 132void CallbackProtector::requestCbExit() { 133 Mutex::Autolock _l(mLock); 134 mSafeToEnterCb = false; 135#ifdef USE_DEBUG 136 mRequesterThread = pthread_self(); 137 mRequesterTid = gettid(); 138#endif 139 if (mCbCount) { 140#ifdef USE_DEBUG 141 SL_LOGV("Callback protector detected in-progress callback by thread %p tid %d during" 142 " non-blocking destroy requested by thread %p tid %d", 143 (void *) mCallbackThread, mCallbackTid, 144 (void *) pthread_self(), gettid()); 145#else 146 SL_LOGV("Callback protector detected in-progress callback during non-blocking destroy"); 147#endif 148 } 149} 150 151} // namespace android 152