@@ -26,9 +26,56 @@ local session_coroutine_address = {}
2626local wakeup_session = {}
2727local sleep_session = {}
2828
29+ local watching_service = {}
30+ local watching_session = {}
31+ local exit_queue = {}
32+
33+ -- suspend is function
34+ local suspend
35+
2936local trace_handle
3037local trace_func = function () end
3138
39+ local function string_to_handle (str )
40+ return tonumber (" 0x" .. string.sub (str , 2 ))
41+ end
42+
43+ ---- - monitor exit
44+
45+ local function dispatch_exit ()
46+ local session = table.remove (exit_queue ,1 )
47+ if session then
48+ local co = session_id_coroutine [session ]
49+ session_id_coroutine [session ] = nil
50+ return suspend (co , coroutine.resume (co , false ))
51+ end
52+ end
53+
54+ local function _exit_dispatch (session , monitor , service )
55+ -- Don't remove from watching_service , because user may call dead service
56+ watching_service [service ] = false
57+ for session , srv in pairs (watching_session ) do
58+ if srv == service then
59+ table.insert (exit_queue , session )
60+ end
61+ end
62+ end
63+
64+ local watch_monitor
65+
66+ function skynet .watch (service )
67+ assert (type (service ) == " number" )
68+ if watch_monitor == nil then
69+ watch_monitor = string_to_handle (c .command (" MONITOR" ))
70+ assert (watch_monitor , " Need a monitor" )
71+ end
72+ if watching_service [service ] == nil then
73+ watching_service [service ] = true
74+ -- read lualib/simplemonitor.lua
75+ assert (skynet .call (watch_monitor , " lua" , " WATCH" , service ), " watch a dead service" )
76+ end
77+ end
78+
3279-- coroutine reuse
3380
3481local coroutine_pool = {}
@@ -52,9 +99,6 @@ local function co_create(f)
5299return co
53100end
54101
55- -- suspend is function
56- local suspend
57-
58102local function dispatch_wakeup ()
59103local co = next (wakeup_session )
60104if co then
@@ -111,6 +155,7 @@ function suspend(co, result, command, param, size)
111155end
112156trace_count ()
113157dispatch_wakeup ()
158+ dispatch_exit ()
114159end
115160
116161function skynet .timeout (ti , func )
@@ -155,10 +200,6 @@ function skynet.name(name, handle)
155200c .command (" NAME" , name .. " " .. handle )
156201end
157202
158- local function string_to_handle (str )
159- return tonumber (" 0x" .. string.sub (str , 2 ))
160- end
161-
162203local self_handle
163204function skynet .self ()
164205if self_handle then
210251
211252function skynet .send (addr , typename , ...)
212253local p = proto [typename ]
254+ if watching_service [addr ] == false then
255+ error (" Service is dead" )
256+ end
213257return c .send (addr , p .id , 0 , p .pack (... ))
214258end
215259
@@ -231,10 +275,21 @@ skynet.pack = assert(c.pack)
231275skynet .unpack = assert (c .unpack )
232276skynet .tostring = assert (c .tostring )
233277
278+ local function yield_call (service , session )
279+ watching_session [session ] = service
280+ local succ , msg , sz = coroutine_yield (" CALL" , session )
281+ watching_session [session ] = nil
282+ assert (succ , " Service is dead" )
283+ return msg ,sz
284+ end
285+
234286function skynet .call (addr , typename , ...)
235287local p = proto [typename ]
236- local session = c .send (addr , p .id , nil , p .pack (... ))
237- return p .unpack (coroutine_yield (" CALL" , assert (session , " call to invalid address" )))
288+ if watching_service [addr ] == false then
289+ error (" Service is dead" )
290+ end
291+ local session = assert (c .send (addr , p .id , nil , p .pack (... ))," call to invalid address" )
292+ return p .unpack (yield_call (addr , session ))
238293end
239294
240295function skynet .blockcall (addr , typename , ...)
@@ -245,13 +300,13 @@ function skynet.blockcall(addr, typename , ...)
245300c .command (" UNLOCK" )
246301error (" call to invalid address" )
247302end
248- return p .unpack (coroutine_yield ( " CALL " , session ))
303+ return p .unpack (yield_call ( addr , session ))
249304end
250305
251306function skynet .rawcall (addr , typename , msg , sz )
252307local p = proto [typename ]
253- local session = c .send (addr , p .id , nil , msg , sz )
254- return coroutine_yield ( " CALL " , assert ( session , " call to invalid address " ) )
308+ local session = assert ( c .send (addr , p .id , nil , msg , sz ), " call to invalid address " )
309+ return yield_call ( addr , session )
255310end
256311
257312function skynet .ret (msg , sz )
@@ -306,7 +361,7 @@ local function raw_dispatch_message(prototype, msg, sz, session, source, ...)
306361else
307362c .trace_switch (trace_handle , session )
308363session_id_coroutine [session ] = nil
309- suspend (co , coroutine.resume (co , msg , sz ))
364+ suspend (co , coroutine.resume (co , true , msg , sz ))
310365end
311366else
312367local p = assert (proto [prototype ], prototype )
419474local remote_call_func = setmetatable ({}, weak_meta )
420475
421476local _send = assert (c .send )
422- local _yield = coroutine.yield
423477local _pack = assert (c .pack )
424478local _unpack = assert (c .unpack )
425479local _local = skynet .self ()
431485local addr = remote_query (t .__remote )
432486-- the proto is 11 (lua is 10)
433487local session = assert (_send (addr , 11 , nil , _pack (t ,method ,... )), " call to invalid address" )
434- local msg , sz = _yield ( " CALL " , session )
488+ local msg , sz = coroutine_yield ( session )
435489return select (2 ,assert (_unpack (msg ,sz )))
436490end
437491remote_call_func [method ] = f
463517
464518local function remote_call (obj , method , ...)
465519if type (obj ) ~= " table" or type (method ) ~= " string" then
466- return _yield (" RETURN" , _pack (false , " Invalid call" ))
520+ return coroutine_yield (" RETURN" , _pack (false , " Invalid call" ))
467521end
468522local f = obj [method ]
469523if type (f ) ~= " function" then
470- return _yield (" RETURN" , _pack (false , " Object has not method " .. method ))
524+ return coroutine_yield (" RETURN" , _pack (false , " Object has not method " .. method ))
471525end
472- return _yield (" RETURN" , _pack (pcall (f ,... )))
526+ return coroutine_yield (" RETURN" , _pack (pcall (f ,... )))
473527end
474528
475529function skynet .remote_root ()
575629unpack = skynet .unpack ,
576630dispatch = _debug_dispatch ,
577631}
632+
633+ REG {
634+ name = " exit" ,
635+ id = 7 ,
636+ pack = skynet .pack ,
637+ unpack = skynet .unpack ,
638+ dispatch = _exit_dispatch ,
639+ }
578640end
579641
580642local init_func = {}
0 commit comments