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.
* settings table is at position 1 on the stack
*/
char const* init_keepers( lua_State* L)
{
	int i;
	PROPAGATE_ALLOCF_PREP( L);

	STACK_CHECK( L);
	lua_getfield( L, 1, "nb_keepers");
	GNbKeepers = (int) lua_tointeger( L, -1);
	lua_pop( L, 1);
	STACK_END( L, 0);
	assert( GNbKeepers >= 1);

	GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper));
	for( i = 0; i < GNbKeepers; ++ i)
	{
		lua_State* K = PROPAGATE_ALLOCF_ALLOC();
		if( K == NULL)
		{
			(void) luaL_error( L, "init_keepers() failed while creating keeper state; 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");

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

		STACK_END( K, 0);
		// 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.
		MUTEX_RECURSIVE_INIT( &GKeepers[i].lock_);
		GKeepers[i].L = K;
	}
#if HAVE_KEEPER_ATEXIT_DESINIT
	atexit( atexit_close_keepers);
#endif // HAVE_KEEPER_ATEXIT_DESINIT
	return NULL; // ok
}
Exemple #2
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);
}