connection: Add support for suspendable sockets. * netlink/connection.scm (syscall->procedure): Add #:waiter. Distinguish first argument and call WAITER upon EWOULDBLOCK or EAGAIN when the first argument is a port. (ffi-sendto, ffi-recvmsg, ffi-bind): Pass #:waiter. (connect, send-msg, receive-msg): Pass SOCK instead of (fileno sock). Signed-off-by: Julien Lepiller <julien@lepiller.eu>
netlink/connection.scm
26 | 26 | #:use-module (srfi srfi-34) | |
27 | 27 | #:use-module (srfi srfi-35) | |
28 | 28 | #:use-module (srfi srfi-71) | |
29 | + | #:autoload (ice-9 suspendable-ports) (current-read-waiter | |
30 | + | current-write-waiter) | |
29 | 31 | #:export (connect | |
30 | 32 | connect-route | |
31 | 33 | close-socket | |
… | |||
36 | 38 | ||
37 | 39 | (define libc (dynamic-link)) | |
38 | 40 | ||
39 | - | (define (syscall->procedure return-type function | |
40 | - | argument-types) | |
41 | + | (define* (syscall->procedure return-type function | |
42 | + | argument-types | |
43 | + | #:key waiter) | |
41 | 44 | "Return a procedure that calls FUNCTION, a syscall wrapper from the C library | |
42 | - | with the given RETURN-TYPE and ARGUMENT-TYPES." | |
45 | + | with the given RETURN-TYPE and ARGUMENT-TYPES. When WAITER is true and the | |
46 | + | first argument is a port, call it upon EAGAIN or EWOULDBLOCK." | |
43 | 47 | (let ((proc (pointer->procedure return-type | |
44 | 48 | (dynamic-func function libc) | |
45 | 49 | argument-types | |
46 | 50 | #:return-errno? #t))) | |
47 | - | (lambda args | |
48 | - | (let ((ret errno (apply proc args))) | |
49 | - | (when (< ret 0) | |
50 | - | (throw 'system-error function "~A" | |
51 | - | (list (strerror errno)) (list errno))) | |
52 | - | ret)))) | |
51 | + | (lambda (first . rest) | |
52 | + | (let loop () | |
53 | + | (let ((ret errno (apply proc | |
54 | + | (if (port? first) (fileno first) first) | |
55 | + | rest))) | |
56 | + | (if (< ret 0) | |
57 | + | (if (and (memv errno (list EAGAIN EWOULDBLOCK)) | |
58 | + | (port? first) waiter) | |
59 | + | (begin | |
60 | + | ((waiter) first) | |
61 | + | (loop)) | |
62 | + | (throw 'system-error function "~A" | |
63 | + | (list (strerror errno)) (list errno))) | |
64 | + | ret)))))) | |
53 | 65 | ||
54 | 66 | (define ffi-sendto | |
55 | - | (syscall->procedure int "sendto" (list int '* size_t int '* int))) | |
67 | + | (syscall->procedure int "sendto" (list int '* size_t int '* int) | |
68 | + | #:waiter (lambda () (current-write-waiter)))) | |
56 | 69 | (define ffi-recvmsg | |
57 | - | (syscall->procedure int "recvmsg" (list int '* int))) | |
70 | + | (syscall->procedure int "recvmsg" (list int '* int) | |
71 | + | #:waiter (lambda () (current-read-waiter)))) | |
58 | 72 | (define ffi-bind | |
59 | - | (syscall->procedure int "bind" (list int '* int))) | |
73 | + | (syscall->procedure int "bind" (list int '* int) | |
74 | + | #:waiter (lambda () (current-read-waiter)))) | |
60 | 75 | ||
61 | 76 | ;; define simple functions to open/close sockets | |
62 | 77 | (define (open-socket proto) | |
… | |||
89 | 104 | ||
90 | 105 | (define* (connect proto addr) | |
91 | 106 | (let ((sock (open-socket proto))) | |
92 | - | (ffi-bind (fileno sock) | |
107 | + | (ffi-bind sock | |
93 | 108 | (bytevector->pointer addr) | |
94 | 109 | 12) | |
95 | 110 | sock)) | |
… | |||
105 | 120 | (let* ((len (data-size msg)) | |
106 | 121 | (bv (make-bytevector len))) | |
107 | 122 | (serialize msg 0 bv) | |
108 | - | (ffi-sendto (fileno sock) (bytevector->pointer bv) len 0 %null-pointer 0))) | |
123 | + | (ffi-sendto sock (bytevector->pointer bv) len 0 %null-pointer 0))) | |
109 | 124 | ||
110 | 125 | (define* (receive-msg sock #:key (addr (get-addr AF_NETLINK 0 0))) | |
111 | 126 | (let* ((len (* 1024 32)) | |
… | |||
115 | 130 | iovec 1 | |
116 | 131 | %null-pointer 0 | |
117 | 132 | 0)) | |
118 | - | (size (ffi-recvmsg (fileno sock) msghdr 0)) | |
133 | + | (size (ffi-recvmsg sock msghdr 0)) | |
119 | 134 | (answer (make-bytevector size))) | |
120 | 135 | (when (> size (* 1024 32)) | |
121 | 136 | (raise (condition (&netlink-answer-too-big-error (size size))))) |