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