1*8e3e3a7aSWarner Losh /* 2*8e3e3a7aSWarner Losh ** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $ 3*8e3e3a7aSWarner Losh ** Global State 4*8e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 5*8e3e3a7aSWarner Losh */ 6*8e3e3a7aSWarner Losh 7*8e3e3a7aSWarner Losh #define lstate_c 8*8e3e3a7aSWarner Losh #define LUA_CORE 9*8e3e3a7aSWarner Losh 10*8e3e3a7aSWarner Losh #include "lprefix.h" 11*8e3e3a7aSWarner Losh 12*8e3e3a7aSWarner Losh 13*8e3e3a7aSWarner Losh #include <stddef.h> 14*8e3e3a7aSWarner Losh #include <string.h> 15*8e3e3a7aSWarner Losh 16*8e3e3a7aSWarner Losh #include "lua.h" 17*8e3e3a7aSWarner Losh 18*8e3e3a7aSWarner Losh #include "lapi.h" 19*8e3e3a7aSWarner Losh #include "ldebug.h" 20*8e3e3a7aSWarner Losh #include "ldo.h" 21*8e3e3a7aSWarner Losh #include "lfunc.h" 22*8e3e3a7aSWarner Losh #include "lgc.h" 23*8e3e3a7aSWarner Losh #include "llex.h" 24*8e3e3a7aSWarner Losh #include "lmem.h" 25*8e3e3a7aSWarner Losh #include "lstate.h" 26*8e3e3a7aSWarner Losh #include "lstring.h" 27*8e3e3a7aSWarner Losh #include "ltable.h" 28*8e3e3a7aSWarner Losh #include "ltm.h" 29*8e3e3a7aSWarner Losh 30*8e3e3a7aSWarner Losh 31*8e3e3a7aSWarner Losh #if !defined(LUAI_GCPAUSE) 32*8e3e3a7aSWarner Losh #define LUAI_GCPAUSE 200 /* 200% */ 33*8e3e3a7aSWarner Losh #endif 34*8e3e3a7aSWarner Losh 35*8e3e3a7aSWarner Losh #if !defined(LUAI_GCMUL) 36*8e3e3a7aSWarner Losh #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ 37*8e3e3a7aSWarner Losh #endif 38*8e3e3a7aSWarner Losh 39*8e3e3a7aSWarner Losh 40*8e3e3a7aSWarner Losh /* 41*8e3e3a7aSWarner Losh ** a macro to help the creation of a unique random seed when a state is 42*8e3e3a7aSWarner Losh ** created; the seed is used to randomize hashes. 43*8e3e3a7aSWarner Losh */ 44*8e3e3a7aSWarner Losh #if !defined(luai_makeseed) 45*8e3e3a7aSWarner Losh #include <time.h> 46*8e3e3a7aSWarner Losh #define luai_makeseed() cast(unsigned int, time(NULL)) 47*8e3e3a7aSWarner Losh #endif 48*8e3e3a7aSWarner Losh 49*8e3e3a7aSWarner Losh 50*8e3e3a7aSWarner Losh 51*8e3e3a7aSWarner Losh /* 52*8e3e3a7aSWarner Losh ** thread state + extra space 53*8e3e3a7aSWarner Losh */ 54*8e3e3a7aSWarner Losh typedef struct LX { 55*8e3e3a7aSWarner Losh lu_byte extra_[LUA_EXTRASPACE]; 56*8e3e3a7aSWarner Losh lua_State l; 57*8e3e3a7aSWarner Losh } LX; 58*8e3e3a7aSWarner Losh 59*8e3e3a7aSWarner Losh 60*8e3e3a7aSWarner Losh /* 61*8e3e3a7aSWarner Losh ** Main thread combines a thread state and the global state 62*8e3e3a7aSWarner Losh */ 63*8e3e3a7aSWarner Losh typedef struct LG { 64*8e3e3a7aSWarner Losh LX l; 65*8e3e3a7aSWarner Losh global_State g; 66*8e3e3a7aSWarner Losh } LG; 67*8e3e3a7aSWarner Losh 68*8e3e3a7aSWarner Losh 69*8e3e3a7aSWarner Losh 70*8e3e3a7aSWarner Losh #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) 71*8e3e3a7aSWarner Losh 72*8e3e3a7aSWarner Losh 73*8e3e3a7aSWarner Losh /* 74*8e3e3a7aSWarner Losh ** Compute an initial seed as random as possible. Rely on Address Space 75*8e3e3a7aSWarner Losh ** Layout Randomization (if present) to increase randomness.. 76*8e3e3a7aSWarner Losh */ 77*8e3e3a7aSWarner Losh #define addbuff(b,p,e) \ 78*8e3e3a7aSWarner Losh { size_t t = cast(size_t, e); \ 79*8e3e3a7aSWarner Losh memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } 80*8e3e3a7aSWarner Losh 81*8e3e3a7aSWarner Losh static unsigned int makeseed (lua_State *L) { 82*8e3e3a7aSWarner Losh char buff[4 * sizeof(size_t)]; 83*8e3e3a7aSWarner Losh unsigned int h = luai_makeseed(); 84*8e3e3a7aSWarner Losh int p = 0; 85*8e3e3a7aSWarner Losh addbuff(buff, p, L); /* heap variable */ 86*8e3e3a7aSWarner Losh addbuff(buff, p, &h); /* local variable */ 87*8e3e3a7aSWarner Losh addbuff(buff, p, luaO_nilobject); /* global variable */ 88*8e3e3a7aSWarner Losh addbuff(buff, p, &lua_newstate); /* public function */ 89*8e3e3a7aSWarner Losh lua_assert(p == sizeof(buff)); 90*8e3e3a7aSWarner Losh return luaS_hash(buff, p, h); 91*8e3e3a7aSWarner Losh } 92*8e3e3a7aSWarner Losh 93*8e3e3a7aSWarner Losh 94*8e3e3a7aSWarner Losh /* 95*8e3e3a7aSWarner Losh ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) 96*8e3e3a7aSWarner Losh ** invariant (and avoiding underflows in 'totalbytes') 97*8e3e3a7aSWarner Losh */ 98*8e3e3a7aSWarner Losh void luaE_setdebt (global_State *g, l_mem debt) { 99*8e3e3a7aSWarner Losh l_mem tb = gettotalbytes(g); 100*8e3e3a7aSWarner Losh lua_assert(tb > 0); 101*8e3e3a7aSWarner Losh if (debt < tb - MAX_LMEM) 102*8e3e3a7aSWarner Losh debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ 103*8e3e3a7aSWarner Losh g->totalbytes = tb - debt; 104*8e3e3a7aSWarner Losh g->GCdebt = debt; 105*8e3e3a7aSWarner Losh } 106*8e3e3a7aSWarner Losh 107*8e3e3a7aSWarner Losh 108*8e3e3a7aSWarner Losh CallInfo *luaE_extendCI (lua_State *L) { 109*8e3e3a7aSWarner Losh CallInfo *ci = luaM_new(L, CallInfo); 110*8e3e3a7aSWarner Losh lua_assert(L->ci->next == NULL); 111*8e3e3a7aSWarner Losh L->ci->next = ci; 112*8e3e3a7aSWarner Losh ci->previous = L->ci; 113*8e3e3a7aSWarner Losh ci->next = NULL; 114*8e3e3a7aSWarner Losh L->nci++; 115*8e3e3a7aSWarner Losh return ci; 116*8e3e3a7aSWarner Losh } 117*8e3e3a7aSWarner Losh 118*8e3e3a7aSWarner Losh 119*8e3e3a7aSWarner Losh /* 120*8e3e3a7aSWarner Losh ** free all CallInfo structures not in use by a thread 121*8e3e3a7aSWarner Losh */ 122*8e3e3a7aSWarner Losh void luaE_freeCI (lua_State *L) { 123*8e3e3a7aSWarner Losh CallInfo *ci = L->ci; 124*8e3e3a7aSWarner Losh CallInfo *next = ci->next; 125*8e3e3a7aSWarner Losh ci->next = NULL; 126*8e3e3a7aSWarner Losh while ((ci = next) != NULL) { 127*8e3e3a7aSWarner Losh next = ci->next; 128*8e3e3a7aSWarner Losh luaM_free(L, ci); 129*8e3e3a7aSWarner Losh L->nci--; 130*8e3e3a7aSWarner Losh } 131*8e3e3a7aSWarner Losh } 132*8e3e3a7aSWarner Losh 133*8e3e3a7aSWarner Losh 134*8e3e3a7aSWarner Losh /* 135*8e3e3a7aSWarner Losh ** free half of the CallInfo structures not in use by a thread 136*8e3e3a7aSWarner Losh */ 137*8e3e3a7aSWarner Losh void luaE_shrinkCI (lua_State *L) { 138*8e3e3a7aSWarner Losh CallInfo *ci = L->ci; 139*8e3e3a7aSWarner Losh CallInfo *next2; /* next's next */ 140*8e3e3a7aSWarner Losh /* while there are two nexts */ 141*8e3e3a7aSWarner Losh while (ci->next != NULL && (next2 = ci->next->next) != NULL) { 142*8e3e3a7aSWarner Losh luaM_free(L, ci->next); /* free next */ 143*8e3e3a7aSWarner Losh L->nci--; 144*8e3e3a7aSWarner Losh ci->next = next2; /* remove 'next' from the list */ 145*8e3e3a7aSWarner Losh next2->previous = ci; 146*8e3e3a7aSWarner Losh ci = next2; /* keep next's next */ 147*8e3e3a7aSWarner Losh } 148*8e3e3a7aSWarner Losh } 149*8e3e3a7aSWarner Losh 150*8e3e3a7aSWarner Losh 151*8e3e3a7aSWarner Losh static void stack_init (lua_State *L1, lua_State *L) { 152*8e3e3a7aSWarner Losh int i; CallInfo *ci; 153*8e3e3a7aSWarner Losh /* initialize stack array */ 154*8e3e3a7aSWarner Losh L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); 155*8e3e3a7aSWarner Losh L1->stacksize = BASIC_STACK_SIZE; 156*8e3e3a7aSWarner Losh for (i = 0; i < BASIC_STACK_SIZE; i++) 157*8e3e3a7aSWarner Losh setnilvalue(L1->stack + i); /* erase new stack */ 158*8e3e3a7aSWarner Losh L1->top = L1->stack; 159*8e3e3a7aSWarner Losh L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; 160*8e3e3a7aSWarner Losh /* initialize first ci */ 161*8e3e3a7aSWarner Losh ci = &L1->base_ci; 162*8e3e3a7aSWarner Losh ci->next = ci->previous = NULL; 163*8e3e3a7aSWarner Losh ci->callstatus = 0; 164*8e3e3a7aSWarner Losh ci->func = L1->top; 165*8e3e3a7aSWarner Losh setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ 166*8e3e3a7aSWarner Losh ci->top = L1->top + LUA_MINSTACK; 167*8e3e3a7aSWarner Losh L1->ci = ci; 168*8e3e3a7aSWarner Losh } 169*8e3e3a7aSWarner Losh 170*8e3e3a7aSWarner Losh 171*8e3e3a7aSWarner Losh static void freestack (lua_State *L) { 172*8e3e3a7aSWarner Losh if (L->stack == NULL) 173*8e3e3a7aSWarner Losh return; /* stack not completely built yet */ 174*8e3e3a7aSWarner Losh L->ci = &L->base_ci; /* free the entire 'ci' list */ 175*8e3e3a7aSWarner Losh luaE_freeCI(L); 176*8e3e3a7aSWarner Losh lua_assert(L->nci == 0); 177*8e3e3a7aSWarner Losh luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ 178*8e3e3a7aSWarner Losh } 179*8e3e3a7aSWarner Losh 180*8e3e3a7aSWarner Losh 181*8e3e3a7aSWarner Losh /* 182*8e3e3a7aSWarner Losh ** Create registry table and its predefined values 183*8e3e3a7aSWarner Losh */ 184*8e3e3a7aSWarner Losh static void init_registry (lua_State *L, global_State *g) { 185*8e3e3a7aSWarner Losh TValue temp; 186*8e3e3a7aSWarner Losh /* create registry */ 187*8e3e3a7aSWarner Losh Table *registry = luaH_new(L); 188*8e3e3a7aSWarner Losh sethvalue(L, &g->l_registry, registry); 189*8e3e3a7aSWarner Losh luaH_resize(L, registry, LUA_RIDX_LAST, 0); 190*8e3e3a7aSWarner Losh /* registry[LUA_RIDX_MAINTHREAD] = L */ 191*8e3e3a7aSWarner Losh setthvalue(L, &temp, L); /* temp = L */ 192*8e3e3a7aSWarner Losh luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); 193*8e3e3a7aSWarner Losh /* registry[LUA_RIDX_GLOBALS] = table of globals */ 194*8e3e3a7aSWarner Losh sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ 195*8e3e3a7aSWarner Losh luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); 196*8e3e3a7aSWarner Losh } 197*8e3e3a7aSWarner Losh 198*8e3e3a7aSWarner Losh 199*8e3e3a7aSWarner Losh /* 200*8e3e3a7aSWarner Losh ** open parts of the state that may cause memory-allocation errors. 201*8e3e3a7aSWarner Losh ** ('g->version' != NULL flags that the state was completely build) 202*8e3e3a7aSWarner Losh */ 203*8e3e3a7aSWarner Losh static void f_luaopen (lua_State *L, void *ud) { 204*8e3e3a7aSWarner Losh global_State *g = G(L); 205*8e3e3a7aSWarner Losh UNUSED(ud); 206*8e3e3a7aSWarner Losh stack_init(L, L); /* init stack */ 207*8e3e3a7aSWarner Losh init_registry(L, g); 208*8e3e3a7aSWarner Losh luaS_init(L); 209*8e3e3a7aSWarner Losh luaT_init(L); 210*8e3e3a7aSWarner Losh luaX_init(L); 211*8e3e3a7aSWarner Losh g->gcrunning = 1; /* allow gc */ 212*8e3e3a7aSWarner Losh g->version = lua_version(NULL); 213*8e3e3a7aSWarner Losh luai_userstateopen(L); 214*8e3e3a7aSWarner Losh } 215*8e3e3a7aSWarner Losh 216*8e3e3a7aSWarner Losh 217*8e3e3a7aSWarner Losh /* 218*8e3e3a7aSWarner Losh ** preinitialize a thread with consistent values without allocating 219*8e3e3a7aSWarner Losh ** any memory (to avoid errors) 220*8e3e3a7aSWarner Losh */ 221*8e3e3a7aSWarner Losh static void preinit_thread (lua_State *L, global_State *g) { 222*8e3e3a7aSWarner Losh G(L) = g; 223*8e3e3a7aSWarner Losh L->stack = NULL; 224*8e3e3a7aSWarner Losh L->ci = NULL; 225*8e3e3a7aSWarner Losh L->nci = 0; 226*8e3e3a7aSWarner Losh L->stacksize = 0; 227*8e3e3a7aSWarner Losh L->twups = L; /* thread has no upvalues */ 228*8e3e3a7aSWarner Losh L->errorJmp = NULL; 229*8e3e3a7aSWarner Losh L->nCcalls = 0; 230*8e3e3a7aSWarner Losh L->hook = NULL; 231*8e3e3a7aSWarner Losh L->hookmask = 0; 232*8e3e3a7aSWarner Losh L->basehookcount = 0; 233*8e3e3a7aSWarner Losh L->allowhook = 1; 234*8e3e3a7aSWarner Losh resethookcount(L); 235*8e3e3a7aSWarner Losh L->openupval = NULL; 236*8e3e3a7aSWarner Losh L->nny = 1; 237*8e3e3a7aSWarner Losh L->status = LUA_OK; 238*8e3e3a7aSWarner Losh L->errfunc = 0; 239*8e3e3a7aSWarner Losh } 240*8e3e3a7aSWarner Losh 241*8e3e3a7aSWarner Losh 242*8e3e3a7aSWarner Losh static void close_state (lua_State *L) { 243*8e3e3a7aSWarner Losh global_State *g = G(L); 244*8e3e3a7aSWarner Losh luaF_close(L, L->stack); /* close all upvalues for this thread */ 245*8e3e3a7aSWarner Losh luaC_freeallobjects(L); /* collect all objects */ 246*8e3e3a7aSWarner Losh if (g->version) /* closing a fully built state? */ 247*8e3e3a7aSWarner Losh luai_userstateclose(L); 248*8e3e3a7aSWarner Losh luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); 249*8e3e3a7aSWarner Losh freestack(L); 250*8e3e3a7aSWarner Losh lua_assert(gettotalbytes(g) == sizeof(LG)); 251*8e3e3a7aSWarner Losh (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ 252*8e3e3a7aSWarner Losh } 253*8e3e3a7aSWarner Losh 254*8e3e3a7aSWarner Losh 255*8e3e3a7aSWarner Losh LUA_API lua_State *lua_newthread (lua_State *L) { 256*8e3e3a7aSWarner Losh global_State *g = G(L); 257*8e3e3a7aSWarner Losh lua_State *L1; 258*8e3e3a7aSWarner Losh lua_lock(L); 259*8e3e3a7aSWarner Losh luaC_checkGC(L); 260*8e3e3a7aSWarner Losh /* create new thread */ 261*8e3e3a7aSWarner Losh L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; 262*8e3e3a7aSWarner Losh L1->marked = luaC_white(g); 263*8e3e3a7aSWarner Losh L1->tt = LUA_TTHREAD; 264*8e3e3a7aSWarner Losh /* link it on list 'allgc' */ 265*8e3e3a7aSWarner Losh L1->next = g->allgc; 266*8e3e3a7aSWarner Losh g->allgc = obj2gco(L1); 267*8e3e3a7aSWarner Losh /* anchor it on L stack */ 268*8e3e3a7aSWarner Losh setthvalue(L, L->top, L1); 269*8e3e3a7aSWarner Losh api_incr_top(L); 270*8e3e3a7aSWarner Losh preinit_thread(L1, g); 271*8e3e3a7aSWarner Losh L1->hookmask = L->hookmask; 272*8e3e3a7aSWarner Losh L1->basehookcount = L->basehookcount; 273*8e3e3a7aSWarner Losh L1->hook = L->hook; 274*8e3e3a7aSWarner Losh resethookcount(L1); 275*8e3e3a7aSWarner Losh /* initialize L1 extra space */ 276*8e3e3a7aSWarner Losh memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), 277*8e3e3a7aSWarner Losh LUA_EXTRASPACE); 278*8e3e3a7aSWarner Losh luai_userstatethread(L, L1); 279*8e3e3a7aSWarner Losh stack_init(L1, L); /* init stack */ 280*8e3e3a7aSWarner Losh lua_unlock(L); 281*8e3e3a7aSWarner Losh return L1; 282*8e3e3a7aSWarner Losh } 283*8e3e3a7aSWarner Losh 284*8e3e3a7aSWarner Losh 285*8e3e3a7aSWarner Losh void luaE_freethread (lua_State *L, lua_State *L1) { 286*8e3e3a7aSWarner Losh LX *l = fromstate(L1); 287*8e3e3a7aSWarner Losh luaF_close(L1, L1->stack); /* close all upvalues for this thread */ 288*8e3e3a7aSWarner Losh lua_assert(L1->openupval == NULL); 289*8e3e3a7aSWarner Losh luai_userstatefree(L, L1); 290*8e3e3a7aSWarner Losh freestack(L1); 291*8e3e3a7aSWarner Losh luaM_free(L, l); 292*8e3e3a7aSWarner Losh } 293*8e3e3a7aSWarner Losh 294*8e3e3a7aSWarner Losh 295*8e3e3a7aSWarner Losh LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { 296*8e3e3a7aSWarner Losh int i; 297*8e3e3a7aSWarner Losh lua_State *L; 298*8e3e3a7aSWarner Losh global_State *g; 299*8e3e3a7aSWarner Losh LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); 300*8e3e3a7aSWarner Losh if (l == NULL) return NULL; 301*8e3e3a7aSWarner Losh L = &l->l.l; 302*8e3e3a7aSWarner Losh g = &l->g; 303*8e3e3a7aSWarner Losh L->next = NULL; 304*8e3e3a7aSWarner Losh L->tt = LUA_TTHREAD; 305*8e3e3a7aSWarner Losh g->currentwhite = bitmask(WHITE0BIT); 306*8e3e3a7aSWarner Losh L->marked = luaC_white(g); 307*8e3e3a7aSWarner Losh preinit_thread(L, g); 308*8e3e3a7aSWarner Losh g->frealloc = f; 309*8e3e3a7aSWarner Losh g->ud = ud; 310*8e3e3a7aSWarner Losh g->mainthread = L; 311*8e3e3a7aSWarner Losh g->seed = makeseed(L); 312*8e3e3a7aSWarner Losh g->gcrunning = 0; /* no GC while building state */ 313*8e3e3a7aSWarner Losh g->GCestimate = 0; 314*8e3e3a7aSWarner Losh g->strt.size = g->strt.nuse = 0; 315*8e3e3a7aSWarner Losh g->strt.hash = NULL; 316*8e3e3a7aSWarner Losh setnilvalue(&g->l_registry); 317*8e3e3a7aSWarner Losh g->panic = NULL; 318*8e3e3a7aSWarner Losh g->version = NULL; 319*8e3e3a7aSWarner Losh g->gcstate = GCSpause; 320*8e3e3a7aSWarner Losh g->gckind = KGC_NORMAL; 321*8e3e3a7aSWarner Losh g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; 322*8e3e3a7aSWarner Losh g->sweepgc = NULL; 323*8e3e3a7aSWarner Losh g->gray = g->grayagain = NULL; 324*8e3e3a7aSWarner Losh g->weak = g->ephemeron = g->allweak = NULL; 325*8e3e3a7aSWarner Losh g->twups = NULL; 326*8e3e3a7aSWarner Losh g->totalbytes = sizeof(LG); 327*8e3e3a7aSWarner Losh g->GCdebt = 0; 328*8e3e3a7aSWarner Losh g->gcfinnum = 0; 329*8e3e3a7aSWarner Losh g->gcpause = LUAI_GCPAUSE; 330*8e3e3a7aSWarner Losh g->gcstepmul = LUAI_GCMUL; 331*8e3e3a7aSWarner Losh for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; 332*8e3e3a7aSWarner Losh if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { 333*8e3e3a7aSWarner Losh /* memory allocation error: free partial state */ 334*8e3e3a7aSWarner Losh close_state(L); 335*8e3e3a7aSWarner Losh L = NULL; 336*8e3e3a7aSWarner Losh } 337*8e3e3a7aSWarner Losh return L; 338*8e3e3a7aSWarner Losh } 339*8e3e3a7aSWarner Losh 340*8e3e3a7aSWarner Losh 341*8e3e3a7aSWarner Losh LUA_API void lua_close (lua_State *L) { 342*8e3e3a7aSWarner Losh L = G(L)->mainthread; /* only the main thread can be closed */ 343*8e3e3a7aSWarner Losh lua_lock(L); 344*8e3e3a7aSWarner Losh close_state(L); 345*8e3e3a7aSWarner Losh } 346*8e3e3a7aSWarner Losh 347*8e3e3a7aSWarner Losh 348