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