Skip to content

Commit

Permalink
When sending large buffers to a socket, use MSG_MORE.
Browse files Browse the repository at this point in the history
  • Loading branch information
phmarek committed Aug 20, 2023
1 parent 260b6b1 commit b79376c
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 8 deletions.
1 change: 1 addition & 0 deletions contrib/sb-bsd-sockets/sockets.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ request an input stream and get an output stream in response\)."
:name (format nil "socket~@[ ~A~]~@[, peer: ~A~]"
(socket-namestring socket)
(socket-peerstring socket))
:class 'sb-sys:socket-stream
:dual-channel-p t
:input input
:output output
Expand Down
30 changes: 23 additions & 7 deletions src/code/fd-stream.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@
(char-size 1 :type (or fixnum function))
(output-bytes #'ill-out :type function))

(defstruct (socket-stream
(:constructor %make-socket-stream)
(:include fd-stream)))

(defun fd-stream-bivalent-p (stream)
(eq (fd-stream-element-mode stream) :bivalent))

Expand Down Expand Up @@ -264,7 +268,7 @@
(length (- end start)))
(cond ((and (not (fd-stream-serve-events stream))
(>= length buffer-length))
(flush-output-buffer stream)
(flush-output-buffer stream t)
(finish-writing-sequence thing stream start end)
(return-from buffer-output))
((plusp space)
Expand All @@ -284,12 +288,23 @@

(define-symbol-macro +write-failed+ "Couldn't write to ~S")

(declaim (inline fd-stream-write))
(defun fd-stream-write (stream sap offset len &optional more?)
(if (typep stream 'socket-stream)
(sb-unix:unix-sendto (fd-stream-fd stream) sap
offset len
(if more?
sb-unix:msg-more
0))
(sb-unix:unix-write (fd-stream-fd stream) sap
offset len)))

;;; Flush the current output buffer of the stream, ensuring that the
;;; new buffer is empty. Returns (for convenience) the new output
;;; buffer -- which may or may not be EQ to the old one. If the is no
;;; queued output we try to write the buffer immediately -- otherwise
;;; we queue it for later.
(defun flush-output-buffer (stream)
(defun flush-output-buffer (stream &optional more?)
(let ((obuf (fd-stream-obuf stream)))
(when obuf
(let ((head (buffer-head obuf))
Expand All @@ -311,8 +326,8 @@
(loop
(let ((length (- tail head)))
(multiple-value-bind (count errno)
(sb-unix:unix-write (fd-stream-fd stream) (buffer-sap obuf)
head length)
(fd-stream-write stream (buffer-sap obuf)
head length more?)
(flet ((queue-or-wait ()
(if (fd-stream-serve-events stream)
(return (%queue-and-replace-output-buffer stream))
Expand Down Expand Up @@ -347,7 +362,7 @@
(loop
(let ((length (- end start)))
(multiple-value-bind (count errno)
(sb-unix:unix-write (fd-stream-fd stream) sequence start length)
(fd-stream-write stream sequence start length)
(flet ((wait ()
(or (wait-until-fd-usable (fd-stream-fd stream) :output
(fd-stream-timeout stream)
Expand Down Expand Up @@ -408,7 +423,7 @@
(declare (index head length))
(aver (>= length 0))
(multiple-value-bind (count errno)
(sb-unix:unix-write (fd-stream-fd stream) (buffer-sap buffer)
(fd-stream-write stream (buffer-sap buffer)
head length)
(cond ((eql count length)
;; Complete write, see if we can do another right
Expand Down Expand Up @@ -455,7 +470,7 @@
(let ((length (- end start)))
(synchronize-stream-output stream)
(multiple-value-bind (count errno)
(sb-unix:unix-write (fd-stream-fd stream) thing start length)
(fd-stream-write stream thing start length)
(cond ((eql count length)
;; Complete write -- done!
)
Expand Down Expand Up @@ -2270,6 +2285,7 @@
(error "File descriptor must be opened either for input or output.")))
(let* ((constructor (ecase class
(fd-stream '%make-fd-stream)
(socket-stream '%make-socket-stream)
(form-tracking-stream '%make-form-tracking-stream)))
(element-mode (stream-element-type-stream-element-mode element-type))
(stream (funcall constructor
Expand Down
32 changes: 32 additions & 0 deletions src/code/unix.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,38 @@ corresponds to NAME, or NIL if there is none."
(system-area-pointer
(%write buf)))))


(defconstant msg-more (+ 0 #+linux #x8000)) ; will send more data

;;; UNIX-SENDTO accepts a file descriptor, a buffer, an offset, the
;;; length to write, and a bitmask for flags.
;;; It attempts to write len bytes to the device
;;; associated with fd from the buffer starting at offset. It returns
;;; the actual number of bytes written.
;;; The sockaddr argument allowed by unix "sendto" is currently not available.
#-win32
(defun unix-sendto (fd buf offset len flags)
(declare (optimize (debug 1)))
(declare (type unix-fd fd)
(type (unsigned-byte 32) offset len flags))
(flet ((%sendto (sap)
(declare (system-area-pointer sap))
(int-syscall ("sendto"
int (* char) int int (* char) int)
fd
(with-alien ((ptr (* char) sap))
(addr (deref ptr offset)))
len
flags
(int-sap 0) 0)))
(etypecase buf
((simple-array * (*))
(with-pinned-objects (buf)
(%sendto (vector-sap buf))))
(system-area-pointer
(%sendto buf)))))


;;; Set up a unix-piping mechanism consisting of an input pipe and an
;;; output pipe. Return two values: if no error occurred the first
;;; value is the pipe to be read from and the second is can be written
Expand Down
4 changes: 3 additions & 1 deletion src/cold/exports.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ interface stability.")
"UNIX-OPEN" "UNIX-OPENDIR" "UNIX-PATHNAME" "UNIX-PID"
"UNIX-PIPE" "UNIX-POLL" "UNIX-SIMPLE-POLL"
"UNIX-READ" "UNIX-READDIR" "UNIX-READLINK" "UNIX-REALPATH"
"UNIX-RENAME" "UNIX-STAT" "UNIX-UID"
"UNIX-RENAME" "UNIX-SENDTO" "UNIX-STAT" "UNIX-UID"
"UNIX-UNLINK" "UNIX-WRITE"
"WCONTINUED" "WNOHANG" "WUNTRACED"
"W_OK" "X_OK"
Expand All @@ -107,6 +107,7 @@ interface stability.")
"CLOCK-THREAD-CPUTIME-ID"
"CLOCK-PROCESS-CPUTIME-ID"
"CLOCK-REALTIME"
"MSG-MORE"

;; signals

Expand Down Expand Up @@ -1603,6 +1604,7 @@ SB-KERNEL) have been undone, but probably more remain.")
"EXTERN-ALIEN-NAME"
"EXIT-CODE"
"FD-STREAM" "FD-STREAM-FD" "FD-STREAM-P"
"SOCKET-STREAM" "SOCKET-STREAM-P"
"FIND-DYNAMIC-FOREIGN-SYMBOL-ADDRESS"
"FIND-FOREIGN-SYMBOL-ADDRESS"
#+(and win32 x86-64) "FOREIGN-HEAP-CORRUPTION"
Expand Down

0 comments on commit b79376c

Please sign in to comment.