From d4023c8b6314b4f8017c6bf702875ce16f87b84b Mon Sep 17 00:00:00 2001 From: sanikoyes Date: Thu, 2 Jul 2015 16:25:10 +0800 Subject: [PATCH 01/97] fix invalid fd after reconnected, used in unpack_f --- examples/login/client.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/login/client.lua b/examples/login/client.lua index 4180e7a7..f7c48018 100644 --- a/examples/login/client.lua +++ b/examples/login/client.lua @@ -131,7 +131,7 @@ local text = "echo" local index = 1 print("connect") -local fd = assert(socket.connect("127.0.0.1", 8888)) +fd = assert(socket.connect("127.0.0.1", 8888)) last = "" local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index) @@ -151,7 +151,7 @@ socket.close(fd) index = index + 1 print("connect again") -local fd = assert(socket.connect("127.0.0.1", 8888)) +fd = assert(socket.connect("127.0.0.1", 8888)) last = "" local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index) From 55cf9375fc11e816ff1bdc5746a7aaa49591839b Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 3 Jul 2015 10:58:40 +0800 Subject: [PATCH 02/97] asterisk(*) should be once or not at all --- lualib/sprotoparser.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lualib/sprotoparser.lua b/lualib/sprotoparser.lua index 7b0b04e2..03524ac0 100644 --- a/lualib/sprotoparser.lua +++ b/lualib/sprotoparser.lua @@ -81,7 +81,7 @@ end local typedef = P { "ALL", - FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)), + FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^-1 * typename * mainkey^0)), STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}", TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ), SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")), From 86bbc9c7011cce8966d192d14ee9c8c8667c35ad Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 7 Jul 2015 12:11:16 +0800 Subject: [PATCH 03/97] off by 1 error --- skynet-src/socket_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index 1b480da7..78f9b47b 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -1265,7 +1265,7 @@ send_request(struct socket_server *ss, struct request_package *request, char typ static int open_request(struct socket_server *ss, struct request_package *req, uintptr_t opaque, const char *addr, int port) { int len = strlen(addr); - if (len + sizeof(req->u.open) > 256) { + if (len + sizeof(req->u.open) >= 256) { fprintf(stderr, "socket-server : Invalid addr %s.\n",addr); return -1; } From ea2437e138a92a0182f19a3e88c431cf2a985c5b Mon Sep 17 00:00:00 2001 From: sanikoyes Date: Thu, 9 Jul 2015 18:07:32 +0800 Subject: [PATCH 04/97] lunpack optimize, do not unpack twice if r <= osz --- lualib-src/sproto/lsproto.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lualib-src/sproto/lsproto.c b/lualib-src/sproto/lsproto.c index 50a05f67..16eaa022 100644 --- a/lualib-src/sproto/lsproto.c +++ b/lualib-src/sproto/lsproto.c @@ -487,10 +487,10 @@ lunpack(lua_State *L) { return luaL_error(L, "Invalid unpack stream"); if (r > osz) { output = expand_buffer(L, osz, r); + r = sproto_unpack(buffer, sz, output, r); + if (r < 0) + return luaL_error(L, "Invalid unpack stream"); } - r = sproto_unpack(buffer, sz, output, r); - if (r < 0) - return luaL_error(L, "Invalid unpack stream"); lua_pushlstring(L, output, r); return 1; } From d9ad981c8c3f55965327f7869038dad0a026cfa0 Mon Sep 17 00:00:00 2001 From: cxj Date: Fri, 10 Jul 2015 20:21:07 +0800 Subject: [PATCH 05/97] sproto optimize, malloc newchunk and return directly if sz >= CHUNK_SIZE in pool_alloc, do not replace current chunk if sz >= p->current_used in pool_alloc, more safety checking --- lualib-src/sproto/sproto.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lualib-src/sproto/sproto.c b/lualib-src/sproto/sproto.c index 8324d64f..b5d61ea6 100644 --- a/lualib-src/sproto/sproto.c +++ b/lualib-src/sproto/sproto.c @@ -83,7 +83,7 @@ static void * pool_alloc(struct pool *p, size_t sz) { // align by 8 sz = (sz + 7) & ~7; - if (sz > CHUNK_SIZE) { + if (sz >= CHUNK_SIZE) { return pool_newchunk(p, sz); } if (p->current == NULL) { @@ -97,7 +97,7 @@ pool_alloc(struct pool *p, size_t sz) { return ret; } - if (sz > p->current_used) { + if (sz >= p->current_used) { return pool_newchunk(p, sz); } else { void * ret = pool_newchunk(p, CHUNK_SIZE); @@ -305,7 +305,7 @@ import_type(struct sproto *s, struct sproto_type *t, const uint8_t * stream) { if (stream == NULL) return NULL; tag = f->tag; - if (tag < last) + if (tag <= last) return NULL; // tag must in ascending order if (tag > last+1) { ++maxn; @@ -394,7 +394,7 @@ create_from_bundle(struct sproto *s, const uint8_t * stream, size_t sz) { const uint8_t * protocoldata = NULL; int fn = struct_field(stream, sz); int i; - if (fn < 0) + if (fn < 0 || fn > 2) return NULL; stream += SIZEOF_HEADER; From 538414408d47af80b29e370db6b512807552b0c4 Mon Sep 17 00:00:00 2001 From: cxj Date: Mon, 13 Jul 2015 13:04:09 +0800 Subject: [PATCH 06/97] sharedata serialization bugfix --- examples/share.lua | 2 +- lualib-src/lua-seri.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/share.lua b/examples/share.lua index 2721d480..8bc4b497 100644 --- a/examples/share.lua +++ b/examples/share.lua @@ -43,7 +43,7 @@ skynet.start(function() for k,v in pairs(nobj) do skynet.error(string.format("nobj[%s]=%s", k,v)) end - for k,v in ipairs(nobj) do + for k,v in ipairs(nobj.b) do skynet.error(string.format("nobj.b[%d]=%s", k,v)) end diff --git a/lualib-src/lua-seri.c b/lualib-src/lua-seri.c index 0db2267d..c0761bd5 100644 --- a/lualib-src/lua-seri.c +++ b/lualib-src/lua-seri.c @@ -266,8 +266,10 @@ wb_table_metapairs(lua_State *L, struct write_block *wb, int index, int depth) { lua_copy(L, -5, -3); lua_call(L, 2, 2); int type = lua_type(L, -2); - if (type == LUA_TNIL) + if (type == LUA_TNIL) { + lua_pop(L, 4); break; + } pack_one(L, wb, -2, depth); pack_one(L, wb, -1, depth); lua_pop(L, 1); From a0ecd512307f074164f3c0580b444262ea7a48bb Mon Sep 17 00:00:00 2001 From: LiBei <252608386@qq.com> Date: Tue, 21 Jul 2015 11:12:55 +0800 Subject: [PATCH 07/97] Update cdummy.lua MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 误定义全局变量 --- service/cdummy.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/service/cdummy.lua b/service/cdummy.lua index 62865222..7926e35e 100644 --- a/service/cdummy.lua +++ b/service/cdummy.lua @@ -4,6 +4,7 @@ require "skynet.manager" -- import skynet.launch, ... local globalname = {} local queryname = {} local harbor = {} +local harbor_service skynet.register_protocol { name = "harbor", From 3f91484791e6be1610633f70b72d1725d803faf4 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 21 Jul 2015 11:31:27 +0800 Subject: [PATCH 08/97] user log service --- examples/config.userlog | 18 ++++++++++++++++++ examples/userlog.lua | 15 +++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 examples/config.userlog create mode 100644 examples/userlog.lua diff --git a/examples/config.userlog b/examples/config.userlog new file mode 100644 index 00000000..97bef6ef --- /dev/null +++ b/examples/config.userlog @@ -0,0 +1,18 @@ +root = "./" +thread = 8 +logger = "userlog" +logservice = "snlua" +logpath = "." +harbor = 1 +address = "127.0.0.1:2526" +master = "127.0.0.1:2013" +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" +-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run +snax = root.."examples/?.lua;"..root.."test/?.lua" +-- snax_interface_g = "snax_g" +cpath = root.."cservice/?.so" +-- daemon = "./skynet.pid" diff --git a/examples/userlog.lua b/examples/userlog.lua new file mode 100644 index 00000000..55aa0952 --- /dev/null +++ b/examples/userlog.lua @@ -0,0 +1,15 @@ +local skynet = require "skynet" +require "skynet.manager" + +skynet.register_protocol { + name = "text", + id = skynet.PTYPE_TEXT, + unpack = skynet.tostring, + dispatch = function(_, address, msg) + print(string.format("%x(%.2f): %s", address, skynet.time(), msg)) + end +} + +skynet.start(function() + skynet.register ".logger" +end) \ No newline at end of file From 4ebb139c2b930cf0054a6c9914efd958e5d2c627 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 22 Jul 2015 15:52:26 +0800 Subject: [PATCH 09/97] bugfix: free message when cluster not connected --- lualib-src/lua-cluster.c | 3 ++- service/clusterd.lua | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index c4875070..586f74bf 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -74,8 +74,9 @@ lpackrequest(lua_State *L) { return luaL_error(L, "Invalid request message"); } size_t sz = (size_t)luaL_checkinteger(L,4); - int session = luaL_checkinteger(L,2); + int session = luaL_optinteger(L,2,1); // new connection start with 1 if (session <= 0) { + skynet_free(msg); return luaL_error(L, "Invalid request session %d", session); } int addr_type = lua_type(L,1); diff --git a/service/clusterd.lua b/service/clusterd.lua index 12c4c4e7..3805be25 100644 --- a/service/clusterd.lua +++ b/service/clusterd.lua @@ -24,7 +24,6 @@ local function open_channel(t, key) } assert(c:connect(true)) t[key] = c - node_session[key] = 1 return c end @@ -63,11 +62,11 @@ function command.listen(source, addr, port) end local function send_request(source, node, addr, msg, sz) - local request - local c = node_channel[node] local session = node_session[node] -- msg is a local pointer, cluster.packrequest will free it - request, node_session[node] = cluster.packrequest(addr, session , msg, sz) + local request, new_session = cluster.packrequest(addr, session, msg, sz) + local c = node_channel[node] + node_session[node] = new_session return c:request(request, session) end From 588c4a350800b3676e23cbcf6ffef2a34dd000ea Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 22 Jul 2015 16:49:25 +0800 Subject: [PATCH 10/97] bugfix --- lualib-src/lua-cluster.c | 2 +- service/clusterd.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index 586f74bf..e9d9e142 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -74,7 +74,7 @@ lpackrequest(lua_State *L) { return luaL_error(L, "Invalid request message"); } size_t sz = (size_t)luaL_checkinteger(L,4); - int session = luaL_optinteger(L,2,1); // new connection start with 1 + int session = luaL_checkinteger(L,2); if (session <= 0) { skynet_free(msg); return luaL_error(L, "Invalid request session %d", session); diff --git a/service/clusterd.lua b/service/clusterd.lua index 3805be25..b0ee6335 100644 --- a/service/clusterd.lua +++ b/service/clusterd.lua @@ -62,7 +62,7 @@ function command.listen(source, addr, port) end local function send_request(source, node, addr, msg, sz) - local session = node_session[node] + local session = node_session[node] or 1 -- msg is a local pointer, cluster.packrequest will free it local request, new_session = cluster.packrequest(addr, session, msg, sz) local c = node_channel[node] From 39f9a96b6c3c8276d715d8a921f17767efe1dfb5 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 23 Jul 2015 16:47:35 +0800 Subject: [PATCH 11/97] add cmemory.info() returns a table of c memory info --- lualib-src/lua-memory.c | 1 + service/cmemory.lua | 6 +++++- skynet-src/malloc_hook.c | 15 +++++++++++++++ skynet-src/malloc_hook.h | 2 ++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lualib-src/lua-memory.c b/lualib-src/lua-memory.c index 17e7cd40..67a3acf6 100644 --- a/lualib-src/lua-memory.c +++ b/lualib-src/lua-memory.c @@ -42,6 +42,7 @@ luaopen_memory(lua_State *L) { { "block", lblock }, { "dumpinfo", ldumpinfo }, { "dump", ldump }, + { "info", dump_mem_lua }, { NULL, NULL }, }; diff --git a/service/cmemory.lua b/service/cmemory.lua index 06627ae3..e33eb42f 100644 --- a/service/cmemory.lua +++ b/service/cmemory.lua @@ -2,7 +2,11 @@ local skynet = require "skynet" local memory = require "memory" memory.dumpinfo() -memory.dump() +--memory.dump() +local info = memory.info() +for k,v in pairs(info) do + print(string.format(":%08x %gK",k,v/1024)) +end print("Total memory:", memory.total()) print("Total block:", memory.block()) diff --git a/skynet-src/malloc_hook.c b/skynet-src/malloc_hook.c index 9b3949a6..d9ad6f32 100644 --- a/skynet-src/malloc_hook.c +++ b/skynet-src/malloc_hook.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "malloc_hook.h" #include "skynet.h" @@ -224,3 +225,17 @@ skynet_lalloc(void *ud, void *ptr, size_t osize, size_t nsize) { return skynet_realloc(ptr, nsize); } } + +int +dump_mem_lua(lua_State *L) { + int i; + lua_newtable(L); + for(i=0; ihandle != 0 && data->allocated != 0) { + lua_pushinteger(L, data->allocated); + lua_rawseti(L, -2, (lua_Integer)data->handle); + } + } + return 1; +} diff --git a/skynet-src/malloc_hook.h b/skynet-src/malloc_hook.h index d35551d1..03339556 100644 --- a/skynet-src/malloc_hook.h +++ b/skynet-src/malloc_hook.h @@ -2,6 +2,7 @@ #define SKYNET_MALLOC_HOOK_H #include +#include extern size_t malloc_used_memory(void); extern size_t malloc_memory_block(void); @@ -9,6 +10,7 @@ extern void memory_info_dump(void); extern size_t mallctl_int64(const char* name, size_t* newval); extern int mallctl_opt(const char* name, int* newval); extern void dump_c_mem(void); +extern int dump_mem_lua(lua_State *L); #endif /* SKYNET_MALLOC_HOOK_H */ From b2d82373639cf2b3902f23078559b9945d19c023 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 23 Jul 2015 18:23:47 +0800 Subject: [PATCH 12/97] improve unregister protocol error report --- lualib/skynet.lua | 20 ++++++++++++++++---- lualib/skynet/debug.lua | 4 ++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lualib/skynet.lua b/lualib/skynet.lua index 02a966fb..cbc16034 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -415,9 +415,13 @@ function skynet.wakeup(co) end function skynet.dispatch(typename, func) - local p = assert(proto[typename],tostring(typename)) - assert(p.dispatch == nil, tostring(typename)) - p.dispatch = func + local p = proto[typename] + if func then + assert(p and (p.dispatch == nil), tostring(typename)) + p.dispatch = func + else + return p and p.dispatch + end end local function unknown_request(session, address, msg, sz, prototype) @@ -466,7 +470,15 @@ local function raw_dispatch_message(prototype, msg, sz, session, source, ...) suspend(co, coroutine.resume(co, true, msg, sz)) end else - local p = assert(proto[prototype], prototype) + local p = proto[prototype] + if p == nil then + if session ~= 0 then + c.send(source, skynet.PTYPE_ERROR, session, "") + else + unknown_request(session, source, msg, sz, prototype) + end + return + end local f = p.dispatch if f then local ref = watching_service[source] diff --git a/lualib/skynet/debug.lua b/lualib/skynet/debug.lua index 0bcb8edb..6c040c24 100644 --- a/lualib/skynet/debug.lua +++ b/lualib/skynet/debug.lua @@ -63,6 +63,10 @@ function dbgcmd.REMOTEDEBUG(...) remotedebug.start(export, ...) end +function dbgcmd.SUPPORT(pname) + return skynet.ret(skynet.pack(skynet.dispatch(pname) ~= nil)) +end + local function _debug_dispatch(session, address, cmd, ...) local f = dbgcmd[cmd] assert(f, cmd) From 1da8a6b38d31b493b64834a52ea3705f6ac3dd0d Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 23 Jul 2015 18:35:29 +0800 Subject: [PATCH 13/97] lazy init debug command --- lualib/skynet/debug.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lualib/skynet/debug.lua b/lualib/skynet/debug.lua index 6c040c24..635bdb31 100644 --- a/lualib/skynet/debug.lua +++ b/lualib/skynet/debug.lua @@ -10,7 +10,10 @@ function skynet.info_func(func) internal_info_func = func end -local dbgcmd = {} +local dbgcmd + +local function init_dbgcmd() +dbgcmd = {} function dbgcmd.MEM() local kb, bytes = collectgarbage "count" @@ -67,8 +70,11 @@ 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[cmd] + local f = (dbgcmd or init_dbgcmd())[cmd] -- lazy init dbgcmd assert(f, cmd) f(...) end From 0ee61de22ceb4c32a76ab26c67daef94e685d094 Mon Sep 17 00:00:00 2001 From: jintiao Date: Fri, 24 Jul 2015 00:48:24 +0800 Subject: [PATCH 14/97] skip jemalloc clean if jemalloc's makefile was missing --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 2982e62c..b92a1a33 100644 --- a/Makefile +++ b/Makefile @@ -130,7 +130,9 @@ clean : rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so cleanall: clean +ifneq (,$(wildcard 3rd/jemalloc/Makefile)) cd 3rd/jemalloc && $(MAKE) clean +endif cd 3rd/lua && $(MAKE) clean rm -f $(LUA_STATICLIB) From e87ac18b84339a0baa3432b9b352530dca00eb14 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 24 Jul 2015 17:50:42 +0800 Subject: [PATCH 15/97] expand lua stack first --- lualib-src/lua-sharedata.c | 1 + service-src/service_snlua.c | 21 ++++++++++++++++++++- skynet-src/malloc_hook.c | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lualib-src/lua-sharedata.c b/lualib-src/lua-sharedata.c index 6ef10f0a..e7a27c57 100644 --- a/lualib-src/lua-sharedata.c +++ b/lualib-src/lua-sharedata.c @@ -376,6 +376,7 @@ pconv(lua_State *L) { static void convert_stringmap(struct context *ctx, struct table *tbl) { lua_State *L = ctx->L; + lua_checkstack(L, ctx->string_index + LUA_MINSTACK); lua_settop(L, ctx->string_index + 1); lua_pushvalue(L, 1); struct state * s = lua_newuserdata(L, sizeof(*s)); diff --git a/service-src/service_snlua.c b/service-src/service_snlua.c index 89e607f6..b839b117 100644 --- a/service-src/service_snlua.c +++ b/service-src/service_snlua.c @@ -12,6 +12,7 @@ struct snlua { lua_State * L; struct skynet_context * ctx; + FILE *f; }; // LUA_CACHELIB may defined in patched lua for shared proto @@ -143,17 +144,35 @@ 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; + if (l->f) { + fprintf(l->f, "%p %d %d\n", ptr, (int)osize, (int)nsize); + } + if (nsize == 0) { + skynet_free(ptr); + return NULL; + } else { + return skynet_realloc(ptr, 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); + char tmp[L_tmpnam]; + l->f = fopen(tmpnam(tmp),"wb"); +// printf("%s\n", tmp); + l->L = lua_newstate(lalloc, l); return l; } void snlua_release(struct snlua *l) { lua_close(l->L); + fclose(l->f); skynet_free(l); } diff --git a/skynet-src/malloc_hook.c b/skynet-src/malloc_hook.c index d9ad6f32..3cff09fa 100644 --- a/skynet-src/malloc_hook.c +++ b/skynet-src/malloc_hook.c @@ -218,6 +218,7 @@ skynet_strdup(const char *str) { void * skynet_lalloc(void *ud, void *ptr, size_t osize, size_t nsize) { + printf("%p osize = %d nsize = %d\n", ptr, (int)osize, (int)nsize); if (nsize == 0) { skynet_free(ptr); return NULL; From b3f966bcaa00f5e8f3003fc24df7cb705122e356 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 29 Jul 2015 16:10:38 +0800 Subject: [PATCH 16/97] bugfix: multicast chan gc --- lualib/multicast.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lualib/multicast.lua b/lualib/multicast.lua index 1f5fbd15..181979cb 100644 --- a/lualib/multicast.lua +++ b/lualib/multicast.lua @@ -8,7 +8,9 @@ local dispatch = setmetatable({} , {__mode = "kv" }) local chan = {} local chan_meta = { __index = chan, - __gc = unsubscribe, + __gc = function(self) + self:unsubscribe() + end, __tostring = function (self) return string.format("[Multicast:%x]",self.channel) end, From 4cbead28d5ec78db8fd881a21d89291e65b0d813 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 29 Jul 2015 16:12:49 +0800 Subject: [PATCH 17/97] skynet.dispatch can replace old func --- lualib/skynet.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lualib/skynet.lua b/lualib/skynet.lua index cbc16034..8906f60d 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -417,8 +417,9 @@ end function skynet.dispatch(typename, func) local p = proto[typename] if func then - assert(p and (p.dispatch == nil), tostring(typename)) + local ret = p.dispatch p.dispatch = func + return ret else return p and p.dispatch end From 3b48beb42808f82264081dc5b577f87e08cc42be Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 30 Jul 2015 15:41:17 +0800 Subject: [PATCH 18/97] bson bugfix --- lualib-src/lua-bson.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lualib-src/lua-bson.c b/lualib-src/lua-bson.c index 52baa64c..9071f56d 100644 --- a/lualib-src/lua-bson.c +++ b/lualib-src/lua-bson.c @@ -243,12 +243,16 @@ append_key(struct bson *bs, int type, const char *key, size_t sz) { write_string(bs, key, sz); } +static inline int +is_32bit(int64_t v) { + return v >= INT32_MIN && v <= INT32_MAX; +} + static void append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { if (lua_isinteger(L, -1)) { int64_t i = lua_tointeger(L, -1); - int si = i >> 31; - if (si == 0 || si == -1) { + if (is_32bit(i)) { append_key(bs, BSON_INT32, key, sz); write_int32(bs, i); } else { From 704b016f2cec9ba7d0799c8bd1408b613fef0e64 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 4 Aug 2015 17:51:35 +0800 Subject: [PATCH 19/97] bugfix: inc session before get channel --- service/clusterd.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/service/clusterd.lua b/service/clusterd.lua index b0ee6335..fc8b4126 100644 --- a/service/clusterd.lua +++ b/service/clusterd.lua @@ -65,9 +65,11 @@ local function send_request(source, node, addr, msg, sz) local session = node_session[node] or 1 -- msg is a local pointer, cluster.packrequest will free it local request, new_session = cluster.packrequest(addr, session, msg, sz) - local c = node_channel[node] node_session[node] = new_session + -- node_channel[node] may yield or throw error + local c = node_channel[node] + return c:request(request, session) end From b5244b96aa119c2f99f3647dc7c9c63abe84e551 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 4 Aug 2015 16:47:55 +0800 Subject: [PATCH 20/97] cluster rpc support large package --- examples/cluster1.lua | 1 + examples/cluster2.lua | 7 +- lualib-src/lua-cluster.c | 361 ++++++++++++++++++++++++++++++++++----- lualib/socketchannel.lua | 68 ++++++-- service/clusterd.lua | 48 +++++- 5 files changed, 418 insertions(+), 67 deletions(-) diff --git a/examples/cluster1.lua b/examples/cluster1.lua index 9ba8fcbf..d44899ba 100644 --- a/examples/cluster1.lua +++ b/examples/cluster1.lua @@ -6,6 +6,7 @@ local snax = require "snax" skynet.start(function() local sdb = skynet.newservice("simpledb") skynet.name(".simpledb", sdb) + print(skynet.call(".simpledb", "lua", "SET", "a", "foobar")) print(skynet.call(".simpledb", "lua", "SET", "b", "foobar2")) print(skynet.call(".simpledb", "lua", "GET", "a")) diff --git a/examples/cluster2.lua b/examples/cluster2.lua index 09e53076..0aef412c 100644 --- a/examples/cluster2.lua +++ b/examples/cluster2.lua @@ -3,7 +3,12 @@ local cluster = require "cluster" skynet.start(function() local proxy = cluster.proxy("db", ".simpledb") - print(skynet.call(proxy, "lua", "GET", "a")) + local largekey = string.rep("X", 128*1024) + local largevalue = string.rep("R", 100 * 1024) + print(skynet.call(proxy, "lua", "SET", largekey, largevalue)) + local v = skynet.call(proxy, "lua", "GET", largekey) + assert(largevalue == v) + print(cluster.call("db", ".simpledb", "GET", "a")) print(cluster.call("db2", ".simpledb", "GET", "b")) diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index e9d9e142..c558fb0f 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -15,7 +15,8 @@ uint32_t next_session */ -#define TEMP_LENGTH 0x10007 +#define TEMP_LENGTH 0x8200 +#define MULTI_PART 0x8000 static void fill_uint32(uint8_t * buf, uint32_t n) { @@ -35,21 +36,69 @@ fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) { buf[1] = sz & 0xff; } -static void -packreq_number(lua_State *L, int session, void * msg, size_t sz) { +/* + The request package : + size <= 0x8000 (32K) and address is id + WORD sz+9 + BYTE 0 + DWORD addr + DWORD session + PADDING msg(sz) + size > 0x8000 and address is id + DWORD 13 + BYTE 1 ; multireq + DWORD addr + DWORD session + DWORD sz + + size <= 0x8000 (32K) and address is string + WORD sz+6+namelen + BYTE 0x80 + BYTE namelen + STRING name + DWORD session + PADDING msg(sz) + size > 0x8000 and address is string + DWORD 10 + namelen + BYTE 0x81 + BYTE namelen + STRING name + DWORD session + DWORD sz + + multi req + WORD sz + 5 + BYTE 2/3 ; 2:multipart, 3:multipart end + DWORD SESSION + PADDING msgpart(sz) + */ +static int +packreq_number(lua_State *L, int session, void * msg, uint32_t sz) { uint32_t addr = (uint32_t)lua_tointeger(L,1); uint8_t buf[TEMP_LENGTH]; - fill_header(L, buf, sz+9, msg); - buf[2] = 0; - fill_uint32(buf+3, addr); - fill_uint32(buf+7, (uint32_t)session); - memcpy(buf+11,msg,sz); + if (sz < MULTI_PART) { + fill_header(L, buf, sz+9, msg); + buf[2] = 0; + fill_uint32(buf+3, addr); + fill_uint32(buf+7, (uint32_t)session); + memcpy(buf+11,msg,sz); - lua_pushlstring(L, (const char *)buf, sz+11); + lua_pushlstring(L, (const char *)buf, sz+11); + return 0; + } else { + int part = (sz - 1) / MULTI_PART + 1; + fill_header(L, buf, 13, msg); + buf[2] = 0x80; + fill_uint32(buf+3, addr); + fill_uint32(buf+7, (uint32_t)session); + fill_uint32(buf+11, sz); + lua_pushlstring(L, (const char *)buf, 15); + return part; + } } -static void -packreq_string(lua_State *L, int session, void * msg, size_t sz) { +static int +packreq_string(lua_State *L, int session, void * msg, uint32_t sz) { size_t namelen = 0; const char *name = lua_tolstring(L, 1, &namelen); if (name == NULL || namelen < 1 || namelen > 255) { @@ -58,13 +107,53 @@ packreq_string(lua_State *L, int session, void * msg, size_t sz) { } uint8_t buf[TEMP_LENGTH]; - fill_header(L, buf, sz+5+namelen, msg); - buf[2] = (uint8_t)namelen; - memcpy(buf+3, name, namelen); - fill_uint32(buf+3+namelen, (uint32_t)session); - memcpy(buf+7+namelen,msg,sz); + if (sz < MULTI_PART) { + fill_header(L, buf, sz+6+namelen, msg); + buf[2] = 0x80; + buf[3] = (uint8_t)namelen; + memcpy(buf+4, name, namelen); + fill_uint32(buf+4+namelen, (uint32_t)session); + memcpy(buf+8+namelen,msg,sz); - lua_pushlstring(L, (const char *)buf, sz+7+namelen); + lua_pushlstring(L, (const char *)buf, sz+8+namelen); + return 0; + } else { + int part = (sz - 1) / MULTI_PART + 1; + fill_header(L, buf, 10+namelen, msg); + buf[2] = 0x81; + buf[3] = (uint8_t)namelen; + memcpy(buf+4, name, namelen); + fill_uint32(buf+4+namelen, (uint32_t)session); + fill_uint32(buf+8+namelen, sz); + + lua_pushlstring(L, (const char *)buf, 12+namelen); + return part; + } +} + +static void +packreq_multi(lua_State *L, int session, void * msg, uint32_t sz) { + uint8_t buf[TEMP_LENGTH]; + int part = (sz - 1) / MULTI_PART + 1; + int i; + char *ptr = msg; + for (i=0;i MULTI_PART) { + s = MULTI_PART; + buf[2] = 2; + } else { + s = sz; + buf[2] = 3; // the last multi part + } + fill_header(L, buf, s+5, msg); + fill_uint32(buf+3, (uint32_t)session); + memcpy(buf+7, ptr, s); + lua_pushlstring(L, (const char *)buf, s+7); + lua_rawseti(L, -2, i+1); + sz -= s; + ptr += s; + } } static int @@ -73,24 +162,33 @@ lpackrequest(lua_State *L) { if (msg == NULL) { return luaL_error(L, "Invalid request message"); } - size_t sz = (size_t)luaL_checkinteger(L,4); + uint32_t sz = (uint32_t)luaL_checkinteger(L,4); int session = luaL_checkinteger(L,2); if (session <= 0) { skynet_free(msg); return luaL_error(L, "Invalid request session %d", session); } int addr_type = lua_type(L,1); + int multipak; if (addr_type == LUA_TNUMBER) { - packreq_number(L, session, msg, sz); + multipak = packreq_number(L, session, msg, sz); } else { - packreq_string(L, session, msg, sz); + multipak = packreq_string(L, session, msg, sz); } + int current_session = session; if (++session < 0) { session = 1; } - skynet_free(msg); lua_pushinteger(L, session); - return 2; + if (multipak) { + lua_createtable(L, multipak, 0); + packreq_multi(L, current_session, msg, sz); + skynet_free(msg); + return 3; + } else { + skynet_free(msg); + return 2; + } } /* @@ -99,6 +197,7 @@ lpackrequest(lua_State *L) { uint32_t or string addr int session string msg + boolean padding */ static inline uint32_t @@ -107,44 +206,122 @@ unpack_uint32(const uint8_t * buf) { } static int -unpackreq_number(lua_State *L, const uint8_t * buf, size_t sz) { +unpackreq_number(lua_State *L, const uint8_t * buf, int sz) { if (sz < 9) { - return luaL_error(L, "Invalid cluster message"); + return luaL_error(L, "Invalid cluster message (size=%d)", sz); } uint32_t address = unpack_uint32(buf+1); uint32_t session = unpack_uint32(buf+5); - lua_pushinteger(L, (uint32_t)address); - lua_pushinteger(L, (uint32_t)session); + lua_pushinteger(L, address); + lua_pushinteger(L, session); lua_pushlstring(L, (const char *)buf+9, sz-9); return 3; } static int -unpackreq_string(lua_State *L, const uint8_t * buf, size_t sz) { - size_t namesz = buf[0]; - if (sz < namesz + 5) { - return luaL_error(L, "Invalid cluster message"); +unpackmreq_number(lua_State *L, const uint8_t * buf, int sz) { + if (sz != 15) { + return luaL_error(L, "Invalid cluster message size %d (multi req must be 15)", sz); } - lua_pushlstring(L, (const char *)buf+1, namesz); - uint32_t session = unpack_uint32(buf + namesz + 1); + uint32_t address = unpack_uint32(buf+1); + uint32_t session = unpack_uint32(buf+5); + uint32_t size = unpack_uint32(buf+9); + lua_pushinteger(L, address); + lua_pushinteger(L, session); + lua_pushinteger(L, size); + lua_pushboolean(L, 1); // padding multi part + + return 4; +} + +static int +unpackmreq_part(lua_State *L, const uint8_t * buf, int sz) { + if (sz < 5) { + return luaL_error(L, "Invalid cluster multi part message"); + } + int padding = (buf[0] == 2); + uint32_t session = unpack_uint32(buf+1); + lua_pushboolean(L, 0); // no address + lua_pushinteger(L, session); + lua_pushlstring(L, (const char *)buf+5, sz-5); + lua_pushboolean(L, padding); + + return 4; +} + +static int +unpackreq_string(lua_State *L, const uint8_t * buf, int sz) { + if (sz < 2) { + return luaL_error(L, "Invalid cluster message (size=%d)", sz); + } + size_t namesz = buf[1]; + if (sz < namesz + 6) { + return luaL_error(L, "Invalid cluster message (size=%d)", sz); + } + lua_pushlstring(L, (const char *)buf+2, namesz); + uint32_t session = unpack_uint32(buf + namesz + 2); lua_pushinteger(L, (uint32_t)session); - lua_pushlstring(L, (const char *)buf+1+namesz+4, sz - namesz - 5); + lua_pushlstring(L, (const char *)buf+2+namesz+4, sz - namesz - 6); return 3; } +static int +unpackmreq_string(lua_State *L, const uint8_t * buf, int sz) { + if (sz < 2) { + return luaL_error(L, "Invalid cluster message (size=%d)", sz); + } + size_t namesz = buf[1]; + if (sz < namesz + 10) { + return luaL_error(L, "Invalid cluster message (size=%d)", sz); + } + lua_pushlstring(L, (const char *)buf+2, namesz); + uint32_t session = unpack_uint32(buf + namesz + 2); + uint32_t size = unpack_uint32(buf + namesz + 6); + lua_pushinteger(L, session); + lua_pushinteger(L, size); + lua_pushboolean(L, 1); // padding multipart + + return 4; +} + static int lunpackrequest(lua_State *L) { - size_t sz; - const char *msg = luaL_checklstring(L,1,&sz); - if (msg[0] == 0) { + size_t ssz; + const char *msg = luaL_checklstring(L,1,&ssz); + int sz = (int)ssz; + switch (msg[0]) { + case 0: return unpackreq_number(L, (const uint8_t *)msg, sz); - } else { + case 1: + return unpackmreq_number(L, (const uint8_t *)msg, sz); + case 2: + case 3: + return unpackmreq_part(L, (const uint8_t *)msg, sz); + case '\x80': return unpackreq_string(L, (const uint8_t *)msg, sz); + case '\x81': + return unpackmreq_string(L, (const uint8_t *)msg, sz); + default: + return luaL_error(L, "Invalid req package type %d", msg[0]); } } +/* + DWORD session + BYTE type + 0: error + 1: ok + 2: multi begin + 3: multi part + 4: multi end + PADDING msg + type = 0, error msg + type = 1, msg + type = 2, DWORD size + type = 3/4, msg + */ /* int session boolean ok @@ -163,14 +340,54 @@ lpackresponse(lua_State *L) { if (lua_type(L,3) == LUA_TSTRING) { msg = (void *)lua_tolstring(L, 3, &sz); - if (sz > 0x1000) { - sz = 0x1000; - } } else { msg = lua_touserdata(L,3); sz = (size_t)luaL_checkinteger(L, 4); } + if (!ok) { + if (sz > MULTI_PART) { + // truncate the error msg if too long + sz = MULTI_PART; + } + } else { + if (sz > MULTI_PART) { + // return + int part = (sz - 1) / MULTI_PART + 1; + lua_createtable(L, part+1, 0); + uint8_t buf[TEMP_LENGTH]; + + // multi part begin + fill_header(L, buf, 9, msg); + fill_uint32(buf+2, session); + buf[6] = 2; + fill_uint32(buf+7, (uint32_t)sz); + lua_pushlstring(L, (const char *)buf, 11); + lua_rawseti(L, -2, 1); + + char * ptr = msg; + int i; + for (i=0;i MULTI_PART) { + s = MULTI_PART; + buf[6] = 3; + } else { + s = sz; + buf[6] = 4; + } + fill_header(L, buf, s+5, msg); + fill_uint32(buf+2, session); + memcpy(buf+7,ptr,s); + lua_pushlstring(L, (const char *)buf, s+7); + lua_rawseti(L, -2, i+2); + sz -= s; + ptr += s; + } + return 1; + } + } + uint8_t buf[TEMP_LENGTH]; fill_header(L, buf, sz+5, msg); fill_uint32(buf+2, session); @@ -187,6 +404,7 @@ lpackresponse(lua_State *L) { return integer session boolean ok string msg + boolean padding */ static int lunpackresponse(lua_State *L) { @@ -197,10 +415,66 @@ lunpackresponse(lua_State *L) { } uint32_t session = unpack_uint32((const uint8_t *)buf); lua_pushinteger(L, (lua_Integer)session); - lua_pushboolean(L, buf[4]); - lua_pushlstring(L, buf+5, sz-5); + switch(buf[4]) { + case 0: // error + lua_pushboolean(L, 0); + lua_pushlstring(L, buf+5, sz-5); + return 3; + case 1: // ok + case 4: // multi end + lua_pushboolean(L, 1); + lua_pushlstring(L, buf+5, sz-5); + return 3; + case 2: // multi begin + if (sz != 9) { + return 0; + } + sz = unpack_uint32((const uint8_t *)buf+5); + lua_pushboolean(L, 1); + lua_pushinteger(L, sz); + lua_pushboolean(L, 1); + return 4; + case 3: // multi part + lua_pushboolean(L, 1); + lua_pushlstring(L, buf+5, sz-5); + lua_pushboolean(L, 1); + return 4; + default: + return 0; + } +} - return 3; +static int +lconcat(lua_State *L) { + if (!lua_istable(L,1)) + return 0; + if (lua_geti(L,1,1) != LUA_TNUMBER) + return 0; + int sz = lua_tointeger(L,-1); + lua_pop(L,1); + char * buff = skynet_malloc(sz); + int idx = 2; + int offset = 0; + while(lua_geti(L,1,idx) == LUA_TSTRING) { + size_t s; + const char * str = lua_tolstring(L, -1, &s); + if (s+offset > sz) { + skynet_free(buff); + return 0; + } + memcpy(buff+offset, str, s); + lua_pop(L,1); + offset += s; + ++idx; + } + if (offset != sz) { + skynet_free(buff); + return 0; + } + // buff/sz will send to other service, See clusterd.lua + lua_pushlightuserdata(L, buff); + lua_pushinteger(L, sz); + return 2; } int @@ -210,6 +484,7 @@ luaopen_cluster_core(lua_State *L) { { "unpackrequest", lunpackrequest }, { "packresponse", lpackresponse }, { "unpackresponse", lunpackresponse }, + { "concat", lconcat }, { NULL, NULL }, }; luaL_checkversion(L); diff --git a/lualib/socketchannel.lua b/lualib/socketchannel.lua index 282e6283..9ff5d451 100644 --- a/lualib/socketchannel.lua +++ b/lualib/socketchannel.lua @@ -81,15 +81,27 @@ local function dispatch_by_session(self) local response = self.__response -- response() return session while self.__sock do - local ok , session, result_ok, result_data = pcall(response, self.__sock) + local ok , session, result_ok, result_data, padding = pcall(response, self.__sock) if ok and session then local co = self.__thread[session] - self.__thread[session] = nil if co then - self.__result[co] = result_ok - self.__result_data[co] = result_data - skynet.wakeup(co) + if padding and result_ok then + -- If padding is true, append result_data to a table (self.__result_data[co]) + local result = self.__result_data[co] or {} + self.__result_data[co] = result + table.insert(result, result_data) + else + self.__thread[session] = nil + self.__result[co] = result_ok + if result_ok and self.__result_data[co] then + table.insert(self.__result_data[co], result_data) + else + self.__result_data[co] = result_data + end + skynet.wakeup(co) + end else + self.__thread[session] = nil skynet.error("socket: unknown session :", session) end else @@ -127,11 +139,23 @@ local function dispatch_by_order(self) wakeup_all(self) end else - local ok, result_ok, result_data = pcall(func, self.__sock) + local ok, result_ok, result_data, padding = pcall(func, self.__sock) if ok then - self.__result[co] = result_ok - self.__result_data[co] = result_data - skynet.wakeup(co) + if padding and result_ok then + -- if padding is true, wait for next result_data + -- self.__result_data[co] is a table + local result = self.__result_data[co] or {} + self.__result_data[co] = result + table.insert(result, result_data) + else + self.__result[co] = result_ok + if result_ok and self.__result_data[co] then + table.insert(self.__result_data[co], result_data) + else + self.__result_data[co] = result_data + end + skynet.wakeup(co) + end else close_channel_socket(self) local errmsg @@ -314,13 +338,27 @@ local function wait_for_response(self, response) end end -function channel:request(request, response) - assert(block_connect(self, true)) -- connect once +local socket_write = socket.write +local socket_lwrite = socket.lwrite - if not socket.write(self.__sock[1], request) then - close_channel_socket(self) - wakeup_all(self) - error(socket_error) +function channel:request(request, response, padding) + assert(block_connect(self, true)) -- connect once + local fd = self.__sock[1] + + if padding then + -- padding may be a table, to support multi part request + -- multi part request use low priority socket write + -- socket_lwrite returns nothing + socket_lwrite(fd , request) + for _,v in ipairs(padding) do + socket_lwrite(fd, v) + end + else + if not socket_write(fd , request) then + close_channel_socket(self) + wakeup_all(self) + error(socket_error) + end end if response == nil then diff --git a/service/clusterd.lua b/service/clusterd.lua index fc8b4126..b3c74722 100644 --- a/service/clusterd.lua +++ b/service/clusterd.lua @@ -11,7 +11,7 @@ local command = {} local function read_response(sock) local sz = socket.header(sock:read(2)) local msg = sock:read(sz) - return cluster.unpackresponse(msg) -- session, ok, data + return cluster.unpackresponse(msg) -- session, ok, data, padding end local function open_channel(t, key) @@ -64,19 +64,23 @@ end local function send_request(source, node, addr, msg, sz) local session = node_session[node] or 1 -- msg is a local pointer, cluster.packrequest will free it - local request, new_session = cluster.packrequest(addr, session, msg, sz) + local request, new_session, padding = cluster.packrequest(addr, session, msg, sz) node_session[node] = new_session -- node_channel[node] may yield or throw error local c = node_channel[node] - return c:request(request, session) + return c:request(request, session, padding) end function command.req(...) local ok, msg, sz = pcall(send_request, ...) if ok then - skynet.ret(msg, sz) + if type(msg) == "table" then + skynet.ret(cluster.concat(msg)) + else + skynet.ret(msg) + end else skynet.error(msg) skynet.response()(false) @@ -93,23 +97,51 @@ function command.proxy(source, node, name) skynet.ret(skynet.pack(proxy[fullname])) end -local request_fd = {} +local large_request = {} function command.socket(source, subcmd, fd, msg) if subcmd == "data" then - local addr, session, msg = cluster.unpackrequest(msg) - local ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg) + local sz + local addr, session, msg, padding = cluster.unpackrequest(msg) + if padding then + local req = large_request[session] or { addr = addr } + large_request[session] = req + table.insert(req, msg) + return + else + local req = large_request[session] + if req then + large_request[session] = nil + table.insert(req, msg) + msg,sz = cluster.concat(req) + addr = req.addr + end + if not msg then + local response = cluster.packresponse(session, false, "Invalid large req") + socket.write(fd, response) + return + end + end + local ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg, sz) local response if ok then response = cluster.packresponse(session, true, msg, sz) + if type(response) == "table" then + for _, v in ipairs(response) do + socket.lwrite(fd, v) + end + else + socket.write(fd, response) + end else response = cluster.packresponse(session, false, msg) + socket.write(fd, response) end - socket.write(fd, response) elseif subcmd == "open" then skynet.error(string.format("socket accept from %s", msg)) skynet.call(source, "lua", "accept", fd) else + large_request = {} skynet.error(string.format("socket %s %d : %s", subcmd, fd, msg)) end end From aff73cbed7e6cebd796b1f83cac150901dec1172 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 5 Aug 2015 12:23:35 +0800 Subject: [PATCH 21/97] Increase message size 16M(24bit) limit to 56bit on 64bit arch --- examples/config.userlog | 5 +---- service-src/service_harbor.c | 9 +++++++-- skynet-src/skynet_error.c | 2 +- skynet-src/skynet_handle.h | 4 +++- skynet-src/skynet_harbor.c | 6 ++++-- skynet-src/skynet_harbor.h | 4 ---- skynet-src/skynet_mq.h | 4 ++++ skynet-src/skynet_server.c | 12 ++++++------ skynet-src/skynet_socket.c | 4 ++-- skynet-src/skynet_start.c | 1 + skynet-src/skynet_timer.c | 4 ++-- 11 files changed, 31 insertions(+), 24 deletions(-) diff --git a/examples/config.userlog b/examples/config.userlog index 97bef6ef..dcd47b7b 100644 --- a/examples/config.userlog +++ b/examples/config.userlog @@ -3,12 +3,9 @@ thread = 8 logger = "userlog" logservice = "snlua" logpath = "." -harbor = 1 -address = "127.0.0.1:2526" -master = "127.0.0.1:2013" +harbor = 0 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" -- preload = "./examples/preload.lua" -- run preload.lua before every lua service run diff --git a/service-src/service_harbor.c b/service-src/service_harbor.c index 5940d62c..90d8bcc6 100644 --- a/service-src/service_harbor.c +++ b/service-src/service_harbor.c @@ -1,6 +1,7 @@ #include "skynet.h" #include "skynet_harbor.h" #include "skynet_socket.h" +#include "skynet_handle.h" /* harbor listen the PTYPE_HARBOR (in text) @@ -323,9 +324,13 @@ forward_local_messsage(struct harbor *h, void *msg, int sz) { static void send_remote(struct skynet_context * ctx, int fd, const char * buffer, size_t sz, struct remote_message_header * cookie) { - uint32_t sz_header = sz+sizeof(*cookie); + size_t sz_header = sz+sizeof(*cookie); + if (sz_header > UINT32_MAX) { + skynet_error(ctx, "remote message from :%08x to :%08x is too large.", cookie->source, cookie->destination); + return; + } uint8_t * sendbuf = skynet_malloc(sz_header+4); - to_bigendian(sendbuf, sz_header); + to_bigendian(sendbuf, (uint32_t)sz_header); memcpy(sendbuf+4, buffer, sz); header_to_message(cookie, sendbuf+4+sz); diff --git a/skynet-src/skynet_error.c b/skynet-src/skynet_error.c index b9c53efd..962ea597 100644 --- a/skynet-src/skynet_error.c +++ b/skynet-src/skynet_error.c @@ -54,7 +54,7 @@ skynet_error(struct skynet_context * context, const char *msg, ...) { } smsg.session = 0; smsg.data = data; - smsg.sz = len | (PTYPE_TEXT << HANDLE_REMOTE_SHIFT); + smsg.sz = len | ((size_t)PTYPE_TEXT << MESSAGE_TYPE_SHIFT); skynet_context_push(logger, &smsg); } diff --git a/skynet-src/skynet_handle.h b/skynet-src/skynet_handle.h index e067eed0..293b6571 100644 --- a/skynet-src/skynet_handle.h +++ b/skynet-src/skynet_handle.h @@ -3,7 +3,9 @@ #include -#include "skynet_harbor.h" +// reserve high 8 bits for remote id +#define HANDLE_MASK 0xffffff +#define HANDLE_REMOTE_SHIFT 24 struct skynet_context; diff --git a/skynet-src/skynet_harbor.c b/skynet-src/skynet_harbor.c index 379fce80..5e39ca62 100644 --- a/skynet-src/skynet_harbor.c +++ b/skynet-src/skynet_harbor.c @@ -1,6 +1,8 @@ #include "skynet.h" #include "skynet_harbor.h" #include "skynet_server.h" +#include "skynet_mq.h" +#include "skynet_handle.h" #include #include @@ -11,8 +13,8 @@ static unsigned int HARBOR = ~0; void skynet_harbor_send(struct remote_message *rmsg, uint32_t source, int session) { - int type = rmsg->sz >> HANDLE_REMOTE_SHIFT; - rmsg->sz &= HANDLE_MASK; + int type = rmsg->sz >> MESSAGE_TYPE_SHIFT; + rmsg->sz &= MESSAGE_TYPE_MASK; assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR && REMOTE); skynet_context_send(REMOTE, rmsg, sizeof(*rmsg) , source, type , session); } diff --git a/skynet-src/skynet_harbor.h b/skynet-src/skynet_harbor.h index 62982455..97a76c20 100644 --- a/skynet-src/skynet_harbor.h +++ b/skynet-src/skynet_harbor.h @@ -7,10 +7,6 @@ #define GLOBALNAME_LENGTH 16 #define REMOTE_MAX 256 -// reserve high 8 bits for remote id -#define HANDLE_MASK 0xffffff -#define HANDLE_REMOTE_SHIFT 24 - struct remote_name { char name[GLOBALNAME_LENGTH]; uint32_t handle; diff --git a/skynet-src/skynet_mq.h b/skynet-src/skynet_mq.h index 17178b4f..3721e32b 100644 --- a/skynet-src/skynet_mq.h +++ b/skynet-src/skynet_mq.h @@ -11,6 +11,10 @@ struct skynet_message { size_t sz; }; +// type is encoding in skynet_message.sz high 8bit +#define MESSAGE_TYPE_MASK (SIZE_MAX >> 8) +#define MESSAGE_TYPE_SHIFT ((sizeof(size_t)-1) * 8) + struct message_queue; void skynet_globalmq_push(struct message_queue * queue); diff --git a/skynet-src/skynet_server.c b/skynet-src/skynet_server.c index ea1aadcf..52331193 100644 --- a/skynet-src/skynet_server.c +++ b/skynet-src/skynet_server.c @@ -246,8 +246,8 @@ dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) { assert(ctx->init); CHECKCALLING_BEGIN(ctx) pthread_setspecific(G_NODE.handle_key, (void *)(uintptr_t)(ctx->handle)); - int type = msg->sz >> HANDLE_REMOTE_SHIFT; - size_t sz = msg->sz & HANDLE_MASK; + int type = msg->sz >> MESSAGE_TYPE_SHIFT; + size_t sz = msg->sz & MESSAGE_TYPE_MASK; if (ctx->logfile) { skynet_log_output(ctx->logfile, msg->source, type, msg->session, msg->data, sz); } @@ -662,13 +662,13 @@ _filter_args(struct skynet_context * context, int type, int *session, void ** da *data = msg; } - *sz |= type << HANDLE_REMOTE_SHIFT; + *sz |= (size_t)type << MESSAGE_TYPE_SHIFT; } int skynet_send(struct skynet_context * context, uint32_t source, uint32_t destination , int type, int session, void * data, size_t sz) { - if ((sz & HANDLE_MASK) != sz) { - skynet_error(context, "The message to %x is too large (sz = %lu)", destination, sz); + if ((sz & MESSAGE_TYPE_MASK) != sz) { + skynet_error(context, "The message to %x is too large", destination); skynet_free(data); return -1; } @@ -751,7 +751,7 @@ skynet_context_send(struct skynet_context * ctx, void * msg, size_t sz, uint32_t smsg.source = source; smsg.session = session; smsg.data = msg; - smsg.sz = sz | type << HANDLE_REMOTE_SHIFT; + smsg.sz = sz | (size_t)type << MESSAGE_TYPE_SHIFT; skynet_mq_push(ctx->queue, &smsg); } diff --git a/skynet-src/skynet_socket.c b/skynet-src/skynet_socket.c index 3f2c9a04..2ea26c0a 100644 --- a/skynet-src/skynet_socket.c +++ b/skynet-src/skynet_socket.c @@ -33,7 +33,7 @@ skynet_socket_free() { static void forward_message(int type, bool padding, struct socket_message * result) { struct skynet_socket_message *sm; - int sz = sizeof(*sm); + size_t sz = sizeof(*sm); if (padding) { if (result->data) { sz += strlen(result->data); @@ -56,7 +56,7 @@ forward_message(int type, bool padding, struct socket_message * result) { message.source = 0; message.session = 0; message.data = sm; - message.sz = sz | PTYPE_SOCKET << HANDLE_REMOTE_SHIFT; + message.sz = sz | ((size_t)PTYPE_SOCKET << MESSAGE_TYPE_SHIFT); if (skynet_context_push((uint32_t)result->opaque, &message)) { // todo: report somewhere to close socket diff --git a/skynet-src/skynet_start.c b/skynet-src/skynet_start.c index 4123c624..5345c76c 100644 --- a/skynet-src/skynet_start.c +++ b/skynet-src/skynet_start.c @@ -8,6 +8,7 @@ #include "skynet_monitor.h" #include "skynet_socket.h" #include "skynet_daemon.h" +#include "skynet_harbor.h" #include #include diff --git a/skynet-src/skynet_timer.c b/skynet-src/skynet_timer.c index f7d5a1ff..a6b4bb87 100644 --- a/skynet-src/skynet_timer.c +++ b/skynet-src/skynet_timer.c @@ -146,7 +146,7 @@ dispatch_list(struct timer_node *current) { message.source = 0; message.session = event->session; message.data = NULL; - message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT; + message.sz = (size_t)MESSAGE_TYPE_SHIFT << MESSAGE_TYPE_SHIFT; skynet_context_push(event->handle, &message); @@ -214,7 +214,7 @@ skynet_timeout(uint32_t handle, int time, int session) { message.source = 0; message.session = session; message.data = NULL; - message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT; + message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT; if (skynet_context_push(handle, &message)) { return -1; From b4048a8eab2ff01888a931ec7e24541d45c7a2ba Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 5 Aug 2015 16:42:05 +0800 Subject: [PATCH 22/97] bugfix: typo --- skynet-src/skynet_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skynet-src/skynet_timer.c b/skynet-src/skynet_timer.c index a6b4bb87..f23114dc 100644 --- a/skynet-src/skynet_timer.c +++ b/skynet-src/skynet_timer.c @@ -146,7 +146,7 @@ dispatch_list(struct timer_node *current) { message.source = 0; message.session = event->session; message.data = NULL; - message.sz = (size_t)MESSAGE_TYPE_SHIFT << MESSAGE_TYPE_SHIFT; + message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT; skynet_context_push(event->handle, &message); From 3156661e0b1fb85dd7e70f7df8c532ba0367e3e3 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 6 Aug 2015 20:00:48 +0800 Subject: [PATCH 23/97] bugfix: response function for socket channel --- lualib/mysql.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lualib/mysql.lua b/lualib/mysql.lua index a83a0986..305e900b 100755 --- a/lualib/mysql.lua +++ b/lualib/mysql.lua @@ -386,7 +386,8 @@ end local function _recv_decode_packet_resp(self) return function(sock) - return true, _recv_packet(self,sock) + -- don't return more than 2 results + return true, (_recv_packet(self,sock)) end end From e9cfdba22a43e4ef9caf29b4f711ab27231426a0 Mon Sep 17 00:00:00 2001 From: snail Date: Fri, 7 Aug 2015 10:38:57 +0800 Subject: [PATCH 24/97] 'hotfix' code cannot use '_ENV' If there's no global variable or function used in any interface of a snax service,the upvalue "_ENV" for 'hotfix' is not set. This modify is not complete, it depend's on the 'collect_uv' method having upvalue '_ENV',maybe other good method to get upvalue index of '_ENV'. --- lualib/snax/hotfix.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lualib/snax/hotfix.lua b/lualib/snax/hotfix.lua index 1a60383a..3a6e4e3e 100644 --- a/lualib/snax/hotfix.lua +++ b/lualib/snax/hotfix.lua @@ -49,7 +49,9 @@ local function collect_all_uv(funcs) collect_uv(v[4], global, envid(v[4])) end end - + if not global["_ENV"] then + global["_ENV"] = {func = collect_uv, index = 1} + end return global end From 5936d3616ccfb0ec49005a19a4c38a758889f6b9 Mon Sep 17 00:00:00 2001 From: BITMAN Date: Fri, 7 Aug 2015 13:51:10 +0800 Subject: [PATCH 25/97] Packing multipart req number first byte is 1 --- lualib-src/lua-cluster.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index c558fb0f..40cc453e 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -88,7 +88,7 @@ packreq_number(lua_State *L, int session, void * msg, uint32_t sz) { } else { int part = (sz - 1) / MULTI_PART + 1; fill_header(L, buf, 13, msg); - buf[2] = 0x80; + buf[2] = 1; fill_uint32(buf+3, addr); fill_uint32(buf+7, (uint32_t)session); fill_uint32(buf+11, sz); From c16ae57639b9568156e7cdb14c27d385d13d838f Mon Sep 17 00:00:00 2001 From: felixdae Date: Fri, 7 Aug 2015 18:36:30 +0800 Subject: [PATCH 26/97] not work with telnet due to \r\n --- service/debug_console.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/service/debug_console.lua b/service/debug_console.lua index 139e76bb..97b35806 100644 --- a/service/debug_console.lua +++ b/service/debug_console.lua @@ -228,6 +228,7 @@ function COMMAND.debug(address, fd) skynet.fork(function() repeat local cmdline = socket.readline(fd, "\n") + cmdline = cmdline:gsub("(.*)\r$", "%1") if not cmdline then skynet.send(agent, "lua", "cmd", "cont") break From 2935ba3521eed5a8f612bf9bd90538a4e1ec63a9 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 10 Aug 2015 16:17:55 +0800 Subject: [PATCH 27/97] Release alpha9 --- HISTORY.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 8f0a1ac4..a970b7c2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,12 @@ +v1.0.0-alpha9 (2015-8-10) +----------- +* Improve lua serialization , support pairs metamethod. +* Bugfix : sproto (See commits log of sproto) +* Add user log service support (In config) +* Remove the size limit of cluster RPC message. +* Remove the size limit of local message. +* Other minor bugfix (See commits log) + v1.0.0-alpha8 (2015-6-29) ----------- * Update lua 5.3.1 From 6fa436e8ff980c05239c8aaa5015d424d0065bdc Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 10 Aug 2015 22:06:36 +0800 Subject: [PATCH 28/97] add core.intcommand , See Issue #321 --- lualib-src/lua-skynet.c | 23 +++++++++++++++++++++++ lualib/skynet.lua | 12 +++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lualib-src/lua-skynet.c b/lualib-src/lua-skynet.c index f1594f79..c92ff98d 100644 --- a/lualib-src/lua-skynet.c +++ b/lualib-src/lua-skynet.c @@ -118,6 +118,28 @@ _command(lua_State *L) { return 0; } +static int +_intcommand(lua_State *L) { + struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); + const char * cmd = luaL_checkstring(L,1); + const char * result; + const char * parm = NULL; + char tmp[64]; // for integer parm + if (lua_gettop(L) == 2) { + int32_t n = (int32_t)luaL_checkinteger(L,2); + sprintf(tmp, "%d", n); + parm = tmp; + } + + result = skynet_command(context, cmd, parm); + if (result) { + lua_Integer r = strtoll(result, NULL, 0); + lua_pushinteger(L, r); + return 1; + } + return 0; +} + static int _genid(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); @@ -310,6 +332,7 @@ luaopen_skynet_core(lua_State *L) { { "genid", _genid }, { "redirect", _redirect }, { "command" , _command }, + { "intcommand", _intcommand }, { "error", _error }, { "tostring", _tostring }, { "harbor", _harbor }, diff --git a/lualib/skynet.lua b/lualib/skynet.lua index 8906f60d..31efffcb 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -248,18 +248,16 @@ function suspend(co, result, command, param, size) end function skynet.timeout(ti, func) - local session = c.command("TIMEOUT",tostring(ti)) + local session = c.intcommand("TIMEOUT",ti) assert(session) - session = tonumber(session) local co = co_create(func) assert(session_id_coroutine[session] == nil) session_id_coroutine[session] = co end function skynet.sleep(ti) - local session = c.command("TIMEOUT",tostring(ti)) + local session = c.intcommand("TIMEOUT",ti) assert(session) - session = tonumber(session) local succ, ret = coroutine_yield("SLEEP", session) sleep_session[coroutine.running()] = nil if succ then @@ -301,11 +299,11 @@ function skynet.localname(name) end function skynet.now() - return tonumber(c.command("NOW")) + return c.intcommand("NOW") end function skynet.starttime() - return tonumber(c.command("STARTTIME")) + return c.intcommand("STARTTIME") end function skynet.time() @@ -643,7 +641,7 @@ function skynet.endless() end function skynet.mqlen() - return tonumber(c.command "MQLEN") + return c.intcommand "MQLEN" end function skynet.task(ret) From 947727e33acb7d26e500875cb17537946e481697 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 11 Aug 2015 13:21:24 +0800 Subject: [PATCH 29/97] add new socket message WARNING --- examples/watchdog.lua | 5 +++++ lualib-src/lua-netpack.c | 9 ++++++++- lualib/skynet.lua | 2 +- lualib/snax/gateserver.lua | 6 ++++++ lualib/socket.lua | 25 +++++++++++++++++++++++++ service-src/service_gate.c | 3 +++ service-src/service_harbor.c | 7 +++++++ service/gate.lua | 4 ++++ skynet-src/skynet_socket.c | 11 +++++++---- skynet-src/skynet_socket.h | 1 + 10 files changed, 67 insertions(+), 6 deletions(-) diff --git a/examples/watchdog.lua b/examples/watchdog.lua index 29111033..efee5e24 100644 --- a/examples/watchdog.lua +++ b/examples/watchdog.lua @@ -32,6 +32,11 @@ function SOCKET.error(fd, msg) close_agent(fd) end +function SOCKET.warning(fd, size) + -- size K bytes havn't send out in fd + print("socket warning", fd, size) +end + function SOCKET.data(fd, msg) end diff --git a/lualib-src/lua-netpack.c b/lualib-src/lua-netpack.c index 1839abe3..88a54d3d 100644 --- a/lualib-src/lua-netpack.c +++ b/lualib-src/lua-netpack.c @@ -19,6 +19,7 @@ #define TYPE_ERROR 3 #define TYPE_OPEN 4 #define TYPE_CLOSE 5 +#define TYPE_WARNING 6 /* Each package is uint16 + data , uint16 (serialized in big-endian) is the number of bytes comprising the data . @@ -371,6 +372,11 @@ lfilter(lua_State *L) { lua_pushinteger(L, message->id); pushstring(L, buffer, size); return 4; + case SKYNET_SOCKET_TYPE_WARNING: + lua_pushvalue(L, lua_upvalueindex(TYPE_WARNING)); + lua_pushinteger(L, message->id); + lua_pushinteger(L, message->ud); + return 4; default: // never get here return 1; @@ -537,8 +543,9 @@ luaopen_netpack(lua_State *L) { lua_pushliteral(L, "error"); lua_pushliteral(L, "open"); lua_pushliteral(L, "close"); + lua_pushliteral(L, "warning"); - lua_pushcclosure(L, lfilter, 5); + lua_pushcclosure(L, lfilter, 6); lua_setfield(L, -2, "filter"); return 1; diff --git a/lualib/skynet.lua b/lualib/skynet.lua index 31efffcb..e4f46908 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -271,7 +271,7 @@ function skynet.sleep(ti) end function skynet.yield() - return skynet.sleep("0") + return skynet.sleep(0) end function skynet.wait() diff --git a/lualib/snax/gateserver.lua b/lualib/snax/gateserver.lua index e68efc12..dfce2fa9 100644 --- a/lualib/snax/gateserver.lua +++ b/lualib/snax/gateserver.lua @@ -114,6 +114,12 @@ function gateserver.start(handler) close_fd(fd) end + function MSG.warning(fd, size) + if handler.warning then + handler.warning(fd, size) + end + end + skynet.register_protocol { name = "socket", id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6 diff --git a/lualib/socket.lua b/lualib/socket.lua index 8d98e5a3..c5fe7858 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -133,6 +133,25 @@ socket_message[6] = function(id, size, data, address) s.callback(str, address) end +local function default_warning(id, size) + local s = socket_pool[id] + local last = s.warningsize or 0 + if last + 64 < size then -- if size increase 64K + s.warningsize = size + skynet.error(string.format("WARNING: %d K bytes need to send out (fd = %d)", size, id)) + end + s.warningsize = size +end + +-- SKYNET_SOCKET_TYPE_WARNING +socket_message[7] = function(id, size) + local s = socket_pool[id] + if s then + local warning = s.warning or default_warning + warning(id, size) + end +end + skynet.register_protocol { name = "socket", id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6 @@ -404,4 +423,10 @@ end socket.sendto = assert(driver.udp_send) socket.udp_address = assert(driver.udp_address) +function socket.warning(id, callback) + local obj = socket_pool[id] + assert(obj) + obj.warning = callback +end + return socket diff --git a/service-src/service_gate.c b/service-src/service_gate.c index 9f5d98ec..ec44c722 100644 --- a/service-src/service_gate.c +++ b/service-src/service_gate.c @@ -262,6 +262,9 @@ dispatch_socket_message(struct gate *g, const struct skynet_socket_message * mes skynet_socket_start(ctx, message->ud); } break; + case SKYNET_SOCKET_TYPE_WARNING: + skynet_error(ctx, "fd (%d) send buffer (%d)K", message->id, message->ud); + break; } } diff --git a/service-src/service_harbor.c b/service-src/service_harbor.c index 90d8bcc6..5ff618f1 100644 --- a/service-src/service_harbor.c +++ b/service-src/service_harbor.c @@ -662,6 +662,13 @@ mainloop(struct skynet_context * context, void * ud, int type, int session, uint case SKYNET_SOCKET_TYPE_CONNECT: // fd forward to this service break; + case SKYNET_SOCKET_TYPE_WARNING: { + int id = harbor_id(h, message->id); + if (id) { + skynet_error(context, "message havn't send to Harbor (%d) reach %d K", id, message->ud); + } + break; + } default: skynet_error(context, "recv invalid socket message type %d", type); break; diff --git a/service/gate.lua b/service/gate.lua index 9fe3a491..78fb099f 100644 --- a/service/gate.lua +++ b/service/gate.lua @@ -63,6 +63,10 @@ function handler.error(fd, msg) skynet.send(watchdog, "lua", "socket", "error", fd, msg) end +function handler.warning(fd, size) + skynet.send(watchdog, "lua", "socket", "warning", fd, size) +end + local CMD = {} function CMD.forward(source, fd, client, address) diff --git a/skynet-src/skynet_socket.c b/skynet-src/skynet_socket.c index 2ea26c0a..9301419f 100644 --- a/skynet-src/skynet_socket.c +++ b/skynet-src/skynet_socket.c @@ -109,10 +109,13 @@ check_wsz(struct skynet_context *ctx, int id, void *buffer, int64_t wsz) { if (wsz < 0) { return -1; } else if (wsz > 1024 * 1024) { - int kb4 = wsz / 1024 / 4; - if (kb4 % 256 == 0) { - skynet_error(ctx, "%d Mb bytes on socket %d need to send out", (int)(wsz / (1024 * 1024)), id); - } + struct skynet_socket_message tmp; + tmp.type = SKYNET_SOCKET_TYPE_WARNING; + tmp.id = id; + tmp.ud = (int)(wsz / 1024); + tmp.buffer = NULL; + skynet_send(ctx, 0, skynet_context_handle(ctx), PTYPE_SOCKET, 0 , &tmp, sizeof(tmp)); +// skynet_error(ctx, "%d Mb bytes on socket %d need to send out", (int)(wsz / (1024 * 1024)), id); } return 0; } diff --git a/skynet-src/skynet_socket.h b/skynet-src/skynet_socket.h index 5327f09f..bcdc137c 100644 --- a/skynet-src/skynet_socket.h +++ b/skynet-src/skynet_socket.h @@ -9,6 +9,7 @@ struct skynet_context; #define SKYNET_SOCKET_TYPE_ACCEPT 4 #define SKYNET_SOCKET_TYPE_ERROR 5 #define SKYNET_SOCKET_TYPE_UDP 6 +#define SKYNET_SOCKET_TYPE_WARNING 7 struct skynet_socket_message { int type; From d3771edc9d5a878c34de954cc845d7096a4bcc1d Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 11 Aug 2015 14:04:15 +0800 Subject: [PATCH 30/97] The cluster message never great than 64K now --- lualib-src/lua-cluster.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index 40cc453e..4afe0e6d 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "skynet.h" @@ -28,10 +29,7 @@ fill_uint32(uint8_t * buf, uint32_t n) { static void fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) { - if (sz >= 0x10000) { - skynet_free(msg); - luaL_error(L, "request message is too long %d", sz); - } + assert(sz < 0x10000); buf[0] = (sz >> 8) & 0xff; buf[1] = sz & 0xff; } From 926b44ddf6b8e6a71dfe340e4af5bcac21d8a09d Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 11 Aug 2015 14:09:16 +0800 Subject: [PATCH 31/97] remove unused parm --- lualib-src/lua-cluster.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index 4afe0e6d..e35615c7 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -28,7 +28,7 @@ fill_uint32(uint8_t * buf, uint32_t n) { } static void -fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) { +fill_header(lua_State *L, uint8_t *buf, int sz) { assert(sz < 0x10000); buf[0] = (sz >> 8) & 0xff; buf[1] = sz & 0xff; @@ -75,7 +75,7 @@ packreq_number(lua_State *L, int session, void * msg, uint32_t sz) { uint32_t addr = (uint32_t)lua_tointeger(L,1); uint8_t buf[TEMP_LENGTH]; if (sz < MULTI_PART) { - fill_header(L, buf, sz+9, msg); + fill_header(L, buf, sz+9); buf[2] = 0; fill_uint32(buf+3, addr); fill_uint32(buf+7, (uint32_t)session); @@ -85,7 +85,7 @@ packreq_number(lua_State *L, int session, void * msg, uint32_t sz) { return 0; } else { int part = (sz - 1) / MULTI_PART + 1; - fill_header(L, buf, 13, msg); + fill_header(L, buf, 13); buf[2] = 1; fill_uint32(buf+3, addr); fill_uint32(buf+7, (uint32_t)session); @@ -106,7 +106,7 @@ packreq_string(lua_State *L, int session, void * msg, uint32_t sz) { uint8_t buf[TEMP_LENGTH]; if (sz < MULTI_PART) { - fill_header(L, buf, sz+6+namelen, msg); + fill_header(L, buf, sz+6+namelen); buf[2] = 0x80; buf[3] = (uint8_t)namelen; memcpy(buf+4, name, namelen); @@ -117,7 +117,7 @@ packreq_string(lua_State *L, int session, void * msg, uint32_t sz) { return 0; } else { int part = (sz - 1) / MULTI_PART + 1; - fill_header(L, buf, 10+namelen, msg); + fill_header(L, buf, 10+namelen); buf[2] = 0x81; buf[3] = (uint8_t)namelen; memcpy(buf+4, name, namelen); @@ -144,7 +144,7 @@ packreq_multi(lua_State *L, int session, void * msg, uint32_t sz) { s = sz; buf[2] = 3; // the last multi part } - fill_header(L, buf, s+5, msg); + fill_header(L, buf, s+5); fill_uint32(buf+3, (uint32_t)session); memcpy(buf+7, ptr, s); lua_pushlstring(L, (const char *)buf, s+7); @@ -356,7 +356,7 @@ lpackresponse(lua_State *L) { uint8_t buf[TEMP_LENGTH]; // multi part begin - fill_header(L, buf, 9, msg); + fill_header(L, buf, 9); fill_uint32(buf+2, session); buf[6] = 2; fill_uint32(buf+7, (uint32_t)sz); @@ -374,7 +374,7 @@ lpackresponse(lua_State *L) { s = sz; buf[6] = 4; } - fill_header(L, buf, s+5, msg); + fill_header(L, buf, s+5); fill_uint32(buf+2, session); memcpy(buf+7,ptr,s); lua_pushlstring(L, (const char *)buf, s+7); @@ -387,7 +387,7 @@ lpackresponse(lua_State *L) { } uint8_t buf[TEMP_LENGTH]; - fill_header(L, buf, sz+5, msg); + fill_header(L, buf, sz+5); fill_uint32(buf+2, session); buf[6] = ok; memcpy(buf+7,msg,sz); From 7547126570000ddce915c58e7590430be55d67c4 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 12 Aug 2015 12:03:52 +0800 Subject: [PATCH 32/97] bugfix: memory leak , See Issue #323 --- 3rd/lua/lfunc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/3rd/lua/lfunc.c b/3rd/lua/lfunc.c index ae603c8f..b0d9db4b 100644 --- a/3rd/lua/lfunc.c +++ b/3rd/lua/lfunc.c @@ -135,6 +135,7 @@ static void freesharedproto (lua_State *L, SharedProto *f) { luaM_freearray(L, f->lineinfo, f->sizelineinfo); luaM_freearray(L, f->locvars, f->sizelocvars); luaM_freearray(L, f->upvalues, f->sizeupvalues); + luaM_free(L, f); } void luaF_freeproto (lua_State *L, Proto *f) { From a4f827a48d1d83fd29acc7135267b7d7e6688dc6 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 12 Aug 2015 14:53:36 +0800 Subject: [PATCH 33/97] use string for msgserver request --- lualib-src/lua-netpack.c | 15 ++------------- lualib/snax/msgserver.lua | 16 ++++++++-------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/lualib-src/lua-netpack.c b/lualib-src/lua-netpack.c index 88a54d3d..0ec6f7e9 100644 --- a/lualib-src/lua-netpack.c +++ b/lualib-src/lua-netpack.c @@ -506,19 +506,8 @@ ltostring(lua_State *L) { if (ptr == NULL) { lua_pushliteral(L, ""); } else { - if (lua_isnumber(L, 3)) { - int offset = lua_tointeger(L, 3); - if (offset < 0) { - return luaL_error(L, "Invalid offset %d", offset); - } - if (offset > size) { - offset = size; - } - lua_pushlstring(L, (const char *)ptr + offset, size-offset); - } else { - lua_pushlstring(L, (const char *)ptr, size); - skynet_free(ptr); - } + lua_pushlstring(L, (const char *)ptr, size); + skynet_free(ptr); } return 1; } diff --git a/lualib/snax/msgserver.lua b/lualib/snax/msgserver.lua index a70ea415..c480a8a6 100644 --- a/lualib/snax/msgserver.lua +++ b/lualib/snax/msgserver.lua @@ -70,7 +70,7 @@ Config for server.start: conf.login_handler(uid, secret) -> subid : the function when a new user login, alloc a subid for it. (may call by login server) conf.logout_handler(uid, subid) : the functon when a user logout. (may call by agent) conf.kick_handler(uid, subid) : the functon when a user logout. (may call by login server) - conf.request_handler(username, session, msg, sz) : the function when recv a new request. + conf.request_handler(username, session, msg) : the function when recv a new request. conf.register_handler(servername) : call when gate open conf.disconnect_handler(username) : call when a connection disconnect (afk) ]] @@ -234,10 +234,10 @@ function server.start(conf) end end - local function do_request(fd, msg, sz) + local function do_request(fd, message) local u = assert(connection[fd], "invalid fd") - local msg_sz = sz - 4 - local session = netpack.tostring(msg, sz, msg_sz) + local session = string.unpack("I4", message, -4) + message = message:sub(1,-5) local p = u.response[session] if p then -- session can be reuse in the same connection @@ -256,7 +256,7 @@ function server.start(conf) if p == nil then p = { fd } u.response[session] = p - local ok, result = pcall(conf.request_handler, u.username, msg, msg_sz) + local ok, result = pcall(conf.request_handler, u.username, message) result = result or "" -- NOTICE: YIELD here, socket may close. if not ok then @@ -270,7 +270,6 @@ function server.start(conf) p[3] = u.version p[4] = u.index else - netpack.tostring(msg, sz) -- request before, so free msg -- update version/index, change return fd. -- resend response. p[1] = fd @@ -292,10 +291,11 @@ function server.start(conf) end local function request(fd, msg, sz) - local ok, err = pcall(do_request, fd, msg, sz) + local message = netpack.tostring(msg, sz) + local ok, err = pcall(do_request, fd, message) -- not atomic, may yield if not ok then - skynet.error(string.format("Invalid package %s : %s", err, netpack.tostring(msg, sz))) + skynet.error(string.format("Invalid package %s : %s", err, message)) if connection[fd] then gateserver.closeclient(fd) end From adc39705f392b0a7cc6cadd62b9bf6ed703699f3 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 12 Aug 2015 20:56:29 +0800 Subject: [PATCH 34/97] remove unused netpack c api --- lualib-src/lua-netpack.c | 53 --------------------------------------- lualib/snax/msgserver.lua | 10 ++++---- 2 files changed, 5 insertions(+), 58 deletions(-) diff --git a/lualib-src/lua-netpack.c b/lualib-src/lua-netpack.c index 0ec6f7e9..193938b1 100644 --- a/lualib-src/lua-netpack.c +++ b/lualib-src/lua-netpack.c @@ -448,57 +448,6 @@ lpack(lua_State *L) { return 2; } -static int -lpack_string(lua_State *L) { - uint8_t tmp[SMALLSTRING+2]; - size_t len; - uint8_t *buffer; - const char * ptr = tolstring(L, &len, 1); - if (len > 0x10000) { - return luaL_error(L, "Invalid size (too long) of data : %d", (int)len); - } - - if (len <= SMALLSTRING) { - buffer = tmp; - } else { - buffer = lua_newuserdata(L, len + 2); - } - - write_size(buffer, len); - memcpy(buffer+2, ptr, len); - lua_pushlstring(L, (const char *)buffer, len+2); - - return 1; -} - -static int -lpack_padding(lua_State *L) { - uint8_t tmp[SMALLSTRING+2]; - size_t content_sz; - uint8_t *buffer; - const char * ptr = tolstring(L, &content_sz, 2); - size_t cookie_sz = 0; - const char * cookie = luaL_checklstring(L,1,&cookie_sz); - size_t len = cookie_sz + content_sz; - - if (len > 0x10000) { - return luaL_error(L, "Invalid size (too long) of data : %d", (int)len); - } - - if (len <= SMALLSTRING) { - buffer = tmp; - } else { - buffer = lua_newuserdata(L, len + 2); - } - - write_size(buffer, len); - memcpy(buffer+2, ptr, content_sz); - memcpy(buffer+2+content_sz, cookie, cookie_sz); - lua_pushlstring(L, (const char *)buffer, len+2); - - return 1; -} - static int ltostring(lua_State *L) { void * ptr = lua_touserdata(L, 1); @@ -518,8 +467,6 @@ luaopen_netpack(lua_State *L) { luaL_Reg l[] = { { "pop", lpop }, { "pack", lpack }, - { "pack_string", lpack_string }, - { "pack_padding", lpack_padding }, { "clear", lclear }, { "tostring", ltostring }, { NULL, NULL }, diff --git a/lualib/snax/msgserver.lua b/lualib/snax/msgserver.lua index c480a8a6..765387cc 100644 --- a/lualib/snax/msgserver.lua +++ b/lualib/snax/msgserver.lua @@ -236,7 +236,7 @@ function server.start(conf) local function do_request(fd, message) local u = assert(connection[fd], "invalid fd") - local session = string.unpack("I4", message, -4) + local session = string.unpack(">I4", message, -4) message = message:sub(1,-5) local p = u.response[session] if p then @@ -257,16 +257,16 @@ function server.start(conf) p = { fd } u.response[session] = p local ok, result = pcall(conf.request_handler, u.username, message) - result = result or "" -- NOTICE: YIELD here, socket may close. + result = result or "" if not ok then skynet.error(result) - result = "\0" .. session + result = string.pack(">BI4", 0, session) else - result = result .. '\1' .. session + result = result .. string.pack(">BI4", 1, session) end - p[2] = netpack.pack_string(result) + p[2] = string.pack(">s2",result) p[3] = u.version p[4] = u.index else From 0ce9921c251988ed50519d3d43d7143efa5b4bc2 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 12 Aug 2015 21:16:02 +0800 Subject: [PATCH 35/97] remove unused sz --- examples/login/gated.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/login/gated.lua b/examples/login/gated.lua index 4a024699..0b8c53b7 100644 --- a/examples/login/gated.lua +++ b/examples/login/gated.lua @@ -74,9 +74,9 @@ function server.disconnect_handler(username) end -- call by self (when recv a request from client) -function server.request_handler(username, msg, sz) +function server.request_handler(username, msg) local u = username_map[username] - return skynet.tostring(skynet.rawcall(u.agent, "client", msg, sz)) + return skynet.tostring(skynet.rawcall(u.agent, "client", msg)) end -- call by self (when gate open) From bf8f9b8654fe5764b5249766b9f7611adb6e8dd0 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 13 Aug 2015 21:00:20 +0800 Subject: [PATCH 36/97] add pthread lock --- Makefile | 9 ++-- lualib-src/lua-bson.c | 3 +- lualib-src/lua-clientsocket.c | 16 ++++---- lualib-src/lua-debugchannel.c | 26 ++++++------ lualib-src/lua-multicast.c | 4 +- lualib-src/lua-sharedata.c | 9 ++-- lualib-src/lua-stm.c | 9 ++-- skynet-src/atomic.h | 14 +++++++ skynet-src/malloc_hook.c | 17 ++++---- skynet-src/rwlock.h | 40 ++++++++++++++++++ skynet-src/skynet_env.c | 16 ++++---- skynet-src/skynet_module.c | 15 ++++--- skynet-src/skynet_monitor.c | 3 +- skynet-src/skynet_mq.c | 42 +++++++++---------- skynet-src/skynet_server.c | 25 +++++++----- skynet-src/skynet_timer.c | 21 +++++----- skynet-src/socket_server.c | 7 ++-- skynet-src/spinlock.h | 77 +++++++++++++++++++++++++++++++++++ 18 files changed, 249 insertions(+), 104 deletions(-) create mode 100644 skynet-src/atomic.h create mode 100644 skynet-src/spinlock.h diff --git a/Makefile b/Makefile index b92a1a33..98f7d1c9 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ CSERVICE_PATH ?= cservice SKYNET_BUILD_PATH ?= . -CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS) +CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS) +# CFLAGS += -DUSE_PTHREAD_LOCK # lua @@ -79,7 +80,7 @@ $(LUA_CLIB_PATH)/socketdriver.so : lualib-src/lua-socket.c | $(LUA_CLIB_PATH) $(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src $(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c | $(LUA_CLIB_PATH) - $(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src + $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ -Iskynet-src $(LUA_CLIB_PATH)/mongo.so : lualib-src/lua-mongo.c | $(LUA_CLIB_PATH) $(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src @@ -109,7 +110,7 @@ $(LUA_CLIB_PATH)/crypt.so : lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CL $(CC) $(CFLAGS) $(SHARED) $^ -o $@ $(LUA_CLIB_PATH)/sharedata.so : lualib-src/lua-sharedata.c | $(LUA_CLIB_PATH) - $(CC) $(CFLAGS) $(SHARED) $^ -o $@ + $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ $(LUA_CLIB_PATH)/stm.so : lualib-src/lua-stm.c | $(LUA_CLIB_PATH) $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ @@ -124,7 +125,7 @@ $(LUA_CLIB_PATH)/mysqlaux.so : lualib-src/lua-mysqlaux.c | $(LUA_CLIB_PATH) $(CC) $(CFLAGS) $(SHARED) $^ -o $@ $(LUA_CLIB_PATH)/debugchannel.so : lualib-src/lua-debugchannel.c | $(LUA_CLIB_PATH) - $(CC) $(CFLAGS) $(SHARED) $^ -o $@ + $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ clean : rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so diff --git a/lualib-src/lua-bson.c b/lualib-src/lua-bson.c index 9071f56d..0fc26985 100644 --- a/lualib-src/lua-bson.c +++ b/lualib-src/lua-bson.c @@ -8,6 +8,7 @@ #include #include #include +#include "atomic.h" #define DEFAULT_CAP 64 #define MAX_NUMBER 1024 @@ -1140,7 +1141,7 @@ lobjectid(lua_State *L) { } else { time_t ti = time(NULL); // old_counter is a static var, use atom inc. - uint32_t id = __sync_fetch_and_add(&oid_counter,1); + uint32_t id = ATOM_FINC(&oid_counter); oid[2] = (ti>>24) & 0xff; oid[3] = (ti>>16) & 0xff; diff --git a/lualib-src/lua-clientsocket.c b/lualib-src/lua-clientsocket.c index 89bfe1f8..fa1a88e8 100644 --- a/lualib-src/lua-clientsocket.c +++ b/lualib-src/lua-clientsocket.c @@ -128,11 +128,8 @@ lusleep(lua_State *L) { #define QUEUE_SIZE 1024 -#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} -#define UNLOCK(q) __sync_lock_release(&(q)->lock); - struct queue { - int lock; + pthread_mutex_t lock; int head; int tail; char * queue[QUEUE_SIZE]; @@ -153,7 +150,7 @@ readline_stdin(void * arg) { memcpy(str, tmp, n); str[n] = 0; - LOCK(q); + pthread_mutex_lock(&q->lock); q->queue[q->tail] = str; if (++q->tail >= QUEUE_SIZE) { @@ -163,7 +160,7 @@ readline_stdin(void * arg) { // queue overflow exit(1); } - UNLOCK(q); + pthread_mutex_unlock(&q->lock); } return NULL; } @@ -171,16 +168,16 @@ readline_stdin(void * arg) { static int lreadstdin(lua_State *L) { struct queue *q = lua_touserdata(L, lua_upvalueindex(1)); - LOCK(q); + pthread_mutex_lock(&q->lock); if (q->head == q->tail) { - UNLOCK(q); + pthread_mutex_unlock(&q->lock); return 0; } char * str = q->queue[q->head]; if (++q->head >= QUEUE_SIZE) { q->head = 0; } - UNLOCK(q); + pthread_mutex_unlock(&q->lock); lua_pushstring(L, str); free(str); return 1; @@ -201,6 +198,7 @@ luaopen_clientsocket(lua_State *L) { struct queue * q = lua_newuserdata(L, sizeof(*q)); memset(q, 0, sizeof(*q)); + pthread_mutex_init(&q->lock, NULL); lua_pushcclosure(L, lreadstdin, 1); lua_setfield(L, -2, "readstdin"); diff --git a/lualib-src/lua-debugchannel.c b/lualib-src/lua-debugchannel.c index 9e4539d3..ad7e1f1b 100644 --- a/lualib-src/lua-debugchannel.c +++ b/lualib-src/lua-debugchannel.c @@ -4,10 +4,9 @@ #include #include #include +#include "spinlock.h" #define METANAME "debugchannel" -#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} -#define UNLOCK(q) __sync_lock_release(&(q)->lock); struct command { struct command * next; @@ -15,7 +14,7 @@ struct command { }; struct channel { - int lock; + struct spinlock lock; int ref; struct command * head; struct command * tail; @@ -26,6 +25,7 @@ channel_new() { struct channel * c = malloc(sizeof(*c)); memset(c, 0 , sizeof(*c)); c->ref = 1; + SPIN_INIT(c) return c; } @@ -33,21 +33,21 @@ channel_new() { static struct channel * channel_connect(struct channel *c) { struct channel * ret = NULL; - LOCK(c) + SPIN_LOCK(c) if (c->ref == 1) { ++c->ref; ret = c; } - UNLOCK(c) + SPIN_UNLOCK(c) return ret; } static struct channel * channel_release(struct channel *c) { - LOCK(c) + SPIN_LOCK(c) --c->ref; if (c->ref > 0) { - UNLOCK(c) + SPIN_UNLOCK(c) return c; } // never unlock while reference is 0 @@ -59,6 +59,8 @@ channel_release(struct channel *c) { free(p); p = next; } + SPIN_UNLOCK(c) + SPIN_DESTROY(c) free(c); return NULL; } @@ -67,9 +69,9 @@ channel_release(struct channel *c) { static struct command * channel_read(struct channel *c, double timeout) { struct command * ret = NULL; - LOCK(c) + SPIN_LOCK(c) if (c->head == NULL) { - UNLOCK(c) + SPIN_UNLOCK(c) int ti = (int)(timeout * 100000); usleep(ti); return NULL; @@ -79,7 +81,7 @@ channel_read(struct channel *c, double timeout) { if (c->head == NULL) { c->tail = NULL; } - UNLOCK(c) + SPIN_UNLOCK(c) return ret; } @@ -90,14 +92,14 @@ channel_write(struct channel *c, const char * s, size_t sz) { cmd->sz = sz; cmd->next = NULL; memcpy(cmd+1, s, sz); - LOCK(c) + SPIN_LOCK(c) if (c->tail == NULL) { c->head = c->tail = cmd; } else { c->tail->next = cmd; c->tail = cmd; } - UNLOCK(c) + SPIN_UNLOCK(c) } struct channel_box { diff --git a/lualib-src/lua-multicast.c b/lualib-src/lua-multicast.c index 599616f9..cff8d434 100644 --- a/lualib-src/lua-multicast.c +++ b/lualib-src/lua-multicast.c @@ -5,6 +5,8 @@ #include #include +#include "atomic.h" + struct mc_package { int reference; uint32_t size; @@ -116,7 +118,7 @@ static int mc_closelocal(lua_State *L) { struct mc_package *pack = lua_touserdata(L,1); - int ref = __sync_sub_and_fetch(&pack->reference, 1); + int ref = ATOM_DEC(&pack->reference); if (ref <= 0) { skynet_free(pack->data); skynet_free(pack); diff --git a/lualib-src/lua-sharedata.c b/lualib-src/lua-sharedata.c index e7a27c57..99cadd15 100644 --- a/lualib-src/lua-sharedata.c +++ b/lualib-src/lua-sharedata.c @@ -4,6 +4,7 @@ #include #include #include +#include "atomic.h" #define KEYTYPE_INTEGER 0 #define KEYTYPE_STRING 1 @@ -663,7 +664,7 @@ releaseobj(lua_State *L) { struct ctrl *c = lua_touserdata(L, 1); struct table *tbl = c->root; struct state *s = lua_touserdata(tbl->L, 1); - __sync_fetch_and_sub(&s->ref, 1); + ATOM_DEC(&s->ref); c->root = NULL; c->update = NULL; @@ -674,7 +675,7 @@ static int lboxconf(lua_State *L) { struct table * tbl = get_table(L,1); struct state * s = lua_touserdata(tbl->L, 1); - __sync_fetch_and_add(&s->ref, 1); + ATOM_INC(&s->ref); struct ctrl * c = lua_newuserdata(L, sizeof(*c)); c->root = tbl; @@ -719,7 +720,7 @@ static int lincref(lua_State *L) { struct table *tbl = get_table(L,1); struct state * s = lua_touserdata(tbl->L, 1); - int ref = __sync_add_and_fetch(&s->ref, 1); + int ref = ATOM_INC(&s->ref); lua_pushinteger(L , ref); return 1; @@ -729,7 +730,7 @@ static int ldecref(lua_State *L) { struct table *tbl = get_table(L,1); struct state * s = lua_touserdata(tbl->L, 1); - int ref = __sync_sub_and_fetch(&s->ref, 1); + int ref = ATOM_DEC(&s->ref); lua_pushinteger(L , ref); return 1; diff --git a/lualib-src/lua-stm.c b/lualib-src/lua-stm.c index b38fbcd1..e175d100 100644 --- a/lualib-src/lua-stm.c +++ b/lualib-src/lua-stm.c @@ -7,6 +7,7 @@ #include "rwlock.h" #include "skynet_malloc.h" +#include "atomic.h" struct stm_object { struct rwlock lock; @@ -45,7 +46,7 @@ static void stm_releasecopy(struct stm_copy *copy) { if (copy == NULL) return; - if (__sync_sub_and_fetch(©->reference, 1) == 0) { + if (ATOM_DEC(©->reference) == 0) { skynet_free(copy->msg); skynet_free(copy); } @@ -70,7 +71,7 @@ stm_release(struct stm_object *obj) { static void stm_releasereader(struct stm_object *obj) { rwlock_rlock(&obj->lock); - if (__sync_sub_and_fetch(&obj->reference,1) == 0) { + if (ATOM_DEC(&obj->reference) == 0) { // last reader, no writer. so no need to unlock assert(obj->copy == NULL); skynet_free(obj); @@ -82,7 +83,7 @@ stm_releasereader(struct stm_object *obj) { static void stm_grab(struct stm_object *obj) { rwlock_rlock(&obj->lock); - int ref = __sync_fetch_and_add(&obj->reference,1); + int ref = ATOM_FINC(&obj->reference); rwlock_runlock(&obj->lock); assert(ref > 0); } @@ -92,7 +93,7 @@ stm_copy(struct stm_object *obj) { rwlock_rlock(&obj->lock); struct stm_copy * ret = obj->copy; if (ret) { - int ref = __sync_fetch_and_add(&ret->reference,1); + int ref = ATOM_FINC(&ret->reference); assert(ref > 0); } rwlock_runlock(&obj->lock); diff --git a/skynet-src/atomic.h b/skynet-src/atomic.h new file mode 100644 index 00000000..f79c7148 --- /dev/null +++ b/skynet-src/atomic.h @@ -0,0 +1,14 @@ +#ifndef SKYNET_ATOMIC_H +#define SKYNET_ATOMIC_H + +#define ATOM_CAS(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) +#define ATOM_CAS_POINTER(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) +#define ATOM_INC(ptr) __sync_add_and_fetch(ptr, 1) +#define ATOM_FINC(ptr) __sync_fetch_and_add(ptr, 1) +#define ATOM_DEC(ptr) __sync_sub_and_fetch(ptr, 1) +#define ATOM_FDEC(ptr) __sync_fetch_and_sub(ptr, 1) +#define ATOM_ADD(ptr,n) __sync_add_and_fetch(ptr, n) +#define ATOM_SUB(ptr,n) __sync_sub_and_fetch(ptr, n) +#define ATOM_AND(ptr,n) __sync_and_and_fetch(ptr, n) + +#endif diff --git a/skynet-src/malloc_hook.c b/skynet-src/malloc_hook.c index d9ad6f32..3b072168 100644 --- a/skynet-src/malloc_hook.c +++ b/skynet-src/malloc_hook.c @@ -6,6 +6,7 @@ #include "malloc_hook.h" #include "skynet.h" +#include "atomic.h" static size_t _used_memory = 0; static size_t _memory_block = 0; @@ -32,11 +33,11 @@ get_allocated_field(uint32_t handle) { ssize_t old_alloc = data->allocated; if(old_handle == 0 || old_alloc <= 0) { // data->allocated may less than zero, because it may not count at start. - if(!__sync_bool_compare_and_swap(&data->handle, old_handle, handle)) { + if(!ATOM_CAS(&data->handle, old_handle, handle)) { return 0; } if (old_alloc < 0) { - __sync_bool_compare_and_swap(&data->allocated, old_alloc, 0); + ATOM_CAS(&data->allocated, old_alloc, 0); } } if(data->handle != handle) { @@ -47,21 +48,21 @@ get_allocated_field(uint32_t handle) { inline static void update_xmalloc_stat_alloc(uint32_t handle, size_t __n) { - __sync_add_and_fetch(&_used_memory, __n); - __sync_add_and_fetch(&_memory_block, 1); + ATOM_ADD(&_used_memory, __n); + ATOM_INC(&_memory_block); ssize_t* allocated = get_allocated_field(handle); if(allocated) { - __sync_add_and_fetch(allocated, __n); + ATOM_ADD(allocated, __n); } } inline static void update_xmalloc_stat_free(uint32_t handle, size_t __n) { - __sync_sub_and_fetch(&_used_memory, __n); - __sync_sub_and_fetch(&_memory_block, 1); + ATOM_SUB(&_used_memory, __n); + ATOM_DEC(&_memory_block); ssize_t* allocated = get_allocated_field(handle); if(allocated) { - __sync_sub_and_fetch(allocated, __n); + ATOM_SUB(allocated, __n); } } diff --git a/skynet-src/rwlock.h b/skynet-src/rwlock.h index e366f18c..5a995918 100644 --- a/skynet-src/rwlock.h +++ b/skynet-src/rwlock.h @@ -1,6 +1,8 @@ #ifndef SKYNET_RWLOCK_H #define SKYNET_RWLOCK_H +#ifndef USE_PTHREAD_LOCK + struct rwlock { int write; int read; @@ -45,4 +47,42 @@ rwlock_runlock(struct rwlock *lock) { __sync_sub_and_fetch(&lock->read,1); } +#else + +#include + +// only for some platform doesn't have __sync_* +// todo: check the result of pthread api + +struct rwlock { + pthread_rwlock_t lock; +}; + +static inline void +rwlock_init(struct rwlock *lock) { + pthread_rwlock_init(&lock->lock, NULL); +} + +static inline void +rwlock_rlock(struct rwlock *lock) { + pthread_rwlock_rdlock(&lock->lock); +} + +static inline void +rwlock_wlock(struct rwlock *lock) { + pthread_rwlock_wrlock(&lock->lock); +} + +static inline void +rwlock_wunlock(struct rwlock *lock) { + pthread_rwlock_unlock(&lock->lock); +} + +static inline void +rwlock_runlock(struct rwlock *lock) { + pthread_rwlock_unlock(&lock->lock); +} + +#endif + #endif diff --git a/skynet-src/skynet_env.c b/skynet-src/skynet_env.c index 9dbbcf9c..a5882f21 100644 --- a/skynet-src/skynet_env.c +++ b/skynet-src/skynet_env.c @@ -1,5 +1,6 @@ #include "skynet.h" #include "skynet_env.h" +#include "spinlock.h" #include #include @@ -8,18 +9,15 @@ #include struct skynet_env { - int lock; + struct spinlock lock; lua_State *L; }; static struct skynet_env *E = NULL; -#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} -#define UNLOCK(q) __sync_lock_release(&(q)->lock); - const char * skynet_getenv(const char *key) { - LOCK(E) + SPIN_LOCK(E) lua_State *L = E->L; @@ -27,14 +25,14 @@ skynet_getenv(const char *key) { const char * result = lua_tostring(L, -1); lua_pop(L, 1); - UNLOCK(E) + SPIN_UNLOCK(E) return result; } void skynet_setenv(const char *key, const char *value) { - LOCK(E) + SPIN_LOCK(E) lua_State *L = E->L; lua_getglobal(L, key); @@ -43,12 +41,12 @@ skynet_setenv(const char *key, const char *value) { lua_pushstring(L,value); lua_setglobal(L,key); - UNLOCK(E) + SPIN_UNLOCK(E) } void skynet_env_init() { E = skynet_malloc(sizeof(*E)); - E->lock = 0; + SPIN_INIT(E) E->L = luaL_newstate(); } diff --git a/skynet-src/skynet_module.c b/skynet-src/skynet_module.c index 2da34629..d586427f 100644 --- a/skynet-src/skynet_module.c +++ b/skynet-src/skynet_module.c @@ -1,6 +1,7 @@ #include "skynet.h" #include "skynet_module.h" +#include "spinlock.h" #include #include @@ -13,7 +14,7 @@ struct modules { int count; - int lock; + struct spinlock lock; const char * path; struct skynet_module m[MAX_MODULE_TYPE]; }; @@ -95,7 +96,7 @@ skynet_module_query(const char * name) { if (result) return result; - while(__sync_lock_test_and_set(&M->lock,1)) {} + SPIN_LOCK(M) result = _query(name); // double check @@ -114,21 +115,22 @@ skynet_module_query(const char * name) { } } - __sync_lock_release(&M->lock); + SPIN_UNLOCK(M) return result; } void skynet_module_insert(struct skynet_module *mod) { - while(__sync_lock_test_and_set(&M->lock,1)) {} + SPIN_LOCK(M) struct skynet_module * m = _query(mod->name); assert(m == NULL && M->count < MAX_MODULE_TYPE); int index = M->count; M->m[index] = *mod; ++M->count; - __sync_lock_release(&M->lock); + + SPIN_UNLOCK(M) } void * @@ -164,7 +166,8 @@ skynet_module_init(const char *path) { struct modules *m = skynet_malloc(sizeof(*m)); m->count = 0; m->path = skynet_strdup(path); - m->lock = 0; + + SPIN_INIT(m) M = m; } diff --git a/skynet-src/skynet_monitor.c b/skynet-src/skynet_monitor.c index 9ee302e5..8d47fc89 100644 --- a/skynet-src/skynet_monitor.c +++ b/skynet-src/skynet_monitor.c @@ -3,6 +3,7 @@ #include "skynet_monitor.h" #include "skynet_server.h" #include "skynet.h" +#include "atomic.h" #include #include @@ -30,7 +31,7 @@ void skynet_monitor_trigger(struct skynet_monitor *sm, uint32_t source, uint32_t destination) { sm->source = source; sm->destination = destination; - __sync_fetch_and_add(&sm->version , 1); + ATOM_INC(&sm->version); } void diff --git a/skynet-src/skynet_mq.c b/skynet-src/skynet_mq.c index ba0c61e6..157f33d8 100644 --- a/skynet-src/skynet_mq.c +++ b/skynet-src/skynet_mq.c @@ -1,6 +1,7 @@ #include "skynet.h" #include "skynet_mq.h" #include "skynet_handle.h" +#include "spinlock.h" #include #include @@ -18,11 +19,11 @@ #define MQ_OVERLOAD 1024 struct message_queue { + struct spinlock lock; uint32_t handle; int cap; int head; int tail; - int lock; int release; int in_global; int overload; @@ -34,19 +35,16 @@ struct message_queue { struct global_queue { struct message_queue *head; struct message_queue *tail; - int lock; + struct spinlock lock; }; static struct global_queue *Q = NULL; -#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} -#define UNLOCK(q) __sync_lock_release(&(q)->lock); - void skynet_globalmq_push(struct message_queue * queue) { struct global_queue *q= Q; - LOCK(q) + SPIN_LOCK(q) assert(queue->next == NULL); if(q->tail) { q->tail->next = queue; @@ -54,14 +52,14 @@ skynet_globalmq_push(struct message_queue * queue) { } else { q->head = q->tail = queue; } - UNLOCK(q) + SPIN_UNLOCK(q) } struct message_queue * skynet_globalmq_pop() { struct global_queue *q = Q; - LOCK(q) + SPIN_LOCK(q) struct message_queue *mq = q->head; if(mq) { q->head = mq->next; @@ -71,7 +69,7 @@ skynet_globalmq_pop() { } mq->next = NULL; } - UNLOCK(q) + SPIN_UNLOCK(q) return mq; } @@ -83,7 +81,7 @@ skynet_mq_create(uint32_t handle) { q->cap = DEFAULT_QUEUE_SIZE; q->head = 0; q->tail = 0; - q->lock = 0; + 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. @@ -100,6 +98,7 @@ skynet_mq_create(uint32_t handle) { static void _release(struct message_queue *q) { assert(q->next == NULL); + SPIN_DESTROY(q) skynet_free(q->queue); skynet_free(q); } @@ -113,11 +112,11 @@ int skynet_mq_length(struct message_queue *q) { int head, tail,cap; - LOCK(q) + SPIN_LOCK(q) head = q->head; tail = q->tail; cap = q->cap; - UNLOCK(q) + SPIN_UNLOCK(q) if (head <= tail) { return tail - head; @@ -138,7 +137,7 @@ skynet_mq_overload(struct message_queue *q) { int skynet_mq_pop(struct message_queue *q, struct skynet_message *message) { int ret = 1; - LOCK(q) + SPIN_LOCK(q) if (q->head != q->tail) { *message = q->queue[q->head++]; @@ -167,7 +166,7 @@ skynet_mq_pop(struct message_queue *q, struct skynet_message *message) { q->in_global = 0; } - UNLOCK(q) + SPIN_UNLOCK(q) return ret; } @@ -190,7 +189,7 @@ expand_queue(struct message_queue *q) { void skynet_mq_push(struct message_queue *q, struct skynet_message *message) { assert(message); - LOCK(q) + SPIN_LOCK(q) q->queue[q->tail] = *message; if (++ q->tail >= q->cap) { @@ -206,25 +205,26 @@ skynet_mq_push(struct message_queue *q, struct skynet_message *message) { skynet_globalmq_push(q); } - UNLOCK(q) + SPIN_UNLOCK(q) } void skynet_mq_init() { struct global_queue *q = skynet_malloc(sizeof(*q)); memset(q,0,sizeof(*q)); + SPIN_INIT(q); Q=q; } void skynet_mq_mark_release(struct message_queue *q) { - LOCK(q) + SPIN_LOCK(q) assert(q->release == 0); q->release = 1; if (q->in_global != MQ_IN_GLOBAL) { skynet_globalmq_push(q); } - UNLOCK(q) + SPIN_UNLOCK(q) } static void @@ -238,13 +238,13 @@ _drop_queue(struct message_queue *q, message_drop drop_func, void *ud) { void skynet_mq_release(struct message_queue *q, message_drop drop_func, void *ud) { - LOCK(q) + SPIN_LOCK(q) if (q->release) { - UNLOCK(q) + SPIN_UNLOCK(q) _drop_queue(q, drop_func, ud); } else { skynet_globalmq_push(q); - UNLOCK(q) + SPIN_UNLOCK(q) } } diff --git a/skynet-src/skynet_server.c b/skynet-src/skynet_server.c index 52331193..4972e7a4 100644 --- a/skynet-src/skynet_server.c +++ b/skynet-src/skynet_server.c @@ -10,6 +10,8 @@ #include "skynet_monitor.h" #include "skynet_imp.h" #include "skynet_log.h" +#include "spinlock.h" +#include "atomic.h" #include @@ -21,16 +23,18 @@ #ifdef CALLING_CHECK -#define CHECKCALLING_BEGIN(ctx) assert(__sync_lock_test_and_set(&ctx->calling,1) == 0); -#define CHECKCALLING_END(ctx) __sync_lock_release(&ctx->calling); -#define CHECKCALLING_INIT(ctx) ctx->calling = 0; -#define CHECKCALLING_DECL int calling; +#define CHECKCALLING_BEGIN(ctx) if (!(spinlock_trylock(&ctx->calling))) { assert(0); } +#define CHECKCALLING_END(ctx) spinlock_unlock(&ctx->calling); +#define CHECKCALLING_INIT(ctx) spinlock_init(&ctx->calling); +#define CHECKCALLING_DESTROY(ctx) spinlock_destroy(&ctx->calling); +#define CHECKCALLING_DECL struct spinlock calling; #else #define CHECKCALLING_BEGIN(ctx) #define CHECKCALLING_END(ctx) #define CHECKCALLING_INIT(ctx) +#define CHECKCALLING_DESTROY(ctx) #define CHECKCALLING_DECL #endif @@ -68,12 +72,12 @@ skynet_context_total() { static void context_inc() { - __sync_fetch_and_add(&G_NODE.total,1); + ATOM_INC(&G_NODE.total); } static void context_dec() { - __sync_fetch_and_sub(&G_NODE.total,1); + ATOM_DEC(&G_NODE.total); } uint32_t @@ -179,7 +183,7 @@ skynet_context_newsession(struct skynet_context *ctx) { void skynet_context_grab(struct skynet_context *ctx) { - __sync_add_and_fetch(&ctx->ref,1); + ATOM_INC(&ctx->ref); } void @@ -197,13 +201,14 @@ delete_context(struct skynet_context *ctx) { } skynet_module_instance_release(ctx->mod, ctx->instance); skynet_mq_mark_release(ctx->queue); + CHECKCALLING_DESTROY(ctx) skynet_free(ctx); context_dec(); } struct skynet_context * skynet_context_release(struct skynet_context *ctx) { - if (__sync_sub_and_fetch(&ctx->ref,1) == 0) { + if (ATOM_DEC(&ctx->ref) == 0) { delete_context(ctx); return NULL; } @@ -560,7 +565,7 @@ cmd_logon(struct skynet_context * context, const char * param) { if (lastf == NULL) { f = skynet_log_open(context, handle); if (f) { - if (!__sync_bool_compare_and_swap(&ctx->logfile, NULL, f)) { + if (!ATOM_CAS_POINTER(&ctx->logfile, NULL, f)) { // logfile opens in other thread, close this one. fclose(f); } @@ -581,7 +586,7 @@ cmd_logoff(struct skynet_context * context, const char * param) { FILE * f = ctx->logfile; if (f) { // logfile may close in other thread - if (__sync_bool_compare_and_swap(&ctx->logfile, f, NULL)) { + if (ATOM_CAS_POINTER(&ctx->logfile, f, NULL)) { skynet_log_close(context, f, handle); } } diff --git a/skynet-src/skynet_timer.c b/skynet-src/skynet_timer.c index f23114dc..c9a113ae 100644 --- a/skynet-src/skynet_timer.c +++ b/skynet-src/skynet_timer.c @@ -4,6 +4,7 @@ #include "skynet_mq.h" #include "skynet_server.h" #include "skynet_handle.h" +#include "spinlock.h" #include #include @@ -17,9 +18,6 @@ typedef void (*timer_execute_func)(void *ud,void *arg); -#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} -#define UNLOCK(q) __sync_lock_release(&(q)->lock); - #define TIME_NEAR_SHIFT 8 #define TIME_NEAR (1 << TIME_NEAR_SHIFT) #define TIME_LEVEL_SHIFT 6 @@ -45,7 +43,7 @@ struct link_list { struct timer { struct link_list near[TIME_NEAR]; struct link_list t[4][TIME_LEVEL]; - int lock; + struct spinlock lock; uint32_t time; uint32_t current; uint32_t starttime; @@ -97,12 +95,12 @@ timer_add(struct timer *T,void *arg,size_t sz,int time) { struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz); memcpy(node+1,arg,sz); - LOCK(T); + SPIN_LOCK(T); node->expire=time+T->time; add_node(T,node); - UNLOCK(T); + SPIN_UNLOCK(T); } static void @@ -162,16 +160,16 @@ timer_execute(struct timer *T) { while (T->near[idx].head.next) { struct timer_node *current = link_clear(&T->near[idx]); - UNLOCK(T); + SPIN_UNLOCK(T); // dispatch_list don't need lock T dispatch_list(current); - LOCK(T); + SPIN_LOCK(T); } } static void timer_update(struct timer *T) { - LOCK(T); + SPIN_LOCK(T); // try to dispatch timeout 0 (rare condition) timer_execute(T); @@ -181,7 +179,7 @@ timer_update(struct timer *T) { timer_execute(T); - UNLOCK(T); + SPIN_UNLOCK(T); } static struct timer * @@ -201,7 +199,8 @@ timer_create_timer() { } } - r->lock = 0; + SPIN_INIT(r) + r->current = 0; return r; diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index 78f9b47b..b2454d2e 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -2,6 +2,7 @@ #include "socket_server.h" #include "socket_poll.h" +#include "atomic.h" #include #include @@ -237,13 +238,13 @@ static int reserve_id(struct socket_server *ss) { int i; for (i=0;ialloc_id), 1); + int id = ATOM_INC(&(ss->alloc_id)); if (id < 0) { - id = __sync_and_and_fetch(&(ss->alloc_id), 0x7fffffff); + id = ATOM_AND(&(ss->alloc_id), 0x7fffffff); } struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID) { - if (__sync_bool_compare_and_swap(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { + if (ATOM_CAS(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { s->id = id; s->fd = -1; return id; diff --git a/skynet-src/spinlock.h b/skynet-src/spinlock.h new file mode 100644 index 00000000..d9744c3f --- /dev/null +++ b/skynet-src/spinlock.h @@ -0,0 +1,77 @@ +#ifndef SKYNET_SPINLOCK_H +#define SKYNET_SPINLOCK_H + +#define SPIN_INIT(q) spinlock_init(&(q)->lock); +#define SPIN_LOCK(q) spinlock_lock(&(q)->lock); +#define SPIN_UNLOCK(q) spinlock_unlock(&(q)->lock); +#define SPIN_DESTROY(q) spinlock_destroy(&(q)->lock); + +#ifndef USE_PTHREAD_LOCK + +struct spinlock { + int lock; +}; + +static inline void +spinlock_init(struct spinlock *lock) { + lock->lock = 0; +} + +static inline void +spinlock_lock(struct spinlock *lock) { + while (__sync_lock_test_and_set(&lock->lock,1)) {} +} + +static inline int +spinlock_trylock(struct spinlock *lock) { + return __sync_lock_test_and_set(&lock->lock,1) == 0; +} + +static inline void +spinlock_unlock(struct spinlock *lock) { + __sync_lock_release(&lock->lock); +} + +static inline void +spinlock_destroy(struct spinlock *lock) { +} + +#else + +#include + +// we use mutex instead of spinlock for some reason +// you can also replace to pthread_spinlock + +struct spinlock { + pthread_mutex_t lock; +}; + +static inline void +spinlock_init(struct spinlock *lock) { + pthread_mutex_init(&lock->lock, NULL); +} + +static inline void +spinlock_lock(struct spinlock *lock) { + pthread_mutex_lock(&lock->lock); +} + +static inline int +spinlock_trylock(struct spinlock *lock) { + return pthread_mutex_trylock(&lock->lock) == 0; +} + +static inline void +spinlock_unlock(struct spinlock *lock) { + pthread_mutex_unlock(&lock->lock); +} + +static inline void +spinlock_destroy(struct spinlock *lock) { + pthread_mutex_destroy(&lock->lock); +} + +#endif + +#endif From a38a3140dde2e8d20aadbe9dd04b8d4c0a14e37b Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 14 Aug 2015 17:32:59 +0800 Subject: [PATCH 37/97] error when send to address 0 --- lualib-src/lua-skynet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lualib-src/lua-skynet.c b/lualib-src/lua-skynet.c index c92ff98d..7d75d2ce 100644 --- a/lualib-src/lua-skynet.c +++ b/lualib-src/lua-skynet.c @@ -172,6 +172,9 @@ _send(lua_State *L) { uint32_t dest = (uint32_t)lua_tointeger(L, 1); const char * dest_string = NULL; if (dest == 0) { + if (lua_type(L,1) == LUA_TNUMBER) { + return luaL_error(L, "Invalid service address 0"); + } dest_string = get_dest_string(L, 1); } From 2583af26d7e5fe58f1f0aef4463d99ae1619a656 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 14 Aug 2015 23:22:00 +0800 Subject: [PATCH 38/97] add cluster.register and cluster.query --- examples/cluster1.lua | 13 +++++++------ examples/cluster2.lua | 9 ++++++--- lualib-src/lua-cluster.c | 4 ++-- lualib/cluster.lua | 10 ++++++++++ service/clusterd.lua | 31 +++++++++++++++++++++++++++++-- 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/examples/cluster1.lua b/examples/cluster1.lua index d44899ba..0eca6176 100644 --- a/examples/cluster1.lua +++ b/examples/cluster1.lua @@ -1,16 +1,17 @@ local skynet = require "skynet" local cluster = require "cluster" -require "skynet.manager" -- import skynet.name local snax = require "snax" skynet.start(function() local sdb = skynet.newservice("simpledb") - skynet.name(".simpledb", sdb) + -- register name "sdb" for simpledb, you can use cluster.query() later. + -- See cluster2.lua + cluster.register("sdb", sdb) - print(skynet.call(".simpledb", "lua", "SET", "a", "foobar")) - print(skynet.call(".simpledb", "lua", "SET", "b", "foobar2")) - print(skynet.call(".simpledb", "lua", "GET", "a")) - print(skynet.call(".simpledb", "lua", "GET", "b")) + print(skynet.call(sdb, "lua", "SET", "a", "foobar")) + print(skynet.call(sdb, "lua", "SET", "b", "foobar2")) + print(skynet.call(sdb, "lua", "GET", "a")) + print(skynet.call(sdb, "lua", "GET", "b")) cluster.open "db" cluster.open "db2" -- unique snax service diff --git a/examples/cluster2.lua b/examples/cluster2.lua index 0aef412c..84648567 100644 --- a/examples/cluster2.lua +++ b/examples/cluster2.lua @@ -2,15 +2,18 @@ local skynet = require "skynet" local cluster = require "cluster" skynet.start(function() - local proxy = cluster.proxy("db", ".simpledb") + -- query name "sdb" of cluster db. + local sdb = cluster.query("db", "sdb") + print("db.sbd=",sdb) + local proxy = cluster.proxy("db", sdb) local largekey = string.rep("X", 128*1024) local largevalue = string.rep("R", 100 * 1024) print(skynet.call(proxy, "lua", "SET", largekey, largevalue)) local v = skynet.call(proxy, "lua", "GET", largekey) assert(largevalue == v) - print(cluster.call("db", ".simpledb", "GET", "a")) - print(cluster.call("db2", ".simpledb", "GET", "b")) + print(cluster.call("db", sdb, "GET", "a")) + print(cluster.call("db2", sdb, "GET", "b")) -- test snax service local pingserver = cluster.snax("db", "pingserver") diff --git a/lualib-src/lua-cluster.c b/lualib-src/lua-cluster.c index e35615c7..6ee1e69b 100644 --- a/lualib-src/lua-cluster.c +++ b/lualib-src/lua-cluster.c @@ -219,8 +219,8 @@ unpackreq_number(lua_State *L, const uint8_t * buf, int sz) { static int unpackmreq_number(lua_State *L, const uint8_t * buf, int sz) { - if (sz != 15) { - return luaL_error(L, "Invalid cluster message size %d (multi req must be 15)", sz); + if (sz != 13) { + return luaL_error(L, "Invalid cluster message size %d (multi req must be 13)", sz); } uint32_t address = unpack_uint32(buf+1); uint32_t session = unpack_uint32(buf+5); diff --git a/lualib/cluster.lua b/lualib/cluster.lua index e4407f06..dba8f318 100644 --- a/lualib/cluster.lua +++ b/lualib/cluster.lua @@ -33,6 +33,16 @@ function cluster.snax(node, name, address) return snax.bind(handle, name) end +function cluster.register(name, addr) + assert(type(name) == "string") + assert(addr == nil or type(addr) == "number") + return skynet.call(clusterd, "lua", "register", name, addr) +end + +function cluster.query(node, name) + return skynet.call(clusterd, "lua", "req", node, 0, skynet.pack(name)) +end + skynet.init(function() clusterd = skynet.uniqueservice("clusterd") end) diff --git a/service/clusterd.lua b/service/clusterd.lua index b3c74722..22d5e9f0 100644 --- a/service/clusterd.lua +++ b/service/clusterd.lua @@ -97,6 +97,21 @@ function command.proxy(source, node, name) skynet.ret(skynet.pack(proxy[fullname])) end +local register_name = {} + +function command.register(source, name, addr) + assert(register_name[name] == nil) + addr = addr or source + local old_name = register_name[addr] + if old_name then + register_name[old_name] = nil + end + register_name[addr] = name + register_name[name] = addr + skynet.ret(nil) + skynet.error(string.format("Register [%s] :%08x", name, addr)) +end + local large_request = {} function command.socket(source, subcmd, fd, msg) @@ -122,8 +137,20 @@ function command.socket(source, subcmd, fd, msg) return end end - local ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg, sz) - local response + local ok, response + if addr == 0 then + local name = skynet.unpack(msg, sz) + local addr = register_name[name] + if addr then + ok = true + msg, sz = skynet.pack(addr) + else + ok = false + msg = "name not found" + end + else + ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg, sz) + end if ok then response = cluster.packresponse(session, true, msg, sz) if type(response) == "table" then From 1b53e6e28de7cda4dd3df8d974525a25e406e486 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 17 Aug 2015 11:21:20 +0800 Subject: [PATCH 39/97] Release alpha 10 --- HISTORY.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index a970b7c2..48c7a069 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,10 +1,20 @@ +v1.0.0-alpha10 (2015-8-17) +----------- +* Remove the size limit of cluster RPC message. +* Remove the size limit of local message. +* Add cluster.query and clsuter.register. +* Add an option of pthread mutex lock. +* Add skynet.core.intcommand to optimize skynet.sleep etc. +* Fix a memory leak bug in lua shared proto. +* snax.msgserver use string instead of lightuserdata/size. +* Remove some unused api in netpack. +* Raise error when skynet.send to 0. + v1.0.0-alpha9 (2015-8-10) ----------- * Improve lua serialization , support pairs metamethod. * Bugfix : sproto (See commits log of sproto) * Add user log service support (In config) -* Remove the size limit of cluster RPC message. -* Remove the size limit of local message. * Other minor bugfix (See commits log) v1.0.0-alpha8 (2015-6-29) From c0862d8445bf6e20f104b0e171e8e03ca98c58e5 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 21 Aug 2015 11:41:01 +0800 Subject: [PATCH 40/97] add global share string table --- 3rd/lua/Makefile | 2 +- 3rd/lua/lapi.c | 4 +- 3rd/lua/lgc.c | 3 +- 3rd/lua/lstring.c | 224 +++++++++++++++++++++++++++++++++++++- 3rd/lua/lstring.h | 5 + 3rd/lua/luaconf.h | 1 + lualib-src/lua-memory.c | 10 ++ service/bootstrap.lua | 4 + service/debug_console.lua | 19 ++++ skynet-src/luashrtbl.h | 17 +++ skynet-src/skynet_main.c | 4 + 11 files changed, 287 insertions(+), 6 deletions(-) create mode 100644 skynet-src/luashrtbl.h diff --git a/3rd/lua/Makefile b/3rd/lua/Makefile index 6c680538..ddf7b349 100644 --- a/3rd/lua/Makefile +++ b/3rd/lua/Makefile @@ -19,7 +19,7 @@ SYSCFLAGS= SYSLDFLAGS= SYSLIBS= -MYCFLAGS= +MYCFLAGS=-I../../skynet-src MYLDFLAGS= MYLIBS= MYOBJS= diff --git a/3rd/lua/lapi.c b/3rd/lua/lapi.c index 953a304b..3f47f7ee 100644 --- a/3rd/lua/lapi.c +++ b/3rd/lua/lapi.c @@ -1000,7 +1000,7 @@ static Proto * cloneproto (lua_State *L, const Proto *src) { const TValue *s=&src->k[i]; TValue *o=&f->k[i]; if (ttisstring(s)) { - TString * str = luaS_newlstr(L,svalue(s),vslen(s)); + TString * str = luaS_clonestring(L,tsvalue(s)); setsvalue2n(L,o,str); } else { setobj(L,o,s); @@ -1288,7 +1288,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { StkId fi = index2addr(L, fidx); api_check(L, ttisLclosure(fi), "Lua function expected"); f = clLvalue(fi); - api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); + api_check(L, (1 <= n && n <= f->p->sp->sizeupvalues), "invalid upvalue index"); if (pf) *pf = f; return &f->upvals[n - 1]; /* get its upvalue pointer */ } diff --git a/3rd/lua/lgc.c b/3rd/lua/lgc.c index e73c58bf..a1ce0245 100644 --- a/3rd/lua/lgc.c +++ b/3rd/lua/lgc.c @@ -188,7 +188,8 @@ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { void luaC_fix (lua_State *L, GCObject *o) { global_State *g = G(L); - lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + if (g->allgc != o) + return; /* if object is not 1st in 'allgc' list, it is in global short string table */ white2gray(o); /* they will be gray forever */ g->allgc = o->next; /* remove object from 'allgc' list */ o->next = g->fixedgc; /* link it to 'fixedgc' list */ diff --git a/3rd/lua/lstring.c b/3rd/lua/lstring.c index 5e0e3c40..dd36eb87 100644 --- a/3rd/lua/lstring.c +++ b/3rd/lua/lstring.c @@ -148,10 +148,9 @@ void luaS_remove (lua_State *L, TString *ts) { /* ** checks whether short string exists and reuses it or creates a new one */ -static TString *internshrstr (lua_State *L, const char *str, size_t l) { +static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned int h) { TString *ts; global_State *g = G(L); - unsigned int h = luaS_hash(str, l, g->seed); TString **list = &g->strt.hash[lmod(h, g->strt.size)]; for (ts = *list; ts != NULL; ts = ts->u.hnext) { if (l == ts->shrlen && @@ -162,6 +161,13 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { return ts; } } + return NULL; +} + +static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int h) { + TString *ts; + global_State *g = G(L); + TString **list = &g->strt.hash[lmod(h, g->strt.size)]; if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { luaS_resize(L, g->strt.size * 2); list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ @@ -174,6 +180,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { return ts; } +static TString *internshrstr (lua_State *L, const char *str, size_t l); /* ** new string (with explicit length) @@ -224,3 +231,216 @@ Udata *luaS_newudata (lua_State *L, size_t s) { return u; } +/* + * global shared table + */ + +#include "rwlock.h" +#include "atomic.h" +#include + +#define SHRSTR_SLOT 0x10000 +#define HASH_NODE(h) ((h) % SHRSTR_SLOT) + +struct shrmap_slot { + struct rwlock lock; + TString *str; +}; + +struct shrmap { + struct shrmap_slot h[SHRSTR_SLOT]; + int n; +}; + +static struct shrmap *SSM = NULL; + +LUA_API void +luaS_initshr() { + struct shrmap * s = malloc(sizeof(*s)); + memset(s, 0, sizeof(*s)); + int i; + for (i=0;ih[i].lock); + } + SSM = s; +} + +LUA_API void +luaS_exitshr() { + int i; + for (i=0;ih[i].str; + while (str) { + TString * next = str->u.hnext; + free(str); + str = next; + } + } + free(SSM); +} + +static TString * +query_string(unsigned int h, const char *str, lu_byte l) { + struct shrmap_slot *s = &SSM->h[HASH_NODE(h)]; + rwlock_rlock(&s->lock); + TString *ts = s->str; + while (ts) { + if (ts->hash == h && + ts->shrlen == l && + memcmp(str, ts+1, l) == 0) { + break; + } + ts = ts->u.hnext; + } + rwlock_runlock(&s->lock); + return ts; +} + +static TString * +query_ptr(TString *t) { + unsigned int h = t->hash; + struct shrmap_slot *s = &SSM->h[HASH_NODE(h)]; + rwlock_rlock(&s->lock); + TString *ts = s->str; + while (ts) { + if (ts == t) + break; + ts = ts->u.hnext; + } + rwlock_runlock(&s->lock); + return ts; +} + +static TString * +new_string(unsigned int h, const char *str, lu_byte l) { + size_t sz = sizelstring(l); + TString *ts = malloc(sz); + memset(ts, 0, sz); + ts->tt = LUA_TSHRSTR; + ts->hash = h; + ts->shrlen = l; + memcpy(ts+1, str, l); + return ts; +} + +static TString * +add_string(unsigned int h, const char *str, lu_byte l) { + TString * tmp = new_string(h, str, l); + struct shrmap_slot *s = &SSM->h[HASH_NODE(h)]; + rwlock_wlock(&s->lock); + TString *ts = s->str; + while (ts) { + if (ts->hash == h && + ts->shrlen == l && + memcmp(str, ts+1, l) == 0) { + break; + } + ts = ts->u.hnext; + } + if (ts == NULL) { + ts = tmp; + ts->u.hnext = s->str; + s->str = ts; + tmp = NULL; + } + rwlock_wunlock(&s->lock); + if (tmp) { + // string is create by other thread, so free tmp + free(tmp); + } + return ts; +} + +static TString * +internshrstr (lua_State *L, const char *str, size_t l) { + TString *ts; + global_State *g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + unsigned int h0; + // lookup global state of this L first + ts = queryshrstr (L, str, l, h); + if (ts) + return ts; + // lookup SSM again + h0 = luaS_hash(str, l, 0); + ts = query_string(h0, str, l); + if (ts) + return ts; + // If SSM->n greate than 0, add it to SSM + if (SSM->n > 0) { + ATOM_DEC(&SSM->n); + return add_string(h0, str, l); + } + // Else add it to global state (local) + return addshrstr (L, str, l, h); +} + +LUA_API void +luaS_expandshr(int n) { + ATOM_ADD(&SSM->n, n); +} + +LUAI_FUNC TString * +luaS_clonestring(lua_State *L, TString *ts) { + unsigned int h; + int l; + const char * str = getaddrstr(ts); + global_State *g = G(L); + TString *result; + if (ts->tt == LUA_TLNGSTR) + return luaS_newlstr(L, str, ts->u.lnglen); + // look up global state of this L first + l = ts->shrlen; + h = luaS_hash(str, l, g->seed); + result = queryshrstr (L, str, l, h); + if (result) + return result; + // look up SSM by ptr + 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); + return add_string(h, str, l); +} + +struct slotinfo { + int len; + int size; +}; + +static void +getslot(struct shrmap_slot *s, struct slotinfo *info) { + memset(info, 0, sizeof(*info)); + rwlock_rlock(&s->lock); + TString *ts = s->str; + while (ts) { + ++info->len; + info->size += ts->shrlen; + ts = ts->u.hnext; + } + rwlock_runlock(&s->lock); +} + +LUA_API int +luaS_shrinfo(lua_State *L) { + struct slotinfo total; + struct slotinfo tmp; + memset(&total, 0, sizeof(total)); + int i; + int len = 0; + for (i=0;ih[i]; + getslot(s, &tmp); + len += tmp.len; + if (tmp.len > total.len) { + total.len = tmp.len; + } + total.size += tmp.size; + } + lua_pushinteger(L, len); + lua_pushinteger(L, total.size); + lua_pushinteger(L, total.len); + lua_pushinteger(L, SSM->n); + return 4; +} diff --git a/3rd/lua/lstring.h b/3rd/lua/lstring.h index e746f5fc..b3cfa1b7 100644 --- a/3rd/lua/lstring.h +++ b/3rd/lua/lstring.h @@ -43,5 +43,10 @@ LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUA_API void luaS_initshr(); +LUA_API void luaS_exitshr(); +LUA_API void luaS_expandshr(int n); +LUAI_FUNC TString *luaS_clonestring(lua_State *L, TString *); +LUA_API int luaS_shrinfo(lua_State *L); #endif diff --git a/3rd/lua/luaconf.h b/3rd/lua/luaconf.h index 7cfa4faf..5e88dcb0 100644 --- a/3rd/lua/luaconf.h +++ b/3rd/lua/luaconf.h @@ -11,6 +11,7 @@ #include #include +#define LUA_USE_APICHECK /* ** =================================================================== diff --git a/lualib-src/lua-memory.c b/lualib-src/lua-memory.c index 67a3acf6..a3afecfc 100644 --- a/lualib-src/lua-memory.c +++ b/lualib-src/lua-memory.c @@ -2,6 +2,7 @@ #include #include "malloc_hook.h" +#include "luashrtbl.h" static int ltotal(lua_State *L) { @@ -33,6 +34,13 @@ ldump(lua_State *L) { return 0; } +static int +lexpandshrtbl(lua_State *L) { + int n = luaL_checkinteger(L, 1); + luaS_expandshr(n); + return 0; +} + int luaopen_memory(lua_State *L) { luaL_checkversion(L); @@ -43,6 +51,8 @@ luaopen_memory(lua_State *L) { { "dumpinfo", ldumpinfo }, { "dump", ldump }, { "info", dump_mem_lua }, + { "ssinfo", luaS_shrinfo }, + { "ssexpand", lexpandshrtbl }, { NULL, NULL }, }; diff --git a/service/bootstrap.lua b/service/bootstrap.lua index 269654c3..db8d8581 100644 --- a/service/bootstrap.lua +++ b/service/bootstrap.lua @@ -1,8 +1,12 @@ local skynet = require "skynet" local harbor = require "skynet.harbor" 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 standalone = skynet.getenv "standalone" local launcher = assert(skynet.launch("snlua","launcher")) diff --git a/service/debug_console.lua b/service/debug_console.lua index 97b35806..37b20c30 100644 --- a/service/debug_console.lua +++ b/service/debug_console.lua @@ -3,6 +3,7 @@ local codecache = require "skynet.codecache" local core = require "skynet.core" local socket = require "socket" local snax = require "snax" +local memory = require "memory" local port = tonumber(...) local COMMAND = {} @@ -130,6 +131,8 @@ function COMMAND.help() log = "launch a new lua service with log", debug = "debug address : debug a lua service", signal = "signal address sig", + cmem = "Show C memory info", + shrtbl = "Show shared short string table info", } end @@ -258,3 +261,19 @@ function COMMAND.signal(address, sig) core.command("SIGNAL", address) end end + +function COMMAND.cmem() + local info = memory.info() + local tmp = {} + for k,v in pairs(info) do + tmp[skynet.address(k)] = v + end + return tmp +end + +function COMMAND.shrtbl() + local n, total, longest, space = memory.ssinfo() + return { n = n, total = total, longest = longest, space = space } +end + + diff --git a/skynet-src/luashrtbl.h b/skynet-src/luashrtbl.h new file mode 100644 index 00000000..6f566038 --- /dev/null +++ b/skynet-src/luashrtbl.h @@ -0,0 +1,17 @@ +#ifndef LUA_SHORT_STRING_TABLE_H +#define LUA_SHORT_STRING_TABLE_H + +#ifndef DISABLE_SHORT_STRING + +#include "lstring.h" + +#else + +static inline int luaS_shrinfo(lua_State *L) { return 0; } +static inline void luaS_initshr() {} +static inline void luaS_exitshr() {} +static inline void luaS_expandshr(int n); + +#endif + +#endif diff --git a/skynet-src/skynet_main.c b/skynet-src/skynet_main.c index 59e344f8..eb6f4429 100644 --- a/skynet-src/skynet_main.c +++ b/skynet-src/skynet_main.c @@ -3,6 +3,7 @@ #include "skynet_imp.h" #include "skynet_env.h" #include "skynet_server.h" +#include "luashrtbl.h" #include #include @@ -105,6 +106,8 @@ main(int argc, char *argv[]) { "usage: skynet configfilename\n"); return 1; } + + luaS_initshr(); skynet_globalinit(); skynet_env_init(); @@ -139,6 +142,7 @@ main(int argc, char *argv[]) { skynet_start(&config); skynet_globalexit(); + luaS_exitshr(); return 0; } From 9acce94464d162da93f6aea7dd7c31727feaedb3 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 21 Aug 2015 13:55:43 +0800 Subject: [PATCH 41/97] disable lua apicheck --- 3rd/lua/luaconf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/3rd/lua/luaconf.h b/3rd/lua/luaconf.h index 5e88dcb0..7cfa4faf 100644 --- a/3rd/lua/luaconf.h +++ b/3rd/lua/luaconf.h @@ -11,7 +11,6 @@ #include #include -#define LUA_USE_APICHECK /* ** =================================================================== From bb6d5d826ec029a025d2bb5525a30d166e098df9 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 21 Aug 2015 15:59:51 +0800 Subject: [PATCH 42/97] add TString struct size --- 3rd/lua/lstring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/lua/lstring.c b/3rd/lua/lstring.c index dd36eb87..3516747a 100644 --- a/3rd/lua/lstring.c +++ b/3rd/lua/lstring.c @@ -416,7 +416,7 @@ getslot(struct shrmap_slot *s, struct slotinfo *info) { TString *ts = s->str; while (ts) { ++info->len; - info->size += ts->shrlen; + info->size += sizelstring(ts->shrlen); ts = ts->u.hnext; } rwlock_runlock(&s->lock); From eb587c63d3897f5f3a5f14b07e125cea910b79af Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 21 Aug 2015 19:42:09 +0800 Subject: [PATCH 43/97] fix issue #327 --- skynet-src/skynet_server.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skynet-src/skynet_server.c b/skynet-src/skynet_server.c index 4972e7a4..64258a92 100644 --- a/skynet-src/skynet_server.c +++ b/skynet-src/skynet_server.c @@ -674,7 +674,9 @@ int skynet_send(struct skynet_context * context, uint32_t source, uint32_t destination , int type, int session, void * data, size_t sz) { if ((sz & MESSAGE_TYPE_MASK) != sz) { skynet_error(context, "The message to %x is too large", destination); - skynet_free(data); + if (type & PTYPE_TAG_DONTCOPY) { + skynet_free(data); + } return -1; } _filter_args(context, type, &session, (void **)&data, &sz); From 010d1c1d4f9826de9f56868ef13faba1261d59d8 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 24 Aug 2015 11:50:40 +0800 Subject: [PATCH 44/97] avoid dead loop --- service-src/service_harbor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/service-src/service_harbor.c b/service-src/service_harbor.c index 5ff618f1..ed05190b 100644 --- a/service-src/service_harbor.c +++ b/service-src/service_harbor.c @@ -317,8 +317,11 @@ forward_local_messsage(struct harbor *h, void *msg, int sz) { destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT); if (skynet_send(h->ctx, header.source, destination, type, (int)header.session, (void *)msg, sz-HEADER_COOKIE_LENGTH) < 0) { - skynet_send(h->ctx, destination, header.source , PTYPE_ERROR, (int)header.session, NULL, 0); - skynet_error(h->ctx, "Unknown destination :%x from :%x", destination, header.source); + if (type != PTYPE_ERROR) { + // don't need report error when type is error + skynet_send(h->ctx, destination, header.source , PTYPE_ERROR, (int)header.session, NULL, 0); + } + skynet_error(h->ctx, "Unknown destination :%x from :%x type(%d)", destination, header.source, type); } } From 9b0e496afe2781c5f01bbbbd90db9a753fcd38e1 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 27 Aug 2015 13:49:31 +0800 Subject: [PATCH 45/97] minor amend --- 3rd/lua/README | 7 ++++--- 3rd/lua/lstring.h | 2 ++ skynet-src/luashrtbl.h | 5 ++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/3rd/lua/README b/3rd/lua/README index a77dc6bf..efb71d70 100644 --- a/3rd/lua/README +++ b/3rd/lua/README @@ -1,5 +1,6 @@ This is a modify version of lua 5.3.1 (http://www.lua.org/ftp/lua-5.3.1.tar.gz) . -For detail : http://lua-users.org/lists/lua-l/2014-03/msg00489.html - - +For detail , + Shared Proto : http://lua-users.org/lists/lua-l/2014-03/msg00489.html + Shared short string table : http://blog.codingnow.com/2015/08/lua_vm_share_string.html + \ No newline at end of file diff --git a/3rd/lua/lstring.h b/3rd/lua/lstring.h index b3cfa1b7..a28ff0a0 100644 --- a/3rd/lua/lstring.h +++ b/3rd/lua/lstring.h @@ -43,6 +43,8 @@ LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +#define ENABLE_SHORT_STRING_TABLE + LUA_API void luaS_initshr(); LUA_API void luaS_exitshr(); LUA_API void luaS_expandshr(int n); diff --git a/skynet-src/luashrtbl.h b/skynet-src/luashrtbl.h index 6f566038..824a0c85 100644 --- a/skynet-src/luashrtbl.h +++ b/skynet-src/luashrtbl.h @@ -1,11 +1,10 @@ #ifndef LUA_SHORT_STRING_TABLE_H #define LUA_SHORT_STRING_TABLE_H -#ifndef DISABLE_SHORT_STRING - #include "lstring.h" -#else +// If you use modified lua, this macro would be defined in lstring.h +#ifndef ENABLE_SHORT_STRING_TABLE static inline int luaS_shrinfo(lua_State *L) { return 0; } static inline void luaS_initshr() {} From 1bfddda435e0c7952d1d6732a35c659364d6782d Mon Sep 17 00:00:00 2001 From: snail Date: Thu, 27 Aug 2015 18:04:56 +0800 Subject: [PATCH 46/97] uncomplete buffer not free 'uncomplete' buffer not freed in clear --- lualib-src/lua-netpack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lualib-src/lua-netpack.c b/lualib-src/lua-netpack.c index 193938b1..6e601e07 100644 --- a/lualib-src/lua-netpack.c +++ b/lualib-src/lua-netpack.c @@ -49,6 +49,7 @@ struct queue { static void clear_list(struct uncomplete * uc) { while (uc) { + skynet_free(uc->pack.buffer); void * tmp = uc; uc = uc->next; skynet_free(tmp); From 633e5fbe324fefeb4642ebf650cd01f185bbc91b Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Sat, 29 Aug 2015 15:24:24 +0800 Subject: [PATCH 47/97] fix issue #331 --- 3rd/lua/lstring.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/3rd/lua/lstring.c b/3rd/lua/lstring.c index 3516747a..5046624d 100644 --- a/3rd/lua/lstring.c +++ b/3rd/lua/lstring.c @@ -252,36 +252,33 @@ struct shrmap { int n; }; -static struct shrmap *SSM = NULL; +static struct shrmap SSM; LUA_API void luaS_initshr() { - struct shrmap * s = malloc(sizeof(*s)); - memset(s, 0, sizeof(*s)); + struct shrmap * s = &SSM; int i; for (i=0;ih[i].lock); } - SSM = s; } LUA_API void luaS_exitshr() { int i; for (i=0;ih[i].str; + TString *str = SSM.h[i].str; while (str) { TString * next = str->u.hnext; free(str); str = next; } } - free(SSM); } static TString * query_string(unsigned int h, const char *str, lu_byte l) { - struct shrmap_slot *s = &SSM->h[HASH_NODE(h)]; + struct shrmap_slot *s = &SSM.h[HASH_NODE(h)]; rwlock_rlock(&s->lock); TString *ts = s->str; while (ts) { @@ -299,7 +296,7 @@ query_string(unsigned int h, const char *str, lu_byte l) { static TString * query_ptr(TString *t) { unsigned int h = t->hash; - struct shrmap_slot *s = &SSM->h[HASH_NODE(h)]; + struct shrmap_slot *s = &SSM.h[HASH_NODE(h)]; rwlock_rlock(&s->lock); TString *ts = s->str; while (ts) { @@ -326,7 +323,7 @@ new_string(unsigned int h, const char *str, lu_byte l) { static TString * add_string(unsigned int h, const char *str, lu_byte l) { TString * tmp = new_string(h, str, l); - struct shrmap_slot *s = &SSM->h[HASH_NODE(h)]; + struct shrmap_slot *s = &SSM.h[HASH_NODE(h)]; rwlock_wlock(&s->lock); TString *ts = s->str; while (ts) { @@ -366,9 +363,9 @@ internshrstr (lua_State *L, const char *str, size_t l) { ts = query_string(h0, str, l); if (ts) return ts; - // If SSM->n greate than 0, add it to SSM - if (SSM->n > 0) { - ATOM_DEC(&SSM->n); + // If SSM.n greate than 0, add it to SSM + if (SSM.n > 0) { + ATOM_DEC(&SSM.n); return add_string(h0, str, l); } // Else add it to global state (local) @@ -377,7 +374,7 @@ internshrstr (lua_State *L, const char *str, size_t l) { LUA_API void luaS_expandshr(int n) { - ATOM_ADD(&SSM->n, n); + ATOM_ADD(&SSM.n, n); } LUAI_FUNC TString * @@ -430,7 +427,7 @@ luaS_shrinfo(lua_State *L) { int i; int len = 0; for (i=0;ih[i]; + struct shrmap_slot *s = &SSM.h[i]; getslot(s, &tmp); len += tmp.len; if (tmp.len > total.len) { @@ -441,6 +438,6 @@ luaS_shrinfo(lua_State *L) { lua_pushinteger(L, len); lua_pushinteger(L, total.size); lua_pushinteger(L, total.len); - lua_pushinteger(L, SSM->n); + lua_pushinteger(L, SSM.n); return 4; } From 4f665d2469e5f278835ea388a76f95e8dadc22d1 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Sun, 30 Aug 2015 12:13:23 +0800 Subject: [PATCH 48/97] init global string table, See issue #331 --- 3rd/lua/lua.c | 5 ++++- 3rd/lua/luac.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/3rd/lua/lua.c b/3rd/lua/lua.c index 7a47582c..c6e81a55 100644 --- a/3rd/lua/lua.c +++ b/3rd/lua/lua.c @@ -18,6 +18,7 @@ #include "lauxlib.h" #include "lualib.h" +#include "lstring.h" #if !defined(LUA_PROMPT) @@ -596,7 +597,9 @@ static int pmain (lua_State *L) { int main (int argc, char **argv) { int status, result; - lua_State *L = luaL_newstate(); /* create state */ + lua_State *L; + luaS_initshr(); /* init global short string table */ + L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; diff --git a/3rd/lua/luac.c b/3rd/lua/luac.c index 0ff987b4..86d47518 100644 --- a/3rd/lua/luac.c +++ b/3rd/lua/luac.c @@ -21,6 +21,7 @@ #include "lobject.h" #include "lstate.h" #include "lundump.h" +#include "lstring.h" static void PrintFunction(const Proto* f, int full); #define luaU_print PrintFunction @@ -195,6 +196,7 @@ int main(int argc, char* argv[]) int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); + luaS_initshr(); L=luaL_newstate(); if (L==NULL) fatal("cannot create state: not enough memory"); lua_pushcfunction(L,&pmain); From bad3472124e0dce5ca8ff76691e2bafe18b787ae Mon Sep 17 00:00:00 2001 From: snail Date: Sun, 30 Aug 2015 16:47:34 +0800 Subject: [PATCH 49/97] 'response' not released 'response' not released after src service died, and defined error. --- lualib/skynet.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lualib/skynet.lua b/lualib/skynet.lua index e4f46908..56d62e6c 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -186,10 +186,12 @@ function suspend(co, result, command, param, size) error(debug.traceback(co)) end local f = param - local function response(ok, ...) + local response + response = function(ok, ...) if ok == "TEST" then if dead_service[co_address] then release_watching(co_address) + unresponse[response] = nil f = false return false else @@ -224,7 +226,7 @@ function suspend(co, result, command, param, size) return ret end watching_service[co_address] = watching_service[co_address] + 1 - session_response[co] = response + session_response[co] = true unresponse[response] = true return suspend(co, coroutine.resume(co, response)) elseif command == "EXIT" then From 7f9c3c8c9a99b87adff4f3d732b2b9bf905b4d0b Mon Sep 17 00:00:00 2001 From: snail Date: Sun, 30 Aug 2015 18:17:41 +0800 Subject: [PATCH 50/97] local function is better local function is the same as " local a; a = function" --- lualib/skynet.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lualib/skynet.lua b/lualib/skynet.lua index 56d62e6c..554d8ff8 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -186,8 +186,7 @@ function suspend(co, result, command, param, size) error(debug.traceback(co)) end local f = param - local response - response = function(ok, ...) + local function response(ok, ...) if ok == "TEST" then if dead_service[co_address] then release_watching(co_address) From 7797de85b457cf6f724748804a3801f6b5c5a68a Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 31 Aug 2015 16:36:57 +0800 Subject: [PATCH 51/97] bugfix: See PR #332 --- service/sharedatad.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/service/sharedatad.lua b/service/sharedatad.lua index a7e8d427..363f59ef 100644 --- a/service/sharedatad.lua +++ b/service/sharedatad.lua @@ -123,6 +123,7 @@ function CMD.monitor(name, obj) if n > pool_count[name].threshold then n = n - check_watch(v.watch) pool_count[name].threshold = n * 2 + pool_count[name].n = n end table.insert(v.watch, skynet.response()) From 6c33f7bc44d0eafe743e5490af3b1e5d86727c45 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 4 Sep 2015 12:14:09 +0800 Subject: [PATCH 52/97] see pr #332 --- service/sharedatad.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/service/sharedatad.lua b/service/sharedatad.lua index 363f59ef..d76fd115 100644 --- a/service/sharedatad.lua +++ b/service/sharedatad.lua @@ -118,13 +118,12 @@ function CMD.monitor(name, obj) return v.obj end - local n = pool_count[name].n - pool_count[name].n = n + 1 + local n = pool_count[name].n + 1 if n > pool_count[name].threshold then n = n - check_watch(v.watch) pool_count[name].threshold = n * 2 - pool_count[name].n = n end + pool_count[name].n = n table.insert(v.watch, skynet.response()) From 846d55eaef0d8e64338ecf323a51718611186d6f Mon Sep 17 00:00:00 2001 From: sanikoyes Date: Mon, 14 Sep 2015 18:03:04 +0800 Subject: [PATCH 53/97] add missing luaS_exitshr call --- 3rd/lua/lua.c | 1 + 1 file changed, 1 insertion(+) diff --git a/3rd/lua/lua.c b/3rd/lua/lua.c index c6e81a55..825d7c21 100644 --- a/3rd/lua/lua.c +++ b/3rd/lua/lua.c @@ -611,6 +611,7 @@ int main (int argc, char **argv) { result = lua_toboolean(L, -1); /* get result */ report(L, status); lua_close(L); + luaS_exitshr(); return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } From b8f419eb691f64bd3c33ff9836549d245d081fb7 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 15 Sep 2015 14:52:30 +0800 Subject: [PATCH 54/97] more error message for socket, and close listen socket when reach limit of open files. See Issue #339 --- lualib/snax/gateserver.lua | 19 +++++++++++++------ lualib/socket.lua | 13 ++++++++----- skynet-src/skynet_socket.c | 8 ++++++-- skynet-src/socket_server.c | 37 +++++++++++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/lualib/snax/gateserver.lua b/lualib/snax/gateserver.lua index dfce2fa9..68f77b58 100644 --- a/lualib/snax/gateserver.lua +++ b/lualib/snax/gateserver.lua @@ -101,17 +101,24 @@ function gateserver.start(handler) end function MSG.close(fd) - if handler.disconnect then - handler.disconnect(fd) + if fd ~= socket then + if handler.disconnect then + handler.disconnect(fd) + end + close_fd(fd) end - close_fd(fd) end function MSG.error(fd, msg) - if handler.error then - handler.error(fd, msg) + if fd == socket then + socketdriver.close(fd) + skynet.error(msg) + else + if handler.error then + handler.error(fd, msg) + end + close_fd(fd) end - close_fd(fd) end function MSG.warning(fd, size) diff --git a/lualib/socket.lua b/lualib/socket.lua index c5fe7858..7f1d603b 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -106,16 +106,17 @@ socket_message[4] = function(id, newid, addr) end -- SKYNET_SOCKET_TYPE_ERROR = 5 -socket_message[5] = function(id) +socket_message[5] = function(id, _, err) local s = socket_pool[id] if s == nil then - skynet.error("socket: error on unknown", id) + skynet.error("socket: error on unknown", id, err) return end - if s.connected then - skynet.error("socket: error on", id) + if s.connected or s.connecting then + skynet.error("socket: error on", id, err) end s.connected = false + driver.close(id) wakeup(s) end @@ -170,6 +171,7 @@ local function connect(id, func) id = id, buffer = newbuffer, connected = false, + connecting = true, read_required = false, co = false, callback = func, @@ -177,6 +179,7 @@ local function connect(id, func) } socket_pool[id] = s suspend(s) + s.connecting = nil if s.connected then return id else @@ -221,7 +224,7 @@ function socket.close(id) return end if s.connected then - driver.close(s.id) + driver.close(id) -- notice: call socket.close in __gc should be carefully, -- because skynet.wait never return in __gc, so driver.clear may not be called if s.co then diff --git a/skynet-src/skynet_socket.c b/skynet-src/skynet_socket.c index 9301419f..f6f8ec56 100644 --- a/skynet-src/skynet_socket.c +++ b/skynet-src/skynet_socket.c @@ -36,7 +36,11 @@ forward_message(int type, bool padding, struct socket_message * result) { size_t sz = sizeof(*sm); if (padding) { if (result->data) { - sz += strlen(result->data); + size_t msg_sz = strlen(result->data); + if (msg_sz > 128) { + msg_sz = 128; + } + sz += msg_sz; } else { result->data = ""; } @@ -86,7 +90,7 @@ skynet_socket_poll() { forward_message(SKYNET_SOCKET_TYPE_CONNECT, true, &result); break; case SOCKET_ERROR: - forward_message(SKYNET_SOCKET_TYPE_ERROR, false, &result); + forward_message(SKYNET_SOCKET_TYPE_ERROR, true, &result); break; case SOCKET_ACCEPT: forward_message(SKYNET_SOCKET_TYPE_ACCEPT, true, &result); diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index b2454d2e..7724a3c5 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -408,6 +408,7 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock status = getaddrinfo( request->host, port, &ai_hints, &ai_list ); if ( status != 0 ) { + result->data = (void *)gai_strerror(status); goto _failed; } int sock= -1; @@ -428,12 +429,14 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock } if (sock < 0) { + result->data = strerror(errno); goto _failed; } ns = new_fd(ss, id, sock, PROTOCOL_TCP, request->opaque, true); if (ns == NULL) { close(sock); + result->data = "reach skynet socket number limit"; goto _failed; } @@ -762,7 +765,7 @@ _failed: result->opaque = request->opaque; result->id = id; result->ud = 0; - result->data = NULL; + result->data = "reach skynet socket number limit"; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; @@ -803,7 +806,7 @@ bind_socket(struct socket_server *ss, struct request_bind *request, struct socke result->ud = 0; struct socket *s = new_fd(ss, id, request->fd, PROTOCOL_TCP, request->opaque, true); if (s == NULL) { - result->data = NULL; + result->data = "reach skynet socket number limit"; return SOCKET_ERROR; } sp_nonblocking(request->fd); @@ -821,11 +824,13 @@ start_socket(struct socket_server *ss, struct request_start *request, struct soc result->data = NULL; struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { + result->data = "invalid socket"; return SOCKET_ERROR; } if (s->type == SOCKET_TYPE_PACCEPT || s->type == SOCKET_TYPE_PLISTEN) { if (sp_add(ss->event_fd, s->fd, s)) { s->type = SOCKET_TYPE_INVALID; + result->data = strerror(errno); return SOCKET_ERROR; } s->type = (s->type == SOCKET_TYPE_PACCEPT) ? SOCKET_TYPE_CONNECTED : SOCKET_TYPE_LISTEN; @@ -913,7 +918,7 @@ set_udp_address(struct socket_server *ss, struct request_setudp *request, struct result->opaque = s->opaque; result->id = s->id; result->ud = 0; - result->data = NULL; + result->data = "protocol mismatch"; return SOCKET_ERROR; } @@ -995,6 +1000,7 @@ forward_message_tcp(struct socket_server *ss, struct socket *s, struct socket_me default: // close when error force_close(ss, s, result); + result->data = strerror(errno); return SOCKET_ERROR; } return -1; @@ -1055,6 +1061,7 @@ forward_message_udp(struct socket_server *ss, struct socket *s, struct socket_me default: // close when error force_close(ss, s, result); + result->data = strerror(errno); return SOCKET_ERROR; } return -1; @@ -1088,6 +1095,7 @@ report_connect(struct socket_server *ss, struct socket *s, struct socket_message int code = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &error, &len); if (code < 0 || error) { force_close(ss,s, result); + result->data = strerror(errno); return SOCKET_ERROR; } else { s->type = SOCKET_TYPE_CONNECTED; @@ -1111,14 +1119,22 @@ report_connect(struct socket_server *ss, struct socket *s, struct socket_message } } -// return 0 when failed +// return 0 when failed, or -1 when file limit static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { - return 0; + if (errno == EMFILE || errno == ENFILE) { + result->opaque = s->opaque; + result->id = s->id; + result->ud = 0; + result->data = strerror(errno); + return -1; + } else { + return 0; + } } int id = reserve_id(ss); if (id < 0) { @@ -1203,11 +1219,16 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int switch (s->type) { case SOCKET_TYPE_CONNECTING: return report_connect(ss, s, result); - case SOCKET_TYPE_LISTEN: - if (report_accept(ss, s, result)) { + case SOCKET_TYPE_LISTEN: { + int ok = report_accept(ss, s, result); + if (ok > 0) { return SOCKET_ACCEPT; - } + } if (ok < 0 ) { + return SOCKET_ERROR; + } + // when ok == 0, retry break; + } case SOCKET_TYPE_INVALID: fprintf(stderr, "socket-server: invalid socket\n"); break; From 00dbf6e9969e7f6ea498cffd3740d991847db710 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 18 Sep 2015 14:10:12 +0800 Subject: [PATCH 55/97] DH key exchange can't be 0 , avoid attack --- lualib-src/lua-crypt.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lualib-src/lua-crypt.c b/lualib-src/lua-crypt.c index 0284c48b..2cb11f40 100644 --- a/lualib-src/lua-crypt.c +++ b/lualib-src/lua-crypt.c @@ -338,8 +338,13 @@ static int lrandomkey(lua_State *L) { char tmp[8]; int i; + char x = 0; for (i=0;i<8;i++) { tmp[i] = random() & 0xff; + x ^= tmp[i]; + } + if (x==0) { + tmp[0] |= 1; // avoid 0 } lua_pushlstring(L, tmp, 8); return 1; @@ -718,8 +723,13 @@ static int ldhsecret(lua_State *L) { uint32_t x[2], y[2]; read64(L, x, y); - uint64_t r = powmodp((uint64_t)x[0] | (uint64_t)x[1]<<32, - (uint64_t)y[0] | (uint64_t)y[1]<<32); + uint64_t xx = (uint64_t)x[0] | (uint64_t)x[1]<<32; + uint64_t yy = (uint64_t)y[0] | (uint64_t)y[1]<<32; + if (xx == 0) + xx = 1; + if (yy == 0) + yy = 1; + uint64_t r = powmodp(xx, yy); push64(L, r); @@ -739,7 +749,11 @@ ldhexchange(lua_State *L) { xx[0] = x[0] | x[1]<<8 | x[2]<<16 | x[3]<<24; xx[1] = x[4] | x[5]<<8 | x[6]<<16 | x[7]<<24; - uint64_t r = powmodp(5, (uint64_t)xx[0] | (uint64_t)xx[1]<<32); + uint64_t x64 = (uint64_t)xx[0] | (uint64_t)xx[1]<<32; + if (x64 == 0) + x64 = 1; + + uint64_t r = powmodp(5, x64); push64(L, r); return 1; } From 008351573a518ab92aea5431363e9d45414ec26a Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Fri, 18 Sep 2015 14:13:16 +0800 Subject: [PATCH 56/97] raise error when DH param is 0 --- lualib-src/lua-crypt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lualib-src/lua-crypt.c b/lualib-src/lua-crypt.c index 2cb11f40..405679a9 100644 --- a/lualib-src/lua-crypt.c +++ b/lualib-src/lua-crypt.c @@ -725,10 +725,8 @@ ldhsecret(lua_State *L) { read64(L, x, y); uint64_t xx = (uint64_t)x[0] | (uint64_t)x[1]<<32; uint64_t yy = (uint64_t)y[0] | (uint64_t)y[1]<<32; - if (xx == 0) - xx = 1; - if (yy == 0) - yy = 1; + if (xx == 0 || yy == 0) + return luaL_error(L, "Can't be 0"); uint64_t r = powmodp(xx, yy); push64(L, r); @@ -751,7 +749,7 @@ ldhexchange(lua_State *L) { uint64_t x64 = (uint64_t)xx[0] | (uint64_t)xx[1]<<32; if (x64 == 0) - x64 = 1; + return luaL_error(L, "Can't be 0"); uint64_t r = powmodp(5, x64); push64(L, r); From 752a501f681a4a692971a49ebd2d4cc389ddbd75 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 21 Sep 2015 10:40:09 +0800 Subject: [PATCH 57/97] bugfix: remove DONTCOPY tag from type --- service-src/service_harbor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service-src/service_harbor.c b/service-src/service_harbor.c index ed05190b..70abe82b 100644 --- a/service-src/service_harbor.c +++ b/service-src/service_harbor.c @@ -313,10 +313,10 @@ forward_local_messsage(struct harbor *h, void *msg, int sz) { message_to_header((const uint32_t *)cookie, &header); uint32_t destination = header.destination; - int type = (destination >> HANDLE_REMOTE_SHIFT) | PTYPE_TAG_DONTCOPY; + int type = destination >> HANDLE_REMOTE_SHIFT; destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT); - if (skynet_send(h->ctx, header.source, destination, type, (int)header.session, (void *)msg, sz-HEADER_COOKIE_LENGTH) < 0) { + if (skynet_send(h->ctx, header.source, destination, type | PTYPE_TAG_DONTCOPY , (int)header.session, (void *)msg, sz-HEADER_COOKIE_LENGTH) < 0) { if (type != PTYPE_ERROR) { // don't need report error when type is error skynet_send(h->ctx, destination, header.source , PTYPE_ERROR, (int)header.session, NULL, 0); From 325452a242657ac0c87a71a19e625d8ba16bd3b3 Mon Sep 17 00:00:00 2001 From: bingo Date: Mon, 21 Sep 2015 11:21:36 +0800 Subject: [PATCH 58/97] Signed-off-by: bingo --- lualib/snax/gateserver.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lualib/snax/gateserver.lua b/lualib/snax/gateserver.lua index 68f77b58..bf62e2ce 100644 --- a/lualib/snax/gateserver.lua +++ b/lualib/snax/gateserver.lua @@ -48,7 +48,6 @@ function gateserver.start(handler) function CMD.close() assert(socket) socketdriver.close(socket) - socket = nil end local MSG = {} @@ -106,6 +105,8 @@ function gateserver.start(handler) handler.disconnect(fd) end close_fd(fd) + else + socket = nil end end From 63942496fdfa7c3b98364e86fab067165da4e270 Mon Sep 17 00:00:00 2001 From: great90 <897346026@qq.com> Date: Mon, 21 Sep 2015 23:50:18 +0800 Subject: [PATCH 59/97] =?UTF-8?q?=E4=BB=8Echeck=5Fwsz=E5=8F=91=E9=80=81?= =?UTF-8?q?=E7=9A=84SKYNET=5FSOCKET=5FTYPE=5FWARNING=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E4=BC=9Aassert=E5=A4=B1=E8=B4=A5=EF=BC=8C=E5=AF=BC=E8=87=B4cor?= =?UTF-8?q?edump?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service-src/service_gate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/service-src/service_gate.c b/service-src/service_gate.c index ec44c722..d59b4050 100644 --- a/service-src/service_gate.c +++ b/service-src/service_gate.c @@ -295,7 +295,6 @@ _cb(struct skynet_context * ctx, void * ud, int type, int session, uint32_t sour } } case PTYPE_SOCKET: - assert(source == 0); // recv socket message from skynet_socket dispatch_socket_message(g, msg, (int)(sz-sizeof(struct skynet_socket_message))); break; From cb9feb34bd263d3c0390c2ca2c55c887026ba945 Mon Sep 17 00:00:00 2001 From: zhengfangxin Date: Sat, 26 Sep 2015 21:03:38 +0800 Subject: [PATCH 60/97] delete two no need call clear_closed_event --- skynet-src/socket_server.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index 7724a3c5..4963dd37 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -1176,6 +1176,7 @@ clear_closed_event(struct socket_server *ss, struct socket_message * result, int if (s) { if (s->type == SOCKET_TYPE_INVALID && s->id == id) { e->s = NULL; + break; } } } @@ -1245,21 +1246,19 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int return SOCKET_UDP; } } - if (e->write) { + if (e->write && type != SOCKET_CLOSE && type != SOCKET_ERROR) { // Try to dispatch write message next step if write flag set. e->read = false; --ss->event_index; } if (type == -1) - break; - clear_closed_event(ss, result, type); + break; return type; } if (e->write) { int type = send_buffer(ss, s, result); if (type == -1) break; - clear_closed_event(ss, result, type); return type; } break; From 97ff6afc8438a22a630bd0acb102555b21760c1d Mon Sep 17 00:00:00 2001 From: xjdrew Date: Tue, 29 Sep 2015 17:29:33 +0800 Subject: [PATCH 61/97] removte unused code --- service-src/service_gate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/service-src/service_gate.c b/service-src/service_gate.c index d59b4050..29eab2ea 100644 --- a/service-src/service_gate.c +++ b/service-src/service_gate.c @@ -335,13 +335,12 @@ gate_init(struct gate *g , struct skynet_context * ctx, char * parm) { if (parm == NULL) return 1; int max = 0; - int buffer = 0; int sz = strlen(parm)+1; char watchdog[sz]; char binding[sz]; int client_tag = 0; char header; - int n = sscanf(parm, "%c %s %s %d %d %d",&header,watchdog, binding,&client_tag , &max,&buffer); + int n = sscanf(parm, "%c %s %s %d %d %d", &header, watchdog, binding, &client_tag, &max); if (n<4) { skynet_error(ctx, "Invalid gate parm %s",parm); return 1; From 97fd5053c9c46fbca4990b353e412d49129f68ae Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 5 Oct 2015 09:56:12 +0800 Subject: [PATCH 62/97] update lpeg to 1.0.0 --- 3rd/lpeg/HISTORY | 8 +- 3rd/lpeg/lpcap.c | 4 +- 3rd/lpeg/lpcap.h | 4 +- 3rd/lpeg/lpcode.c | 22 +-- 3rd/lpeg/lpcode.h | 10 +- 3rd/lpeg/lpeg.html | 27 +-- 3rd/lpeg/lpprint.c | 8 +- 3rd/lpeg/lpprint.h | 3 +- 3rd/lpeg/lptree.c | 446 +++++++++++++++++++++++++-------------------- 3rd/lpeg/lptypes.h | 34 ++-- 3rd/lpeg/lpvm.c | 6 +- 3rd/lpeg/re.html | 8 +- 3rd/lpeg/test.lua | 55 +++++- 13 files changed, 376 insertions(+), 259 deletions(-) diff --git a/3rd/lpeg/HISTORY b/3rd/lpeg/HISTORY index 8ada7743..0c10edd0 100644 --- a/3rd/lpeg/HISTORY +++ b/3rd/lpeg/HISTORY @@ -1,4 +1,10 @@ -HISTORY for LPeg 0.12 +HISTORY for LPeg 1.0 + +* Changes from version 0.12 to 1.0 + --------------------------------- + + group "names" can be any Lua value + + some bugs fixed + + other small improvements * Changes from version 0.11 to 0.12 --------------------------------- diff --git a/3rd/lpeg/lpcap.c b/3rd/lpeg/lpcap.c index b6911cb1..c9085de0 100644 --- a/3rd/lpeg/lpcap.c +++ b/3rd/lpeg/lpcap.c @@ -1,5 +1,5 @@ /* -** $Id: lpcap.c,v 1.5 2014/12/12 16:58:47 roberto Exp $ +** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $ ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) */ @@ -126,7 +126,7 @@ static Capture *findback (CapState *cs, Capture *cap) { continue; /* opening an enclosing capture: skip and get previous */ if (captype(cap) == Cgroup) { getfromktable(cs, cap->idx); /* get group name */ - if (lua_equal(L, -2, -1)) { /* right group? */ + if (lp_equal(L, -2, -1)) { /* right group? */ lua_pop(L, 2); /* remove reference name and group name */ return cap; } diff --git a/3rd/lpeg/lpcap.h b/3rd/lpeg/lpcap.h index c0a0e382..d762fdcf 100644 --- a/3rd/lpeg/lpcap.h +++ b/3rd/lpeg/lpcap.h @@ -1,5 +1,5 @@ /* -** $Id: lpcap.h,v 1.1 2013/03/21 20:25:12 roberto Exp $ +** $Id: lpcap.h,v 1.2 2015/02/27 17:13:17 roberto Exp $ */ #if !defined(lpcap_h) @@ -18,7 +18,7 @@ typedef enum CapKind { typedef struct Capture { const char *s; /* subject position */ - short idx; /* extra info about capture (group name, arg index, etc.) */ + unsigned short idx; /* extra info (group name, arg index, etc.) */ byte kind; /* kind of capture */ byte siz; /* size of full capture + 1 (0 = not a full capture) */ } Capture; diff --git a/3rd/lpeg/lpcode.c b/3rd/lpeg/lpcode.c index 93c0d2aa..fbf44feb 100644 --- a/3rd/lpeg/lpcode.c +++ b/3rd/lpeg/lpcode.c @@ -1,5 +1,5 @@ /* -** $Id: lpcode.c,v 1.21 2014/12/12 17:01:29 roberto Exp $ +** $Id: lpcode.c,v 1.23 2015/06/12 18:36:47 roberto Exp $ ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) */ @@ -431,11 +431,11 @@ typedef struct CompileState { /* -** code generation is recursive; 'opt' indicates that the code is -** being generated under a 'IChoice' operator jumping to its end -** (that is, the match is "optional"). -** 'tt' points to a previous test protecting this code. 'fl' is -** the follow set of the pattern. +** code generation is recursive; 'opt' indicates that the code is being +** generated as the last thing inside an optional pattern (so, if that +** code is optional too, it can reuse the 'IChoice' already in place for +** the outer pattern). 'tt' points to a previous test protecting this +** code (or NOINST). 'fl' is the follow set of the pattern. */ static void codegen (CompileState *compst, TTree *tree, int opt, int tt, const Charset *fl); @@ -638,13 +638,13 @@ static void codebehind (CompileState *compst, TTree *tree) { /* ** Choice; optimizations: -** - when p1 is headfail -** - when first(p1) and first(p2) are disjoint; than +** - when p1 is headfail or +** when first(p1) and first(p2) are disjoint, than ** a character not in first(p1) cannot go to p1, and a character ** in first(p1) cannot go to p2 (at it is not in first(p2)). ** (The optimization is not valid if p1 accepts the empty string, ** as then there is no character at all...) -** - when p2 is empty and opt is true; a IPartialCommit can resuse +** - when p2 is empty and opt is true; a IPartialCommit can reuse ** the Choice already active in the stack. */ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt, @@ -671,7 +671,7 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt, } else { /* == - test(fail(p1)) -> L1; choice L1; ; commit L2; L1: ; L2: */ + test(first(p1)) -> L1; choice L1; ; commit L2; L1: ; L2: */ int pcommit; int test = codetestset(compst, &cs1, e1); int pchoice = addoffsetinst(compst, IChoice); @@ -759,7 +759,7 @@ static void coderep (CompileState *compst, TTree *tree, int opt, /* L1: test (fail(p1)) -> L2;

; jmp L1; L2: */ int jmp; int test = codetestset(compst, &st, 0); - codegen(compst, tree, opt, test, fullset); + codegen(compst, tree, 0, test, fullset); jmp = addoffsetinst(compst, IJmp); jumptohere(compst, test); jumptothere(compst, jmp, test); diff --git a/3rd/lpeg/lpcode.h b/3rd/lpeg/lpcode.h index 72d2bb94..896d3c79 100644 --- a/3rd/lpeg/lpcode.h +++ b/3rd/lpeg/lpcode.h @@ -1,5 +1,5 @@ /* -** $Id: lpcode.h,v 1.6 2013/11/28 14:56:02 roberto Exp $ +** $Id: lpcode.h,v 1.7 2015/06/12 18:24:45 roberto Exp $ */ #if !defined(lpcode_h) @@ -24,7 +24,15 @@ int sizei (const Instruction *i); #define PEnullable 0 #define PEnofail 1 +/* +** nofail(t) implies that 't' cannot fail with any input +*/ #define nofail(t) checkaux(t, PEnofail) + +/* +** (not nullable(t)) implies 't' cannot match without consuming +** something +*/ #define nullable(t) checkaux(t, PEnullable) #define fixedlen(t) fixedlenx(t, 0, 0) diff --git a/3rd/lpeg/lpeg.html b/3rd/lpeg/lpeg.html index 0eb1747f..c0a7f090 100644 --- a/3rd/lpeg/lpeg.html +++ b/3rd/lpeg/lpeg.html @@ -10,7 +10,7 @@ - +

@@ -22,7 +22,7 @@
LPeg
- Parsing Expression Grammars For Lua, version 0.12 + Parsing Expression Grammars For Lua, version 1.0
@@ -195,13 +195,16 @@ Returns a string with the running version of LPeg.

lpeg.setmaxstack (max)

-Sets the maximum size for the backtrack stack used by LPeg to +Sets a limit for the size of the backtrack stack used by LPeg to track calls and choices. +(The default limit is 400.) Most well-written patterns need little backtrack levels and -therefore you seldom need to change this maximum; -but a few useful patterns may need more space. -Before changing this maximum you should try to rewrite your +therefore you seldom need to change this limit; +before changing it you should try to rewrite your pattern to avoid the need for extra space. +Nevertheless, a few useful patterns may overflow. +Also, with recursive grammars, +subjects with deep recursion may also need larger limits.

@@ -682,7 +685,8 @@ argument given in the call to lpeg.match. Creates a back capture. This pattern matches the empty string and produces the values produced by the most recent -group capture named name. +group capture named name +(where name can be any Lua value).

@@ -762,7 +766,8 @@ Creates a group capture. It groups all values returned by patt into a single capture. The group may be anonymous (if no name is given) -or named with the given name. +or named with the given name +(which can be any non-nil Lua value).

@@ -1375,13 +1380,13 @@ and the new term for each repetition.

Download

LPeg -source code.

+source code.

License

-Copyright © 2014 Lua.org, PUC-Rio. +Copyright © 2007-2015 Lua.org, PUC-Rio.

Permission is hereby granted, free of charge, @@ -1419,7 +1424,7 @@ THE SOFTWARE.

-$Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $ +$Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $

diff --git a/3rd/lpeg/lpprint.c b/3rd/lpeg/lpprint.c index 05fa6488..174d1687 100644 --- a/3rd/lpeg/lpprint.c +++ b/3rd/lpeg/lpprint.c @@ -1,5 +1,5 @@ /* -** $Id: lpprint.c,v 1.7 2013/04/12 16:29:49 roberto Exp $ +** $Id: lpprint.c,v 1.9 2015/06/15 16:09:57 roberto Exp $ ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) */ @@ -52,7 +52,7 @@ static void printjmp (const Instruction *op, const Instruction *p) { } -static void printinst (const Instruction *op, const Instruction *p) { +void printinst (const Instruction *op, const Instruction *p) { const char *const names[] = { "any", "char", "set", "testany", "testchar", "testset", @@ -221,10 +221,10 @@ void printtree (TTree *tree, int ident) { void printktable (lua_State *L, int idx) { int n, i; - lua_getfenv(L, idx); + lua_getuservalue(L, idx); if (lua_isnil(L, -1)) /* no ktable? */ return; - n = lua_objlen(L, -1); + n = lua_rawlen(L, -1); printf("["); for (i = 1; i <= n; i++) { printf("%d = ", i); diff --git a/3rd/lpeg/lpprint.h b/3rd/lpeg/lpprint.h index e640f744..63297607 100644 --- a/3rd/lpeg/lpprint.h +++ b/3rd/lpeg/lpprint.h @@ -1,5 +1,5 @@ /* -** $Id: lpprint.h,v 1.1 2013/03/21 20:25:12 roberto Exp $ +** $Id: lpprint.h,v 1.2 2015/06/12 18:18:08 roberto Exp $ */ @@ -18,6 +18,7 @@ void printtree (TTree *tree, int ident); void printktable (lua_State *L, int idx); void printcharset (const byte *st); void printcaplist (Capture *cap, Capture *limit); +void printinst (const Instruction *op, const Instruction *p); #else diff --git a/3rd/lpeg/lptree.c b/3rd/lpeg/lptree.c index 7c5b8200..ac5f5150 100644 --- a/3rd/lpeg/lptree.c +++ b/3rd/lpeg/lptree.c @@ -1,5 +1,5 @@ /* -** $Id: lptree.c,v 1.13 2014/12/12 16:59:10 roberto Exp $ +** $Id: lptree.c,v 1.21 2015/09/28 17:01:25 roberto Exp $ ** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license) */ @@ -126,6 +126,189 @@ static void finalfix (lua_State *L, int postable, TTree *g, TTree *t) { } + +/* +** {=================================================================== +** KTable manipulation +** +** - The ktable of a pattern 'p' can be shared by other patterns that +** contain 'p' and no other constants. Because of this sharing, we +** should not add elements to a 'ktable' unless it was freshly created +** for the new pattern. +** +** - The maximum index in a ktable is USHRT_MAX, because trees and +** patterns use unsigned shorts to store those indices. +** ==================================================================== +*/ + +/* +** Create a new 'ktable' to the pattern at the top of the stack. +*/ +static void newktable (lua_State *L, int n) { + lua_createtable(L, n, 0); /* create a fresh table */ + lua_setuservalue(L, -2); /* set it as 'ktable' for pattern */ +} + + +/* +** Add element 'idx' to 'ktable' of pattern at the top of the stack; +** Return index of new element. +** If new element is nil, does not add it to table (as it would be +** useless) and returns 0, as ktable[0] is always nil. +*/ +static int addtoktable (lua_State *L, int idx) { + if (lua_isnil(L, idx)) /* nil value? */ + return 0; + else { + int n; + lua_getuservalue(L, -1); /* get ktable from pattern */ + n = lua_rawlen(L, -1); + if (n >= USHRT_MAX) + luaL_error(L, "too many Lua values in pattern"); + lua_pushvalue(L, idx); /* element to be added */ + lua_rawseti(L, -2, ++n); + lua_pop(L, 1); /* remove 'ktable' */ + return n; + } +} + + +/* +** Return the number of elements in the ktable at 'idx'. +** In Lua 5.2/5.3, default "environment" for patterns is nil, not +** a table. Treat it as an empty table. In Lua 5.1, assumes that +** the environment has no numeric indices (len == 0) +*/ +static int ktablelen (lua_State *L, int idx) { + if (!lua_istable(L, idx)) return 0; + else return lua_rawlen(L, idx); +} + + +/* +** Concatentate the contents of table 'idx1' into table 'idx2'. +** (Assume that both indices are negative.) +** Return the original length of table 'idx2' (or 0, if no +** element was added, as there is no need to correct any index). +*/ +static int concattable (lua_State *L, int idx1, int idx2) { + int i; + int n1 = ktablelen(L, idx1); + int n2 = ktablelen(L, idx2); + if (n1 + n2 > USHRT_MAX) + luaL_error(L, "too many Lua values in pattern"); + if (n1 == 0) return 0; /* nothing to correct */ + for (i = 1; i <= n1; i++) { + lua_rawgeti(L, idx1, i); + lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */ + } + return n2; +} + + +/* +** When joining 'ktables', constants from one of the subpatterns must +** be renumbered; 'correctkeys' corrects their indices (adding 'n' +** to each of them) +*/ +static void correctkeys (TTree *tree, int n) { + if (n == 0) return; /* no correction? */ + tailcall: + switch (tree->tag) { + case TOpenCall: case TCall: case TRunTime: case TRule: { + if (tree->key > 0) + tree->key += n; + break; + } + case TCapture: { + if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum) + tree->key += n; + break; + } + default: break; + } + switch (numsiblings[tree->tag]) { + case 1: /* correctkeys(sib1(tree), n); */ + tree = sib1(tree); goto tailcall; + case 2: + correctkeys(sib1(tree), n); + tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */ + default: assert(numsiblings[tree->tag] == 0); break; + } +} + + +/* +** Join the ktables from p1 and p2 the ktable for the new pattern at the +** top of the stack, reusing them when possible. +*/ +static void joinktables (lua_State *L, int p1, TTree *t2, int p2) { + int n1, n2; + lua_getuservalue(L, p1); /* get ktables */ + lua_getuservalue(L, p2); + n1 = ktablelen(L, -2); + n2 = ktablelen(L, -1); + if (n1 == 0 && n2 == 0) /* are both tables empty? */ + lua_pop(L, 2); /* nothing to be done; pop tables */ + else if (n2 == 0 || lp_equal(L, -2, -1)) { /* 2nd table empty or equal? */ + lua_pop(L, 1); /* pop 2nd table */ + lua_setuservalue(L, -2); /* set 1st ktable into new pattern */ + } + else if (n1 == 0) { /* first table is empty? */ + lua_setuservalue(L, -3); /* set 2nd table into new pattern */ + lua_pop(L, 1); /* pop 1st table */ + } + else { + lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */ + /* stack: new p; ktable p1; ktable p2; new ktable */ + concattable(L, -3, -1); /* from p1 into new ktable */ + concattable(L, -2, -1); /* from p2 into new ktable */ + lua_setuservalue(L, -4); /* new ktable becomes 'p' environment */ + lua_pop(L, 2); /* pop other ktables */ + correctkeys(t2, n1); /* correction for indices from p2 */ + } +} + + +/* +** copy 'ktable' of element 'idx' to new tree (on top of stack) +*/ +static void copyktable (lua_State *L, int idx) { + lua_getuservalue(L, idx); + lua_setuservalue(L, -2); +} + + +/* +** merge 'ktable' from 'stree' at stack index 'idx' into 'ktable' +** from tree at the top of the stack, and correct corresponding +** tree. +*/ +static void mergektable (lua_State *L, int idx, TTree *stree) { + int n; + lua_getuservalue(L, -1); /* get ktables */ + lua_getuservalue(L, idx); + n = concattable(L, -1, -2); + lua_pop(L, 2); /* remove both ktables */ + correctkeys(stree, n); +} + + +/* +** Create a new 'ktable' to the pattern at the top of the stack, adding +** all elements from pattern 'p' (if not 0) plus element 'idx' to it. +** Return index of new element. +*/ +static int addtonewktable (lua_State *L, int p, int idx) { + newktable(L, 1); + if (p) + mergektable(L, p, NULL); + return addtoktable(L, idx); +} + +/* }====================================================== */ + + /* ** {====================================================== ** Tree generation @@ -155,7 +338,7 @@ static Pattern *getpattern (lua_State *L, int idx) { static int getsize (lua_State *L, int idx) { - return (lua_objlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1; + return (lua_rawlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1; } @@ -168,12 +351,16 @@ static TTree *gettree (lua_State *L, int idx, int *len) { /* -** create a pattern +** create a pattern. Set its uservalue (the 'ktable') equal to its +** metatable. (It could be any empty sequence; the metatable is at +** hand here, so we use it.) */ static TTree *newtree (lua_State *L, int len) { size_t size = (len - 1) * sizeof(TTree) + sizeof(Pattern); Pattern *p = (Pattern *)lua_newuserdata(L, size); luaL_getmetatable(L, PATTERN_T); + lua_pushvalue(L, -1); + lua_setuservalue(L, -3); lua_setmetatable(L, -2); p->code = NULL; p->codesize = 0; return p->tree; @@ -206,35 +393,6 @@ static TTree *seqaux (TTree *tree, TTree *sib, int sibsize) { } -/* -** Add element 'idx' to 'ktable' of pattern at the top of the stack; -** create new 'ktable' if necessary. Return index of new element. -** If new element is nil, does not add it to table (as it would be -** useless) and returns 0, as ktable[0] is always nil. -*/ -static int addtoktable (lua_State *L, int idx) { - if (idx == 0) /* no actual value to insert? */ - return 0; - else { - int n; - lua_getfenv(L, -1); /* get ktable from pattern */ - n = lua_objlen(L, -1); - if (n == 0) { /* is it empty/non-existent? */ - lua_pop(L, 1); /* remove it */ - lua_createtable(L, 1, 0); /* create a fresh table */ - lua_pushvalue(L, -1); /* make a copy */ - lua_setfenv(L, -3); /* set it as 'ktable' for pattern */ - } - if (!lua_isnil(L, idx)) { /* non-nil value? */ - lua_pushvalue(L, idx); /* element to be added */ - lua_rawseti(L, -2, ++n); - } - lua_pop(L, 1); /* remove 'ktable' */ - return n; - } -} - - /* ** Build a sequence of 'n' nodes, each with tag 'tag' and 'u.n' got ** from the array 's' (or 0 if array is NULL). (TSeq is binary, so it @@ -310,7 +468,7 @@ static TTree *getpatt (lua_State *L, int idx, int *len) { case LUA_TFUNCTION: { tree = newtree(L, 2); tree->tag = TRunTime; - tree->key = addtoktable(L, idx); + tree->key = addtonewktable(L, 0, idx); sib1(tree)->tag = TTrue; break; } @@ -325,123 +483,6 @@ static TTree *getpatt (lua_State *L, int idx, int *len) { } -/* -** Return the number of elements in the ktable of pattern at 'idx'. -** In Lua 5.2, default "environment" for patterns is nil, not -** a table. Treat it as an empty table. In Lua 5.1, assumes that -** the environment has no numeric indices (len == 0) -*/ -static int ktablelen (lua_State *L, int idx) { - if (!lua_istable(L, idx)) return 0; - else return lua_objlen(L, idx); -} - - -/* -** Concatentate the contents of table 'idx1' into table 'idx2'. -** (Assume that both indices are negative.) -** Return the original length of table 'idx2' -*/ -static int concattable (lua_State *L, int idx1, int idx2) { - int i; - int n1 = ktablelen(L, idx1); - int n2 = ktablelen(L, idx2); - if (n1 == 0) return 0; /* nothing to correct */ - for (i = 1; i <= n1; i++) { - lua_rawgeti(L, idx1, i); - lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */ - } - return n2; -} - - -/* -** Make a merge of ktables from p1 and p2 the ktable for the new -** pattern at the top of the stack. -*/ -static int joinktables (lua_State *L, int p1, int p2) { - int n1, n2; - lua_getfenv(L, p1); /* get ktables */ - lua_getfenv(L, p2); - n1 = ktablelen(L, -2); - n2 = ktablelen(L, -1); - if (n1 == 0 && n2 == 0) { /* are both tables empty? */ - lua_pop(L, 2); /* nothing to be done; pop tables */ - return 0; /* nothing to correct */ - } - if (n2 == 0 || lua_equal(L, -2, -1)) { /* second table is empty or equal? */ - lua_pop(L, 1); /* pop 2nd table */ - lua_setfenv(L, -2); /* set 1st ktable into new pattern */ - return 0; /* nothing to correct */ - } - if (n1 == 0) { /* first table is empty? */ - lua_setfenv(L, -3); /* set 2nd table into new pattern */ - lua_pop(L, 1); /* pop 1st table */ - return 0; /* nothing to correct */ - } - else { - lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */ - /* stack: new p; ktable p1; ktable p2; new ktable */ - concattable(L, -3, -1); /* from p1 into new ktable */ - concattable(L, -2, -1); /* from p2 into new ktable */ - lua_setfenv(L, -4); /* new ktable becomes p env */ - lua_pop(L, 2); /* pop other ktables */ - return n1; /* correction for indices from p2 */ - } -} - - -static void correctkeys (TTree *tree, int n) { - if (n == 0) return; /* no correction? */ - tailcall: - switch (tree->tag) { - case TOpenCall: case TCall: case TRunTime: case TRule: { - if (tree->key > 0) - tree->key += n; - break; - } - case TCapture: { - if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum) - tree->key += n; - break; - } - default: break; - } - switch (numsiblings[tree->tag]) { - case 1: /* correctkeys(sib1(tree), n); */ - tree = sib1(tree); goto tailcall; - case 2: - correctkeys(sib1(tree), n); - tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */ - default: assert(numsiblings[tree->tag] == 0); break; - } -} - - -/* -** copy 'ktable' of element 'idx' to new tree (on top of stack) -*/ -static void copyktable (lua_State *L, int idx) { - lua_getfenv(L, idx); - lua_setfenv(L, -2); -} - - -/* -** merge 'ktable' from rule at stack index 'idx' into 'ktable' -** from tree at the top of the stack, and correct corresponding -** tree. -*/ -static void mergektable (lua_State *L, int idx, TTree *rule) { - int n; - lua_getfenv(L, -1); /* get ktables */ - lua_getfenv(L, idx); - n = concattable(L, -1, -2); - lua_pop(L, 2); /* remove both ktables */ - correctkeys(rule, n); -} - - /* ** create a new tree, whith a new root and one sibling. ** Sibling must be on the Lua stack, at index 1. @@ -470,7 +511,7 @@ static TTree *newroot2sib (lua_State *L, int tag) { tree->u.ps = 1 + s1; memcpy(sib1(tree), tree1, s1 * sizeof(TTree)); memcpy(sib2(tree), tree2, s2 * sizeof(TTree)); - correctkeys(sib2(tree), joinktables(L, 1, 2)); + joinktables(L, 1, sib2(tree), 2); return tree; } @@ -599,7 +640,7 @@ static int lp_sub (lua_State *L) { sib1(tree)->tag = TNot; /* ...not... */ memcpy(sib1(sib1(tree)), t2, s2 * sizeof(TTree)); /* ...t2 */ memcpy(sib2(tree), t1, s1 * sizeof(TTree)); /* ... and t1 */ - correctkeys(sib1(tree), joinktables(L, 1, 2)); + joinktables(L, 1, sib1(tree), 2); } return 1; } @@ -640,7 +681,7 @@ static int lp_behind (lua_State *L) { TTree *tree; TTree *tree1 = getpatt(L, 1, NULL); int n = fixedlen(tree1); - luaL_argcheck(L, n > 0, 1, "pattern may not have fixed length"); + luaL_argcheck(L, n >= 0, 1, "pattern may not have fixed length"); luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures"); luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind"); tree = newroot1sib(L, TBehind); @@ -655,7 +696,7 @@ static int lp_behind (lua_State *L) { static int lp_V (lua_State *L) { TTree *tree = newleaf(L, TOpenCall); luaL_argcheck(L, !lua_isnoneornil(L, 1), 1, "non-nil value expected"); - tree->key = addtoktable(L, 1); + tree->key = addtonewktable(L, 0, 1); return 1; } @@ -668,7 +709,7 @@ static int lp_V (lua_State *L) { static int capture_aux (lua_State *L, int cap, int labelidx) { TTree *tree = newroot1sib(L, TCapture); tree->cap = cap; - tree->key = addtoktable(L, labelidx); + tree->key = (labelidx == 0) ? 0 : addtonewktable(L, 1, labelidx); return 1; } @@ -676,10 +717,9 @@ static int capture_aux (lua_State *L, int cap, int labelidx) { /* ** Fill a tree with an empty capture, using an empty (TTrue) sibling. */ -static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) { +static TTree *auxemptycap (TTree *tree, int cap) { tree->tag = TCapture; tree->cap = cap; - tree->key = addtoktable(L, idx); sib1(tree)->tag = TTrue; return tree; } @@ -688,8 +728,18 @@ static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) { /* ** Create a tree for an empty capture */ -static TTree *newemptycap (lua_State *L, int cap, int idx) { - return auxemptycap(L, newtree(L, 2), cap, idx); +static TTree *newemptycap (lua_State *L, int cap) { + return auxemptycap(newtree(L, 2), cap); +} + + +/* +** Create a tree for an empty capture with an associated Lua value +*/ +static TTree *newemptycapkey (lua_State *L, int cap, int idx) { + TTree *tree = auxemptycap(newtree(L, 2), cap); + tree->key = addtonewktable(L, 0, idx); + return tree; } @@ -728,10 +778,8 @@ static int lp_tablecapture (lua_State *L) { static int lp_groupcapture (lua_State *L) { if (lua_isnoneornil(L, 2)) return capture_aux(L, Cgroup, 0); - else { - luaL_checkstring(L, 2); + else return capture_aux(L, Cgroup, 2); - } } @@ -747,14 +795,14 @@ static int lp_simplecapture (lua_State *L) { static int lp_poscapture (lua_State *L) { - newemptycap(L, Cposition, 0); + newemptycap(L, Cposition); return 1; } static int lp_argcapture (lua_State *L) { int n = (int)luaL_checkinteger(L, 1); - TTree *tree = newemptycap(L, Carg, 0); + TTree *tree = newemptycap(L, Carg); tree->key = n; luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index"); return 1; @@ -762,8 +810,8 @@ static int lp_argcapture (lua_State *L) { static int lp_backref (lua_State *L) { - luaL_checkstring(L, 1); - newemptycap(L, Cbackref, 1); + luaL_checkany(L, 1); + newemptycapkey(L, Cbackref, 1); return 1; } @@ -777,9 +825,10 @@ static int lp_constcapture (lua_State *L) { if (n == 0) /* no values? */ newleaf(L, TTrue); /* no capture */ else if (n == 1) - newemptycap(L, Cconst, 1); /* single constant capture */ + newemptycapkey(L, Cconst, 1); /* single constant capture */ else { /* create a group capture with all values */ TTree *tree = newtree(L, 1 + 3 * (n - 1) + 2); + newktable(L, n); /* create a 'ktable' for new tree */ tree->tag = TCapture; tree->cap = Cgroup; tree->key = 0; @@ -787,10 +836,12 @@ static int lp_constcapture (lua_State *L) { for (i = 1; i <= n - 1; i++) { tree->tag = TSeq; tree->u.ps = 3; /* skip TCapture and its sibling */ - auxemptycap(L, sib1(tree), Cconst, i); + auxemptycap(sib1(tree), Cconst); + sib1(tree)->key = addtoktable(L, i); tree = sib2(tree); } - auxemptycap(L, tree, Cconst, i); + auxemptycap(tree, Cconst); + tree->key = addtoktable(L, i); } return 1; } @@ -800,7 +851,7 @@ static int lp_matchtime (lua_State *L) { TTree *tree; luaL_checktype(L, 2, LUA_TFUNCTION); tree = newroot1sib(L, TRunTime); - tree->key = addtoktable(L, 2); + tree->key = addtonewktable(L, 1, 2); return 1; } @@ -857,7 +908,7 @@ static int collectrules (lua_State *L, int arg, int *totalsize) { lua_pushnil(L); /* prepare to traverse grammar table */ while (lua_next(L, arg) != 0) { if (lua_tonumber(L, -2) == 1 || - lua_equal(L, -2, postab + 1)) { /* initial rule? */ + lp_equal(L, -2, postab + 1)) { /* initial rule? */ lua_pop(L, 1); /* remove value (keep key for lua_next) */ continue; } @@ -934,36 +985,40 @@ static int verifyerror (lua_State *L, int *passed, int npassed) { /* ** Check whether a rule can be left recursive; raise an error in that -** case; otherwise return 1 iff pattern is nullable. Assume ktable at -** the top of the stack. +** case; otherwise return 1 iff pattern is nullable. +** The return value is used to check sequences, where the second pattern +** is only relevant if the first is nullable. +** Parameter 'nb' works as an accumulator, to allow tail calls in +** choices. ('nb' true makes function returns true.) +** Assume ktable at the top of the stack. */ static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed, - int nullable) { + int nb) { tailcall: switch (tree->tag) { case TChar: case TSet: case TAny: case TFalse: - return nullable; /* cannot pass from here */ + return nb; /* cannot pass from here */ case TTrue: case TBehind: /* look-behind cannot have calls */ return 1; case TNot: case TAnd: case TRep: /* return verifyrule(L, sib1(tree), passed, npassed, 1); */ - tree = sib1(tree); nullable = 1; goto tailcall; + tree = sib1(tree); nb = 1; goto tailcall; case TCapture: case TRunTime: - /* return verifyrule(L, sib1(tree), passed, npassed); */ + /* return verifyrule(L, sib1(tree), passed, npassed, nb); */ tree = sib1(tree); goto tailcall; case TCall: - /* return verifyrule(L, sib2(tree), passed, npassed); */ + /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ tree = sib2(tree); goto tailcall; - case TSeq: /* only check 2nd child if first is nullable */ + case TSeq: /* only check 2nd child if first is nb */ if (!verifyrule(L, sib1(tree), passed, npassed, 0)) - return nullable; - /* else return verifyrule(L, sib2(tree), passed, npassed); */ + return nb; + /* else return verifyrule(L, sib2(tree), passed, npassed, nb); */ tree = sib2(tree); goto tailcall; case TChoice: /* must check both children */ - nullable = verifyrule(L, sib1(tree), passed, npassed, nullable); - /* return verifyrule(L, sib2(tree), passed, npassed, nullable); */ + nb = verifyrule(L, sib1(tree), passed, npassed, nb); + /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ tree = sib2(tree); goto tailcall; case TRule: if (npassed >= MAXRULES) @@ -1006,7 +1061,7 @@ static void verifygrammar (lua_State *L, TTree *grammar) { */ static void initialrulename (lua_State *L, TTree *grammar, int frule) { if (sib1(grammar)->key == 0) { /* initial rule is not referenced? */ - int n = lua_objlen(L, -1) + 1; /* index for name */ + int n = lua_rawlen(L, -1) + 1; /* index for name */ lua_pushvalue(L, frule); /* rule's name */ lua_rawseti(L, -2, n); /* ktable was on the top of the stack */ sib1(grammar)->key = n; @@ -1022,9 +1077,9 @@ static TTree *newgrammar (lua_State *L, int arg) { luaL_argcheck(L, n <= MAXRULES, arg, "grammar has too many rules"); g->tag = TGrammar; g->u.n = n; lua_newtable(L); /* create 'ktable' */ - lua_setfenv(L, -2); + lua_setuservalue(L, -2); buildgrammar(L, g, frule, n); - lua_getfenv(L, -1); /* get 'ktable' for new tree */ + lua_getuservalue(L, -1); /* get 'ktable' for new tree */ finalfix(L, frule - 1, g, sib1(g)); initialrulename(L, g, frule); verifygrammar(L, g); @@ -1038,7 +1093,7 @@ static TTree *newgrammar (lua_State *L, int arg) { static Instruction *prepcompile (lua_State *L, Pattern *p, int idx) { - lua_getfenv(L, idx); /* push 'ktable' (may be used by 'finalfix') */ + lua_getuservalue(L, idx); /* push 'ktable' (may be used by 'finalfix') */ finalfix(L, 0, NULL, p->tree); lua_pop(L, 1); /* remove 'ktable' */ return compile(L, p); @@ -1049,7 +1104,7 @@ static int lp_printtree (lua_State *L) { TTree *tree = getpatt(L, 1, NULL); int c = lua_toboolean(L, 2); if (c) { - lua_getfenv(L, 1); /* push 'ktable' (may be used by 'finalfix') */ + lua_getuservalue(L, 1); /* push 'ktable' (may be used by 'finalfix') */ finalfix(L, 0, NULL, tree); lua_pop(L, 1); /* remove 'ktable' */ } @@ -1102,7 +1157,7 @@ static int lp_match (lua_State *L) { int ptop = lua_gettop(L); lua_pushnil(L); /* initialize subscache */ lua_pushlightuserdata(L, capture); /* initialize caplistidx */ - lua_getfenv(L, 1); /* initialize penvidx */ + lua_getuservalue(L, 1); /* initialize penvidx */ r = match(L, s, s + i, s + l, code, capture, ptop); if (r == NULL) { lua_pushnil(L); @@ -1119,8 +1174,12 @@ static int lp_match (lua_State *L) { ** ======================================================= */ +/* maximum limit for stack size */ +#define MAXLIM (INT_MAX / 100) + static int lp_setmax (lua_State *L) { - luaL_optinteger(L, 1, -1); + lua_Integer lim = luaL_checkinteger(L, 1); + luaL_argcheck(L, 0 < lim && lim <= MAXLIM, 1, "out of range"); lua_settop(L, 1); lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); return 0; @@ -1144,8 +1203,7 @@ static int lp_type (lua_State *L) { int lp_gc (lua_State *L) { Pattern *p = getpattern(L, 1); - if (p->codesize > 0) - realloccode(L, p, 0); + realloccode(L, p, 0); /* delete code block */ return 0; } @@ -1228,8 +1286,8 @@ int luaopen_lpeg (lua_State *L) { luaL_newmetatable(L, PATTERN_T); lua_pushnumber(L, MAXBACK); /* initialize maximum backtracking */ lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); - luaL_register(L, NULL, metareg); - luaL_register(L, "lpeg", pattreg); + luaL_setfuncs(L, metareg, 0); + luaL_newlib(L, pattreg); lua_pushvalue(L, -1); lua_setfield(L, -3, "__index"); return 1; diff --git a/3rd/lpeg/lptypes.h b/3rd/lpeg/lptypes.h index b85c0c97..5eb7987b 100644 --- a/3rd/lpeg/lptypes.h +++ b/3rd/lpeg/lptypes.h @@ -1,7 +1,7 @@ /* -** $Id: lptypes.h,v 1.10 2014/12/12 17:11:35 roberto Exp $ +** $Id: lptypes.h,v 1.14 2015/09/28 17:17:41 roberto Exp $ ** LPeg - PEG pattern matching for Lua -** Copyright 2007-2014, Lua.org & PUC-Rio (see 'lpeg.html' for license) +** Copyright 2007-2015, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** written by Roberto Ierusalimschy */ @@ -19,7 +19,7 @@ #include "lua.h" -#define VERSION "0.12.1" +#define VERSION "1.0.0" #define PATTERN_T "lpeg-pattern" @@ -27,31 +27,31 @@ /* -** compatibility with Lua 5.2 +** compatibility with Lua 5.1 */ -#if (LUA_VERSION_NUM >= 502) +#if (LUA_VERSION_NUM == 501) -#undef lua_equal -#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lp_equal lua_equal -#undef lua_getfenv -#define lua_getfenv lua_getuservalue -#undef lua_setfenv -#define lua_setfenv lua_setuservalue +#define lua_getuservalue lua_getfenv +#define lua_setuservalue lua_setfenv -#undef lua_objlen -#define lua_objlen lua_rawlen +#define lua_rawlen lua_objlen -#undef luaL_register -#define luaL_register(L,n,f) \ - { if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); } +#define luaL_setfuncs(L,f,n) luaL_register(L,NULL,f) +#define luaL_newlib(L,f) luaL_register(L,"lpeg",f) #endif +#if !defined(lp_equal) +#define lp_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#endif + + /* default maximum size for call/backtrack stack */ #if !defined(MAXBACK) -#define MAXBACK 100 +#define MAXBACK 400 #endif diff --git a/3rd/lpeg/lpvm.c b/3rd/lpeg/lpvm.c index cd893ed8..eaf2ebfd 100644 --- a/3rd/lpeg/lpvm.c +++ b/3rd/lpeg/lpvm.c @@ -1,5 +1,5 @@ /* -** $Id: lpvm.c,v 1.5 2013/04/12 16:29:49 roberto Exp $ +** $Id: lpvm.c,v 1.6 2015/09/28 17:01:25 roberto Exp $ ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) */ @@ -18,7 +18,7 @@ /* initial size for call/backtrack stack */ #if !defined(INITBACK) -#define INITBACK 100 +#define INITBACK MAXBACK #endif @@ -70,7 +70,7 @@ static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) { max = lua_tointeger(L, -1); /* maximum allowed size */ lua_pop(L, 1); if (n >= max) /* already at maximum size? */ - luaL_error(L, "too many pending calls/choices"); + luaL_error(L, "backtrack stack overflow (current limit is %d)", max); newn = 2 * n; /* new size */ if (newn > max) newn = max; newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack)); diff --git a/3rd/lpeg/re.html b/3rd/lpeg/re.html index 4717ec2b..d0d9744f 100644 --- a/3rd/lpeg/re.html +++ b/3rd/lpeg/re.html @@ -10,7 +10,7 @@ - +
@@ -296,7 +296,7 @@ it would be useful if each table had a tag field telling what non terminal that table represents. We can add such a tag using -named group captures: +named group captures:

 x = re.compile[[
@@ -450,7 +450,7 @@ print(re.match(p, p))   -- a self description must match itself
 

License

-Copyright © 2008-2010 Lua.org, PUC-Rio. +Copyright © 2008-2015 Lua.org, PUC-Rio.

Permission is hereby granted, free of charge, @@ -488,7 +488,7 @@ THE SOFTWARE.

-$Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $ +$Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $

diff --git a/3rd/lpeg/test.lua b/3rd/lpeg/test.lua index fec5a85b..017a3abf 100755 --- a/3rd/lpeg/test.lua +++ b/3rd/lpeg/test.lua @@ -1,6 +1,6 @@ -#!/usr/bin/env lua5.1 +#!/usr/bin/env lua --- $Id: test.lua,v 1.105 2014/12/12 17:00:39 roberto Exp $ +-- $Id: test.lua,v 1.109 2015/09/28 17:01:25 roberto Exp $ -- require"strict" -- just to be pedantic @@ -16,9 +16,6 @@ local unpack = rawget(table, "unpack") or unpack local loadstring = rawget(_G, "loadstring") or load --- most tests here do not need much stack space -m.setmaxstack(5) - local any = m.P(1) local space = m.S" \t\n"^0 @@ -291,6 +288,13 @@ assert(m.match(m.P"ab"^-1 - "c", "abcd") == 3) p = ('Aa' * ('Bb' * ('Cc' * m.P'Dd'^0)^0)^0)^-1 assert(p:match("AaBbCcDdBbCcDdDdDdBb") == 21) + + +-- bug in 0.12.2 +-- p = { ('ab' ('c' 'ef'?)*)? } +p = m.C(('ab' * ('c' * m.P'ef'^-1)^0)^-1) +s = "abcefccefc" +assert(s == p:match(s)) pi = "3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510" @@ -352,6 +356,11 @@ checkeq(t, {hi = 10, ho = 20}) t = p:match'abc' checkeq(t, {hi = 10, ho = 20, 'a', 'b', 'c'}) +-- non-string group names +p = m.Ct(m.Cg(1, print) * m.Cg(1, 23.5) * m.Cg(1, io)) +t = p:match('abcdefghij') +assert(t[print] == 'a' and t[23.5] == 'b' and t[io] == 'c') + -- test for error messages local function checkerr (msg, f, ...) @@ -388,6 +397,25 @@ p = m.P { (m.P {m.P'abc'} + 'ayz') * m.V'y'; y = m.P'x' } assert(p:match('abcx') == 5 and p:match('ayzx') == 5 and not p:match'abc') +do + -- large dynamic Cc + local lim = 2^16 - 1 + local c = 0 + local function seq (n) + if n == 1 then c = c + 1; return m.Cc(c) + else + local m = math.floor(n / 2) + return seq(m) * seq(n - m) + end + end + p = m.Ct(seq(lim)) + t = p:match('') + assert(t[lim] == lim) + checkerr("too many", function () p = p / print end) + checkerr("too many", seq, lim + 1) +end + + -- tests for non-pattern as arguments to pattern functions p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 } @@ -575,9 +603,9 @@ assert(not p:match(string.rep("011", 10001))) -- this grammar does need backtracking info. local lim = 10000 p = m.P{ '0' * m.V(1) + '0' } -checkerr("too many pending", m.match, p, string.rep("0", lim)) +checkerr("stack overflow", m.match, p, string.rep("0", lim)) m.setmaxstack(2*lim) -checkerr("too many pending", m.match, p, string.rep("0", lim)) +checkerr("stack overflow", m.match, p, string.rep("0", lim)) m.setmaxstack(2*lim + 4) assert(m.match(p, string.rep("0", lim)) == lim + 1) @@ -586,7 +614,7 @@ p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' } m.setmaxstack(200) assert(p:match(string.rep('a', 180) .. 'c' .. string.rep('b', 180)) == 362) -m.setmaxstack(5) -- restore original limit +m.setmaxstack(100) -- restore low limit -- tests for optional start position assert(m.match("a", "abc", 1)) @@ -718,6 +746,10 @@ t = {m.match(m.Cc(nil,nil,4) * m.Cc(nil,3) * m.Cc(nil, nil) / g / g, "")} t1 = {1,1,nil,nil,4,nil,3,nil,nil} for i=1,10 do assert(t[i] == t1[i]) end +-- bug in 0.12.2: ktable with only nil could be eliminated when joining +-- with a pattern without ktable +assert((m.P"aaa" * m.Cc(nil)):match"aaa" == nil) + t = {m.match((m.C(1) / function (x) return x, x.."x" end)^0, "abc")} checkeq(t, {"a", "ax", "b", "bx", "c", "cx"}) @@ -925,6 +957,13 @@ p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k")) t = p:match("ab") checkeq(t, {"a", "b"}) +p = m.P(true) +for i = 1, 10 do p = p * m.Cg(1, i) end +for i = 1, 10 do + local p = p * m.Cb(i) + assert(p:match('abcdefghij') == string.sub('abcdefghij', i, i)) +end + t = {} function foo (p) t[#t + 1] = p; return p .. "x" end From 3a06dcf534e89a81e5bcf532e3b3cbade985bab9 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 5 Oct 2015 10:05:36 +0800 Subject: [PATCH 63/97] update jemalloc to 4.0.3 --- 3rd/jemalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/jemalloc b/3rd/jemalloc index 3541a904..e9192eac 160000 --- a/3rd/jemalloc +++ b/3rd/jemalloc @@ -1 +1 @@ -Subproject commit 3541a904d6fb949f3f0aea05418ccce7cbd4b705 +Subproject commit e9192eacf8935e29fc62fddc2701f7942b1cc02c From 79e73d907e566b12fb69d2ad6ead02914bde7916 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 5 Oct 2015 10:09:22 +0800 Subject: [PATCH 64/97] add target update3rd --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 98f7d1c9..e0f0b14d 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ JEMALLOC_INC := 3rd/jemalloc/include/jemalloc all : jemalloc -.PHONY : jemalloc +.PHONY : jemalloc update3rd MALLOC_STATICLIB := $(JEMALLOC_STATICLIB) @@ -39,6 +39,9 @@ $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile jemalloc : $(MALLOC_STATICLIB) +update3rd : + rm -rf 3rd/jemalloc && git submodule update --init + # skynet CSERVICE = snlua logger gate harbor From 8924b86ad7231e52b44d6dc8c06ab3d58d25f77e Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 8 Oct 2015 15:15:35 +0800 Subject: [PATCH 65/97] check empty group, See pr #351 --- service/multicastd.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/multicastd.lua b/service/multicastd.lua index 7bafab78..2ff1a7f0 100644 --- a/service/multicastd.lua +++ b/service/multicastd.lua @@ -67,7 +67,7 @@ end -- for remote node, call remote_publish. (call mc.unpack and skynet.tostring to convert message pointer to string) local function publish(c , source, pack, size) local group = channel[c] - if group == nil then + if group == nil or next(group) == nil then -- dead channel, delete the pack. mc.bind returns the pointer in pack local pack = mc.bind(pack, 1) mc.close(pack) From 8c1011c503f6b57b780dd08e0713efa33ee8f7e1 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 8 Oct 2015 15:30:15 +0800 Subject: [PATCH 66/97] Add sproto:exist_type and sproto:exist_proto --- lualib/sproto.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lualib/sproto.lua b/lualib/sproto.lua index 911dc877..d3ae40ad 100644 --- a/lualib/sproto.lua +++ b/lualib/sproto.lua @@ -58,6 +58,15 @@ local function querytype(self, typename) return v end +function sproto:exist_type(typename) + local v = self.__tcache[typename] + if not v then + return core.querytype(self.__cobj, typename) ~= nil + else + return true + end +end + function sproto:encode(typename, tbl) local st = querytype(self, typename) return core.encode(st, tbl) @@ -99,6 +108,15 @@ local function queryproto(self, pname) return v end +function sproto:exist_proto(pname) + local v = self.__pcache[pname] + if not v then + return core.protocol(self.__cobj, pname) ~= nil + else + return true + end +end + function sproto:request_encode(protoname, tbl) local p = queryproto(self, protoname) local request = p.request From 8dd9923cf6313a2858f0a5633ff0aa43964d8695 Mon Sep 17 00:00:00 2001 From: xjdrew Date: Thu, 8 Oct 2015 16:55:29 +0800 Subject: [PATCH 67/97] gate: application could control when to start receiving data --- service-src/service_gate.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/service-src/service_gate.c b/service-src/service_gate.c index 29eab2ea..600c4ec7 100644 --- a/service-src/service_gate.c +++ b/service-src/service_gate.c @@ -132,7 +132,12 @@ _ctrl(struct gate * g, const void * msg, int sz) { return; } if (memcmp(command,"start",i) == 0) { - skynet_socket_start(ctx, g->listen_id); + _parm(tmp, sz, i); + int uid = strtol(command , NULL, 10); + int id = hashid_lookup(&g->hash, uid); + if (id>=0) { + skynet_socket_start(ctx, uid); + } return; } if (memcmp(command, "close", i) == 0) { @@ -225,10 +230,7 @@ dispatch_socket_message(struct gate *g, const struct skynet_socket_message * mes break; } int id = hashid_lookup(&g->hash, message->id); - if (id>=0) { - struct connection *c = &g->conn[id]; - _report(g, "%d open %d %s:0",message->id,message->id,c->remote_name); - } else { + if (id<0) { skynet_error(ctx, "Close unknown connection %d", message->id); skynet_socket_close(ctx, message->id); } @@ -259,7 +261,8 @@ dispatch_socket_message(struct gate *g, const struct skynet_socket_message * mes c->id = message->ud; memcpy(c->remote_name, message+1, sz); c->remote_name[sz] = '\0'; - skynet_socket_start(ctx, message->ud); + _report(g, "%d open %d %s:0",c->id, c->id, c->remote_name); + skynet_error(ctx, "socket open: %x", c->id); } break; case SKYNET_SOCKET_TYPE_WARNING: @@ -327,6 +330,7 @@ start_listen(struct gate *g, char * listen_addr) { if (g->listen_id < 0) { return 1; } + skynet_socket_start(ctx, g->listen_id); return 0; } From 515326dadcfb1b9c922bbdff4c99110e19f550a6 Mon Sep 17 00:00:00 2001 From: xjdrew Date: Sat, 10 Oct 2015 18:39:42 +0800 Subject: [PATCH 68/97] bugfix: remove Wformat warning --- service-src/service_gate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-src/service_gate.c b/service-src/service_gate.c index 600c4ec7..71ab1a64 100644 --- a/service-src/service_gate.c +++ b/service-src/service_gate.c @@ -344,7 +344,7 @@ gate_init(struct gate *g , struct skynet_context * ctx, char * parm) { char binding[sz]; int client_tag = 0; char header; - int n = sscanf(parm, "%c %s %s %d %d %d", &header, watchdog, binding, &client_tag, &max); + int n = sscanf(parm, "%c %s %s %d %d", &header, watchdog, binding, &client_tag, &max); if (n<4) { skynet_error(ctx, "Invalid gate parm %s",parm); return 1; From 878110f9f75fe0ddb179077bcf409d9fbc34de44 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 12 Oct 2015 12:29:19 +0800 Subject: [PATCH 69/97] add codecache.mode() --- 3rd/lua/lauxlib.c | 50 +++++++++++++++++++++++++++++++++++++ service-src/service_snlua.c | 1 + 2 files changed, 51 insertions(+) diff --git a/3rd/lua/lauxlib.c b/3rd/lua/lauxlib.c index e4d79955..49657027 100644 --- a/3rd/lua/lauxlib.c +++ b/3rd/lua/lauxlib.c @@ -1040,13 +1040,62 @@ save(const char *key, const void * proto) { return result; } +#define CACHE_OFF 0 +#define CACHE_EXIST 1 +#define CACHE_ON 2 + +static int cache_key = 0; + +static int cache_level(lua_State *L) { + int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key); + int r = lua_tointeger(L, -1); + lua_pop(L,1); + if (t == LUA_TNUMBER) { + return r; + } + return CACHE_ON; +} + +static int cache_mode(lua_State *L) { + static const char * lst[] = { + "OFF", + "EXIST", + "ON", + NULL, + }; + if (lua_isnoneornil(L,1)) { + int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key); + int r = lua_tointeger(L, -1); + if (t == LUA_TNUMBER) { + if (r < 0 || r >= CACHE_ON) { + r = CACHE_ON; + } + } else { + r = CACHE_ON; + } + lua_pushstring(L, lst[r]); + return 1; + } + int t = luaL_checkoption(L, 1, "OFF" , lst); + lua_pushinteger(L, t); + lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key); + return 0; +} + LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { + int level = cache_level(L); + if (level == CACHE_OFF) { + return luaL_loadfilex_(L, filename, mode); + } const void * proto = load(filename); if (proto) { lua_clonefunction(L, proto); return LUA_OK; } + if (level == CACHE_EXIST) { + return luaL_loadfilex_(L, filename, mode); + } lua_State * eL = luaL_newstate(); if (eL == NULL) { lua_pushliteral(L, "New state failed"); @@ -1083,6 +1132,7 @@ cache_clear(lua_State *L) { LUAMOD_API int luaopen_cache(lua_State *L) { luaL_Reg l[] = { { "clear", cache_clear }, + { "mode", cache_mode }, { NULL, NULL }, }; luaL_newlib(L,l); diff --git a/service-src/service_snlua.c b/service-src/service_snlua.c index 89e607f6..20440780 100644 --- a/service-src/service_snlua.c +++ b/service-src/service_snlua.c @@ -30,6 +30,7 @@ static int codecache(lua_State *L) { luaL_Reg l[] = { { "clear", cleardummy }, + { "mode", cleardummy }, { NULL, NULL }, }; luaL_newlib(L,l); From d7e4e43a1b1cd73e6d40369265766084d9deaee3 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 12 Oct 2015 13:07:09 +0800 Subject: [PATCH 70/97] use spinlock macro --- 3rd/lua/lauxlib.c | 21 ++++++++++----------- skynet-src/spinlock.h | 1 + 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/3rd/lua/lauxlib.c b/3rd/lua/lauxlib.c index 49657027..dec81e8a 100644 --- a/3rd/lua/lauxlib.c +++ b/3rd/lua/lauxlib.c @@ -972,29 +972,28 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { // use clonefunction -#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {} -#define UNLOCK(q) __sync_lock_release(&(q)->lock); +#include "spinlock.h" struct codecache { - int lock; + struct spinlock lock; lua_State *L; }; -static struct codecache CC = { 0 , NULL }; +static struct codecache CC; static void clearcache() { if (CC.L == NULL) return; - LOCK(&CC) + SPIN_LOCK(&CC) lua_close(CC.L); CC.L = luaL_newstate(); - UNLOCK(&CC) + SPIN_UNLOCK(&CC) } static void init() { - CC.lock = 0; + SPIN_INIT(&CC); CC.L = luaL_newstate(); } @@ -1002,13 +1001,13 @@ static const void * load(const char *key) { if (CC.L == NULL) return NULL; - LOCK(&CC) + SPIN_LOCK(&CC) lua_State *L = CC.L; lua_pushstring(L, key); lua_rawget(L, LUA_REGISTRYINDEX); const void * result = lua_touserdata(L, -1); lua_pop(L, 1); - UNLOCK(&CC) + SPIN_UNLOCK(&CC) return result; } @@ -1018,7 +1017,7 @@ save(const char *key, const void * proto) { lua_State *L; const void * result = NULL; - LOCK(&CC) + SPIN_LOCK(&CC) if (CC.L == NULL) { init(); L = CC.L; @@ -1036,7 +1035,7 @@ save(const char *key, const void * proto) { lua_pop(L,2); } } - UNLOCK(&CC) + SPIN_UNLOCK(&CC) return result; } diff --git a/skynet-src/spinlock.h b/skynet-src/spinlock.h index d9744c3f..514546f4 100644 --- a/skynet-src/spinlock.h +++ b/skynet-src/spinlock.h @@ -34,6 +34,7 @@ spinlock_unlock(struct spinlock *lock) { static inline void spinlock_destroy(struct spinlock *lock) { + (void) lock; } #else From d2f2e299d527a0ab19a9c69a58ebfcd73db63e47 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 12 Oct 2015 14:40:42 +0800 Subject: [PATCH 71/97] call socket.abandon while auth error, see issue #355 --- lualib/snax/loginserver.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lualib/snax/loginserver.lua b/lualib/snax/loginserver.lua index 01b2d49b..dfaa3ebd 100644 --- a/lualib/snax/loginserver.lua +++ b/lualib/snax/loginserver.lua @@ -49,7 +49,6 @@ end local function launch_slave(auth_handler) local function auth(fd, addr) - fd = assert(tonumber(fd)) skynet.error(string.format("connect from %s (fd = %d)", addr, fd)) socket.start(fd) @@ -84,11 +83,11 @@ local function launch_slave(auth_handler) local ok, server, uid = pcall(auth_handler,token) - socket.abandon(fd) return ok, server, uid, secret end - local function ret_pack(ok, err, ...) + local function ret_pack(fd, ok, err, ...) + socket.abandon(fd) if ok then skynet.ret(skynet.pack(err, ...)) else @@ -100,8 +99,12 @@ local function launch_slave(auth_handler) end end - skynet.dispatch("lua", function(_,_,...) - ret_pack(pcall(auth, ...)) + skynet.dispatch("lua", function(_,_,fd,...) + if type(fd) ~= "number" then + skynet.ret(skynet.pack(false, "invalid fd type")) + else + ret_pack(fd,pcall(auth, fd, ...)) + end end) end From 9aaa35ef142da0d6e9ab0c6a2326ee8442716d6b Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 14 Oct 2015 15:24:51 +0800 Subject: [PATCH 72/97] avoid lua stack overflow --- lualib-src/lua-bson.c | 2 ++ skynet-src/skynet_timer.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lualib-src/lua-bson.c b/lualib-src/lua-bson.c index 0fc26985..bcd44162 100644 --- a/lualib-src/lua-bson.c +++ b/lualib-src/lua-bson.c @@ -408,6 +408,7 @@ bson_numstr( char *str, unsigned int i ) { static void pack_dict(lua_State *L, struct bson *b, bool isarray) { + luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table int length = reserve_length(b); lua_pushnil(L); while(lua_next(L,-2) != 0) { @@ -495,6 +496,7 @@ make_object(lua_State *L, int type, const void * ptr, size_t len) { static void unpack_dict(lua_State *L, struct bson_reader *br, bool array) { + luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table int sz = read_int32(L, br); const void * bytes = read_bytes(L, br, sz-5); struct bson_reader t = { bytes, sz-5 }; diff --git a/skynet-src/skynet_timer.c b/skynet-src/skynet_timer.c index c9a113ae..1f366b85 100644 --- a/skynet-src/skynet_timer.c +++ b/skynet-src/skynet_timer.c @@ -208,7 +208,7 @@ timer_create_timer() { int skynet_timeout(uint32_t handle, int time, int session) { - if (time == 0) { + if (time <= 0) { struct skynet_message message; message.source = 0; message.session = session; From 7486e5323287765b14e04b22412b6aa93e5f047a Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 14 Oct 2015 15:44:09 +0800 Subject: [PATCH 73/97] avoid circular reference while encodeing bson --- lualib-src/lua-bson.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lualib-src/lua-bson.c b/lualib-src/lua-bson.c index bcd44162..7319a0dd 100644 --- a/lualib-src/lua-bson.c +++ b/lualib-src/lua-bson.c @@ -12,6 +12,8 @@ #define DEFAULT_CAP 64 #define MAX_NUMBER 1024 +// avoid circular reference while encodeing +#define MAX_DEPTH 128 #define BSON_REAL 1 #define BSON_STRING 2 @@ -236,7 +238,7 @@ write_double(struct bson *b, lua_Number d) { } } -static void pack_dict(lua_State *L, struct bson *b, bool array); +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) { @@ -268,7 +270,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) { +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) { @@ -284,7 +286,7 @@ append_table(struct bson *bs, lua_State *L, const char *key, size_t sz) { } else { append_key(bs, BSON_DOCUMENT, key, sz); } - pack_dict(L, bs, isarray); + pack_dict(L, bs, isarray, depth); } static void @@ -297,7 +299,7 @@ write_binary(struct bson *b, const void * buffer, size_t sz) { } static void -append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) { +append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { int vt = lua_type(L,-1); switch(vt) { case LUA_TNUMBER: @@ -385,7 +387,7 @@ append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) { break; } case LUA_TTABLE: - append_table(bs, L, key, sz); + append_table(bs, L, key, sz, depth+1); break; case LUA_TBOOLEAN: append_key(bs, BSON_BOOLEAN, key, sz); @@ -407,7 +409,10 @@ bson_numstr( char *str, unsigned int i ) { } static void -pack_dict(lua_State *L, struct bson *b, bool isarray) { +pack_dict(lua_State *L, struct bson *b, bool isarray, 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 int length = reserve_length(b); lua_pushnil(L); @@ -424,7 +429,7 @@ pack_dict(lua_State *L, struct bson *b, bool isarray) { sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1); key = numberkey; - append_one(b, L, key, sz); + append_one(b, L, key, sz, depth); lua_pop(L,1); } else { switch(kt) { @@ -433,12 +438,12 @@ pack_dict(lua_State *L, struct bson *b, bool isarray) { lua_pushvalue(L,-2); lua_insert(L,-2); key = lua_tolstring(L,-2,&sz); - append_one(b, L, key, 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); + append_one(b, L, key, sz, depth); lua_pop(L,1); break; default: @@ -452,7 +457,7 @@ pack_dict(lua_State *L, struct bson *b, bool isarray) { } static void -pack_ordered_dict(lua_State *L, struct bson *b, int n) { +pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) { int length = reserve_length(b); int i; for (i=0;i Date: Wed, 14 Oct 2015 20:12:30 +0800 Subject: [PATCH 74/97] bugfix: socketchannel order mode may blocked. (used by redis driver) --- lualib/dns.lua | 2 +- lualib/skynet.lua | 4 +-- lualib/socket.lua | 6 ++-- lualib/socketchannel.lua | 74 ++++++++++++++++++++++------------------ 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/lualib/dns.lua b/lualib/dns.lua index 35e38084..e349699f 100644 --- a/lualib/dns.lua +++ b/lualib/dns.lua @@ -265,7 +265,7 @@ local function suspend(tid, name, qtype) co = coroutine.running(), } request_pool[tid] = req - skynet.wait() + skynet.wait(req.co) local answers = request_pool[tid].answers request_pool[tid] = nil assert(answers, "no ip") diff --git a/lualib/skynet.lua b/lualib/skynet.lua index 554d8ff8..c20efaa2 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -275,10 +275,10 @@ function skynet.yield() return skynet.sleep(0) end -function skynet.wait() +function skynet.wait(co) local session = c.genid() local ret, msg = coroutine_yield("SLEEP", session) - local co = coroutine.running() + co = co or coroutine.running() sleep_session[co] = nil session_id_coroutine[session] = nil end diff --git a/lualib/socket.lua b/lualib/socket.lua index 7f1d603b..58fe2678 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -30,7 +30,7 @@ end local function suspend(s) assert(not s.co) s.co = coroutine.running() - skynet.wait() + skynet.wait(s.co) -- wakeup closing corouting every time suspend, -- because socket.close() will wait last socket buffer operation before clear the buffer. if s.closing then @@ -232,7 +232,7 @@ function socket.close(id) -- wait reading coroutine read the buffer. assert(not s.closing) s.closing = coroutine.running() - skynet.wait() + skynet.wait(s.closing) else suspend(s) end @@ -361,7 +361,7 @@ function socket.lock(id) else local co = coroutine.running() table.insert(lock_set, co) - skynet.wait() + skynet.wait(co) end end diff --git a/lualib/socketchannel.lua b/lualib/socketchannel.lua index 9ff5d451..547b9f87 100644 --- a/lualib/socketchannel.lua +++ b/lualib/socketchannel.lua @@ -115,8 +115,17 @@ local function dispatch_by_session(self) end end +local wait_response + local function pop_response(self) - return table.remove(self.__request, 1), table.remove(self.__thread, 1) + while true do + local func,co = table.remove(self.__request, 1), table.remove(self.__thread, 1) + if func then + return func, co + end + wait_response = coroutine.running() + skynet.wait(wait_response) + end end local function push_response(self, response, co) @@ -127,46 +136,43 @@ local function push_response(self, response, co) -- response is a function, push it to __request table.insert(self.__request, response) table.insert(self.__thread, co) + if wait_response then + skynet.wakeup(wait_response) + wait_response = nil + end end end local function dispatch_by_order(self) while self.__sock do local func, co = pop_response(self) - if func == nil then - if not socket.block(self.__sock[1]) then - close_channel_socket(self) - wakeup_all(self) + local ok, result_ok, result_data, padding = pcall(func, self.__sock) + if ok then + if padding and result_ok then + -- if padding is true, wait for next result_data + -- self.__result_data[co] is a table + local result = self.__result_data[co] or {} + self.__result_data[co] = result + table.insert(result, result_data) + else + self.__result[co] = result_ok + if result_ok and self.__result_data[co] then + table.insert(self.__result_data[co], result_data) + else + self.__result_data[co] = result_data + end + skynet.wakeup(co) end else - local ok, result_ok, result_data, padding = pcall(func, self.__sock) - if ok then - if padding and result_ok then - -- if padding is true, wait for next result_data - -- self.__result_data[co] is a table - local result = self.__result_data[co] or {} - self.__result_data[co] = result - table.insert(result, result_data) - else - self.__result[co] = result_ok - if result_ok and self.__result_data[co] then - table.insert(self.__result_data[co], result_data) - else - self.__result_data[co] = result_data - end - skynet.wakeup(co) - end - else - close_channel_socket(self) - local errmsg - if result_ok ~= socket_error then - errmsg = result_ok - end - self.__result[co] = socket_error - self.__result_data[co] = errmsg - skynet.wakeup(co) - wakeup_all(self, errmsg) + close_channel_socket(self) + local errmsg + if result_ok ~= socket_error then + errmsg = result_ok end + self.__result[co] = socket_error + self.__result_data[co] = errmsg + skynet.wakeup(co) + wakeup_all(self, errmsg) end end end @@ -288,7 +294,7 @@ local function block_connect(self, once) -- connecting in other coroutine local co = coroutine.running() table.insert(self.__connecting, co) - skynet.wait() + skynet.wait(co) else self.__connecting[1] = true try_connect(self, once) @@ -319,7 +325,7 @@ end local function wait_for_response(self, response) local co = coroutine.running() push_response(self, response, co) - skynet.wait() + skynet.wait(co) local result = self.__result[co] self.__result[co] = nil From bab91a306753174d2e95cfca133b7ff8f78ea642 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 15 Oct 2015 14:01:50 +0800 Subject: [PATCH 75/97] bugfix: don't use global wait_response --- lualib/socketchannel.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lualib/socketchannel.lua b/lualib/socketchannel.lua index 547b9f87..0452cc15 100644 --- a/lualib/socketchannel.lua +++ b/lualib/socketchannel.lua @@ -115,16 +115,14 @@ local function dispatch_by_session(self) end end -local wait_response - local function pop_response(self) while true do local func,co = table.remove(self.__request, 1), table.remove(self.__thread, 1) if func then return func, co end - wait_response = coroutine.running() - skynet.wait(wait_response) + self.wait_response = coroutine.running() + skynet.wait(self.wait_response) end end @@ -136,9 +134,9 @@ local function push_response(self, response, co) -- response is a function, push it to __request table.insert(self.__request, response) table.insert(self.__thread, co) - if wait_response then - skynet.wakeup(wait_response) - wait_response = nil + if self.wait_response then + skynet.wakeup(self.wait_response) + self.wait_response = nil end end end From 2d27df6f4607d637b4773977b385efeb2db4c2f6 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 15 Oct 2015 14:08:01 +0800 Subject: [PATCH 76/97] change name --- lualib/socketchannel.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lualib/socketchannel.lua b/lualib/socketchannel.lua index 0452cc15..7e7a0f6b 100644 --- a/lualib/socketchannel.lua +++ b/lualib/socketchannel.lua @@ -121,8 +121,8 @@ local function pop_response(self) if func then return func, co end - self.wait_response = coroutine.running() - skynet.wait(self.wait_response) + self.__wait_response = coroutine.running() + skynet.wait(self.__wait_response) end end @@ -134,9 +134,9 @@ local function push_response(self, response, co) -- response is a function, push it to __request table.insert(self.__request, response) table.insert(self.__thread, co) - if self.wait_response then - skynet.wakeup(self.wait_response) - self.wait_response = nil + if self.__wait_response then + skynet.wakeup(self.__wait_response) + self.__wait_response = nil end end end From 26cbebfcfd0051bdb17757a96df7509f96fefeab Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 21 Oct 2015 12:58:57 +0800 Subject: [PATCH 77/97] verify callback overflow --- lualib-src/sproto/sproto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lualib-src/sproto/sproto.c b/lualib-src/sproto/sproto.c index b5d61ea6..ec77441b 100644 --- a/lualib-src/sproto/sproto.c +++ b/lualib-src/sproto/sproto.c @@ -677,6 +677,7 @@ 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); + assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow if (sz <= 0) return sz; if (args->type == SPROTO_TSTRING) { From fe3954fb041c676557acccf9c5148c20d4a771ba Mon Sep 17 00:00:00 2001 From: fztcjjl Date: Sat, 24 Oct 2015 01:35:16 +0800 Subject: [PATCH 78/97] add a callback for mysql auth --- lualib/mysql.lua | 13 ++++++++----- test/testmysql.lua | 6 ++---- 2 files changed, 10 insertions(+), 9 deletions(-) mode change 100755 => 100644 lualib/mysql.lua diff --git a/lualib/mysql.lua b/lualib/mysql.lua old mode 100755 new mode 100644 index 305e900b..331c7942 --- a/lualib/mysql.lua +++ b/lualib/mysql.lua @@ -418,7 +418,7 @@ local function _recv_auth_resp(self) end -local function _mysql_login(self,user,password,database) +local function _mysql_login(self,user,password,database,cb) return function(sockchannel) local packet, typ, err = sockchannel:response( _recv_decode_packet_resp(self) ) @@ -490,7 +490,10 @@ local function _mysql_login(self,user,password,database) local packet_len = #req local authpacket=_compose_packet(self,req,packet_len) - return sockchannel:request(authpacket,_recv_auth_resp(self)) + sockchannel:request(authpacket,_recv_auth_resp(self)) + if cb then + cb(self) + end end end @@ -626,7 +629,7 @@ local function _query_resp(self) end end -function _M.connect( opts) +function _M.connect(opts, cb) local self = setmetatable( {}, mt) @@ -645,11 +648,11 @@ function _M.connect( opts) local channel = socketchannel.channel { host = opts.host, port = opts.port or 3306, - auth = _mysql_login(self,user,password,database ), + auth = _mysql_login(self,user,password,database,cb), } + self.sockchannel = channel -- try connect first only once channel:connect(true) - self.sockchannel = channel return self diff --git a/test/testmysql.lua b/test/testmysql.lua index 7bd54855..8679e7bc 100644 --- a/test/testmysql.lua +++ b/test/testmysql.lua @@ -70,21 +70,19 @@ local function test3( db) end skynet.start(function() - local db=mysql.connect{ + local db=mysql.connect({ host="127.0.0.1", port=3306, database="skynet", user="root", password="1", max_packet_size = 1024 * 1024 - } + }, function(db) db:query("set charset utf8") end) if not db then print("failed to connect") end print("testmysql success to connect to mysql server") - db:query("set names utf8") - local res = db:query("drop table if exists cats") res = db:query("create table cats " .."(id serial primary key, ".. "name varchar(5))") From 1653b3213a8faae7df79438f4c79e4c2157b3352 Mon Sep 17 00:00:00 2001 From: fztcjjl Date: Sat, 24 Oct 2015 06:37:25 +0800 Subject: [PATCH 79/97] add a callback for mysql auth --- lualib/mysql.lua | 10 +++++----- test/testmysql.lua | 8 ++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lualib/mysql.lua b/lualib/mysql.lua index 331c7942..c3573ae2 100644 --- a/lualib/mysql.lua +++ b/lualib/mysql.lua @@ -418,7 +418,7 @@ local function _recv_auth_resp(self) end -local function _mysql_login(self,user,password,database,cb) +local function _mysql_login(self,user,password,database,on_connect) return function(sockchannel) local packet, typ, err = sockchannel:response( _recv_decode_packet_resp(self) ) @@ -491,8 +491,8 @@ local function _mysql_login(self,user,password,database,cb) local authpacket=_compose_packet(self,req,packet_len) sockchannel:request(authpacket,_recv_auth_resp(self)) - if cb then - cb(self) + if on_connect then + on_connect(self) end end end @@ -629,7 +629,7 @@ local function _query_resp(self) end end -function _M.connect(opts, cb) +function _M.connect(opts) local self = setmetatable( {}, mt) @@ -648,7 +648,7 @@ function _M.connect(opts, cb) local channel = socketchannel.channel { host = opts.host, port = opts.port or 3306, - auth = _mysql_login(self,user,password,database,cb), + auth = _mysql_login(self,user,password,database,opts.on_connect), } self.sockchannel = channel -- try connect first only once diff --git a/test/testmysql.lua b/test/testmysql.lua index 8679e7bc..e8b420aa 100644 --- a/test/testmysql.lua +++ b/test/testmysql.lua @@ -70,14 +70,18 @@ local function test3( db) end skynet.start(function() + local function on_connect(db) + db:query("set charset utf8"); + end local db=mysql.connect({ host="127.0.0.1", port=3306, database="skynet", user="root", password="1", - max_packet_size = 1024 * 1024 - }, function(db) db:query("set charset utf8") end) + max_packet_size = 1024 * 1024, + on_connect = on_connect + }) if not db then print("failed to connect") end From f5740e00b17d125e0be02510a93b7db6aea59b5a Mon Sep 17 00:00:00 2001 From: nbwk1988 Date: Mon, 26 Oct 2015 16:12:10 +0800 Subject: [PATCH 80/97] add hmac_md5 add hmac_md5 --- lualib/md5.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lualib/md5.lua b/lualib/md5.lua index 26f5cfa6..ceaddb38 100644 --- a/lualib/md5.lua +++ b/lualib/md5.lua @@ -15,4 +15,22 @@ function core.sumhexa (k) end)) end -return core \ No newline at end of file +function core.hmac_md5(data,key) + if #key>64 then + key=core.sum(key) + key=string.sub(key,1,16) + end + + local b=table.pack(string.byte(key,1,#key)) + local ipad_s="" + local opad_s="" + for i=1,64 do + ipad_s=ipad_s..string.char((b[i] or 0)~0x36) + opad_s=opad_s..string.char((b[i] or 0)~0x5c) + end + local istr=core.sum(ipad_s..data) + local ostr=core.sumhexa(opad_s..istr) + return ostr +end + +return core From 1999a03ff7f913fe97eb58c3a7c5baa17f73da49 Mon Sep 17 00:00:00 2001 From: nbwk1988 Date: Tue, 27 Oct 2015 10:44:23 +0800 Subject: [PATCH 81/97] =?UTF-8?q?=E4=BC=98=E5=8C=96hmac?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lualib/md5.lua | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lualib/md5.lua b/lualib/md5.lua index ceaddb38..90e28739 100644 --- a/lualib/md5.lua +++ b/lualib/md5.lua @@ -15,19 +15,21 @@ function core.sumhexa (k) end)) end -function core.hmac_md5(data,key) +local function get_ipad(c) + return string.char(c:byte() ~ 0x36) +end + +local function get_opad(c) + return string.char(c:byte() ~ 0x5c) +end + +function core.hmacmd5(data,key) if #key>64 then key=core.sum(key) - key=string.sub(key,1,16) - end - - local b=table.pack(string.byte(key,1,#key)) - local ipad_s="" - local opad_s="" - for i=1,64 do - ipad_s=ipad_s..string.char((b[i] or 0)~0x36) - opad_s=opad_s..string.char((b[i] or 0)~0x5c) + key=key:sub(1,16) end + local ipad_s=key:gsub(".", get_ipad)..string.rep("6",64-#key) + local opad_s=key:gsub(".", get_opad)..string.rep("\\",64-#key) local istr=core.sum(ipad_s..data) local ostr=core.sumhexa(opad_s..istr) return ostr From a4af35f442ca4779d1320a6dd4a38eba5a7e4e33 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 27 Oct 2015 14:00:25 +0800 Subject: [PATCH 82/97] fix issue #364 --- lualib/snax/interface.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lualib/snax/interface.lua b/lualib/snax/interface.lua index bd996c4d..740f09d9 100644 --- a/lualib/snax/interface.lua +++ b/lualib/snax/interface.lua @@ -59,8 +59,6 @@ return function (name , G, loader) end end - setmetatable(G, { __index = env , __newindex = init_system }) - local pattern do @@ -85,9 +83,10 @@ return function (name , G, loader) end end - mainfunc() - + setmetatable(G, { __index = env , __newindex = init_system }) + local ok, err = pcall(mainfunc) setmetatable(G, nil) + assert(ok,err) for k,v in pairs(temp_global) do G[k] = v From 13d920e1852d71584c830dd3b76fc99810699a03 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 27 Oct 2015 15:40:15 +0800 Subject: [PATCH 83/97] body may contain ascii 0, see issue #365 --- lualib/http/httpc.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lualib/http/httpc.lua b/lualib/http/httpc.lua index ae771dc8..49ccb9b8 100644 --- a/lualib/http/httpc.lua +++ b/lualib/http/httpc.lua @@ -22,8 +22,9 @@ local function request(fd, method, host, url, recvheader, header, content) end if content then - local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n\r\n%s", method, url, header_content, #content, content) + local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n\r\n", method, url, header_content, #content) write(data) + write(content) else local request_header = string.format("%s %s HTTP/1.1\r\n%scontent-length:0\r\n\r\n", method, url, header_content) write(request_header) From 935863f43455c5e902d1c62a7e9d481b3eda2cb1 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 28 Oct 2015 16:12:01 +0800 Subject: [PATCH 84/97] report connect failed reason --- lualib/socket.lua | 6 +++++- lualib/socketchannel.lua | 18 +++++++++++------- skynet-src/socket_server.c | 5 ++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lualib/socket.lua b/lualib/socket.lua index 58fe2678..25a6099f 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -112,8 +112,10 @@ socket_message[5] = function(id, _, err) skynet.error("socket: error on unknown", id, err) return end - if s.connected or s.connecting then + if s.connected then skynet.error("socket: error on", id, err) + elseif s.connecting then + s.connecting = err end s.connected = false driver.close(id) @@ -179,11 +181,13 @@ local function connect(id, func) } socket_pool[id] = s suspend(s) + local err = s.connecting s.connecting = nil if s.connected then return id else socket_pool[id] = nil + return nil, err end end diff --git a/lualib/socketchannel.lua b/lualib/socketchannel.lua index 7e7a0f6b..31a339c5 100644 --- a/lualib/socketchannel.lua +++ b/lualib/socketchannel.lua @@ -209,11 +209,11 @@ local function connect_once(self) return false end assert(not self.__sock and not self.__authcoroutine) - local fd = socket.open(self.__host, self.__port) + local fd,err = socket.open(self.__host, self.__port) if not fd then fd = connect_backup(self) if not fd then - return false + return false, err end end if self.__nodelay then @@ -247,13 +247,16 @@ end local function try_connect(self , once) local t = 0 while not self.__closed do - if connect_once(self) then + local ok, err = connect_once(self) + if ok then if not once then skynet.error("socket: connect to", self.__host, self.__port) end - return true + return elseif once then - return false + return err + else + skynet.error("socket: connect", err) end if t > 1000 then skynet.error("socket: try to reconnect", self.__host, self.__port) @@ -287,6 +290,7 @@ local function block_connect(self, once) if r ~= nil then return r end + local err if #self.__connecting > 0 then -- connecting in other coroutine @@ -295,7 +299,7 @@ local function block_connect(self, once) skynet.wait(co) else self.__connecting[1] = true - try_connect(self, once) + err = try_connect(self, once) self.__connecting[1] = nil for i=2, #self.__connecting do local co = self.__connecting[i] @@ -306,7 +310,7 @@ local function block_connect(self, once) r = check_connection(self) if r == nil then - error(string.format("Connect to %s:%d failed", self.__host, self.__port)) + error(string.format("Connect to %s:%d failed (%s)", self.__host, self.__port, err)) else return r end diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index 4963dd37..6ee4d03a 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -1095,7 +1095,10 @@ report_connect(struct socket_server *ss, struct socket *s, struct socket_message int code = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &error, &len); if (code < 0 || error) { force_close(ss,s, result); - result->data = strerror(errno); + if (code >= 0) + result->data = strerror(error); + else + result->data = strerror(errno); return SOCKET_ERROR; } else { s->type = SOCKET_TYPE_CONNECTED; From 0199ba1382c1007e9ba9e4f79d9f1b916910abb2 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 28 Oct 2015 17:37:06 +0800 Subject: [PATCH 85/97] sharedata support filename string --- lualib/skynet.lua | 8 ++++++-- service/sharedatad.lua | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lualib/skynet.lua b/lualib/skynet.lua index c20efaa2..2dd38f8d 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -608,11 +608,15 @@ local function init_all() end end +local function ret(f, ...) + f() + return ... +end + local function init_template(start) init_all() init_func = {} - start() - init_all() + return ret(init_all, start()) end function skynet.pcall(start) diff --git a/service/sharedatad.lua b/service/sharedatad.lua index d76fd115..1ae9022c 100644 --- a/service/sharedatad.lua +++ b/service/sharedatad.lua @@ -1,6 +1,8 @@ local skynet = require "skynet" local sharedata = require "sharedata.corelib" local table = table +local cache = require "skynet.codecache" +cache.mode "OFF" -- turn off codecache, because CMD.new may load data file local NORET = {} local pool = {} @@ -43,9 +45,17 @@ function CMD.new(name, t) value = t elseif dt == "string" then value = setmetatable({}, env_mt) - local f = load(t, "=" .. name, "t", value) - assert(skynet.pcall(f)) + local f + if t:sub(1,1) == "@" then + f = assert(loadfile(t:sub(2),"bt",value)) + else + f = assert(load(t, "=" .. name, "bt", value)) + end + local _, ret = assert(skynet.pcall(f)) setmetatable(value, nil) + if type(ret) == "table" then + value = ret + end elseif dt == "nil" then value = {} else From ac4d51b779c3719d6f8723137e343228291d9232 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 29 Oct 2015 11:22:26 +0800 Subject: [PATCH 86/97] bugfix issue #368 --- lualib-src/sproto/sproto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lualib-src/sproto/sproto.c b/lualib-src/sproto/sproto.c index ec77441b..68ccd047 100644 --- a/lualib-src/sproto/sproto.c +++ b/lualib-src/sproto/sproto.c @@ -677,12 +677,12 @@ 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); - assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow if (sz <= 0) return sz; if (args->type == SPROTO_TSTRING) { --sz; // the length of null string is 1 } + assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow return fill_size(data, sz); } From d1b26a60eb016fac567d1422638fa6dbae5f60ec Mon Sep 17 00:00:00 2001 From: kexiao8 Date: Sat, 31 Oct 2015 17:43:33 +0800 Subject: [PATCH 87/97] =?UTF-8?q?=20repeated=20=E2=80=9Cstruct=20table"=20?= =?UTF-8?q?of=20line=2019?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lualib-src/lua-sharedata.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lualib-src/lua-sharedata.c b/lualib-src/lua-sharedata.c index 99cadd15..abbc175d 100644 --- a/lualib-src/lua-sharedata.c +++ b/lualib-src/lua-sharedata.c @@ -36,8 +36,6 @@ struct node { uint8_t nocolliding; // 0 means colliding slot }; -struct table; - struct state { int dirty; int ref; From d83fc0c00fe5db22c8e47f3d896ea375a224cba9 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Mon, 2 Nov 2015 19:50:51 +0800 Subject: [PATCH 88/97] sproto support all integer representation --- lualib-src/sproto/lsproto.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lualib-src/sproto/lsproto.c b/lualib-src/sproto/lsproto.c index 16eaa022..1d71d887 100644 --- a/lualib-src/sproto/lsproto.c +++ b/lualib-src/sproto/lsproto.c @@ -41,8 +41,18 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { #if LUA_VERSION_NUM < 503 -// lua_isinteger is lua 5.3 api -#define lua_isinteger lua_isnumber +#if LUA_VERSION_NUM < 502 +static lua_Integer lua_tointegerx(lua_State *L, int idx, int *isnum) { + if (lua_isnumber(L, idx)) { + if (isnum) *isnum = 1; + return lua_tointeger(L, idx); + } + else { + if (isnum) *isnum = 0; + return 0; + } +} +#endif // work around , use push & lua_gettable may be better #define lua_geti lua_rawgeti @@ -156,11 +166,11 @@ encode(const struct sproto_arg *args) { case SPROTO_TINTEGER: { lua_Integer v; lua_Integer vh; - if (!lua_isinteger(L, -1)) { + int isnum; + v = lua_tointegerx(L, -1, &isnum); + if(!isnum) { return luaL_error(L, ".%s[%d] is not an integer (Is a %s)", args->tagname, args->index, lua_typename(L, lua_type(L, -1))); - } else { - v = lua_tointeger(L, -1); } lua_pop(L,1); // notice: in lua 5.2, lua_Integer maybe 52bit From 9382454bcdd1443db501136089e6ce0056392ab3 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 10 Nov 2015 12:12:42 +0800 Subject: [PATCH 89/97] update jemalloc to 4.0.4 --- 3rd/jemalloc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/jemalloc b/3rd/jemalloc index e9192eac..91010a9e 160000 --- a/3rd/jemalloc +++ b/3rd/jemalloc @@ -1 +1 @@ -Subproject commit e9192eacf8935e29fc62fddc2701f7942b1cc02c +Subproject commit 91010a9e2ebfc84b1ac1ed7fdde3bfed4f65f180 From c28ae25c7020673790c160d30ef7488613aeb458 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Tue, 10 Nov 2015 12:19:04 +0800 Subject: [PATCH 90/97] release 1.0.0 beta --- HISTORY.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 48c7a069..23e1ae10 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,22 @@ +v1.0.0-beta (2015-11-10) +----------- +* Improve and fix bug for sproto +* Add global short string pool for lua vm +* Add code cache mode +* Add a callback for mysql auth +* Add hmac_md5 +* Sharedata support filename as a string +* Fix a bug in socket.httpc +* Fix a lua stack overflow bug in lua bson +* Fix a socketchannel bug may block the data steam +* Avoid dead loop when sending message to the service exiting +* Fix memory leak in netpack +* Improve DH key exchange implement +* Minor fix for socket +* Minor fix for multicast +* Update jemalloc to 4.0.4 +* Update lpeg to 1.0.0 + v1.0.0-alpha10 (2015-8-17) ----------- * Remove the size limit of cluster RPC message. From 7521fe05300c117923a57c5cbd6409de355b1f5a Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 11 Nov 2015 10:44:50 +0800 Subject: [PATCH 91/97] socket.shutdown abandon unsend buffer now, see issue #371 --- lualib-src/lua-socket.c | 9 +++++++++ lualib/socket.lua | 14 +++++++++----- skynet-src/skynet_socket.c | 6 ++++++ skynet-src/skynet_socket.h | 1 + skynet-src/socket_server.c | 14 +++++++++++++- skynet-src/socket_server.h | 1 + 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/lualib-src/lua-socket.c b/lualib-src/lua-socket.c index 5ac0b359..9d12ab52 100644 --- a/lualib-src/lua-socket.c +++ b/lualib-src/lua-socket.c @@ -461,6 +461,14 @@ lclose(lua_State *L) { return 0; } +static int +lshutdown(lua_State *L) { + int id = luaL_checkinteger(L,1); + struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); + skynet_socket_shutdown(ctx, id); + return 0; +} + static int llisten(lua_State *L) { const char * host = luaL_checkstring(L,1); @@ -639,6 +647,7 @@ luaopen_socketdriver(lua_State *L) { luaL_Reg l2[] = { { "connect", lconnect }, { "close", lclose }, + { "shutdown", lshutdown }, { "listen", llisten }, { "send", lsend }, { "lsend", lsendlow }, diff --git a/lualib/socket.lua b/lualib/socket.lua index 25a6099f..1fd9d60b 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -118,7 +118,7 @@ socket_message[5] = function(id, _, err) s.connecting = err end s.connected = false - driver.close(id) + driver.shutdown(id) wakeup(s) end @@ -210,18 +210,22 @@ function socket.start(id, func) return connect(id, func) end -function socket.shutdown(id) +local function close_fd(id, func) local s = socket_pool[id] if s then if s.buffer then driver.clear(s.buffer,buffer_pool) end if s.connected then - driver.close(id) + func(id) end end end +function socket.shutdown(id) + close_fd(id, driver.shutdown) +end + function socket.close(id) local s = socket_pool[id] if s == nil then @@ -232,7 +236,7 @@ function socket.close(id) -- notice: call socket.close in __gc should be carefully, -- because skynet.wait never return in __gc, so driver.clear may not be called if s.co then - -- reading this socket on another coroutine, so don't shutdown (clear the buffer) immediatel + -- reading this socket on another coroutine, so don't shutdown (clear the buffer) immediately -- wait reading coroutine read the buffer. assert(not s.closing) s.closing = coroutine.running() @@ -242,7 +246,7 @@ function socket.close(id) end s.connected = false end - socket.shutdown(id) + close_fd(id) -- clear the buffer (already close fd) assert(s.lock_set == nil or next(s.lock_set) == nil) socket_pool[id] = nil end diff --git a/skynet-src/skynet_socket.c b/skynet-src/skynet_socket.c index f6f8ec56..2f3aec84 100644 --- a/skynet-src/skynet_socket.c +++ b/skynet-src/skynet_socket.c @@ -159,6 +159,12 @@ skynet_socket_close(struct skynet_context *ctx, int id) { socket_server_close(SOCKET_SERVER, source, id); } +void +skynet_socket_shutdown(struct skynet_context *ctx, int id) { + uint32_t source = skynet_context_handle(ctx); + socket_server_shutdown(SOCKET_SERVER, source, id); +} + void skynet_socket_start(struct skynet_context *ctx, int id) { uint32_t source = skynet_context_handle(ctx); diff --git a/skynet-src/skynet_socket.h b/skynet-src/skynet_socket.h index bcdc137c..55b98595 100644 --- a/skynet-src/skynet_socket.h +++ b/skynet-src/skynet_socket.h @@ -29,6 +29,7 @@ int skynet_socket_listen(struct skynet_context *ctx, const char *host, int port, int skynet_socket_connect(struct skynet_context *ctx, const char *host, int port); int skynet_socket_bind(struct skynet_context *ctx, int fd); void skynet_socket_close(struct skynet_context *ctx, int id); +void skynet_socket_shutdown(struct skynet_context *ctx, int id); void skynet_socket_start(struct skynet_context *ctx, int id); void skynet_socket_nodelay(struct skynet_context *ctx, int id); diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index 6ee4d03a..2e26e24f 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -119,6 +119,7 @@ struct request_setudp { struct request_close { int id; + int shutdown; uintptr_t opaque; }; @@ -787,7 +788,7 @@ close_socket(struct socket_server *ss, struct request_close *request, struct soc if (type != -1) return type; } - if (send_buffer_empty(s)) { + if (request->shutdown || send_buffer_empty(s)) { force_close(ss,s,result); result->id = id; result->opaque = request->opaque; @@ -1366,6 +1367,17 @@ void socket_server_close(struct socket_server *ss, uintptr_t opaque, int id) { struct request_package request; request.u.close.id = id; + request.u.close.shutdown = 0; + request.u.close.opaque = opaque; + send_request(ss, &request, 'K', sizeof(request.u.close)); +} + + +void +socket_server_shutdown(struct socket_server *ss, uintptr_t opaque, int id) { + struct request_package request; + request.u.close.id = id; + request.u.close.shutdown = 1; request.u.close.opaque = opaque; send_request(ss, &request, 'K', sizeof(request.u.close)); } diff --git a/skynet-src/socket_server.h b/skynet-src/socket_server.h index b6f0f5fb..41ef9cca 100644 --- a/skynet-src/socket_server.h +++ b/skynet-src/socket_server.h @@ -26,6 +26,7 @@ int socket_server_poll(struct socket_server *, struct socket_message *result, in void socket_server_exit(struct socket_server *); void socket_server_close(struct socket_server *, uintptr_t opaque, int id); +void socket_server_shutdown(struct socket_server *, uintptr_t opaque, int id); void socket_server_start(struct socket_server *, uintptr_t opaque, int id); // return -1 when error From 9f3baf2ee3e0157d2f3f37ffdafdce502a17f4ad Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Wed, 11 Nov 2015 15:06:10 +0800 Subject: [PATCH 92/97] fix issue #372 --- skynet-src/skynet_error.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/skynet-src/skynet_error.c b/skynet-src/skynet_error.c index 962ea597..856c4700 100644 --- a/skynet-src/skynet_error.c +++ b/skynet-src/skynet_error.c @@ -28,7 +28,7 @@ skynet_error(struct skynet_context * context, const char *msg, ...) { va_start(ap,msg); int len = vsnprintf(tmp, LOG_MESSAGE_SIZE, msg, ap); va_end(ap); - if (len < LOG_MESSAGE_SIZE) { + if (len >=0 && len < LOG_MESSAGE_SIZE) { data = skynet_strdup(tmp); } else { int max_size = LOG_MESSAGE_SIZE; @@ -44,6 +44,11 @@ skynet_error(struct skynet_context * context, const char *msg, ...) { skynet_free(data); } } + if (len < 0) { + skynet_free(data); + perror("vsnprintf error :"); + return; + } struct skynet_message smsg; From fa729d593b2672776ff0e614561a315a44bf0ea2 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 12 Nov 2015 10:53:14 +0800 Subject: [PATCH 93/97] lua alloc use raw allocator --- skynet-src/malloc_hook.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/skynet-src/malloc_hook.c b/skynet-src/malloc_hook.c index 3b072168..06e3bbf7 100644 --- a/skynet-src/malloc_hook.c +++ b/skynet-src/malloc_hook.c @@ -25,6 +25,10 @@ static mem_data mem_stats[SLOT_SIZE]; #include "jemalloc.h" +// for skynet_lalloc use +#define raw_realloc je_realloc +#define raw_free je_free + static ssize_t* get_allocated_field(uint32_t handle) { int h = (int)(handle & (SLOT_SIZE - 1)); @@ -165,6 +169,10 @@ skynet_calloc(size_t nmemb,size_t size) { #else +// for skynet_lalloc use +#define raw_realloc realloc +#define raw_free free + void memory_info_dump(void) { skynet_error(NULL, "No jemalloc"); @@ -220,10 +228,10 @@ skynet_strdup(const char *str) { void * skynet_lalloc(void *ud, void *ptr, size_t osize, size_t nsize) { if (nsize == 0) { - skynet_free(ptr); + raw_free(ptr); return NULL; } else { - return skynet_realloc(ptr, nsize); + return raw_realloc(ptr, nsize); } } From 7138144a689374399baef55572a4d192d6c0486e Mon Sep 17 00:00:00 2001 From: huanzai <857763401@qq.com> Date: Thu, 12 Nov 2015 11:15:50 +0800 Subject: [PATCH 94/97] Update lua-netpack.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当长度等于0x10000时,read_size读出的值为0 --- lualib-src/lua-netpack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lualib-src/lua-netpack.c b/lualib-src/lua-netpack.c index 6e601e07..5fae0406 100644 --- a/lualib-src/lua-netpack.c +++ b/lualib-src/lua-netpack.c @@ -435,7 +435,7 @@ static int lpack(lua_State *L) { size_t len; const char * ptr = tolstring(L, &len, 1); - if (len > 0x10000) { + if (len >= 0x10000) { return luaL_error(L, "Invalid size (too long) of data : %d", (int)len); } From 5edde990d6fd5cd8e8e25cc8e4e23d98ce0a5da4 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 12 Nov 2015 15:41:41 +0800 Subject: [PATCH 95/97] bugfix: skynet.fork use table.pack to pack table --- lualib/skynet.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lualib/skynet.lua b/lualib/skynet.lua index 2dd38f8d..0bc2d6e9 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -446,12 +446,10 @@ function skynet.dispatch_unknown_response(unknown) return prev end -local tunpack = table.unpack - function skynet.fork(func,...) - local args = { ... } + local args = table.pack(...) local co = co_create(function() - func(tunpack(args)) + func(table.unpack(args,1,args.n)) end) table.insert(fork_queue, co) return co From b72f0921d4ea9b9184fbfd675f422eb744309357 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 12 Nov 2015 16:21:44 +0800 Subject: [PATCH 96/97] remove unused local function --- service/snaxd.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/service/snaxd.lua b/service/snaxd.lua index d27008be..1b8ddee6 100644 --- a/service/snaxd.lua +++ b/service/snaxd.lua @@ -26,14 +26,6 @@ end local traceback = debug.traceback -local function do_func(f, msg) - return xpcall(f, traceback, table.unpack(msg)) -end - -local function dispatch(f, ...) - return skynet.pack(f(...)) -end - local function return_f(f, ...) return skynet.ret(skynet.pack(f(...))) end From d283d7fcaab86905f1d621a5ca25ec339f2ca220 Mon Sep 17 00:00:00 2001 From: Cloud Wu Date: Thu, 12 Nov 2015 18:34:50 +0800 Subject: [PATCH 97/97] check close return value --- skynet-src/socket_server.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index 2e26e24f..a3326b05 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -337,7 +337,9 @@ force_close(struct socket_server *ss, struct socket *s, struct socket_message *r sp_del(ss->event_fd, s->fd); } if (s->type != SOCKET_TYPE_BIND) { - close(s->fd); + if (close(s->fd) < 0) { + perror("close socket:"); + } } s->type = SOCKET_TYPE_INVALID; }