/* * 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 }
/* * 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); }