Home | History | Annotate | Download | only in rs
      1 /*
      2  * Copyright (C) 2009 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 "rsObjectBase.h"
     18 #include "rsContext.h"
     19 #include "rsDebugHelper.h"
     20 
     21 namespace android {
     22 namespace renderscript {
     23 
     24 pthread_mutex_t ObjectBase::gObjectInitMutex = PTHREAD_MUTEX_INITIALIZER;
     25 
     26 ObjectBase::ObjectBase(Context *rsc) {
     27     mUserRefCount = 0;
     28     mSysRefCount = 0;
     29     mRSC = rsc;
     30     mNext = nullptr;
     31     mPrev = nullptr;
     32     mDH = nullptr;
     33     mName = nullptr;
     34 
     35     if (gDebugStacks || gDebugReferences || gDebugLeaks) {
     36         mDH = new DebugHelper();
     37     }
     38 
     39     rsAssert(rsc);
     40     add();
     41 
     42     if (gDebugLifetime || gDebugReferences) {
     43         ALOGV("ObjectBase constructed %p", this);
     44     }
     45 }
     46 
     47 ObjectBase::~ObjectBase() {
     48     if (gDebugLifetime || gDebugReferences) {
     49         ALOGV("ObjectBase destroyed %p   refs %i %i", this, mUserRefCount, mSysRefCount);
     50     }
     51 
     52     if (gDebugStacks || gDebugReferences || gDebugLeaks) {
     53         if (gDebugStacks || gDebugReferences) {
     54             mDH->dump();
     55         }
     56         delete mDH;
     57         mDH = nullptr;
     58     }
     59 
     60     free(const_cast<char *>(mName));
     61 
     62     if (mPrev || mNext) {
     63         // While the normal practice is to call remove before we call
     64         // delete.  Its possible for objects without a re-use list
     65         // for avoiding duplication to be created on the stack.  In those
     66         // cases we need to remove ourself here.
     67         asyncLock();
     68         remove();
     69         asyncUnlock();
     70     }
     71 
     72     rsAssert(!mUserRefCount);
     73     rsAssert(!mSysRefCount);
     74 }
     75 
     76 void ObjectBase::dumpLOGV(const char *op) const {
     77     if (mName) {
     78         ALOGV("%s RSobj %p, name %s, refs %i,%i  links %p,%p,%p",
     79              op, this, mName, mUserRefCount, mSysRefCount, mNext, mPrev, mRSC);
     80     } else {
     81         ALOGV("%s RSobj %p, no-name, refs %i,%i  links %p,%p,%p",
     82              op, this, mUserRefCount, mSysRefCount, mNext, mPrev, mRSC);
     83     }
     84 }
     85 
     86 void ObjectBase::incUserRef() const {
     87     __sync_fetch_and_add(&mUserRefCount, 1);
     88     if (gDebugReferences) {
     89         ALOGV("ObjectBase %p incU ref %i, %i", this, mUserRefCount, mSysRefCount);
     90     }
     91 }
     92 
     93 void ObjectBase::incSysRef() const {
     94     __sync_fetch_and_add(&mSysRefCount, 1);
     95     if (gDebugReferences) {
     96         ALOGV("ObjectBase %p incS ref %i, %i", this, mUserRefCount, mSysRefCount);
     97     }
     98 }
     99 
    100 void ObjectBase::preDestroy() const {
    101 }
    102 
    103 bool ObjectBase::freeChildren() {
    104     return false;
    105 }
    106 
    107 bool ObjectBase::checkDelete(const ObjectBase *ref) {
    108     if (!ref) {
    109         return false;
    110     }
    111 
    112     asyncLock();
    113     // This lock protects us against the non-RS threads changing
    114     // the ref counts.  At this point we should be the only thread
    115     // working on them.
    116     if (ref->mUserRefCount || ref->mSysRefCount) {
    117         asyncUnlock();
    118         return false;
    119     }
    120 
    121     ref->remove();
    122     // At this point we can unlock because there should be no possible way
    123     // for another thread to reference this object.
    124     ref->preDestroy();
    125     asyncUnlock();
    126     delete ref;
    127     return true;
    128 }
    129 
    130 bool ObjectBase::decUserRef() const {
    131     rsAssert(mUserRefCount > 0);
    132     if (gDebugReferences) {
    133         ALOGV("ObjectBase %p decU ref %i, %i", this, mUserRefCount, mSysRefCount);
    134         if (mUserRefCount <= 0) {
    135             mDH->dump();
    136         }
    137     }
    138 
    139 
    140     if ((__sync_fetch_and_sub(&mUserRefCount, 1) <= 1)) {
    141         __sync_synchronize();
    142         if (mSysRefCount <= 0) {
    143             return checkDelete(this);
    144         }
    145     }
    146     return false;
    147 }
    148 
    149 bool ObjectBase::zeroUserRef() const {
    150     if (gDebugReferences) {
    151         ALOGV("ObjectBase %p zeroU ref %i, %i", this, mUserRefCount, mSysRefCount);
    152     }
    153 
    154     __sync_and_and_fetch(&mUserRefCount, 0);
    155     if (mSysRefCount <= 0) {
    156         return checkDelete(this);
    157     }
    158     return false;
    159 }
    160 
    161 bool ObjectBase::decSysRef() const {
    162     if (gDebugReferences) {
    163         ALOGV("ObjectBase %p decS ref %i, %i", this, mUserRefCount, mSysRefCount);
    164     }
    165 
    166     rsAssert(mSysRefCount > 0);
    167     if ((__sync_fetch_and_sub(&mSysRefCount, 1) <= 1)) {
    168         __sync_synchronize();
    169         if (mUserRefCount <= 0) {
    170             return checkDelete(this);
    171         }
    172     }
    173     return false;
    174 }
    175 
    176 void ObjectBase::setName(const char *name) {
    177     mName = strdup(name);
    178 }
    179 
    180 void ObjectBase::setName(const char *name, uint32_t len) {
    181     char *c = (char*)calloc(len + 1, sizeof(char));
    182     rsAssert(c);
    183     memcpy(c, name, len);
    184     mName = c;
    185 }
    186 
    187 void ObjectBase::asyncLock() {
    188     pthread_mutex_lock(&gObjectInitMutex);
    189 }
    190 
    191 void ObjectBase::asyncUnlock() {
    192     pthread_mutex_unlock(&gObjectInitMutex);
    193 }
    194 
    195 void ObjectBase::add() const {
    196     asyncLock();
    197 
    198     rsAssert(!mNext);
    199     rsAssert(!mPrev);
    200     mNext = mRSC->mObjHead;
    201     if (mRSC->mObjHead) {
    202         mRSC->mObjHead->mPrev = this;
    203     }
    204     mRSC->mObjHead = this;
    205 
    206     asyncUnlock();
    207 }
    208 
    209 void ObjectBase::remove() const {
    210     if (!mRSC) {
    211         rsAssert(!mPrev);
    212         rsAssert(!mNext);
    213         return;
    214     }
    215 
    216     if (mRSC->mObjHead == this) {
    217         mRSC->mObjHead = mNext;
    218     }
    219     if (mPrev) {
    220         mPrev->mNext = mNext;
    221     }
    222     if (mNext) {
    223         mNext->mPrev = mPrev;
    224     }
    225     mPrev = nullptr;
    226     mNext = nullptr;
    227 }
    228 
    229 void ObjectBase::zeroAllUserRef(Context *rsc) {
    230     if (gDebugReferences || gDebugLeaks) {
    231         ALOGV("Forcing release of all outstanding user refs.");
    232     }
    233 
    234     // This operation can be slow, only to be called during context cleanup.
    235     const ObjectBase * o = rsc->mObjHead;
    236     while (o) {
    237         //ALOGE("o %p", o);
    238         if (o->zeroUserRef()) {
    239             // deleted the object and possibly others, restart from head.
    240             o = rsc->mObjHead;
    241             //ALOGE("o head %p", o);
    242         } else {
    243             o = o->mNext;
    244             //ALOGE("o next %p", o);
    245         }
    246     }
    247 
    248     if (gDebugReferences || gDebugLeaks) {
    249         ALOGV("Objects remaining.");
    250         dumpAll(rsc);
    251     }
    252 }
    253 
    254 void ObjectBase::freeAllChildren(Context *rsc) {
    255     if (gDebugReferences) {
    256         ALOGV("Forcing release of all child objects.");
    257     }
    258 
    259     // This operation can be slow, only to be called during context cleanup.
    260     ObjectBase * o = (ObjectBase *)rsc->mObjHead;
    261     while (o) {
    262         if (o->freeChildren()) {
    263             // deleted ref to self and possibly others, restart from head.
    264             o = (ObjectBase *)rsc->mObjHead;
    265         } else {
    266             o = (ObjectBase *)o->mNext;
    267         }
    268     }
    269 
    270     if (gDebugReferences) {
    271         ALOGV("Objects remaining.");
    272         dumpAll(rsc);
    273     }
    274 }
    275 
    276 void ObjectBase::dumpAll(Context *rsc) {
    277     asyncLock();
    278 
    279     ALOGV("Dumping all objects");
    280     const ObjectBase * o = rsc->mObjHead;
    281     while (o) {
    282         ALOGV(" Object %p", o);
    283         o->dumpLOGV("  ");
    284         if (o->mDH != nullptr) {
    285             o->mDH->dump();
    286         }
    287         o = o->mNext;
    288     }
    289 
    290     asyncUnlock();
    291 }
    292 
    293 bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj) {
    294     asyncLock();
    295 
    296     const ObjectBase * o = rsc->mObjHead;
    297     while (o) {
    298         if (o == obj) {
    299             asyncUnlock();
    300             return true;
    301         }
    302         o = o->mNext;
    303     }
    304     asyncUnlock();
    305     return false;
    306 }
    307 
    308 void ObjectBase::callUpdateCacheObject(const Context *rsc, void *dstObj) const {
    309     //ALOGE("ObjectBase::callUpdateCacheObject %p  %p", this, dstObj);
    310     *((const void **)dstObj) = this;
    311 }
    312 
    313 } // namespace renderscript
    314 } // namespace android
    315