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