xref: /freebsd-src/contrib/lua/src/lstate.c (revision 8e3e3a7ae841ccf6f6ac30a2eeab85df5d7f04bc)
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