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