Compare commits

...

116 Commits

Author SHA1 Message Date
Cloud Wu
fd1b230a54 1.0.0 rc5 2016-07-04 16:31:58 +08:00
Cloud Wu
33321e89a1 don't launch console service when in daemon mode 2016-06-28 18:31:12 +08:00
云风
b50e663a3a Merge pull request #525 from zxfishhack/master
auto determine primary host
2016-06-27 11:39:15 +08:00
zxfishhack
14a699cb85 auto determine primary host 2016-06-27 10:59:50 +08:00
Cloud Wu
098d44162b bson support meta array 2016-06-23 16:14:16 +08:00
Cloud Wu
16af94795e lua 5.3.3 bugfix 1 2016-06-22 22:28:54 +08:00
云风
00f41c6bc9 Merge pull request #521 from ahuang007/patch-1
Update lua-crypt.c
2016-06-21 15:37:56 +08:00
ahuang007
0465688403 Update lua-crypt.c
这个地方应该用G
2016-06-21 15:25:08 +08:00
Cloud Wu
8cd5834d28 Merge branch 'master' of github.com:cloudwu/skynet 2016-06-17 12:19:56 +08:00
Cloud Wu
040089639f memory leak bugfix in multicast, See issue #519 2016-06-17 12:17:53 +08:00
云风
81c4e47a6d Merge pull request #517 from cloudwu/mongoauth
Add mongo auth_scram_sha1 , See pr #492
2016-06-16 09:47:03 +08:00
Cloud Wu
2aef994aa4 add authmod in conf 2016-06-15 17:58:58 +08:00
Cloud Wu
ffa2bbf1e4 support mongo auth_scram_sha1 2016-06-15 16:49:58 +08:00
Cloud Wu
6a54fe8293 1.0.0 rc4 2016-06-13 15:13:17 +08:00
Cloud Wu
2020ce3c9c update jemalloc to 4.2.1 2016-06-13 15:08:33 +08:00
云风
2557559d5c Merge pull request #512 from cloudwu/createindex
add createindexes , for detail see pr #511
2016-06-13 13:12:57 +08:00
Cloud Wu
bb0143e476 add some assert 2016-06-13 12:29:01 +08:00
Cloud Wu
fd2c814fe0 default key ascending 2016-06-13 12:13:02 +08:00
Cloud Wu
bd3d9b70ec change arg name 2016-06-13 12:05:52 +08:00
Cloud Wu
ee1a218870 typo 2016-06-13 12:01:54 +08:00
Cloud Wu
84ee3da79a add mongo.createIndexs, and fix the bug in old API createIndex. For detail, see PR #511 2016-06-13 11:55:31 +08:00
云风
fdee7de36d Merge pull request #509 from dpull/master
重新设计debug.lua接口
2016-06-12 16:41:18 +08:00
dpull
bf5b74b6ca 重新设计debug.lua接口 2016-06-12 16:29:47 +08:00
Cloud Wu
d9b0347741 don't close fd twice 2016-06-12 15:07:56 +08:00
Cloud Wu
9546537256 debug console support simple http 2016-06-12 14:51:18 +08:00
Cloud Wu
f84fe84b96 update userlog 2016-06-12 13:48:53 +08:00
Cloud Wu
ea9bc53261 reopen log file when recv signal HUP 2016-06-12 13:40:23 +08:00
Cloud Wu
0edb839c95 Lua 5.3.3 released 2016-06-07 09:43:43 +08:00
Cloud Wu
b8bb327f98 make coroutine_pool weak would be better 2016-06-06 16:23:39 +08:00
cloudwu
27d69334ee Merge pull request #506 from rickone/master
Update socketchannel.lua
2016-06-05 01:07:42 +08:00
rickone
838e63ab62 Update socketchannel.lua
request的时候可能会连接失败,这时raise的不是socket_error,上层处理不太统一。
2016-06-04 16:26:07 +08:00
Cloud Wu
ba264700dc update jemalloc to 4.2.0 2016-05-31 09:36:21 +08:00
Cloud Wu
e00ad7ab79 update to lua 5.3.3 rc3 2016-05-31 09:30:21 +08:00
Cloud Wu
de176b735f update to lua 5.3.3 rc2 2016-05-19 13:16:19 +08:00
cloudwu
cc3e985834 Merge pull request #502 from pigparadise/cloudwu
lua_bson的encode方法增加对有自定义__pairs的table的支持
2016-05-19 13:19:21 +08:00
LiuYang
3b5f45eea2 lua_bson的encode方法增加对有自定义__pairs的table的支持 2016-05-19 13:10:33 +08:00
cloudwu
c3056b04c1 Merge pull request #498 from asanosoyokaze/patch-1
add vararg for INFO debug console command
2016-05-16 19:35:02 +08:00
David Feng
58755a6772 add vararg for INFO debug console command 2016-05-16 18:57:40 +08:00
Cloud Wu
1cf976c4e4 add debug console command : ping 2016-05-13 09:46:44 +08:00
Cloud Wu
5be836527c bugfix issue #494 2016-05-11 22:02:10 +08:00
Cloud Wu
e9f397945d bugfix issue #494 2016-05-10 16:59:34 +08:00
Cloud Wu
78df0b8161 refine code 2016-05-09 19:16:29 +08:00
cloudwu
db17245005 Merge pull request #493 from chenkete/master
修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败
2016-05-09 19:17:56 +08:00
chenkete
4edb586077 修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败 2016-05-09 17:16:37 +08:00
Cloud Wu
ed1a8313f4 1.0.0 rc3 2016-05-09 10:06:32 +08:00
Cloud Wu
c450b7b5d7 update jemaloc to 4.1.1 2016-05-09 09:56:30 +08:00
Cloud Wu
56846b7dda new script to check deadloop service 2016-05-09 09:47:01 +08:00
Cloud Wu
fb232cc43e update lua to 5.3.3 rc1 2016-05-09 09:45:40 +08:00
Cloud Wu
a5c79cc4bd move skynet.memlimit from skynet.manager to skynet 2016-05-07 09:23:01 +08:00
Cloud Wu
4b96ade660 support sandbox memory limit 2016-05-06 23:40:44 +08:00
Cloud Wu
76d1e6fa1f memory warning 2016-05-06 20:37:51 +08:00
Cloud Wu
a6299a0748 optimize skynet.error 2016-05-06 20:10:11 +08:00
Cloud Wu
6cc558bb82 output Exit when new service exit 2016-05-06 19:45:50 +08:00
Cloud Wu
84b08bf286 detect console fd closed 2016-05-06 19:37:16 +08:00
Cloud Wu
4ada09b93c add pcall in launcher 2016-05-06 14:06:38 +08:00
Cloud Wu
2862568eca typo in history 2016-04-29 16:25:12 +08:00
cloudwu
ed2e16a346 Merge pull request #491 from asanosoyokaze/patch-go
skynet.pcall support vararg; sharedata loader can use custom args
2016-04-27 21:44:59 +08:00
David Feng
45d46b9072 skynet.pcall support vararg; sharedata loader can use custom args 2016-04-27 20:53:05 +08:00
Cloud Wu
4924c6d30b Merge branch 'master' of github.com:cloudwu/skynet 2016-04-20 22:35:29 +08:00
Cloud Wu
6b2eb80188 fix #487 2016-04-20 22:35:01 +08:00
cloudwu
298e4baf0e Merge pull request #485 from dpull/patch-1
给dbgcmd增加扩展性
2016-04-20 10:24:54 +08:00
Cloud Wu
c5fb93823a update sproto, fix bug in sproto.default 2016-04-20 10:11:55 +08:00
Acai
f238113677 给dbgcmd增加扩展性
我们项目增加了一个dbgcmd的指令,主要用于热更新,但在升级skynet版本时,需要记得合并这个差异,感觉挺挫的。

但现有的debug.lua并不利于扩展,于是呢,我想通过给debug.lua增加一个upvalue来解决这个问题。

其实也是解决的挺挫的 :)
2016-04-19 21:11:31 +08:00
Cloud Wu
f56d777cc2 for compatible 2016-04-18 12:05:46 +08:00
Cloud Wu
b124d4c1b8 skynet.getenv can return empty string 2016-04-18 11:55:39 +08:00
cloudwu
4fe098713f Merge pull request #483 from t0350/master
bugfix, error when use lua apicheck
2016-04-08 10:34:45 +08:00
caijietao
146f8ea09d bugfix, error when use lua apicheck 2016-04-08 10:29:34 +08:00
Cloud Wu
69b5bd8c13 update sproto. support encode empty table 2016-04-07 10:12:30 +08:00
cloudwu
dd7e962c94 Merge pull request #480 from rickone/master
Update redis.lua
2016-04-01 14:33:10 +08:00
rickone
5332021086 Update redis.lua
exec执行时其中一条出错,看不到错误信息
2016-04-01 12:39:09 +08:00
Cloud Wu
8de3149485 request global name from master, see issue #476 2016-04-01 10:22:57 +08:00
cloudwu
e3fee604e1 Merge pull request #478 from xjdrew/skynet_init
skynet.init按照顺序初始化
2016-03-31 17:51:29 +08:00
xjdrew
dd152fc910 skynet.init按照顺序初始化 2016-03-31 17:33:47 +08:00
Cloud Wu
c4b45acae3 sproto: check args 2016-03-29 12:34:55 +08:00
cloudwu
cf50a582f2 Merge pull request #474 from felixonmars/patch-1
Improve some English in README
2016-03-24 17:53:00 +08:00
Felix Yan
ca5e855c34 Improve some English in README 2016-03-24 17:48:43 +08:00
Cloud Wu
13d1d9fc9d update jemalloc to 4.1.0 2016-03-24 16:29:00 +08:00
Cloud Wu
242ff32bca lua 5.3.2 bugfix 2/3 2016-03-24 16:19:06 +08:00
cloudwu
ba451c1cd2 Merge pull request #465 from mrvon/master
skynet.coroutine
2016-03-11 15:28:56 +08:00
dennis
e5490522ce this line is useless 2016-03-09 17:50:33 +08:00
dennis
ae717c3e7d Merge remote-tracking branch 'upstream/master' 2016-03-09 17:48:16 +08:00
cloudwu
1a7df9108a Merge pull request #463 from great90/master
delete unused local variable
2016-03-08 11:34:25 +08:00
great90
7771e180ec delete unused local variable
delete unused local variable table "udp_socket"
2016-03-08 11:25:59 +08:00
great90
82bbb1c944 Merge pull request #3 from cloudwu/master
release rc2
2016-03-08 11:21:18 +08:00
Cloud Wu
cbf22ac9f3 release rc2 2016-03-07 11:46:30 +08:00
great90
bacaf10f1b Merge pull request #2 from cloudwu/master
update from cloudwu
2016-03-02 09:08:40 +08:00
Cloud Wu
8f7fa6a562 merge sproto 2016-02-25 14:40:24 +08:00
cloudwu
7b96eb28eb Merge pull request #455 from niuys/patch-2
error deal for query containing multi statement
2016-02-22 16:15:51 +08:00
snail
14ccf96eb0 error deal for query containing multi statement
A query may execute multi sql statements.If an error occurs for any sql, the result should return the error info.
2016-02-22 11:23:35 +08:00
dennis
6303886b8c Merge remote-tracking branch 'upstream/master' 2016-02-15 10:12:09 +08:00
Cloud Wu
ea8557296b fix issue #450 2016-02-13 19:20:07 +08:00
cloudwu
2a821fb62a Merge pull request #445 from DavidFeng/patch
fix
2016-01-27 13:55:14 +08:00
David Feng
d982009260 fix 2016-01-27 10:35:48 +08:00
cloudwu
a3f028ee3d Merge pull request #444 from DavidFeng/patch-1
修复调试模块调试结束后定时器没有取消的问题
2016-01-22 11:05:04 +08:00
David Feng
d34b092cdd remotedebug.lua call skynet.timeout() only in debug hook
定时器在debug结束后没有取消。
2016-01-22 10:28:03 +08:00
David Feng
77f4071191 remove unused local variables 2016-01-22 10:26:13 +08:00
cloudwu
653b29145d Merge pull request #442 from DavidFeng/patch-2
change socket.write to socketdriver.send
2016-01-20 22:05:23 +08:00
David Feng
96e0a4e3cc change socket.write to socketdriver.send
这样改过之后可以直接调试使用了gate服务的模块。
因为gate服务注册了socket类型的消息,所以不能和socket模块一块使用;而debug模块只使用到了socket模块的write函数,所以这样修改后对debug的功能并没有影响,但改过之后就可以调试gate服务了。
2016-01-20 19:24:58 +08:00
Cloud Wu
1da92850a0 bugfix: dispatch local global message queue 2016-01-19 17:14:52 +08:00
Cloud Wu
9747cf9aee don't assert here 2016-01-19 16:16:18 +08:00
Cloud Wu
7f45b3fd10 correct maxsz 2016-01-13 13:13:31 +08:00
cloudwu
217ab47577 Merge pull request #435 from niuys/patch-1
reduce needless 'add_string' call
2016-01-11 15:56:52 +08:00
snail
532f47444b reduce needless 'add_string' call
Short strings in lua proto are reused most of the time. The string in SSM may be added by one service and used by other service,  there is no need to call `add_string`,which will call 'new_string' first.
2016-01-11 15:06:51 +08:00
Cloud Wu
24f9ee1560 work thread for channel may not create if you never connect 2016-01-08 18:34:45 +08:00
Cloud Wu
d7a76c7c72 If no content-length, read all. see issue #431 2016-01-07 16:01:17 +08:00
Cloud Wu
c175d66e23 remove unused function 2016-01-06 16:55:15 +08:00
dennis
30cbcfd013 Merge remote-tracking branch 'upstream/master' 2016-01-06 15:57:42 +08:00
Cloud Wu
05003e3e2a sproto.attach also need ud 2016-01-05 17:51:48 +08:00
Cloud Wu
64c2cb1b51 sproto dispatch support ud 2016-01-05 16:06:20 +08:00
cloudwu
7f0e4eac8a Merge pull request #428 from fztcjjl/master
fix comment error
2016-01-04 16:07:50 +08:00
Cloud Wu
141a4d0992 lua 5.3.2 bugfix,see http://lua-users.org/lists/lua-l/2016-01/msg00000.html 2016-01-04 16:01:03 +08:00
fztcjjl
645ce72e7e fix comment error 2016-01-04 14:55:28 +08:00
cloudwu
fca4d67a43 Merge pull request #425 from DeanHH/patch-1
Update skynet_mq.c
2016-01-01 00:08:23 +08:00
DeanHH
014cbb9676 Update skynet_mq.c
Comment error:-)
2015-12-31 17:31:08 +08:00
Dennis
a39e822184 Merge pull request #1 from cloudwu/master
update from origin
2015-12-30 09:51:58 +08:00
great90
716ecccaed Merge pull request #1 from cloudwu/master
update skynet
2015-10-23 14:33:54 +08:00
78 changed files with 2090 additions and 1038 deletions

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp $
** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -379,9 +379,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL;
}
lua_lock(L); /* 'luaO_tostring' may create a new string */
luaO_tostring(L, o);
luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */
luaO_tostring(L, o);
lua_unlock(L);
}
if (len != NULL)
@@ -480,10 +480,10 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
luaC_checkGC(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return getstr(ts);
}
@@ -495,12 +495,12 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
setnilvalue(L->top);
else {
TString *ts;
luaC_checkGC(L);
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return s;
}
@@ -510,8 +510,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) {
const char *ret;
lua_lock(L);
luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp);
luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -521,10 +521,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret;
va_list argp;
lua_lock(L);
luaC_checkGC(L);
va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp);
luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -539,7 +539,6 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
CClosure *cl;
api_checknelems(L, n);
api_check(L, n <= MAXUPVAL, "upvalue index too large");
luaC_checkGC(L);
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
@@ -550,6 +549,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -586,16 +586,16 @@ LUA_API int lua_pushthread (lua_State *L) {
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux;
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, aux, luaH_getstr)) {
setobj2s(L, L->top, aux);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
}
lua_unlock(L);
return ttnov(L->top - 1);
@@ -627,17 +627,17 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *aux;
const TValue *slot;
lua_lock(L);
t = index2addr(L, idx);
if (luaV_fastget(L, t, n, aux, luaH_getint)) {
setobj2s(L, L->top, aux);
if (luaV_fastget(L, t, n, slot, luaH_getint)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
}
lua_unlock(L);
return ttnov(L->top - 1);
@@ -684,12 +684,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
luaC_checkGC(L);
t = luaH_new(L);
sethvalue(L, L->top, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -741,15 +741,15 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** t[k] = value at the top of the stack (where 'k' is a string)
*/
static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux;
const TValue *slot;
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1))
if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
L->top--; /* pop value */
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
@@ -782,16 +782,16 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *aux;
const TValue *slot;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1))
if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L);
@@ -1012,10 +1012,9 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
return status;
}
static Proto * cloneproto (lua_State *L, const Proto *src) {
void cloneproto (lua_State *L, Proto *f, const Proto *src) {
/* copy constants and nested proto */
int i,n;
Proto *f = luaF_newproto(L, src->sp);
n = src->sp->sizek;
f->k=luaM_newvector(L,n,TValue);
for (i=0; i<n; i++) setnilvalue(&f->k[i]);
@@ -1033,9 +1032,9 @@ static Proto * cloneproto (lua_State *L, const Proto *src) {
f->p=luaM_newvector(L,n,struct Proto *);
for (i=0; i<n; i++) f->p[i]=NULL;
for (i=0; i<n; i++) {
f->p[i]=cloneproto(L, src->p[i]);
f->p[i]= luaF_newproto(L, src->p[i]->sp);
cloneproto(L, f->p[i], src->p[i]);
}
return f;
}
LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
@@ -1049,9 +1048,10 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
return;
}
cl = luaF_newLclosure(L,f->nupvalues);
cl->p = cloneproto(L, f->p);
setclLvalue(L,L->top,cl);
api_incr_top(L);
cl->p = luaF_newproto(L, f->p->sp);
cloneproto(L, cl->p, f->p);
luaF_initupvals(L, cl);
if (cl->nupvalues >= 1) { /* does it have an upvalue? */
@@ -1193,7 +1193,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L);
api_checknelems(L, n);
if (n >= 2) {
luaC_checkGC(L);
luaV_concat(L, n);
}
else if (n == 0) { /* push empty string */
@@ -1201,6 +1200,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L);
}
/* else n == 1; nothing to do */
luaC_checkGC(L);
lua_unlock(L);
}
@@ -1236,10 +1236,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
luaC_checkGC(L);
u = luaS_newudata(L, size);
setuvalue(L, L->top, u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return getudatamem(u);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.c,v 1.284 2015/11/19 19:16:22 roberto Exp $
** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -17,7 +17,8 @@
#include <string.h>
/* This file uses only the official API of Lua.
/*
** This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
@@ -198,6 +199,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
}
/*
** The use of 'lua_pushfstring' ensures this function does not
** need reserved stack space when called.
*/
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
@@ -207,10 +212,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return;
}
}
lua_pushliteral(L, ""); /* else, no information available... */
lua_pushfstring(L, ""); /* else, no information available... */
}
/*
** Again, the use of 'lua_pushvfstring' ensures this function does
** not need reserved stack space when called. (At worst, it generates
** an error with "stack overflow" instead of the given message.)
*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@@ -349,10 +359,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
}
/*
** Ensures the stack has at least 'space' extra slots, raising an error
** if it cannot fulfill the request. (The error handling needs a few
** extra slots to format the error message. In case of an error without
** this extra space, Lua will generate the same 'stack overflow' error,
** but without 'msg'.)
*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (!lua_checkstack(L, space)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
@@ -678,7 +693,7 @@ static int skipcomment (LoadF *lf, int *cp) {
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
} while (c != EOF && c != '\n') ;
} while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbaselib.c,v 1.312 2015/10/29 15:21:04 roberto Exp $
** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
luaL_where(L, level);
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
@@ -251,9 +251,8 @@ static int ipairsaux (lua_State *L) {
/*
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
** traverse a table, depending on whether the table has metamethods
** that can affect the traversal.
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
#if defined(LUA_COMPAT_IPAIRS)

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->sp->code[(e)->u.info])
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->sp->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $
** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
@@ -75,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */
if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.c,v 2.117 2015/11/02 18:48:07 roberto Exp $
** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,13 @@ static void swapextra (lua_State *L) {
/*
** this function can be called asynchronous (e.g. during a signal)
** This function can be called asynchronously (e.g. during a signal).
** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
** 'resethookcount') are for debug only, and it is no problem if they
** get arbitrary values (causes at most one wrong hook call). 'hookmask'
** is an atomic value. We assume that pointers are atomic too (e.g., gcc
** ensures that for all platforms where it runs). Moreover, 'hook' is
** always checked before being called (see 'luaD_hook').
*/
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
@@ -118,7 +124,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
static const char *upvalname (Proto *p, int uv) {
TString *s = check_exp(uv < p->sizeupvalues, p->sp->upvalues[uv].name);
TString *s = check_exp(uv < p->sp->sizeupvalues, p->sp->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
@@ -558,7 +564,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *t = objtypename(o);
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
}
@@ -590,9 +596,9 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1);
const char *t2 = objtypename(p2);
if (t1 == t2)
const char *t1 = luaT_objtypename(L, p1);
const char *t2 = luaT_objtypename(L, p2);
if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.150 2015/11/19 19:16:22 roberto Exp $
** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -242,9 +242,14 @@ void luaD_inctop (lua_State *L) {
/* }================================================================== */
/*
** Call a hook for the given event. Make sure there is a hook to be
** called. (Both 'L->hook' and 'L->hookmask', which triggers this
** function, can be changed asynchronously by signals.)
*/
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
if (hook && L->allowhook) {
if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
@@ -768,7 +773,7 @@ static void f_parser (lua_State *L, void *ud) {
checkmode(L, p->mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
luaF_initupvals(L, cl);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp $
** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -25,7 +25,7 @@
{ pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,,)
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.210 2015/11/03 18:10:44 roberto Exp $
** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -492,15 +492,19 @@ static int marksharedproto (global_State *g, SharedProto *f) {
** NULL, so the use of 'markobjectN')
*/
static int traverseproto (global_State *g, Proto *f) {
int i;
int i,nk,np;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
for (i = 0; i < f->sp->sizek; i++) /* mark literals */
if (f->sp == NULL)
return sizeof(Proto);
nk = (f->k == NULL) ? 0 : f->sp->sizek;
np = (f->p == NULL) ? 0 : f->sp->sizep;
for (i = 0; i < nk; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sp->sizep; i++) /* mark nested protos */
for (i = 0; i < np; i++) /* mark nested protos */
markobjectN(g, f->p[i]);
return sizeof(Proto) + sizeof(Proto *) * f->sp->sizep +
sizeof(TValue) * f->sp->sizek +
return sizeof(Proto) + sizeof(Proto *) * np +
sizeof(TValue) * nk +
marksharedproto(g, f->sp);
}
@@ -761,14 +765,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/*
** sweep a list until a live object (or end of list)
*/
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p;
int i = 0;
do {
i++;
p = sweeplist(L, p, 1);
} while (p == old);
if (n) *n += i;
return p;
}
@@ -863,10 +864,10 @@ static int runafewfinalizers (lua_State *L) {
/*
** call all pending finalizers
*/
static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L);
while (g->tobefnz)
GCTM(L, propagateerrors);
GCTM(L, 0);
}
@@ -916,7 +917,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */
g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
}
/* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@@ -958,19 +959,16 @@ static void setpause (global_State *g) {
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes pointer point to an object inside
** the list (instead of to the header), so that the real sweep do not
** need to skip objects created between "now" and the start of the real
** sweep.
** Returns how many objects it swept.
** The call to 'sweeplist' tries to make pointer point to an object
** inside the list (instead of to the header), so that the real sweep do
** not need to skip objects created between "now" and the start of the
** real sweep.
*/
static int entersweep (lua_State *L) {
static void entersweep (lua_State *L) {
global_State *g = G(L);
int n = 0;
g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL);
g->sweepgc = sweeptolive(L, &g->allgc, &n);
return n;
g->sweepgc = sweeplist(L, &g->allgc, 1);
}
@@ -978,7 +976,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
callallpendingfinalizers(L, 0);
callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL;
@@ -1071,12 +1069,11 @@ static lu_mem singlestep (lua_State *L) {
}
case GCSatomic: {
lu_mem work;
int sw;
propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */
sw = entersweep(L);
entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */;
return work + sw * GCSWEEPCOST;
return work;
}
case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp $
** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -112,7 +112,7 @@
condchangemem(L,pre,pos); }
/* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,,)
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \

View File

@@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.148 2015/11/23 11:36:11 roberto Exp $
** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -375,14 +375,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */
#define MAXRN 200
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/* auxiliary structure used by 'read_number' */
typedef struct {
FILE *f; /* file being read */
int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */
char buff[MAXRN + 1]; /* +1 for ending '\0' */
char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN;
@@ -390,7 +393,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one
*/
static int nextc (RN *rn) {
if (rn->n >= MAXRN) { /* buffer overflow? */
if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */
}
@@ -403,10 +406,10 @@ static int nextc (RN *rn) {
/*
** Accept current char if it is in 'set' (of size 1 or 2)
** Accept current char if it is in 'set' (of size 2)
*/
static int test2 (RN *rn, const char *set) {
if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0'))
if (rn->c == set[0] || rn->c == set[1])
return nextc(rn);
else return 0;
}
@@ -435,11 +438,11 @@ static int read_number (lua_State *L, FILE *f) {
char decp[2];
rn.f = f; rn.n = 0;
decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
decp[1] = '\0';
decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */
if (test2(&rn, "0")) {
if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp $
** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -162,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->t.token = 0;
ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -207,35 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
}
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
if (from != to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
}
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, TValue *o) {
char old = ls->decpoint;
ls->decpoint = lua_getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (luaO_str2num(luaZ_buffer(ls->buff), o) == 0) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_FLT);
}
}
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2num'
@@ -259,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break;
}
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
trydecpoint(ls, &obj); /* try to update decimal point separator */
lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj);
return TK_INT;

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $
** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.c,v 2.108 2015/11/02 16:09:30 roberto Exp $
** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -243,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */
static const char *l_str2d (const char *s, lua_Number *result) {
/* maximum length of a numeral */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr;
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
return NULL;
else if (strpbrk(s, "xX")) /* hex? */
*result = lua_strx2number(s, &endptr);
else
*result = lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized */
while (lisspace(cast_uchar(*endptr))) endptr++;
return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */
*result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
: lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized? */
while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
}
/*
** Convert string 's' to a Lua number (put in 'result'). Return NULL
** on fail or the address of the ending '\0' on success.
** 'pmode' points to (and 'mode' contains) special things in the string:
** - 'x'/'X' means an hexadecimal numeral
** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
** - '.' just optimizes the search for the common case (nothing special)
** This function accepts both the current locale or a dot as the radix
** mark. If the convertion fails, it may mean number has a dot but
** locale accepts something else. In that case, the code copies 's'
** to a buffer (because 's' is read-only), changes the dot to the
** current locale radix mark, and tries to convert again.
*/
static const char *l_str2d (const char *s, lua_Number *result) {
const char *endptr;
const char *pmode = strpbrk(s, ".xXnN");
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
endptr = l_str2dloc(buff, result, mode); /* try again */
if (endptr != NULL)
endptr = s + (endptr - buff); /* make relative to 's' */
}
return endptr;
}
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
int empty = 1;
@@ -273,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
}
else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) {
a = a * 10 + *s - '0';
int d = *s - '0';
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return NULL; /* do not accept it (as integer) */
a = a * 10 + d;
empty = 0;
}
}
@@ -351,8 +393,10 @@ static void pushstr (lua_State *L, const char *str, size_t l) {
}
/* this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U' */
/*
** this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
@@ -360,13 +404,13 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
if (e == NULL) break;
pushstr(L, fmt, e - fmt);
switch (*(e+1)) {
case 's': {
case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s));
break;
}
case 'c': {
case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1);
@@ -374,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break;
}
case 'd': {
case 'd': { /* an 'int' */
setivalue(L->top, va_arg(argp, int));
goto top2str;
}
case 'I': {
case 'I': { /* a 'lua_Integer' */
setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
goto top2str;
}
case 'f': {
case 'f': { /* a 'lua_Number' */
setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
top2str:
top2str: /* convert the top element to a string */
luaD_inctop(L);
luaO_tostring(L, L->top - 1);
break;
}
case 'p': {
case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l);
break;
}
case 'U': {
case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l);

View File

@@ -1,5 +1,5 @@
/*
** $Id: loslib.c,v 1.60 2015/11/19 19:16:22 roberto Exp $
** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -24,18 +24,29 @@
/*
** {==================================================================
** list of valid conversion specifiers for the 'strftime' function
** List of valid conversion specifiers for the 'strftime' function;
** options are grouped by length; group of length 2 start with '||'.
** ===================================================================
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
/* options for ANSI C 89 */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS \
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
"E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#endif
#endif /* } */
@@ -195,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key);
}
/*
** Set all fields from structure 'tm' in the table on top of the stack
*/
static void setallfields (lua_State *L, struct tm *stm) {
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon + 1);
setfield(L, "year", stm->tm_year + 1900);
setfield(L, "wday", stm->tm_wday + 1);
setfield(L, "yday", stm->tm_yday + 1);
setboolfield(L, "isdst", stm->tm_isdst);
}
static int getboolfield (lua_State *L, const char *key) {
int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@@ -210,18 +238,18 @@ static int getboolfield (lua_State *L, const char *key) {
static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum;
int t = lua_getfield(L, -1, key);
int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not a number? */
if (!isnum) { /* field is not an integer? */
if (t != LUA_TNIL) /* some other value? */
return luaL_error(L, "field '%s' not an integer", key);
return luaL_error(L, "field '%s' is not an integer", key);
else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key);
res = d;
}
else {
if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return luaL_error(L, "field '%s' out-of-bounds", key);
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
lua_pop(L, 1);
@@ -230,21 +258,15 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static const char *const options[] = LUA_STRFTIMEOPTIONS;
unsigned int i;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
buff[1] = *conv;
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
buff[2] = '\0'; /* end buffer */
return conv + 1;
}
else if (*(conv + 1) != '\0' &&
strchr(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
const char *option;
int oplen = 1;
for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
if (*option == '|') /* next block? */
oplen++; /* next length */
else if (memcmp(conv, option, oplen) == 0) { /* match? */
memcpy(buff, conv, oplen); /* copy valid option to buffer */
buff[oplen] = '\0';
return conv + oplen; /* return next item */
}
}
luaL_argerror(L, 1,
@@ -271,18 +293,10 @@ static int os_date (lua_State *L) {
luaL_error(L, "time result cannot be represented in this installation");
if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
setallfields(L, stm);
}
else {
char cc[4];
char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
@@ -292,7 +306,7 @@ static int os_date (lua_State *L) {
else {
size_t reslen;
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc);
s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen);
}
@@ -319,6 +333,7 @@ static int os_time (lua_State *L) {
ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
setallfields(L, &ts); /* update fields with normalized values */
}
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this installation");

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.c,v 2.149 2015/11/02 16:09:30 roberto Exp $
** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -165,7 +165,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables");
while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
while (oldsize < f->sizelocvars)
f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, fp, varname);
return fs->nlocvars++;
@@ -232,7 +233,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
while (oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
@@ -257,7 +259,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
while (bl->nactvar > level) bl = bl->previous;
while (bl->nactvar > level)
bl = bl->previous;
bl->upval = 1;
}
@@ -266,27 +269,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions.
*/
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
return VVOID; /* default is global */
init_exp(var, VVOID, 0); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
}
else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
return VVOID; /* not found; is a global */
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
if (var->k == VVOID) /* not found? */
return; /* it is a global */
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */
}
init_exp(var, VUPVAL, idx);
return VUPVAL;
init_exp(var, VUPVAL, idx); /* new or old upvalue */
}
}
}
@@ -295,10 +297,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
singlevaraux(fs, varname, var, 1);
if (var->k == VVOID) { /* global name? */
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k == VLOCAL || var->k == VUPVAL);
lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -322,6 +325,8 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
luaK_nil(fs, reg, extra);
}
}
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
@@ -501,7 +506,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sp->sizep) {
int oldsize = f->sp->sizep;
luaM_growvector(L, f->p, fs->np, f->sp->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sp->sizep) f->p[oldsize++] = NULL;
while (oldsize < f->sp->sizep)
f->p[oldsize++] = NULL;
}
f->p[fs->np++] = clp = luaF_newproto(L, NULL);
luaC_objbarrier(L, f, clp);
@@ -1159,11 +1165,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
int nexps;
checknext(ls, '=');
nexps = explist(ls, &e);
if (nexps != nvars) {
if (nexps != nvars)
adjust_assign(ls, nvars, nexps, &e);
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
else {
luaK_setoneret(ls->fs, &e); /* close last expression */
luaK_storevar(ls->fs, &lh->v, &e);
@@ -1229,7 +1232,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
l = newlabelentry(ls, ll, label, line, fs->pc);
l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -1497,7 +1500,7 @@ static void exprstat (LexState *ls) {
}
else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error");
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
}
}
@@ -1514,8 +1517,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
}
first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */
@@ -1597,7 +1600,7 @@ static void statement (LexState *ls) {
break;
}
}
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
lua_assert(ls->fs->f->sp->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
leavelevel(ls);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $
** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,25 +13,38 @@
/*
** Expression descriptor
** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/
/* kinds of variables/expressions */
typedef enum {
VVOID, /* no value */
VNIL,
VTRUE,
VFALSE,
VK, /* info = index of constant in 'k' */
VKFLT, /* nval = numerical float value */
VKINT, /* nval = numerical integer value */
VNONRELOC, /* info = result register */
VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in 'upvalues' */
VINDEXED, /* t = table register/upvalue; idx = index R/K */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */
VVOID, /* when 'expdesc' describes the last expression a list,
this kind means an empty list (so, no expression) */
VNIL, /* constant nil */
VTRUE, /* constant true */
VFALSE, /* constant false */
VK, /* constant in 'k'; info = index of constant in 'k' */
VKFLT, /* floating constant; nval = numerical float value */
VKINT, /* integer constant; nval = numerical integer value */
VNONRELOC, /* expression has its value in a fixed register;
info = result register */
VLOCAL, /* local variable; info = local register */
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VINDEXED, /* indexed variable;
ind.vt = whether 't' is register or upvalue;
ind.t = table register or upvalue;
ind.idx = key's R/K index */
VJMP, /* expression is a test/comparison;
info = pc of corresponding jump instruction */
VRELOCABLE, /* expression can put result in any register;
info = instruction pc */
VCALL, /* expression is a function call; info = instruction pc */
VVARARG /* vararg expression; info = instruction pc */
} expkind;
@@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc {
expkind k;
union {
lua_Integer ival; /* for VKINT */
lua_Number nval; /* for VKFLT */
int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
int info; /* for generic use */
lua_Number nval; /* for VKFLT */
lua_Integer ival; /* for VKINT */
} u;
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.128 2015/11/13 12:16:51 roberto Exp $
** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT sig_atomic_t
#endif
/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5
@@ -162,14 +171,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
lua_Hook hook;
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
l_signalT hookmask;
lu_byte allowhook;
};

View File

@@ -419,8 +419,11 @@ luaS_clonestring(lua_State *L, TString *ts) {
result = query_ptr(ts);
if (result)
return result;
// ts is not in SSM, so recalc hash, and add it to SSM
h = luaS_hash(str, l, 0);
result = query_string(h, str, l);
if (result)
return result;
// ts is not in SSM, so recalc hash, and add it to SSM
return add_string(h, str, l);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstrlib.c,v 1.239 2015/11/25 16:28:17 roberto Exp $
** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -13,6 +13,7 @@
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -26,7 +27,8 @@
/*
** maximum number of captures that a pattern can do during
** pattern-matching. This limit is arbitrary.
** pattern-matching. This limit is arbitrary, but must fit in
** an unsigned char.
*/
#if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32
@@ -214,9 +216,8 @@ typedef struct MatchState {
const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */
lua_State *L;
size_t nrep; /* limit to avoid non-linear complexity */
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
int level; /* total number of captures (finished or unfinished) */
unsigned char level; /* total number of captures (finished or unfinished) */
struct {
const char *init;
ptrdiff_t len;
@@ -234,17 +235,6 @@ static const char *match (MatchState *ms, const char *s, const char *p);
#endif
/*
** parameters to control the maximum number of operators handled in
** a match (to avoid non-linear complexity). The maximum will be:
** (subject length) * A_REPS + B_REPS
*/
#if !defined(A_REPS)
#define A_REPS 4
#define B_REPS 100000
#endif
#define L_ESC '%'
#define SPECIALS "^$*+?.([%-"
@@ -502,8 +492,6 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
s = NULL; /* fail */
}
else { /* matched once */
if (ms->nrep-- == 0)
luaL_error(ms->L, "pattern too complex");
switch (*ep) { /* handle optional suffix */
case '?': { /* optional */
const char *res;
@@ -607,10 +595,6 @@ static void prepstate (MatchState *ms, lua_State *L,
ms->src_init = s;
ms->src_end = s + ls;
ms->p_end = p + lp;
if (ls < (MAX_SIZET - B_REPS) / A_REPS)
ms->nrep = A_REPS * ls + B_REPS;
else /* overflow (very long subject) */
ms->nrep = MAX_SIZET; /* no limit */
}
@@ -681,6 +665,7 @@ static int str_match (lua_State *L) {
typedef struct GMatchState {
const char *src; /* current position */
const char *p; /* pattern */
const char *lastmatch; /* end of last match */
MatchState ms; /* match state */
} GMatchState;
@@ -688,14 +673,12 @@ typedef struct GMatchState {
static int gmatch_aux (lua_State *L) {
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src;
gm->ms.L = L;
for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e;
reprepstate(&gm->ms);
if ((e = match(&gm->ms, src, gm->p)) != NULL) {
if (e == src) /* empty match? */
gm->src =src + 1; /* go at least one position */
else
gm->src = e;
if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
gm->src = gm->lastmatch = e;
return push_captures(&gm->ms, src, e);
}
}
@@ -711,7 +694,7 @@ static int gmatch (lua_State *L) {
lua_settop(L, 2); /* keep them on closure to avoid being collected */
gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
prepstate(&gm->ms, L, s, ls, p, lp);
gm->src = s; gm->p = p;
gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
@@ -778,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) {
size_t srcl, lp;
const char *src = luaL_checklstring(L, 1, &srcl);
const char *p = luaL_checklstring(L, 2, &lp);
int tr = lua_type(L, 3);
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
const char *lastmatch = NULL; /* end of last match */
int tr = lua_type(L, 3); /* replacement type */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^');
lua_Integer n = 0;
lua_Integer n = 0; /* replacement count */
MatchState ms;
luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -796,16 +780,15 @@ static int str_gsub (lua_State *L) {
prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) {
const char *e;
reprepstate(&ms);
if ((e = match(&ms, src, p)) != NULL) {
reprepstate(&ms); /* (re)prepare state for new match */
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++;
add_value(&ms, &b, src, e, tr);
add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
src = lastmatch = e;
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
else if (src < ms.src_end) /* otherwise, skip one character */
luaL_addchar(&b, *src++);
else break;
else break; /* end of subject */
if (anchor) break;
}
luaL_addlstring(&b, src, ms.src_end-src);
@@ -830,7 +813,6 @@ static int str_gsub (lua_State *L) {
** Hexadecimal floating-point formatter
*/
#include <locale.h>
#include <math.h>
#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
@@ -922,16 +904,14 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
#define MAX_FORMAT 32
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
luaL_addchar(b, '"');
while (l--) {
while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\');
luaL_addchar(b, *s);
}
else if (*s == '\0' || iscntrl(uchar(*s))) {
else if (iscntrl(uchar(*s))) {
char buff[10];
if (!isdigit(uchar(*(s+1))))
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
@@ -946,6 +926,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"');
}
/*
** Ensures the 'buff' string uses a dot as the radix character.
*/
static void checkdp (char *buff, int nb) {
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
char point = lua_getlocaledecpoint(); /* try locale point */
char *ppoint = memchr(buff, point, nb);
if (ppoint) *ppoint = '.'; /* change it to a dot */
}
}
static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
switch (lua_type(L, arg)) {
case LUA_TSTRING: {
size_t len;
const char *s = lua_tolstring(L, arg, &len);
addquoted(b, s, len);
break;
}
case LUA_TNUMBER: {
char *buff = luaL_prepbuffsize(b, MAX_ITEM);
int nb;
if (!lua_isinteger(L, arg)) { /* float? */
lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
checkdp(buff, nb); /* ensure it uses a dot */
}
else { /* integers */
lua_Integer n = lua_tointeger(L, arg);
const char *format = (n == LUA_MININTEGER) /* corner case? */
? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
: LUA_INTEGER_FMT; /* else use default format */
nb = l_sprintf(buff, MAX_ITEM, format, n);
}
luaL_addsize(b, nb);
break;
}
case LUA_TNIL: case LUA_TBOOLEAN: {
luaL_tolstring(L, arg, NULL);
luaL_addvalue(b);
break;
}
default: {
luaL_argerror(L, arg, "value has no literal form");
}
}
}
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
@@ -1025,7 +1056,7 @@ static int str_format (lua_State *L) {
break;
}
case 'q': {
addquoted(L, &b, arg);
addliteral(L, &b, arg);
break;
}
case 's': {
@@ -1070,8 +1101,8 @@ static int str_format (lua_State *L) {
/* value used for padding */
#if !defined(LUA_PACKPADBYTE)
#define LUA_PACKPADBYTE 0x00
#if !defined(LUAL_PACKPADBYTE)
#define LUAL_PACKPADBYTE 0x00
#endif
/* maximum size for the binary representation of an integer */
@@ -1308,7 +1339,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size;
while (ntoalign-- > 0)
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++;
switch (opt) {
case Kint: { /* signed integers */
@@ -1343,13 +1374,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */
size_t len;
const char *s = luaL_checklstring(L, arg, &len);
if ((size_t)size <= len) /* string larger than (or equal to) needed? */
luaL_addlstring(&b, s, size); /* truncate string to asked size */
else { /* string smaller than needed */
luaL_addlstring(&b, s, len); /* add it all */
while (len++ < (size_t)size) /* pad extra space */
luaL_addchar(&b, LUA_PACKPADBYTE);
}
luaL_argcheck(L, len <= (size_t)size, arg,
"string longer than given size");
luaL_addlstring(&b, s, len); /* add string */
while (len++ < (size_t)size) /* pad extra space */
luaL_addchar(&b, LUAL_PACKPADBYTE);
break;
}
case Kstring: { /* strings with length count */
@@ -1372,7 +1401,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1;
break;
}
case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */
case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop:
arg--; /* undo increment */
break;

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltablib.c,v 1.90 2015/11/25 12:48:57 roberto Exp $
** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -53,7 +53,7 @@ static void checktab (lua_State *L, int arg, int what) {
lua_pop(L, n); /* pop metatable and tested metamethods */
}
else
luaL_argerror(L, arg, "table expected"); /* force an error */
luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
}
}
@@ -139,7 +139,7 @@ static int tmove (lua_State *L) {
n = e - f + 1; /* number of elements to move */
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
"destination wrap around");
if (t > e || t <= f || tt != 1) {
if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
for (i = 0; i < n; i++) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
@@ -152,7 +152,7 @@ static int tmove (lua_State *L) {
}
}
}
lua_pushvalue(L, tt); /* return "to table" */
lua_pushvalue(L, tt); /* return destination table */
return 1;
}
@@ -172,7 +172,7 @@ static int tconcat (lua_State *L) {
size_t lsep;
const char *sep = luaL_optlstring(L, 2, "", &lsep);
lua_Integer i = luaL_optinteger(L, 3, 1);
last = luaL_opt(L, luaL_checkinteger, 4, last);
last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b);
for (; i < last; i++) {
addfield(L, &b, i);
@@ -232,6 +232,10 @@ static int unpack (lua_State *L) {
*/
/* type for array indices */
typedef unsigned int IdxT;
/*
** Produce a "random" 'unsigned int' to randomize pivot choice. This
** macro is used only when 'sort' detects a big imbalance in the result
@@ -270,7 +274,7 @@ static unsigned int l_randomizePivot (void) {
#define RANLIMIT 100u
static void set2 (lua_State *L, unsigned int i, unsigned int j) {
static void set2 (lua_State *L, IdxT i, IdxT j) {
lua_seti(L, 1, i);
lua_seti(L, 1, j);
}
@@ -303,10 +307,9 @@ static int sort_comp (lua_State *L, int a, int b) {
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
** returns 'i'.
*/
static unsigned int partition (lua_State *L, unsigned int lo,
unsigned int up) {
unsigned int i = lo; /* will be incremented before first use */
unsigned int j = up - 1; /* will be decremented before first use */
static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
IdxT i = lo; /* will be incremented before first use */
IdxT j = up - 1; /* will be decremented before first use */
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
for (;;) {
/* next loop: repeat ++i while a[i] < P */
@@ -340,10 +343,9 @@ static unsigned int partition (lua_State *L, unsigned int lo,
** Choose an element in the middle (2nd-3th quarters) of [lo,up]
** "randomized" by 'rnd'
*/
static unsigned int choosePivot (unsigned int lo, unsigned int up,
unsigned int rnd) {
unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */
unsigned int p = rnd % (r4 * 2) + (lo + r4);
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
IdxT r4 = (up - lo) / 4; /* range/4 */
IdxT p = rnd % (r4 * 2) + (lo + r4);
lua_assert(lo + r4 <= p && p <= up - r4);
return p;
}
@@ -352,11 +354,11 @@ static unsigned int choosePivot (unsigned int lo, unsigned int up,
/*
** QuickSort algorithm (recursive function)
*/
static void auxsort (lua_State *L, unsigned int lo, unsigned int up,
static void auxsort (lua_State *L, IdxT lo, IdxT up,
unsigned int rnd) {
while (lo < up) { /* loop for tail recursion */
unsigned int p; /* Pivot index */
unsigned int n; /* to be used later */
IdxT p; /* Pivot index */
IdxT n; /* to be used later */
/* sort elements 'lo', 'p', and 'up' */
lua_geti(L, 1, lo);
lua_geti(L, 1, up);
@@ -400,7 +402,7 @@ static void auxsort (lua_State *L, unsigned int lo, unsigned int up,
n = up - p; /* size of smaller interval */
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
}
if ((up - lo) / 128u > n) /* partition too imbalanced? */
if ((up - lo) / 128 > n) /* partition too imbalanced? */
rnd = l_randomizePivot(); /* try a new randomization */
} /* tail call auxsort(L, lo, up, rnd) */
}
@@ -410,11 +412,10 @@ static int sort (lua_State *L) {
lua_Integer n = aux_getn(L, 1, TAB_RW);
if (n > 1) { /* non-trivial interval? */
luaL_argcheck(L, n < INT_MAX, 1, "array too big");
luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, 1, (unsigned int)n, 0u);
auxsort(L, 1, (IdxT)n, 0);
}
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 2.36 2015/11/03 15:47:30 roberto Exp $
** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -83,6 +83,22 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
}
/*
** Return the name of the type of an object. For tables and userdata
** with metatable, use their '__name' metafield, if present.
*/
const char *luaT_objtypename (lua_State *L, const TValue *o) {
Table *mt;
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
if (ttisstring(name)) /* is '__name' a string? */
return getstr(tsvalue(name)); /* use it as type name */
}
return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.329 2015/11/13 17:18:42 roberto Exp $
** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "2"
#define LUA_VERSION_RELEASE "3"
#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-2015 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -363,7 +363,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@@ -467,7 +467,7 @@ LUA_API void (lua_checksig_)(lua_State *L);
#define lua_checksig(L) if (skynet_sig_L) { lua_checksig_(L); }
/******************************************************************************
* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
* Copyright (C) 1994-2016 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

@@ -1,5 +1,5 @@
/*
** $Id: luaconf.h,v 1.254 2015/10/21 18:17:40 roberto Exp $
** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -612,7 +612,7 @@
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) l_sprintf(b,sz,f,n)
#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
#endif

View File

@@ -273,7 +273,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
luaD_inctop(L);
cl->p = luaF_newproto(L, NULL);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
luai_verifycode(L, buff, cl->p);
return cl;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp $
** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -163,55 +163,69 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/*
** Complete a table access: if 't' is a table, 'tm' has its metamethod;
** otherwise, 'tm' is NULL.
** Finish the table access 'val = t[key]'.
** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be nil).
*/
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *tm) {
const TValue *slot) {
int loop; /* counter to avoid infinite loops */
lua_assert(tm != NULL || !ttistable(t));
const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (tm == NULL) { /* no metamethod (from a table)? */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
if (slot == NULL) { /* 't' is not a table? */
lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
}
if (ttisfunction(tm)) { /* metamethod is a function */
else { /* 't' is a table */
lua_assert(ttisnil(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(val); /* result is nil */
return;
}
/* else will try the metamethod */
}
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */
return;
}
t = tm; /* else repeat access over 'tm' */
if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */
setobj2s(L, val, tm); /* done */
t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, slot); /* done */
return;
}
/* else repeat */
/* else repeat (tail call 'luaV_finishget') */
}
luaG_runerror(L, "gettable chain too long; possible loop");
luaG_runerror(L, "'__index' chain too long; possible loop");
}
/*
** Main function for table assignment (invoking metamethods if needed).
** Compute 't[key] = val'
** Finish a table assignment 't[key] = val'.
** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.)
*/
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval) {
StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (oldval != NULL) {
lua_assert(ttistable(t) && ttisnil(oldval));
/* must check the metamethod */
if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL &&
/* no metamethod; is there a previous entry in the table? */
(oldval != luaO_nilobject ||
/* no previous entry; must create one. (The next test is
always true; we only need the assignment.) */
(oldval = luaH_newkey(L, hvalue(t), key), 1))) {
const TValue *tm; /* '__newindex' metamethod */
if (slot != NULL) { /* is 't' a table? */
Table *h = hvalue(t); /* save 't' table */
lua_assert(ttisnil(slot)); /* old value must be nil */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */
if (slot == luaO_nilobject) /* no previous entry? */
slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, oldval), val);
invalidateTMcache(hvalue(t));
luaC_barrierback(L, hvalue(t), val);
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h);
luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
@@ -226,11 +240,11 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
return;
}
t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, oldval, luaH_get, val))
if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */
/* else loop */
}
luaG_runerror(L, "settable chain too long; possible loop");
luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
@@ -748,18 +762,28 @@ void luaV_finishOp (lua_State *L) {
luai_threadyield(L); }
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
/*
** copy of 'luaV_gettable', but protecting call to potential metamethod
** (which can reallocate the stack)
** copy of 'luaV_gettable', but protecting the call to potential
** metamethod (which can reallocate the stack)
*/
#define gettableProtected(L,t,k,v) { const TValue *aux; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \
else Protect(luaV_finishget(L,t,k,v,aux)); }
#define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */
@@ -782,14 +806,9 @@ void luaV_execute (lua_State *L) {
base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
Instruction i = *(ci->u.l.savedpc++);
Instruction i;
StkId ra;
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT))
Protect(luaG_traceexec(L));
/* WARNING: several calls may realloc the stack and invalidate 'ra' */
ra = RA(i);
lua_assert(base == ci->u.l.base);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
vmfetch();
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i));
@@ -1162,7 +1181,7 @@ void luaV_execute (lua_State *L) {
oci->u.l.savedpc = nci->u.l.savedpc;
oci->callstatus |= CIST_TAIL; /* function was tail called */
ci = L->ci = oci; /* remove new frame */
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->sp->maxstacksize);
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp $
** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -49,25 +49,24 @@
/*
** fast track for 'gettable': 1 means 'aux' points to resulted value;
** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is
** the raw get function to use.
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,aux,f) \
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \
: (aux = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \
: (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\
aux != NULL ? 0 /* has metamethod? must call it */ \
: (aux = luaO_nilobject, 1)))) /* else, final result is nil */
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(slot))) /* result not nil? */
/*
** standard implementation for 'gettable'
*/
#define luaV_gettable(L,t,k,v) { const TValue *aux; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \
else luaV_finishget(L,t,k,v,aux); }
#define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,slot); }
/*
@@ -100,9 +99,9 @@ LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *tm);
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval);
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);

View File

@@ -1,3 +1,42 @@
v1.0.0-rc5 (2016-7-4)
-----------
* MongoDB : Support auth_scram_sha1
* MongoDB : Auto determine primary host
* Bugfix : memory leak in multicast
* Bugfix : Lua 5.3.3
* Bson : support meta array
v1.0.0-rc4 (2016-6-13)
-----------
* Update lua to 5.3.3
* Update jemalloc to 4.2.1
* Add debug console command ping
* Lua bson support __pairs
* Add mongo.createIndexes and fix bug in old mongo.createIndex
* Handle signal HUP to reopen log file (for logrotate)
v1.0.0-rc3 (2016-5-9)
-----------
* Update jemalloc 4.1.1
* Update lua 5.3.3 rc1
* Update sproto to support encoding empty table
* Make skynet.init stable (keep order)
* skynet.getenv can return empty string
* Add lua VM memory warning
* lua VM support memory limit
* skynet.pcall suport varargs
* Bugfix : Global name query
* Bugfix : snax.queryglobal
v1.0.0-rc2 (2016-3-7)
-----------
* Fix a bug in lua 5.3.2
* Update sproto (fix bugs and add ud for package)
* Fix a bug in http
* Fix a bug in harbor
* Fix a bug in socket channel
* Enhance remote debugger
v1.0.0-rc (2015-12-28)
-----------
* Update to lua 5.3.2

View File

@@ -1,6 +1,6 @@
## Build
For linux, install autoconf first for jemalloc
For Linux, install autoconf first for jemalloc:
```
git clone https://github.com/cloudwu/skynet.git
@@ -8,31 +8,31 @@ cd skynet
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
```
Or you can :
Or you can:
```
export PLAT=linux
make
```
For freeBSD , use gmake instead of make .
For FreeBSD , use gmake instead of make.
## Test
Run these in different console
Run these in different consoles:
```
./skynet examples/config # Launch first skynet node (Gate server) and a skynet-master (see config for standalone option)
./3rd/lua/lua examples/client.lua # Launch a client, and try to input hello.
```
## About Lua
## About Lua version
Skynet now use a modify version of lua 5.3.2 ( http://www.lua.org/ftp/lua-5.3.2.tar.gz ) .
Skynet now uses a modified version of lua 5.3.3 ( http://www.lua.org/ftp/lua-5.3.3.tar.gz ) .
For detail : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
For details: http://lua-users.org/lists/lua-l/2014-03/msg00489.html
You can also use the other official Lua version , edit the makefile by yourself .
You can also use official Lua versions, just edit the Makefile by yourself.
## How To Use (Sorry, Only in Chinese now)

View File

@@ -0,0 +1,30 @@
local skynet = require "skynet"
local list = {}
local function timeout_check(ti)
if not next(list) then
return
end
skynet.sleep(ti) -- sleep 10 sec
for k,v in pairs(list) do
skynet.error("timout",ti,k,v)
end
end
skynet.start(function()
skynet.error("ping all")
local list_ret = skynet.call(".launcher", "lua", "LIST")
for addr, desc in pairs(list_ret) do
list[addr] = desc
skynet.fork(function()
skynet.call(addr,"debug","INFO")
list[addr] = nil
end)
end
skynet.sleep(0)
timeout_check(100)
timeout_check(400)
timeout_check(500)
skynet.exit()
end)

View File

@@ -9,7 +9,9 @@ start = "main" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
standalone = "0.0.0.0:2013"
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
lualoader = "lualib/loader.lua"
lualoader = root .. "lualib/loader.lua"
lua_path = root.."lualib/?.lua;"..root.."lualib/?/init.lua"
lua_cpath = root .. "luaclib/?.so"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
snax = root.."examples/?.lua;"..root.."test/?.lua"
-- snax_interface_g = "snax_g"

View File

@@ -4,9 +4,11 @@ local sprotoloader = require "sprotoloader"
local max_client = 64
skynet.start(function()
print("Server start")
skynet.error("Server start")
skynet.uniqueservice("protoloader")
local console = skynet.newservice("console")
if not skynet.getenv "daemon" then
local console = skynet.newservice("console")
end
skynet.newservice("debug_console",8000)
skynet.newservice("simpledb")
local watchdog = skynet.newservice("watchdog")
@@ -15,7 +17,6 @@ skynet.start(function()
maxclient = max_client,
nodelay = true,
})
print("Watchdog listen on ", 8888)
skynet.error("Watchdog listen on", 8888)
skynet.exit()
end)

View File

@@ -6,7 +6,17 @@ skynet.register_protocol {
id = skynet.PTYPE_TEXT,
unpack = skynet.tostring,
dispatch = function(_, address, msg)
print(string.format("%x(%.2f): %s", address, skynet.time(), msg))
print(string.format(":%08x(%.2f): %s", address, skynet.time(), msg))
end
}
skynet.register_protocol {
name = "SYSTEM",
id = skynet.PTYPE_SYSTEM,
unpack = function(...) return ... end,
dispatch = function()
-- reopen signal
print("SIGHUP")
end
}

View File

@@ -238,8 +238,6 @@ write_double(struct bson *b, lua_Number d) {
}
}
static void pack_dict(lua_State *L, struct bson *b, bool array, int depth);
static inline void
append_key(struct bson *bs, int type, const char *key, size_t sz) {
write_byte(bs, type);
@@ -269,25 +267,7 @@ append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
}
}
static void
append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) {
size_t len = lua_rawlen(L, -1);
bool isarray = false;
if (len > 0) {
lua_pushinteger(L, len);
if (lua_next(L,-2) == 0) {
isarray = true;
} else {
lua_pop(L,2);
}
}
if (isarray) {
append_key(bs, BSON_ARRAY, key, sz);
} else {
append_key(bs, BSON_DOCUMENT, key, sz);
}
pack_dict(L, bs, isarray, depth);
}
static void append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth);
static void
write_binary(struct bson *b, const void * buffer, size_t sz) {
@@ -409,53 +389,122 @@ bson_numstr( char *str, unsigned int i ) {
}
static void
pack_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (depth > MAX_DEPTH) {
luaL_error(L, "Too depth while encoding bson");
pack_array(lua_State *L, struct bson *b, int depth, size_t len) {
int length = reserve_length(b);
size_t i;
for (i=1;i<=len;i++) {
char numberkey[32];
size_t sz = bson_numstr(numberkey, i - 1);
const char * key = numberkey;
lua_geti(L, -1, i);
append_one(b, L, key, sz, depth);
lua_pop(L, 1);
}
luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table
write_byte(b,0);
write_length(b, b->size - length, length);
}
static void
pack_dict_data(lua_State *L, struct bson *b, int depth, int kt) {
const char * key = NULL;
size_t sz;
switch(kt) {
case LUA_TNUMBER:
// copy key, don't change key type
lua_pushvalue(L,-2);
lua_insert(L,-2);
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,2);
break;
case LUA_TSTRING:
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,1);
break;
default:
luaL_error(L, "Invalid key type : %s", lua_typename(L, kt));
return;
}
}
static void
pack_simple_dict(lua_State *L, struct bson *b, int depth) {
int length = reserve_length(b);
lua_pushnil(L);
while(lua_next(L,-2) != 0) {
int kt = lua_type(L, -2);
char numberkey[32];
const char * key = NULL;
size_t sz;
if (isarray) {
if (kt != LUA_TNUMBER) {
luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt));
return;
}
sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1);
key = numberkey;
append_one(b, L, key, sz, depth);
lua_pop(L,1);
} else {
switch(kt) {
case LUA_TNUMBER:
// copy key, don't change key type
lua_pushvalue(L,-2);
lua_insert(L,-2);
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,2);
break;
case LUA_TSTRING:
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,1);
break;
default:
luaL_error(L, "Invalid key type : %s", lua_typename(L, kt));
return;
}
}
pack_dict_data(L, b, depth, kt);
}
write_byte(b,0);
write_length(b, b->size - length, length);
}
static void
pack_meta_dict(lua_State *L, struct bson *b, int depth) {
int length = reserve_length(b);
lua_pushvalue(L, -2); // push meta_obj
lua_call(L, 1, 3); // call __pairs_func => next_func, t_data, first_k
for(;;) {
lua_pushvalue(L, -2); // copy data
lua_pushvalue(L, -2); // copy k
lua_copy(L, -5, -3); // copy next_func replace old_k
lua_call(L, 2, 2); // call next_func
int kt = lua_type(L, -2);
if (kt == LUA_TNIL) {
lua_pop(L, 4); // pop all k, v, next_func, obj
break;
}
pack_dict_data(L, b, depth, kt);
}
write_byte(b,0);
write_length(b, b->size - length, length);
}
static bool
is_rawarray(lua_State *L) {
size_t len = lua_rawlen(L, -1);
if (len > 0) {
lua_pushinteger(L, len);
if (lua_next(L,-2) == 0) {
return true;
} else {
lua_pop(L,2);
}
}
return false;
}
static void
append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) {
if (depth > MAX_DEPTH) {
luaL_error(L, "Too depth while encoding bson");
}
luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table
if (luaL_getmetafield(L, -1, "__len") != LUA_TNIL) {
lua_pushvalue(L, -2);
lua_call(L, 1, 1);
if (!lua_isinteger(L, -1)) {
luaL_error(L, "__len should return integer");
}
size_t len = lua_tointeger(L, -1);
lua_pop(L, 1);
append_key(bs, BSON_ARRAY, key, sz);
pack_array(L, bs, depth, len);
} else if (luaL_getmetafield(L, -1, "__pairs") != LUA_TNIL) {
append_key(bs, BSON_DOCUMENT, key, sz);
pack_meta_dict(L, bs, depth);
} else if (is_rawarray(L)) {
append_key(bs, BSON_ARRAY, key, sz);
pack_array(L, bs, depth, lua_rawlen(L, -1));
} else {
append_key(bs, BSON_DOCUMENT, key, sz);
pack_simple_dict(L, bs, depth);
}
}
static void
pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) {
int length = reserve_length(b);
@@ -853,7 +902,11 @@ lencode(lua_State *L) {
bson_create(&b);
lua_settop(L,1);
luaL_checktype(L, 1, LUA_TTABLE);
pack_dict(L, &b, false, 0);
if (luaL_getmetafield(L, -1, "__pairs") != LUA_TNIL) {
pack_meta_dict(L, &b, 0);
} else {
pack_simple_dict(L, &b, 0);
}
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
bson_destroy(&b);

View File

@@ -751,7 +751,7 @@ ldhexchange(lua_State *L) {
if (x64 == 0)
return luaL_error(L, "Can't be 0");
uint64_t r = powmodp(5, x64);
uint64_t r = powmodp(G, x64);
push64(L, r);
return 1;
}
@@ -878,6 +878,25 @@ lb64decode(lua_State *L) {
return 1;
}
static int
lxor_str(lua_State *L) {
size_t len1,len2;
const char *s1 = luaL_checklstring(L,1,&len1);
const char *s2 = luaL_checklstring(L,2,&len2);
if (len2 == 0) {
return luaL_error(L, "Can't xor empty string");
}
luaL_Buffer b;
char * buffer = luaL_buffinitsize(L, &b, len1);
int i;
for (i=0;i<len1;i++) {
buffer[i] = s1[i] ^ s2[i % len2];
}
luaL_addsize(&b, len1);
luaL_pushresult(&b);
return 1;
}
// defined in lsha1.c
int lsha1(lua_State *L);
int lhmac_sha1(lua_State *L);
@@ -885,7 +904,12 @@ int lhmac_sha1(lua_State *L);
int
luaopen_crypt(lua_State *L) {
luaL_checkversion(L);
srandom(time(NULL));
static int init = 0;
if (!init) {
// Don't need call srandom more than once.
init = 1 ;
srandom(time(NULL));
}
luaL_Reg l[] = {
{ "hashkey", lhashkey },
{ "randomkey", lrandomkey },
@@ -901,6 +925,7 @@ luaopen_crypt(lua_State *L) {
{ "sha1", lsha1 },
{ "hmac_sha1", lhmac_sha1 },
{ "hmac_hash", lhmac_hash },
{ "xor_str", lxor_str },
{ NULL, NULL },
};
luaL_newlib(L,l);

View File

@@ -60,18 +60,6 @@ mc_packremote(lua_State *L) {
return pack(L, msg, size);
}
static int
mc_packstring(lua_State *L) {
size_t size;
const char * msg = luaL_checklstring(L, 1, &size);
if (size != (uint32_t)size) {
return luaL_error(L, "string is too long");
}
void * data = skynet_malloc(size);
memcpy(data, msg, size);
return pack(L, data, size);
}
/*
lightuserdata struct mc_package **
integer size (must be sizeof(struct mc_package *)
@@ -82,7 +70,7 @@ static int
mc_unpacklocal(lua_State *L) {
struct mc_package ** pack = lua_touserdata(L,1);
int sz = luaL_checkinteger(L,2);
if (sz != sizeof(*pack)) {
if (sz != sizeof(pack)) {
return luaL_error(L, "Invalid multicast package size %d", sz);
}
lua_pushlightuserdata(L, *pack);
@@ -108,6 +96,8 @@ mc_bindrefer(lua_State *L) {
lua_pushlightuserdata(L, *pack);
skynet_free(pack);
return 1;
}
@@ -161,7 +151,6 @@ luaopen_multicast_core(lua_State *L) {
{ "bind", mc_bindrefer },
{ "close", mc_closelocal },
{ "remote", mc_remote },
{ "packstring", mc_packstring },
{ "packremote", mc_packremote },
{ "nextid", mc_nextid },
{ NULL, NULL },

View File

@@ -551,7 +551,7 @@ seri(lua_State *L, struct block *b, int len) {
}
int
_luaseri_unpack(lua_State *L) {
luaseri_unpack(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
@@ -595,7 +595,7 @@ _luaseri_unpack(lua_State *L) {
}
int
_luaseri_pack(lua_State *L) {
luaseri_pack(lua_State *L) {
struct block temp;
temp.next = NULL;
struct write_block wb;

View File

@@ -3,7 +3,7 @@
#include <lua.h>
int _luaseri_pack(lua_State *L);
int _luaseri_unpack(lua_State *L);
int luaseri_pack(lua_State *L);
int luaseri_unpack(lua_State *L);
#endif

View File

@@ -81,7 +81,7 @@ forward_cb(struct skynet_context * context, void * ud, int type, int session, ui
}
static int
_callback(lua_State *L) {
lcallback(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
int forward = lua_toboolean(L, 2);
luaL_checktype(L,1,LUA_TFUNCTION);
@@ -101,7 +101,7 @@ _callback(lua_State *L) {
}
static int
_command(lua_State *L) {
lcommand(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * cmd = luaL_checkstring(L,1);
const char * result;
@@ -119,7 +119,7 @@ _command(lua_State *L) {
}
static int
_intcommand(lua_State *L) {
lintcommand(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * cmd = luaL_checkstring(L,1);
const char * result;
@@ -141,7 +141,7 @@ _intcommand(lua_State *L) {
}
static int
_genid(lua_State *L) {
lgenid(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
int session = skynet_send(context, 0, 0, PTYPE_TAG_ALLOCSESSION , 0 , NULL, 0);
lua_pushinteger(L, session);
@@ -167,7 +167,7 @@ get_dest_string(lua_State *L, int index) {
integer len
*/
static int
_send(lua_State *L) {
lsend(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
uint32_t dest = (uint32_t)lua_tointeger(L, 1);
const char * dest_string = NULL;
@@ -224,7 +224,7 @@ _send(lua_State *L) {
}
static int
_redirect(lua_State *L) {
lredirect(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
uint32_t dest = (uint32_t)lua_tointeger(L,1);
const char * dest_string = NULL;
@@ -267,14 +267,32 @@ _redirect(lua_State *L) {
}
static int
_error(lua_State *L) {
lerror(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
skynet_error(context, "%s", luaL_checkstring(L,1));
int n = lua_gettop(L);
if (n <= 1) {
lua_settop(L, 1);
const char * s = luaL_tolstring(L, 1, NULL);
skynet_error(context, "%s", s);
return 0;
}
luaL_Buffer b;
luaL_buffinit(L, &b);
int i;
for (i=1; i<=n; i++) {
luaL_tolstring(L, i, NULL);
luaL_addvalue(&b);
if (i<n) {
luaL_addchar(&b, ' ');
}
}
luaL_pushresult(&b);
skynet_error(context, "%s", lua_tostring(L, -1));
return 0;
}
static int
_tostring(lua_State *L) {
ltostring(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
@@ -285,7 +303,7 @@ _tostring(lua_State *L) {
}
static int
_harbor(lua_State *L) {
lharbor(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
uint32_t handle = (uint32_t)luaL_checkinteger(L,1);
int harbor = 0;
@@ -298,7 +316,7 @@ _harbor(lua_State *L) {
static int
lpackstring(lua_State *L) {
_luaseri_pack(L);
luaseri_pack(L);
char * str = (char *)lua_touserdata(L, -2);
int sz = lua_tointeger(L, -1);
lua_pushlstring(L, str, sz);
@@ -338,19 +356,19 @@ luaopen_skynet_core(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "send" , _send },
{ "genid", _genid },
{ "redirect", _redirect },
{ "command" , _command },
{ "intcommand", _intcommand },
{ "error", _error },
{ "tostring", _tostring },
{ "harbor", _harbor },
{ "pack", _luaseri_pack },
{ "unpack", _luaseri_unpack },
{ "send" , lsend },
{ "genid", lgenid },
{ "redirect", lredirect },
{ "command" , lcommand },
{ "intcommand", lintcommand },
{ "error", lerror },
{ "tostring", ltostring },
{ "harbor", lharbor },
{ "pack", luaseri_pack },
{ "unpack", luaseri_unpack },
{ "packstring", lpackstring },
{ "trash" , ltrash },
{ "callback", _callback },
{ "callback", lcallback },
{ "now", lnow },
{ NULL, NULL },
};

View File

@@ -210,13 +210,13 @@ Each integer number must be serialized in little-endian format.
The sproto message must be a user defined type struct, and a struct is encoded in three parts. The header, the field part, and the data part.
The tag and small integer or boolean will be encoded in field part, and others are in data part.
All the fields must be encoded in ascending order (by tag). The tags of fields can be discontinuous, if a field is nil. (default value in lua), don't encode it in message.
All the fields must be encoded in ascending order (by tag, base 0). The tags of fields can be discontinuous, if a field is nil. (default value in lua), don't encode it in message.
The header is a 16bit integer. It is the number of fields.
Each field in field part is a 16bit integer (n). If n is zero, that means the field data is encoded in data part ;
If n is even (and not zero), the value of this field is n/2-1 ;
If n is even (and not zero), the value of this field is n/2-1 , and the tag increases 1;
If n is odd, that means the tags is not continuous, and we should add current tag by (n+1)/2 .

View File

@@ -126,7 +126,7 @@ encode(const struct sproto_arg *args) {
lua_replace(L, self->array_index);
}
self->array_index = 0;
return 0;
return SPROTO_CB_NOARRAY;
}
if (!lua_istable(L, -1)) {
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
@@ -147,7 +147,7 @@ encode(const struct sproto_arg *args) {
// iterate end
lua_pushnil(L);
lua_replace(L, self->iter_index);
return 0;
return SPROTO_CB_NIL;
}
lua_insert(L, -2);
lua_replace(L, self->iter_index);
@@ -159,7 +159,7 @@ encode(const struct sproto_arg *args) {
}
if (lua_isnil(L, -1)) {
lua_pop(L,1);
return 0;
return SPROTO_CB_NIL;
}
switch (args->type) {
case SPROTO_TINTEGER: {
@@ -203,10 +203,10 @@ encode(const struct sproto_arg *args) {
str = lua_tolstring(L, -1, &sz);
}
if (sz > args->length)
return -1;
return SPROTO_CB_ERROR;
memcpy(args->value, str, sz);
lua_pop(L,1);
return sz + 1; // The length of empty string is 1.
return sz;
}
case SPROTO_TSTRUCT: {
struct encode_ud sub;
@@ -226,6 +226,8 @@ encode(const struct sproto_arg *args) {
sub.iter_index = sub.tbl_index + 1;
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
lua_settop(L, top-1); // pop the value
if (r < 0)
return SPROTO_CB_ERROR;
return r;
}
default:
@@ -309,7 +311,7 @@ decode(const struct sproto_arg *args) {
lua_State *L = self->L;
if (self->deep >= ENCODE_DEEPLEVEL)
return luaL_error(L, "The table is too deep");
if (args->index > 0) {
if (args->index != 0) {
// It's array
if (args->tagname != self->array_tag) {
self->array_tag = args->tagname;
@@ -321,6 +323,10 @@ decode(const struct sproto_arg *args) {
} else {
self->array_index = lua_gettop(L);
}
if (args->index < 0) {
// It's a empty array, return now.
return 0;
}
}
}
switch (args->type) {
@@ -355,9 +361,10 @@ decode(const struct sproto_arg *args) {
sub.key_index = lua_gettop(L);
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
if (r < 0 || r != args->length)
if (r < 0)
return SPROTO_CB_ERROR;
if (r != args->length)
return r;
// assert(args->index > 0);
lua_pushvalue(L, sub.key_index);
if (lua_isnil(L, -1)) {
luaL_error(L, "Can't find main index (tag=%d) in [%s]", args->mainindex, args->tagname);
@@ -370,7 +377,9 @@ decode(const struct sproto_arg *args) {
sub.mainindex_tag = -1;
sub.key_index = 0;
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
if (r < 0 || r != args->length)
if (r < 0)
return SPROTO_CB_ERROR;
if (r != args->length)
return r;
lua_settop(L, sub.result_index);
break;
@@ -469,7 +478,7 @@ lpack(lua_State *L) {
size_t sz=0;
const void * buffer = getbuffer(L, 1, &sz);
// the worst-case space overhead of packing is 2 bytes per 2 KiB of input (256 words = 2KiB).
size_t maxsz = (sz + 2047) / 2048 * 2 + sz;
size_t maxsz = (sz + 2047) / 2048 * 2 + sz + 2;
void * output = lua_touserdata(L, lua_upvalueindex(1));
int bytes;
int osz = lua_tointeger(L, lua_upvalueindex(2));
@@ -532,6 +541,9 @@ lprotocol(lua_State *L) {
lua_pushstring(L, name);
} else {
const char * name = lua_tostring(L, 2);
if (name == NULL) {
return luaL_argerror(L, 2, "Should be number or string");
}
tag = sproto_prototag(sp, name);
if (tag < 0)
return 0;
@@ -592,6 +604,8 @@ encode_default(const struct sproto_arg *args) {
lua_pushstring(L, args->tagname);
if (args->index > 0) {
lua_newtable(L);
lua_rawset(L, -3);
return SPROTO_CB_NOARRAY;
} else {
switch(args->type) {
case SPROTO_TINTEGER:
@@ -609,9 +623,9 @@ encode_default(const struct sproto_arg *args) {
lua_setfield(L, -2, "__type");
break;
}
lua_rawset(L, -3);
return SPROTO_CB_NIL;
}
lua_rawset(L, -3);
return 0;
}
/*

View File

@@ -677,10 +677,10 @@ encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int si
args->value = data+SIZEOF_LENGTH;
args->length = size-SIZEOF_LENGTH;
sz = cb(args);
if (sz <= 0)
return sz;
if (args->type == SPROTO_TSTRING) {
--sz; // the length of null string is 1
if (sz < 0) {
if (sz == SPROTO_CB_NIL)
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow
return fill_size(data, sz);
@@ -702,7 +702,7 @@ uint32_to_uint64(int negative, uint8_t *buffer) {
}
static uint8_t *
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size) {
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size, int *noarray) {
uint8_t * header = buffer;
int intlen;
int index;
@@ -712,6 +712,8 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
size--;
intlen = sizeof(uint32_t);
index = 1;
*noarray = 0;
for (;;) {
int sz;
union {
@@ -722,10 +724,15 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
args->length = sizeof(u);
args->index = index;
sz = cb(args);
if (sz < 0)
return NULL;
if (sz == 0) // nil object, end of array
break;
if (sz <= 0) {
if (sz == SPROTO_CB_NIL) // nil object, end of array
break;
if (sz == SPROTO_CB_NOARRAY) { // no array, don't encode it
*noarray = 1;
break;
}
return NULL; // sz == SPROTO_CB_ERROR
}
if (size < sizeof(uint64_t))
return NULL;
if (sz == sizeof(uint32_t)) {
@@ -790,11 +797,17 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
size -= SIZEOF_LENGTH;
buffer = data + SIZEOF_LENGTH;
switch (args->type) {
case SPROTO_TINTEGER:
buffer = encode_integer_array(cb,args,buffer,size);
case SPROTO_TINTEGER: {
int noarray;
buffer = encode_integer_array(cb,args,buffer,size, &noarray);
if (buffer == NULL)
return -1;
if (noarray) {
return 0;
}
break;
}
case SPROTO_TBOOLEAN:
args->index = 1;
for (;;) {
@@ -802,10 +815,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = &v;
args->length = sizeof(v);
sz = cb(args);
if (sz < 0)
return -1;
if (sz == 0) // nil object , end of array
break;
if (sz < 0) {
if (sz == SPROTO_CB_NIL) // nil object , end of array
break;
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (size < 1)
return -1;
buffer[0] = v ? 1: 0;
@@ -823,12 +839,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = buffer+SIZEOF_LENGTH;
args->length = size;
sz = cb(args);
if (sz == 0)
break;
if (sz < 0)
return -1;
if (args->type == SPROTO_TSTRING) {
--sz;
if (sz < 0) {
if (sz == SPROTO_CB_NIL) {
break;
}
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
fill_size(buffer, sz);
buffer += SIZEOF_LENGTH+sz;
@@ -838,8 +855,6 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
break;
}
sz = buffer - (data + SIZEOF_LENGTH);
if (sz == 0) // empty array
return 0;
return fill_size(data, sz);
}
@@ -885,10 +900,13 @@ sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_call
args.value = &u;
args.length = sizeof(u);
sz = cb(&args);
if (sz < 0)
return -1;
if (sz == 0) // nil object
continue;
if (sz < 0) {
if (sz == SPROTO_CB_NIL)
continue;
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (sz == sizeof(uint32_t)) {
if (u.u32 < 0x7fff) {
value = (u.u32+1) * 2;
@@ -985,13 +1003,18 @@ decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
uint32_t sz = todword(stream);
int type = args->type;
int i;
if (sz == 0) {
// It's empty array, call cb with index == -1 to create the empty array.
args->index = -1;
args->value = NULL;
args->length = 0;
cb(args);
return 0;
}
stream += SIZEOF_LENGTH;
switch (type) {
case SPROTO_TINTEGER: {
int len;
if (sz < 1)
return -1;
len = *stream;
int len = *stream;
++stream;
--sz;
if (len == sizeof(uint32_t)) {

View File

@@ -14,6 +14,10 @@ struct sproto_type;
#define SPROTO_TSTRING 2
#define SPROTO_TSTRUCT 3
#define SPROTO_CB_ERROR -1
#define SPROTO_CB_NIL -2
#define SPROTO_CB_NOARRAY -3
struct sproto * sproto_create(const void * proto, size_t sz);
void sproto_release(struct sproto *);

View File

@@ -72,7 +72,8 @@ local function request(fd, method, host, url, recvheader, header, content)
body = body .. padding
end
else
body = nil
-- no content-length, read all
body = body .. socket.readall(fd)
end
end

View File

@@ -8,7 +8,43 @@ local socket_error = setmetatable({} , { __tostring = function() return "[Socket
sockethelper.socket_error = socket_error
function sockethelper.readfunc(fd)
local function preread(fd, str)
return function (sz)
if str then
if sz == #str or sz == nil then
local ret = str
str = nil
return ret
else
if sz < #str then
local ret = str:sub(1,sz)
str = str:sub(sz + 1)
return ret
else
sz = sz - #str
local ret = readbytes(fd, sz)
if ret then
return str .. ret
else
error(socket_error)
end
end
end
else
local ret = readbytes(fd, sz)
if ret then
return ret
else
error(socket_error)
end
end
end
end
function sockethelper.readfunc(fd, pre)
if pre then
return preread(fd, pre)
end
return function (sz)
local ret = readbytes(fd, sz)
if ret then
@@ -19,6 +55,8 @@ function sockethelper.readfunc(fd)
end
end
sockethelper.readall = socket.readall
function sockethelper.writefunc(fd)
return function(content)
local ok = writebytes(fd, content)

View File

@@ -4,6 +4,7 @@ local socketchannel = require "socketchannel"
local skynet = require "skynet"
local driver = require "mongo.driver"
local md5 = require "md5"
local crypt = require "crypt"
local rawget = rawget
local assert = assert
@@ -83,10 +84,15 @@ end
local function mongo_auth(mongoc)
local user = rawget(mongoc, "username")
local pass = rawget(mongoc, "password")
local authmod = rawget(mongoc, "authmod") or "scram_sha1"
authmod = "auth_" .. authmod
return function()
if user ~= nil and pass ~= nil then
assert(mongoc:auth(user, pass))
-- autmod can be "mongodb_cr" or "scram_sha1"
local auth_func = mongoc[authmod]
assert(auth_func , "Invalid authmod")
assert(auth_func(mongoc,user, pass))
end
local rs_data = mongoc:runCommand("ismaster")
if rs_data.ok == 1 then
@@ -99,12 +105,38 @@ local function mongo_auth(mongoc)
mongoc.__sock:changebackup(backup)
end
if rs_data.ismaster then
if rawget(mongoc, "__pickserver") then
rawset(mongoc, "__pickserver", nil)
end
return
else
local host, port = __parse_addr(rs_data.primary)
mongoc.host = host
mongoc.port = port
mongoc.__sock:changehost(host, port)
if rs_data.primary then
local host, port = __parse_addr(rs_data.primary)
mongoc.host = host
mongoc.port = port
mongoc.__sock:changehost(host, port)
else
skynet.error("WARNING: NO PRIMARY RETURN " .. rs_data.me)
-- determine the primary db using hosts
local pickserver = {}
if rawget(mongoc, "__pickserver") == nil then
for _, v in ipairs(rs_data.hosts) do
if v ~= rs_data.me then
table.insert(pickserver, v)
end
rawset(mongoc, "__pickserver", pickserver)
end
end
if #mongoc.__pickserver <= 0 then
error("CAN NOT DETERMINE THE PRIMARY DB")
end
skynet.error("INFO: TRY TO CONNECT " .. mongoc.__pickserver[1])
local host, port = __parse_addr(mongoc.__pickserver[1])
table.remove(mongoc.__pickserver, 1)
mongoc.host = host
mongoc.port = port
mongoc.__sock:changehost(host, port)
end
end
end
end
@@ -122,6 +154,7 @@ function mongo.client( conf )
port = first.port or 27017,
username = first.username,
password = first.password,
authmod = first.authmod,
}
obj.__id = 0
@@ -172,7 +205,7 @@ function mongo_client:runCommand(...)
return self.admin:runCommand(...)
end
function mongo_client:auth(user,password)
function mongo_client:auth_mongodb_cr(user,password)
local password = md5.sumhexa(string.format("%s:mongo:%s",user,password))
local result= self:runCommand "getnonce"
if result.ok ~=1 then
@@ -184,6 +217,83 @@ function mongo_client:auth(user,password)
return result.ok == 1
end
local function salt_password(password, salt, iter)
salt = salt .. "\0\0\0\1"
local output = crypt.hmac_sha1(password, salt)
local inter = output
for i=2,iter do
inter = crypt.hmac_sha1(password, inter)
output = crypt.xor_str(output, inter)
end
return output
end
function mongo_client:auth_scram_sha1(username,password)
local user = string.gsub(string.gsub(username, '=', '=3D'), ',' , '=2C')
local nonce = crypt.base64encode(crypt.randomkey())
local first_bare = "n=" .. user .. ",r=" .. nonce
local sasl_start_payload = crypt.base64encode("n,," .. first_bare)
local r
r = self:runCommand("saslStart",1,"autoAuthorize",1,"mechanism","SCRAM-SHA-1","payload",sasl_start_payload)
if r.ok ~= 1 then
return false
end
local conversationId = r['conversationId']
local server_first = r['payload']
local parsed_s = crypt.base64decode(server_first)
local parsed_t = {}
for k, v in string.gmatch(parsed_s, "(%w+)=([^,]*)") do
parsed_t[k] = v
end
local iterations = tonumber(parsed_t['i'])
local salt = parsed_t['s']
local rnonce = parsed_t['r']
if not string.sub(rnonce, 1, 12) == nonce then
skynet.error("Server returned an invalid nonce.")
return false
end
local without_proof = "c=biws,r=" .. rnonce
local pbkdf2_key = md5.sumhexa(string.format("%s:mongo:%s",username,password))
local salted_pass = salt_password(pbkdf2_key, crypt.base64decode(salt), iterations)
local client_key = crypt.hmac_sha1(salted_pass, "Client Key")
local stored_key = crypt.sha1(client_key)
local auth_msg = first_bare .. ',' .. parsed_s .. ',' .. without_proof
local client_sig = crypt.hmac_sha1(stored_key, auth_msg)
local client_key_xor_sig = crypt.xor_str(client_key, client_sig)
local client_proof = "p=" .. crypt.base64encode(client_key_xor_sig)
local client_final = crypt.base64encode(without_proof .. ',' .. client_proof)
local server_key = crypt.hmac_sha1(salted_pass, "Server Key")
local server_sig = crypt.base64encode(crypt.hmac_sha1(server_key, auth_msg))
r = self:runCommand("saslContinue",1,"conversationId",conversationId,"payload",client_final)
if r.ok ~= 1 then
return false
end
parsed_s = crypt.base64decode(r['payload'])
parsed_t = {}
for k, v in string.gmatch(parsed_s, "(%w+)=([^,]*)") do
parsed_t[k] = v
end
if parsed_t['v'] ~= server_sig then
skynet.error("Server returned an invalid signature.")
return false
end
if not r.done then
r = self:runCommand("saslContinue",1,"conversationId",conversationId,"payload","")
if r.ok ~= 1 then
return false
end
if not r.done then
skynet.error("SASL conversation failed to complete.")
return false
end
end
return true
end
function mongo_client:logout()
local result = self:runCommand "logout"
return result.ok == 1
@@ -318,30 +428,73 @@ function mongo_cursor:count(with_limit_and_skip)
end
-- For compatibility.
-- collection:createIndex({username = 1}, {unique = true})
function mongo_collection:createIndex(keys, option)
local name = option.name
option.name = nil
if not name then
for k, v in pairs(keys) do
name = (name == nil) and k or (name .. "_" .. k)
name = name .. "_" .. v
end
end
local doc = {};
doc.name = name
doc.key = keys
for k, v in pairs(option) do
local function createIndex_onekey(self, key, option)
local doc = {}
for k,v in pairs(option) do
doc[k] = v
end
local k,v = next(key) -- support only one key
assert(next(key,k) == nil, "Use new api for multi-keys")
doc.name = doc.name or (k .. "_" .. v)
doc.key = key
return self.database:runCommand("createIndexes", self.name, "indexes", {doc})
end
mongo_collection.ensureIndex = mongo_collection.createIndex;
local function IndexModel(option)
local doc = {}
for k,v in pairs(option) do
if type(k) == "string" then
doc[k] = v
end
end
local keys = {}
local name
for _, kv in ipairs(option) do
local k,v
if type(kv) == "string" then
k = kv
v = 1
else
k,v = next(kv)
end
table.insert(keys, k)
table.insert(keys, v)
name = (name == nil) and k or (name .. "_" .. k)
name = name .. "_" .. v
end
assert(name, "Need keys")
doc.name = doc.name or name
doc.key = bson_encode_order(table.unpack(keys))
return doc
end
-- collection:createIndex { { key1 = 1}, { key2 = 1 }, unique = true }
-- or collection:createIndex { "key1", "key2", unique = true }
-- or collection:createIndex( { key1 = 1} , { unique = true } ) -- For compatibility
function mongo_collection:createIndex(arg1 , arg2)
if arg2 then
return createIndex_onekey(self, arg1, arg2)
else
return self.database:runCommand("createIndexes", self.name, "indexes", { IndexModel(arg1) })
end
end
function mongo_collection:createIndexes(...)
local idx = { ... }
for k,v in ipairs(idx) do
idx[k] = IndexModel(v)
end
return self.database:runCommand("createIndexes", self.name, "indexes", idx)
end
mongo_collection.ensureIndex = mongo_collection.createIndex
function mongo_collection:drop()
return self.database:runCommand("drop", self.name)

View File

@@ -125,19 +125,6 @@ local function _compose_packet(self, req, size)
return packet
end
local function _send_packet(self, req, size)
local sock = self.sock
self.packet_no = self.packet_no + 1
local packet = _set_byte3(size) .. strchar(self.packet_no) .. req
return socket.write(self.sock,packet)
end
local function _recv_packet(self,sock)
@@ -620,6 +607,10 @@ local function _query_resp(self)
while err =="again" do
res, err, errno, sqlstate = read_result(self,sock)
if not res then
mulitresultset.badresult = true
mulitresultset.err = err
mulitresultset.errno = errno
mulitresultset.sqlstate = sqlstate
return true, mulitresultset
end
mulitresultset[i]=res

View File

@@ -54,43 +54,16 @@ redcmd[42] = function(fd, data) -- '*'
local noerr = true
for i = 1,n do
local ok, v = read_response(fd)
if ok then
bulk[i] = v
else
if not ok then
noerr = false
end
bulk[i] = v
end
return noerr, bulk
end
-------------------
local function redis_login(auth, db)
if auth == nil and db == nil then
return
end
return function(so)
if auth then
so:request("AUTH "..auth.."\r\n", read_response)
end
if db then
so:request("SELECT "..db.."\r\n", read_response)
end
end
end
function redis.connect(db_conf)
local channel = socketchannel.channel {
host = db_conf.host,
port = db_conf.port or 6379,
auth = redis_login(db_conf.auth, db_conf.db),
nodelay = true,
}
-- try connect first only once
channel:connect(true)
return setmetatable( { channel }, meta )
end
function command:disconnect()
self[1]:close()
setmetatable(self, nil)
@@ -150,6 +123,32 @@ local function compose_message(cmd, msg)
return lines
end
local function redis_login(auth, db)
if auth == nil and db == nil then
return
end
return function(so)
if auth then
so:request(compose_message("AUTH", auth), read_response)
end
if db then
so:request(compose_message("SELECT", db), read_response)
end
end
end
function redis.connect(db_conf)
local channel = socketchannel.channel {
host = db_conf.host,
port = db_conf.port or 6379,
auth = redis_login(db_conf.auth, db_conf.db),
nodelay = true,
}
-- try connect first only once
channel:connect(true)
return setmetatable( { channel }, meta )
end
setmetatable(command, { __index = function(t,k)
local cmd = string.upper(k)
local f = function (self, v, ...)
@@ -234,7 +233,7 @@ local watchmeta = {
local function watch_login(obj, auth)
return function(so)
if auth then
so:request("AUTH "..auth.."\r\n", read_response)
so:request(compose_message("AUTH", auth), read_response)
end
for k in pairs(obj.__psubscribe) do
so:request(compose_message ("PSUBSCRIBE", k))

View File

@@ -28,12 +28,12 @@ function sharedata.query(name)
return r
end
function sharedata.new(name, v)
skynet.call(service, "lua", "new", name, v)
function sharedata.new(name, v, ...)
skynet.call(service, "lua", "new", name, v, ...)
end
function sharedata.update(name, v)
skynet.call(service, "lua", "update", name, v)
function sharedata.update(name, v, ...)
skynet.call(service, "lua", "update", name, v, ...)
end
function sharedata.delete(name)

View File

@@ -95,7 +95,7 @@ end
-- coroutine reuse
local coroutine_pool = {}
local coroutine_pool = setmetatable({}, { __mode = "kv" })
local function co_create(f)
local co = table.remove(coroutine_pool)
@@ -343,12 +343,7 @@ function skynet.exit()
end
function skynet.getenv(key)
local ret = c.command("GETENV",key)
if ret == "" then
return
else
return ret
end
return (c.command("GETENV",key))
end
function skynet.setenv(key, value)
@@ -553,13 +548,7 @@ function skynet.harbor(addr)
return c.harbor(addr)
end
function skynet.error(...)
local t = {...}
for i=1,#t do
t[i] = tostring(t[i])
end
return c.error(table.concat(t, " "))
end
skynet.error = c.error
----- register protocol
do
@@ -592,9 +581,9 @@ function skynet.init(f, name)
if init_func == nil then
f()
else
if name == nil then
table.insert(init_func, f)
else
table.insert(init_func, f)
if name then
assert(type(name) == "string")
assert(init_func[name] == nil)
init_func[name] = f
end
@@ -605,8 +594,8 @@ local function init_all()
local funcs = init_func
init_func = nil
if funcs then
for k,v in pairs(funcs) do
v()
for _,f in ipairs(funcs) do
f()
end
end
end
@@ -616,14 +605,14 @@ local function ret(f, ...)
return ...
end
local function init_template(start)
local function init_template(start, ...)
init_all()
init_func = {}
return ret(init_all, start())
return ret(init_all, start(...))
end
function skynet.pcall(start)
return xpcall(init_template, debug.traceback, start)
function skynet.pcall(start, ...)
return xpcall(init_template, debug.traceback, start, ...)
end
function skynet.init_service(start)
@@ -667,15 +656,15 @@ function skynet.term(service)
return _error_dispatch(0, service)
end
local function clear_pool()
coroutine_pool = {}
function skynet.memlimit(bytes)
debug.getregistry().memlimit = bytes
skynet.memlimit = nil -- set only once
end
-- Inject internal debug framework
local debug = require "skynet.debug"
debug(skynet, {
debug.init(skynet, {
dispatch = skynet.dispatch_message,
clear = clear_pool,
suspend = suspend,
})

View File

@@ -10,7 +10,6 @@ local coroutine_running = coroutine.running
local select = select
local skynetco = {}
skynetco.create = coroutine.create
skynetco.isyieldable = coroutine.isyieldable
skynetco.running = coroutine.running
skynetco.status = coroutine.status

View File

@@ -1,90 +1,105 @@
local io = io
local table = table
local debug = debug
local extern_dbgcmd = {}
return function (skynet, export)
local function init(skynet, export)
local internal_info_func
local internal_info_func
function skynet.info_func(func)
internal_info_func = func
end
local dbgcmd
local function init_dbgcmd()
dbgcmd = {}
function dbgcmd.MEM()
local kb, bytes = collectgarbage "count"
skynet.ret(skynet.pack(kb,bytes))
end
function dbgcmd.GC()
export.clear()
collectgarbage "collect"
end
function dbgcmd.STAT()
local stat = {}
stat.mqlen = skynet.mqlen()
stat.task = skynet.task()
skynet.ret(skynet.pack(stat))
end
function dbgcmd.TASK()
local task = {}
skynet.task(task)
skynet.ret(skynet.pack(task))
end
function dbgcmd.INFO()
if internal_info_func then
skynet.ret(skynet.pack(internal_info_func()))
else
skynet.ret(skynet.pack(nil))
function skynet.info_func(func)
internal_info_func = func
end
local dbgcmd
local function init_dbgcmd()
dbgcmd = {}
function dbgcmd.MEM()
local kb, bytes = collectgarbage "count"
skynet.ret(skynet.pack(kb,bytes))
end
function dbgcmd.GC()
collectgarbage "collect"
end
function dbgcmd.STAT()
local stat = {}
stat.mqlen = skynet.mqlen()
stat.task = skynet.task()
skynet.ret(skynet.pack(stat))
end
function dbgcmd.TASK()
local task = {}
skynet.task(task)
skynet.ret(skynet.pack(task))
end
function dbgcmd.INFO(...)
if internal_info_func then
skynet.ret(skynet.pack(internal_info_func(...)))
else
skynet.ret(skynet.pack(nil))
end
end
function dbgcmd.EXIT()
skynet.exit()
end
function dbgcmd.RUN(source, filename)
local inject = require "skynet.inject"
local output = inject(skynet, source, filename , export.dispatch, skynet.register_protocol)
collectgarbage "collect"
skynet.ret(skynet.pack(table.concat(output, "\n")))
end
function dbgcmd.TERM(service)
skynet.term(service)
end
function dbgcmd.REMOTEDEBUG(...)
local remotedebug = require "skynet.remotedebug"
remotedebug.start(export, ...)
end
function dbgcmd.SUPPORT(pname)
return skynet.ret(skynet.pack(skynet.dispatch(pname) ~= nil))
end
function dbgcmd.PING()
return skynet.ret()
end
function dbgcmd.LINK()
-- no return, raise error when exit
end
return dbgcmd
end -- function init_dbgcmd
local function _debug_dispatch(session, address, cmd, ...)
dbgcmd = dbgcmd or init_dbgcmd() -- lazy init dbgcmd
local f = dbgcmd[cmd] or extern_dbgcmd[cmd]
assert(f, cmd)
f(...)
end
skynet.register_protocol {
name = "debug",
id = assert(skynet.PTYPE_DEBUG),
pack = assert(skynet.pack),
unpack = assert(skynet.unpack),
dispatch = _debug_dispatch,
}
end
function dbgcmd.EXIT()
skynet.exit()
local function reg_debugcmd(name, fn)
extern_dbgcmd[name] = fn
end
function dbgcmd.RUN(source, filename)
local inject = require "skynet.inject"
local output = inject(skynet, source, filename , export.dispatch, skynet.register_protocol)
collectgarbage "collect"
skynet.ret(skynet.pack(table.concat(output, "\n")))
end
function dbgcmd.TERM(service)
skynet.term(service)
end
function dbgcmd.REMOTEDEBUG(...)
local remotedebug = require "skynet.remotedebug"
remotedebug.start(export, ...)
end
function dbgcmd.SUPPORT(pname)
return skynet.ret(skynet.pack(skynet.dispatch(pname) ~= nil))
end
return dbgcmd
end -- function init_dbgcmd
local function _debug_dispatch(session, address, cmd, ...)
local f = (dbgcmd or init_dbgcmd())[cmd] -- lazy init dbgcmd
assert(f, cmd)
f(...)
end
skynet.register_protocol {
name = "debug",
id = assert(skynet.PTYPE_DEBUG),
pack = assert(skynet.pack),
unpack = assert(skynet.unpack),
dispatch = _debug_dispatch,
return {
init = init,
reg_debugcmd = reg_debugcmd,
}
end

View File

@@ -1,6 +1,6 @@
local skynet = require "skynet"
local debugchannel = require "debugchannel"
local socket = require "socket"
local socketdriver = require "socketdriver"
local injectrun = require "skynet.injectcode"
local table = table
local debug = debug
@@ -56,7 +56,7 @@ local function gen_print(fd)
tmp[i] = tostring(tmp[i])
end
table.insert(tmp, "\n")
socket.write(fd, table.concat(tmp, "\t"))
socketdriver.send(fd, table.concat(tmp, "\t"))
end
end
@@ -140,10 +140,13 @@ end
local function watch_proto(protoname, cond)
local proto = assert(replace_upvalue(skynet.register_protocol, "proto"), "Can't find proto table")
local p = proto[protoname]
local dispatch = p.dispatch_origin or p.dispatch
if p == nil or dispatch == nil then
if p == nil then
return "No " .. protoname
end
local dispatch = p.dispatch_origin or p.dispatch
if dispatch == nil then
return "No dispatch"
end
p.dispatch_origin = dispatch
p.dispatch = function(...)
if not cond or cond(...) then
@@ -208,7 +211,7 @@ local function hook_dispatch(dispatcher, resp, fd, channel)
local function debug_hook()
while true do
if newline then
socket.write(fd, prompt)
socketdriver.send(fd, prompt)
newline = false
end
local cmd = channel:read()
@@ -244,7 +247,9 @@ local function hook_dispatch(dispatcher, resp, fd, channel)
func = replace_upvalue(dispatcher, HOOK_FUNC, hook)
if func then
local function idle()
skynet.timeout(10,idle) -- idle every 0.1s
if raw_dispatcher then
skynet.timeout(10,idle) -- idle every 0.1s
end
end
skynet.timeout(0, idle)
end

View File

@@ -1,7 +1,4 @@
local si = require "snax.interface"
local io = io
local hotfix = {}
local function envid(f)
local i = 1

View File

@@ -407,8 +407,6 @@ end
---------------------- UDP
local udp_socket = {}
local function create_udp_object(id, cb)
assert(not socket_pool[id], "socket is not closed")
socket_pool[id] = {

View File

@@ -328,7 +328,8 @@ local function block_connect(self, once)
r = check_connection(self)
if r == nil then
error(string.format("Connect to %s:%d failed (%s)", self.__host, self.__port, err))
skynet.error(string.format("Connect to %s:%d failed (%s)", self.__host, self.__port, err))
error(socket_error)
else
return r
end
@@ -411,10 +412,10 @@ end
function channel:close()
if not self.__closed then
local thread = assert(self.__dispatch_thread)
local thread = self.__dispatch_thread
self.__closed = true
close_channel_socket(self)
if not self.__response and self.__dispatch_thread == thread then
if not self.__response and self.__dispatch_thread == thread and thread then
-- dispatch by order, send close signal to dispatch thread
push_response(self, true, false) -- (true, false) is close signal
end

View File

@@ -180,9 +180,10 @@ end
local header_tmp = {}
local function gen_response(self, response, session)
return function(args)
return function(args, ud)
header_tmp.type = nil
header_tmp.session = session
header_tmp.ud = ud
local header = core.encode(self.__package, header_tmp)
if response then
local content = core.encode(response, args)
@@ -197,6 +198,7 @@ function host:dispatch(...)
local bin = core.unpack(...)
header_tmp.type = nil
header_tmp.session = nil
header_tmp.ud = nil
local header, size = core.decode(self.__package, bin, header_tmp)
local content = bin:sub(size + 1)
if header.type then
@@ -207,9 +209,9 @@ function host:dispatch(...)
result = core.decode(proto.request, content)
end
if header_tmp.session then
return "REQUEST", proto.name, result, gen_response(self, proto.response, header_tmp.session)
return "REQUEST", proto.name, result, gen_response(self, proto.response, header_tmp.session), header.ud
else
return "REQUEST", proto.name, result
return "REQUEST", proto.name, result, nil, header.ud
end
else
-- response
@@ -217,19 +219,20 @@ function host:dispatch(...)
local response = assert(self.__session[session], "Unknown session")
self.__session[session] = nil
if response == true then
return "RESPONSE", session
return "RESPONSE", session, nil, header.ud
else
local result = core.decode(response, content)
return "RESPONSE", session, result
return "RESPONSE", session, result, header.ud
end
end
end
function host:attach(sp)
return function(name, args, session)
return function(name, args, session, ud)
local proto = queryproto(sp, name)
header_tmp.type = proto.tag
header_tmp.session = session
header_tmp.ud = ud
local header = core.encode(self.__package, header_tmp)
if session then

View File

@@ -346,7 +346,6 @@ dispatch_name_queue(struct harbor *h, struct keyvalue * node) {
struct harbor_msg_queue * queue = node->queue;
uint32_t handle = node->value;
int harbor_id = handle >> HANDLE_REMOTE_SHIFT;
assert(harbor_id != 0);
struct skynet_context * context = h->ctx;
struct slave *s = &h->s[harbor_id];
int fd = s->fd;
@@ -366,6 +365,16 @@ dispatch_name_queue(struct harbor *h, struct keyvalue * node) {
push_queue_msg(s->queue, m);
}
}
if (harbor_id == (h->slave >> HANDLE_REMOTE_SHIFT)) {
// the harbor_id is local
struct harbor_msg * m;
while ((m = pop_queue(s->queue)) != NULL) {
int type = m->header.destination >> HANDLE_REMOTE_SHIFT;
skynet_send(context, m->header.source, handle , type | PTYPE_TAG_DONTCOPY, m->header.session, m->buffer, m->size);
}
release_queue(s->queue);
s->queue = NULL;
}
}
return;
}

View File

@@ -3,9 +3,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
struct logger {
FILE * handle;
char * filename;
int close;
};
@@ -14,6 +16,8 @@ logger_create(void) {
struct logger * inst = skynet_malloc(sizeof(*inst));
inst->handle = NULL;
inst->close = 0;
inst->filename = NULL;
return inst;
}
@@ -22,16 +26,26 @@ logger_release(struct logger * inst) {
if (inst->close) {
fclose(inst->handle);
}
skynet_free(inst->filename);
skynet_free(inst);
}
static int
_logger(struct skynet_context * context, void *ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
logger_cb(struct skynet_context * context, void *ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct logger * inst = ud;
fprintf(inst->handle, "[:%08x] ",source);
fwrite(msg, sz , 1, inst->handle);
fprintf(inst->handle, "\n");
fflush(inst->handle);
switch (type) {
case PTYPE_SYSTEM:
if (inst->filename) {
inst->handle = freopen(inst->filename, "a", inst->handle);
}
break;
case PTYPE_TEXT:
fprintf(inst->handle, "[:%08x] ",source);
fwrite(msg, sz , 1, inst->handle);
fprintf(inst->handle, "\n");
fflush(inst->handle);
break;
}
return 0;
}
@@ -43,12 +57,14 @@ logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm)
if (inst->handle == NULL) {
return 1;
}
inst->filename = skynet_malloc(strlen(parm)+1);
strcpy(inst->filename, parm);
inst->close = 1;
} else {
inst->handle = stdout;
}
if (inst->handle) {
skynet_callback(ctx, inst, _logger);
skynet_callback(ctx, inst, logger_cb);
skynet_command(ctx, "REG", ".logger");
return 0;
}

View File

@@ -9,9 +9,14 @@
#include <stdlib.h>
#include <stdio.h>
#define MEMORY_WARNING_REPORT (1024 * 1024 * 32)
struct snlua {
lua_State * L;
struct skynet_context * ctx;
size_t mem;
size_t mem_report;
size_t mem_limit;
};
// LUA_CACHELIB may defined in patched lua for shared proto
@@ -53,7 +58,7 @@ traceback (lua_State *L) {
}
static void
_report_launcher_error(struct skynet_context *ctx) {
report_launcher_error(struct skynet_context *ctx) {
// sizeof "ERROR" == 5
skynet_sendname(ctx, 0, ".launcher", PTYPE_TEXT, 0, "ERROR", 5);
}
@@ -68,7 +73,7 @@ optstring(struct skynet_context *ctx, const char *key, const char * str) {
}
static int
_init(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) {
init_cb(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) {
lua_State *L = l->L;
l->ctx = ctx;
lua_gc(L, LUA_GCSTOP, 0);
@@ -101,17 +106,25 @@ _init(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz)
int r = luaL_loadfile(L,loader);
if (r != LUA_OK) {
skynet_error(ctx, "Can't load %s : %s", loader, lua_tostring(L, -1));
_report_launcher_error(ctx);
report_launcher_error(ctx);
return 1;
}
lua_pushlstring(L, args, sz);
r = lua_pcall(L,1,0,1);
if (r != LUA_OK) {
skynet_error(ctx, "lua loader error : %s", lua_tostring(L, -1));
_report_launcher_error(ctx);
report_launcher_error(ctx);
return 1;
}
lua_settop(L,0);
if (lua_getfield(L, LUA_REGISTRYINDEX, "memlimit") == LUA_TNUMBER) {
size_t limit = lua_tointeger(L, -1);
l->mem_limit = limit;
skynet_error(ctx, "Set memory limit to %.2f M", (float)limit / (1024 * 1024));
lua_pushnil(L);
lua_setfield(L, LUA_REGISTRYINDEX, "memlimit");
}
lua_pop(L, 1);
lua_gc(L, LUA_GCRESTART, 0);
@@ -119,11 +132,11 @@ _init(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz)
}
static int
_launch(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) {
launch_cb(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) {
assert(type == 0 && session == 0);
struct snlua *l = ud;
skynet_callback(context, NULL, NULL);
int err = _init(l, context, msg, sz);
int err = init_cb(l, context, msg, sz);
if (err) {
skynet_command(context, "EXIT", NULL);
}
@@ -136,7 +149,7 @@ snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) {
int sz = strlen(args);
char * tmp = skynet_malloc(sz);
memcpy(tmp, args, sz);
skynet_callback(ctx, l , _launch);
skynet_callback(ctx, l , launch_cb);
const char * self = skynet_command(ctx, "REG", NULL);
uint32_t handle_id = strtoul(self+1, NULL, 16);
// it must be first message
@@ -144,11 +157,33 @@ snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) {
return 0;
}
static void *
lalloc(void * ud, void *ptr, size_t osize, size_t nsize) {
struct snlua *l = ud;
size_t mem = l->mem;
l->mem += nsize;
if (ptr)
l->mem -= osize;
if (l->mem_limit != 0 && l->mem > l->mem_limit) {
if (ptr == NULL || nsize > osize) {
l->mem = mem;
return NULL;
}
}
if (l->mem > l->mem_report) {
l->mem_report *= 2;
skynet_error(l->ctx, "Memory warning %.2f M", (float)l->mem / (1024 * 1024));
}
return skynet_lalloc(ptr, osize, nsize);
}
struct snlua *
snlua_create(void) {
struct snlua * l = skynet_malloc(sizeof(*l));
memset(l,0,sizeof(*l));
l->L = lua_newstate(skynet_lalloc, NULL);
l->mem_report = MEMORY_WARNING_REPORT;
l->mem_limit = 0;
l->L = lua_newstate(lalloc, l);
return l;
}
@@ -161,8 +196,12 @@ snlua_release(struct snlua *l) {
void
snlua_signal(struct snlua *l, int signal) {
skynet_error(l->ctx, "recv a signal %d", signal);
if (signal == 0) {
#ifdef lua_checksig
// If our lua support signal (modified lua version by skynet), trigger it.
skynet_sig_L = l->L;
#endif
} else if (signal == 1) {
skynet_error(l->ctx, "Current Memory %.3fK", (float)l->mem / 1024);
}
}

View File

@@ -4,15 +4,15 @@ require "skynet.manager" -- import skynet.launch, ...
local memory = require "memory"
skynet.start(function()
local sharestring = tonumber(skynet.getenv "sharestring")
memory.ssexpand(sharestring or 4096)
local sharestring = tonumber(skynet.getenv "sharestring" or 4096)
memory.ssexpand(sharestring)
local standalone = skynet.getenv "standalone"
local launcher = assert(skynet.launch("snlua","launcher"))
skynet.name(".launcher", launcher)
local harbor_id = tonumber(skynet.getenv "harbor")
local harbor_id = tonumber(skynet.getenv "harbor" or 0)
if harbor_id == 0 then
assert(standalone == nil)
standalone = true

View File

@@ -215,6 +215,7 @@ function harbor.QUERYNAME(fd, name)
end
local queue = queryname[name]
if queue == nil then
socket.write(fd, pack_package("Q", name))
queue = { skynet.response() }
queryname[name] = queue
else

View File

@@ -4,6 +4,8 @@ local core = require "skynet.core"
local socket = require "socket"
local snax = require "snax"
local memory = require "memory"
local httpd = require "http.httpd"
local sockethelper = require "http.sockethelper"
local port = tonumber(...)
local COMMAND = {}
@@ -52,13 +54,10 @@ end
local function docmd(cmdline, print, fd)
local split = split_cmdline(cmdline)
local command = split[1]
if command == "debug" then
table.insert(split, fd)
end
local cmd = COMMAND[command]
local ok, list
if cmd then
ok, list = pcall(cmd, select(2,table.unpack(split)))
ok, list = pcall(cmd, fd, select(2,table.unpack(split)))
else
print("Invalid command, type help for command list")
end
@@ -79,18 +78,28 @@ local function docmd(cmdline, print, fd)
end
local function console_main_loop(stdin, print)
socket.lock(stdin)
print("Welcome to skynet console")
while true do
local cmdline = socket.readline(stdin, "\n")
if not cmdline then
break
skynet.error(stdin, "connected")
pcall(function()
while true do
local cmdline = socket.readline(stdin, "\n")
if not cmdline then
break
end
if cmdline:sub(1,4) == "GET " then
-- http
local code, url = httpd.read_request(sockethelper.readfunc(stdin, cmdline.. "\n"), 8192)
local cmdline = url:sub(2):gsub("/"," ")
docmd(cmdline, print, stdin)
break
end
if cmdline ~= "" then
docmd(cmdline, print, stdin)
end
end
if cmdline ~= "" then
docmd(cmdline, print, stdin)
end
end
socket.unlock(stdin)
end)
skynet.error(stdin, "disconnected")
socket.close(stdin)
end
skynet.start(function()
@@ -115,7 +124,7 @@ function COMMAND.help()
help = "This help message",
list = "List all the service",
stat = "Dump all stats",
info = "Info address : get service infomation",
info = "info address : get service infomation",
exit = "exit address : kill a lua service",
kill = "kill address : kill service",
mem = "mem : show memory status",
@@ -133,6 +142,7 @@ function COMMAND.help()
signal = "signal address sig",
cmem = "Show C memory info",
shrtbl = "Show shared short string table info",
ping = "ping address",
}
end
@@ -140,25 +150,33 @@ function COMMAND.clearcache()
codecache.clear()
end
function COMMAND.start(...)
function COMMAND.start(fd, ...)
local ok, addr = pcall(skynet.newservice, ...)
if ok then
return { [skynet.address(addr)] = ... }
if addr then
return { [skynet.address(addr)] = ... }
else
return "Exit"
end
else
return "Failed"
end
end
function COMMAND.log(...)
function COMMAND.log(fd, ...)
local ok, addr = pcall(skynet.call, ".launcher", "lua", "LOGLAUNCH", "snlua", ...)
if ok then
return { [skynet.address(addr)] = ... }
if addr then
return { [skynet.address(addr)] = ... }
else
return "Failed"
end
else
return "Failed"
end
end
function COMMAND.snax(...)
function COMMAND.snax(fd, ...)
local ok, s = pcall(snax.newservice, ...)
if ok then
local addr = s.handle
@@ -191,7 +209,7 @@ function COMMAND.mem()
return skynet.call(".launcher", "lua", "MEM")
end
function COMMAND.kill(address)
function COMMAND.kill(fd, address)
return skynet.call(".launcher", "lua", "KILL", address)
end
@@ -199,11 +217,11 @@ function COMMAND.gc()
return skynet.call(".launcher", "lua", "GC")
end
function COMMAND.exit(address)
function COMMAND.exit(fd, address)
skynet.send(adjust_address(address), "debug", "EXIT")
end
function COMMAND.inject(address, filename)
function COMMAND.inject(fd, address, filename)
address = adjust_address(address)
local f = io.open(filename, "rb")
if not f then
@@ -214,17 +232,17 @@ function COMMAND.inject(address, filename)
return skynet.call(address, "debug", "RUN", source, filename)
end
function COMMAND.task(address)
function COMMAND.task(fd, address)
address = adjust_address(address)
return skynet.call(address,"debug","TASK")
end
function COMMAND.info(address)
function COMMAND.info(fd, address, ...)
address = adjust_address(address)
return skynet.call(address,"debug","INFO")
return skynet.call(address,"debug","INFO", ...)
end
function COMMAND.debug(address, fd)
function COMMAND.debug(fd, address)
address = adjust_address(address)
local agent = skynet.newservice "debug_agent"
local stop
@@ -243,17 +261,17 @@ function COMMAND.debug(address, fd)
stop = true
end
function COMMAND.logon(address)
function COMMAND.logon(fd, address)
address = adjust_address(address)
core.command("LOGON", skynet.address(address))
end
function COMMAND.logoff(address)
function COMMAND.logoff(fd, address)
address = adjust_address(address)
core.command("LOGOFF", skynet.address(address))
end
function COMMAND.signal(address, sig)
function COMMAND.signal(fd, address, sig)
address = skynet.address(adjust_address(address))
if sig then
core.command("SIGNAL", string.format("%s %d",address,sig))
@@ -275,3 +293,11 @@ function COMMAND.shrtbl()
local n, total, longest, space = memory.ssinfo()
return { n = n, total = total, longest = longest, space = space }
end
function COMMAND.ping(fd, address)
address = adjust_address(address)
local ti = skynet.now()
skynet.call(address, "debug", "PING")
ti = skynet.now() - ti
return tostring(ti)
end

View File

@@ -24,7 +24,10 @@ end
function command.STAT()
local list = {}
for k,v in pairs(services) do
local stat = skynet.call(k,"debug","STAT")
local ok, stat = pcall(skynet.call,k,"debug","STAT")
if not ok then
stat = string.format("ERROR (%s)",v)
end
list[skynet.address(k)] = stat
end
return list
@@ -41,8 +44,12 @@ end
function command.MEM()
local list = {}
for k,v in pairs(services) do
local kb, bytes = skynet.call(k,"debug","MEM")
list[skynet.address(k)] = string.format("%.2f Kb (%s)",kb,v)
local ok, kb, bytes = pcall(skynet.call,k,"debug","MEM")
if not ok then
list[skynet.address(k)] = string.format("ERROR (%s)",v)
else
list[skynet.address(k)] = string.format("%.2f Kb (%s)",kb,v)
end
end
return list
end

View File

@@ -78,13 +78,13 @@ local function publish(c , source, pack, size)
local group = channel[c]
if group == nil or next(group) == nil then
-- dead channel, delete the pack. mc.bind returns the pointer in pack
-- dead channel, delete the pack. mc.bind returns the pointer in pack and free the pack (struct mc_package **)
local pack = mc.bind(pack, 1)
mc.close(pack)
return
end
mc.bind(pack, channel_n[c])
local msg = skynet.tostring(pack, size)
local msg = skynet.tostring(pack, size) -- copy (pack,size) to a string
mc.bind(pack, channel_n[c]) -- mc.bind will free the pack(struct mc_package **)
for k in pairs(group) do
-- the msg is a pointer to the real message, publish pointer in local is ok.
skynet.redirect(k, source, "multicast", c , msg)

View File

@@ -142,14 +142,23 @@ local function register_global()
end
local function register_local()
function cmd.GLAUNCH(name, ...)
local function waitfor_remote(cmd, name, ...)
local global_name = "@" .. name
return waitfor(global_name, skynet.call, "SERVICE", "lua", "LAUNCH", global_name, ...)
local local_name
if name == "snaxd" then
local_name = global_name .. "." .. (...)
else
local_name = global_name
end
return waitfor(local_name, skynet.call, "SERVICE", "lua", cmd, global_name, ...)
end
function cmd.GQUERY(name, ...)
local global_name = "@" .. name
return waitfor(global_name, skynet.call, "SERVICE", "lua", "QUERY", global_name, ...)
function cmd.GLAUNCH(...)
return waitfor_remote("LAUNCH", ...)
end
function cmd.GQUERY(...)
return waitfor_remote("QUERY", ...)
end
function cmd.LIST()

View File

@@ -38,7 +38,7 @@ local CMD = {}
local env_mt = { __index = _ENV }
function CMD.new(name, t)
function CMD.new(name, t, ...)
local dt = type(t)
local value
if dt == "table" then
@@ -51,7 +51,7 @@ function CMD.new(name, t)
else
f = assert(load(t, "=" .. name, "bt", value))
end
local _, ret = assert(skynet.pcall(f))
local _, ret = assert(skynet.pcall(f, ...))
setmetatable(value, nil)
if type(ret) == "table" then
value = ret
@@ -90,7 +90,7 @@ function CMD.confirm(cobj)
return NORET
end
function CMD.update(name, t)
function CMD.update(name, t, ...)
local v = pool[name]
local watch, oldcobj
if v then
@@ -101,7 +101,7 @@ function CMD.update(name, t)
pool[name] = nil
pool_count[name] = nil
end
CMD.new(name, t)
CMD.new(name, t, ...)
local newobj = pool[name].obj
if watch then
sharedata.host.markdirty(oldcobj)

View File

@@ -227,7 +227,7 @@ skynet_strdup(const char *str) {
}
void *
skynet_lalloc(void *ud, void *ptr, size_t osize, size_t nsize) {
skynet_lalloc(void *ptr, size_t osize, size_t nsize) {
if (nsize == 0) {
raw_free(ptr);
return NULL;

View File

@@ -115,7 +115,7 @@ main(int argc, char *argv[]) {
struct skynet_config config;
struct lua_State *L = lua_newstate(skynet_lalloc, NULL);
struct lua_State *L = luaL_newstate();
luaL_openlibs(L); // link lua lib
int err = luaL_loadstring(L, load_config);

View File

@@ -13,6 +13,6 @@ void * skynet_calloc(size_t nmemb,size_t size);
void * skynet_realloc(void *ptr, size_t size);
void skynet_free(void *ptr);
char * skynet_strdup(const char *str);
void * skynet_lalloc(void *ud, void *ptr, size_t osize, size_t nsize); // use for lua
void * skynet_lalloc(void *ptr, size_t osize, size_t nsize); // use for lua
#endif

View File

@@ -84,7 +84,7 @@ skynet_mq_create(uint32_t handle) {
SPIN_INIT(q)
// When the queue is create (always between service create and service init) ,
// set in_global flag to avoid push it to global queue .
// If the service init success, skynet_context_new will call skynet_mq_force_push to push it to global queue.
// If the service init success, skynet_context_new will call skynet_mq_push to push it to global queue.
q->in_global = MQ_IN_GLOBAL;
q->release = 0;
q->overload = 0;

View File

@@ -16,6 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
struct monitor {
int count;
@@ -32,6 +33,15 @@ struct worker_parm {
int weight;
};
static int SIG = 0;
static void
handle_hup(int signal) {
if (signal == SIGHUP) {
SIG = 1;
}
}
#define CHECK_ABORT if (skynet_context_total()==0) break;
static void
@@ -100,6 +110,21 @@ thread_monitor(void *p) {
return NULL;
}
static void
signal_hup() {
// make log file reopen
struct skynet_message smsg;
smsg.source = 0;
smsg.session = 0;
smsg.data = NULL;
smsg.sz = (size_t)PTYPE_SYSTEM << MESSAGE_TYPE_SHIFT;
uint32_t logger = skynet_handle_findname("logger");
if (logger) {
skynet_context_push(logger, &smsg);
}
}
static void *
thread_timer(void *p) {
struct monitor * m = p;
@@ -109,6 +134,10 @@ thread_timer(void *p) {
CHECK_ABORT
wakeup(m,m->count-1);
usleep(2500);
if (SIG) {
signal_hup();
SIG = 0;
}
}
// wakeup socket thread
skynet_socket_exit();
@@ -216,6 +245,13 @@ bootstrap(struct skynet_context * logger, const char * cmdline) {
void
skynet_start(struct skynet_config * config) {
// register SIGHUP for log file reopen
struct sigaction sa;
sa.sa_handler = &handle_hup;
sa.sa_flags = SA_RESTART;
sigfillset(&sa.sa_mask);
sigaction(SIGHUP, &sa, NULL);
if (config->daemon) {
if (daemon_init(config->daemon)) {
exit(1);

View File

@@ -16,7 +16,7 @@ struct socket_server;
struct socket_message {
int id;
uintptr_t opaque;
int ud; // for accept, ud is listen id ; for data, ud is size of data
int ud; // for accept, ud is new connection id ; for data, ud is size of data
char * data;
};

95
test/testbson.lua Normal file
View File

@@ -0,0 +1,95 @@
local bson = require "bson"
sub = bson.encode_order( "hello", 1, "world", 2 )
local function tbl_next(...)
print("--- next.a", ...)
local k, v = next(...)
print("--- next.b", k, v)
return k, v
end
local function tbl_pairs(obj)
return tbl_next, obj.__data, nil
end
local obj_a = {
__data = {
[1] = 2,
[3] = 4,
[5] = 6,
}
}
setmetatable(
obj_a,
{
__index = obj_a.__data,
__pairs = tbl_pairs,
}
)
local obj_b = {
__data = {
[7] = 8,
[9] = 10,
[11] = obj_a,
}
}
setmetatable(
obj_b,
{
__index = obj_b.__data,
__pairs = tbl_pairs,
}
)
local metaarray = setmetatable({ n = 5 }, {
__len = function(self) return self.n end,
__index = function(self, idx) return tostring(idx) end,
})
b = bson.encode {
a = 1,
b = true,
c = bson.null,
d = { 1,2,3,4 },
e = bson.binary "hello",
f = bson.regex ("*","i"),
g = bson.regex "hello",
h = bson.date (os.time()),
i = bson.timestamp(os.time()),
j = bson.objectid(),
k = { a = false, b = true },
l = {},
m = bson.minkey,
n = bson.maxkey,
o = sub,
p = 2^32-1,
q = obj_b,
r = metaarray,
}
print "\n[before replace]"
t = b:decode()
for k, v in pairs(t) do
print(k,type(v))
end
for k,v in ipairs(t.r) do
print(k,v)
end
b:makeindex()
b.a = 2
b.b = false
b.h = bson.date(os.time())
b.i = bson.timestamp(os.time())
b.j = bson.objectid()
print "\n[after replace]"
t = b:decode()
print("o.hello", bson.type(t.o.hello))

26
test/testmemlimit.lua Normal file
View File

@@ -0,0 +1,26 @@
local skynet = require "skynet"
local names = {"cluster", "dns", "mongo", "mysql", "redis", "sharedata", "socket", "sproto"}
-- set sandbox memory limit to 1M, must set here (at start, out of skynet.start)
skynet.memlimit(1 * 1024 * 1024)
skynet.start(function()
local a = {}
local limit
local ok, err = pcall(function()
for i=1, 12355 do
limit = i
table.insert(a, {})
end
end)
local libs = {}
for k,v in ipairs(names) do
local ok, m = pcall(require, v)
if ok then
libs[v] = m
end
end
skynet.error(limit, err)
skynet.exit()
end)