Async type creation.

Change-Id: I4d98446fabbf7e8a98c97f85b573a58c8a0c58c2
diff --git a/RenderScript.h b/RenderScript.h
index da8edbe..e63cc9b 100644
--- a/RenderScript.h
+++ b/RenderScript.h
@@ -27,6 +27,8 @@
 //////////////////////////////////////////////////////
 //
 
+typedef void * RsAsyncVoidPtr;
+
 typedef void * RsAdapter1D;
 typedef void * RsAdapter2D;
 typedef void * RsAllocation;
@@ -285,6 +287,11 @@
 } RsScriptCall;
 
 
+// Async commands for returning new IDS
+void * rsaTypeCreate(RsContext, RsElement, uint32_t dimCount,
+                     const RsDimension *dims, const uint32_t *vals);
+
+
 #ifndef NO_RS_FUNCS
 #include "rsgApiFuncDecl.h"
 #endif
diff --git a/rs.spec b/rs.spec
index 27bb006..eb2942e 100644
--- a/rs.spec
+++ b/rs.spec
@@ -64,7 +64,7 @@
 	}
 
 ObjDestroy {
-	param void *obj
+	param RsAsyncVoidPtr objPtr
 	}
 
 ElementCreate {
@@ -97,18 +97,6 @@
 	param uint32_t dataSize
 	}
 
-TypeBegin {
-	param RsElement type
-	}
-
-TypeAdd {
-	param RsDimension dim
-	param size_t value
-	}
-
-TypeCreate {
-	ret RsType
-	}
 
 TypeGetNativeData {
 	param RsType type
@@ -135,8 +123,8 @@
 
 AllocationCreateBitmapRef {
 	param RsType type
-	param void * bmpPtr
-	param void * callbackData
+	param RsAsyncVoidPtr bmpPtr
+	param RsAsyncVoidPtr callbackData
 	param RsBitmapCallback_t callback
 	ret RsAllocation
 	}
diff --git a/rsAllocation.cpp b/rsAllocation.cpp
index 172d07d..775fdf7 100644
--- a/rsAllocation.cpp
+++ b/rsAllocation.cpp
@@ -794,13 +794,9 @@
     const Element *dst = static_cast<const Element *>(_dst);
 
     //LOGE("%p rsi_AllocationCreateFromBitmap %i %i %i", rsc, w, h, genMips);
-    rsi_TypeBegin(rsc, _dst);
-    rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
-    rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
-    if (genMips) {
-        rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
-    }
-    RsType type = rsi_TypeCreate(rsc);
+    RsDimension dims[] = {RS_DIMENSION_X, RS_DIMENSION_Y, RS_DIMENSION_LOD};
+    uint32_t dimValues[] = {w, h, genMips};
+    RsType type = rsaTypeCreate(rsc, _dst, 3, dims, dimValues);
 
     RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
     Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
diff --git a/rsAllocation.h b/rsAllocation.h
index 24e245f..12cf832 100644
--- a/rsAllocation.h
+++ b/rsAllocation.h
@@ -30,8 +30,6 @@
     // The graphics equilivent of malloc.  The allocation contains a structure of elements.
 
 public:
-    // By policy this allocation will hold a pointer to the type
-    // but will not destroy it on destruction.
     Allocation(Context *rsc, const Type *);
     Allocation(Context *rsc, const Type *, void *bmp, void *callbackData, RsBitmapCallback_t callback);
 
diff --git a/rsContext.cpp b/rsContext.cpp
index be8fb0e..4dd074e 100644
--- a/rsContext.cpp
+++ b/rsContext.cpp
@@ -976,9 +976,9 @@
     (*name) = ob->getName();
 }
 
-void rsi_ObjDestroy(Context *rsc, void *obj)
+void rsi_ObjDestroy(Context *rsc, void *optr)
 {
-    ObjectBase *ob = static_cast<ObjectBase *>(obj);
+    ObjectBase *ob = static_cast<ObjectBase *>(optr);
     rsc->removeName(ob);
     ob->decUserRef();
 }
diff --git a/rsLocklessFifo.cpp b/rsLocklessFifo.cpp
index 019ea72..10b38af 100644
--- a/rsLocklessFifo.cpp
+++ b/rsLocklessFifo.cpp
@@ -15,6 +15,8 @@
  */
 
 #include "rsLocklessFifo.h"
+#include "utils/Timers.h"
+#include "utils/StopWatch.h"
 
 using namespace android;
 using namespace android::renderscript;
@@ -115,6 +117,10 @@
     if (mInShutdown) {
         return;
     }
+
+    //char buf[1024];
+    //sprintf(buf, "RenderScript LocklessCommandFifo::commitSync  %p %i  %i", this, command, sizeInBytes);
+    //StopWatch compileTimer(buf);
     commit(command, sizeInBytes);
     flush();
 }
diff --git a/rsObjectBase.cpp b/rsObjectBase.cpp
index 124d5e6..e4b07c4 100644
--- a/rsObjectBase.cpp
+++ b/rsObjectBase.cpp
@@ -25,16 +25,20 @@
 using namespace android;
 using namespace android::renderscript;
 
+pthread_mutex_t ObjectBase::gObjectInitMutex = PTHREAD_MUTEX_INITIALIZER;
+
 ObjectBase::ObjectBase(Context *rsc)
 {
     mUserRefCount = 0;
     mSysRefCount = 0;
-    mRSC = NULL;
+    mRSC = rsc;
     mNext = NULL;
     mPrev = NULL;
     mAllocFile = __FILE__;
     mAllocLine = __LINE__;
-    setContext(rsc);
+
+    rsAssert(rsc);
+    add();
 }
 
 ObjectBase::~ObjectBase()
@@ -56,24 +60,19 @@
     }
 }
 
-void ObjectBase::setContext(Context *rsc)
-{
-    if (mRSC) {
-        remove();
-    }
-    rsAssert(rsc);
-    mRSC = rsc;
-    if (rsc) {
-        add();
-    }
-}
-
 void ObjectBase::incUserRef() const
 {
-    mUserRefCount ++;
+    lockUserRef();
+    mUserRefCount++;
+    unlockUserRef();
     //LOGV("ObjectBase %p inc ref %i", this, mUserRefCount);
 }
 
+void ObjectBase::prelockedIncUserRef() const
+{
+    mUserRefCount++;
+}
+
 void ObjectBase::incSysRef() const
 {
     mSysRefCount ++;
@@ -83,10 +82,20 @@
 bool ObjectBase::checkDelete() const
 {
     if (!(mSysRefCount | mUserRefCount)) {
+        lockUserRef();
+
+        // Recheck the user ref count since it can be incremented from other threads.
+        if (mUserRefCount) {
+            unlockUserRef();
+            return false;
+        }
+
         if (mRSC && mRSC->props.mLogObjects) {
             dumpLOGV("checkDelete");
         }
         delete this;
+
+        unlockUserRef();
         return true;
     }
     return false;
@@ -94,17 +103,25 @@
 
 bool ObjectBase::decUserRef() const
 {
+    lockUserRef();
     rsAssert(mUserRefCount > 0);
-    mUserRefCount --;
     //dumpLOGV("decUserRef");
-    return checkDelete();
+    mUserRefCount--;
+    unlockUserRef();
+    bool ret = checkDelete();
+    return ret;
 }
 
 bool ObjectBase::zeroUserRef() const
 {
+    lockUserRef();
+    // This can only happen during cleanup and is therefore
+    // thread safe.
     mUserRefCount = 0;
     //dumpLOGV("zeroUserRef");
-    return checkDelete();
+    unlockUserRef();
+    bool ret = checkDelete();
+    return ret;
 }
 
 bool ObjectBase::decSysRef() const
@@ -125,8 +142,20 @@
     mName.setTo(name, len);
 }
 
+void ObjectBase::lockUserRef()
+{
+    pthread_mutex_lock(&gObjectInitMutex);
+}
+
+void ObjectBase::unlockUserRef()
+{
+    pthread_mutex_unlock(&gObjectInitMutex);
+}
+
 void ObjectBase::add() const
 {
+    pthread_mutex_lock(&gObjectInitMutex);
+
     rsAssert(!mNext);
     rsAssert(!mPrev);
     //LOGV("calling add  rsc %p", mRSC);
@@ -135,16 +164,22 @@
         mRSC->mObjHead->mPrev = this;
     }
     mRSC->mObjHead = this;
+
+    pthread_mutex_unlock(&gObjectInitMutex);
 }
 
 void ObjectBase::remove() const
 {
+    // Should be within gObjectInitMutex lock
+    // lock will be from checkDelete a few levels up in the stack.
+
     //LOGV("calling remove  rsc %p", mRSC);
     if (!mRSC) {
         rsAssert(!mPrev);
         rsAssert(!mNext);
         return;
     }
+
     if (mRSC->mObjHead == this) {
         mRSC->mObjHead = mNext;
     }
@@ -160,6 +195,8 @@
 
 void ObjectBase::zeroAllUserRef(Context *rsc)
 {
+    lockUserRef();
+
     if (rsc->props.mLogObjects) {
         LOGV("Forcing release of all outstanding user refs.");
     }
@@ -182,10 +219,14 @@
         LOGV("Objects remaining.");
         dumpAll(rsc);
     }
+
+    unlockUserRef();
 }
 
 void ObjectBase::dumpAll(Context *rsc)
 {
+    lockUserRef();
+
     LOGV("Dumping all objects");
     const ObjectBase * o = rsc->mObjHead;
     while (o) {
@@ -193,17 +234,23 @@
         o->dumpLOGV("  ");
         o = o->mNext;
     }
+
+    unlockUserRef();
 }
 
 bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj)
 {
+    lockUserRef();
+
     const ObjectBase * o = rsc->mObjHead;
     while (o) {
         if (o == obj) {
+            unlockUserRef();
             return true;
         }
         o = o->mNext;
     }
+    unlockUserRef();
     return false;
 }
 
diff --git a/rsObjectBase.h b/rsObjectBase.h
index 59fb4a6..8d1ace1 100644
--- a/rsObjectBase.h
+++ b/rsObjectBase.h
@@ -39,6 +39,7 @@
     void incUserRef() const;
     bool decUserRef() const;
     bool zeroUserRef() const;
+    void prelockedIncUserRef() const;
 
     const char * getName() const {
         return mName.string();
@@ -47,7 +48,6 @@
     void setName(const char *, uint32_t len);
 
     Context * getContext() const {return mRSC;}
-    void setContext(Context *);
 
     static void zeroAllUserRef(Context *rsc);
     static void dumpAll(Context *rsc);
@@ -58,12 +58,17 @@
 
     static bool isValid(const Context *rsc, const ObjectBase *obj);
 
+    static void lockUserRef();
+    static void unlockUserRef();
+
 protected:
     const char *mAllocFile;
     uint32_t mAllocLine;
     Context *mRSC;
 
 private:
+    static pthread_mutex_t gObjectInitMutex;
+
     void add() const;
     void remove() const;
 
diff --git a/rsScriptC.cpp b/rsScriptC.cpp
index e60255a..a2910d7 100644
--- a/rsScriptC.cpp
+++ b/rsScriptC.cpp
@@ -529,8 +529,6 @@
 
     ss->runCompiler(rsc, s.get());
     s->incUserRef();
-    s->setContext(rsc);
-
     ss->clear(rsc);
     return s.get();
 }
diff --git a/rsType.cpp b/rsType.cpp
index e0716eb..27b1b4f 100644
--- a/rsType.cpp
+++ b/rsType.cpp
@@ -381,88 +381,6 @@
 namespace android {
 namespace renderscript {
 
-void rsi_TypeBegin(Context *rsc, RsElement vse)
-{
-    TypeState * stc = &rsc->mStateType;
-
-    stc->mX = 0;
-    stc->mY = 0;
-    stc->mZ = 0;
-    stc->mLOD = false;
-    stc->mFaces = false;
-    stc->mElement.set(static_cast<const Element *>(vse));
-}
-
-void rsi_TypeAdd(Context *rsc, RsDimension dim, size_t value)
-{
-    TypeState * stc = &rsc->mStateType;
-
-    if (dim < 0) {
-        //error
-        return;
-    }
-
-
-    switch (dim) {
-    case RS_DIMENSION_X:
-        stc->mX = value;
-        return;
-    case RS_DIMENSION_Y:
-        stc->mY = value;
-        return;
-    case RS_DIMENSION_Z:
-        stc->mZ = value;
-        return;
-    case RS_DIMENSION_FACE:
-        stc->mFaces = (value != 0);
-        return;
-    case RS_DIMENSION_LOD:
-        stc->mLOD = (value != 0);
-        return;
-    default:
-        break;
-    }
-
-    if ((dim < 0) || (dim > RS_DIMENSION_MAX)) {
-        LOGE("rsTypeAdd: Bad dimension");
-        //error
-        return;
-    }
-
-    // todo: implement array support
-
-}
-
-RsType rsi_TypeCreate(Context *rsc)
-{
-    TypeState * stc = &rsc->mStateType;
-
-    for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) {
-        Type *t = stc->mTypes[ct];
-        if (t->getElement() != stc->mElement.get()) continue;
-        if (t->getDimX() != stc->mX) continue;
-        if (t->getDimY() != stc->mY) continue;
-        if (t->getDimZ() != stc->mZ) continue;
-        if (t->getDimLOD() != stc->mLOD) continue;
-        if (t->getDimFaces() != stc->mFaces) continue;
-        t->incUserRef();
-        return t;
-    }
-
-    Type * st = new Type(rsc);
-    st->incUserRef();
-    st->setDimX(stc->mX);
-    st->setDimY(stc->mY);
-    st->setDimZ(stc->mZ);
-    st->setElement(stc->mElement.get());
-    st->setDimLOD(stc->mLOD);
-    st->setDimFaces(stc->mFaces);
-    st->compute();
-    stc->mElement.clear();
-    stc->mTypes.push(st);
-    return st;
-}
-
 void rsi_TypeGetNativeData(Context *rsc, RsType type, uint32_t *typeData, uint32_t typeDataSize)
 {
     rsAssert(typeDataSize == 6);
@@ -483,3 +401,61 @@
 }
 }
 
+void * rsaTypeCreate(RsContext con, RsElement _e, uint32_t dimCount,
+                     const RsDimension *dims, const uint32_t *vals)
+{
+    Context *rsc = static_cast<Context *>(con);
+    Element *e = static_cast<Element *>(_e);
+    TypeState * stc = &rsc->mStateType;
+
+    uint32_t dimX = 0;
+    uint32_t dimY = 0;
+    uint32_t dimZ = 0;
+    uint32_t dimLOD = 0;
+    uint32_t dimFaces = 0;
+
+    for (uint32_t ct=0; ct < dimCount; ct++) {
+        switch(dims[ct]) {
+        case RS_DIMENSION_X: dimX = vals[ct]; break;
+        case RS_DIMENSION_Y: dimY = vals[ct]; break;
+        case RS_DIMENSION_Z: dimZ = vals[ct]; break;
+        case RS_DIMENSION_LOD: dimLOD = vals[ct]; break;
+        case RS_DIMENSION_FACE: dimFaces = vals[ct]; break;
+
+        default:
+            LOGE("rsaTypeCreate: Bad dimension");
+            rsAssert(0);
+        }
+    }
+
+    ObjectBase::lockUserRef();
+    for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) {
+        Type *t = stc->mTypes[ct];
+        if (t->getElement() != e) continue;
+        if (t->getDimX() != dimX) continue;
+        if (t->getDimY() != dimY) continue;
+        if (t->getDimZ() != dimZ) continue;
+        if (t->getDimLOD() != dimLOD) continue;
+        if (t->getDimFaces() != dimFaces) continue;
+        t->prelockedIncUserRef();
+        ObjectBase::unlockUserRef();
+        return t;
+    }
+    ObjectBase::unlockUserRef();
+
+    Type * st = new Type(rsc);
+    st->incUserRef();
+    st->setDimX(dimX);
+    st->setDimY(dimY);
+    st->setDimZ(dimZ);
+    st->setElement(e);
+    st->setDimLOD(dimLOD);
+    st->setDimFaces(dimFaces);
+    st->compute();
+
+    ObjectBase::lockUserRef();
+    stc->mTypes.push(st);
+    ObjectBase::unlockUserRef();
+    return st;
+}
+
diff --git a/rsType.h b/rsType.h
index 891edd4..a0c77ab 100644
--- a/rsType.h
+++ b/rsType.h
@@ -134,14 +134,6 @@
     TypeState();
     ~TypeState();
 
-    size_t mX;
-    size_t mY;
-    size_t mZ;
-    uint32_t mLOD;
-    bool mFaces;
-    ObjectBaseRef<const Element> mElement;
-
-
     // Cache of all existing types.
     Vector<Type *> mTypes;
 };