-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgo.lua
More file actions
122 lines (101 loc) · 2.58 KB
/
Copy pathgo.lua
File metadata and controls
122 lines (101 loc) · 2.58 KB
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
----- utils -----
local q = require 'queue'
local function log (fmt, ...)
print (string.format(fmt, ...))
end
local function thunk(f, ...)
local args = { ... }
return function () return f(unpack(args)) end
end
----- channels -----
local recv_pull
local function send(ch, val)
while ch.q:is_full() do
coroutine.yield('schan', ch.id)
end
recv_pull(ch.id)
ch.q:enqueue(val)
end
local send_pull
local function recv(ch)
while ch.q:is_empty() do
coroutine.yield('rchan', ch.id)
end
send_pull(ch.id)
return ch.q:dequeue()
end
local chid = 0
local chan_mt = { __index = { send = send, recv = recv }}
local function chan(size)
chid = chid + 1
local ch = { id = chid; q = q.fixed_queue_new(size) }
setmetatable(ch, chan_mt)
return ch
end
----- tasks -----
local pending_tasks = q.queue_new()
local async_tasks = {}
local function async_handler(handle)
return function()
local task = async_tasks[handle]
if not task then return end
async_tasks[handle] = nil
pending_tasks:enqueue(task)
end
end
local function add_wait_queue(wq, chid, task)
if not wq[chid] then
wq[chid] = q.queue_new()
end
wq[chid]:enqueue(task)
end
local function pull_wait_queue(wq, chid)
if not wq[chid] then return end
if wq[chid]:is_empty() then return end
pending_tasks:enqueue(wq[chid]:dequeue())
end
local send_wq = {}
function send_wait(chid, task) add_wait_queue(send_wq, chid, task) end
send_pull = function (chid) pull_wait_queue(send_wq, chid) end
local recv_wq = {}
function recv_wait(chid, task) add_wait_queue(recv_wq, chid, task) end
recv_pull = function (chid) pull_wait_queue(recv_wq, chid) end
local function resume(task)
--if not task then return end
local ok, type, key = coroutine.resume(task)
if not ok then print "kita"; return end -- task throwed an exception
if coroutine.status(task) == 'dead' then return end
if type == 'async' then async_tasks[key] = task
elseif type == 'schan' then send_wait(key, task)
elseif type == 'rchan' then recv_wait(key, task)
end
end
local function flush_pending_tasks()
while not pending_tasks:is_empty() do
resume(pending_tasks:dequeue())
end
end
local function go(task, ...)
local f = thunk(task, ...)
pending_tasks:enqueue(coroutine.create(f))
end
local function run(step)
return function (f)
go(f)
while true do
flush_pending_tasks()
step()
end
end
end
----- iface -----
return {
go = go,
run = run
;
chan = chan,
recv = recv,
send = send
;
async_handler = async_handler
}