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 //-------------------------------------------------------------------------------------------------- 23 namespace android { 24 25 26 CallbackProtector::CallbackProtector() : RefBase(), 27 mSafeToEnterCb(true), 28 mCbCount(0) 29 #ifdef USE_DEBUG 30 , mCallbackThread(NULL), 31 mCallbackTid(0), 32 mRequesterThread(NULL), 33 mRequesterTid(0) 34 #endif 35 { 36 } 37 38 39 CallbackProtector::~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 49 bool 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 59 bool 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 85 void 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 = NULL; 105 mCallbackTid = 0; 106 #endif 107 } 108 } 109 110 111 void 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 132 void 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