Compare commits

...

62 Commits

Author SHA1 Message Date
Cloud Wu
ba64be6f9f Update history for v1.8.0 release 2025-01-14 09:50:26 +08:00
Jason N. White
e1c28ed13e Update LICENSE, fix license year (#2021)
Signed-off-by: JasonnnW3000 <sufssl04@gmail.com>
2025-01-01 08:53:34 +08:00
华仔
474f04e864 fix socketchannel closed thread not wakeup (#2020) 2024-12-30 21:26:40 +08:00
sundream
7c3942cdbd fix(rediscluster): maybe too many connection when MOVED (#2016) 2024-12-29 09:24:21 +08:00
navi
88df42a60f fix message数量过多导致int溢出 (#2014)
Co-authored-by: 角弓 <jiaogong.lzh@alibaba-inc.com>
2024-12-26 17:29:48 +08:00
851773277
cada3f5cb0 datacenterd query接口查询时,当db为nil时,终止递归 (#2006) 2024-12-09 19:51:37 +08:00
华仔
2fc8e86925 fix websocket accept mem leakage (#2002)
* fix websocket accept mem leakage

* fix websocket accept mem leakage

* fix websocket accept mem leakage

* fix websocket accept mem leakage
2024-12-07 15:20:19 +08:00
华仔
4c8d42153e throw it out err (#2003) 2024-12-06 17:23:42 +08:00
Bob Conan
b5403a6866 Updated HISTORY.md, fix typo(s) (#1999) 2024-11-16 07:34:04 +08:00
lcw4u
270ed6e198 fix: 调整一个错误描述 (#1991) 2024-10-24 09:40:49 +08:00
JulyWind
8900360fab fix client recv_package (#1977) 2024-09-14 17:37:01 +08:00
b1bb84ddbd 去除语法检查告警 (#1973)
* Update loader.lua去除语法检查告警

* Update mysql.lua去除语法检查告警
2024-08-30 12:33:30 +08:00
huojicha
839570ce3f 1.提供支持ipv6的udp client和server接口, 可支持ipv6 (#1967)
* 1.提供支持ipv6的udp client和server接口, 可支持ipv6

* remove chinese comments
2024-08-08 02:34:15 +08:00
bcf97ecd1b debug_console help命令增加getenv,setenv信息 (#1966) 2024-08-07 14:14:04 +08:00
4dfdeb146e debug_console增加getenv,setenv命令 (#1965)
方便获取配置文件中信息
2024-08-07 11:59:27 +08:00
76d73c295f debug_console 增加http post,避免get url转义问题 (#1964)
增加http post,避免get url转义问题
2024-08-07 10:54:03 +08:00
zhuilang
c2b391ed42 Update httpc.lua (#1962) 2024-07-27 00:42:15 +08:00
89372a257d https set extension:server_name (#1960)
Co-authored-by: root <root@DESKTOP-5DF4NN3.localdomain>
2024-07-24 11:55:05 +08:00
Cloud Wu
b519c53fe4 Try to fix #1958 2024-07-22 00:52:19 +08:00
Bruce
027e599037 Avoid different function declarations when build as windows DLL (#1959) 2024-07-21 07:45:21 +08:00
hong
2cfe36a809 refix register_name_mt (#1954) 2024-07-06 12:59:33 +08:00
hong
059fd5cc00 new_register_name() (#1949) 2024-06-28 05:32:01 +08:00
Cloud Wu
64a0ed4bfa Try to fix #1948 2024-06-27 08:31:30 +08:00
Cloud Wu
41928512f0 Use getshrstr() 2024-06-26 13:05:27 +08:00
Cloud Wu
afb50a0587 update lua 5.4.7 2024-06-26 08:41:59 +08:00
Cloud Wu
aa20f7642b cleanup 2024-06-24 23:15:20 +08:00
anonymou3
f214c68ff3 The listen function supports passing backlog parameters (#1941)
Co-authored-by: anonymou3 <anonymou3>
2024-06-24 07:21:49 +08:00
华仔
dc1980dfc8 fix attempt to concatenate a nil value (local timeout) (#1936) 2024-06-24 07:21:49 +08:00
mippo520
ccd923c44f skynet.wait中使用的session增加回绕判断 (#1931)
* skynet.wait中使用的session增加回绕判断

* 去除session判空

---------

Co-authored-by: mippo <hui.zeng@centurygame.com>
2024-06-24 07:21:49 +08:00
King
c226ea3f1f 修复打开DEBUG_LOG时,编译错误 (#1922) 2024-06-24 07:21:49 +08:00
华仔
45b407481d fix socketchannel mem leakage (#1921) 2024-06-24 07:21:49 +08:00
Ikko Eltociear Ashimine
8f7e9cc823 docs: update README.md (#1908)
sumbit -> submit
2024-06-24 07:21:49 +08:00
Cloud Wu
89a821ced0 Avoid to use je_malloc_usable_size, See #1907 2024-06-24 07:21:31 +08:00
yzj12138
267e4ad44d skynet使用原生error,防止给替换 (#1906)
Co-authored-by: xingfan.yzj <xingfan.yzj@alibaba-inc.com>
2024-05-09 18:06:47 +08:00
chengf2018
1a0041982b fix annotation (#1903) 2024-04-24 10:16:17 +08:00
t0350
caf513e6c0 make task/uniqtask consistent (#1902) 2024-04-23 15:32:36 +08:00
华仔
18a6dc5786 typo rename faild to failed (#1901) 2024-04-10 13:51:03 +08:00
华仔
22df64244a 优化http出错抛出更详细的错误信息 (#1900)
* 优化http出错抛出更详细的错误信息

* 优化http err_info写法
2024-04-10 13:40:41 +08:00
yzj12138
1d47bfa0b6 session或者source为0时不回消息 (#1897)
Co-authored-by: xingfan.yzj <xingfan.yzj@alibaba-inc.com>
2024-04-09 10:01:46 +08:00
华仔
43225367fb fix websocket客户端连接过程中握手失败导致内存泄漏 (#1899)
* fix word err

* fix word err

* 增加mongo update 测试

* remove unused local variable

* fix websocket客户端连接过程中握手失败导致内存泄漏
2024-04-08 16:36:11 +08:00
iamwlj
cde8f75d68 Update bootstrap.lua (#1891)
1. local var `harbor' not used
2.
`
local skynet = require "skynet"
require "skynet.manager"
`
can be simplified as `local skynet = require "skynet.manager"`
2024-03-18 22:54:39 +08:00
iamwlj
9fd43778e2 Update skynet_main.c (#1890)
Putting the relevant code together makes it easier to understand
2024-03-18 18:58:54 +08:00
iamwlj
72688f5771 Update msgserver.lua (#1889)
使用本地变量,不然本地变量`request_handler`未使用
2024-03-18 18:54:12 +08:00
zhuilang
3bbb62e673 Update mongo.lua (#1884) 2024-03-07 19:20:51 +08:00
zhuilang
c18f99eb7e mongodb 查询增加 maxTimeMS (#1882)
* 查询增加 maxTimeMS

* Update mongo.lua
2024-03-07 10:13:22 +08:00
coldskycoldsky
bd5f12b959 fix: 当 mysql 数据库日期类型(timestamp, datetime)的字段,数据值没有 "时间部分(时分秒)" 时,比如 "2019-01-01" (#1879)
数据的长度是4(年2,月1, 日1),
而不是预期的7(年2,月1, 日1, 时1, 分1, 秒1)
2024-03-01 14:08:27 +08:00
emmanuel
267cf5384c Update README.md (#1870) 2024-02-13 09:20:44 +08:00
zhuilang
6f24b08f02 mongo 支持 hint (#1865)
* mongo 支持 hint

mongodb查询有时不会命中最优索引,所以支持下 hint 使用
2024-02-02 15:58:57 +08:00
华仔
d0b11c7955 remove unused local variable (#1864)
* fix word err

* fix word err

* 增加mongo update 测试

* remove unused local variable
2024-01-31 10:57:26 +08:00
t0350
6bdc8b8608 bugfix, parsing http array form (#1852) 2024-01-12 18:10:36 +08:00
华仔
b309d82538 fix word err (#1848)
* fix word err

* fix word err

* 增加mongo update 测试
2024-01-06 16:38:14 +08:00
华仔
fb97668f9e fix word err (#1847) 2024-01-03 20:05:28 +08:00
yzj12138
9e000da81f 修复执行skynet.exit后别的服务call有概率卡死 (#1846)
Co-authored-by: xingfan.yzj <xingfan.yzj@alibaba-inc.com>
2024-01-03 18:14:17 +08:00
Cloud Wu
d9c30f9119 fix #1845 2023-12-27 21:02:25 +08:00
robot
4030687400 在进行https握手时,会有小概率在进行密钥协商前,tcp流卡住,导至不能有效timeout行为 (#1842) 2023-12-20 13:07:38 +08:00
Zoro
1f93f4864f fix write_handshake (#1841)
Signed-off-by: zorocn <mengzust@gmail.com>
2023-12-14 21:04:43 +08:00
子熏
e66e892ee5 fix read_handshake (#1839)
Co-authored-by: zixun <lb151450@alibaba-inc.com>
2023-12-13 11:53:08 +08:00
kuzhu
30d967ea05 add get_sender function to outside (#1832)
* add get_sender function to outside

目的是用sender结合skynet.select的超时特性,实现一个超时的cluster.call,所以希望这里能够把get_sender的接口加上

* Update cluster.lua

改为cluster.get_sender = get_sender
2023-12-04 16:28:30 +08:00
felove
4b0937cc19 修复mysql.execute的变长参数最后一个为nil时的NULL位图错误 (#1829)
Co-authored-by: wfl <felove_2008@qq.com>
2023-12-01 11:28:59 +08:00
zhuilang
89b47f9372 modify httpc.request (#1823)
* modify httpc.request

这样可能更好点

* modify httpc.request
2023-11-17 19:49:42 +08:00
zhuilang
6249062c2d Update httpc.request (#1822) 2023-11-15 22:11:24 +08:00
Cloud Wu
8b5bbaabd9 Update lua version number 2023-11-13 15:17:02 +08:00
74 changed files with 1012 additions and 407 deletions

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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 },

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 */
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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},

View File

@@ -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)))

View File

@@ -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.

View File

@@ -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)));
}

View File

@@ -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)
/* }================================================================== */

View File

@@ -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] := {} */

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 "-"
/* }================================================================== */

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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()

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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 },

View File

@@ -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

View File

@@ -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 = {}

View File

@@ -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 = {}

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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, "(.*/)[^/?]+$")

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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"

View File

@@ -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

View File

@@ -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], ...)

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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';
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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)

View File

@@ -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)