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