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))))) | |