Exemple #1
0
/*
* Initialize keeper states
*
* If there is a problem, return an error message (NULL for okay).
*
* Note: Any problems would be design flaws; the created Lua state is left
*       unclosed, because it does not really matter. In production code, this
*       function never fails.
*/
char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
{
	int i;
	assert( _nbKeepers >= 1);
	GNbKeepers = _nbKeepers;
	GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper));
	for( i = 0; i < _nbKeepers; ++ i)
	{

		// We need to load all base libraries in the keeper states so that the transfer databases are populated properly
		// 
		// 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs
		// the others because they export functions that we may store in a keeper for transfer between lanes
		lua_State* K = luaG_newstate( "*", _on_state_create);
		if (!K)
			return "out of memory";

		STACK_CHECK( K)
		// to see VM name in Decoda debugger
		lua_pushliteral( K, "Keeper #");
		lua_pushinteger( K, i + 1);
		lua_concat( K, 2);
		lua_setglobal( K, "decoda_name");

#if KEEPER_MODEL == KEEPER_MODEL_C
		// create the fifos table in the keeper state
		lua_pushlightuserdata( K, fifos_key);
		lua_newtable( K);
		lua_rawset( K, LUA_REGISTRYINDEX);
#endif // KEEPER_MODEL == KEEPER_MODEL_C

#if KEEPER_MODEL == KEEPER_MODEL_LUA
		// use package.loaders[2] to find keeper microcode
		lua_getglobal( K, "package");                  // package
		lua_getfield( K, -1, "loaders");               // package package.loaders
		lua_rawgeti( K, -1, 2);                        // package package.loaders package.loaders[2]
		lua_pushliteral( K, "lanes-keeper");           // package package.loaders package.loaders[2] "lanes-keeper"
		STACK_MID( K, 4);
		// first pcall loads lanes-keeper.lua, second one runs the chunk
		if( lua_pcall( K, 1 /*args*/, 1 /*results*/, 0 /*errfunc*/) || lua_pcall( K, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/))
		{
			// LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR
			//
			char const* err = lua_tostring( K, -1);
			assert( err);
			return err;
		}                                              // package package.loaders
		STACK_MID( K, 2);
		lua_pop( K, 2);
#endif // KEEPER_MODEL == KEEPER_MODEL_LUA
		STACK_END( K, 0)
		MUTEX_INIT( &GKeepers[i].lock_);
		GKeepers[i].L = K;
		//GKeepers[i].count = 0;
	}
#if HAVE_KEEPER_ATEXIT_DESINIT
	atexit( atexit_close_keepers);
#endif // HAVE_KEEPER_ATEXIT_DESINIT
	return NULL;    // ok
}
Exemple #2
0
/*
* Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists.
* Pops the both values off the stack.
*/
static void set_deep_lookup( lua_State* L)
{
	STACK_GROW( L, 3);
	STACK_CHECK( L);                                         // a b
	push_registry_subtable( L, DEEP_LOOKUP_KEY);             // a b {}
	STACK_MID( L, 1);
	lua_insert( L, -3);                                      // {} a b
	lua_pushvalue( L, -1);                                   // {} a b b
	lua_pushvalue( L,-3);                                    // {} a b b a
	lua_rawset( L, -5);                                      // {} a b
	lua_rawset( L, -3);                                      // {}
	lua_pop( L, 1);                                          //
	STACK_END( L, -2);
}
Exemple #3
0
/*
* Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists.
* Pops the both values off the stack.
*/
void set_deep_lookup( lua_State *L ) {

    STACK_GROW(L,3);

  STACK_CHECK(L)
#if 1
    push_registry_subtable( L, DEEP_LOOKUP_KEY );
#else
    /* ..to be removed.. */
    lua_pushlightuserdata( L, DEEP_LOOKUP_KEY );
    lua_rawget( L, LUA_REGISTRYINDEX );

    if (lua_isnil(L,-1)) {
        // First time here; let's make the lookup
        //
        lua_pop(L,1);

        lua_newtable(L);
        lua_pushlightuserdata( L, DEEP_LOOKUP_KEY );
        lua_pushvalue(L,-2);
            //
            // [-3]: {} (2nd ref)
            // [-2]: DEEP_LOOKUP_KEY
            // [-1]: {}

        lua_rawset( L, LUA_REGISTRYINDEX );
            //
            // [-1]: lookup table (empty)
    }
#endif
  STACK_MID(L,1)

    lua_insert(L,-3);

    // [-3]: lookup table
    // [-2]: A
    // [-1]: B
    
    lua_pushvalue( L,-1 );  // B
    lua_pushvalue( L,-3 );  // A
    lua_rawset( L, -5 );    // B->A
    lua_rawset( L, -3 );    // A->B
    lua_pop( L,1 );

  STACK_END(L,-2)
}
Exemple #4
0
int keeper_push_linda_storage( struct s_Universe* U, lua_State* L, void* ptr, unsigned long magic_)
{
	struct s_Keeper* K = keeper_acquire( U->keepers, magic_);
	lua_State* KL = K ? K->L : NULL;
	if( KL == NULL) return 0;
	STACK_GROW( KL, 4);
	STACK_CHECK( KL);
	lua_pushlightuserdata( KL, fifos_key);                      // fifos_key
	lua_rawget( KL, LUA_REGISTRYINDEX);                         // fifos
	lua_pushlightuserdata( KL, ptr);                            // fifos ud
	lua_rawget( KL, -2);                                        // fifos storage
	lua_remove( KL, -2);                                        // storage
	if( !lua_istable( KL, -1))
	{
		lua_pop( KL, 1);                                          //
		STACK_MID( KL, 0);
		return 0;
	}
	// move data from keeper to destination state                  KEEPER                       MAIN
	lua_pushnil( KL);                                           // storage nil
	STACK_GROW( L, 5);
	STACK_CHECK( L);
	lua_newtable( L);                                                                        // out
	while( lua_next( KL, -2))                                   // storage key fifo
	{
		keeper_fifo* fifo = prepare_fifo_access( KL, -1);         // storage key fifo
		lua_pushvalue( KL, -2);                                   // storage key fifo key
		luaG_inter_move( U, KL, L, 1, eLM_FromKeeper);            // storage key fifo          // out key
		STACK_MID( L, 2);
		lua_newtable( L);                                                                      // out key keyout
		luaG_inter_move( U, KL, L, 1, eLM_FromKeeper);            // storage key               // out key keyout fifo
		lua_pushinteger( L, fifo->first);                                                      // out key keyout fifo first
		STACK_MID( L, 5);
		lua_setfield( L, -3, "first");                                                         // out key keyout fifo
		lua_pushinteger( L, fifo->count);                                                      // out key keyout fifo count
		STACK_MID( L, 5);
		lua_setfield( L, -3, "count");                                                         // out key keyout fifo
		lua_pushinteger( L, fifo->limit);                                                      // out key keyout fifo limit
		STACK_MID( L, 5);
		lua_setfield( L, -3, "limit");                                                         // out key keyout fifo
		lua_setfield( L, -2, "fifo");                                                          // out key keyout
		lua_rawset( L, -3);                                                                    // out
		STACK_MID( L, 1);
	}
	STACK_END( L, 1);
	lua_pop( KL, 1);                                            //
	STACK_END( KL, 0);
	keeper_release( K);
	return 1;
}
Exemple #5
0
int keeper_push_linda_storage( lua_State* L, void* ptr)
{
	struct s_Keeper* K = keeper_acquire( ptr);
	lua_State* KL = K->L;
	STACK_CHECK( KL)
	lua_pushlightuserdata( KL, fifos_key);                      // fifos_key
	lua_rawget( KL, LUA_REGISTRYINDEX);                         // fifos
	lua_pushlightuserdata( KL, ptr);                            // fifos ud
	lua_rawget( KL, -2);                                        // fifos storage
	lua_remove( KL, -2);                                        // storage
	if( !lua_istable( KL, -1))
	{
		lua_pop( KL, 1);                                          //
		STACK_MID( KL, 0);
		return 0;
	}
	lua_pushnil( KL);                                           // storage nil
	lua_newtable( L);                                                                        // out
	while( lua_next( KL, -2))                                   // storage key fifo
	{
		keeper_fifo* fifo = prepare_fifo_access( KL, -1);         // storage key fifo
		lua_pushvalue( KL, -2);                                   // storage key fifo key
		luaG_inter_move( KL, L, 1);                               // storage key fifo          // out key
		STACK_CHECK( L)
		lua_newtable( L);                                                                      // out key keyout
		luaG_inter_move( KL, L, 1);                               // storage key               // out key keyout fifo
		lua_pushinteger( L, fifo->first);                                                      // out key keyout fifo first
		lua_setfield( L, -3, "first");                                                         // out key keyout fifo
		lua_pushinteger( L, fifo->count);                                                      // out key keyout fifo count
		lua_setfield( L, -3, "count");                                                         // out key keyout fifo
		lua_pushinteger( L, fifo->limit);                                                      // out key keyout fifo limit
		lua_setfield( L, -3, "limit");                                                         // out key keyout fifo
		lua_setfield( L, -2, "fifo");                                                          // out key keyout
		lua_rawset( L, -3);                                                                    // out
		STACK_END( L, 0)
	}
	lua_pop( KL, 1);                                            //
	STACK_END( KL, 0)
	keeper_release( K);
	return 1;
}
Exemple #6
0
static void push_table( lua_State* L, int idx)
{
	STACK_GROW( L, 4);
	STACK_CHECK( L);
	idx = lua_absindex( L, idx);
	lua_pushlightuserdata( L, fifos_key);        // ud fifos_key
	lua_rawget( L, LUA_REGISTRYINDEX);           // ud fifos
	lua_pushvalue( L, idx);                      // ud fifos ud
	lua_rawget( L, -2);                          // ud fifos fifos[ud]
	STACK_MID( L, 2);
	if( lua_isnil( L, -1))
	{
		lua_pop( L, 1);                            // ud fifos
		// add a new fifos table for this linda
		lua_newtable( L);                          // ud fifos fifos[ud]
		lua_pushvalue( L, idx);                    // ud fifos fifos[ud] ud
		lua_pushvalue( L, -2);                     // ud fifos fifos[ud] ud fifos[ud]
		lua_rawset( L, -4);                        // ud fifos fifos[ud]
	}
	lua_remove( L, -2);                          // ud fifos[ud]
	STACK_END( L, 1);
}
Exemple #7
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
}
Exemple #8
0
/*
* Initialize keeper states
*
* If there is a problem, return an error message (NULL for okay).
*
* Note: Any problems would be design flaws; the created Lua state is left
*       unclosed, because it does not really matter. In production code, this
*       function never fails.
*/
char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers)
{
	int i;
	assert( _nbKeepers >= 1);
	GNbKeepers = _nbKeepers;
	GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper));
	for( i = 0; i < _nbKeepers; ++ i)
	{
		lua_State* K;
		DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i));
		DEBUGSPEW_CODE( ++ debugspew_indent_depth);
		// We need to load all base libraries in the keeper states so that the transfer databases are populated properly
		// 
		// 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs
		// the others because they export functions that we may store in a keeper for transfer between lanes
		K = luaG_newstate( L, _on_state_create, "K");

		STACK_CHECK( K);

		// replace default 'package' contents with stuff gotten from the master state
		lua_getglobal( L, "package");
		luaG_inter_copy_package( L, K, -1);
		lua_pop( L, 1);

		DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d END\n" INDENT_END, i));
		DEBUGSPEW_CODE( -- debugspew_indent_depth);

		// to see VM name in Decoda debugger
		lua_pushliteral( K, "Keeper #");
		lua_pushinteger( K, i + 1);
		lua_concat( K, 2);
		lua_setglobal( K, "decoda_name");

#if KEEPER_MODEL == KEEPER_MODEL_C
		// create the fifos table in the keeper state
		lua_pushlightuserdata( K, fifos_key);
		lua_newtable( K);
		lua_rawset( K, LUA_REGISTRYINDEX);
#endif // KEEPER_MODEL == KEEPER_MODEL_C

#if KEEPER_MODEL == KEEPER_MODEL_LUA
		// use package.loaders[2] to find keeper microcode (NOTE: this works only if nobody tampered with the loaders table...)
		lua_getglobal( K, "package");                  // package
		lua_getfield( K, -1, "loaders");               // package package.loaders
		lua_rawgeti( K, -1, 2);                        // package package.loaders package.loaders[2]
		lua_pushliteral( K, "lanes-keeper");           // package package.loaders package.loaders[2] "lanes-keeper"
		STACK_MID( K, 4);
		// first pcall loads lanes-keeper.lua, second one runs the chunk
		if( lua_pcall( K, 1 /*args*/, 1 /*results*/, 0 /*errfunc*/) || lua_pcall( K, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/))
		{
			// LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR
			//
			char const* err = lua_tostring( K, -1);
			assert( err);
			return err;
		}                                              // package package.loaders
		STACK_MID( K, 2);
		lua_pop( K, 2);
#endif // KEEPER_MODEL == KEEPER_MODEL_LUA
		STACK_END( K, 0);
		MUTEX_INIT( &GKeepers[i].lock_);
		GKeepers[i].L = K;
		//GKeepers[i].count = 0;
	}
#if HAVE_KEEPER_ATEXIT_DESINIT
	atexit( atexit_close_keepers);
#endif // HAVE_KEEPER_ATEXIT_DESINIT
	return NULL;    // ok
}
Exemple #9
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;
}
Exemple #10
0
/*
 * Initialize keeper states
 *
 * If there is a problem, returns NULL and pushes the error message on the stack
 * else returns the keepers bookkeeping structure.
 *
 * Note: Any problems would be design flaws; the created Lua state is left
 *       unclosed, because it does not really matter. In production code, this
 *       function never fails.
 * settings table is at position 1 on the stack
 */
void init_keepers( struct s_Universe* U, lua_State* L)
{
	int i;
	int nb_keepers;
	void* allocUD;
	lua_Alloc allocF = lua_getallocf( L, &allocUD);

	STACK_CHECK( L);                                       // L                            K
	lua_getfield( L, 1, "nb_keepers");                     // nb_keepers
	nb_keepers = (int) lua_tointeger( L, -1);
	lua_pop( L, 1);                                        //
	assert( nb_keepers >= 1);

	// struct s_Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states
	{
		size_t const bytes = sizeof( struct s_Keepers) + (nb_keepers - 1) * sizeof(struct s_Keeper);
		U->keepers = (struct s_Keepers*) allocF( allocUD, NULL, 0, bytes);
		if( U->keepers == NULL)
		{
			(void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory");
			return;
		}
		memset( U->keepers, 0, bytes);
		U->keepers->nb_keepers = nb_keepers;
	}
	for( i = 0; i < nb_keepers; ++ i)                      // keepersUD
	{
		lua_State* K = PROPAGATE_ALLOCF_ALLOC();
		if( K == NULL)
		{
			(void) luaL_error( L, "init_keepers() failed while creating keeper states; out of memory");
			return;
		}

		U->keepers->keeper_array[i].L = K;
		// we can trigger a GC from inside keeper_call(), where a keeper is acquired
		// from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread.
		// therefore, we need a recursive mutex.
		MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs);
		STACK_CHECK( K);

		// copy the universe pointer in the keeper itself
		lua_pushlightuserdata( K, UNIVERSE_REGKEY);
		lua_pushlightuserdata( K, U);
		lua_rawset( K, LUA_REGISTRYINDEX);
		STACK_MID( K, 0);

		// make sure 'package' is initialized in keeper states, so that we have require()
		// this because this is needed when transferring deep userdata object
		luaL_requiref( K, "package", luaopen_package, 1);                                 // package
		lua_pop( K, 1);                                                                   //
		STACK_MID( K, 0);
		serialize_require( U, K);
		STACK_MID( K, 0);

		// copy package.path and package.cpath from the source state
		lua_getglobal( L, "package");                        // "..." keepersUD package
		if( !lua_isnil( L, -1))
		{
			// when copying with mode eLM_ToKeeper, error message is pushed at the top of the stack, not raised immediately
			if( luaG_inter_copy_package( U, L, K, -1, eLM_ToKeeper))
			{
				// if something went wrong, the error message is at the top of the stack
				lua_remove( L, -2);                              // error_msg
				(void) lua_error( L);
				return;
			}
		}
		lua_pop( L, 1);                                      //
		STACK_MID( L, 0);

		// attempt to call on_state_create(), if we have one and it is a C function
		// (only support a C function because we can't transfer executable Lua code in keepers)
		// will raise an error in L in case of problem
		call_on_state_create( U, K, L, eLM_ToKeeper);

		// to see VM name in Decoda debugger
		lua_pushliteral( K, "Keeper #");                                                  // "Keeper #"
		lua_pushinteger( K, i + 1);                                                       // "Keeper #" n
		lua_concat( K, 2);                                                                // "Keeper #n"
		lua_setglobal( K, "decoda_name");                                                 //

		// create the fifos table in the keeper state
		lua_pushlightuserdata( K, fifos_key);                                             // fifo_key
		lua_newtable( K);                                                                 // fifo_key {}
		lua_rawset( K, LUA_REGISTRYINDEX);                                                //

		STACK_END( K, 0);
	}
	STACK_END( L, 0);
}