test: group examples into per-category folders
Move examples/*.sx and their expected/ snapshots into per-category subfolders (examples/<category>/...). Folder = leading filename token, with ffi-objc/ffi-jni kept whole; filenames are unchanged. The corpus runner and LSP sweep now discover each category's expected/ dir, while issues/ stays flat. Example 1058's repo-root-relative companion import is made file-relative. Path strings embedded in 164 snapshots were regenerated (path-only changes). Test-layout docs in CLAUDE.md updated.
This commit is contained in:
94
examples/socket/1630-socket-nonblocking.sx
Normal file
94
examples/socket/1630-socket-nonblocking.sx
Normal file
@@ -0,0 +1,94 @@
|
||||
// std.socket nonblocking surface (PLAN-HTTPZ S2): set_nonblocking via
|
||||
// the C-variadic fcntl, and the typed _nb wrappers' full result
|
||||
// algebra — bytes, WouldBlock, Closed — on a unix socketpair, plus
|
||||
// accept_nb on a nonblocking TCP listener (WouldBlock with an empty
|
||||
// backlog, a connection after a loopback connect).
|
||||
#import "modules/std.sx";
|
||||
|
||||
PORT :: 18931;
|
||||
|
||||
main :: () -> i32 {
|
||||
// ── socketpair: read/write algebra ────────────────────────────────
|
||||
pair : [2]i32 = ---;
|
||||
if socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0, @pair[0]) != 0 {
|
||||
print("socketpair failed\n");
|
||||
return 1;
|
||||
}
|
||||
a := pair[0];
|
||||
b := pair[1];
|
||||
if !socket.set_nonblocking(a) or !socket.set_nonblocking(b) {
|
||||
print("set_nonblocking failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf : [16]u8 = ---;
|
||||
n, e := socket.read_nb(a, @buf[0], 16);
|
||||
if e != error.WouldBlock {
|
||||
print("empty pair read: expected WouldBlock\n");
|
||||
return 1;
|
||||
}
|
||||
print("empty read: WouldBlock\n");
|
||||
|
||||
msg := "ping";
|
||||
wn, we := socket.write_nb(b, msg.ptr, 4);
|
||||
if we { print("write_nb failed\n"); return 1; }
|
||||
if wn != 4 { print("short write: {}\n", wn); return 1; }
|
||||
rn, re := socket.read_nb(a, @buf[0], 16);
|
||||
if re { print("read_nb after write failed\n"); return 1; }
|
||||
if rn != 4 { print("short read: {}\n", rn); return 1; }
|
||||
print("pair round trip: {} bytes\n", rn);
|
||||
|
||||
socket.close(b);
|
||||
cn, ce := socket.read_nb(a, @buf[0], 16);
|
||||
if ce != error.Closed {
|
||||
print("read after peer close: expected Closed\n");
|
||||
return 1;
|
||||
}
|
||||
print("peer close: Closed\n");
|
||||
socket.close(a);
|
||||
|
||||
// ── nonblocking listener: accept_nb ───────────────────────────────
|
||||
lfd := socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
|
||||
if lfd < 0 { print("listener socket failed\n"); return 1; }
|
||||
one : i32 = 1;
|
||||
socket.setsockopt(lfd, socket.SOL_SOCKET, socket.SO_REUSEADDR, @one, 4);
|
||||
addr : socket.SockAddr = .{
|
||||
sin_len = 16, sin_family = xx socket.AF_INET,
|
||||
sin_port = socket.htons(PORT), sin_addr = 0x0100007F, // 127.0.0.1
|
||||
};
|
||||
if socket.bind(lfd, @addr, 16) != 0 { print("bind failed\n"); return 1; }
|
||||
if socket.listen(lfd, 4) != 0 { print("listen failed\n"); return 1; }
|
||||
if !socket.set_nonblocking(lfd) { print("listener set_nonblocking failed\n"); return 1; }
|
||||
|
||||
afd, ae := socket.accept_nb(lfd);
|
||||
if ae != error.WouldBlock {
|
||||
print("empty backlog: expected WouldBlock\n");
|
||||
return 1;
|
||||
}
|
||||
print("empty backlog: WouldBlock\n");
|
||||
|
||||
// A blocking loopback connect completes the handshake against the
|
||||
// listen queue without an accept having run yet.
|
||||
cfd := socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
|
||||
if cfd < 0 { print("client socket failed\n"); return 1; }
|
||||
if socket.connect(cfd, @addr, 16) != 0 {
|
||||
print("connect failed: errno {}\n", socket.errno());
|
||||
return 1;
|
||||
}
|
||||
got := -1;
|
||||
tries := 0;
|
||||
while got < 0 and tries < 1000 {
|
||||
c2, ae2 := socket.accept_nb(lfd);
|
||||
if !ae2 { got = xx c2; }
|
||||
else if ae2 != error.WouldBlock { print("accept_nb fault\n"); return 1; }
|
||||
tries += 1;
|
||||
}
|
||||
if got < 0 { print("accept never produced the connection\n"); return 1; }
|
||||
print("accept after connect: ok\n");
|
||||
|
||||
socket.close(xx got);
|
||||
socket.close(cfd);
|
||||
socket.close(lfd);
|
||||
print("socket nonblocking ok\n");
|
||||
return 0;
|
||||
}
|
||||
1
examples/socket/expected/1630-socket-nonblocking.exit
Normal file
1
examples/socket/expected/1630-socket-nonblocking.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/socket/expected/1630-socket-nonblocking.stderr
Normal file
1
examples/socket/expected/1630-socket-nonblocking.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
6
examples/socket/expected/1630-socket-nonblocking.stdout
Normal file
6
examples/socket/expected/1630-socket-nonblocking.stdout
Normal file
@@ -0,0 +1,6 @@
|
||||
empty read: WouldBlock
|
||||
pair round trip: 4 bytes
|
||||
peer close: Closed
|
||||
empty backlog: WouldBlock
|
||||
accept after connect: ok
|
||||
socket nonblocking ok
|
||||
Reference in New Issue
Block a user