Skip to content

Commit 61fd15a

Browse files
committed
feat: add a new module channel similar to Golang's channel
See example `examples/channel.lua`. Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
1 parent 65befb7 commit 61fd15a

File tree

5 files changed

+154
-1
lines changed

5 files changed

+154
-1
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ install(
192192

193193
install(
194194
FILES time.lua sys.lua file.lua dns.lua socket.lua packet.lua mqtt.lua
195-
websocket.lua sync.lua nl.lua genl.lua ip.lua nl80211.lua
195+
websocket.lua sync.lua channel.lua nl.lua genl.lua ip.lua nl80211.lua
196196
DESTINATION ${LUA_INSTALL_PREFIX}/eco
197197
)
198198

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Lua-eco also provides some modules for you to build applications quickly:
3737
* `dns`: Provides a DNS client implementation for Lua-eco applications, allowing you to perform DNS lookups and resolve domain names.
3838
* `ubus`: Provides a Lua interface to the [ubus] system in OpenWrt, allowing you to interact with system services and daemons.
3939
* `sync`: Provides operations for synchronization between coroutines.
40+
* `channel`: Provides a mechanism for communication between coroutines by sending and receiving values.
4041
* `netlink`: Provides operations for inter-process communication (IPC) between both the kernel and userspace processes.
4142
* `nl80211`: Show/manipulate wireless devices and their configuration.
4243
* `termios`: Bind unix API for terminal/serial I/O.

README_ZH.md

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Lua-eco 还提供了一些有用的模块,方便您快速构建应用程序:
4040
* `dns`: 为 Lua-eco 应用程序提供了一个 DNS 客户端实现,允许您执行 DNS 查找和解析域名。
4141
* `ubus`: 提供了一个 Lua 接口,用于 OpenWrt 中的 [ubus] 系统,允许您与系统服务和守护程序交互。
4242
* `sync`: 提供了协程间同步的操作。
43+
* `channel`: 提供了一种协程间通信的机制,通过发送和接收数据。
4344
* `netlink`: 为内核和用户空间进程之间的进程间通信(IPC)提供操作。
4445
* `nl80211`: 显示/操作无线设备及其配置。
4546
* `termios`: 绑定 unix 接口用于操作终端和串口。

channel.lua

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
-- SPDX-License-Identifier: MIT
2+
-- Author: Jianhui Zhao <zhaojh329@gmail.com>
3+
4+
local sync = require 'eco.sync'
5+
6+
local M = {}
7+
8+
local methods = {}
9+
10+
function methods:length()
11+
return #self.buf
12+
end
13+
14+
function methods:close()
15+
if self.closed then
16+
return
17+
end
18+
19+
self.closed = true
20+
self.cond_recv:signal()
21+
end
22+
23+
-- On success, true is returned
24+
-- On error, false is returned with a string describing the error
25+
function methods:send(v, timeout)
26+
assert(not self.closed, 'sending on closed channel')
27+
28+
local buf = self.buf
29+
30+
if #buf == self.capacity then
31+
local ok, err = self.cond_send:wait(timeout)
32+
if not ok then
33+
return false, err
34+
end
35+
end
36+
37+
buf[#buf + 1] = v
38+
39+
self.cond_recv:signal()
40+
41+
return true
42+
end
43+
44+
-- On success, the value received is returned
45+
-- On closed, nil is returned
46+
-- On error, nil is returned with a string describing the error
47+
function methods:recv(timeout)
48+
local buf = self.buf
49+
50+
if #buf < 1 then
51+
if self.closed then
52+
return nil
53+
end
54+
55+
local ok, err = self.cond_recv:wait(timeout)
56+
if not ok then
57+
return nil, err
58+
end
59+
end
60+
61+
if #buf < 1 then
62+
return nil
63+
end
64+
65+
local v = buf[1]
66+
67+
table.remove(buf, 1)
68+
69+
self.cond_send:signal()
70+
71+
return v
72+
end
73+
74+
local metatable = {
75+
__index = methods
76+
}
77+
78+
--[[
79+
A channel provides a mechanism for communication between coroutines by sending and receiving values.
80+
81+
When a coroutine sends data to a channel, if the channel is full, the sending operation is blocked
82+
until another coroutine has taken data from the channel.
83+
84+
Similarly, when a coroutine receives data from a channel, if there is no data available in the channel,
85+
the receiving operation will be blocked until another coroutine has sent data to the channel.
86+
87+
Closing a channel notifies other coroutines that the channel is no longer in use. After a channel is closed,
88+
other coroutines can still receive data from it, but they can no longer send data to it.
89+
90+
A channel can have a buffer, default is 1.
91+
--]]
92+
function M.new(capacity)
93+
assert(capacity == nil or math.type(capacity) == 'integer', 'capacity must be an integer')
94+
95+
if not capacity or capacity < 1 then
96+
capacity = 1
97+
end
98+
99+
local ch = {
100+
cond_send = sync.cond(),
101+
cond_recv = sync.cond(),
102+
capacity = capacity,
103+
closed = false,
104+
buf = {}
105+
}
106+
107+
return setmetatable(ch, metatable)
108+
end
109+
110+
return M

examples/channel.lua

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env eco
2+
3+
local channel = require 'eco.channel'
4+
local time = require 'eco.time'
5+
6+
-- Create a channel with 5 buffers.
7+
local ch = channel.new(5)
8+
9+
eco.run(function()
10+
local i = 1
11+
while true do
12+
ch:send(i)
13+
14+
print(os.time(), 'send', i)
15+
16+
if i == 5 then
17+
ch:close()
18+
break
19+
end
20+
21+
i = i + 1
22+
time.sleep(1)
23+
end
24+
end)
25+
26+
eco.run(function()
27+
time.sleep(2)
28+
while true do
29+
local v = ch:recv()
30+
if v then
31+
print(os.time(), 'recv:', v)
32+
else
33+
print(os.time(), 'closed')
34+
break
35+
end
36+
end
37+
end)
38+
39+
while true do
40+
time.sleep(1)
41+
end

0 commit comments

Comments
 (0)