Created
January 2, 2015 06:48
-
-
Save mniip/8dab452a3adba3c70fe7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lua-5.2.3/src/Makefile b/lua-5.2.3/src/Makefile | |
index 7b4b2b7..efe504b 100644 | |
--- a/lua-5.2.3/src/Makefile | |
+++ b/lua-5.2.3/src/Makefile | |
@@ -103,7 +103,7 @@ freebsd: | |
generic: $(ALL) | |
linux: | |
- $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" | |
+ $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -lpthread" | |
macosx: | |
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc | |
@@ -144,7 +144,7 @@ ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ | |
lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \ | |
lstring.h ltable.h lundump.h lvm.h | |
ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ | |
- lzio.h lmem.h lundump.h | |
+ lzio.h lmem.h lundump.h ldo.h | |
lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \ | |
lstate.h ltm.h lzio.h lmem.h | |
lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ | |
@@ -177,11 +177,11 @@ ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ | |
lmem.h lstring.h lgc.h ltable.h | |
lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h | |
luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \ | |
- ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h | |
+ ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h ldo.h | |
lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ | |
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h | |
lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ | |
lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h | |
lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ | |
- lzio.h | |
+ lzio.h ldo.h | |
diff --git a/lua-5.2.3/src/lapi.c b/lua-5.2.3/src/lapi.c | |
index d011431..2da4a51 100644 | |
--- a/lua-5.2.3/src/lapi.c | |
+++ b/lua-5.2.3/src/lapi.c | |
@@ -1014,6 +1014,11 @@ LUA_API int lua_status (lua_State *L) { | |
} | |
+LUA_API int lua_threadstatus (lua_State *L) { | |
+ return L->inthread; | |
+} | |
+ | |
+ | |
/* | |
** Garbage-collection function | |
*/ | |
diff --git a/lua-5.2.3/src/lcorolib.c b/lua-5.2.3/src/lcorolib.c | |
index ce4f6ad..b4f5bc8 100644 | |
--- a/lua-5.2.3/src/lcorolib.c | |
+++ b/lua-5.2.3/src/lcorolib.c | |
@@ -64,6 +64,73 @@ static int luaB_coresume (lua_State *L) { | |
} | |
+static int luaB_coasync (lua_State *L) { | |
+ lua_State *co = lua_tothread(L, 1); | |
+ int narg = lua_gettop(L) - 1; | |
+ luaL_argcheck(L, co, 1, "coroutine expected"); | |
+ if (!lua_checkstack(co, narg)) { | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "too many arguments to resume"); | |
+ return 2; | |
+ } | |
+ lua_xmove(L, co, narg); | |
+ switch(lua_async(co, L, narg)) { | |
+ case LUA_OK: | |
+ lua_pushboolean(L, 1); | |
+ return 1; | |
+ case LUA_ERRRUN: | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "could not resume dead coroutine"); | |
+ return 2; | |
+ case LUA_ASYNC: | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "coroutine already running"); | |
+ return 2; | |
+ default: | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "could not create an asynchronous thread"); | |
+ return 2; | |
+ } | |
+} | |
+ | |
+static int luaB_cojoin (lua_State *L) { | |
+ lua_State *co = lua_tothread(L, 1); | |
+ luaL_argcheck(L, co, 1, "coroutine expected"); | |
+ lua_settop(L, 0); | |
+ switch(lua_join(co)) { | |
+ case LUA_OK: case LUA_YIELD: | |
+ { | |
+ int nres = lua_gettop(co); | |
+ if (!lua_checkstack(L, nres + 1)) { | |
+ lua_pop(co, nres); | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "too many results to resume"); | |
+ return 2; | |
+ } | |
+ lua_pushboolean(L, 1); | |
+ lua_xmove(co, L, nres); | |
+ return nres + 1; | |
+ } | |
+ case LUA_ASYNC: | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "coroutine not joinable"); | |
+ return 2; | |
+ case LUA_ERRRUN: | |
+ lua_pushboolean(L, 0); | |
+ lua_xmove(co, L, 1); | |
+ return 2; | |
+ case LUA_NOTHREAD: | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "could not join coroutine"); | |
+ return 2; | |
+ default: | |
+ lua_pushboolean(L, 0); | |
+ lua_pushliteral(L, "moo"); | |
+ return 2; | |
+ } | |
+} | |
+ | |
+ | |
static int luaB_auxwrap (lua_State *L) { | |
lua_State *co = lua_tothread(L, lua_upvalueindex(1)); | |
int r = auxresume(L, co, lua_gettop(L)); | |
@@ -104,6 +171,14 @@ static int luaB_yield (lua_State *L) { | |
static int luaB_costatus (lua_State *L) { | |
lua_State *co = lua_tothread(L, 1); | |
luaL_argcheck(L, co, 1, "coroutine expected"); | |
+ switch(lua_threadstatus(co)) { | |
+ case LUA_ASYNC: | |
+ lua_pushliteral(L, "async"); | |
+ return 1; | |
+ case LUA_JOINABLE: | |
+ lua_pushliteral(L, "joinable"); | |
+ return 1; | |
+ } | |
if (L == co) lua_pushliteral(L, "running"); | |
else { | |
switch (lua_status(co)) { | |
@@ -137,7 +212,9 @@ static int luaB_corunning (lua_State *L) { | |
static const luaL_Reg co_funcs[] = { | |
+ {"async", luaB_coasync}, | |
{"create", luaB_cocreate}, | |
+ {"join", luaB_cojoin}, | |
{"resume", luaB_coresume}, | |
{"running", luaB_corunning}, | |
{"status", luaB_costatus}, | |
diff --git a/lua-5.2.3/src/ldo.c b/lua-5.2.3/src/ldo.c | |
index e9dd5fa..89ddd9c 100644 | |
--- a/lua-5.2.3/src/ldo.c | |
+++ b/lua-5.2.3/src/ldo.c | |
@@ -592,6 +592,107 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { | |
} | |
+#if defined(LUA_USE_PTHREAD) | |
+struct async_context { lua_State *L; lua_State *from; int nargs; }; | |
+ | |
+static void *auxasync(void *p) | |
+{ | |
+ struct async_context *ctx = cast(struct async_context *, p); | |
+ lua_State *L = ctx->L; | |
+ lua_State *from = ctx->from; | |
+ int nargs = ctx->nargs; | |
+ int ret; | |
+ lua_lock(L); | |
+ luaM_free(L, ctx); | |
+ lua_unlock(L); | |
+ ret = lua_resume(L, from, nargs); | |
+ lua_lock(L); | |
+ L->inthread = LUA_JOINABLE; | |
+ L->threadret = ret; | |
+ G(L)->threads--; | |
+ luaD_gilunlock(L); | |
+ return NULL; | |
+} | |
+#endif | |
+ | |
+LUA_API int lua_async (lua_State *L, lua_State *from, int nargs) | |
+{ | |
+#if defined(LUA_USE_PTHREAD) | |
+ struct async_context *ctx; | |
+ lua_lock(L); | |
+ if (L->inthread != LUA_OK) | |
+ { | |
+ lua_unlock(L); | |
+ return LUA_ASYNC; | |
+ } | |
+ if (lua_status(L) == LUA_OK && lua_gettop(L) == 0) { | |
+ lua_unlock(L); | |
+ return LUA_ERRRUN; | |
+ } | |
+ ctx = luaM_new(L, struct async_context); | |
+ ctx->L = L; | |
+ ctx->from = from; | |
+ ctx->nargs = nargs; | |
+ L->inthread = LUA_ASYNC; | |
+ if(!G(L)->threads) | |
+ luaD_gillock(L); | |
+ G(L)->threads++; | |
+ if (pthread_create(&L->thread, NULL, &auxasync, cast(void *, ctx))) | |
+ { | |
+ L->inthread = LUA_OK; | |
+ G(L)->threads--; | |
+ luaD_gilunlock(L); | |
+ return LUA_NOTHREAD; | |
+ } | |
+ lua_unlock(L); | |
+ return LUA_OK; | |
+#else | |
+ return LUA_NOTHREAD; | |
+#endif | |
+} | |
+ | |
+int luaD_join (lua_State *L) | |
+{ | |
+#if defined(LUA_USE_PTHREAD) | |
+ void *dummy; | |
+ int ret = pthread_join(L->thread, &dummy); | |
+ lua_lock(L); | |
+ L->inthread = LUA_OK; | |
+ lua_unlock(L); | |
+ return ret; | |
+#endif | |
+ return 1; | |
+} | |
+ | |
+void luaD_cancel (lua_State *L) | |
+{ | |
+#if defined(LUA_USE_PTHREAD) | |
+ lua_unlock(L); | |
+ pthread_cancel(L->thread); | |
+ luaD_join(L); | |
+ lua_lock(L); | |
+#endif | |
+} | |
+ | |
+LUA_API int lua_join (lua_State *L) | |
+{ | |
+#if defined(LUA_USE_PTHREAD) | |
+ lua_lock(L); | |
+ if(L->inthread == LUA_OK) | |
+ { | |
+ lua_unlock(L); | |
+ return LUA_ASYNC; | |
+ } | |
+ lua_unlock(L); | |
+ if(luaD_join(L)) | |
+ return LUA_NOTHREAD; | |
+ return L->threadret; | |
+#else | |
+ return LUA_NOTHREAD; | |
+#endif | |
+} | |
+ | |
+ | |
int luaD_pcall (lua_State *L, Pfunc func, void *u, | |
ptrdiff_t old_top, ptrdiff_t ef) { | |
int status; | |
@@ -679,3 +780,18 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, | |
} | |
+void luaD_gillock (lua_State *L) | |
+{ | |
+#if defined(LUA_USE_PTHREAD) | |
+ pthread_mutex_lock(&G(L)->mutex); | |
+#endif | |
+} | |
+ | |
+ | |
+void luaD_gilunlock (lua_State *L) | |
+{ | |
+#if defined(LUA_USE_PTHREAD) | |
+ pthread_mutex_unlock(&G(L)->mutex); | |
+ pthread_testcancel(); | |
+#endif | |
+} | |
diff --git a/lua-5.2.3/src/ldo.h b/lua-5.2.3/src/ldo.h | |
index d3d3082..2717595 100644 | |
--- a/lua-5.2.3/src/ldo.h | |
+++ b/lua-5.2.3/src/ldo.h | |
@@ -42,5 +42,10 @@ LUAI_FUNC void luaD_shrinkstack (lua_State *L); | |
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); | |
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); | |
+LUAI_FUNC int luaD_join (lua_State *L); | |
+LUAI_FUNC void luaD_cancel (lua_State *L); | |
+LUAI_FUNC void luaD_gillock (lua_State *L); | |
+LUAI_FUNC void luaD_gilunlock (lua_State *L); | |
+ | |
#endif | |
diff --git a/lua-5.2.3/src/ldump.c b/lua-5.2.3/src/ldump.c | |
index 61fa2cd..b5b7604 100644 | |
--- a/lua-5.2.3/src/ldump.c | |
+++ b/lua-5.2.3/src/ldump.c | |
@@ -14,6 +14,7 @@ | |
#include "lobject.h" | |
#include "lstate.h" | |
#include "lundump.h" | |
+#include "ldo.h" | |
typedef struct { | |
lua_State* L; | |
diff --git a/lua-5.2.3/src/lgc.c b/lua-5.2.3/src/lgc.c | |
index 52460dc..25597fa 100644 | |
--- a/lua-5.2.3/src/lgc.c | |
+++ b/lua-5.2.3/src/lgc.c | |
@@ -305,6 +305,32 @@ static void markmt (global_State *g) { | |
} | |
+static void markasync (global_State *g) { | |
+ if(g->threads) | |
+ { | |
+ GCObject *o; | |
+ for(o = g->allgc; o !=NULL; o = gch(o)->next) | |
+ if(gch(o)->tt == LUA_TTHREAD && gco2th(o)->inthread == LUA_ASYNC) | |
+ markobject(g, o); | |
+ } | |
+} | |
+ | |
+ | |
+static void cancelasync (global_State *g) { | |
+ tryagain: | |
+ if(g->threads) | |
+ { | |
+ GCObject *o; | |
+ for(o = g->allgc; o !=NULL; o = gch(o)->next) | |
+ if(gch(o)->tt == LUA_TTHREAD && gco2th(o)->inthread == LUA_ASYNC) | |
+ { | |
+ luaD_cancel(gco2th(o)); | |
+ goto tryagain; | |
+ } | |
+ } | |
+} | |
+ | |
+ | |
/* | |
** mark all objects in list of being-finalized | |
*/ | |
@@ -338,6 +364,7 @@ static void restartcollection (global_State *g) { | |
g->gray = g->grayagain = NULL; | |
g->weak = g->allweak = g->ephemeron = NULL; | |
markobject(g, g->mainthread); | |
+ markasync(g); | |
markvalue(g, &g->l_registry); | |
markmt(g); | |
markbeingfnz(g); /* mark any finalizing object left from previous cycle */ | |
@@ -986,6 +1013,7 @@ void luaC_freeallobjects (lua_State *L) { | |
separatetobefnz(L, 1); /* separate all objects with finalizers */ | |
lua_assert(g->finobj == NULL); | |
callallpendingfinalizers(L, 0); | |
+ cancelasync(g); | |
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ | |
g->gckind = KGC_NORMAL; | |
sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ | |
@@ -1002,6 +1030,7 @@ static l_mem atomic (lua_State *L) { | |
GCObject *origweak, *origall; | |
lua_assert(!iswhite(obj2gco(g->mainthread))); | |
markobject(g, L); /* mark running thread */ | |
+ markasync(g); | |
/* registry and global metatables may be changed by API */ | |
markvalue(g, &g->l_registry); | |
markmt(g); /* mark basic metatables */ | |
diff --git a/lua-5.2.3/src/llimits.h b/lua-5.2.3/src/llimits.h | |
index 152dd05..aae5e1f 100644 | |
--- a/lua-5.2.3/src/llimits.h | |
+++ b/lua-5.2.3/src/llimits.h | |
@@ -152,9 +152,14 @@ typedef lu_int32 Instruction; | |
#if !defined(lua_lock) | |
+#if defined(LUA_USE_PTHREAD) | |
+#define lua_lock(L) ((void) (G(L)->threads && (luaD_gillock(L), 0))) | |
+#define lua_unlock(L) ((void) (G(L)->threads && (luaD_gilunlock(L), 0))) | |
+#else | |
#define lua_lock(L) ((void) 0) | |
#define lua_unlock(L) ((void) 0) | |
#endif | |
+#endif | |
#if !defined(luai_threadyield) | |
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} | |
diff --git a/lua-5.2.3/src/lstate.c b/lua-5.2.3/src/lstate.c | |
index c7f2672..2636483 100644 | |
--- a/lua-5.2.3/src/lstate.c | |
+++ b/lua-5.2.3/src/lstate.c | |
@@ -217,6 +217,7 @@ static void preinit_state (lua_State *L, global_State *g) { | |
L->nny = 1; | |
L->status = LUA_OK; | |
L->errfunc = 0; | |
+ L->inthread = LUA_OK; | |
} | |
@@ -229,6 +230,9 @@ static void close_state (lua_State *L) { | |
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); | |
luaZ_freebuffer(L, &g->buff); | |
freestack(L); | |
+#if defined(LUA_USE_PTHREAD) | |
+ pthread_mutex_destroy(&g->mutex); | |
+#endif | |
lua_assert(gettotalbytes(g) == sizeof(LG)); | |
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ | |
} | |
@@ -255,6 +259,11 @@ LUA_API lua_State *lua_newthread (lua_State *L) { | |
void luaE_freethread (lua_State *L, lua_State *L1) { | |
LX *l = fromstate(L1); | |
+#if defined(LUA_USE_PTHREAD) | |
+ lua_assert(L1->inthread != LUA_ASYNC); | |
+ if(L1->inthread == LUA_JOINABLE) | |
+ luaD_join(L1); | |
+#endif | |
luaF_close(L1, L1->stack); /* close all upvalues for this thread */ | |
lua_assert(L1->openupval == NULL); | |
luai_userstatefree(L, L1); | |
@@ -310,6 +319,10 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |
close_state(L); | |
L = NULL; | |
} | |
+#if defined(LUA_USE_PTHREAD) | |
+ pthread_mutex_init(&g->mutex, NULL); | |
+ g->threads = 0; | |
+#endif | |
return L; | |
} | |
diff --git a/lua-5.2.3/src/lstate.h b/lua-5.2.3/src/lstate.h | |
index daffd9a..110d406 100644 | |
--- a/lua-5.2.3/src/lstate.h | |
+++ b/lua-5.2.3/src/lstate.h | |
@@ -145,6 +145,10 @@ typedef struct global_State { | |
TString *memerrmsg; /* memory-error message */ | |
TString *tmname[TM_N]; /* array with tag-method names */ | |
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ | |
+ int threads; | |
+#if defined(LUA_USE_PTHREAD) | |
+ pthread_mutex_t mutex; | |
+#endif | |
} global_State; | |
@@ -173,6 +177,11 @@ struct lua_State { | |
struct lua_longjmp *errorJmp; /* current error recover point */ | |
ptrdiff_t errfunc; /* current error handling function (stack index) */ | |
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ | |
+ int inthread; | |
+ int threadret; | |
+#if defined(LUA_USE_PTHREAD) | |
+ pthread_t thread; | |
+#endif | |
}; | |
diff --git a/lua-5.2.3/src/lua.h b/lua-5.2.3/src/lua.h | |
index 149a2c3..a0dc697 100644 | |
--- a/lua-5.2.3/src/lua.h | |
+++ b/lua-5.2.3/src/lua.h | |
@@ -49,6 +49,9 @@ | |
#define LUA_ERRMEM 4 | |
#define LUA_ERRGCMM 5 | |
#define LUA_ERRERR 6 | |
+#define LUA_ASYNC 7 | |
+#define LUA_JOINABLE 8 | |
+#define LUA_NOTHREAD 9 | |
typedef struct lua_State lua_State; | |
@@ -273,6 +276,9 @@ LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, | |
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) | |
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); | |
LUA_API int (lua_status) (lua_State *L); | |
+LUA_API int (lua_async) (lua_State *L, lua_State *from, int narg); | |
+LUA_API int (lua_join) (lua_State *L); | |
+LUA_API int (lua_threadstatus) (lua_State *L); | |
/* | |
** garbage-collection function and options | |
diff --git a/lua-5.2.3/src/luac.c b/lua-5.2.3/src/luac.c | |
index 7409706..ff19ca3 100644 | |
--- a/lua-5.2.3/src/luac.c | |
+++ b/lua-5.2.3/src/luac.c | |
@@ -18,6 +18,7 @@ | |
#include "lobject.h" | |
#include "lstate.h" | |
#include "lundump.h" | |
+#include "ldo.h" | |
static void PrintFunction(const Proto* f, int full); | |
#define luaU_print PrintFunction | |
diff --git a/lua-5.2.3/src/luaconf.h b/lua-5.2.3/src/luaconf.h | |
index 18be9a9..c609a6d 100644 | |
--- a/lua-5.2.3/src/luaconf.h | |
+++ b/lua-5.2.3/src/luaconf.h | |
@@ -47,6 +47,7 @@ | |
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ | |
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ | |
#define LUA_USE_LONGLONG /* assume support for long long */ | |
+#define LUA_USE_PTHREAD | |
#endif | |
#if defined(LUA_USE_MACOSX) | |
@@ -74,6 +75,9 @@ | |
#endif | |
+#if defined(LUA_USE_PTHREAD) | |
+#include <pthread.h> | |
+#endif | |
/* | |
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for | |
diff --git a/lua-5.2.3/src/lvm.c b/lua-5.2.3/src/lvm.c | |
index 141b9fd..f15268e 100644 | |
--- a/lua-5.2.3/src/lvm.c | |
+++ b/lua-5.2.3/src/lvm.c | |
@@ -536,6 +536,7 @@ void luaV_execute (lua_State *L) { | |
LClosure *cl; | |
TValue *k; | |
StkId base; | |
+ int yield = 0; | |
newframe: /* reentry point when frame changes (call/return) */ | |
lua_assert(ci == L->ci); | |
cl = clLvalue(ci->func); | |
@@ -549,6 +550,11 @@ void luaV_execute (lua_State *L) { | |
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { | |
Protect(traceexec(L)); | |
} | |
+ if(!yield--) | |
+ { | |
+ yield = 64; | |
+ luai_threadyield(L); | |
+ } | |
/* WARNING: several calls may realloc the stack and invalidate `ra' */ | |
ra = RA(i); | |
lua_assert(base == ci->u.l.base); | |
diff --git a/lua-5.2.3/src/lzio.c b/lua-5.2.3/src/lzio.c | |
index 20efea9..5c736fe 100644 | |
--- a/lua-5.2.3/src/lzio.c | |
+++ b/lua-5.2.3/src/lzio.c | |
@@ -16,6 +16,7 @@ | |
#include "lmem.h" | |
#include "lstate.h" | |
#include "lzio.h" | |
+#include "ldo.h" | |
int luaZ_fill (ZIO *z) { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment