-
Notifications
You must be signed in to change notification settings - Fork 13
/
sync.lua
99 lines (72 loc) · 2.09 KB
/
sync.lua
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
-- SPDX-License-Identifier: MIT
-- Author: Jianhui Zhao <[email protected]>
local M = {}
local cond_methods = {}
-- waiting to be awakened
function cond_methods:wait(timeout)
local watchers = self.watchers
local w = eco.watcher(eco.ASYNC)
watchers[#watchers + 1] = w
return w:wait(timeout)
end
-- wakes one coroutine waiting on the cond, if there is any.
-- returns true if one coroutine was waked
function cond_methods:signal()
local watchers = self.watchers
if #watchers > 0 then
watchers[1]:send()
table.remove(watchers, 1)
return true
end
return false
end
-- wakes all coroutines waiting on the cond
-- returns the number of awakened coroutines
function cond_methods:broadcast()
local cnt = #self.watchers
for _, w in ipairs(self.watchers) do
w:send()
end
self.watchers = {}
return cnt
end
local cond_mt = { __index = cond_methods }
-- implements a condition variable, a rendezvous point for coroutines waiting for or announcing the occurrence of an event.
function M.cond()
return setmetatable({ watchers = {} }, cond_mt)
end
local waitgroup_methods = {}
function waitgroup_methods:add(delta)
self.counter = self.counter + delta
end
function waitgroup_methods:done()
local counter = self.counter
counter = counter - 1
if counter < 0 then
error('negative wait group counter')
end
self.counter = counter
if counter == 0 then
self.cond:broadcast()
end
end
function waitgroup_methods:wait(timeout)
if self.counter == 0 then
return true
end
return self.cond:wait(timeout)
end
local waitgroup_mt = { __index = waitgroup_methods }
--[[
A waitgroup waits for a collection of coroutines to finish.
One coroutine calls add to set the number of coroutines to wait for.
Then each of the coroutines runs and calls done when finished.
At the same time, wait can be used to block until all coroutines have finished.
--]]
function M.waitgroup()
return setmetatable({
counter = 0,
cond = M.cond()
}, waitgroup_mt)
end
return M