diff --git a/lualib/skynet.lua b/lualib/skynet.lua index db060b36..9ef95974 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -627,4 +627,9 @@ function skynet.context_ptr() return c.context() end +function skynet.monitor(service) + local monitor = skynet.uniqueservice(true, service) + c.command("MONITOR", string.format(":%08x", monitor)) +end + return skynet diff --git a/service/main.lua b/service/main.lua index e63760fc..31ab2a31 100644 --- a/service/main.lua +++ b/service/main.lua @@ -4,6 +4,7 @@ skynet.start(function() print("Server start") skynet.launch("socket",128) local service = skynet.newservice("service_mgr") + skynet.monitor "simplemonitor" local lualog = skynet.newservice("lualog") local console = skynet.newservice("console") local remoteroot = skynet.newservice("remote_root") diff --git a/service/main_log.lua b/service/main_log.lua index b4655929..500e8dab 100644 --- a/service/main_log.lua +++ b/service/main_log.lua @@ -2,11 +2,12 @@ local skynet = require "skynet" skynet.start(function() print("Log server start") - -- local connection = skynet.launch("connection","256") skynet.launch("socket",128) - local lualog = skynet.launch("snlua","lualog") - local console = skynet.launch("snlua","console") - local log = skynet.launch("snlua","globallog") + local service = skynet.newservice("service_mgr") + skynet.monitor "simplemonitor" + local lualog = skynet.newservice("lualog") + local console = skynet.newservice("console") + local log = skynet.newservice("globallog") -- skynet.launch("snlua","testgroup_c 11 1") skynet.exit() end) diff --git a/service/simplemonitor.lua b/service/simplemonitor.lua new file mode 100644 index 00000000..5e6453c1 --- /dev/null +++ b/service/simplemonitor.lua @@ -0,0 +1,14 @@ +local skynet = require "skynet" + +-- It's a simple service exit monitor, you can do something more when a service exit. + +skynet.register_protocol { + name = "client", + id = 3, + unpack = function() end, + dispatch = function(_, address) + print(string.format("[:%x] exit", address)) + end +} + +skynet.start(function() end) diff --git a/skynet-src/skynet_server.c b/skynet-src/skynet_server.c index 671358f1..5a7b06d4 100644 --- a/skynet-src/skynet_server.c +++ b/skynet-src/skynet_server.c @@ -49,21 +49,26 @@ struct skynet_context { CHECKCALLING_DECL }; -static int g_total_context = 0; +struct skynet_node { + int total; + uint32_t monitor_exit; +}; + +static struct skynet_node G_NODE = { 0,0 }; int skynet_context_total() { - return g_total_context; + return G_NODE.total; } static void _context_inc() { - __sync_fetch_and_add(&g_total_context,1); + __sync_fetch_and_add(&G_NODE.total,1); } static void _context_dec() { - __sync_fetch_and_sub(&g_total_context,1); + __sync_fetch_and_sub(&G_NODE.total,1); } static void @@ -348,6 +353,17 @@ skynet_queryname(struct skynet_context * context, const char * name) { return 0; } +static void +handle_exit(struct skynet_context * context, uint32_t handle) { + if (G_NODE.monitor_exit) { + skynet_send(context, handle, G_NODE.monitor_exit, PTYPE_CLIENT, 0, NULL, 0); + } + if (handle == 0) { + handle = context->handle; + } + skynet_handle_retire(handle); +} + const char * skynet_command(struct skynet_context * context, const char * cmd , const char * param) { if (strcmp(cmd,"TIMEOUT") == 0) { @@ -422,7 +438,7 @@ skynet_command(struct skynet_context * context, const char * cmd , const char * } if (strcmp(cmd,"EXIT") == 0) { - skynet_handle_retire(context->handle); + handle_exit(context, 0); return NULL; } @@ -437,7 +453,7 @@ skynet_command(struct skynet_context * context, const char * cmd , const char * // todo : kill global service } if (handle) { - skynet_handle_retire(handle); + handle_exit(context, handle); } return NULL; } @@ -512,6 +528,24 @@ skynet_command(struct skynet_context * context, const char * cmd , const char * return NULL; } + if (strcmp(cmd,"MONITOR") == 0) { + uint32_t handle; + if (param == NULL || param[0] == '\0') { + handle = context->handle; + } else { + if (param[0] == ':') { + handle = strtoul(param+1, NULL, 16); + } else if (param[0] == '.') { + handle = skynet_handle_findname(param+1); + } else { + skynet_error(context, "Can't monitor %s",param); + // todo : monitor global service + } + } + G_NODE.monitor_exit = handle; + return NULL; + } + return NULL; }