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 //ALOGV("~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 //ALOGV("calling add rsc %p", mRSC); 182 mNext = mRSC->mObjHead; 183 if (mRSC->mObjHead) { 184 mRSC->mObjHead->mPrev = this; 185 } 186 mRSC->mObjHead = this; 187 188 asyncUnlock(); 189 } 190 191 void ObjectBase::remove() const { 192 //ALOGV("calling remove rsc %p", mRSC); 193 if (!mRSC) { 194 rsAssert(!mPrev); 195 rsAssert(!mNext); 196 return; 197 } 198 199 if (mRSC->mObjHead == this) { 200 mRSC->mObjHead = mNext; 201 } 202 if (mPrev) { 203 mPrev->mNext = mNext; 204 } 205 if (mNext) { 206 mNext->mPrev = mPrev; 207 } 208 mPrev = NULL; 209 mNext = NULL; 210 } 211 212 void ObjectBase::zeroAllUserRef(Context *rsc) { 213 if (rsc->props.mLogObjects) { 214 ALOGV("Forcing release of all outstanding user refs."); 215 } 216 217 // This operation can be slow, only to be called during context cleanup. 218 const ObjectBase * o = rsc->mObjHead; 219 while (o) { 220 //ALOGE("o %p", o); 221 if (o->zeroUserRef()) { 222 // deleted the object and possibly others, restart from head. 223 o = rsc->mObjHead; 224 //ALOGE("o head %p", o); 225 } else { 226 o = o->mNext; 227 //ALOGE("o next %p", o); 228 } 229 } 230 231 if (rsc->props.mLogObjects) { 232 ALOGV("Objects remaining."); 233 dumpAll(rsc); 234 } 235 } 236 237 void ObjectBase::freeAllChildren(Context *rsc) { 238 if (rsc->props.mLogObjects) { 239 ALOGV("Forcing release of all child objects."); 240 } 241 242 // This operation can be slow, only to be called during context cleanup. 243 ObjectBase * o = (ObjectBase *)rsc->mObjHead; 244 while (o) { 245 if (o->freeChildren()) { 246 // deleted ref to self and possibly others, restart from head. 247 o = (ObjectBase *)rsc->mObjHead; 248 } else { 249 o = (ObjectBase *)o->mNext; 250 } 251 } 252 253 if (rsc->props.mLogObjects) { 254 ALOGV("Objects remaining."); 255 dumpAll(rsc); 256 } 257 } 258 259 void ObjectBase::dumpAll(Context *rsc) { 260 asyncLock(); 261 262 ALOGV("Dumping all objects"); 263 const ObjectBase * o = rsc->mObjHead; 264 while (o) { 265 ALOGV(" Object %p", o); 266 o->dumpLOGV(" "); 267 o = o->mNext; 268 } 269 270 asyncUnlock(); 271 } 272 273 bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj) { 274 asyncLock(); 275 276 const ObjectBase * o = rsc->mObjHead; 277 while (o) { 278 if (o == obj) { 279 asyncUnlock(); 280 return true; 281 } 282 o = o->mNext; 283 } 284 asyncUnlock(); 285 return false; 286 } 287