/* * 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 //-------------------------------------------------------------------------------------------------- namespace android { CallbackProtector::CallbackProtector() : RefBase(), mSafeToEnterCb(true), mCbCount(0) #ifdef USE_DEBUG , mCallbackThread((pthread_t) NULL), mCallbackTid(0), mRequesterThread((pthread_t) 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 &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 = (pthread_t) 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