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))
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 (with-device (device)
131 (if (and timeout
(zerop timeout
))
132 (read-octets/non-blocking device vector start end
)
133 (read-octets/timeout device vector start end timeout
))))
135 (defun read-octets/non-blocking
(device vector start end
)
136 (declare (type device device
)
137 (type ub8-simple-vector vector
)
138 (type iobuf-index start end
))
139 (with-pointer-to-vector-data (buf vector
)
141 (nix:repeat-upon-eintr
142 (nix:read
(input-handle-of device
) (inc-pointer buf start
) (- end start
)))
143 (nix:ewouldblock
() 0)
144 (nix:posix-error
(err)
145 (posix-file-error err device
"reading data from"))
147 (if (zerop nbytes
) :eof nbytes
)))))
149 (defun read-octets/timeout
(device vector start end timeout
)
150 (declare (type device device
)
151 (type ub8-simple-vector vector
)
152 (type iobuf-index start end
)
153 (type device-timeout timeout
))
154 (with-pointer-to-vector-data (buf vector
)
155 (nix:repeat-decreasing-timeout
(remaining timeout
:rloop
)
156 (flet ((check-timeout ()
157 (if (plusp remaining
)
158 (wait-for-input device remaining
)
159 (return-from :rloop
0))))
161 (nix:read
(input-handle-of device
) (inc-pointer buf start
) (- end start
))
162 (nix:eintr
() (check-timeout))
163 (nix:ewouldblock
() (check-timeout))
164 (nix:posix-error
(err)
165 (posix-file-error err device
"reading data from"))
168 (if (zerop nbytes
) :eof nbytes
))))))))
171 ;;;-----------------------------------------------------------------------------
172 ;;; Default DEVICE-WRITE
173 ;;;-----------------------------------------------------------------------------
175 (defmethod device-write ((device device
) vector start end
&optional timeout
)
176 (when (= start end
) (return-from device-write
0))
177 (with-device (device)
178 (if (and timeout
(zerop timeout
))
179 (write-octets/non-blocking device vector start end
)
180 (write-octets/timeout device vector start end timeout
))))
182 (defun write-octets/non-blocking
(device vector start end
)
183 (declare (type device device
)
184 (type ub8-simple-vector vector
)
185 (type iobuf-index start end
))
186 (with-pointer-to-vector-data (buf vector
)
188 (osicat-posix:repeat-upon-eintr
189 (nix:write
(output-handle-of device
) (inc-pointer buf start
) (- end start
)))
190 (nix:ewouldblock
() 0)
192 (nix:posix-error
(err)
193 (posix-file-error err device
"writing data to"))
195 (if (zerop nbytes
) :eof nbytes
)))))
197 (defun write-octets/timeout
(device vector start end timeout
)
198 (declare (type device device
)
199 (type ub8-simple-vector vector
)
200 (type iobuf-index start end
)
201 (type device-timeout timeout
))
202 (with-pointer-to-vector-data (buf vector
)
203 (nix:repeat-decreasing-timeout
(remaining timeout
:rloop
)
204 (flet ((check-timeout ()
205 (if (plusp remaining
)
206 (wait-for-output device remaining
)
207 (return-from :rloop
0))))
209 (nix:write
(output-handle-of device
) (inc-pointer buf start
) (- end start
))
210 (nix:eintr
() (check-timeout))
211 (nix:ewouldblock
() (check-timeout))
212 (nix:epipe
() (return-from :rloop
:eof
))
213 (nix:posix-error
(err)
214 (posix-file-error err device
"writing data to"))
217 (if (zerop nbytes
) :eof nbytes
))))))))