int exec_setup_stack(struct lwp *l, struct exec_package *epp) { u_long max_stack_size; u_long access_linear_min, access_size; u_long noaccess_linear_min, noaccess_size; #ifndef USRSTACK32 #define USRSTACK32 (0x00000000ffffffffL&~PGOFSET) #endif if (epp->ep_flags & EXEC_32) { epp->ep_minsaddr = USRSTACK32; max_stack_size = MAXSSIZ; } else { epp->ep_minsaddr = USRSTACK; max_stack_size = MAXSSIZ; } epp->ep_ssize = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur; #ifdef PAX_ASLR pax_aslr_stack(l, epp, &max_stack_size); #endif /* PAX_ASLR */ l->l_proc->p_stackbase = epp->ep_minsaddr; epp->ep_maxsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, max_stack_size); /* * set up commands for stack. note that this takes *two*, one to * map the part of the stack which we can access, and one to map * the part which we can't. * * arguably, it could be made into one, but that would require the * addition of another mapping proc, which is unnecessary */ access_size = epp->ep_ssize; access_linear_min = (u_long)STACK_ALLOC(epp->ep_minsaddr, access_size); noaccess_size = max_stack_size - access_size; noaccess_linear_min = (u_long)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr, access_size), noaccess_size); if (noaccess_size > 0 && noaccess_size <= MAXSSIZ) { NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size, noaccess_linear_min, NULL, 0, VM_PROT_NONE, VMCMD_STACK); } KASSERT(access_size > 0 && access_size <= MAXSSIZ); NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, access_size, access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE, VMCMD_STACK); return 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; }
// in: fifo // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) static void fifo_pop( lua_State* L, keeper_fifo* fifo, int count_) { int fifo_idx = lua_gettop( L); // ... fifo int i; // each iteration pushes a value on the stack! STACK_GROW( L, count_ + 2); // skip first item, we will push it last for( i = 1; i < count_; ++ i) { int const at = fifo->first + i; // push item on the stack lua_rawgeti( L, fifo_idx, at); // ... fifo val // remove item from the fifo lua_pushnil( L); // ... fifo val nil lua_rawseti( L, fifo_idx, at); // ... fifo val } // now process first item { int const at = fifo->first; lua_rawgeti( L, fifo_idx, at); // ... fifo vals val lua_pushnil( L); // ... fifo vals val nil lua_rawseti( L, fifo_idx, at); // ... fifo vals val lua_replace( L, fifo_idx); // ... vals } { // avoid ever-growing indexes by resetting each time we detect the fifo is empty int const new_count = fifo->count - count_; fifo->first = (new_count == 0) ? 1 : (fifo->first + count_); fifo->count = new_count; } }
const char *luaG_openlibs( lua_State *L, const char *libs ) { const char *p; unsigned len; if (!libs) return NULL; // no libs, not even 'base' // 'lua.c' stops GC during initialization so perhaps its a good idea. :) // lua_gc(L, LUA_GCSTOP, 0); // Anything causes 'base' to be taken in // STACK_GROW(L,2); lua_pushcfunction( L, luaopen_base ); lua_pushliteral( L, "" ); lua_call( L, 1, 0 ); for( p= libs; *p; p+=len ) { len=0; while (*p && !is_name_char(*p)) p++; // bypass delimiters while (is_name_char(p[len])) len++; // bypass name if (len && (!openlib( L, p, len ))) break; } lua_gc(L, LUA_GCRESTART, 0); return *p ? p : NULL; }
// in: fifo // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) static void fifo_pop( lua_State* L, keeper_fifo* fifo, int _count) { int fifo_idx = lua_gettop( L); // ... fifo int i; // each iteration pushes a value on the stack! STACK_GROW( L, _count + 2); // skip first item, we will push it last for( i = 1; i < _count; ++ i) { int const at = fifo->first + i; // push item on the stack lua_rawgeti( L, fifo_idx, at); // ... fifo val // remove item from the fifo lua_pushnil( L); // ... fifo val nil lua_rawseti( L, fifo_idx, at); // ... fifo val } // now process first item { int const at = fifo->first; lua_rawgeti( L, fifo_idx, at); // ... fifo vals val lua_pushnil( L); // ... fifo vals val nil lua_rawseti( L, fifo_idx, at); // ... fifo vals val lua_replace( L, fifo_idx); // ... vals } fifo->first += _count; fifo->count -= _count; }
/* * Call a function ('func_name') in the keeper state, and pass on the returned * values to 'L'. * * 'linda': deep Linda pointer (used only as a unique table key, first parameter) * 'starting_index': first of the rest of parameters (none if 0) * * Returns: number of return values (pushed to 'L') or -1 in case of error */ int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index) { int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; int const Ktos = lua_gettop( K); int retvals = -1; STACK_GROW( K, 2); PUSH_KEEPER_FUNC( K, _func); lua_pushlightuserdata( K, linda); if( (args == 0) || luaG_inter_copy( L, K, args) == 0) // L->K { lua_call( K, 1 + args, LUA_MULTRET); retvals = lua_gettop( K) - Ktos; if( (retvals > 0) && luaG_inter_move( K, L, retvals) != 0) // K->L { retvals = -1; } } // whatever happens, restore the stack to where it was at the origin lua_settop( K, Ktos); return retvals; }
// cause each keeper state to populate its database of transferable functions with those from the specified module // do do this we simply require the module inside the keeper state, then populate the lookup database void populate_keepers( lua_State* L) { size_t name_len; char const* name = luaL_checklstring( L, -1, &name_len); int i; DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "populate_keepers %s BEGIN\n" INDENT_END, name)); DEBUGSPEW_CODE( ++ debugspew_indent_depth); for( i = 0; i < GNbKeepers; ++ i) { lua_State* K = GKeepers[i].L; int res; MUTEX_LOCK( &GKeepers[i].lock_); STACK_CHECK( K); STACK_GROW( K, 2); lua_getglobal( K, "require"); lua_pushlstring( K, name, name_len); res = lua_pcall( K, 1, 1, 0); if( res != LUA_OK) { char const* err = luaL_checkstring( K, -1); luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); } // after requiring the module, register the functions it exported in our name<->function database populate_func_lookup_table( K, -1, name); lua_pop( K, 1); STACK_END( K, 0); MUTEX_UNLOCK( &GKeepers[i].lock_); } DEBUGSPEW_CODE( -- debugspew_indent_depth); }
/* * 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)); }
/* * 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( eDO_new [, ...] ) -- creates a new deep data instance * void = idfunc( eDO_delete, lightuserdata ) -- releases a deep data instance * tbl = idfunc( eDO_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_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) { char const* errmsg; DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE)); if( prelude == NULL) { return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); } prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 prelude->idfunc = idfunc; STACK_GROW( L, 1); STACK_CHECK( L); { int oldtop = lua_gettop( L); prelude->deep = idfunc( L, eDO_new); if( prelude->deep == NULL) { luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); } if( lua_gettop( L) - oldtop != 0) { luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); } } errmsg = push_deep_proxy( get_universe( L), L, prelude, eLM_LaneBody); // proxy if( errmsg != NULL) { luaL_error( L, errmsg); } STACK_END( L, 1); return 1; }
/* * Return the registered ID function for 'index' (deep userdata proxy), * or NULL if 'index' is not a deep userdata proxy. */ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupMode mode_) { // when looking inside a keeper, we are 100% sure the object is a deep userdata if( mode_ == eLM_FromKeeper) { DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); // we can (and must) cast and fetch the internally stored idfunc return (*proxy)->idfunc; } else { // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database // it is the only way to ensure that the userdata is indeed a deep userdata! // of course, we could just trust the caller, but we won't luaG_IdFunction ret; STACK_GROW( L, 1); STACK_CHECK( L); if( !lua_getmetatable( L, index)) // deep ... metatable? { return NULL; // no metatable: can't be a deep userdata object! } // replace metatable with the idfunc pointer, if it is actually a deep userdata get_deep_lookup( L); // deep ... idfunc|nil ret = (luaG_IdFunction) lua_touserdata( L, -1); // NULL if not a userdata lua_pop( L, 1); STACK_END( L, 0); return ret; } }
/* * Call a function ('func_name') in the keeper state, and pass on the returned * values to 'L'. * * 'linda': deep Linda pointer (used only as a unique table key, first parameter) * 'starting_index': first of the rest of parameters (none if 0) * * Returns: number of return values (pushed to 'L') or -1 in case of error */ int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index) { int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; int const Ktos = lua_gettop( K); int retvals = -1; STACK_GROW( K, 2); PUSH_KEEPER_FUNC( K, _func); lua_pushlightuserdata( K, linda); if( (args == 0) || luaG_inter_copy( L, K, args, eLM_ToKeeper) == 0) // L->K { lua_call( K, 1 + args, LUA_MULTRET); retvals = lua_gettop( K) - Ktos; // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired // this may interrupt a lane, causing the destruction of the underlying OS thread // after this, another lane making use of this keeper can get an error code from the mutex-locking function // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) if( (retvals > 0) && luaG_inter_move( K, L, retvals, eLM_FromKeeper) != 0) // K->L { retvals = -1; } } // whatever happens, restore the stack to where it was at the origin lua_settop( K, Ktos); return retvals; }
/* * 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) ); }
// cause each keeper state to populate its database of transferable functions with those from the specified module void populate_keepers( lua_State *L) { size_t name_len; char const *name = luaL_checklstring( L, -1, &name_len); size_t package_path_len; char const *package_path; size_t package_cpath_len; char const *package_cpath; int i; // we need to make sure that package.path & package.cpath are the same in the keepers // than what is currently in use when the module is required in the caller's Lua state STACK_CHECK(L) STACK_GROW( L, 3); lua_getglobal( L, "package"); lua_getfield( L, -1, "path"); package_path = luaL_checklstring( L, -1, &package_path_len); lua_getfield( L, -2, "cpath"); package_cpath = luaL_checklstring( L, -1, &package_cpath_len); for( i = 0; i < GNbKeepers; ++ i) { lua_State *K = GKeepers[i].L; int res; MUTEX_LOCK( &GKeepers[i].lock_); STACK_CHECK(K) STACK_GROW( K, 2); lua_getglobal( K, "package"); lua_pushlstring( K, package_path, package_path_len); lua_setfield( K, -2, "path"); lua_pushlstring( K, package_cpath, package_cpath_len); lua_setfield( K, -2, "cpath"); lua_pop( K, 1); lua_getglobal( K, "require"); lua_pushlstring( K, name, name_len); res = lua_pcall( K, 1, 0, 0); if( res != 0) { char const *err = luaL_checkstring( K, -1); luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); } STACK_END(K, 0) MUTEX_UNLOCK( &GKeepers[i].lock_); } lua_pop( L, 3); STACK_END(L, 0) }
// in: fifo // out: ...|nothing // expects exactly 1 value on the stack! // currently only called with a count of 1, but this may change in the future // function assumes that there is enough data in the fifo to satisfy the request static void fifo_peek( lua_State* L, keeper_fifo* fifo, int _count) { int i; STACK_GROW( L, _count); for( i = 0; i < _count; ++ i) { lua_rawgeti( L, 1, fifo->first + i); } }
//in: linda_ud key [val] int keepercall_set( lua_State* L) { STACK_GROW( L, 6); // make sure we have a value on the stack if( lua_gettop( L) == 2) // ud key val? { lua_pushnil( L); // ud key nil } // retrieve fifos associated with the linda push_table( L, 1); // ud key val fifos lua_replace( L, 1); // fifos key val if( !lua_isnil( L, 3)) // set/replace contents stored at the specified key? { keeper_fifo* fifo; lua_pushvalue( L, -2); // fifos key val key lua_rawget( L, 1); // fifos key val fifo|nil fifo = (keeper_fifo*) lua_touserdata( L, -1); if( fifo == NULL) // might be NULL if we set a nonexistent key to nil { lua_pop( L, 1); // fifos key val fifo_new( L); // fifos key val fifo lua_pushvalue( L, 2); // fifos key val fifo key lua_pushvalue( L, -2); // fifos key val fifo key fifo lua_rawset( L, 1); // fifos key val fifo } else // the fifo exists, we just want to clear its contents { // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! lua_newtable( L); // fifos key val fifo {} lua_setuservalue( L, -2); // fifos key val fifo fifo->first = 1; fifo->count = 0; } fifo = prepare_fifo_access( L, -1); lua_insert( L, -2); // fifos key fifo val fifo_push( L, fifo, 1); // fifos key fifo } else // val == nil // fifos key nil { keeper_fifo* fifo; lua_pop( L, 1); // fifos key lua_rawget( L, 1); // fifos fifo|nil // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! fifo = (keeper_fifo*) lua_touserdata( L, -1); if( fifo != NULL) // might be NULL if we set a nonexistent key to nil { lua_newtable( L); // fifos fifo {} lua_setuservalue( L, -2); // fifos fifo fifo->first = 1; fifo->count = 0; } } return 0; }
int darwin_exec_setup_stack(struct lwp *l, struct exec_package *epp) { u_long max_stack_size; u_long access_linear_min, access_size; u_long noaccess_linear_min, noaccess_size; if (epp->ep_flags & EXEC_32) { epp->ep_minsaddr = DARWIN_USRSTACK32; max_stack_size = MAXSSIZ; } else { epp->ep_minsaddr = DARWIN_USRSTACK; max_stack_size = MAXSSIZ; } epp->ep_maxsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, max_stack_size); epp->ep_ssize = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur; /* * set up commands for stack. note that this takes *two*, one to * map the part of the stack which we can access, and one to map * the part which we can't. * * arguably, it could be made into one, but that would require the * addition of another mapping proc, which is unnecessary */ access_size = epp->ep_ssize; access_linear_min = (u_long)STACK_ALLOC(epp->ep_minsaddr, access_size); noaccess_size = max_stack_size - access_size; noaccess_linear_min = (u_long)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr, access_size), noaccess_size); if (noaccess_size > 0) { NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size, noaccess_linear_min, NULL, 0, VM_PROT_NONE, VMCMD_STACK); } KASSERT(access_size > 0); NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, access_size, access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE, VMCMD_STACK); return 0; }
// in: nothing // out: { first = 1, count = 0, limit = -1} static void fifo_new( lua_State* L) { keeper_fifo* fifo; STACK_GROW( L, 2); fifo = (keeper_fifo*) lua_newuserdata( L, sizeof( keeper_fifo)); fifo->first = 1; fifo->count = 0; fifo->limit = -1; lua_newtable( L); lua_setuservalue( L, -2); }
// in: linda_ud int keepercall_clear( lua_State* L) { STACK_GROW( L, 3); lua_pushlightuserdata( L, fifos_key); // ud fifos_key lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos lua_pushvalue( L, 1); // ud fifos ud lua_pushnil( L); // ud fifos ud nil lua_rawset( L, -3); // ud fifos lua_pop( L, 1); // ud return 0; }
// replaces the fifo ud by its uservalue on the stack static keeper_fifo* prepare_fifo_access( lua_State* L, int idx) { keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx); if( fifo != NULL) { idx = lua_absindex( L, idx); STACK_GROW( L, 1); // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around lua_getuservalue( L, idx); lua_replace( L, idx); } return fifo; }
/* * 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); }
/* * Pops the key (metatable or idfunc) off the stack, and replaces with the * deep lookup value (idfunc/metatable/nil). */ static void get_deep_lookup( lua_State* L) { STACK_GROW( L, 1); STACK_CHECK( L); // a lua_pushlightuserdata( L, DEEP_LOOKUP_KEY); // a DLK lua_rawget( L, LUA_REGISTRYINDEX); // a {} if( !lua_isnil( L, -1)) { lua_insert( L, -2); // {} a lua_rawget( L, -2); // {} b } lua_remove( L, -2); // a|b STACK_END( L, 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) }
static bool_t openlib( lua_State *L, const char *name, size_t len ) { unsigned i; bool_t all= strncmp( name, "*", len ) == 0; for( i=0; libs[i].name; i++ ) { if (all || (strncmp(name, libs[i].name, len) ==0)) { if (libs[i].func) { STACK_GROW(L,2); lua_pushcfunction( L, libs[i].func ); lua_pushstring( L, libs[i].name ); lua_call( L, 1, 0 ); } if (!all) return TRUE; } } return all; }
void luaG_dump( lua_State* L ) { int top= lua_gettop(L); int i; fprintf( stderr, "\n\tDEBUG STACK:\n" ); if (top==0) fprintf( stderr, "\t(none)\n" ); for( i=1; i<=top; i++ ) { int type= lua_type( L, i ); fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename(L,type) ); // Print item contents here... // // Note: this requires 'tostring()' to be defined. If it is NOT, // enable it for more debugging. // STACK_CHECK(L) STACK_GROW( L, 2 ) lua_getglobal( L, "tostring" ); // // [-1]: tostring function, or nil if (!lua_isfunction(L,-1)) { fprintf( stderr, "('tostring' not available)" ); } else { lua_pushvalue( L, i ); lua_call( L, 1 /*args*/, 1 /*retvals*/ ); // Don't trust the string contents // fprintf( stderr, "%s", lua_tostring(L,-1) ); } lua_pop(L,1); STACK_END(L,0) fprintf( stderr, "\n" ); } fprintf( stderr, "\n" ); }
/* * Get a unique ID for metatable at [i]. */ static uint_t get_mt_id( lua_State *L, int i ) { static uint_t last_id= 0; uint_t id; i= STACK_ABS(L,i); STACK_GROW(L,3); STACK_CHECK(L) push_registry_subtable( L, REG_MTID ); lua_pushvalue(L, i); lua_rawget( L, -2 ); // // [-2]: reg[REG_MTID] // [-1]: nil/uint id= lua_tointeger(L,-1); // 0 for nil lua_pop(L,1); STACK_MID(L,1) if (id==0) { MUTEX_LOCK( &mtid_lock ); id= ++last_id; MUTEX_UNLOCK( &mtid_lock ); /* Create two-way references: id_uint <-> table */ lua_pushvalue(L,i); lua_pushinteger(L,id); lua_rawset( L, -3 ); lua_pushinteger(L,id); lua_pushvalue(L,i); lua_rawset( L, -3 ); } lua_pop(L,1); // remove 'reg[REG_MTID]' reference STACK_END(L,0) return id; }
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); }
/* * Pops the key (metatable or idfunc) off the stack, and replaces with the * deep lookup value (idfunc/metatable/nil). */ void get_deep_lookup( lua_State *L ) { STACK_GROW(L,1); STACK_CHECK(L) lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); lua_rawget( L, LUA_REGISTRYINDEX ); if (!lua_isnil(L,-1)) { // [-2]: key (metatable or idfunc) // [-1]: lookup table lua_insert( L, -2 ); lua_rawget( L, -2 ); // [-2]: lookup table // [-1]: value (metatable / idfunc / nil) } lua_remove(L,-2); // remove lookup, or unused key STACK_END(L,0) }
/* * Return the registered ID function for 'index' (deep userdata proxy), * or NULL if 'index' is not a deep userdata proxy. */ static lua_CFunction get_idfunc( lua_State *L, int index ) { lua_CFunction ret; index= STACK_ABS(L,index); STACK_GROW(L,1); STACK_CHECK(L) if (!lua_getmetatable( L, index )) return NULL; // no metatable // [-1]: metatable of [index] get_deep_lookup(L); // // [-1]: idfunc/nil ret= lua_tocfunction(L,-1); lua_pop(L,1); STACK_END(L,0) return ret; }
/* * 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; }
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) }