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
ObjectBase(Context * rsc)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
~ObjectBase()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
dumpLOGV(const char * op) const76 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
incUserRef() const86 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
incSysRef() const93 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
preDestroy() const100 void ObjectBase::preDestroy() const {
101 }
102
freeChildren()103 bool ObjectBase::freeChildren() {
104 return false;
105 }
106
checkDelete(const ObjectBase * ref)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
decUserRef() const130 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
zeroUserRef() const149 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
decSysRef() const161 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
setName(const char * name)176 void ObjectBase::setName(const char *name) {
177 mName = strdup(name);
178 }
179
setName(const char * name,uint32_t len)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
asyncLock()187 void ObjectBase::asyncLock() {
188 pthread_mutex_lock(&gObjectInitMutex);
189 }
190
asyncUnlock()191 void ObjectBase::asyncUnlock() {
192 pthread_mutex_unlock(&gObjectInitMutex);
193 }
194
add() const195 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
remove() const209 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
zeroAllUserRef(Context * rsc)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 #ifdef __clang_analyzer__
240 // Assure the static analyzer that we updated mObjHead. Otherwise,
241 // it complains about a use-after-free here. Needed for b/27101951.
242 if (o == rsc->mObjHead) {
243 abort();
244 }
245 #endif
246 // deleted the object and possibly others, restart from head.
247 o = rsc->mObjHead;
248 //ALOGE("o head %p", o);
249 } else {
250 o = o->mNext;
251 //ALOGE("o next %p", o);
252 }
253 }
254
255 if (gDebugReferences || gDebugLeaks) {
256 ALOGV("Objects remaining.");
257 dumpAll(rsc);
258 }
259 }
260
freeAllChildren(Context * rsc)261 void ObjectBase::freeAllChildren(Context *rsc) {
262 if (gDebugReferences) {
263 ALOGV("Forcing release of all child objects.");
264 }
265
266 // This operation can be slow, only to be called during context cleanup.
267 ObjectBase * o = (ObjectBase *)rsc->mObjHead;
268 while (o) {
269 if (o->freeChildren()) {
270 // deleted ref to self and possibly others, restart from head.
271 o = (ObjectBase *)rsc->mObjHead;
272 } else {
273 o = (ObjectBase *)o->mNext;
274 }
275 }
276
277 if (gDebugReferences) {
278 ALOGV("Objects remaining.");
279 dumpAll(rsc);
280 }
281 }
282
dumpAll(Context * rsc)283 void ObjectBase::dumpAll(Context *rsc) {
284 asyncLock();
285
286 ALOGV("Dumping all objects");
287 const ObjectBase * o = rsc->mObjHead;
288 while (o) {
289 ALOGV(" Object %p", o);
290 o->dumpLOGV(" ");
291 if (o->mDH != nullptr) {
292 o->mDH->dump();
293 }
294 o = o->mNext;
295 }
296
297 asyncUnlock();
298 }
299
isValid(const Context * rsc,const ObjectBase * obj)300 bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj) {
301 asyncLock();
302
303 const ObjectBase * o = rsc->mObjHead;
304 while (o) {
305 if (o == obj) {
306 asyncUnlock();
307 return true;
308 }
309 o = o->mNext;
310 }
311 asyncUnlock();
312 return false;
313 }
314
callUpdateCacheObject(const Context * rsc,void * dstObj) const315 void ObjectBase::callUpdateCacheObject(const Context *rsc, void *dstObj) const {
316 //ALOGE("ObjectBase::callUpdateCacheObject %p %p", this, dstObj);
317 *((const void **)dstObj) = this;
318 }
319
320 } // namespace renderscript
321 } // namespace android
322