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