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