Skip to content

Commit 98635cf

Browse files
committed
add poll metamethod to socket
1 parent c766cfe commit 98635cf

6 files changed

Lines changed: 54 additions & 39 deletions

File tree

examples/tcp_client_nonblocking.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ while true do
4242
end
4343
end
4444
else
45-
socket:poll_connect()
45+
socket:try_connect()
4646
end
4747
end

examples/tcp_client_nonblocking_tls.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,6 @@ while true do
5959
end
6060
end
6161
else
62-
socket:poll_connect()
62+
socket:try_connect()
6363
end
6464
end

examples/tcp_server_nonblocking.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ do -- server
2323
local content = header .. body
2424

2525
while true do
26+
--assert(server:poll({"in"}, 1000))
2627
local client, err = server:accept()
2728

2829
if client then

ljsocket.lua

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,9 @@ timeout_messages[errno.EWOULDBLOCK] = true
995995
timeout_messages[errno.ETIMEDOUT] = true
996996
local pollfd_box = ffi.typeof("$[1]", pollfd)
997997

998-
function M.poll(sock, flags, timeout)
998+
function M.poll(socks, flags, timeout)
999+
-- Transform single socket to array
1000+
9991001
local events = 0
10001002
if flags then
10011003
-- On Windows, POLLERR and POLLHUP are output-only flags and cannot be requested
@@ -1012,21 +1014,28 @@ function M.poll(sock, flags, timeout)
10121014
end
10131015
end
10141016

1015-
local pfd = ffi.new(
1016-
pollfd_box,
1017-
{
1018-
{
1019-
fd = sock.fd,
1020-
events = events,
1021-
revents = 0,
1022-
},
1017+
-- Create pollfd array for all sockets
1018+
local pfds = {}
1019+
for i, sock in ipairs(socks) do
1020+
pfds[i] = {
1021+
fd = sock.fd,
1022+
events = events,
1023+
revents = 0,
10231024
}
1024-
)
1025-
local ok, err = socket.poll(pfd, 1, timeout or 0)
1025+
end
1026+
1027+
local pfd = ffi.new(pollfd_box, pfds)
1028+
local ok, err = socket.poll(pfd, #socks, timeout or 0)
10261029

10271030
if not ok then return ok, err end
10281031

1029-
return POLL.flags_to_table(pfd[0].revents, bit.bor), ok
1032+
-- Return array of results for each socket
1033+
local results = {}
1034+
for i = 0, #socks - 1 do
1035+
results[i + 1] = POLL.flags_to_table(pfd[i].revents, bit.bor)
1036+
end
1037+
1038+
return results, ok
10301039
end
10311040

10321041
function M.bind(host, service)
@@ -1385,7 +1394,7 @@ do
13851394
return true
13861395
end
13871396

1388-
function meta:poll_connect()
1397+
function meta:try_connect()
13891398
if self.on_connect and self.timeout_connected and self:is_connected() then
13901399
local ok, err, num = self:on_connect(unpack(self.timeout_connected))
13911400
self.timeout_connected = nil
@@ -1448,6 +1457,15 @@ do
14481457
return nil, err, num
14491458
end
14501459

1460+
function meta:poll(timeout, ...)
1461+
local results, count = M.poll({self}, {...}, timeout)
1462+
1463+
if not results then return results, count end
1464+
if count == 0 then return true end
1465+
1466+
return results[1]
1467+
end
1468+
14511469
function meta:is_connected()
14521470
local ip, service, num = self:get_peer_name()
14531471
local ip2, service2, _ = self:get_name()

test/poll.lua

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,10 @@ test('poll() returns immediately with timeout=0', function()
3737
sock:set_blocking(false)
3838

3939
local start = get_time_ms()
40-
local events, count = assert(socket.poll(sock, {"in"}, 0))
40+
local events = assert(sock:poll(0, "in"))
4141
local elapsed = get_time_ms() - start
4242

4343
ok(elapsed < 50, "poll(timeout=0) should return quickly")
44-
ok(count ~= nil, "poll should return count")
4544

4645
sock:close()
4746
end)
@@ -52,12 +51,11 @@ test('poll() respects timeout duration', function()
5251

5352
local timeout = 100
5453
local start = get_time_ms()
55-
local events, count = assert(socket.poll(sock, {"in"}, timeout))
54+
local events = assert(sock:poll(timeout, "in"))
5655
local elapsed = get_time_ms() - start
5756

5857
ok(elapsed >= timeout - 10, "poll should wait for timeout")
5958
ok(elapsed < timeout + 100, "poll should not wait too long")
60-
ok(count == 0, "should have no events")
6159

6260
sock:close()
6361
end)
@@ -76,9 +74,8 @@ test('POLLIN flag set when data available (UDP)', function()
7674
assert(client:send_to(send_addr, "test data"))
7775
sleep(50)
7876

79-
local events, count = assert(socket.poll(server, {"in"}, 100))
77+
local events = assert(server:poll(100, "in"))
8078
ok(events["in"] == true, "POLLIN should be set when data available")
81-
ok(count == 1, "should have 1 event")
8279

8380
local data, addr = assert(server:receive_from())
8481
ok(data == "test data", "should receive correct data")
@@ -91,7 +88,7 @@ test('POLLOUT flag set when socket writable', function()
9188
local sock = assert(socket.create("inet", "dgram", "udp"))
9289
assert(sock:set_blocking(false))
9390

94-
local events, count = assert(socket.poll(sock, {"out"}, 100))
91+
local events = assert(sock:poll(100, "out"))
9592
ok(events["out"] == true, "POLLOUT should be set on writable socket")
9693

9794
sock:close()
@@ -101,9 +98,8 @@ test('Multiple poll flags work correctly', function()
10198
local sock = assert(socket.create("inet", "dgram", "udp"))
10299
assert(sock:set_blocking(false))
103100

104-
local events, count = assert(socket.poll(sock, {"in", "out"}, 100))
101+
local events = assert(sock:poll(100, "in", "out"))
105102
ok(events["out"] == true, "POLLOUT should be set")
106-
ok(count >= 1, "should have at least 1 event")
107103

108104
sock:close()
109105
end)
@@ -115,7 +111,7 @@ test('POLLERR detection', function()
115111
local connect_addr = assert(socket.find_first_address_info("127.0.0.1", 1))
116112
sock:connect(connect_addr)
117113

118-
local events, count = assert(socket.poll(sock, {"out", "err"}, 1000))
114+
local events = assert(sock:poll(1000, "out", "err"))
119115
ok(events["out"] or events["err"], "should have POLLOUT or POLLERR")
120116

121117
sock:close()
@@ -136,7 +132,7 @@ test('TCP non-blocking connect detection with POLLOUT', function()
136132
local connect_addr = assert(socket.find_first_address_info("127.0.0.1", port))
137133
client:connect(connect_addr)
138134

139-
local events, count = assert(socket.poll(client, {"out"}, 2000))
135+
local events = assert(client:poll(2000, "out"))
140136
ok(events["out"] == true, "POLLOUT should be set after connect")
141137

142138
local errno = client:get_option("error", "socket")
@@ -168,7 +164,7 @@ test('POLLHUP detection on peer disconnect', function()
168164
client:close()
169165
sleep(100)
170166

171-
local events, count = assert(socket.poll(conn, {"in", "hup"}, 500))
167+
local events = assert(conn:poll(500, "in", "hup"))
172168
ok(events["in"] or events["hup"], "should have POLLIN or POLLHUP after close")
173169

174170
conn:close()
@@ -179,8 +175,8 @@ test('poll() with empty flags returns zero events', function()
179175
local sock = assert(socket.create("inet", "dgram", "udp"))
180176
assert(sock:set_blocking(false))
181177

182-
local events, count = assert(socket.poll(sock, {}, 100))
183-
ok(count == 0, "should have no events with empty flags")
178+
local events = assert(sock:poll(100))
179+
ok(events == true, "should have no events with empty flags")
184180

185181
sock:close()
186182
end)
@@ -191,7 +187,7 @@ test('Rapid polling with timeout=0 does not block', function()
191187

192188
local start = get_time_ms()
193189
for i = 1, 100 do
194-
assert(socket.poll(sock, {"in"}, 0))
190+
assert(sock:poll(0, "in"))
195191
end
196192
local elapsed = get_time_ms() - start
197193

@@ -204,7 +200,7 @@ test('poll() on closed socket returns error', function()
204200
local sock = assert(socket.create("inet", "dgram", "udp"))
205201
sock:close()
206202

207-
local events, err = socket.poll(sock, {"in"}, 100)
203+
local events, err = sock:poll(100, "in")
208204
ok(events == nil or (events and events["nval"]), "poll on closed socket should error or return POLLNVAL")
209205
end)
210206

@@ -221,25 +217,25 @@ test('Full UDP send/receive cycle with poll()', function()
221217
assert(client:set_blocking(false))
222218
local send_addr = assert(socket.find_first_address_info("127.0.0.1", port))
223219

224-
local events = assert(socket.poll(client, {"out"}, 100))
220+
local events = assert(client:poll(100, "out"))
225221
ok(events["out"], "client should be writable")
226222
client:send_to(send_addr, "ping")
227223

228224
sleep(50)
229225

230-
events = assert(socket.poll(server, {"in"}, 500))
226+
events = assert(server:poll(500, "in"))
231227
ok(events["in"], "server should have data")
232228

233229
local data, addr = assert(server:receive_from())
234230
ok(data == "ping", "server should receive ping")
235231

236-
events = assert(socket.poll(server, {"out"}, 100))
232+
events = assert(server:poll(100, "out"))
237233
ok(events["out"], "server should be writable")
238234
server:send_to(addr, "pong")
239235

240236
sleep(50)
241237

242-
events = assert(socket.poll(client, {"in"}, 500))
238+
events = assert(client:poll(500, "in"))
243239
ok(events["in"], "client should have data")
244240

245241
data, addr = assert(client:receive_from())
@@ -265,7 +261,7 @@ test('POLLIN on listening socket indicates accept readiness', function()
265261

266262
sleep(50)
267263

268-
local events = assert(socket.poll(server, {"in"}, 500))
264+
local events = assert(server:poll(500, "in"))
269265
ok(events["in"], "POLLIN should be set when connection pending")
270266

271267
local conn = server:accept()
@@ -293,7 +289,7 @@ test('poll() with -1 timeout waits indefinitely', function()
293289
sleep(50)
294290

295291
local start = get_time_ms()
296-
local events = assert(socket.poll(sock, {"in"}, -1))
292+
local events = assert(sock:poll(-1, "in"))
297293
local elapsed = get_time_ms() - start
298294

299295
ok(events["in"], "poll(-1) should detect data")
@@ -320,7 +316,7 @@ test('Large UDP datagram handling with poll()', function()
320316
assert(client:send_to(send_addr, large_data))
321317
sleep(50)
322318

323-
local events = assert(socket.poll(server, {"in"}, 500))
319+
local events = assert(server:poll(500, "in"))
324320
ok(events["in"], "server should receive large datagram")
325321

326322
local data = assert(server:receive_from())

test/tcp_client_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ test('TCP client non-blocking test', function()
101101
end
102102
end
103103
else
104-
sock:poll_connect()
104+
sock:try_connect()
105105
end
106106
end
107107
end)

0 commit comments

Comments
 (0)