1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Device common functions.
6 (in-package :io.zeta-streams
)
8 ;;;-----------------------------------------------------------------------------
9 ;;; Device Classes and Types
10 ;;;-----------------------------------------------------------------------------
13 ((input-handle :initarg
:input-handle
:accessor input-handle-of
)
14 (output-handle :initarg
:output-handle
:accessor output-handle-of
)))
16 (defclass single-channel-device
(device) ())
18 (defclass dual-channel-device
(device) ())
20 (defclass direct-device
(single-channel-device) ())
22 (defclass memory-buffer-device
(direct-device) ())
24 (defclass socket-device
(dual-channel-device)
25 ((domain :initarg
:domain
)
27 (protocol :initarg
:protocol
)))
29 (deftype device-timeout
()
30 `(or null non-negative-real
))
32 (deftype stream-position
() '(unsigned-byte 64))
35 ;;;-----------------------------------------------------------------------------
37 ;;;-----------------------------------------------------------------------------
39 (defgeneric device-open
(device &rest initargs
))
41 (defgeneric device-close
(device &optional abort
))
43 (defgeneric device-read
(device vector start end
&optional timeout
))
45 (defgeneric device-write
(device vector start end
&optional timeout
))
47 (defgeneric device-position
(device))
49 (defgeneric (setf device-position
) (position device
&rest args
))
51 (defgeneric device-length
(device))
53 (defgeneric wait-for-input
(device &optional timeout
))
55 (defgeneric wait-for-output
(device &optional timeout
))
58 ;;;-----------------------------------------------------------------------------
60 ;;;-----------------------------------------------------------------------------
62 (defmacro with-device
((name) &body body
)
63 `(let ((*device
* ,name
))
64 (declare (special *device
*))
68 ;;;-----------------------------------------------------------------------------
69 ;;; Default no-op methods
70 ;;;-----------------------------------------------------------------------------
72 (defmethod device-position ((device device
))
75 (defmethod (setf device-position
) (position (device device
) &rest args
)
76 (declare (ignore position args
))
79 (defmethod device-length ((device device
))
83 ;;;-----------------------------------------------------------------------------
84 ;;; Get and Set O_NONBLOCK
85 ;;;-----------------------------------------------------------------------------
87 (defun %get-fd-nonblock-mode
(fd)
88 (declare (special *device
*))
90 (let ((current-flags (nix:fcntl fd nix
:f-getfl
)))
91 (logtest nix
:o-nonblock current-flags
))
92 (nix:posix-error
(err)
93 (posix-file-error err
*device
* "getting O_NONBLOCK from"))))
95 (defun %set-fd-nonblock-mode
(fd mode
)
96 (declare (special *device
*))
99 (nix:fcntl fd nix
:f-getfl
)
100 (nix:posix-error
(err)
101 (posix-file-error err
*device
* "getting O_NONBLOCK from"))))
103 (logior current-flags nix
:o-nonblock
)
104 (logandc2 current-flags nix
:o-nonblock
))))
105 (when (/= new-flags current-flags
)
107 (nix:fcntl fd nix
:f-setfl new-flags
)
108 (nix:posix-error
(err)
109 (posix-file-error err
*device
* "setting O_NONBLOCK on"))))
113 ;;;-----------------------------------------------------------------------------
115 ;;;-----------------------------------------------------------------------------
117 (defmethod wait-for-input ((device device
) &optional timeout
)
118 (iomux:wait-until-fd-ready
(input-handle-of device
) :input timeout
))
120 (defmethod wait-for-output ((device device
) &optional timeout
)
121 (iomux:wait-until-fd-ready
(output-handle-of device
) :output timeout
))
124 ;;;-----------------------------------------------------------------------------
125 ;;; Default DEVICE-READ
126 ;;;-----------------------------------------------------------------------------
128 (defmethod device-read ((device device
) vector start end
&optional timeout
)
129 (when (= start end
) (return-from device-read
0))
130 (if (and timeout
(zerop timeout
))
131 (read-octets/non-blocking device vector start end
)
132 (read-octets/timeout device vector start end timeout
)))
134 (defun read-octets/non-blocking
(device vector start end
)
135 (declare (type device device
)
136 (type ub8-simple-vector vector
)
137 (type iobuf-index start end
))
138 (with-pointer-to-vector-data (buf vector
)
140 (nix:repeat-upon-eintr
141 (nix:read
(input-handle-of device
) (inc-pointer buf start
) (- end start
)))
142 (nix:ewouldblock
() 0)
143 (nix:posix-error
(err)
144 (posix-file-error err device
"reading data from"))
146 (if (zerop nbytes
) :eof nbytes
)))))
148 (defun read-octets/timeout
(device vector start end timeout
)
149 (declare (type device device
)
150 (type ub8-simple-vector vector
)
151 (type iobuf-index start end
)
152 (type device-timeout timeout
))
153 (with-pointer-to-vector-data (buf vector
)
154 (nix:repeat-decreasing-timeout
(remaining timeout
:rloop
)
155 (flet ((check-timeout ()
156 (if (plusp remaining
)
157 (wait-for-input device remaining
)
158 (return-from :rloop
0))))
160 (nix:read
(input-handle-of device
) (inc-pointer buf start
) (- end start
))
161 (nix:eintr
() (check-timeout))
162 (nix:ewouldblock
() (check-timeout))
163 (nix:posix-error
(err)
164 (posix-file-error err device
"reading data from"))
167 (if (zerop nbytes
) :eof nbytes
))))))))
170 ;;;-----------------------------------------------------------------------------
171 ;;; Default DEVICE-WRITE
172 ;;;-----------------------------------------------------------------------------
174 (defmethod device-write ((device device
) vector start end
&optional timeout
)
175 (when (= start end
) (return-from device-write
0))
176 (if (and timeout
(zerop timeout
))
177 (write-octets/non-blocking device vector start end
)
178 (write-octets/timeout device vector start end timeout
)))
180 (defun write-octets/non-blocking
(device vector start end
)
181 (declare (type device device
)
182 (type ub8-simple-vector vector
)
183 (type iobuf-index start end
))
184 (with-pointer-to-vector-data (buf vector
)
186 (osicat-posix:repeat-upon-eintr
187 (nix:write
(output-handle-of device
) (inc-pointer buf start
) (- end start
)))
188 (nix:ewouldblock
() 0)
190 (nix:posix-error
(err)
191 (posix-file-error err device
"writing data to"))
193 (if (zerop nbytes
) :eof nbytes
)))))
195 (defun write-octets/timeout
(device vector start end timeout
)
196 (declare (type device device
)
197 (type ub8-simple-vector vector
)
198 (type iobuf-index start end
)
199 (type device-timeout timeout
))
200 (with-pointer-to-vector-data (buf vector
)
201 (nix:repeat-decreasing-timeout
(remaining timeout
:rloop
)
202 (flet ((check-timeout ()
203 (if (plusp remaining
)
204 (wait-for-output device remaining
)
205 (return-from :rloop
0))))
207 (nix:write
(output-handle-of device
) (inc-pointer buf start
) (- end start
))
208 (nix:eintr
() (check-timeout))
209 (nix:ewouldblock
() (check-timeout))
210 (nix:epipe
() (return-from :rloop
:eof
))
211 (nix:posix-error
(err)
212 (posix-file-error err device
"writing data to"))
215 (if (zerop nbytes
) :eof nbytes
))))))))