/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rsObjectBase.h"

#ifndef ANDROID_RS_BUILD_FOR_HOST
#include "rsContext.h"
#else
#include "rsContextHostStub.h"
#endif


using namespace android;
using namespace android::renderscript;

pthread_mutex_t ObjectBase::gObjectInitMutex = PTHREAD_MUTEX_INITIALIZER;

ObjectBase::ObjectBase(Context *rsc) {
    mUserRefCount = 0;
    mSysRefCount = 0;
    mRSC = rsc;
    mNext = NULL;
    mPrev = NULL;

#if RS_OBJECT_DEBUG
    mStack.update(2);
#endif

    rsAssert(rsc);
    add();
    //LOGV("ObjectBase %p con", this);
}

ObjectBase::~ObjectBase() {
    //LOGV("~ObjectBase %p  ref %i,%i", this, mUserRefCount, mSysRefCount);
#if RS_OBJECT_DEBUG
    mStack.dump();
#endif

    if (mPrev || mNext) {
        // While the normal practice is to call remove before we call
        // delete.  Its possible for objects without a re-use list
        // for avoiding duplication to be created on the stack.  In those
        // cases we need to remove ourself here.
        asyncLock();
        remove();
        asyncUnlock();
    }

    rsAssert(!mUserRefCount);
    rsAssert(!mSysRefCount);
}

void ObjectBase::dumpLOGV(const char *op) const {
    if (mName.size()) {
        LOGV("%s RSobj %p, name %s, refs %i,%i  links %p,%p,%p",
             op, this, mName.string(), mUserRefCount, mSysRefCount, mNext, mPrev, mRSC);
    } else {
        LOGV("%s RSobj %p, no-name, refs %i,%i  links %p,%p,%p",
             op, this, mUserRefCount, mSysRefCount, mNext, mPrev, mRSC);
    }
}

void ObjectBase::incUserRef() const {
    android_atomic_inc(&mUserRefCount);
    //LOGV("ObjectBase %p incU ref %i, %i", this, mUserRefCount, mSysRefCount);
}

void ObjectBase::incSysRef() const {
    android_atomic_inc(&mSysRefCount);
    //LOGV("ObjectBase %p incS ref %i, %i", this, mUserRefCount, mSysRefCount);
}

void ObjectBase::preDestroy() const {
}

bool ObjectBase::checkDelete(const ObjectBase *ref) {
    if (!ref) {
        return false;
    }

    asyncLock();
    // This lock protects us against the non-RS threads changing
    // the ref counts.  At this point we should be the only thread
    // working on them.
    if (ref->mUserRefCount || ref->mSysRefCount) {
        asyncUnlock();
        return false;
    }

    ref->remove();
    // At this point we can unlock because there should be no possible way
    // for another thread to reference this object.
    ref->preDestroy();
    asyncUnlock();
    delete ref;
    return true;
}

bool ObjectBase::decUserRef() const {
    rsAssert(mUserRefCount > 0);
#if RS_OBJECT_DEBUG
    LOGV("ObjectBase %p decU ref %i, %i", this, mUserRefCount, mSysRefCount);
    if (mUserRefCount <= 0) {
        mStack.dump();
    }
#endif


    if ((android_atomic_dec(&mUserRefCount) <= 1) &&
        (android_atomic_acquire_load(&mSysRefCount) <= 0)) {
        return checkDelete(this);
    }
    return false;
}

bool ObjectBase::zeroUserRef() const {
    //LOGV("ObjectBase %p zeroU ref %i, %i", this, mUserRefCount, mSysRefCount);
    android_atomic_acquire_store(0, &mUserRefCount);
    if (android_atomic_acquire_load(&mSysRefCount) <= 0) {
        return checkDelete(this);
    }
    return false;
}

bool ObjectBase::decSysRef() const {
    //LOGV("ObjectBase %p decS ref %i, %i", this, mUserRefCount, mSysRefCount);
    rsAssert(mSysRefCount > 0);
    if ((android_atomic_dec(&mSysRefCount) <= 1) &&
        (android_atomic_acquire_load(&mUserRefCount) <= 0)) {
        return checkDelete(this);
    }
    return false;
}

void ObjectBase::setName(const char *name) {
    mName.setTo(name);
}

void ObjectBase::setName(const char *name, uint32_t len) {
    mName.setTo(name, len);
}

void ObjectBase::asyncLock() {
    pthread_mutex_lock(&gObjectInitMutex);
}

void ObjectBase::asyncUnlock() {
    pthread_mutex_unlock(&gObjectInitMutex);
}

void ObjectBase::add() const {
    asyncLock();

    rsAssert(!mNext);
    rsAssert(!mPrev);
    //LOGV("calling add  rsc %p", mRSC);
    mNext = mRSC->mObjHead;
    if (mRSC->mObjHead) {
        mRSC->mObjHead->mPrev = this;
    }
    mRSC->mObjHead = this;

    asyncUnlock();
}

void ObjectBase::remove() const {
    //LOGV("calling remove  rsc %p", mRSC);
    if (!mRSC) {
        rsAssert(!mPrev);
        rsAssert(!mNext);
        return;
    }

    if (mRSC->mObjHead == this) {
        mRSC->mObjHead = mNext;
    }
    if (mPrev) {
        mPrev->mNext = mNext;
    }
    if (mNext) {
        mNext->mPrev = mPrev;
    }
    mPrev = NULL;
    mNext = NULL;
}

void ObjectBase::zeroAllUserRef(Context *rsc) {
    if (rsc->props.mLogObjects) {
        LOGV("Forcing release of all outstanding user refs.");
    }

    // This operation can be slow, only to be called during context cleanup.
    const ObjectBase * o = rsc->mObjHead;
    while (o) {
        //LOGE("o %p", o);
        if (o->zeroUserRef()) {
            // deleted the object and possibly others, restart from head.
            o = rsc->mObjHead;
            //LOGE("o head %p", o);
        } else {
            o = o->mNext;
            //LOGE("o next %p", o);
        }
    }

    if (rsc->props.mLogObjects) {
        LOGV("Objects remaining.");
        dumpAll(rsc);
    }
}

void ObjectBase::dumpAll(Context *rsc) {
    asyncLock();

    LOGV("Dumping all objects");
    const ObjectBase * o = rsc->mObjHead;
    while (o) {
        LOGV(" Object %p", o);
        o->dumpLOGV("  ");
        o = o->mNext;
    }

    asyncUnlock();
}

bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj) {
    asyncLock();

    const ObjectBase * o = rsc->mObjHead;
    while (o) {
        if (o == obj) {
            asyncUnlock();
            return true;
        }
        o = o->mNext;
    }
    asyncUnlock();
    return false;
}

