| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "CallbackProtector.h" |
| #include "sllog.h" |
| |
| #include <media/stagefright/foundation/ADebug.h> |
| |
| //-------------------------------------------------------------------------------------------------- |
| namespace android { |
| |
| |
| CallbackProtector::CallbackProtector() : RefBase(), |
| mSafeToEnterCb(true), |
| mCbCount(0) |
| #ifdef USE_DEBUG |
| , mCallbackThread(NULL), |
| mCallbackTid(0), |
| mRequesterThread(NULL), |
| mRequesterTid(0) |
| #endif |
| { |
| } |
| |
| |
| CallbackProtector::~CallbackProtector() { |
| Mutex::Autolock _l(mLock); |
| if (mCbCount) { |
| SL_LOGE("Callback protector detected an active callback after destroy"); |
| } |
| |
| } |
| |
| |
| // static |
| bool CallbackProtector::enterCbIfOk(const sp<CallbackProtector> &protector) { |
| if (protector != 0) { |
| return protector->enterCb(); |
| } else { |
| SL_LOGE("Callback protector is missing"); |
| return false; |
| } |
| } |
| |
| |
| bool CallbackProtector::enterCb() { |
| Mutex::Autolock _l(mLock); |
| if (mSafeToEnterCb) { |
| mCbCount++; |
| #ifdef USE_DEBUG |
| if (mCbCount > 1) { |
| SL_LOGV("Callback protector allowed multiple or nested callback entry: %u", mCbCount); |
| } else { |
| mCallbackThread = pthread_self(); |
| mCallbackTid = gettid(); |
| } |
| #endif |
| } else { |
| #ifdef USE_DEBUG |
| SL_LOGV("Callback protector denied callback entry by thread %p tid %d during destroy" |
| " requested by thread %p tid %d", |
| (void *) pthread_self(), gettid(), |
| (void *) mRequesterThread, mRequesterTid); |
| #else |
| SL_LOGV("Callback protector denied callback entry during destroy"); |
| #endif |
| } |
| return mSafeToEnterCb; |
| } |
| |
| |
| void CallbackProtector::exitCb() { |
| Mutex::Autolock _l(mLock); |
| |
| CHECK(mCbCount > 0); |
| mCbCount--; |
| |
| if (mCbCount == 0) { |
| if (!mSafeToEnterCb) { |
| #ifdef USE_DEBUG |
| SL_LOGV("Callback protector detected return from callback by thread %p tid %d during" |
| " destroy requested by thread %p tid %d", |
| (void *) mCallbackThread, mCallbackTid, |
| (void *) mRequesterThread, mRequesterTid); |
| #else |
| SL_LOGV("Callback protector detected return from callback during destroy"); |
| #endif |
| mCbExitedCondition.broadcast(); |
| } |
| #ifdef USE_DEBUG |
| mCallbackThread = NULL; |
| mCallbackTid = 0; |
| #endif |
| } |
| } |
| |
| |
| void CallbackProtector::requestCbExitAndWait() { |
| Mutex::Autolock _l(mLock); |
| mSafeToEnterCb = false; |
| #ifdef USE_DEBUG |
| mRequesterThread = pthread_self(); |
| mRequesterTid = gettid(); |
| #endif |
| while (mCbCount) { |
| #ifdef USE_DEBUG |
| SL_LOGV("Callback protector detected in-progress callback by thread %p tid %d during" |
| " blocking destroy requested by thread %p tid %d", |
| (void *) mCallbackThread, mCallbackTid, |
| (void *) pthread_self(), gettid()); |
| #else |
| SL_LOGV("Callback protector detected in-progress callback during blocking destroy"); |
| #endif |
| mCbExitedCondition.wait(mLock); |
| } |
| } |
| |
| |
| void CallbackProtector::requestCbExit() { |
| Mutex::Autolock _l(mLock); |
| mSafeToEnterCb = false; |
| #ifdef USE_DEBUG |
| mRequesterThread = pthread_self(); |
| mRequesterTid = gettid(); |
| #endif |
| if (mCbCount) { |
| #ifdef USE_DEBUG |
| SL_LOGV("Callback protector detected in-progress callback by thread %p tid %d during" |
| " non-blocking destroy requested by thread %p tid %d", |
| (void *) mCallbackThread, mCallbackTid, |
| (void *) pthread_self(), gettid()); |
| #else |
| SL_LOGV("Callback protector detected in-progress callback during non-blocking destroy"); |
| #endif |
| } |
| } |
| |
| } // namespace android |