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