mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba64be6f9f | ||
|
|
e1c28ed13e | ||
|
|
474f04e864 | ||
|
|
7c3942cdbd | ||
|
|
88df42a60f | ||
|
|
cada3f5cb0 | ||
|
|
2fc8e86925 | ||
|
|
4c8d42153e | ||
|
|
b5403a6866 | ||
|
|
270ed6e198 | ||
|
|
8900360fab | ||
|
|
b1bb84ddbd | ||
|
|
839570ce3f | ||
|
|
bcf97ecd1b | ||
|
|
4dfdeb146e | ||
|
|
76d73c295f | ||
|
|
c2b391ed42 | ||
|
|
89372a257d | ||
|
|
b519c53fe4 | ||
|
|
027e599037 | ||
|
|
2cfe36a809 | ||
|
|
059fd5cc00 | ||
|
|
64a0ed4bfa | ||
|
|
41928512f0 | ||
|
|
afb50a0587 | ||
|
|
aa20f7642b | ||
|
|
f214c68ff3 | ||
|
|
dc1980dfc8 | ||
|
|
ccd923c44f | ||
|
|
c226ea3f1f | ||
|
|
45b407481d | ||
|
|
8f7e9cc823 | ||
|
|
89a821ced0 | ||
|
|
267e4ad44d | ||
|
|
1a0041982b | ||
|
|
caf513e6c0 | ||
|
|
18a6dc5786 | ||
|
|
22df64244a | ||
|
|
1d47bfa0b6 | ||
|
|
43225367fb | ||
|
|
cde8f75d68 | ||
|
|
9fd43778e2 | ||
|
|
72688f5771 | ||
|
|
3bbb62e673 | ||
|
|
c18f99eb7e | ||
|
|
bd5f12b959 | ||
|
|
267cf5384c | ||
|
|
6f24b08f02 | ||
|
|
d0b11c7955 | ||
|
|
6bdc8b8608 | ||
|
|
b309d82538 | ||
|
|
fb97668f9e | ||
|
|
9e000da81f | ||
|
|
d9c30f9119 | ||
|
|
4030687400 | ||
|
|
1f93f4864f | ||
|
|
e66e892ee5 | ||
|
|
30d967ea05 | ||
|
|
4b0937cc19 | ||
|
|
89b47f9372 | ||
|
|
6249062c2d | ||
|
|
8b5bbaabd9 |
@@ -1,4 +1,4 @@
|
||||
This is a modify version of lua 5.4.3 .
|
||||
This is a modify version of lua 5.4.7 .
|
||||
|
||||
For detail ,
|
||||
Shared Proto : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
|
||||
|
||||
@@ -417,9 +417,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
|
||||
o = index2value(L, idx); /* previous call may reallocate the stack */
|
||||
}
|
||||
if (len != NULL)
|
||||
*len = vslen(o);
|
||||
*len = tsslen(tsvalue(o));
|
||||
lua_unlock(L);
|
||||
return svalue(o);
|
||||
return getstr(tsvalue(o));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
||||
int top = lua_gettop(L);
|
||||
lua_getinfo(L, "f", ar); /* push function */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||
luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */
|
||||
if (findfield(L, top + 1, 2)) {
|
||||
const char *name = lua_tostring(L, -1);
|
||||
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
|
||||
@@ -249,11 +250,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
const char *msg;
|
||||
luaL_pushfail(L);
|
||||
msg = (en != 0) ? strerror(en) : "(no extra info)";
|
||||
if (fname)
|
||||
lua_pushfstring(L, "%s: %s", fname, strerror(en));
|
||||
lua_pushfstring(L, "%s: %s", fname, msg);
|
||||
else
|
||||
lua_pushstring(L, strerror(en));
|
||||
lua_pushstring(L, msg);
|
||||
lua_pushinteger(L, en);
|
||||
return 3;
|
||||
}
|
||||
@@ -732,9 +735,12 @@ static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||
|
||||
|
||||
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
||||
const char *serr = strerror(errno);
|
||||
int err = errno;
|
||||
const char *filename = lua_tostring(L, fnameindex) + 1;
|
||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
||||
if (err != 0)
|
||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err));
|
||||
else
|
||||
lua_pushfstring(L, "cannot %s %s", what, filename);
|
||||
lua_remove(L, fnameindex);
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
@@ -787,6 +793,7 @@ LUALIB_API int luaL_loadfilex_ (lua_State *L, const char *filename,
|
||||
}
|
||||
else {
|
||||
lua_pushfstring(L, "@%s", filename);
|
||||
errno = 0;
|
||||
lf.f = fopen(filename, "r");
|
||||
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
||||
}
|
||||
@@ -796,6 +803,7 @@ LUALIB_API int luaL_loadfilex_ (lua_State *L, const char *filename,
|
||||
if (c == LUA_SIGNATURE[0]) { /* binary file? */
|
||||
lf.n = 0; /* remove possible newline */
|
||||
if (filename) { /* "real" file? */
|
||||
errno = 0;
|
||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||
skipcomment(lf.f, &c); /* re-read initial portion */
|
||||
@@ -803,6 +811,7 @@ LUALIB_API int luaL_loadfilex_ (lua_State *L, const char *filename,
|
||||
}
|
||||
if (c != EOF)
|
||||
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
|
||||
errno = 0;
|
||||
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
|
||||
readstatus = ferror(lf.f);
|
||||
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
||||
@@ -933,7 +942,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
||||
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
||||
luaL_checkstack(L, nup, "too many upvalues");
|
||||
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
||||
if (l->func == NULL) /* place holder? */
|
||||
if (l->func == NULL) /* placeholder? */
|
||||
lua_pushboolean(L, 0);
|
||||
else {
|
||||
int i;
|
||||
@@ -1025,9 +1034,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Standard panic funcion just prints an error message. The test
|
||||
** with 'lua_type' avoids possible memory errors in 'lua_tostring'.
|
||||
*/
|
||||
static int panic (lua_State *L) {
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
if (msg == NULL) msg = "error object is not a string";
|
||||
const char *msg = (lua_type(L, -1) == LUA_TSTRING)
|
||||
? lua_tostring(L, -1)
|
||||
: "error object is not a string";
|
||||
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
||||
msg);
|
||||
return 0; /* return to Lua to abort */
|
||||
@@ -1136,9 +1150,6 @@ init(void) {
|
||||
CC.L = luaL_newstate();
|
||||
}
|
||||
|
||||
|
||||
void luaL_initcodecache(void);
|
||||
|
||||
LUALIB_API void
|
||||
luaL_initcodecache(void) {
|
||||
SPIN_INIT(&CC);
|
||||
@@ -1282,8 +1293,6 @@ cache_clear(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luaopen_cache(lua_State *L);
|
||||
|
||||
LUAMOD_API int luaopen_cache(lua_State *L) {
|
||||
luaL_Reg l[] = {
|
||||
{ "clear", cache_clear },
|
||||
|
||||
@@ -415,7 +415,7 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
|
||||
/*
|
||||
** Format and emit an 'iAsBx' instruction.
|
||||
*/
|
||||
int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
|
||||
static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
|
||||
unsigned int b = bc + OFFSET_sBx;
|
||||
lua_assert(getOpMode(o) == iAsBx);
|
||||
lua_assert(a <= MAXARG_A && b <= MAXARG_Bx);
|
||||
@@ -671,7 +671,7 @@ static int fitsBx (lua_Integer i) {
|
||||
|
||||
void luaK_int (FuncState *fs, int reg, lua_Integer i) {
|
||||
if (fitsBx(i))
|
||||
luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i));
|
||||
codeAsBx(fs, OP_LOADI, reg, cast_int(i));
|
||||
else
|
||||
luaK_codek(fs, reg, luaK_intK(fs, i));
|
||||
}
|
||||
@@ -680,7 +680,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) {
|
||||
static void luaK_float (FuncState *fs, int reg, lua_Number f) {
|
||||
lua_Integer fi;
|
||||
if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi))
|
||||
luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
|
||||
codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
|
||||
else
|
||||
luaK_codek(fs, reg, luaK_numberK(fs, f));
|
||||
}
|
||||
@@ -776,7 +776,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
||||
break;
|
||||
}
|
||||
case VLOCAL: { /* already in a register */
|
||||
e->u.info = e->u.var.ridx;
|
||||
int temp = e->u.var.ridx;
|
||||
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
|
||||
e->k = VNONRELOC; /* becomes a non-relocatable value */
|
||||
break;
|
||||
}
|
||||
@@ -1025,7 +1026,7 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) {
|
||||
** in the range of R/K indices).
|
||||
** Returns 1 iff expression is K.
|
||||
*/
|
||||
int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
||||
static int exp2RK (FuncState *fs, expdesc *e) {
|
||||
if (luaK_exp2K(fs, e))
|
||||
return 1;
|
||||
else { /* not a constant in the right range: put it in a register */
|
||||
@@ -1037,7 +1038,7 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
||||
|
||||
static void codeABRK (FuncState *fs, OpCode o, int a, int b,
|
||||
expdesc *ec) {
|
||||
int k = luaK_exp2RK(fs, ec);
|
||||
int k = exp2RK(fs, ec);
|
||||
luaK_codeABCk(fs, o, a, b, ec->u.info, k);
|
||||
}
|
||||
|
||||
@@ -1215,7 +1216,7 @@ static void codenot (FuncState *fs, expdesc *e) {
|
||||
|
||||
|
||||
/*
|
||||
** Check whether expression 'e' is a small literal string
|
||||
** Check whether expression 'e' is a short literal string
|
||||
*/
|
||||
static int isKstr (FuncState *fs, expdesc *e) {
|
||||
return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B &&
|
||||
@@ -1225,7 +1226,7 @@ static int isKstr (FuncState *fs, expdesc *e) {
|
||||
/*
|
||||
** Check whether expression 'e' is a literal integer.
|
||||
*/
|
||||
int luaK_isKint (expdesc *e) {
|
||||
static int isKint (expdesc *e) {
|
||||
return (e->k == VKINT && !hasjumps(e));
|
||||
}
|
||||
|
||||
@@ -1235,7 +1236,7 @@ int luaK_isKint (expdesc *e) {
|
||||
** proper range to fit in register C
|
||||
*/
|
||||
static int isCint (expdesc *e) {
|
||||
return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C));
|
||||
return isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C));
|
||||
}
|
||||
|
||||
|
||||
@@ -1244,7 +1245,7 @@ static int isCint (expdesc *e) {
|
||||
** proper range to fit in register sC
|
||||
*/
|
||||
static int isSCint (expdesc *e) {
|
||||
return luaK_isKint(e) && fitsC(e->u.ival);
|
||||
return isKint(e) && fitsC(e->u.ival);
|
||||
}
|
||||
|
||||
|
||||
@@ -1283,15 +1284,17 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
||||
if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
|
||||
luaK_exp2anyreg(fs, t); /* put it in a register */
|
||||
if (t->k == VUPVAL) {
|
||||
t->u.ind.t = t->u.info; /* upvalue index */
|
||||
t->u.ind.idx = k->u.info; /* literal string */
|
||||
int temp = t->u.info; /* upvalue index */
|
||||
lua_assert(isKstr(fs, k));
|
||||
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
|
||||
t->u.ind.idx = k->u.info; /* literal short string */
|
||||
t->k = VINDEXUP;
|
||||
}
|
||||
else {
|
||||
/* register index of the table */
|
||||
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
|
||||
if (isKstr(fs, k)) {
|
||||
t->u.ind.idx = k->u.info; /* literal string */
|
||||
t->u.ind.idx = k->u.info; /* literal short string */
|
||||
t->k = VINDEXSTR;
|
||||
}
|
||||
else if (isCint(k)) {
|
||||
@@ -1459,7 +1462,7 @@ static void codebinK (FuncState *fs, BinOpr opr,
|
||||
*/
|
||||
static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2,
|
||||
OpCode op, int line, TMS event) {
|
||||
if (!luaK_isKint(e2))
|
||||
if (!isKint(e2))
|
||||
return 0; /* not an integer constant */
|
||||
else {
|
||||
lua_Integer i2 = e2->u.ival;
|
||||
@@ -1592,7 +1595,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
|
||||
op = OP_EQI;
|
||||
r2 = im; /* immediate operand */
|
||||
}
|
||||
else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
|
||||
else if (exp2RK(fs, e2)) { /* 2nd expression is constant? */
|
||||
op = OP_EQK;
|
||||
r2 = e2->u.info; /* constant index */
|
||||
}
|
||||
@@ -1658,7 +1661,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||
}
|
||||
case OPR_EQ: case OPR_NE: {
|
||||
if (!tonumeral(v, NULL))
|
||||
luaK_exp2RK(fs, v);
|
||||
exp2RK(fs, v);
|
||||
/* else keep numeral, which may be an immediate operand */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -61,10 +61,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
||||
|
||||
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
|
||||
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
||||
LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
|
||||
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
|
||||
int B, int C, int k);
|
||||
LUAI_FUNC int luaK_isKint (expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
||||
@@ -76,7 +74,6 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||
|
||||
218
3rd/lua/ldebug.c
218
3rd/lua/ldebug.c
@@ -31,7 +31,7 @@
|
||||
|
||||
|
||||
|
||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
|
||||
#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
|
||||
|
||||
|
||||
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||
@@ -254,7 +254,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
|
||||
|
||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
if (noLuaClosure(cl)) {
|
||||
if (!LuaClosure(cl)) {
|
||||
ar->source = "=[C]";
|
||||
ar->srclen = LL("=[C]");
|
||||
ar->linedefined = -1;
|
||||
@@ -288,29 +288,31 @@ static int nextline (const Proto *p, int currentline, int pc) {
|
||||
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (noLuaClosure(f)) {
|
||||
if (!LuaClosure(f)) {
|
||||
setnilvalue(s2v(L->top.p));
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
TValue v;
|
||||
const Proto *p = f->l.p;
|
||||
int currentline = p->linedefined;
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue2s(L, L->top.p, t); /* push it on stack */
|
||||
api_incr_top(L);
|
||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||
if (!p->is_vararg) /* regular function? */
|
||||
i = 0; /* consider all instructions */
|
||||
else { /* vararg function */
|
||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||
currentline = nextline(p, currentline, 0);
|
||||
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
||||
}
|
||||
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
||||
currentline = nextline(p, currentline, i); /* get its line */
|
||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||
if (p->lineinfo != NULL) { /* proto with debug information? */
|
||||
int i;
|
||||
TValue v;
|
||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||
if (!p->is_vararg) /* regular function? */
|
||||
i = 0; /* consider all instructions */
|
||||
else { /* vararg function */
|
||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||
currentline = nextline(p, currentline, 0);
|
||||
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
||||
}
|
||||
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
||||
currentline = nextline(p, currentline, i); /* get its line */
|
||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,7 +341,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
}
|
||||
case 'u': {
|
||||
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
||||
if (noLuaClosure(f)) {
|
||||
if (!LuaClosure(f)) {
|
||||
ar->isvararg = 1;
|
||||
ar->nparams = 0;
|
||||
}
|
||||
@@ -417,40 +419,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
const char **name);
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for the constant 'c'.
|
||||
*/
|
||||
static void kname (const Proto *p, int c, const char **name) {
|
||||
TValue *kvalue = &p->k[c];
|
||||
*name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for the register 'c'.
|
||||
*/
|
||||
static void rname (const Proto *p, int pc, int c, const char **name) {
|
||||
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
|
||||
if (!(what && *what == 'c')) /* did not find a constant name? */
|
||||
*name = "?";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for a 'C' value in an RK instruction.
|
||||
*/
|
||||
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
|
||||
int c = GETARG_C(i); /* key index */
|
||||
if (GETARG_k(i)) /* is 'c' a constant? */
|
||||
kname(p, c, name);
|
||||
else /* 'c' is a register */
|
||||
rname(p, pc, c, name);
|
||||
}
|
||||
|
||||
|
||||
static int filterpc (int pc, int jmptarget) {
|
||||
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
||||
@@ -509,28 +477,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) {
|
||||
|
||||
|
||||
/*
|
||||
** Check whether table being indexed by instruction 'i' is the
|
||||
** environment '_ENV'
|
||||
** Find a "name" for the constant 'c'.
|
||||
*/
|
||||
static const char *gxf (const Proto *p, int pc, Instruction i, int isup) {
|
||||
int t = GETARG_B(i); /* table index */
|
||||
const char *name; /* name of indexed variable */
|
||||
if (isup) /* is an upvalue? */
|
||||
name = upvalname(p, t);
|
||||
else
|
||||
getobjname(p, pc, t, &name);
|
||||
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
||||
static const char *kname (const Proto *p, int index, const char **name) {
|
||||
TValue *kvalue = &p->k[index];
|
||||
if (ttisstring(kvalue)) {
|
||||
*name = getstr(tsvalue(kvalue));
|
||||
return "constant";
|
||||
}
|
||||
else {
|
||||
*name = "?";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
const char **name) {
|
||||
int pc;
|
||||
*name = luaF_getlocalname(p, reg + 1, lastpc);
|
||||
static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
|
||||
const char **name) {
|
||||
int pc = *ppc;
|
||||
*name = luaF_getlocalname(p, reg + 1, pc);
|
||||
if (*name) /* is a local? */
|
||||
return "local";
|
||||
/* else try symbolic execution */
|
||||
pc = findsetreg(p, lastpc, reg);
|
||||
*ppc = pc = findsetreg(p, pc, reg);
|
||||
if (pc != -1) { /* could find instruction? */
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
@@ -538,18 +507,80 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
case OP_MOVE: {
|
||||
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
||||
if (b < GETARG_A(i))
|
||||
return getobjname(p, pc, b, name); /* get name for 'b' */
|
||||
return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
|
||||
break;
|
||||
}
|
||||
case OP_GETUPVAL: {
|
||||
*name = upvalname(p, GETARG_B(i));
|
||||
return "upvalue";
|
||||
}
|
||||
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
|
||||
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return NULL; /* could not find reasonable name */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for the register 'c'.
|
||||
*/
|
||||
static void rname (const Proto *p, int pc, int c, const char **name) {
|
||||
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
|
||||
if (!(what && *what == 'c')) /* did not find a constant name? */
|
||||
*name = "?";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for a 'C' value in an RK instruction.
|
||||
*/
|
||||
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
|
||||
int c = GETARG_C(i); /* key index */
|
||||
if (GETARG_k(i)) /* is 'c' a constant? */
|
||||
kname(p, c, name);
|
||||
else /* 'c' is a register */
|
||||
rname(p, pc, c, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether table being indexed by instruction 'i' is the
|
||||
** environment '_ENV'
|
||||
*/
|
||||
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
|
||||
int t = GETARG_B(i); /* table index */
|
||||
const char *name; /* name of indexed variable */
|
||||
if (isup) /* is 't' an upvalue? */
|
||||
name = upvalname(p, t);
|
||||
else /* 't' is a register */
|
||||
basicgetobjname(p, &pc, t, &name);
|
||||
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Extend 'basicgetobjname' to handle table accesses
|
||||
*/
|
||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
const char **name) {
|
||||
const char *kind = basicgetobjname(p, &lastpc, reg, name);
|
||||
if (kind != NULL)
|
||||
return kind;
|
||||
else if (lastpc != -1) { /* could find instruction? */
|
||||
Instruction i = p->code[lastpc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
switch (op) {
|
||||
case OP_GETTABUP: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
kname(p, k, name);
|
||||
return gxf(p, pc, i, 1);
|
||||
return isEnv(p, lastpc, i, 1);
|
||||
}
|
||||
case OP_GETTABLE: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
rname(p, pc, k, name);
|
||||
return gxf(p, pc, i, 0);
|
||||
rname(p, lastpc, k, name);
|
||||
return isEnv(p, lastpc, i, 0);
|
||||
}
|
||||
case OP_GETI: {
|
||||
*name = "integer index";
|
||||
@@ -558,24 +589,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
case OP_GETFIELD: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
kname(p, k, name);
|
||||
return gxf(p, pc, i, 0);
|
||||
}
|
||||
case OP_GETUPVAL: {
|
||||
*name = upvalname(p, GETARG_B(i));
|
||||
return "upvalue";
|
||||
}
|
||||
case OP_LOADK:
|
||||
case OP_LOADKX: {
|
||||
int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
||||
: GETARG_Ax(p->code[pc + 1]);
|
||||
if (ttisstring(&p->k[b])) {
|
||||
*name = svalue(&p->k[b]);
|
||||
return "constant";
|
||||
}
|
||||
break;
|
||||
return isEnv(p, lastpc, i, 0);
|
||||
}
|
||||
case OP_SELF: {
|
||||
rkname(p, pc, i, name);
|
||||
rkname(p, lastpc, i, name);
|
||||
return "method";
|
||||
}
|
||||
default: break; /* go through to return NULL */
|
||||
@@ -627,7 +644,7 @@ static const char *funcnamefromcode (lua_State *L, const Proto *p,
|
||||
default:
|
||||
return NULL; /* cannot find a reasonable name */
|
||||
}
|
||||
*name = getstr(G(L)->tmname[tm]) + 2;
|
||||
*name = getshrstr(G(L)->tmname[tm]) + 2;
|
||||
return "metamethod";
|
||||
}
|
||||
|
||||
@@ -865,6 +882,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traces Lua calls. If code is running the first instruction of a function,
|
||||
** and function is not vararg, and it is not coming from an yield,
|
||||
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
|
||||
** after adjusting its variable arguments; otherwise, they could call
|
||||
** a line/count hook before the call hook. Functions coming from
|
||||
** an yield already called 'luaD_hookcall' before yielding.)
|
||||
*/
|
||||
int luaG_tracecall (lua_State *L) {
|
||||
CallInfo *ci = L->ci;
|
||||
Proto *p = ci_func(ci)->p;
|
||||
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
||||
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
||||
if (p->is_vararg)
|
||||
return 0; /* hooks will start at VARARGPREP instruction */
|
||||
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */
|
||||
luaD_hookcall(L, ci); /* check 'call' hook */
|
||||
}
|
||||
return 1; /* keep 'trap' on */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traces the execution of a Lua function. Called before the execution
|
||||
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
||||
@@ -888,12 +927,12 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||
}
|
||||
pc++; /* reference is always next instruction */
|
||||
ci->u.l.savedpc = pc; /* save 'pc' */
|
||||
counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
|
||||
counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
|
||||
if (counthook)
|
||||
resethookcount(L); /* reset count */
|
||||
else if (!(mask & LUA_MASKLINE))
|
||||
return 1; /* no line hook and count != 0; nothing to be done now */
|
||||
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
|
||||
if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
|
||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
||||
}
|
||||
@@ -915,7 +954,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||
if (counthook)
|
||||
L->hookcount = 1; /* undo decrement to zero */
|
||||
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
|
||||
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
||||
TString *src, int line);
|
||||
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
||||
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
|
||||
LUAI_FUNC int luaG_tracecall (lua_State *L);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -409,7 +409,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
||||
** stack, below original 'func', so that 'luaD_precall' can call it. Raise
|
||||
** an error if there is no '__call' metafield.
|
||||
*/
|
||||
StkId luaD_tryfuncTM (lua_State *L, StkId func) {
|
||||
static StkId tryfuncTM (lua_State *L, StkId func) {
|
||||
const TValue *tm;
|
||||
StkId p;
|
||||
checkstackGCp(L, 1, func); /* space for metamethod */
|
||||
@@ -568,7 +568,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||
return -1;
|
||||
}
|
||||
default: { /* not a function */
|
||||
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
func = tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
|
||||
narg1++;
|
||||
goto retry; /* try again */
|
||||
@@ -609,7 +609,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
return ci;
|
||||
}
|
||||
default: { /* not a function */
|
||||
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
func = tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
/* return luaD_precall(L, func, nresults); */
|
||||
goto retry; /* try again with metamethod */
|
||||
}
|
||||
@@ -792,6 +792,10 @@ static void resume (lua_State *L, void *ud) {
|
||||
lua_assert(L->status == LUA_YIELD);
|
||||
L->status = LUA_OK; /* mark that it is running (again) */
|
||||
if (isLua(ci)) { /* yielded inside a hook? */
|
||||
/* undo increment made by 'luaG_traceexec': instruction was not
|
||||
executed yet */
|
||||
lua_assert(ci->callstatus & CIST_HOOKYIELD);
|
||||
ci->u.l.savedpc--;
|
||||
L->top.p = firstArg; /* discard arguments */
|
||||
luaV_execute(L, ci); /* just continue running Lua code */
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
|
||||
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
|
||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||
|
||||
@@ -542,10 +542,12 @@ static void traversestrongtable (global_State *g, Table *h) {
|
||||
static lu_mem traversetable (global_State *g, Table *h) {
|
||||
const char *weakkey, *weakvalue;
|
||||
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
|
||||
TString *smode;
|
||||
markobjectN(g, h->metatable);
|
||||
if (mode && ttisstring(mode) && /* is there a weak mode? */
|
||||
(cast_void(weakkey = strchr(svalue(mode), 'k')),
|
||||
cast_void(weakvalue = strchr(svalue(mode), 'v')),
|
||||
if (mode && ttisshrstring(mode) && /* is there a weak mode? */
|
||||
(cast_void(smode = tsvalue(mode)),
|
||||
cast_void(weakkey = strchr(getshrstr(smode), 'k')),
|
||||
cast_void(weakvalue = strchr(getshrstr(smode), 'v')),
|
||||
(weakkey || weakvalue))) { /* is really weak? */
|
||||
if (!weakkey) /* strong keys? */
|
||||
traverseweakvalue(g, h);
|
||||
@@ -638,7 +640,9 @@ static int traversethread (global_State *g, lua_State *th) {
|
||||
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
|
||||
markobject(g, uv); /* open upvalues cannot be collected */
|
||||
if (g->gcstate == GCSatomic) { /* final traversal? */
|
||||
for (; o < th->stack_last.p + EXTRA_STACK; o++)
|
||||
if (!g->gcemergency)
|
||||
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
|
||||
for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++)
|
||||
setnilvalue(s2v(o)); /* clear dead stack slice */
|
||||
/* 'remarkupvals' may have removed thread from 'twups' list */
|
||||
if (!isintwups(th) && th->openupval != NULL) {
|
||||
@@ -646,8 +650,6 @@ static int traversethread (global_State *g, lua_State *th) {
|
||||
g->twups = th;
|
||||
}
|
||||
}
|
||||
else if (!g->gcemergency)
|
||||
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
|
||||
return 1 + stacksize(th);
|
||||
}
|
||||
|
||||
@@ -1415,7 +1417,7 @@ static void stepgenfull (lua_State *L, global_State *g) {
|
||||
setminordebt(g);
|
||||
}
|
||||
else { /* another bad collection; stay in incremental mode */
|
||||
g->GCestimate = gettotalbytes(g); /* first estimate */;
|
||||
g->GCestimate = gettotalbytes(g); /* first estimate */
|
||||
entersweep(L);
|
||||
luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
|
||||
setpause(g);
|
||||
@@ -1610,7 +1612,7 @@ static lu_mem singlestep (lua_State *L) {
|
||||
case GCSenteratomic: {
|
||||
work = atomic(L); /* work is what was traversed by 'atomic' */
|
||||
entersweep(L);
|
||||
g->GCestimate = gettotalbytes(g); /* first estimate */;
|
||||
g->GCestimate = gettotalbytes(g); /* first estimate */
|
||||
break;
|
||||
}
|
||||
case GCSswpallgc: { /* sweep "regular" objects */
|
||||
@@ -1716,6 +1718,8 @@ static void fullinc (lua_State *L, global_State *g) {
|
||||
entersweep(L); /* sweep everything to turn them back to white */
|
||||
/* finish any pending sweep phase to start a new cycle */
|
||||
luaC_runtilstate(L, bitmask(GCSpause));
|
||||
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
|
||||
g->gcstate = GCSenteratomic; /* go straight to atomic phase */
|
||||
luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
|
||||
/* estimate must be correct after a full GC cycle */
|
||||
lua_assert(g->GCestimate == gettotalbytes(g));
|
||||
|
||||
@@ -245,8 +245,8 @@ static int f_gc (lua_State *L) {
|
||||
*/
|
||||
static int io_fclose (lua_State *L) {
|
||||
LStream *p = tolstream(L);
|
||||
int res = fclose(p->f);
|
||||
return luaL_fileresult(L, (res == 0), NULL);
|
||||
errno = 0;
|
||||
return luaL_fileresult(L, (fclose(p->f) == 0), NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -272,6 +272,7 @@ static int io_open (lua_State *L) {
|
||||
LStream *p = newfile(L);
|
||||
const char *md = mode; /* to traverse/check mode */
|
||||
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
|
||||
errno = 0;
|
||||
p->f = fopen(filename, mode);
|
||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||
}
|
||||
@@ -292,6 +293,7 @@ static int io_popen (lua_State *L) {
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
LStream *p = newprefile(L);
|
||||
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
|
||||
errno = 0;
|
||||
p->f = l_popen(L, filename, mode);
|
||||
p->closef = &io_pclose;
|
||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||
@@ -300,6 +302,7 @@ static int io_popen (lua_State *L) {
|
||||
|
||||
static int io_tmpfile (lua_State *L) {
|
||||
LStream *p = newfile(L);
|
||||
errno = 0;
|
||||
p->f = tmpfile();
|
||||
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
|
||||
}
|
||||
@@ -567,6 +570,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
|
||||
int nargs = lua_gettop(L) - 1;
|
||||
int n, success;
|
||||
clearerr(f);
|
||||
errno = 0;
|
||||
if (nargs == 0) { /* no arguments? */
|
||||
success = read_line(L, f, 1);
|
||||
n = first + 1; /* to return 1 result */
|
||||
@@ -660,6 +664,7 @@ static int io_readline (lua_State *L) {
|
||||
static int g_write (lua_State *L, FILE *f, int arg) {
|
||||
int nargs = lua_gettop(L) - arg;
|
||||
int status = 1;
|
||||
errno = 0;
|
||||
for (; nargs--; arg++) {
|
||||
if (lua_type(L, arg) == LUA_TNUMBER) {
|
||||
/* optimization: could be done exactly as for strings */
|
||||
@@ -678,7 +683,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
|
||||
}
|
||||
if (l_likely(status))
|
||||
return 1; /* file handle already on stack top */
|
||||
else return luaL_fileresult(L, status, NULL);
|
||||
else
|
||||
return luaL_fileresult(L, status, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -703,6 +709,7 @@ static int f_seek (lua_State *L) {
|
||||
l_seeknum offset = (l_seeknum)p3;
|
||||
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
||||
"not an integer in proper range");
|
||||
errno = 0;
|
||||
op = l_fseek(f, offset, mode[op]);
|
||||
if (l_unlikely(op))
|
||||
return luaL_fileresult(L, 0, NULL); /* error */
|
||||
@@ -719,19 +726,25 @@ static int f_setvbuf (lua_State *L) {
|
||||
FILE *f = tofile(L);
|
||||
int op = luaL_checkoption(L, 2, NULL, modenames);
|
||||
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
|
||||
int res = setvbuf(f, NULL, mode[op], (size_t)sz);
|
||||
int res;
|
||||
errno = 0;
|
||||
res = setvbuf(f, NULL, mode[op], (size_t)sz);
|
||||
return luaL_fileresult(L, res == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int io_flush (lua_State *L) {
|
||||
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
|
||||
FILE *f = getiofile(L, IO_OUTPUT);
|
||||
errno = 0;
|
||||
return luaL_fileresult(L, fflush(f) == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int f_flush (lua_State *L) {
|
||||
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
|
||||
FILE *f = tofile(L);
|
||||
errno = 0;
|
||||
return luaL_fileresult(L, fflush(f) == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -773,7 +786,7 @@ static const luaL_Reg meth[] = {
|
||||
** metamethods for file handles
|
||||
*/
|
||||
static const luaL_Reg metameth[] = {
|
||||
{"__index", NULL}, /* place holder */
|
||||
{"__index", NULL}, /* placeholder */
|
||||
{"__gc", f_gc},
|
||||
{"__close", f_gc},
|
||||
{"__tostring", f_tostring},
|
||||
|
||||
@@ -249,6 +249,15 @@ static int math_type (lua_State *L) {
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** This code uses lots of shifts. ANSI C does not allow shifts greater
|
||||
** than or equal to the width of the type being shifted, so some shifts
|
||||
** are written in convoluted ways to match that restriction. For
|
||||
** preprocessor tests, it assumes a width of 32 bits, so the maximum
|
||||
** shift there is 31 bits.
|
||||
*/
|
||||
|
||||
|
||||
/* number of binary digits in the mantissa of a float */
|
||||
#define FIGS l_floatatt(MANT_DIG)
|
||||
|
||||
@@ -271,16 +280,19 @@ static int math_type (lua_State *L) {
|
||||
|
||||
/* 'long' has at least 64 bits */
|
||||
#define Rand64 unsigned long
|
||||
#define SRand64 long
|
||||
|
||||
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
|
||||
|
||||
/* there is a 'long long' type (which must have at least 64 bits) */
|
||||
#define Rand64 unsigned long long
|
||||
#define SRand64 long long
|
||||
|
||||
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
|
||||
|
||||
/* 'lua_Unsigned' has at least 64 bits */
|
||||
#define Rand64 lua_Unsigned
|
||||
#define SRand64 lua_Integer
|
||||
|
||||
#endif
|
||||
|
||||
@@ -319,23 +331,30 @@ static Rand64 nextrand (Rand64 *state) {
|
||||
}
|
||||
|
||||
|
||||
/* must take care to not shift stuff by more than 63 slots */
|
||||
|
||||
|
||||
/*
|
||||
** Convert bits from a random integer into a float in the
|
||||
** interval [0,1), getting the higher FIG bits from the
|
||||
** random unsigned integer and converting that to a float.
|
||||
** Some old Microsoft compilers cannot cast an unsigned long
|
||||
** to a floating-point number, so we use a signed long as an
|
||||
** intermediary. When lua_Number is float or double, the shift ensures
|
||||
** that 'sx' is non negative; in that case, a good compiler will remove
|
||||
** the correction.
|
||||
*/
|
||||
|
||||
/* must throw out the extra (64 - FIGS) bits */
|
||||
#define shift64_FIG (64 - FIGS)
|
||||
|
||||
/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
|
||||
/* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */
|
||||
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
|
||||
|
||||
static lua_Number I2d (Rand64 x) {
|
||||
return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG;
|
||||
SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
|
||||
lua_Number res = (lua_Number)(sx) * scaleFIG;
|
||||
if (sx < 0)
|
||||
res += l_mathop(1.0); /* correct the two's complement if negative */
|
||||
lua_assert(0 <= res && res < 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
||||
@@ -471,8 +490,6 @@ static lua_Number I2d (Rand64 x) {
|
||||
|
||||
#else /* 32 < FIGS <= 64 */
|
||||
|
||||
/* must take care to not shift stuff by more than 31 slots */
|
||||
|
||||
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
|
||||
#define scaleFIG \
|
||||
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
|
||||
|
||||
@@ -24,15 +24,6 @@
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
/*
|
||||
** LUA_IGMARK is a mark to ignore all before it when building the
|
||||
** luaopen_ function name.
|
||||
*/
|
||||
#if !defined (LUA_IGMARK)
|
||||
#define LUA_IGMARK "-"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** LUA_CSUBSEP is the character that replaces dots in submodule names
|
||||
** when searching for a C loader.
|
||||
|
||||
@@ -542,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
||||
clearbuff(&buff); /* empty buffer into the stack */
|
||||
lua_assert(buff.pushed == 1);
|
||||
return svalue(s2v(L->top.p - 1));
|
||||
return getstr(tsvalue(s2v(L->top.p - 1)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -386,7 +386,7 @@ typedef struct GCObject {
|
||||
typedef struct TString {
|
||||
CommonHeader;
|
||||
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
||||
lu_byte shrlen; /* length for short strings */
|
||||
lu_byte shrlen; /* length for short strings, 0xFF for long strings */
|
||||
unsigned int hash;
|
||||
size_t id; /* id for short strings */
|
||||
union {
|
||||
@@ -399,19 +399,17 @@ typedef struct TString {
|
||||
|
||||
|
||||
/*
|
||||
** Get the actual string (array of bytes) from a 'TString'.
|
||||
** Get the actual string (array of bytes) from a 'TString'. (Generic
|
||||
** version and specialized versions for long and short strings.)
|
||||
*/
|
||||
#define getstr(ts) ((ts)->contents)
|
||||
#define getstr(ts) ((ts)->contents)
|
||||
#define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents)
|
||||
#define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents)
|
||||
|
||||
|
||||
/* get the actual string (array of bytes) from a Lua value */
|
||||
#define svalue(o) getstr(tsvalue(o))
|
||||
|
||||
/* get string length from 'TString *s' */
|
||||
#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)
|
||||
|
||||
/* get string length from 'TValue *o' */
|
||||
#define vslen(o) tsslen(tsvalue(o))
|
||||
#define tsslen(s) \
|
||||
((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen)
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
@@ -210,15 +210,15 @@ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
||||
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
|
||||
|
||||
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */
|
||||
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */
|
||||
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
|
||||
OP_GETI,/* A B C R[A] := R[B][C] */
|
||||
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */
|
||||
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */
|
||||
|
||||
OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */
|
||||
OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */
|
||||
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
|
||||
OP_SETI,/* A B C R[A][B] := RK(C) */
|
||||
OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */
|
||||
OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */
|
||||
|
||||
OP_NEWTABLE,/* A B C k R[A] := {} */
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ static int os_execute (lua_State *L) {
|
||||
|
||||
static int os_remove (lua_State *L) {
|
||||
const char *filename = luaL_checkstring(L, 1);
|
||||
errno = 0;
|
||||
return luaL_fileresult(L, remove(filename) == 0, filename);
|
||||
}
|
||||
|
||||
@@ -162,6 +163,7 @@ static int os_remove (lua_State *L) {
|
||||
static int os_rename (lua_State *L) {
|
||||
const char *fromname = luaL_checkstring(L, 1);
|
||||
const char *toname = luaL_checkstring(L, 2);
|
||||
errno = 0;
|
||||
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1022,10 +1022,11 @@ static int explist (LexState *ls, expdesc *v) {
|
||||
}
|
||||
|
||||
|
||||
static void funcargs (LexState *ls, expdesc *f, int line) {
|
||||
static void funcargs (LexState *ls, expdesc *f) {
|
||||
FuncState *fs = ls->fs;
|
||||
expdesc args;
|
||||
int base, nparams;
|
||||
int line = ls->linenumber;
|
||||
switch (ls->t.token) {
|
||||
case '(': { /* funcargs -> '(' [ explist ] ')' */
|
||||
luaX_next(ls);
|
||||
@@ -1063,8 +1064,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
|
||||
}
|
||||
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
|
||||
luaK_fixline(fs, line);
|
||||
fs->freereg = base+1; /* call remove function and arguments and leaves
|
||||
(unless changed) one result */
|
||||
fs->freereg = base+1; /* call removes function and arguments and leaves
|
||||
one result (unless changed later) */
|
||||
}
|
||||
|
||||
|
||||
@@ -1103,7 +1104,6 @@ static void suffixedexp (LexState *ls, expdesc *v) {
|
||||
/* suffixedexp ->
|
||||
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
|
||||
FuncState *fs = ls->fs;
|
||||
int line = ls->linenumber;
|
||||
primaryexp(ls, v);
|
||||
for (;;) {
|
||||
switch (ls->t.token) {
|
||||
@@ -1123,12 +1123,12 @@ static void suffixedexp (LexState *ls, expdesc *v) {
|
||||
luaX_next(ls);
|
||||
codename(ls, &key);
|
||||
luaK_self(fs, v, &key);
|
||||
funcargs(ls, v, line);
|
||||
funcargs(ls, v);
|
||||
break;
|
||||
}
|
||||
case '(': case TK_STRING: case '{': { /* funcargs */
|
||||
luaK_exp2nextreg(fs, v);
|
||||
funcargs(ls, v, line);
|
||||
funcargs(ls, v);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
|
||||
@@ -119,7 +119,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
|
||||
/*
|
||||
** free all CallInfo structures not in use by a thread
|
||||
*/
|
||||
void luaE_freeCI (lua_State *L) {
|
||||
static void freeCI (lua_State *L) {
|
||||
CallInfo *ci = L->ci;
|
||||
CallInfo *next = ci->next;
|
||||
ci->next = NULL;
|
||||
@@ -204,7 +204,7 @@ static void freestack (lua_State *L) {
|
||||
if (L->stack.p == NULL)
|
||||
return; /* stack not completely built yet */
|
||||
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
||||
luaE_freeCI(L);
|
||||
freeCI(L);
|
||||
lua_assert(L->nci == 0);
|
||||
luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
|
||||
}
|
||||
@@ -432,7 +432,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
|
||||
void luaE_warnerror (lua_State *L, const char *where) {
|
||||
TValue *errobj = s2v(L->top.p - 1); /* error object */
|
||||
const char *msg = (ttisstring(errobj))
|
||||
? svalue(errobj)
|
||||
? getstr(tsvalue(errobj))
|
||||
: "error object is not a string";
|
||||
/* produce warning "error in %s (%s)" (where, msg) */
|
||||
luaE_warning(L, "error in ", 1);
|
||||
|
||||
@@ -181,7 +181,7 @@ struct CallInfo {
|
||||
union {
|
||||
struct { /* only for Lua functions */
|
||||
const Instruction *savedpc;
|
||||
volatile l_signalT trap;
|
||||
volatile l_signalT trap; /* function is tracing lines/counts */
|
||||
int nextraargs; /* # of extra arguments in vararg functions */
|
||||
} l;
|
||||
struct { /* only for C functions */
|
||||
@@ -395,7 +395,6 @@ union GCUnion {
|
||||
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
||||
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
||||
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
||||
|
||||
@@ -39,14 +39,13 @@ int luaS_eqlngstr (TString *a, TString *b) {
|
||||
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
|
||||
return (a == b) || /* same instance or... */
|
||||
((len == b->u.lnglen) && /* equal length and ... */
|
||||
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
|
||||
(memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */
|
||||
}
|
||||
|
||||
int luaS_eqshrstr (TString *a, TString *b) {
|
||||
int r;
|
||||
lu_byte len = a->shrlen;
|
||||
lua_assert(b->tt == LUA_VSHRSTR);
|
||||
r = len == b->shrlen && (memcmp(getstr(a), getstr(b), len) == 0);
|
||||
r = len == b->shrlen && (memcmp(getshrstr(a), getshrstr(b), len) == 0);
|
||||
if (r) {
|
||||
if (a->id < b->id) {
|
||||
a->id = b->id;
|
||||
@@ -76,7 +75,7 @@ unsigned int luaS_hashlongstr (TString *ts) {
|
||||
lua_assert(ts->tt == LUA_VLNGSTR);
|
||||
if (ts->extra == 0) { /* no hash? */
|
||||
size_t len = ts->u.lnglen;
|
||||
ts->hash = luaS_hash(getstr(ts), len, ts->hash);
|
||||
ts->hash = luaS_hash(getlngstr(ts), len, ts->hash);
|
||||
ts->extra = 1; /* now it has its hash */
|
||||
}
|
||||
return ts->hash;
|
||||
@@ -201,6 +200,7 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
|
||||
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
|
||||
TString *ts = createstrobj(L, l, LUA_VLNGSTR, STRSEED);
|
||||
ts->u.lnglen = l;
|
||||
ts->shrlen = 0xFF; /* signals that it is a long string */
|
||||
return ts;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
||||
TString **list = &tb->hash[lmod(h, tb->size)];
|
||||
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
||||
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
||||
if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
|
||||
if (l == ts->shrlen && (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) {
|
||||
/* found! */
|
||||
if (isdead(g, ts)) /* dead (but not collected yet)? */
|
||||
changewhite(ts); /* resurrect it */
|
||||
@@ -250,8 +250,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
||||
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
|
||||
}
|
||||
ts = createstrobj(L, l, LUA_VSHRSTR, h);
|
||||
memcpy(getstr(ts), str, l * sizeof(char));
|
||||
ts->shrlen = cast_byte(l);
|
||||
memcpy(getshrstr(ts), str, l * sizeof(char));
|
||||
ts->u.hnext = *list;
|
||||
*list = ts;
|
||||
tb->nuse++;
|
||||
@@ -267,10 +267,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
||||
return internshrstr(L, str, l);
|
||||
else {
|
||||
TString *ts;
|
||||
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
|
||||
if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString))))
|
||||
luaM_toobig(L);
|
||||
ts = luaS_createlngstrobj(L, l);
|
||||
memcpy(getstr(ts), str, l * sizeof(char));
|
||||
memcpy(getlngstr(ts), str, l * sizeof(char));
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
|
||||
return t->alimit; /* this is the size */
|
||||
else {
|
||||
unsigned int size = t->alimit;
|
||||
/* compute the smallest power of 2 not smaller than 'n' */
|
||||
/* compute the smallest power of 2 not smaller than 'size' */
|
||||
size |= (size >> 1);
|
||||
size |= (size >> 2);
|
||||
size |= (size >> 4);
|
||||
@@ -664,7 +664,8 @@ static Node *getfreepos (Table *t) {
|
||||
** put new key in its main position; otherwise (colliding node is in its main
|
||||
** position), new key goes to an empty position.
|
||||
*/
|
||||
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
||||
static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
||||
TValue *value) {
|
||||
Node *mp;
|
||||
TValue aux;
|
||||
if (l_unlikely(isshared(t)))
|
||||
@@ -725,22 +726,36 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
||||
|
||||
/*
|
||||
** Search function for integers. If integer is inside 'alimit', get it
|
||||
** directly from the array part. Otherwise, if 'alimit' is not equal to
|
||||
** the real size of the array, key still can be in the array part. In
|
||||
** this case, try to avoid a call to 'luaH_realasize' when key is just
|
||||
** one more than the limit (so that it can be incremented without
|
||||
** changing the real size of the array).
|
||||
** directly from the array part. Otherwise, if 'alimit' is not
|
||||
** the real size of the array, the key still can be in the array part.
|
||||
** In this case, do the "Xmilia trick" to check whether 'key-1' is
|
||||
** smaller than the real size.
|
||||
** The trick works as follow: let 'p' be an integer such that
|
||||
** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'.
|
||||
** That is, 2^(p+1) is the real size of the array, and 'p' is the highest
|
||||
** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'.
|
||||
** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will
|
||||
** have the 'p' bit cleared. If the key is outside the array, that is,
|
||||
** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p',
|
||||
** therefore it will be larger or equal to 'alimit', and the check
|
||||
** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than
|
||||
** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller
|
||||
** than 2^p, therefore smaller than 'alimit', and the check succeeds.
|
||||
** As special cases, when 'alimit' is 0 the condition is trivially false,
|
||||
** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'.
|
||||
** If key is 0 or negative, 'res' will have its higher bit on, so that
|
||||
** if cannot be smaller than alimit.
|
||||
*/
|
||||
const TValue *luaH_getint (Table *t, lua_Integer key) {
|
||||
if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */
|
||||
lua_Unsigned alimit = t->alimit;
|
||||
if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */
|
||||
return &t->array[key - 1];
|
||||
else if (!limitequalsasize(t) && /* key still may be in the array part? */
|
||||
(l_castS2U(key) == t->alimit + 1 ||
|
||||
l_castS2U(key) - 1u < luaH_realasize(t))) {
|
||||
else if (!isrealasize(t) && /* key still may be in the array part? */
|
||||
(((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) {
|
||||
t->alimit = cast_uint(key); /* probably '#t' is here now */
|
||||
return &t->array[key - 1];
|
||||
}
|
||||
else {
|
||||
else { /* key is not in the array part; check the hash */
|
||||
Node *n = hashint(t, key);
|
||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
||||
if (keyisinteger(n) && keyival(n) == key)
|
||||
|
||||
@@ -41,8 +41,6 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
||||
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
|
||||
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
|
||||
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
|
||||
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
||||
TValue *value);
|
||||
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
|
||||
TValue *value);
|
||||
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
||||
|
||||
@@ -73,8 +73,9 @@ static void badexit (const char *fmt, const char *s1, const char *s2) {
|
||||
|
||||
|
||||
static int tpanic (lua_State *L) {
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
if (msg == NULL) msg = "error object is not a string";
|
||||
const char *msg = (lua_type(L, -1) == LUA_TSTRING)
|
||||
? lua_tostring(L, -1)
|
||||
: "error object is not a string";
|
||||
return (badexit("PANIC: unprotected error in call to Lua API (%s)\n",
|
||||
msg, NULL),
|
||||
0); /* do not return to Lua */
|
||||
@@ -1533,7 +1534,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
||||
lua_newthread(L1);
|
||||
}
|
||||
else if EQ("resetthread") {
|
||||
lua_pushinteger(L1, lua_resetthread(L1, L));
|
||||
lua_pushinteger(L1, lua_resetthread(L1)); /* deprecated */
|
||||
}
|
||||
else if EQ("newuserdata") {
|
||||
lua_newuserdata(L1, getnum);
|
||||
@@ -1649,6 +1650,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
||||
int nres;
|
||||
status = lua_resume(lua_tothread(L1, i), L, getnum, &nres);
|
||||
}
|
||||
else if EQ("traceback") {
|
||||
const char *msg = getstring;
|
||||
int level = getnum;
|
||||
luaL_traceback(L1, L1, msg, level);
|
||||
}
|
||||
else if EQ("return") {
|
||||
int n = getnum;
|
||||
if (L1 != L) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -96,8 +95,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||
int inv, int isfloat, TMS event);
|
||||
|
||||
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
|
||||
CallInfo *ci, const Proto *p);
|
||||
LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
|
||||
struct CallInfo *ci, const Proto *p);
|
||||
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
|
||||
StkId where, int wanted);
|
||||
|
||||
|
||||
|
||||
@@ -115,12 +115,13 @@ static void l_message (const char *pname, const char *msg) {
|
||||
|
||||
/*
|
||||
** Check whether 'status' is not OK and, if so, prints the error
|
||||
** message on the top of the stack. It assumes that the error object
|
||||
** is a string, as it was either generated by Lua or by 'msghandler'.
|
||||
** message on the top of the stack.
|
||||
*/
|
||||
static int report (lua_State *L, int status) {
|
||||
if (status != LUA_OK) {
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
if (msg == NULL)
|
||||
msg = "(error message not a string)";
|
||||
l_message(progname, msg);
|
||||
lua_pop(L, 1); /* remove message */
|
||||
}
|
||||
@@ -210,12 +211,17 @@ static int dostring (lua_State *L, const char *s, const char *name) {
|
||||
|
||||
/*
|
||||
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
|
||||
** If there is no explicit modname and globname contains a '-', cut
|
||||
** the suffix after '-' (the "version") to make the global name.
|
||||
*/
|
||||
static int dolibrary (lua_State *L, char *globname) {
|
||||
int status;
|
||||
char *suffix = NULL;
|
||||
char *modname = strchr(globname, '=');
|
||||
if (modname == NULL) /* no explicit name? */
|
||||
if (modname == NULL) { /* no explicit name? */
|
||||
modname = globname; /* module name is equal to global name */
|
||||
suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */
|
||||
}
|
||||
else {
|
||||
*modname = '\0'; /* global name ends here */
|
||||
modname++; /* module name starts after the '=' */
|
||||
@@ -223,8 +229,11 @@ static int dolibrary (lua_State *L, char *globname) {
|
||||
lua_getglobal(L, "require");
|
||||
lua_pushstring(L, modname);
|
||||
status = docall(L, 1, 1); /* call 'require(modname)' */
|
||||
if (status == LUA_OK)
|
||||
if (status == LUA_OK) {
|
||||
if (suffix != NULL) /* is there a suffix mark? */
|
||||
*suffix = '\0'; /* remove suffix from global name */
|
||||
lua_setglobal(L, globname); /* globname = require(modname) */
|
||||
}
|
||||
return report(L, status);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
#define LUA_VERSION_MAJOR "5"
|
||||
#define LUA_VERSION_MINOR "4"
|
||||
#define LUA_VERSION_RELEASE "6"
|
||||
#define LUA_VERSION_RELEASE "7"
|
||||
|
||||
#define LUA_VERSION_NUM 504
|
||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
|
||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 7)
|
||||
|
||||
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2024 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||
|
||||
|
||||
@@ -501,7 +501,7 @@ struct lua_Debug {
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
|
||||
* Copyright (C) 1994-2024 Lua.org, PUC-Rio.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -257,6 +257,15 @@
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** LUA_IGMARK is a mark to ignore all after it when building the
|
||||
** module name (e.g., used to build the luaopen_ function name).
|
||||
** Typically, the suffix after the mark is the module version,
|
||||
** as in "mod-v1.2.so".
|
||||
*/
|
||||
#define LUA_IGMARK "-"
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ static size_t loadUnsigned (LoadState *S, size_t limit) {
|
||||
|
||||
|
||||
static size_t loadSize (LoadState *S) {
|
||||
return loadUnsigned(S, ~(size_t)0);
|
||||
return loadUnsigned(S, MAX_SIZET);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ static TString *loadStringN (LoadState *S, Proto *p) {
|
||||
ts = luaS_createlngstrobj(L, size); /* create string */
|
||||
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
|
||||
luaD_inctop(L);
|
||||
loadVector(S, getstr(ts), size); /* load directly in final place */
|
||||
loadVector(S, getlngstr(ts), size); /* load directly in final place */
|
||||
L->top.p--; /* pop string */
|
||||
}
|
||||
luaC_objbarrier(L, p, ts);
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
/*
|
||||
** Encode major-minor version in one byte, one nibble for each
|
||||
*/
|
||||
#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */
|
||||
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
|
||||
#define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100)
|
||||
|
||||
#define LUAC_FORMAT 0 /* this is the official format */
|
||||
|
||||
|
||||
@@ -91,8 +91,10 @@ static int l_strton (const TValue *obj, TValue *result) {
|
||||
lua_assert(obj != result);
|
||||
if (!cvt2num(obj)) /* is object not a string? */
|
||||
return 0;
|
||||
else
|
||||
return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1);
|
||||
else {
|
||||
TString *st = tsvalue(obj);
|
||||
return (luaO_str2num(getstr(st), result) == tsslen(st) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -368,30 +370,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||
|
||||
|
||||
/*
|
||||
** Compare two strings 'ls' x 'rs', returning an integer less-equal-
|
||||
** -greater than zero if 'ls' is less-equal-greater than 'rs'.
|
||||
** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
|
||||
** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
|
||||
** The code is a little tricky because it allows '\0' in the strings
|
||||
** and it uses 'strcoll' (to respect locales) for each segments
|
||||
** of the strings.
|
||||
** and it uses 'strcoll' (to respect locales) for each segment
|
||||
** of the strings. Note that segments can compare equal but still
|
||||
** have different lengths.
|
||||
*/
|
||||
static int l_strcmp (const TString *ls, const TString *rs) {
|
||||
const char *l = getstr(ls);
|
||||
size_t ll = tsslen(ls);
|
||||
const char *r = getstr(rs);
|
||||
size_t lr = tsslen(rs);
|
||||
static int l_strcmp (const TString *ts1, const TString *ts2) {
|
||||
const char *s1 = getstr(ts1);
|
||||
size_t rl1 = tsslen(ts1); /* real length */
|
||||
const char *s2 = getstr(ts2);
|
||||
size_t rl2 = tsslen(ts2);
|
||||
for (;;) { /* for each segment */
|
||||
int temp = strcoll(l, r);
|
||||
int temp = strcoll(s1, s2);
|
||||
if (temp != 0) /* not equal? */
|
||||
return temp; /* done */
|
||||
else { /* strings are equal up to a '\0' */
|
||||
size_t len = strlen(l); /* index of first '\0' in both strings */
|
||||
if (len == lr) /* 'rs' is finished? */
|
||||
return (len == ll) ? 0 : 1; /* check 'ls' */
|
||||
else if (len == ll) /* 'ls' is finished? */
|
||||
return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */
|
||||
/* both strings longer than 'len'; go on comparing after the '\0' */
|
||||
len++;
|
||||
l += len; ll -= len; r += len; lr -= len;
|
||||
size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */
|
||||
size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */
|
||||
if (zl2 == rl2) /* 's2' is finished? */
|
||||
return (zl1 == rl1) ? 0 : 1; /* check 's1' */
|
||||
else if (zl1 == rl1) /* 's1' is finished? */
|
||||
return -1; /* 's1' is less than 's2' ('s2' is not finished) */
|
||||
/* both strings longer than 'zl'; go on comparing after the '\0' */
|
||||
zl1++; zl2++;
|
||||
s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -626,8 +630,9 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
||||
static void copy2buff (StkId top, int n, char *buff) {
|
||||
size_t tl = 0; /* size already copied */
|
||||
do {
|
||||
size_t l = vslen(s2v(top - n)); /* length of string being copied */
|
||||
memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char));
|
||||
TString *st = tsvalue(s2v(top - n));
|
||||
size_t l = tsslen(st); /* length of string being copied */
|
||||
memcpy(buff + tl, getstr(st), l * sizeof(char));
|
||||
tl += l;
|
||||
} while (--n > 0);
|
||||
}
|
||||
@@ -653,12 +658,12 @@ void luaV_concat (lua_State *L, int total) {
|
||||
}
|
||||
else {
|
||||
/* at least two non-empty string values; get as many as possible */
|
||||
size_t tl = vslen(s2v(top - 1));
|
||||
size_t tl = tsslen(tsvalue(s2v(top - 1)));
|
||||
TString *ts;
|
||||
/* collect total length and number of strings */
|
||||
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
|
||||
size_t l = vslen(s2v(top - n - 1));
|
||||
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
|
||||
size_t l = tsslen(tsvalue(s2v(top - n - 1)));
|
||||
if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) {
|
||||
L->top.p = top - total; /* pop strings to avoid wasting stack */
|
||||
luaG_runerror(L, "string length overflow");
|
||||
}
|
||||
@@ -671,7 +676,7 @@ void luaV_concat (lua_State *L, int total) {
|
||||
}
|
||||
else { /* long string; copy strings directly to final result */
|
||||
ts = luaS_createlngstrobj(L, tl);
|
||||
copy2buff(top, n, getstr(ts));
|
||||
copy2buff(top, n, getlngstr(ts));
|
||||
}
|
||||
setsvalue2s(L, top - n, ts); /* create result */
|
||||
}
|
||||
@@ -1157,18 +1162,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
startfunc:
|
||||
trap = L->hookmask;
|
||||
returning: /* trap already set */
|
||||
cl = clLvalue(s2v(ci->func.p));
|
||||
cl = ci_func(ci);
|
||||
k = cl->p->k;
|
||||
pc = ci->u.l.savedpc;
|
||||
if (l_unlikely(trap)) {
|
||||
if (pc == cl->p->code) { /* first instruction (not resuming)? */
|
||||
if (cl->p->is_vararg)
|
||||
trap = 0; /* hooks will start after VARARGPREP instruction */
|
||||
else /* check 'call' hook */
|
||||
luaD_hookcall(L, ci);
|
||||
}
|
||||
ci->u.l.trap = 1; /* assume trap is on, for now */
|
||||
}
|
||||
if (l_unlikely(trap))
|
||||
trap = luaG_tracecall(L);
|
||||
base = ci->func.p + 1;
|
||||
/* main loop of interpreter */
|
||||
for (;;) {
|
||||
@@ -1255,7 +1253,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
const TValue *slot;
|
||||
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
|
||||
TValue *rc = KC(i);
|
||||
TString *key = tsvalue(rc); /* key must be a string */
|
||||
TString *key = tsvalue(rc); /* key must be a short string */
|
||||
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
|
||||
setobj2s(L, ra, slot);
|
||||
}
|
||||
@@ -1298,7 +1296,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
const TValue *slot;
|
||||
TValue *rb = vRB(i);
|
||||
TValue *rc = KC(i);
|
||||
TString *key = tsvalue(rc); /* key must be a string */
|
||||
TString *key = tsvalue(rc); /* key must be a short string */
|
||||
if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) {
|
||||
setobj2s(L, ra, slot);
|
||||
}
|
||||
@@ -1311,7 +1309,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
|
||||
TValue *rb = KB(i);
|
||||
TValue *rc = RKC(i);
|
||||
TString *key = tsvalue(rb); /* key must be a string */
|
||||
TString *key = tsvalue(rb); /* key must be a short string */
|
||||
if (luaV_fastset(L, upval, key, slot, luaH_getshortstr)) {
|
||||
luaV_finishfastset(L, upval, slot, rc);
|
||||
}
|
||||
@@ -1354,7 +1352,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
const TValue *slot;
|
||||
TValue *rb = KB(i);
|
||||
TValue *rc = RKC(i);
|
||||
TString *key = tsvalue(rb); /* key must be a string */
|
||||
TString *key = tsvalue(rb); /* key must be a short string */
|
||||
if (luaV_fastset(L, s2v(ra), key, slot, luaH_getshortstr)) {
|
||||
luaV_finishfastset(L, s2v(ra), slot, rc);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
/*
|
||||
* one.c -- Lua core, libraries, and interpreter in a single file
|
||||
** Lua core, libraries, and interpreter in a single file.
|
||||
** Compiling just this file generates a complete Lua stand-alone
|
||||
** program:
|
||||
**
|
||||
** $ gcc -O2 -std=c99 -o lua onelua.c -lm
|
||||
**
|
||||
** or
|
||||
**
|
||||
** $ gcc -O2 -std=c89 -DLUA_USE_C89 -o lua onelua.c -lm
|
||||
**
|
||||
*/
|
||||
|
||||
/* default is to build the full interpreter */
|
||||
@@ -11,8 +20,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* choose suitable platform-specific features */
|
||||
/* some of these may need extra libraries such as -ldl -lreadline -lncurses */
|
||||
|
||||
/*
|
||||
** Choose suitable platform-specific features. Default is no
|
||||
** platform-specific features. Some of these options may need extra
|
||||
** libraries such as -ldl -lreadline -lncurses
|
||||
*/
|
||||
#if 0
|
||||
#define LUA_USE_LINUX
|
||||
#define LUA_USE_MACOSX
|
||||
@@ -20,6 +33,7 @@
|
||||
#define LUA_ANSI
|
||||
#endif
|
||||
|
||||
|
||||
/* no need to change anything below this line ----------------------------- */
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
29
HISTORY.md
29
HISTORY.md
@@ -1,3 +1,18 @@
|
||||
v1.8.0 (2025-1-14)
|
||||
-----------
|
||||
* Update Lua to 5.4.7
|
||||
* service sessions can be rewind
|
||||
* Improve: udp (ipv6 support)
|
||||
* Improve: debug console
|
||||
* Improve: http
|
||||
* Improve: mongo driver
|
||||
* Improve: mysql driver
|
||||
* Bugfix: socketchannel
|
||||
* Bugfix: cluster
|
||||
* Bugfix: ssl
|
||||
* Bugfix: websocket
|
||||
* Bugfix: redis cluster driver
|
||||
|
||||
v1.7.0 (2023-11-13)
|
||||
-----------
|
||||
* Update Lua to 5.4.6
|
||||
@@ -92,7 +107,7 @@ v1.1.0-rc (2017-7-18)
|
||||
* httpc : Add httpc.timeout
|
||||
* mongo driver : sort support multi-key
|
||||
* bson : Check utf8 string
|
||||
* bson : No longer support numberic key
|
||||
* bson : No longer support numeric key
|
||||
* daemon mode: Can output the error messages
|
||||
* sproto : Support decimal number
|
||||
* sproto: Support binary type
|
||||
@@ -136,7 +151,7 @@ v1.0.0-rc3 (2016-5-9)
|
||||
* skynet.getenv can return empty string
|
||||
* Add lua VM memory warning
|
||||
* lua VM support memory limit
|
||||
* skynet.pcall suport varargs
|
||||
* skynet.pcall support varargs
|
||||
* Bugfix : Global name query
|
||||
* Bugfix : snax.queryglobal
|
||||
|
||||
@@ -236,7 +251,7 @@ v1.0.0-alpha6 (2015-5-18)
|
||||
|
||||
v1.0.0-alpha5 (2015-4-27)
|
||||
-----------
|
||||
* merge lua 5.3 offical bugfix
|
||||
* merge lua 5.3 official bugfix
|
||||
* improve sproto rpc api
|
||||
* fix a deadlock bug when service retire
|
||||
* improve cluster config reload
|
||||
@@ -352,7 +367,7 @@ v0.6.0 (2014-8-18)
|
||||
* add sharedata
|
||||
* bugfix: service exit before init would not report back
|
||||
* add skynet.response and check multicall skynet.ret
|
||||
* skynet.newservice throw error when lanuch faild
|
||||
* skynet.newservice throw error when lanuch failed
|
||||
* Don't check imported function in snax.hotfix
|
||||
* snax service add change SERVICE_PATH and add it to package.path
|
||||
* skynet.redirect support string address
|
||||
@@ -412,7 +427,7 @@ v0.4.0 (2014-6-30)
|
||||
* cluster.open support cluster name.
|
||||
* Add new api skynet.packstring , and skynet.unpack support lua string
|
||||
* socket.listen support put port into address. (address:port)
|
||||
* Redesign harbor/master/dummy, remove lots of C code and rewite in lua.
|
||||
* Redesign harbor/master/dummy, remove lots of C code and rewrite in lua.
|
||||
* Remove block connect api, queue sending message during connecting now.
|
||||
* Add skynet.time()
|
||||
|
||||
@@ -452,8 +467,8 @@ v0.2.0 (2014-5-12)
|
||||
* Add some snax api, snax.uniqueservice (etc.) , use independent protocol `PTYPE_SNAX` .
|
||||
* Add bootstrap lua script , remove some code in C .
|
||||
* Use a lua loader to load lua service code (and set the lua environment), remove some code in C.
|
||||
* Support preload a file before each lua serivce start.
|
||||
* Add datacenter serivce.
|
||||
* Support preload a file before each lua service start.
|
||||
* Add datacenter service.
|
||||
* Add multicast api.
|
||||
* Remove skynet.blockcall , simplify the implement of message queue.
|
||||
* When dropping message queue (at service exit) , dispatcher will post an error back to the source of each message.
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2022 codingnow.com
|
||||
Copyright (c) 2012-2025 codingnow.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -4,7 +4,7 @@ Skynet is a multi-user Lua framework supporting the actor model, often used in g
|
||||
|
||||
[It is heavily used in the Chinese game industry](https://github.com/cloudwu/skynet/wiki/Uses), but is also now spreading to other industries, and to English-centric developers. To visit related sites, visit the Chinese pages using something like Google or Deepl translate.
|
||||
|
||||
The community is friendly and almost contributors can speak English, so English speakers are welcome to ask questions in [Discussion](https://github.com/cloudwu/skynet/discussions), or sumbit issues in English.
|
||||
The community is friendly and almost all contributors can speak English, so English speakers are welcome to ask questions in [Discussion](https://github.com/cloudwu/skynet/discussions), or submit issues in English.
|
||||
|
||||
## Build
|
||||
|
||||
@@ -36,7 +36,7 @@ Run these in different consoles:
|
||||
|
||||
## About Lua version
|
||||
|
||||
Skynet now uses a modified version of lua 5.4.4 ( https://github.com/ejoy/lua/tree/skynet54 ) for multiple lua states.
|
||||
Skynet now uses a modified version of lua 5.4.7 ( https://github.com/ejoy/lua/tree/skynet54 ) for multiple lua states.
|
||||
|
||||
Official Lua versions can also be used as long as the Makefile is edited.
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ local function recv_package(last)
|
||||
if r == "" then
|
||||
error "Server closed"
|
||||
end
|
||||
return unpack_package(last .. r)
|
||||
return recv_package(last .. r)
|
||||
end
|
||||
|
||||
local session = 0
|
||||
|
||||
@@ -79,7 +79,6 @@ local function encode_token(token)
|
||||
end
|
||||
|
||||
local etoken = crypt.desencode(secret, encode_token(token))
|
||||
local b = crypt.base64encode(etoken)
|
||||
writeline(fd, crypt.base64encode(etoken))
|
||||
|
||||
local result = readline()
|
||||
|
||||
@@ -35,18 +35,18 @@ static void
|
||||
_init_bio(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
|
||||
tls_p->ssl = SSL_new(ctx_p->ctx);
|
||||
if(!tls_p->ssl) {
|
||||
luaL_error(L, "SSL_new faild");
|
||||
luaL_error(L, "SSL_new failed");
|
||||
}
|
||||
|
||||
tls_p->in_bio = BIO_new(BIO_s_mem());
|
||||
if(!tls_p->in_bio) {
|
||||
luaL_error(L, "new in bio faild");
|
||||
luaL_error(L, "new in bio failed");
|
||||
}
|
||||
BIO_set_mem_eof_return(tls_p->in_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
|
||||
|
||||
tls_p->out_bio = BIO_new(BIO_s_mem());
|
||||
if(!tls_p->out_bio) {
|
||||
luaL_error(L, "new out bio faild");
|
||||
luaL_error(L, "new out bio failed");
|
||||
}
|
||||
BIO_set_mem_eof_return(tls_p->out_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
|
||||
|
||||
@@ -267,6 +267,15 @@ _ltls_context_write(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lset_ext_host_name(lua_State* L) {
|
||||
struct tls_context* tls_p = _check_context(L, 1);
|
||||
size_t slen = 0;
|
||||
char* host = (char*)lua_tolstring(L, 2, &slen);
|
||||
int ret = SSL_set_tlsext_host_name(tls_p->ssl, host);
|
||||
lua_pushinteger(L, ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lctx_gc(lua_State* L) {
|
||||
@@ -330,7 +339,7 @@ lnew_ctx(lua_State* L) {
|
||||
unsigned int err = ERR_get_error();
|
||||
char buf[256];
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
luaL_error(L, "SSL_CTX_new client faild. %s\n", buf);
|
||||
luaL_error(L, "SSL_CTX_new client failed. %s\n", buf);
|
||||
}
|
||||
|
||||
if(luaL_newmetatable(L, "_TLS_SSLCTX_METATABLE_")) {
|
||||
@@ -378,6 +387,7 @@ lnew_tls(lua_State* L) {
|
||||
{"handshake", _ltls_context_handshake},
|
||||
{"read", _ltls_context_read},
|
||||
{"write", _ltls_context_write},
|
||||
{"set_ext_host_name", _lset_ext_host_name},
|
||||
{NULL, NULL},
|
||||
};
|
||||
luaL_newlib(L, l);
|
||||
|
||||
@@ -114,7 +114,7 @@ packreq_string(lua_State *L, int session, void * msg, uint32_t sz, int is_push)
|
||||
if (name == NULL) {
|
||||
luaL_error(L, "name is not a string, it's a %s", lua_typename(L, lua_type(L, 1)));
|
||||
} else {
|
||||
luaL_error(L, "name is too long %s", name);
|
||||
luaL_error(L, "name length is invalid, must be between 1 and 255 characters: %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +675,44 @@ ludp_connect(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ludp_dial(lua_State *L){
|
||||
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
size_t sz = 0;
|
||||
const char * addr = luaL_checklstring(L, 1, &sz);
|
||||
char tmp[sz];
|
||||
int port = 0;
|
||||
const char * host = address_port(L, tmp, addr, 2, &port);
|
||||
|
||||
int id = skynet_socket_udp_dial(ctx, host, port);
|
||||
if (id < 0){
|
||||
return luaL_error(L, "udp dial host failed");
|
||||
}
|
||||
|
||||
lua_pushinteger(L, id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ludp_listen(lua_State *L){
|
||||
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
size_t sz = 0;
|
||||
const char * addr = luaL_checklstring(L, 1, &sz);
|
||||
char tmp[sz];
|
||||
|
||||
int port = 0;
|
||||
const char * host = address_port(L, tmp, addr, 2, &port);
|
||||
|
||||
int id = skynet_socket_udp_listen(ctx, host, port);
|
||||
if (id < 0){
|
||||
return luaL_error(L, "udp listen host failed");
|
||||
}
|
||||
|
||||
lua_pushinteger(L, id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ludp_send(lua_State *L) {
|
||||
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
@@ -849,6 +887,8 @@ luaopen_skynet_socketdriver(lua_State *L) {
|
||||
{ "nodelay", lnodelay },
|
||||
{ "udp", ludp },
|
||||
{ "udp_connect", ludp_connect },
|
||||
{ "udp_dial", ludp_dial},
|
||||
{ "udp_listen", ludp_listen},
|
||||
{ "udp_send", ludp_send },
|
||||
{ "udp_address", ludp_address },
|
||||
{ "resolve", lresolve },
|
||||
|
||||
@@ -2,8 +2,12 @@ local skynet = require "skynet"
|
||||
local socket = require "http.sockethelper"
|
||||
local internal = require "http.internal"
|
||||
local dns = require "skynet.dns"
|
||||
|
||||
local string = string
|
||||
local table = table
|
||||
local pcall = pcall
|
||||
local error = error
|
||||
local pairs = pairs
|
||||
|
||||
local httpc = {}
|
||||
|
||||
@@ -83,9 +87,6 @@ local function connect(host, timeout)
|
||||
end
|
||||
-- print("protocol hostname port", protocol, hostname, port)
|
||||
local interface = gen_interface(protocol, fd, hostname)
|
||||
if interface.init then
|
||||
interface.init()
|
||||
end
|
||||
if timeout then
|
||||
skynet.timeout(timeout, function()
|
||||
if not interface.finish then
|
||||
@@ -93,6 +94,9 @@ local function connect(host, timeout)
|
||||
end
|
||||
end)
|
||||
end
|
||||
if interface.init then
|
||||
interface.init(host)
|
||||
end
|
||||
return fd, interface, host
|
||||
end
|
||||
|
||||
@@ -115,7 +119,7 @@ function httpc.request(method, hostname, url, recvheader, header, content)
|
||||
if ok then
|
||||
return statuscode, body
|
||||
else
|
||||
error(statuscode)
|
||||
error(body or statuscode)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@ local internal = require "http.internal"
|
||||
|
||||
local string = string
|
||||
local type = type
|
||||
local assert = assert
|
||||
local tonumber = tonumber
|
||||
local pcall = pcall
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
|
||||
local httpd = {}
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
local table = table
|
||||
local type = type
|
||||
local string = string
|
||||
local tonumber = tonumber
|
||||
local pcall = pcall
|
||||
local assert = assert
|
||||
local error = error
|
||||
local pairs = pairs
|
||||
|
||||
local M = {}
|
||||
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
local socket = require "skynet.socket"
|
||||
local skynet = require "skynet"
|
||||
|
||||
local coroutine = coroutine
|
||||
local error = error
|
||||
local tostring = tostring
|
||||
|
||||
local readbytes = socket.read
|
||||
local writebytes = socket.write
|
||||
|
||||
local sockethelper = {}
|
||||
local socket_error = setmetatable({} , { __tostring = function() return "[Socket Error]" end })
|
||||
local socket_error = setmetatable({} , {
|
||||
__tostring = function(self)
|
||||
local info = self.err_info
|
||||
self.err_info = nil
|
||||
return info or "[Socket Error]"
|
||||
end,
|
||||
|
||||
__call = function (self, info)
|
||||
self.err_info = "[Socket Error] : " .. tostring(info)
|
||||
return self
|
||||
end
|
||||
})
|
||||
|
||||
sockethelper.socket_error = socket_error
|
||||
|
||||
@@ -27,7 +42,7 @@ local function preread(fd, str)
|
||||
if ret then
|
||||
return str .. ret
|
||||
else
|
||||
error(socket_error)
|
||||
error(socket_error("read failed fd = " .. fd))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -36,7 +51,7 @@ local function preread(fd, str)
|
||||
if ret then
|
||||
return ret
|
||||
else
|
||||
error(socket_error)
|
||||
error(socket_error("read failed fd = " .. fd))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -51,7 +66,7 @@ function sockethelper.readfunc(fd, pre)
|
||||
if ret then
|
||||
return ret
|
||||
else
|
||||
error(socket_error)
|
||||
error(socket_error("read failed fd = " .. fd))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -62,24 +77,27 @@ function sockethelper.writefunc(fd)
|
||||
return function(content)
|
||||
local ok = writebytes(fd, content)
|
||||
if not ok then
|
||||
error(socket_error)
|
||||
error(socket_error("write failed fd = " .. fd))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function sockethelper.connect(host, port, timeout)
|
||||
local fd
|
||||
local fd, err
|
||||
local is_time_out = false
|
||||
if timeout then
|
||||
is_time_out = true
|
||||
local drop_fd
|
||||
local co = coroutine.running()
|
||||
-- asynchronous connect
|
||||
skynet.fork(function()
|
||||
fd = socket.open(host, port)
|
||||
fd, err = socket.open(host, port)
|
||||
if drop_fd then
|
||||
-- sockethelper.connect already return, and raise socket_error
|
||||
socket.close(fd)
|
||||
else
|
||||
-- socket.open before sleep, wakeup.
|
||||
is_time_out = false
|
||||
skynet.wakeup(co)
|
||||
end
|
||||
end)
|
||||
@@ -89,13 +107,14 @@ function sockethelper.connect(host, port, timeout)
|
||||
drop_fd = true
|
||||
end
|
||||
else
|
||||
is_time_out = false
|
||||
-- block connect
|
||||
fd = socket.open(host, port)
|
||||
end
|
||||
if fd then
|
||||
return fd
|
||||
end
|
||||
error(socket_error)
|
||||
error(socket_error("connect failed host = " .. host .. ' port = '.. port .. ' timeout = ' .. tostring(timeout) .. ' err = ' .. tostring(err) .. ' is_time_out = '.. tostring(is_time_out)))
|
||||
end
|
||||
|
||||
function sockethelper.close(fd)
|
||||
|
||||
@@ -6,7 +6,8 @@ local tlshelper = {}
|
||||
function tlshelper.init_requestfunc(fd, tls_ctx)
|
||||
local readfunc = socket.readfunc(fd)
|
||||
local writefunc = socket.writefunc(fd)
|
||||
return function ()
|
||||
return function (hostname)
|
||||
tls_ctx:set_ext_host_name(hostname)
|
||||
local ds1 = tls_ctx:handshake()
|
||||
writefunc(ds1)
|
||||
while not tls_ctx:finished() do
|
||||
|
||||
@@ -20,7 +20,17 @@ end
|
||||
function url.parse_query(q)
|
||||
local r = {}
|
||||
for k,v in q:gmatch "(.-)=([^&]*)&?" do
|
||||
r[decode(k)] = decode(v)
|
||||
local dk, dv = decode(k), decode(v)
|
||||
local oldv = r[dk]
|
||||
if oldv then
|
||||
if type(oldv) ~= "table" then
|
||||
r[dk] = {oldv, dv}
|
||||
else
|
||||
oldv[#oldv+1] = dv
|
||||
end
|
||||
else
|
||||
r[dk] = dv
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
@@ -14,6 +14,7 @@ local pairs = pairs
|
||||
local error = error
|
||||
local string = string
|
||||
local xpcall = xpcall
|
||||
local pcall = pcall
|
||||
local debug = debug
|
||||
local table = table
|
||||
local tonumber = tonumber
|
||||
@@ -33,6 +34,27 @@ local function _isws_closed(id)
|
||||
return not ws_pool[id]
|
||||
end
|
||||
|
||||
local function reader_with_payload(self, payload)
|
||||
local sz_payload = #payload
|
||||
if sz_payload == 0 then
|
||||
return
|
||||
end
|
||||
local read = self.read
|
||||
function self.read (sz)
|
||||
if sz == nil or sz == sz_payload then
|
||||
self.read = read
|
||||
return payload
|
||||
end
|
||||
if sz < sz_payload then
|
||||
local ret = payload:sub(1, sz)
|
||||
payload = payload:sub(sz + 1)
|
||||
sz_payload = #payload
|
||||
return ret
|
||||
end
|
||||
self.read = read
|
||||
return payload .. read(sz - sz_payload)
|
||||
end
|
||||
end
|
||||
|
||||
local function write_handshake(self, host, url, header)
|
||||
local key = crypt.base64encode(crypt.randomkey()..crypt.randomkey())
|
||||
@@ -50,11 +72,11 @@ local function write_handshake(self, host, url, header)
|
||||
end
|
||||
|
||||
local recvheader = {}
|
||||
local code, body = internal.request(self, "GET", host, url, recvheader, request_header)
|
||||
local code, payload = internal.request(self, "GET", host, url, recvheader, request_header)
|
||||
if code ~= 101 then
|
||||
error(string.format("websocket handshake error: code[%s] info:%s", code, body))
|
||||
error(string.format("websocket handshake error: code[%s] info:%s", code, payload))
|
||||
end
|
||||
assert(body == "") -- todo: M.read may need handle it
|
||||
reader_with_payload(self, payload)
|
||||
|
||||
if not recvheader["upgrade"] or recvheader["upgrade"]:lower() ~= "websocket" then
|
||||
error("websocket handshake upgrade must websocket")
|
||||
@@ -76,17 +98,17 @@ local function write_handshake(self, host, url, header)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function read_handshake(self, upgrade_ops)
|
||||
local header, method, url
|
||||
if upgrade_ops then
|
||||
header, method, url = upgrade_ops.header, upgrade_ops.method, upgrade_ops.url
|
||||
else
|
||||
local tmpline = {}
|
||||
local header_body = internal.recvheader(self.read, tmpline, "")
|
||||
if not header_body then
|
||||
local payload = internal.recvheader(self.read, tmpline, "")
|
||||
if not payload then
|
||||
return 413
|
||||
end
|
||||
reader_with_payload(self, payload)
|
||||
|
||||
local request = assert(tmpline[1])
|
||||
local httpver
|
||||
@@ -406,16 +428,25 @@ end
|
||||
-- connect / handshake / message / ping / pong / close / error
|
||||
function M.accept(socket_id, handle, protocol, addr, options)
|
||||
if not (options and options.upgrade) then
|
||||
socket.start(socket_id)
|
||||
local isok, err = socket.start(socket_id)
|
||||
if not isok then
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
protocol = protocol or "ws"
|
||||
local ws_obj = _new_server_ws(socket_id, handle, protocol)
|
||||
ws_obj.addr = addr
|
||||
local on_warning = handle and handle["warning"]
|
||||
if on_warning then
|
||||
socket.warning(socket_id, function (id, sz)
|
||||
local isok = pcall(socket.warning, socket_id, function(id, sz)
|
||||
on_warning(ws_obj, sz)
|
||||
end)
|
||||
if not isok then
|
||||
if not _isws_closed(socket_id) then
|
||||
_close_websocket(ws_obj)
|
||||
end
|
||||
return false, "connect is closed " .. socket_id
|
||||
end
|
||||
end
|
||||
|
||||
local ok, err = xpcall(resolve_accept, debug.traceback, ws_obj, options)
|
||||
@@ -428,7 +459,7 @@ function M.accept(socket_id, handle, protocol, addr, options)
|
||||
if closed then
|
||||
try_handle(ws_obj, "close")
|
||||
else
|
||||
try_handle(ws_obj, "error")
|
||||
try_handle(ws_obj, "error", err)
|
||||
end
|
||||
else
|
||||
-- error(err)
|
||||
@@ -460,7 +491,12 @@ function M.connect(url, header, timeout)
|
||||
local socket_id = sockethelper.connect(host_addr, host_port, timeout)
|
||||
local ws_obj = _new_client_ws(socket_id, protocol, hostname)
|
||||
ws_obj.addr = host
|
||||
write_handshake(ws_obj, host_addr, uri, header)
|
||||
|
||||
local is_ok,err = pcall(write_handshake, ws_obj, host_addr, uri, header)
|
||||
if not is_ok then
|
||||
_close_websocket(ws_obj)
|
||||
error(err)
|
||||
end
|
||||
return socket_id
|
||||
end
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ if not main then
|
||||
end
|
||||
|
||||
LUA_SERVICE = nil
|
||||
package.path , LUA_PATH = LUA_PATH
|
||||
package.cpath , LUA_CPATH = LUA_CPATH
|
||||
package.path , LUA_PATH = LUA_PATH, nil
|
||||
package.cpath , LUA_CPATH = LUA_CPATH, nil
|
||||
|
||||
local service_path = string.match(pattern, "(.*/)[^/?]+$")
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ local skynet_require = require "skynet.require"
|
||||
local tostring = tostring
|
||||
local coroutine = coroutine
|
||||
local assert = assert
|
||||
local error = error
|
||||
local pairs = pairs
|
||||
local pcall = pcall
|
||||
local table = table
|
||||
@@ -69,7 +70,7 @@ local watching_session = {}
|
||||
local error_queue = {}
|
||||
local fork_queue = { h = 1, t = 0 }
|
||||
|
||||
local auxsend, auxtimeout
|
||||
local auxsend, auxtimeout, auxwait
|
||||
do ---- avoid session rewind conflict
|
||||
local csend = c.send
|
||||
local cintcommand = c.intcommand
|
||||
@@ -139,6 +140,12 @@ do ---- avoid session rewind conflict
|
||||
return session
|
||||
end
|
||||
|
||||
local function auxwait_checkconflict()
|
||||
local session = c.genid()
|
||||
checkconflict(session)
|
||||
return session
|
||||
end
|
||||
|
||||
local function auxsend_checkrewind(addr, proto, msg, sz)
|
||||
local session = csend(addr, proto, nil, msg, sz)
|
||||
if session and session > dangerzone_low and session <= dangerzone_up then
|
||||
@@ -157,15 +164,26 @@ do ---- avoid session rewind conflict
|
||||
return session
|
||||
end
|
||||
|
||||
local function auxwait_checkrewind()
|
||||
local session = c.genid()
|
||||
if session > dangerzone_low and session <= dangerzone_up then
|
||||
-- enter dangerzone
|
||||
set_checkconflict(session)
|
||||
end
|
||||
return session
|
||||
end
|
||||
|
||||
set_checkrewind = function()
|
||||
auxsend = auxsend_checkrewind
|
||||
auxtimeout = auxtimeout_checkrewind
|
||||
auxwait = auxwait_checkrewind
|
||||
end
|
||||
|
||||
set_checkconflict = function(session)
|
||||
reset_dangerzone(session)
|
||||
auxsend = auxsend_checkconflict
|
||||
auxtimeout = auxtimeout_checkconflict
|
||||
auxwait = auxwait_checkconflict
|
||||
end
|
||||
|
||||
-- in safezone at the beginning
|
||||
@@ -515,7 +533,7 @@ function skynet.yield()
|
||||
end
|
||||
|
||||
function skynet.wait(token)
|
||||
local session = c.genid()
|
||||
local session = auxwait()
|
||||
token = token or coroutine.running()
|
||||
suspend_sleep(session, token)
|
||||
sleep_session[token] = nil
|
||||
@@ -652,7 +670,11 @@ function skynet.exit()
|
||||
for address in pairs(tmp) do
|
||||
c.send(address, skynet.PTYPE_ERROR, 0, "")
|
||||
end
|
||||
c.callback(function() end)
|
||||
c.callback(function(prototype, msg, sz, session, source)
|
||||
if session ~= 0 and source ~= 0 then
|
||||
c.send(source, skynet.PTYPE_ERROR, session, "")
|
||||
end
|
||||
end)
|
||||
c.command("EXIT")
|
||||
-- quit service
|
||||
coroutine_yield "QUIT"
|
||||
@@ -1072,10 +1094,20 @@ function skynet.stat(what)
|
||||
return c.intcommand("STAT", what)
|
||||
end
|
||||
|
||||
local function task_traceback(co)
|
||||
if co == "BREAK" then
|
||||
return co
|
||||
elseif timeout_traceback and timeout_traceback[co] then
|
||||
return timeout_traceback[co]
|
||||
else
|
||||
return traceback(co)
|
||||
end
|
||||
end
|
||||
|
||||
function skynet.task(ret)
|
||||
if ret == nil then
|
||||
local t = 0
|
||||
for session,co in pairs(session_id_coroutine) do
|
||||
for _,co in pairs(session_id_coroutine) do
|
||||
if co ~= "BREAK" then
|
||||
t = t + 1
|
||||
end
|
||||
@@ -1093,23 +1125,13 @@ function skynet.task(ret)
|
||||
if tt == "table" then
|
||||
for session,co in pairs(session_id_coroutine) do
|
||||
local key = string.format("%s session: %d", tostring(co), session)
|
||||
if co == "BREAK" then
|
||||
ret[key] = "BREAK"
|
||||
elseif timeout_traceback and timeout_traceback[co] then
|
||||
ret[key] = timeout_traceback[co]
|
||||
else
|
||||
ret[key] = traceback(co)
|
||||
end
|
||||
ret[key] = task_traceback(co)
|
||||
end
|
||||
return
|
||||
elseif tt == "number" then
|
||||
local co = session_id_coroutine[ret]
|
||||
if co then
|
||||
if co == "BREAK" then
|
||||
return "BREAK"
|
||||
else
|
||||
return traceback(co)
|
||||
end
|
||||
return task_traceback(co)
|
||||
else
|
||||
return "No session"
|
||||
end
|
||||
@@ -1126,7 +1148,7 @@ end
|
||||
function skynet.uniqtask()
|
||||
local stacks = {}
|
||||
for session, co in pairs(session_id_coroutine) do
|
||||
local stack = traceback(co)
|
||||
local stack = task_traceback(co)
|
||||
local info = stacks[stack] or {count = 0, sessions = {}}
|
||||
info.count = info.count + 1
|
||||
if info.count < 10 then
|
||||
|
||||
@@ -55,6 +55,8 @@ local function get_sender(node)
|
||||
return s
|
||||
end
|
||||
|
||||
cluster.get_sender = get_sender
|
||||
|
||||
function cluster.call(node, address, ...)
|
||||
-- skynet.pack(...) will free by cluster.core.packrequest
|
||||
local s = sender[node]
|
||||
|
||||
@@ -511,9 +511,7 @@ function mongo_collection:find(query, projection)
|
||||
__data = nil,
|
||||
__cursor = nil,
|
||||
__document = {},
|
||||
__skip = 0,
|
||||
__limit = 0,
|
||||
__sort = empty_bson,
|
||||
__sort = empty_bson
|
||||
} , cursor_meta)
|
||||
end
|
||||
|
||||
@@ -548,15 +546,52 @@ function mongo_cursor:limit(amount)
|
||||
return self
|
||||
end
|
||||
|
||||
function mongo_cursor:hint(indexName)
|
||||
self.__hint = indexName
|
||||
return self
|
||||
end
|
||||
|
||||
function mongo_cursor:maxTimeMS(ms)
|
||||
self.__maxTimeMS = ms
|
||||
return self
|
||||
end
|
||||
|
||||
local opt_func = {}
|
||||
|
||||
local function opt_define(name)
|
||||
local key = "__" .. name
|
||||
opt_func[name] = function (self, ...)
|
||||
local v = self[key]
|
||||
if v ~= nil then
|
||||
return name, v, ...
|
||||
else
|
||||
return ...
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
opt_define "skip"
|
||||
opt_define "limit"
|
||||
opt_define "hint"
|
||||
opt_define "maxTimeMS"
|
||||
|
||||
local function add_opt(self, opt, ...)
|
||||
if opt == nil then
|
||||
return
|
||||
end
|
||||
return opt_func[opt](self, add_opt(self, ...))
|
||||
end
|
||||
|
||||
function mongo_cursor:count(with_limit_and_skip)
|
||||
local ret
|
||||
if with_limit_and_skip then
|
||||
ret = self.__collection.database:runCommand('count', self.__collection.name, 'query', self.__query,
|
||||
'limit', self.__limit, 'skip', self.__skip)
|
||||
add_opt(self, "skip", "limit", "hint", "maxTimeMS"))
|
||||
else
|
||||
ret = self.__collection.database:runCommand('count', self.__collection.name, 'query', self.__query)
|
||||
ret = self.__collection.database:runCommand('count', self.__collection.name, 'query', self.__query,
|
||||
add_opt(self, "hint", "maxTimeMS"))
|
||||
end
|
||||
assert(ret and ret.ok == 1)
|
||||
assert(ret.ok == 1, ret.errmsg)
|
||||
return ret.n
|
||||
end
|
||||
|
||||
@@ -701,7 +736,7 @@ function mongo_cursor:hasNext()
|
||||
if self.__data == nil then
|
||||
local name = self.__collection.name
|
||||
response = database:runCommand("find", name, "filter", self.__query, "sort", self.__sort,
|
||||
"skip", self.__skip, "limit", self.__limit, "projection", self.__projection)
|
||||
"projection", self.__projection, add_opt(self, "skip", "limit", "hint", "maxTimeMS"))
|
||||
else
|
||||
if self.__cursor and self.__cursor > 0 then
|
||||
local name = self.__collection.name
|
||||
@@ -728,7 +763,7 @@ function mongo_cursor:hasNext()
|
||||
self.__cursor = cursor.id
|
||||
|
||||
local limit = self.__limit
|
||||
if cursor.id > 0 and limit > 0 then
|
||||
if limit and limit > 0 and cursor.id > 0 then
|
||||
limit = limit - #self.__document
|
||||
if limit <= 0 then
|
||||
-- reach limit
|
||||
|
||||
@@ -584,7 +584,7 @@ local function _compose_stmt_execute(self, stmt, cursor_type, args)
|
||||
for i = 1, null_count do
|
||||
local byte = 0
|
||||
for j = 0, 7 do
|
||||
if field_index < arg_num then
|
||||
if field_index <= arg_num then
|
||||
if args[field_index] == nil then
|
||||
byte = byte | (1 << j)
|
||||
else
|
||||
@@ -820,7 +820,7 @@ end
|
||||
|
||||
local function _prepare_resp(self, sql)
|
||||
return function(sock)
|
||||
return read_prepare_result(self, sock, sql)
|
||||
return read_prepare_result(self, sock)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -841,6 +841,9 @@ local function _get_datetime(data, pos)
|
||||
if len == 7 then
|
||||
year, month, day, hour, minute, second, pos = string.unpack("<I2BBBBB", data, pos)
|
||||
value = strformat("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
|
||||
elseif len == 4 then
|
||||
year, month, day, pos = string.unpack("<I2BB", data, pos)
|
||||
value = strformat("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, 0, 0, 0)
|
||||
else
|
||||
value = "2017-09-09 20:08:09"
|
||||
--unsupported format
|
||||
|
||||
@@ -121,8 +121,8 @@ function rediscluster:initialize_slots_cache()
|
||||
self:set_node_name(slave_node)
|
||||
table.insert(master_node.slaves,slave_node)
|
||||
end
|
||||
table.insert(self.nodes,master_node)
|
||||
for slot=tonumber(result[1]),tonumber(result[2]) do
|
||||
table.insert(self.nodes,master_node)
|
||||
self.slots[slot] = master_node
|
||||
end
|
||||
end
|
||||
|
||||
@@ -154,7 +154,7 @@ socket_message[5] = function(id, _, err)
|
||||
return
|
||||
end
|
||||
if s.callback then
|
||||
skynet.error("socket: accpet error:", err)
|
||||
skynet.error("socket: accept error:", err)
|
||||
return
|
||||
end
|
||||
if s.connected then
|
||||
@@ -330,7 +330,7 @@ function socket.read(id, sz)
|
||||
if ret then
|
||||
return ret
|
||||
end
|
||||
if not s.connected then
|
||||
if s.closing or not s.connected then
|
||||
return false, driver.readall(s.buffer, s.pool)
|
||||
end
|
||||
|
||||
@@ -471,6 +471,18 @@ function socket.udp_connect(id, addr, port, callback)
|
||||
driver.udp_connect(id, addr, port)
|
||||
end
|
||||
|
||||
function socket.udp_listen(addr, port, callback)
|
||||
local id = driver.udp_listen(addr, port)
|
||||
create_udp_object(id, callback)
|
||||
return id
|
||||
end
|
||||
|
||||
function socket.udp_dial(addr, port, callback)
|
||||
local id = driver.udp_dial(addr, port)
|
||||
create_udp_object(id, callback)
|
||||
return id
|
||||
end
|
||||
|
||||
socket.sendto = assert(driver.udp_send)
|
||||
socket.udp_address = assert(driver.udp_address)
|
||||
socket.netstat = assert(driver.info)
|
||||
|
||||
@@ -60,6 +60,10 @@ local function close_channel_socket(self)
|
||||
if self.__sock then
|
||||
local so = self.__sock
|
||||
self.__sock = false
|
||||
if self.__wait_response then
|
||||
skynet.wakeup(self.__wait_response)
|
||||
self.__wait_response = nil
|
||||
end
|
||||
-- never raise error
|
||||
pcall(socket.close,so[1])
|
||||
end
|
||||
@@ -112,6 +116,11 @@ local function dispatch_by_session(self)
|
||||
end
|
||||
skynet.wakeup(co)
|
||||
end
|
||||
if not self.__sock then
|
||||
-- closed
|
||||
wakeup_all(self, "channel_closed")
|
||||
break
|
||||
end
|
||||
else
|
||||
self.__thread[session] = nil
|
||||
skynet.error("socket: unknown session :", session)
|
||||
@@ -128,7 +137,7 @@ local function dispatch_by_session(self)
|
||||
end
|
||||
|
||||
local function pop_response(self)
|
||||
while true do
|
||||
while self.__sock do
|
||||
local func,co = table.remove(self.__request, 1), table.remove(self.__thread, 1)
|
||||
if func then
|
||||
return func, co
|
||||
@@ -207,6 +216,11 @@ local function dispatch_by_order(self)
|
||||
self.__result_data[co] = result_data
|
||||
end
|
||||
skynet.wakeup(co)
|
||||
if not self.__sock then
|
||||
-- closed
|
||||
wakeup_all(self, "channel_closed")
|
||||
break
|
||||
end
|
||||
else
|
||||
close_channel_socket(self)
|
||||
local errmsg
|
||||
|
||||
@@ -43,7 +43,7 @@ function gateserver.start(handler)
|
||||
maxclient = conf.maxclient or 1024
|
||||
nodelay = conf.nodelay
|
||||
skynet.error(string.format("Listen on %s:%d", address, port))
|
||||
socket = socketdriver.listen(address, port)
|
||||
socket = socketdriver.listen(address, port, conf.backlog)
|
||||
listen_context.co = coroutine.running()
|
||||
listen_context.fd = socket
|
||||
skynet.wait(listen_context.co)
|
||||
|
||||
@@ -262,7 +262,7 @@ function server.start(conf)
|
||||
if p == nil then
|
||||
p = { fd }
|
||||
u.response[session] = p
|
||||
local ok, result = pcall(conf.request_handler, u.username, message)
|
||||
local ok, result = pcall(request_handler, u.username, message)
|
||||
-- NOTICE: YIELD here, socket may close.
|
||||
result = result or ""
|
||||
if not ok then
|
||||
|
||||
@@ -147,7 +147,7 @@ _ctrl(struct gate * g, const void * msg, int sz) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
skynet_error(ctx, "[gate] Unkown command : %s", command);
|
||||
skynet_error(ctx, "[gate] Unknown command : %s", command);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -680,7 +680,7 @@ mainloop(struct skynet_context * context, void * ud, int type, int session, uint
|
||||
if (id) {
|
||||
report_harbor_down(h,id);
|
||||
} else {
|
||||
skynet_error(context, "Unkown fd (%d) closed", message->id);
|
||||
skynet_error(context, "Unknown fd (%d) closed", message->id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -188,6 +188,7 @@ timing_resume(lua_State *L, int co_index, int n) {
|
||||
if (timing_enable(L, co_index, &start_time)) {
|
||||
start_time = get_time();
|
||||
#ifdef DEBUG_LOG
|
||||
double ti = diff_time(start_time);
|
||||
fprintf(stderr, "PROFILE [%p] resume %lf\n", co, ti);
|
||||
#endif
|
||||
lua_pushvalue(L, co_index);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
local skynet = require "skynet"
|
||||
local harbor = require "skynet.harbor"
|
||||
local service = require "skynet.service"
|
||||
require "skynet.manager" -- import skynet.launch, ...
|
||||
local skynet = require "skynet.manager" -- import skynet.launch, ...
|
||||
|
||||
skynet.start(function()
|
||||
local standalone = skynet.getenv "standalone"
|
||||
|
||||
@@ -10,21 +10,23 @@ fd = tonumber(fd)
|
||||
|
||||
local large_request = {}
|
||||
local inquery_name = {}
|
||||
local register_name
|
||||
|
||||
local register_name_mt = { __index =
|
||||
function(self, name)
|
||||
local waitco = inquery_name[name]
|
||||
if waitco then
|
||||
local co=coroutine.running()
|
||||
local co = coroutine.running()
|
||||
table.insert(waitco, co)
|
||||
skynet.wait(co)
|
||||
return rawget(self, name)
|
||||
return rawget(register_name, name)
|
||||
else
|
||||
waitco = {}
|
||||
inquery_name[name] = waitco
|
||||
|
||||
local addr = skynet.call(clusterd, "lua", "queryname", name:sub(2)) -- name must be '@xxxx'
|
||||
if addr then
|
||||
self[name] = addr
|
||||
register_name[name] = addr
|
||||
end
|
||||
inquery_name[name] = nil
|
||||
for _, co in ipairs(waitco) do
|
||||
@@ -36,10 +38,9 @@ local register_name_mt = { __index =
|
||||
}
|
||||
|
||||
local function new_register_name()
|
||||
return setmetatable({}, register_name_mt)
|
||||
register_name = setmetatable({}, register_name_mt)
|
||||
end
|
||||
|
||||
local register_name = new_register_name()
|
||||
new_register_name()
|
||||
|
||||
local tracetag
|
||||
|
||||
@@ -130,14 +131,15 @@ skynet.start(function()
|
||||
dispatch = dispatch_request,
|
||||
}
|
||||
-- fd can write, but don't read fd, the data package will forward from gate though client protocol.
|
||||
skynet.call(gate, "lua", "forward", fd)
|
||||
-- forward may fail, see https://github.com/cloudwu/skynet/issues/1958
|
||||
pcall(skynet.call,gate, "lua", "forward", fd)
|
||||
|
||||
skynet.dispatch("lua", function(_,source, cmd, ...)
|
||||
if cmd == "exit" then
|
||||
socket.close_fd(fd)
|
||||
skynet.exit()
|
||||
elseif cmd == "namechange" then
|
||||
register_name = new_register_name()
|
||||
new_register_name()
|
||||
else
|
||||
skynet.error(string.format("Invalid command %s from %s", cmd, skynet.address(source)))
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ local wait_queue = {}
|
||||
local mode = {}
|
||||
|
||||
local function query(db, key, ...)
|
||||
if key == nil then
|
||||
if db == nil or key == nil then
|
||||
return db
|
||||
else
|
||||
return query(db[key], ...)
|
||||
|
||||
@@ -104,7 +104,13 @@ local function console_main_loop(stdin, print, addr)
|
||||
local cmdline = url:sub(2):gsub("/"," ")
|
||||
docmd(cmdline, print, stdin)
|
||||
break
|
||||
elseif cmdline:sub(1,5) == "POST " then
|
||||
-- http post
|
||||
local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(stdin, cmdline.. "\n"), 8192)
|
||||
docmd(body, print, stdin)
|
||||
break
|
||||
end
|
||||
|
||||
if cmdline ~= "" then
|
||||
docmd(cmdline, print, stdin)
|
||||
end
|
||||
@@ -166,6 +172,8 @@ function COMMAND.help()
|
||||
dumpheap = "dumpheap : dump heap profilling",
|
||||
killtask = "killtask address threadname : threadname listed by task",
|
||||
dbgcmd = "run address debug command",
|
||||
getenv = "getenv name : skynet.getenv(name)",
|
||||
setenv = "setenv name value: skynet.setenv(name,value)",
|
||||
}
|
||||
end
|
||||
|
||||
@@ -470,3 +478,12 @@ function COMMAND.profactive(flag)
|
||||
local active = memory.profactive()
|
||||
return "heap profilling is ".. (active and "active" or "deactive")
|
||||
end
|
||||
|
||||
function COMMAND.getenv(name)
|
||||
local value = skynet.getenv(name)
|
||||
return {[name]=tostring(value)}
|
||||
end
|
||||
|
||||
function COMMAND.setenv(name,value)
|
||||
return skynet.setenv(name,value)
|
||||
end
|
||||
|
||||
@@ -24,10 +24,12 @@ struct mem_data {
|
||||
};
|
||||
|
||||
struct mem_cookie {
|
||||
size_t size;
|
||||
uint32_t handle;
|
||||
#ifdef MEMORY_CHECK
|
||||
uint32_t dogtag;
|
||||
#endif
|
||||
uint32_t cookie_size; // should be the last
|
||||
};
|
||||
|
||||
#define SLOT_SIZE 0x10000
|
||||
@@ -86,37 +88,42 @@ update_xmalloc_stat_free(uint32_t handle, size_t __n) {
|
||||
}
|
||||
|
||||
inline static void*
|
||||
fill_prefix(char* ptr) {
|
||||
fill_prefix(char* ptr, size_t sz, uint32_t cookie_size) {
|
||||
uint32_t handle = skynet_current_handle();
|
||||
size_t size = je_malloc_usable_size(ptr);
|
||||
struct mem_cookie *p = (struct mem_cookie *)(ptr + size - sizeof(struct mem_cookie));
|
||||
memcpy(&p->handle, &handle, sizeof(handle));
|
||||
struct mem_cookie *p = (struct mem_cookie *)ptr;
|
||||
char * ret = ptr + cookie_size;
|
||||
p->size = sz;
|
||||
p->handle = handle;
|
||||
#ifdef MEMORY_CHECK
|
||||
uint32_t dogtag = MEMORY_ALLOCTAG;
|
||||
memcpy(&p->dogtag, &dogtag, sizeof(dogtag));
|
||||
p->dogtag = MEMORY_ALLOCTAG;
|
||||
#endif
|
||||
update_xmalloc_stat_alloc(handle, size);
|
||||
return ptr;
|
||||
update_xmalloc_stat_alloc(handle, sz);
|
||||
memcpy(ret - sizeof(uint32_t), &cookie_size, sizeof(cookie_size));
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline static uint32_t
|
||||
get_cookie_size(char *ptr) {
|
||||
uint32_t cookie_size;
|
||||
memcpy(&cookie_size, ptr - sizeof(cookie_size), sizeof(cookie_size));
|
||||
return cookie_size;
|
||||
}
|
||||
|
||||
inline static void*
|
||||
clean_prefix(char* ptr) {
|
||||
size_t size = je_malloc_usable_size(ptr);
|
||||
struct mem_cookie *p = (struct mem_cookie *)(ptr + size - sizeof(struct mem_cookie));
|
||||
uint32_t handle;
|
||||
memcpy(&handle, &p->handle, sizeof(handle));
|
||||
uint32_t cookie_size = get_cookie_size(ptr);
|
||||
struct mem_cookie *p = (struct mem_cookie *)(ptr - cookie_size);
|
||||
uint32_t handle = p->handle;
|
||||
#ifdef MEMORY_CHECK
|
||||
uint32_t dogtag;
|
||||
memcpy(&dogtag, &p->dogtag, sizeof(dogtag));
|
||||
uint32_t dogtag = p->dogtag;
|
||||
if (dogtag == MEMORY_FREETAG) {
|
||||
fprintf(stderr, "xmalloc: double free in :%08x\n", handle);
|
||||
}
|
||||
assert(dogtag == MEMORY_ALLOCTAG); // memory out of bounds
|
||||
dogtag = MEMORY_FREETAG;
|
||||
memcpy(&p->dogtag, &dogtag, sizeof(dogtag));
|
||||
p->dogtag = MEMORY_FREETAG;
|
||||
#endif
|
||||
update_xmalloc_stat_free(handle, size);
|
||||
return ptr;
|
||||
update_xmalloc_stat_free(handle, p->size);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void malloc_oom(size_t size) {
|
||||
@@ -185,17 +192,18 @@ void *
|
||||
skynet_malloc(size_t size) {
|
||||
void* ptr = je_malloc(size + PREFIX_SIZE);
|
||||
if(!ptr) malloc_oom(size);
|
||||
return fill_prefix(ptr);
|
||||
return fill_prefix(ptr, size, PREFIX_SIZE);
|
||||
}
|
||||
|
||||
void *
|
||||
skynet_realloc(void *ptr, size_t size) {
|
||||
if (ptr == NULL) return skynet_malloc(size);
|
||||
|
||||
uint32_t cookie_size = get_cookie_size(ptr);
|
||||
void* rawptr = clean_prefix(ptr);
|
||||
void *newptr = je_realloc(rawptr, size+PREFIX_SIZE);
|
||||
void *newptr = je_realloc(rawptr, size+cookie_size);
|
||||
if(!newptr) malloc_oom(size);
|
||||
return fill_prefix(newptr);
|
||||
return fill_prefix(newptr, size, cookie_size);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -206,31 +214,50 @@ skynet_free(void *ptr) {
|
||||
}
|
||||
|
||||
void *
|
||||
skynet_calloc(size_t nmemb,size_t size) {
|
||||
void* ptr = je_calloc(nmemb + ((PREFIX_SIZE+size-1)/size), size );
|
||||
if(!ptr) malloc_oom(size);
|
||||
return fill_prefix(ptr);
|
||||
skynet_calloc(size_t nmemb, size_t size) {
|
||||
uint32_t cookie_n = (PREFIX_SIZE+size-1)/size;
|
||||
void* ptr = je_calloc(nmemb + cookie_n, size);
|
||||
if(!ptr) malloc_oom(nmemb * size);
|
||||
return fill_prefix(ptr, nmemb * size, cookie_n * size);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
alignment_cookie_size(size_t alignment) {
|
||||
if (alignment >= PREFIX_SIZE)
|
||||
return alignment;
|
||||
switch (alignment) {
|
||||
case 4 :
|
||||
return (PREFIX_SIZE + 3) / 4 * 4;
|
||||
case 8 :
|
||||
return (PREFIX_SIZE + 7) / 8 * 8;
|
||||
case 16 :
|
||||
return (PREFIX_SIZE + 15) / 16 * 16;
|
||||
}
|
||||
return (PREFIX_SIZE + alignment - 1) / alignment * alignment;
|
||||
}
|
||||
|
||||
void *
|
||||
skynet_memalign(size_t alignment, size_t size) {
|
||||
void* ptr = je_memalign(alignment, size + PREFIX_SIZE);
|
||||
uint32_t cookie_size = alignment_cookie_size(alignment);
|
||||
void* ptr = je_memalign(alignment, size + cookie_size);
|
||||
if(!ptr) malloc_oom(size);
|
||||
return fill_prefix(ptr);
|
||||
return fill_prefix(ptr, size, cookie_size);
|
||||
}
|
||||
|
||||
void *
|
||||
skynet_aligned_alloc(size_t alignment, size_t size) {
|
||||
void* ptr = je_aligned_alloc(alignment, size + (size_t)((PREFIX_SIZE + alignment -1) & ~(alignment-1)));
|
||||
uint32_t cookie_size = alignment_cookie_size(alignment);
|
||||
void* ptr = je_aligned_alloc(alignment, size + cookie_size);
|
||||
if(!ptr) malloc_oom(size);
|
||||
return fill_prefix(ptr);
|
||||
return fill_prefix(ptr, size, cookie_size);
|
||||
}
|
||||
|
||||
int
|
||||
skynet_posix_memalign(void **memptr, size_t alignment, size_t size) {
|
||||
int err = je_posix_memalign(memptr, alignment, size + PREFIX_SIZE);
|
||||
uint32_t cookie_size = alignment_cookie_size(alignment);
|
||||
int err = je_posix_memalign(memptr, alignment, size + cookie_size);
|
||||
if (err) malloc_oom(size);
|
||||
fill_prefix(*memptr);
|
||||
fill_prefix(*memptr, size, cookie_size);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,7 @@ main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
_init_env(L);
|
||||
lua_close(L);
|
||||
|
||||
config.thread = optint("thread",8);
|
||||
config.module_path = optstring("cpath","./cservice/?.so");
|
||||
@@ -161,8 +162,6 @@ main(int argc, char *argv[]) {
|
||||
config.logservice = optstring("logservice", "logger");
|
||||
config.profile = optboolean("profile", 1);
|
||||
|
||||
lua_close(L);
|
||||
|
||||
skynet_start(&config);
|
||||
skynet_globalexit();
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ struct skynet_context {
|
||||
uint32_t handle;
|
||||
int session_id;
|
||||
ATOM_INT ref;
|
||||
int message_count;
|
||||
size_t message_count;
|
||||
bool init;
|
||||
bool endless;
|
||||
bool profile;
|
||||
@@ -118,7 +118,7 @@ drop_message(struct skynet_message *msg, void *ud) {
|
||||
uint32_t source = d->handle;
|
||||
assert(source);
|
||||
// report error to the message source
|
||||
skynet_send(NULL, source, msg->source, PTYPE_ERROR, 0, NULL, 0);
|
||||
skynet_send(NULL, source, msg->source, PTYPE_ERROR, msg->session, NULL, 0);
|
||||
}
|
||||
|
||||
struct skynet_context *
|
||||
@@ -574,7 +574,7 @@ cmd_stat(struct skynet_context * context, const char * param) {
|
||||
strcpy(context->result, "0");
|
||||
}
|
||||
} else if (strcmp(param, "message") == 0) {
|
||||
sprintf(context->result, "%d", context->message_count);
|
||||
sprintf(context->result, "%zu", context->message_count);
|
||||
} else {
|
||||
context->result[0] = '\0';
|
||||
}
|
||||
|
||||
@@ -180,6 +180,18 @@ skynet_socket_udp(struct skynet_context *ctx, const char * addr, int port) {
|
||||
return socket_server_udp(SOCKET_SERVER, source, addr, port);
|
||||
}
|
||||
|
||||
int
|
||||
skynet_socket_udp_dial(struct skynet_context *ctx, const char * addr, int port){
|
||||
uint32_t source = skynet_context_handle(ctx);
|
||||
return socket_server_udp_dial(SOCKET_SERVER, source, addr, port);
|
||||
}
|
||||
|
||||
int
|
||||
skynet_socket_udp_listen(struct skynet_context *ctx, const char * addr, int port){
|
||||
uint32_t source = skynet_context_handle(ctx);
|
||||
return socket_server_udp_listen(SOCKET_SERVER, source, addr, port);
|
||||
}
|
||||
|
||||
int
|
||||
skynet_socket_udp_connect(struct skynet_context *ctx, int id, const char * addr, int port) {
|
||||
return socket_server_udp_connect(SOCKET_SERVER, id, addr, port);
|
||||
|
||||
@@ -40,6 +40,8 @@ void skynet_socket_nodelay(struct skynet_context *ctx, int id);
|
||||
|
||||
int skynet_socket_udp(struct skynet_context *ctx, const char * addr, int port);
|
||||
int skynet_socket_udp_connect(struct skynet_context *ctx, int id, const char * addr, int port);
|
||||
int skynet_socket_udp_dial(struct skynet_context *ctx, const char * addr, int port);
|
||||
int skynet_socket_udp_listen(struct skynet_context *ctx, const char * addr, int port);
|
||||
int skynet_socket_udp_sendbuffer(struct skynet_context *ctx, const char * address, struct socket_sendbuffer *buffer);
|
||||
const char * skynet_socket_udp_address(struct skynet_socket_message *, int *addrsz);
|
||||
|
||||
|
||||
@@ -190,22 +190,30 @@ struct request_udp {
|
||||
uintptr_t opaque;
|
||||
};
|
||||
|
||||
struct request_dial_udp {
|
||||
int id;
|
||||
int fd;
|
||||
uintptr_t opaque;
|
||||
uint8_t address[UDP_ADDRESS_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
The first byte is TYPE
|
||||
|
||||
S Start socket
|
||||
R Resume socket
|
||||
S Pause socket
|
||||
B Bind socket
|
||||
L Listen socket
|
||||
K Close socket
|
||||
O Connect to (Open)
|
||||
X Exit
|
||||
X Exit socket thread
|
||||
W Enable write
|
||||
D Send package (high)
|
||||
P Send package (low)
|
||||
A Send UDP package
|
||||
C set udp address
|
||||
N client dial to UDP host port
|
||||
T Set opt
|
||||
U Create UDP socket
|
||||
C set udp address
|
||||
Q query info
|
||||
*/
|
||||
|
||||
struct request_package {
|
||||
@@ -222,6 +230,7 @@ struct request_package {
|
||||
struct request_setopt setopt;
|
||||
struct request_udp udp;
|
||||
struct request_setudp set_udp;
|
||||
struct request_dial_udp dial_udp;
|
||||
} u;
|
||||
uint8_t dummy[256];
|
||||
};
|
||||
@@ -1329,6 +1338,30 @@ set_udp_address(struct socket_server *ss, struct request_setudp *request, struct
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
dial_udp_socket(struct socket_server *ss, struct request_dial_udp *request, struct socket_message *result){
|
||||
int id = request->id;
|
||||
int protocol = request->address[0];
|
||||
|
||||
struct socket *ns = new_fd(ss, id, request->fd, protocol, request->opaque, true);
|
||||
if (ns == NULL){
|
||||
close(request->fd);
|
||||
ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (protocol == PROTOCOL_UDP){
|
||||
memcpy(ns->p.udp_address, request->address, 1 + 2 + 4);
|
||||
} else {
|
||||
memcpy(ns->p.udp_address, request->address, 1 + 2 + 16);
|
||||
}
|
||||
|
||||
ATOM_STORE(&ns->type , SOCKET_TYPE_CONNECTED);
|
||||
|
||||
ATOM_FDEC(&ns->udpconnecting);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
inc_sending_ref(struct socket *s, int id) {
|
||||
if (s->protocol != PROTOCOL_TCP)
|
||||
@@ -1408,6 +1441,8 @@ ctrl_cmd(struct socket_server *ss, struct socket_message *result) {
|
||||
}
|
||||
case 'C':
|
||||
return set_udp_address(ss, (struct request_setudp *)buffer, result);
|
||||
case 'N':
|
||||
return dial_udp_socket(ss, (struct request_dial_udp *)buffer, result);
|
||||
case 'T':
|
||||
setopt_socket(ss, (struct request_setopt *)buffer);
|
||||
return -1;
|
||||
@@ -2115,6 +2150,92 @@ socket_server_udp(struct socket_server *ss, uintptr_t opaque, const char * addr,
|
||||
return id;
|
||||
}
|
||||
|
||||
int
|
||||
socket_server_udp_listen(struct socket_server *ss, uintptr_t opaque, const char* addr, int port){
|
||||
int fd;
|
||||
if (port == 0){
|
||||
return -1;
|
||||
}
|
||||
|
||||
int family;
|
||||
// bind
|
||||
fd = do_bind(addr, port, IPPROTO_UDP, &family);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp_nonblocking(fd);
|
||||
|
||||
int id = reserve_id(ss);
|
||||
if (id < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
struct request_package request;
|
||||
request.u.udp.id = id;
|
||||
request.u.udp.fd = fd;
|
||||
request.u.udp.opaque = opaque;
|
||||
request.u.udp.family = family;
|
||||
|
||||
send_request(ss, &request, 'U', sizeof(request.u.udp));
|
||||
return id;
|
||||
}
|
||||
|
||||
int
|
||||
socket_server_udp_dial(struct socket_server *ss, uintptr_t opaque, const char* addr, int port){
|
||||
int status;
|
||||
struct addrinfo ai_hints;
|
||||
struct addrinfo *ai_list = NULL;
|
||||
char portstr[16];
|
||||
sprintf(portstr, "%d", port);
|
||||
memset( &ai_hints, 0, sizeof( ai_hints ) );
|
||||
ai_hints.ai_family = AF_UNSPEC;
|
||||
ai_hints.ai_socktype = SOCK_DGRAM;
|
||||
ai_hints.ai_protocol = IPPROTO_UDP;
|
||||
|
||||
|
||||
status = getaddrinfo(addr, portstr, &ai_hints, &ai_list );
|
||||
if ( status != 0 ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int protocol;
|
||||
|
||||
if (ai_list->ai_family == AF_INET) {
|
||||
protocol = PROTOCOL_UDP;
|
||||
} else if (ai_list->ai_family == AF_INET6) {
|
||||
protocol = PROTOCOL_UDPv6;
|
||||
} else {
|
||||
freeaddrinfo( ai_list );
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = socket(ai_list->ai_family, SOCK_DGRAM, 0);
|
||||
if (fd < 0){
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp_nonblocking(fd);
|
||||
int id = reserve_id(ss);
|
||||
if (id < 0){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct request_package request;
|
||||
request.u.dial_udp.id = id;
|
||||
request.u.dial_udp.fd = fd;
|
||||
request.u.dial_udp.opaque = opaque;
|
||||
|
||||
|
||||
int addrsz = gen_udp_address(protocol, (union sockaddr_all *)ai_list->ai_addr, request.u.dial_udp.address);
|
||||
|
||||
freeaddrinfo( ai_list );
|
||||
|
||||
send_request(ss, &request, 'N', sizeof(request.u.dial_udp) - sizeof(request.u.dial_udp.address) + addrsz);
|
||||
return id;
|
||||
}
|
||||
|
||||
int
|
||||
socket_server_udp_send(struct socket_server *ss, const struct socket_udp_address *addr, struct socket_sendbuffer *buf) {
|
||||
int id = buf->id;
|
||||
|
||||
@@ -57,6 +57,12 @@ struct socket_udp_address;
|
||||
int socket_server_udp(struct socket_server *, uintptr_t opaque, const char * addr, int port);
|
||||
// set default dest address, return 0 when success
|
||||
int socket_server_udp_connect(struct socket_server *, int id, const char * addr, int port);
|
||||
|
||||
// create an udp client socket handle, and connect to server addr, return id when success
|
||||
int socket_server_udp_dial(struct socket_server *ss, uintptr_t opaque, const char* addr, int port);
|
||||
// create an udp server socket handle, and bind the host port, return id when success
|
||||
int socket_server_udp_listen(struct socket_server *ss, uintptr_t opaque, const char* addr, int port);
|
||||
|
||||
// If the socket_udp_address is NULL, use last call socket_server_udp_connect address instead
|
||||
// You can also use socket_server_send
|
||||
int socket_server_udp_send(struct socket_server *, const struct socket_udp_address *, struct socket_sendbuffer *buffer);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
local skynet = require "skynet"
|
||||
local httpc = require "http.httpc"
|
||||
local httpurl = require "http.url"
|
||||
local dns = require "skynet.dns"
|
||||
|
||||
local function http_test(protocol)
|
||||
@@ -44,11 +45,25 @@ local function http_head_test()
|
||||
end
|
||||
end
|
||||
|
||||
local function http_url_test()
|
||||
local url = "http://baidu.com/get?k1=1&k2=2&k4=a%20space&k5=b%20space&k5=b%20space&k5=b%20space"
|
||||
local path, query = httpurl.parse(url)
|
||||
print("url", path, query)
|
||||
local qret = httpurl.parse_query(query)
|
||||
for k, v in pairs(qret) do
|
||||
print(k, v)
|
||||
end
|
||||
assert(#qret["k5"] == 3)
|
||||
assert(qret[1] == qret[2])
|
||||
assert(qret[1] == qret[3])
|
||||
end
|
||||
|
||||
local function main()
|
||||
dns.server()
|
||||
|
||||
http_stream_test()
|
||||
http_head_test()
|
||||
http_url_test()
|
||||
|
||||
http_test("http")
|
||||
if not pcall(require,"ltls.c") then
|
||||
|
||||
@@ -7,6 +7,11 @@ if port then
|
||||
port = math.tointeger(port)
|
||||
end
|
||||
|
||||
host = '127.0.0.1'
|
||||
port = 27017
|
||||
username = "admin"
|
||||
password = 123456
|
||||
db_name = "admin"
|
||||
-- print(host, port, db_name, username, password)
|
||||
|
||||
local function _create_client()
|
||||
@@ -19,7 +24,7 @@ local function _create_client()
|
||||
)
|
||||
end
|
||||
|
||||
function test_auth()
|
||||
local function test_auth()
|
||||
local ok, err, ret
|
||||
local c = mongo.client(
|
||||
{
|
||||
@@ -39,7 +44,7 @@ function test_auth()
|
||||
assert(ok and ret and ret.n == 1, err)
|
||||
end
|
||||
|
||||
function test_insert_without_index()
|
||||
local function test_insert_without_index()
|
||||
local ok, err, ret
|
||||
local c = _create_client()
|
||||
local db = c[db_name]
|
||||
@@ -54,7 +59,7 @@ function test_insert_without_index()
|
||||
assert(ok and ret and ret.n == 1, err)
|
||||
end
|
||||
|
||||
function test_insert_with_index()
|
||||
local function test_insert_with_index()
|
||||
local ok, err, ret
|
||||
local c = _create_client()
|
||||
local db = c[db_name]
|
||||
@@ -71,7 +76,7 @@ function test_insert_with_index()
|
||||
assert(ok == false and string.find(err, "duplicate key error"))
|
||||
end
|
||||
|
||||
function test_find_and_remove()
|
||||
local function test_find_and_remove()
|
||||
local ok, err, ret
|
||||
local c = _create_client()
|
||||
local db = c[db_name]
|
||||
@@ -117,7 +122,7 @@ function test_find_and_remove()
|
||||
assert(ret == nil)
|
||||
end
|
||||
|
||||
function test_runcommand()
|
||||
local function test_runcommand()
|
||||
local ok, err, ret
|
||||
local c = _create_client()
|
||||
local db = c[db_name]
|
||||
@@ -148,7 +153,7 @@ function test_runcommand()
|
||||
assert(ret and ret.cursor.firstBatch[1].test_key2_total == 6)
|
||||
end
|
||||
|
||||
function test_expire_index()
|
||||
local function test_expire_index()
|
||||
local ok, err, ret
|
||||
local c = _create_client()
|
||||
local db = c[db_name]
|
||||
@@ -221,6 +226,26 @@ local function test_safe_batch_delete()
|
||||
assert((length - del_num) == ret:count(), "test safe batch delete failed")
|
||||
end
|
||||
|
||||
local function test_safe_update()
|
||||
local ok, err, ret
|
||||
local c = _create_client()
|
||||
local db = c[db_name]
|
||||
|
||||
db.testcoll:drop()
|
||||
|
||||
db.testcoll:safe_insert({test_key = 100, test_value = "hello mongo"})
|
||||
|
||||
db.testcoll:ensureIndex({test_key = 1}, {unique = true, name = "test_key_index"})
|
||||
|
||||
local query = {test_key = 100}
|
||||
local update = {test_value = "hi mongo"}
|
||||
ok, err = db.testcoll:safe_update(query, {['$set'] = update})
|
||||
assert(ok, err)
|
||||
|
||||
ret = db.testcoll:findOne(query)
|
||||
assert(ret.test_value == "hi mongo")
|
||||
end
|
||||
|
||||
skynet.start(function()
|
||||
if username then
|
||||
print("Test auth")
|
||||
@@ -240,5 +265,7 @@ skynet.start(function()
|
||||
test_safe_batch_insert()
|
||||
print("test safe batch delete")
|
||||
test_safe_batch_delete()
|
||||
print("test_safe_update")
|
||||
test_safe_update()
|
||||
print("mongodb test finish.");
|
||||
end)
|
||||
|
||||
@@ -4,14 +4,14 @@ local socket = require "skynet.socket"
|
||||
local function server()
|
||||
local host
|
||||
host = socket.udp(function(str, from)
|
||||
print("server recv", str, socket.udp_address(from))
|
||||
print("server v4 recv", str, socket.udp_address(from))
|
||||
socket.sendto(host, from, "OK " .. str)
|
||||
end , "127.0.0.1", 8765) -- bind an address
|
||||
end
|
||||
|
||||
local function client()
|
||||
local c = socket.udp(function(str, from)
|
||||
print("client recv", str, socket.udp_address(from))
|
||||
print("client v4 recv", str, socket.udp_address(from))
|
||||
end)
|
||||
socket.udp_connect(c, "127.0.0.1", 8765)
|
||||
for i=1,20 do
|
||||
@@ -19,7 +19,30 @@ local function client()
|
||||
end
|
||||
end
|
||||
|
||||
local function server_v6()
|
||||
local server
|
||||
server = socket.udp_listen("::1", 8766, function(str, from)
|
||||
print(string.format("server_v6 recv str:%s from:%s", str, socket.udp_address(from)))
|
||||
socket.sendto(server, from, "OK " .. str)
|
||||
end) -- bind an address
|
||||
print("create server succeed. "..server)
|
||||
return server
|
||||
end
|
||||
|
||||
local function client_v6()
|
||||
local c = socket.udp_dial("::1", 8766, function(str, from)
|
||||
print(string.format("client recv v6 response str:%s from:%s", str, socket.udp_address(from)))
|
||||
end)
|
||||
|
||||
print("create client succeed. "..c)
|
||||
for i=1,20 do
|
||||
socket.write(c, "hello " .. i) -- write to the address by udp_connect binding
|
||||
end
|
||||
end
|
||||
|
||||
skynet.start(function()
|
||||
skynet.fork(server)
|
||||
skynet.fork(client)
|
||||
skynet.fork(server_v6)
|
||||
skynet.fork(client_v6)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user