Blame view

publish/skynet/lualib/skynet/coroutine.lua 3.06 KB
4d6f285d   zhouhaihai   增加发布功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  -- You should use this module (skynet.coroutine) instead of origin lua coroutine in skynet framework
  
  local coroutine = coroutine
  -- origin lua coroutine module
  local coroutine_resume = coroutine.resume
  local coroutine_yield = coroutine.yield
  local coroutine_status = coroutine.status
  local coroutine_running = coroutine.running
  
  local select = select
  local skynetco = {}
  
  skynetco.isyieldable = coroutine.isyieldable
  skynetco.running = coroutine.running
  skynetco.status = coroutine.status
  
  local skynet_coroutines = setmetatable({}, { __mode = "kv" })
  
  function skynetco.create(f)
  	local co = coroutine.create(f)
  	-- mark co as a skynet coroutine
  	skynet_coroutines[co] = true
  	return co
  end
  
  do -- begin skynetco.resume
  
  	local profile = require "skynet.profile"
  	-- skynet use profile.resume_co/yield_co instead of coroutine.resume/yield
  
  	local skynet_resume = profile.resume_co
  	local skynet_yield = profile.yield_co
  
  	local function unlock(co, ...)
  		skynet_coroutines[co] = true
  		return ...
  	end
  
  	local function skynet_yielding(co, from, ...)
  		skynet_coroutines[co] = false
  		return unlock(co, skynet_resume(co, from, skynet_yield(from, ...)))
  	end
  
  	local function resume(co, from, ok, ...)
  		if not ok then
  			return ok, ...
  		elseif coroutine_status(co) == "dead" then
  			-- the main function exit
  			skynet_coroutines[co] = nil
  			return true, ...
  		elseif (...) == "USER" then
  			return true, select(2, ...)
  		else
  			-- blocked in skynet framework, so raise the yielding message
  			return resume(co, from, skynet_yielding(co, from, ...))
  		end
  	end
  
  	-- record the root of coroutine caller (It should be a skynet thread)
  	local coroutine_caller = setmetatable({} , { __mode = "kv" })
  
  function skynetco.resume(co, ...)
  	local co_status = skynet_coroutines[co]
  	if not co_status then
  		if co_status == false then
  			-- is running
  			return false, "cannot resume a skynet coroutine suspend by skynet framework"
  		end
  		if coroutine_status(co) == "dead" then
  			-- always return false, "cannot resume dead coroutine"
  			return coroutine_resume(co, ...)
  		else
  			return false, "cannot resume none skynet coroutine"
  		end
  	end
  	local from = coroutine_running()
  	local caller = coroutine_caller[from] or from
  	coroutine_caller[co] = caller
  	return resume(co, caller, coroutine_resume(co, ...))
  end
  
  function skynetco.thread(co)
  	co = co or coroutine_running()
  	if skynet_coroutines[co] ~= nil then
  		return coroutine_caller[co] , false
  	else
  		return co, true
  	end
  end
  
  end -- end of skynetco.resume
  
  function skynetco.status(co)
  	local status = coroutine.status(co)
  	if status == "suspended" then
  		if skynet_coroutines[co] == false then
  			return "blocked"
  		else
  			return "suspended"
  		end
  	else
  		return status
  	end
  end
  
  function skynetco.yield(...)
  	return coroutine_yield("USER", ...)
  end
  
  do -- begin skynetco.wrap
  
  	local function wrap_co(ok, ...)
  		if ok then
  			return ...
  		else
  			error(...)
  		end
  	end
  
  function skynetco.wrap(f)
  	local co = skynetco.create(function(...)
  		return f(...)
  	end)
  	return function(...)
  		return wrap_co(skynetco.resume(co, ...))
  	end
  end
  
  end	-- end of skynetco.wrap
  
  return skynetco