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