Example #1
0
/*
* void= mt.__gc( proxy_ud )
*
* End of life for a proxy object; reduce the deep reference count and clean
* it up if reaches 0.
*/
static
int deep_userdata_gc( lua_State *L ) {
    DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 );
    DEEP_PRELUDE *p= *proxy;
    int v;

    *proxy= 0;  // make sure we don't use it any more

    MUTEX_LOCK( &deep_lock );
      v= --(p->refcount);
    MUTEX_UNLOCK( &deep_lock );

    if (v==0) {
        int pushed;

        // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup
        //
        lua_CFunction idfunc= get_idfunc(L,1);
        ASSERT_L(idfunc);
        
        lua_settop(L,0);    // clean stack so we can call 'idfunc' directly

        // void= idfunc( "delete", lightuserdata )
        //
        lua_pushliteral( L, "delete" );
        lua_pushlightuserdata( L, p->deep );
        pushed= idfunc(L);
        
        if (pushed)
            luaL_error( L, "Bad idfunc on \"delete\": returned something" );

        DEEP_FREE( (void*)p );
    }
    return 0;
}
Example #2
0
/*
* Push a registry subtable (keyed by unique 'token') onto the stack.
* If the subtable does not exist, it is created and chained.
*/
static
void push_registry_subtable( lua_State *L, void *token ) {

    STACK_GROW(L,3);

  STACK_CHECK(L)
    
    lua_pushlightuserdata( L, token );
    lua_rawget( L, LUA_REGISTRYINDEX );
        //
        // [-1]: nil/subtable
    
    if (lua_isnil(L,-1)) {
        lua_pop(L,1);
        lua_newtable(L);                    // value
        lua_pushlightuserdata( L, token );  // key
        lua_pushvalue(L,-2);
            //
            // [-3]: value (2nd ref)
            // [-2]: key
            // [-1]: value

        lua_rawset( L, LUA_REGISTRYINDEX );
    }
  STACK_END(L,1)

    ASSERT_L( lua_istable(L,-1) );
}
Example #3
0
/*
* Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it
*/
void push_registry_subtable_mode( lua_State* L, void* key_, const char* mode_)
{
	STACK_GROW( L, 3);
	STACK_CHECK( L);

	lua_pushlightuserdata( L, key_);                      // key
	lua_rawget( L, LUA_REGISTRYINDEX);                    // {}|nil

	if( lua_isnil( L, -1))
	{
		lua_pop( L, 1);                                     //
		lua_newtable( L);                                   // {}
		lua_pushlightuserdata( L, key_);                    // {} key
		lua_pushvalue( L, -2);                              // {} key {}

		// _R[key_] = {}
		lua_rawset( L, LUA_REGISTRYINDEX);                  // {}

		// Set its metatable if requested
		if( mode_)
		{
			lua_newtable( L);                                 // {} mt
			lua_pushliteral( L, "__mode");                    // {} mt "__mode"
			lua_pushstring( L, mode_);                        // {} mt "__mode" mode
			lua_rawset( L, -3);                               // {} mt
			lua_setmetatable( L, -2);                         // {}
		}
	}
	STACK_END( L, 1);
	ASSERT_L( lua_istable( L, -1));
}
Example #4
0
void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_)
{
	// Call 'idfunc( "delete", deep_ptr )' to make deep cleanup
	lua_pushlightuserdata( L, prelude_->deep);
	ASSERT_L( prelude_->idfunc);
	prelude_->idfunc( L, eDO_delete);
	DEEP_FREE( (void*) prelude_);
}
Example #5
0
/*
* Create a deep userdata
*
*   proxy_ud= deep_userdata( idfunc [, ...] )
*
* Creates a deep userdata entry of the type defined by 'idfunc'.
* Other parameters are passed on to the 'idfunc' "new" invocation.
*
* 'idfunc' must fulfill the following features:
*
*   lightuserdata= idfunc( "new" [, ...] )      -- creates a new deep data instance
*   void= idfunc( "delete", lightuserdata )     -- releases a deep data instance
*   tbl= idfunc( "metatable" )          -- gives metatable for userdata proxies
*
* Reference counting and true userdata proxying are taken care of for the
* actual data type.
*
* Types using the deep userdata system (and only those!) can be passed between
* separate Lua states via 'luaG_inter_move()'.
*
* Returns:  'proxy' userdata for accessing the deep data via 'luaG_todeep()'
*/
int luaG_deep_userdata( lua_State *L ) {
    lua_CFunction idfunc= lua_tocfunction( L,1 );
    int pushed;

    DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) );
    ASSERT_L(prelude);

    prelude->refcount= 0;   // 'luaG_push_proxy' will lift it to 1

    STACK_GROW(L,1);
  STACK_CHECK(L)

    // Replace 'idfunc' with "new" in the stack (keep possible other params)
    //
    lua_remove(L,1);
    lua_pushliteral( L, "new" );
    lua_insert(L,1);

    // lightuserdata= idfunc( "new" [, ...] )
    //
    pushed= idfunc(L);

    if ((pushed!=1) || lua_type(L,-1) != LUA_TLIGHTUSERDATA)
        luaL_error( L, "Bad idfunc on \"new\": did not return light userdata" );

    prelude->deep= lua_touserdata(L,-1);
    ASSERT_L(prelude->deep);

    lua_pop(L,1);   // pop deep data

    luaG_push_proxy( L, idfunc, prelude );
        //
        // [-1]: proxy userdata

  STACK_END(L,1)
    return 1;
}
Example #6
0
/**
 * Free a memory block.
 *
 * @param   pHeapInt       The heap.
 * @param   pBlock         The memory block to free.
 */
static void rtHeapOffsetFreeBlock(PRTHEAPOFFSETINTERNAL pHeapInt, PRTHEAPOFFSETBLOCK pBlock)
{
    PRTHEAPOFFSETFREE   pFree = (PRTHEAPOFFSETFREE)pBlock;
    PRTHEAPOFFSETFREE   pLeft;
    PRTHEAPOFFSETFREE   pRight;

#ifdef RTHEAPOFFSET_STRICT
    rtHeapOffsetAssertAll(pHeapInt);
#endif

    /*
     * Look for the closest free list blocks by walking the blocks right
     * of us (both lists are sorted by address).
     */
    pLeft = NULL;
    pRight = NULL;
    if (pHeapInt->offFreeTail)
    {
        pRight = RTHEAPOFF_TO_PTR_N(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETFREE);
        while (pRight && !RTHEAPOFFSETBLOCK_IS_FREE(&pRight->Core))
        {
            ASSERT_BLOCK(pHeapInt, &pRight->Core);
            pRight = RTHEAPOFF_TO_PTR_N(pHeapInt, pRight->Core.offNext, PRTHEAPOFFSETFREE);
        }
        if (!pRight)
            pLeft = RTHEAPOFF_TO_PTR_N(pHeapInt, pHeapInt->offFreeTail, PRTHEAPOFFSETFREE);
        else
        {
            ASSERT_BLOCK_FREE(pHeapInt, pRight);
            pLeft = RTHEAPOFF_TO_PTR_N(pHeapInt, pRight->offPrev, PRTHEAPOFFSETFREE);
        }
        if (pLeft)
            ASSERT_BLOCK_FREE(pHeapInt, pLeft);
    }
    AssertMsgReturnVoid(pLeft != pFree, ("Freed twice! pv=%p (pBlock=%p)\n", pBlock + 1, pBlock));
    ASSERT_L(RTHEAPOFF_TO_OFF(pHeapInt, pLeft), RTHEAPOFF_TO_OFF(pHeapInt, pFree));
    Assert(!pRight || (uintptr_t)pRight > (uintptr_t)pFree);
    Assert(!pLeft || RTHEAPOFF_TO_PTR_N(pHeapInt, pLeft->offNext, PRTHEAPOFFSETFREE) == pRight);

    /*
     * Insert at the head of the free block list?
     */
    if (!pLeft)
    {
        Assert(pRight == RTHEAPOFF_TO_PTR_N(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE));
        pFree->Core.fFlags |= RTHEAPOFFSETBLOCK_FLAGS_FREE;
        pFree->offPrev = 0;
        pFree->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pRight);
        if (pRight)
            pRight->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
        else
            pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
        pHeapInt->offFreeHead = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
    }
    else
    {
        /*
         * Can we merge with left hand free block?
         */
        if (pLeft->Core.offNext == RTHEAPOFF_TO_OFF(pHeapInt, pFree))
        {
            pLeft->Core.offNext = pFree->Core.offNext;
            if (pFree->Core.offNext)
                RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pLeft);
            pHeapInt->cbFree -= pLeft->cb;
            pFree = pLeft;
        }
        /*
         * No, just link it into the free list then.
         */
        else
        {
            pFree->Core.fFlags |= RTHEAPOFFSETBLOCK_FLAGS_FREE;
            pFree->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pRight);
            pFree->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pLeft);
            pLeft->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
            if (pRight)
                pRight->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
            else
                pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
        }
    }

    /*
     * Can we merge with right hand free block?
     */
    if (    pRight
        &&  pRight->Core.offPrev == RTHEAPOFF_TO_OFF(pHeapInt, pFree))
    {
        /* core */
        pFree->Core.offNext = pRight->Core.offNext;
        if (pRight->Core.offNext)
            RTHEAPOFF_TO_PTR(pHeapInt, pRight->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);

        /* free */
        pFree->offNext = pRight->offNext;
        if (pRight->offNext)
            RTHEAPOFF_TO_PTR(pHeapInt, pRight->offNext, PRTHEAPOFFSETFREE)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
        else
            pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
        pHeapInt->cbFree -= pRight->cb;
    }

    /*
     * Calculate the size and update free stats.
     */
    pFree->cb = (pFree->Core.offNext ? pFree->Core.offNext : pHeapInt->cbHeap)
              - RTHEAPOFF_TO_OFF(pHeapInt, pFree) - sizeof(RTHEAPOFFSETBLOCK);
    pHeapInt->cbFree += pFree->cb;
    ASSERT_BLOCK_FREE(pHeapInt, pFree);

#ifdef RTHEAPOFFSET_STRICT
    rtHeapOffsetAssertAll(pHeapInt);
#endif
}
Example #7
0
static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) {

    lua_CFunction cfunc= lua_tocfunction( L,i );
    unsigned n;

    ASSERT_L( L2_cache_i != 0 );

  STACK_GROW(L,2);

  STACK_CHECK(L)
    if (!cfunc) {   // Lua function
        luaL_Buffer b;
        const char *s;
        size_t sz;
        int tmp;
        const char *name= NULL;

#if 0
        // "To get information about a function you push it onto the 
        // stack and start the what string with the character '>'."
        //
        { lua_Debug ar;
        lua_pushvalue( L, i );
        lua_getinfo(L, ">n", &ar);      // fills 'name' and 'namewhat', pops function
        name= ar.namewhat;
        
        fprintf( stderr, "NAME: %s\n", name );  // just gives NULL
        }
#endif 
        // 'lua_dump()' needs the function at top of stack
        //
        if (i!=-1) lua_pushvalue( L, i );

        luaL_buffinit(L,&b);
        tmp= lua_dump(L, buf_writer, &b);
        ASSERT_L(tmp==0);
            //
            // "value returned is the error code returned by the last call 
            // to the writer" (and we only return 0)

        luaL_pushresult(&b);    // pushes dumped string on 'L'
        s= lua_tolstring(L,-1,&sz);
        ASSERT_L( s && sz );

        if (i!=-1) lua_remove( L, -2 );

        // Note: Line numbers seem to be taken precisely from the 
        //       original function. 'name' is not used since the chunk
        //       is precompiled (it seems...). 
        //
        // TBD: Can we get the function's original name through, as well?
        //
        if (luaL_loadbuffer(L2, s, sz, name) != 0) {
            // chunk is precompiled so only LUA_ERRMEM can happen
            // "Otherwise, it pushes an error message"
            //
            STACK_GROW( L,1 );
            luaL_error( L, "%s", lua_tostring(L2,-1) );
        }
        lua_pop(L,1);   // remove the dumped string
  STACK_MID(L,0)
    }
Example #8
0
static
void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) {
    // TBD: Merge this and same code for tables

    ASSERT_L( hijacked_tostring );
    ASSERT_L( L2_cache_i != 0 );

    STACK_GROW(L,2);
    STACK_GROW(L2,3);

  STACK_CHECK(L)
    lua_pushcfunction( L, hijacked_tostring );
    lua_pushvalue( L, i );
    lua_call( L, 1 /*args*/, 1 /*retvals*/ );
        //
        // [-1]: "function: 0x...."

  STACK_END(L,1)
    ASSERT_L( lua_type(L,-1) == LUA_TSTRING );

    // L2_cache[id_str]= function
    //
  STACK_CHECK(L2)

    // We don't need to use the from state ('L') in ID since the life span
    // is only for the duration of a copy (both states are locked).
    //
    lua_pushstring( L2, lua_tostring(L,-1) );
    lua_pop(L,1);   // remove the 'tostring(tbl)' value (in L!)

//fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) );

    lua_pushvalue( L2, -1 );
    lua_rawget( L2, L2_cache_i );
        //
        // [-2]: identity string ("function: 0x...")
        // [-1]: function|nil|true  (true means: we're working on it; recursive)

    if (lua_isnil(L2,-1)) {
        lua_pop(L2,1);
        
        // Set to 'true' for the duration of creation; need to find self-references
        // via upvalues
        //
        lua_pushboolean(L2,TRUE);
        lua_setfield( L2, L2_cache_i, lua_tostring(L2,-2) );        

        inter_copy_func( L2, L2_cache_i, L, i );    // pushes a copy of the func

        lua_pushvalue(L2,-1);
        lua_insert(L2,-3);
            //
            // [-3]: function (2nd ref)
            // [-2]: identity string
            // [-1]: function

        lua_rawset(L2,L2_cache_i);
            //
            // [-1]: function (tied to 'L2_cache' table')
        
    } else if (lua_isboolean(L2,-1)) {
        // Loop in preparing upvalues; either direct or via a table
        // 
        // Note: This excludes the case where a function directly addresses
        //       itself as an upvalue (recursive lane creation).
        //
        luaL_error( L, "Recursive use of upvalues; cannot copy the function" );
    
    } else {
        lua_remove(L2,-2);
    }
  STACK_END(L2,1)
    //
    // L2 [-1]: function

    ASSERT_L( lua_isfunction(L2,-1) );
}
Example #9
0
/* 
 * Check if we've already copied the same table from 'L', and
 * reuse the old copy. This allows table upvalues shared by multiple
 * local functions to point to the same table, also in the target.
 *
 * Always pushes a table to 'L2'.
 *
 * Returns TRUE if the table was cached (no need to fill it!); FALSE if
 * it's a virgin.
 */
static
bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) {
    bool_t ret;

    ASSERT_L( hijacked_tostring );
    ASSERT_L( L2_cache_i != 0 );

    STACK_GROW(L,2);
    STACK_GROW(L2,3);

    // Create an identity string for table at [i]; it should stay unique at
    // least during copying of the data (then we can clear the caches).
    //
  STACK_CHECK(L)
    lua_pushcfunction( L, hijacked_tostring );
    lua_pushvalue( L, i );
    lua_call( L, 1 /*args*/, 1 /*retvals*/ );
        //
        // [-1]: "table: 0x...."

  STACK_END(L,1)
    ASSERT_L( lua_type(L,-1) == LUA_TSTRING );

    // L2_cache[id_str]= [{...}]
    //
  STACK_CHECK(L2)

    // We don't need to use the from state ('L') in ID since the life span
    // is only for the duration of a copy (both states are locked).
    //
    lua_pushstring( L2, lua_tostring(L,-1) );
    lua_pop(L,1);   // remove the 'tostring(tbl)' value (in L!)

//fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) );

    lua_pushvalue( L2, -1 );
    lua_rawget( L2, L2_cache_i );
        //
        // [-2]: identity string ("table: 0x...")
        // [-1]: table|nil

    if (lua_isnil(L2,-1)) {
        lua_pop(L2,1);
        lua_newtable(L2);
        lua_pushvalue(L2,-1);
        lua_insert(L2,-3);
            //
            // [-3]: new table (2nd ref)
            // [-2]: identity string
            // [-1]: new table

        lua_rawset(L2, L2_cache_i);
            //
            // [-1]: new table (tied to 'L2_cache' table')

        ret= FALSE;     // brand new
        
    } else {
        lua_remove(L2,-2);
        ret= TRUE;      // from cache
    }
  STACK_END(L2,1)
    //
    // L2 [-1]: table to use as destination

    ASSERT_L( lua_istable(L2,-1) );
    return ret;
}
Example #10
0
/*
* Push a proxy userdata on the stack.
*
* Initializes necessary structures if it's the first time 'idfunc' is being
* used in this Lua state (metatable, registring it). Otherwise, increments the
* reference count.
*/
void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude ) {
    DEEP_PRELUDE **proxy;

    MUTEX_LOCK( &deep_lock );
      ++(prelude->refcount);  // one more proxy pointing to this deep data
    MUTEX_UNLOCK( &deep_lock );

    STACK_GROW(L,4);

  STACK_CHECK(L)

    proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) );
    ASSERT_L(proxy);
    *proxy= prelude;

    // Get/create metatable for 'idfunc' (in this state)
    //
    lua_pushcfunction( L, idfunc );    // key
    get_deep_lookup(L);
        //
        // [-2]: proxy
        // [-1]: metatable / nil
    
    if (lua_isnil(L,-1)) {
        // No metatable yet; make one and register it
        //
        lua_pop(L,1);

        // tbl= idfunc( "metatable" )
        //
        lua_pushcfunction( L, idfunc );
        lua_pushliteral( L, "metatable" );
        lua_call( L, 1 /*args*/, 1 /*results*/ );
            //
            // [-2]: proxy
            // [-1]: metatable (returned by 'idfunc')

        if (!lua_istable(L,-1))
            luaL_error( L, "Bad idfunc on \"metatable\": did not return one" );

        // Add '__gc' method
        //
        lua_pushcfunction( L, deep_userdata_gc );
        lua_setfield( L, -2, "__gc" );

        // Memorize for later rounds
        //
        lua_pushvalue( L,-1 );
        lua_pushcfunction( L, idfunc );
            //
            // [-4]: proxy
            // [-3]: metatable (2nd ref)
            // [-2]: metatable
            // [-1]: idfunc

        set_deep_lookup(L);
    } 
  STACK_MID(L,2)
    ASSERT_L( lua_isuserdata(L,-2) );
    ASSERT_L( lua_istable(L,-1) );

    // [-2]: proxy userdata
    // [-1]: metatable to use

    lua_setmetatable( L, -2 );
    
  STACK_END(L,1)
    // [-1]: proxy userdata
}
/**
 * Free a memory block.
 *
 * @param   pHeapInt       The heap.
 * @param   pBlock         The memory block to free.
 */
static void rtHeapSimpleFreeBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, PRTHEAPSIMPLEBLOCK pBlock)
{
    PRTHEAPSIMPLEFREE   pFree = (PRTHEAPSIMPLEFREE)pBlock;
    PRTHEAPSIMPLEFREE   pLeft;
    PRTHEAPSIMPLEFREE   pRight;

#ifdef RTHEAPSIMPLE_STRICT
    rtHeapSimpleAssertAll(pHeapInt);
#endif

    /*
     * Look for the closest free list blocks by walking the blocks right
     * of us (both lists are sorted by address).
     */
    pLeft = NULL;
    pRight = NULL;
    if (pHeapInt->pFreeTail)
    {
        pRight = (PRTHEAPSIMPLEFREE)pFree->Core.pNext;
        while (pRight && !RTHEAPSIMPLEBLOCK_IS_FREE(&pRight->Core))
        {
            ASSERT_BLOCK(pHeapInt, &pRight->Core);
            pRight = (PRTHEAPSIMPLEFREE)pRight->Core.pNext;
        }
        if (!pRight)
            pLeft = pHeapInt->pFreeTail;
        else
        {
            ASSERT_BLOCK_FREE(pHeapInt, pRight);
            pLeft = pRight->pPrev;
        }
        if (pLeft)
            ASSERT_BLOCK_FREE(pHeapInt, pLeft);
    }
    AssertMsgReturnVoid(pLeft != pFree, ("Freed twice! pv=%p (pBlock=%p)\n", pBlock + 1, pBlock));
    ASSERT_L(pLeft, pFree);
    Assert(!pRight || (uintptr_t)pRight > (uintptr_t)pFree);
    Assert(!pLeft || pLeft->pNext == pRight);

    /*
     * Insert at the head of the free block list?
     */
    if (!pLeft)
    {
        Assert(pRight == pHeapInt->pFreeHead);
        pFree->Core.fFlags |= RTHEAPSIMPLEBLOCK_FLAGS_FREE;
        pFree->pPrev = NULL;
        pFree->pNext = pRight;
        if (pRight)
            pRight->pPrev = pFree;
        else
            pHeapInt->pFreeTail = pFree;
        pHeapInt->pFreeHead = pFree;
    }
    else
    {
        /*
         * Can we merge with left hand free block?
         */
        if (pLeft->Core.pNext == &pFree->Core)
        {
            pLeft->Core.pNext = pFree->Core.pNext;
            if (pFree->Core.pNext)
                pFree->Core.pNext->pPrev = &pLeft->Core;
            pHeapInt->cbFree -= pLeft->cb;
            pFree = pLeft;
        }
        /*
         * No, just link it into the free list then.
         */
        else
        {
            pFree->Core.fFlags |= RTHEAPSIMPLEBLOCK_FLAGS_FREE;
            pFree->pNext = pRight;
            pFree->pPrev = pLeft;
            pLeft->pNext = pFree;
            if (pRight)
                pRight->pPrev = pFree;
            else
                pHeapInt->pFreeTail = pFree;
        }
    }

    /*
     * Can we merge with right hand free block?
     */
    if (    pRight
        &&  pRight->Core.pPrev == &pFree->Core)
    {
        /* core */
        pFree->Core.pNext = pRight->Core.pNext;
        if (pRight->Core.pNext)
            pRight->Core.pNext->pPrev = &pFree->Core;

        /* free */
        pFree->pNext = pRight->pNext;
        if (pRight->pNext)
            pRight->pNext->pPrev = pFree;
        else
            pHeapInt->pFreeTail = pFree;
        pHeapInt->cbFree -= pRight->cb;
    }

    /*
     * Calculate the size and update free stats.
     */
    pFree->cb = (pFree->Core.pNext ? (uintptr_t)pFree->Core.pNext : (uintptr_t)pHeapInt->pvEnd)
              - (uintptr_t)pFree - sizeof(RTHEAPSIMPLEBLOCK);
    pHeapInt->cbFree += pFree->cb;
    ASSERT_BLOCK_FREE(pHeapInt, pFree);

#ifdef RTHEAPSIMPLE_STRICT
    rtHeapSimpleAssertAll(pHeapInt);
#endif
}
Example #12
0
/*
 * Push a proxy userdata on the stack.
 * returns NULL if ok, else some error string related to bad idfunc behavior or module require problem
 * (error cannot happen with mode_ == eLM_ToKeeper)
 *
 * Initializes necessary structures if it's the first time 'idfunc' is being
 * used in this Lua state (metatable, registring it). Otherwise, increments the
 * reference count.
 */
char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_)
{
	DEEP_PRELUDE** proxy;

	// Check if a proxy already exists
	push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v");                                        // DPC
	lua_pushlightuserdata( L, prelude->deep);                                                          // DPC deep
	lua_rawget( L, -2);                                                                                // DPC proxy
	if ( !lua_isnil( L, -1))
	{
		lua_remove( L, -2);                                                                              // proxy
		return NULL;
	}
	else
	{
		lua_pop( L, 1);                                                                                  // DPC
	}

	MUTEX_LOCK( &U->deep_lock);
	++ (prelude->refcount);  // one more proxy pointing to this deep data
	MUTEX_UNLOCK( &U->deep_lock);

	STACK_GROW( L, 7);
	STACK_CHECK( L);

	proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*));                                               // DPC proxy
	ASSERT_L( proxy);
	*proxy = prelude;

	// Get/create metatable for 'idfunc' (in this state)
	lua_pushlightuserdata( L, prelude->idfunc);                                                        // DPC proxy idfunc
	get_deep_lookup( L);                                                                               // DPC proxy metatable?

	if( lua_isnil( L, -1)) // // No metatable yet.
	{
		char const* modname;
		int oldtop = lua_gettop( L);                                                                     // DPC proxy nil
		lua_pop( L, 1);                                                                                  // DPC proxy
		// 1 - make one and register it
		if( mode_ != eLM_ToKeeper)
		{
			prelude->idfunc( L, eDO_metatable);                                                            // DPC proxy metatable deepversion
			if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1))
			{
				lua_settop( L, oldtop);                                                                      // DPC proxy X
				lua_pop( L, 3);                                                                              //
				return "Bad idfunc(eOP_metatable): unexpected pushed value";
			}
			luaG_pushdeepversion( L);                                                                      // DPC proxy metatable deepversion deepversion
			if( !lua501_equal( L, -1, -2))
			{
				lua_pop( L, 5);                                                                              //
				return "Bad idfunc(eOP_metatable): mismatched deep version";
			}
			lua_pop( L, 2);                                                                                // DPC proxy metatable
			// make sure the idfunc didn't export __gc, as we will store our own
			lua_getfield( L, -1, "__gc");                                                                  // DPC proxy metatable __gc
			if( !lua_isnil( L, -1))
			{
				lua_pop( L, 4);                                                                              //
				return "idfunc-created metatable shouldn't contain __gc";
			}
			lua_pop( L, 1);                                                                                // DPC proxy metatable
		}
		else
		{
			// keepers need a minimal metatable that only contains __gc
			lua_newtable( L);                                                                              // DPC proxy metatable
		}
		// Add our own '__gc' method
		lua_pushcfunction( L, deep_userdata_gc);                                                         // DPC proxy metatable __gc
		lua_setfield( L, -2, "__gc");                                                                    // DPC proxy metatable

		// Memorize for later rounds
		lua_pushvalue( L, -1);                                                                           // DPC proxy metatable metatable
		lua_pushlightuserdata( L, prelude->idfunc);                                                      // DPC proxy metatable metatable idfunc
		set_deep_lookup( L);                                                                             // DPC proxy metatable

		// 2 - cause the target state to require the module that exported the idfunc
		// this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc
		{
			int oldtop = lua_gettop( L);
			modname = (char const*) prelude->idfunc( L, eDO_module);                                       // DPC proxy metatable
			// make sure the function pushed nothing on the stack!
			if( lua_gettop( L) - oldtop != 0)
			{
				lua_pop( L, 3);                                                                              //
				return "Bad idfunc(eOP_module): should not push anything";
			}
		}
		if( modname) // we actually got a module name
		{
			// somehow, L.registry._LOADED can exist without having registered the 'package' library.
			lua_getglobal( L, "require");                                                                  // DPC proxy metatable require()
			// check that the module is already loaded (or being loaded, we are happy either way)
			if( lua_isfunction( L, -1))
			{
				lua_pushstring( L, modname);                                                                 // DPC proxy metatable require() "module"
				lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED");                                              // DPC proxy metatable require() "module" _R._LOADED
				if( lua_istable( L, -1))
				{
					bool_t alreadyloaded;
					lua_pushvalue( L, -2);                                                                     // DPC proxy metatable require() "module" _R._LOADED "module"
					lua_rawget( L, -2);                                                                        // DPC proxy metatable require() "module" _R._LOADED module
					alreadyloaded = lua_toboolean( L, -1);
					if( !alreadyloaded) // not loaded
					{
						int require_result;
						lua_pop( L, 2);                                                                          // DPC proxy metatable require() "module"
						// require "modname"
						require_result = lua_pcall( L, 1, 0, 0);                                                 // DPC proxy metatable error?
						if( require_result != LUA_OK)
						{
							// failed, return the error message
							lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname);
							lua_insert( L, -2);                                                                    // DPC proxy metatable prefix error
							lua_concat( L, 2);                                                                     // DPC proxy metatable error
							return lua_tostring( L, -1);
						}
					}
					else // already loaded, we are happy
					{
						lua_pop( L, 4);                                                                          // DPC proxy metatable
					}
				}
				else // no L.registry._LOADED; can this ever happen?
				{
					lua_pop( L, 6);                                                                            //
					return "unexpected error while requiring a module identified by idfunc(eOP_module)";
				}
			}
			else // a module name, but no require() function :-(
			{
				lua_pop( L, 4);                                                                              //
				return "lanes receiving deep userdata should register the 'package' library";
			}
		}
	}
	STACK_MID( L, 2);                                                                                  // DPC proxy metatable
	ASSERT_L( lua_isuserdata( L, -2));
	ASSERT_L( lua_istable( L, -1));
	lua_setmetatable( L, -2);                                                                          // DPC proxy

	// If we're here, we obviously had to create a new proxy, so cache it.
	lua_pushlightuserdata( L, (*proxy)->deep);                                                         // DPC proxy deep
	lua_pushvalue( L, -2);                                                                             // DPC proxy deep proxy
	lua_rawset( L, -4);                                                                                // DPC proxy
	lua_remove( L, -2);                                                                                // proxy
	ASSERT_L( lua_isuserdata( L, -1));
	STACK_END( L, 0);
	return NULL;
}
Example #13
0
// in: linda_ud [, key [, ...]]
int keepercall_count( lua_State* L)
{
	int top;
	push_table( L, 1);                                   // ud keys fifos
	switch( lua_gettop( L))
	{
		// no key is specified: return a table giving the count of all known keys
		case 2:                                            // ud fifos
		lua_newtable( L);                                  // ud fifos out
		lua_replace( L, 1);                                // out fifos
		lua_pushnil( L);                                   // out fifos nil
		while( lua_next( L, 2))                            // out fifos key fifo
		{
			keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo
			lua_pop( L, 1);                                  // out fifos key
			lua_pushvalue( L, -1);                           // out fifos key key
			lua_pushinteger( L, fifo->count);                // out fifos key key count
			lua_rawset( L, -5);                              // out fifos key
		}
		lua_pop( L, 1);                                    // out
		break;

		// 1 key is specified: return its count
		case 3:                                            // ud key fifos
		{
			keeper_fifo* fifo;
			lua_replace( L, 1);                              // fifos key
			lua_rawget( L, -2);                              // fifos fifo|nil
			if( lua_isnil( L, -1)) // the key is unknown
			{                                                // fifos nil
				lua_remove( L, -2);                            // nil
			}
			else // the key is known
			{                                                // fifos fifo
				fifo = prepare_fifo_access( L, -1);            // fifos fifo
				lua_pushinteger( L, fifo->count);              // fifos fifo count
				lua_replace( L, -3);                           // count fifo
				lua_pop( L, 1);                                // count
			}
		}
		break;

		// a variable number of keys is specified: return a table of their counts
		default:                                           // ud keys fifos
		lua_newtable( L);                                  // ud keys fifos out
		lua_replace( L, 1);                                // out keys fifos
		// shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable
		lua_insert( L, 2);                                 // out fifos keys
		while( (top = lua_gettop( L)) > 2)
		{
			keeper_fifo* fifo;
			lua_pushvalue( L, -1);                           // out fifos keys key
			lua_rawget( L, 2);                               // out fifos keys fifo|nil
			fifo = prepare_fifo_access( L, -1);              // out fifos keys fifo|nil
			lua_pop( L, 1);                                  // out fifos keys
			if( fifo != NULL) // the key is known
			{
				lua_pushinteger( L, fifo->count);              // out fifos keys count
				lua_rawset( L, 1);                             // out fifos keys
			}
			else // the key is unknown
			{
				lua_pop( L, 1);                                // out fifos keys
			}
		}
		lua_pop( L, 1);                                    // out
	}
	ASSERT_L( lua_gettop( L) == 1);
	return 1;
}