From 56715c3079c80dccfcc6200092008c0c4b908947 Mon Sep 17 00:00:00 2001 From: root <> Date: Sun, 18 May 2025 13:13:13 +0000 Subject: [PATCH 1/6] fail to find EAGAIN by experiment --- eagain.c | 27 +++++++++++++++++++++++++++ eagain.zig | 12 ++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 eagain.c create mode 100644 eagain.zig diff --git a/eagain.c b/eagain.c new file mode 100644 index 0000000..746d1e5 --- /dev/null +++ b/eagain.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include + +char path[] = "eagain.sock"; +char spam[0xffff0]; + +int main() { + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + fcntl(sock, F_SETFL, O_NONBLOCK); + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + int i = 0; + while (1) { + addr.sun_path[i] = path[i]; + if (path[i] == 0) break; + i += 1; + } + connect(sock, (struct sockaddr*)&addr, sizeof(addr)); + //shutdown(sock, SHUT_WR); + for (i = 0; i < 9999; i += 1) { + int result = write(sock, spam, 0xffff); + if (result < 0) exit(1); + } +} diff --git a/eagain.zig b/eagain.zig new file mode 100644 index 0000000..e25cfa0 --- /dev/null +++ b/eagain.zig @@ -0,0 +1,12 @@ +const std = @import("std"); + +const path = "eagain.sock"; +const spam: [0xffff]u8 = undefined; + +pub fn main() !void { + const stream = try std.net.connectUnixSocket(path); + _ = try std.posix.fcntl(stream.handle, std.c.F.SETFL, std.c.SOCK.NONBLOCK); + for (0..99999) |_| { + _ = try stream.write(&spam); + } +} From 2a59922c014b17eb408538fa581430ae8eae54a7 Mon Sep 17 00:00:00 2001 From: root <> Date: Sun, 18 May 2025 13:13:50 +0000 Subject: [PATCH 2/6] succeed at finding EAGAIN by experiment: -11 --- eagain.s | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 eagain.s diff --git a/eagain.s b/eagain.s new file mode 100644 index 0000000..07f7311 --- /dev/null +++ b/eagain.s @@ -0,0 +1,92 @@ +global _start + +; constants +SYS_WRITE equ 1 +SYS_SOCKET equ 41 +SYS_CONNECT equ 42 +SYS_SHUTDOWN equ 48 +SYS_FCNTL equ 72 +SYS_EXIT equ 60 +AF_UNIX equ 1 +SOCK_STREAM equ 1 +F_GETFL equ 3 +F_SETFL equ 4 +O_NONBLOCK equ 2048 +SHUT_RDWR equ 2 + +SECTION .data +server_path db "eagain.sock", 0x00 +server_path_len equ $ - server_path +sockaddr_size equ 2 + 108 ; $ man 7 unix + +SECTION .bss +sockaddr resb sockaddr_size +spam resb 0xffff + +SECTION .text + +_start: + mov rax, SYS_SOCKET + mov rdi, AF_UNIX + mov rsi, SOCK_STREAM + mov rdx, 0 + syscall + + mov r15, rax + + call nonblocking + call make_sockaddr + + mov rax, SYS_CONNECT + mov rdi, r15 + mov rsi, sockaddr + mov rdx, sockaddr_size + syscall + +loop: + mov rax, SYS_WRITE + mov rdi, r15 + mov rsi, spam + mov rdx, 0xffff + syscall + + cmp rax, 0 + jge loop + + mov rax, SYS_EXIT + mov rdi, 1 + syscall + +nonblocking: + mov r10, rax + + mov rax, SYS_FCNTL + mov rdi, r10 + mov rsi, F_GETFL + syscall + + mov r11, rax + xor r11, O_NONBLOCK + + mov rax, SYS_FCNTL + mov rdi, r10 + mov rsi, F_SETFL + mov rdx, r11 + syscall + + ret + +make_sockaddr: + mov word [sockaddr], AF_UNIX + mov rax, 0 + +make_sockaddr__copy_server_path: + cmp rax, server_path_len + jge return + mov r10, [server_path + rax] + mov [sockaddr + rax + 2], r10 + add rax, 8 + jmp make_sockaddr__copy_server_path + +return: + ret From 21153b7d1451e05d6517fa94bf79d2a5f819d074 Mon Sep 17 00:00:00 2001 From: root <> Date: Wed, 21 May 2025 09:07:58 +0000 Subject: [PATCH 3/6] EAGAIN in constants.c --- constants.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/constants.c b/constants.c index 8239355..3a8123c 100644 --- a/constants.c +++ b/constants.c @@ -2,6 +2,7 @@ #include #include #include +#include // printf("x %d\n", x); void main() { @@ -17,4 +18,6 @@ void main() { printf("POLLERR %d\n", POLLERR); printf("POLLNVAL %d\n", POLLNVAL); printf("SHUT_RDWR %d\n", SHUT_RDWR); + printf("EAGAIN %d\n", EAGAIN); + printf("EWOULDBLOCK %d\n", EWOULDBLOCK); } From e31c9452c848147940411963099de73c0e3a6492 Mon Sep 17 00:00:00 2001 From: root <> Date: Wed, 21 May 2025 09:06:25 +0000 Subject: [PATCH 4/6] remove eagain experiment --- eagain.c | 27 ---------------- eagain.s | 92 ------------------------------------------------------ eagain.zig | 12 ------- 3 files changed, 131 deletions(-) delete mode 100644 eagain.c delete mode 100644 eagain.s delete mode 100644 eagain.zig diff --git a/eagain.c b/eagain.c deleted file mode 100644 index 746d1e5..0000000 --- a/eagain.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include -#include - -char path[] = "eagain.sock"; -char spam[0xffff0]; - -int main() { - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - fcntl(sock, F_SETFL, O_NONBLOCK); - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - int i = 0; - while (1) { - addr.sun_path[i] = path[i]; - if (path[i] == 0) break; - i += 1; - } - connect(sock, (struct sockaddr*)&addr, sizeof(addr)); - //shutdown(sock, SHUT_WR); - for (i = 0; i < 9999; i += 1) { - int result = write(sock, spam, 0xffff); - if (result < 0) exit(1); - } -} diff --git a/eagain.s b/eagain.s deleted file mode 100644 index 07f7311..0000000 --- a/eagain.s +++ /dev/null @@ -1,92 +0,0 @@ -global _start - -; constants -SYS_WRITE equ 1 -SYS_SOCKET equ 41 -SYS_CONNECT equ 42 -SYS_SHUTDOWN equ 48 -SYS_FCNTL equ 72 -SYS_EXIT equ 60 -AF_UNIX equ 1 -SOCK_STREAM equ 1 -F_GETFL equ 3 -F_SETFL equ 4 -O_NONBLOCK equ 2048 -SHUT_RDWR equ 2 - -SECTION .data -server_path db "eagain.sock", 0x00 -server_path_len equ $ - server_path -sockaddr_size equ 2 + 108 ; $ man 7 unix - -SECTION .bss -sockaddr resb sockaddr_size -spam resb 0xffff - -SECTION .text - -_start: - mov rax, SYS_SOCKET - mov rdi, AF_UNIX - mov rsi, SOCK_STREAM - mov rdx, 0 - syscall - - mov r15, rax - - call nonblocking - call make_sockaddr - - mov rax, SYS_CONNECT - mov rdi, r15 - mov rsi, sockaddr - mov rdx, sockaddr_size - syscall - -loop: - mov rax, SYS_WRITE - mov rdi, r15 - mov rsi, spam - mov rdx, 0xffff - syscall - - cmp rax, 0 - jge loop - - mov rax, SYS_EXIT - mov rdi, 1 - syscall - -nonblocking: - mov r10, rax - - mov rax, SYS_FCNTL - mov rdi, r10 - mov rsi, F_GETFL - syscall - - mov r11, rax - xor r11, O_NONBLOCK - - mov rax, SYS_FCNTL - mov rdi, r10 - mov rsi, F_SETFL - mov rdx, r11 - syscall - - ret - -make_sockaddr: - mov word [sockaddr], AF_UNIX - mov rax, 0 - -make_sockaddr__copy_server_path: - cmp rax, server_path_len - jge return - mov r10, [server_path + rax] - mov [sockaddr + rax + 2], r10 - add rax, 8 - jmp make_sockaddr__copy_server_path - -return: - ret diff --git a/eagain.zig b/eagain.zig deleted file mode 100644 index e25cfa0..0000000 --- a/eagain.zig +++ /dev/null @@ -1,12 +0,0 @@ -const std = @import("std"); - -const path = "eagain.sock"; -const spam: [0xffff]u8 = undefined; - -pub fn main() !void { - const stream = try std.net.connectUnixSocket(path); - _ = try std.posix.fcntl(stream.handle, std.c.F.SETFL, std.c.SOCK.NONBLOCK); - for (0..99999) |_| { - _ = try stream.write(&spam); - } -} From c16c82b15f9db5d1cc893a10875f37663bcc8462 Mon Sep 17 00:00:00 2001 From: root <> Date: Wed, 21 May 2025 09:07:31 +0000 Subject: [PATCH 5/6] server.s: use r15 not r10 for persisting thru syscalls --- server.s | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/server.s b/server.s index baea35b..fc2d1c7 100644 --- a/server.s +++ b/server.s @@ -9,53 +9,61 @@ make_server: mov rsi, SOCK_STREAM mov rdx, 0 syscall - push rax + push r15 + mov r15, rax + + mov rdi, r15 call nonblocking + + mov rdi, r15 call make_sockaddr - pop r10 mov rax, SYS_BIND - mov rdi, r10 + mov rdi, r15 mov rsi, sockaddr mov rdx, sockaddr_size syscall mov rax, SYS_LISTEN - mov rdi, r10 + mov rdi, r15 mov rsi, 100 syscall - mov rax, r10 + mov rax, r15 + pop r15 ret +; rdi - fd nonblocking: - mov r10, rax + push r15 + mov r15, rdi mov rax, SYS_FCNTL - mov rdi, r10 + mov rdi, r15 mov rsi, F_GETFL syscall - mov r11, rax - xor r11, O_NONBLOCK + mov r10, rax + or r10, O_NONBLOCK mov rax, SYS_FCNTL - mov rdi, r10 + mov rdi, r15 mov rsi, F_SETFL - mov rdx, r11 + mov rdx, r10 syscall + pop r15 ret make_sockaddr: mov word [sockaddr], AF_UNIX - mov rax, 0 + mov r10, 0 make_sockaddr__copy_server_path: - cmp rax, server_path_len + cmp r10, server_path_len jge return - mov r10, [server_path + rax] - mov [sockaddr + rax + 2], r10 - add rax, 8 + mov r8b, [server_path + r10] + mov [sockaddr + 2 + r10], r8b + add r10, 1 jmp make_sockaddr__copy_server_path From fc1cc26b0f1374b99c841fad0f32f6fba9355fe7 Mon Sep 17 00:00:00 2001 From: root <> Date: Wed, 21 May 2025 09:23:48 +0000 Subject: [PATCH 6/6] rewrite client__pollout algorithm: 1. call client__pollout__before_fresh_lines 2. if error, return 3. find line length 4. if no line, set POLLIN and goto 8 5. call client__pollout__line 6. if error, goto 7 7. finished with this line; goto 3 8. move the final incomplete line to the start of the client's buffer 9. return --- client.s | 221 +++++++++++++++++++++++++++++++++++++++++++++---------- main.s | 15 +++- 2 files changed, 194 insertions(+), 42 deletions(-) diff --git a/client.s b/client.s index d3a1e7a..9946311 100644 --- a/client.s +++ b/client.s @@ -70,83 +70,226 @@ client__pollin__line_too_long: jmp client__pollin__return -; Returns: -; rax - non-negative from write(2) ; Errors: -; rax - -1024 - no line was buffered -; rax - other negative - from write(2) +; rax - negative or zero - from write(2) ; Arguments: ; rdi - fd ; rsi - address of client within clients array ; rdx - pollfds index ; Variables: +; rbp - fd ; rbx - pollfds index ; r12 - address of client within clients array -; r13 - line length -; r11 - client buffer end of text after call to write(2) +; r13 - line start +; r14 - line end +; r15 - client buffer end +; r11 - client buffer, length of last incomplete line client__pollout: + push rbp push rbx push r12 push r13 + push r14 + push r15 + mov rbp, rdi mov rbx, rdx mov r12, rsi + mov r13, rsi + add r13, OFFSET_CLIENT_BUFFER + mov r15, r13 + add r15, 255 - push rdi - mov rdi, r12 - add rdi, OFFSET_CLIENT_BUFFER - mov rsi, 255 - call scanline - pop rdi - - ; poll(2)'d for POLLOUT but we had no line buffered; - ; should be impossible - cmp rax, 0 - je client__pollout__no_line - - mov r13, rax - - mov rax, SYS_WRITE + mov rdi, rbp mov rsi, r12 - add rsi, OFFSET_CLIENT_BUFFER - mov rdx, r13 - syscall + call client__pollout__before_fresh_lines - ; error from write(2) cmp rax, 0 - jl client__pollout__return + jle client__pollout__return - mov r10, r12 +client__pollout__scan: + mov rdi, r13 + mov rsi, 0 + mov sil, [r12 + OFFSET_CLIENT_BUFFER_LEN] + call scanline + + cmp rax, 0 + jle client__pollout__set_pollin ; no lines left + + sub [r12 + OFFSET_CLIENT_BUFFER_LEN], al + + ; line_end = line_start + line_len + mov r14, r13 + add r14, rax + + mov rdi, rbp + mov rsi, r12 + mov rdx, r13 + mov rcx, r14 + sub rcx, r13 + call client__pollout__line + + mov r13, r14 + + cmp rax, 0 + jle client__pollout__shunt + jmp client__pollout__scan + +client__pollout__set_pollin: + mov word [pollfds + rbx * pollfd_size + 4], POLLIN + mov rax, 1 + +client__pollout__shunt: + mov r10, 0 mov r11, 0 mov r11b, [r12 + OFFSET_CLIENT_BUFFER_LEN] add r11, r12 - sub r11, rax + add r11, OFFSET_CLIENT_BUFFER + sub r11, r13 -client__pollout__shunt: +client__pollout__shunt__loop: cmp r10, r11 jge client__pollout__shunt__finished - mov r8b, [r10 + rax] + mov r8b, [r10 + r13] mov [r10], r8b add r10, 1 - jmp client__pollout__shunt + jmp client__pollout__shunt__loop client__pollout__shunt__finished: - ; buffer_len -= rax - sub [r12 + OFFSET_CLIENT_BUFFER_LEN], al - cmp rax, r13 - jl client__pollout__return - mov word [pollfds + rbx * pollfd_size + 4], POLLIN + mov r10, r13 + sub r10, r12 + sub r10, OFFSET_CLIENT_BUFFER client__pollout__return: + pop r15 + pop r14 pop r13 pop r12 pop rbx + pop rbp ret -client__pollout__no_line: - mov rax, -1024 - jmp client__pollout__return +; Errors: +; rax - -1024 - some scratch buffer bytes remain, stop write(2)ing +; rax - other negative or zero - from write(2) +; Arguments: +; rdi - fd +; rsi - address of client within clients array +client__pollout__before_fresh_lines: + mov rdx, 0 + mov dl, [rsi + OFFSET_CLIENT_SCRATCH_LEN] + cmp rdx, 0 + jle client__pollout__before_fresh_lines__return__succ + + mov rax, SYS_WRITE + push rdx + add rsi, OFFSET_CLIENT_SCRATCH + push rsi + syscall + + pop rsi + pop rdx + + cmp rax, 0 + jle return + + sub [rsi - OFFSET_CLIENT_SCRATCH + OFFSET_CLIENT_SCRATCH_LEN], al + + mov r10, rsi + mov r11, rsi + add r11, rdx + sub r11, rax + +client__pollout__before_fresh_lines__shunt: + cmp r10, r11 + jge client__pollout__before_fresh_lines__return + mov r8b, [r10 + rax] + mov [r10], r8b + add r10, 1 + jmp client__pollout__before_fresh_lines__shunt + +client__pollout__before_fresh_lines__return: + cmp rax, rdx + jl client__pollout__before_fresh_lines__return__fail + +client__pollout__before_fresh_lines__return__succ: + mov rax, 1 + ret + +client__pollout__before_fresh_lines__return__fail: + mov rax, -1024 + ret + +; Errors: +; rax - negative or zero - from write(2) +; Arguments: +; rdi - fd +; rsi - address of client within clients array +; rdx - line start +; rcx - line length +; Variables: +; rsi - client scratch +; r10 - line write(2) end +; r9 - line end +; Assumptions: +; scratch is empty, bc it was emptied by client__pollout__before_fresh_lines +; we must deal with the whole line we are given +client__pollout__line: + ; TODO we've got a line + ; - try writing it + ; - if socket is fucked: return + ; - if ok: cool + ; - if couldn't do the whole thing: you have scratch available, if it's needed for the protocol + + push rdx + push rcx + + mov rax, SYS_WRITE + mov rsi, rdx + mov rdx, rcx + syscall + + pop rcx + pop rdx + + ; TODO continue here also not sure calling fn is correct yet + ; check that changes to server.s haven't fucked anything up + + ; error from write(2) + cmp rax, 0 + jl client__pollout__line__error + + cmp rax, rcx + jl client__pollout__line__incomplete + + mov rax, 1 + ret + +client__pollout__line__error: + mov r10, 0 + jmp client__pollout__line__write_scratch + +client__pollout__line__incomplete: + mov r10, rax + +client__pollout__line__write_scratch: + add rsi, OFFSET_CLIENT_SCRATCH + add r10, rdx + mov r11, 0 + mov r9, rcx + add r9, rdx + +client__pollout__line__write_scratch__loop: + cmp r10, r9 + jge return + mov r8b, [r10 + r11] + mov [rsi + r11], r8b + add r11, 1 + jmp client__pollout__line__write_scratch__loop + + +; Arguments: ; rdi - fd client__shutdown_close: mov rax, SYS_SHUTDOWN diff --git a/main.s b/main.s index ffa5496..d78bb66 100644 --- a/main.s +++ b/main.s @@ -26,6 +26,7 @@ POLLERR equ 8 POLLNVAL equ 32 ; TODO(?) POLLPRI: see poll(2), tcp(7) SHUT_RDWR equ 2 +EAGAIN equ -11 ;STATE_READING equ 0 ;STATE_WRITING equ 1 @@ -34,14 +35,18 @@ SHUT_RDWR equ 2 OFFSET_CLIENT_FD equ 0 OFFSET_CLIENT_STATE equ 4 OFFSET_CLIENT_BUFFER_LEN equ 5 -OFFSET_CLIENT_BUFFER equ 6 +OFFSET_CLIENT_SCRATCH_LEN equ 6 +OFFSET_CLIENT_BUFFER equ 7 +OFFSET_CLIENT_SCRATCH equ 7 + client_buffer_size pollfd_size equ 4 + 2 + 2 ; $ man 2 poll pollfds_capacity equ 100 client_buffer_size equ 255 -; fd, state, buffer_len, buffer -client_size equ 4 + 2 + client_buffer_size +client_scratch_size equ 255 + +; fd, state, buffer_len, scratch_len, buffer, scratch +client_size equ 4 + 2 + client_buffer_size + client_scratch_size clients_capacity equ pollfds_capacity - 1 SECTION .data @@ -158,8 +163,12 @@ _client__pollout: mov rsi, r12 mov rdx, r15 call client__pollout + cmp rax, EAGAIN + je _client__pollout__finished cmp rax, 0 jle _client__error_or_eof + +_client__pollout__finished: add r15, 1 jmp scan__loop