Home | History | Annotate | Download | only in android
      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