Skip to content

Instantly share code, notes, and snippets.

@mniip
Created January 2, 2015 06:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mniip/8dab452a3adba3c70fe7 to your computer and use it in GitHub Desktop.
Save mniip/8dab452a3adba3c70fe7 to your computer and use it in GitHub Desktop.
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