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