@@ -4,6 +4,13 @@ local getmetatable = getmetatable
4
4
local xpcall = xpcall
5
5
local math_floor = math.floor
6
6
local math_ceil = math.ceil
7
+ local coroutine_resume = coroutine.resume
8
+ local coroutine_status = coroutine.status
9
+ local coroutine_running = coroutine.running
10
+ local coroutine_create = coroutine.create
11
+ local yield = coroutine.yield
12
+ local pcall = pcall
13
+ local unpack = unpack
7
14
8
15
table .unpack = unpack
9
16
@@ -36,45 +43,50 @@ function math.type(x)
36
43
end
37
44
end
38
45
39
- local coroutine_resume = coroutine.resume
40
- local coroutine_status = coroutine.status
41
- local coroutine_running = coroutine.running
46
+
42
47
43
48
local cancel_table = setmetatable ({}, { __mode = ' kv' })
44
49
45
50
function coroutine .resume (co , ...)
46
- if cancel_table [co ] then
47
- return false , ' cannot resume dead coroutine'
51
+ local results = { pcall (coroutine_resume , co , ... ) }
52
+ local ok = results [1 ]
53
+ if not ok then
54
+ local reason = results [2 ]
55
+ if reason == " cancel" then
56
+ return false , ' cannot resume dead coroutine'
57
+ end
48
58
end
49
59
50
- return coroutine_resume ( co , ... )
60
+ return ok , unpack ( results , 2 )
51
61
end
52
62
53
- function coroutine . status ( co )
54
- if cancel_table [ co ] then
55
- return ' dead '
56
- end
63
+ -- donot return 'dead' status
64
+ -- function coroutine.status(co)
65
+ -- return coroutine_status(co)
66
+ -- end
57
67
58
- return coroutine_status (co )
68
+ -- 要实现取消, 只能在协程内的调用通过错误让协程消亡
69
+ function coroutine .yield (...)
70
+ if cancel_table [coroutine_running ()] then
71
+ error (" cancel" )
72
+ end
73
+ return yield (... )
59
74
end
60
75
61
76
function coroutine .close (co )
62
77
if coroutine_status (co ) == ' suspended' then
63
78
cancel_table [co ] = true
79
+ return true
64
80
end
81
+ return false
65
82
end
66
83
67
84
function defer (toBeClosed , callback )
68
85
local ctype = type (toBeClosed )
69
86
local meta = getmetatable (toBeClosed )
70
- local closeCallback = nil
71
87
local ok , result
72
88
73
- local co = coroutine_running ()
74
- if coroutine.status (co ) ~= ' dead' then
75
- ok , result = xpcall (callback , log .error )
76
- end
77
-
89
+ ok , result = xpcall (callback , log .error )
78
90
if meta and meta .__close then
79
91
meta .__close (toBeClosed )
80
92
elseif ctype == ' function' then
0 commit comments