1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Device buffers.
6 (in-package :io.zeta-streams
)
8 ;;;-------------------------------------------------------------------------
10 ;;;-------------------------------------------------------------------------
13 ((synchronized :initarg
:synchronized
14 :reader synchronizedp
)
18 (input-iobuf :initarg
:input-buffer
19 :accessor input-iobuf-of
)
20 (output-iobuf :initarg
:output-buffer
21 :accessor output-iobuf-of
))
22 (:default-initargs
:synchronized nil
))
24 (defclass single-channel-buffer
(buffer)
25 ((last-io-op :initform nil
:accessor last-io-op-of
)))
27 (defclass dual-channel-buffer
(buffer) ())
30 ;;;-------------------------------------------------------------------------
32 ;;;-------------------------------------------------------------------------
34 (defgeneric buffer-fill
(buffer &key timeout
))
36 (defgeneric buffer-flush
(buffer &key timeout
))
38 (defgeneric buffer-wait-until-flushable
(buffer &key timeout
))
40 (defgeneric buffer-clear-input
(buffer))
42 (defgeneric buffer-clear-output
(buffer))
44 ;;; Internal functions
46 (defgeneric %buffer-read-vector
(buffer vector start end timeout
))
48 (defgeneric %buffer-write-vector
(buffer vector start end timeout
))
50 (defgeneric %buffer-fill
(buffer timeout
))
52 (defgeneric %buffer-flush
(buffer timeout
))
54 (defgeneric %buffer-clear-input
(buffer))
56 (defgeneric %buffer-clear-output
(buffer))
59 ;;;-------------------------------------------------------------------------
61 ;;;-------------------------------------------------------------------------
63 (defmacro with-synchronized-buffer
((buffer &optional direction
) &body body
)
64 (with-gensyms (body-fun)
65 (labels ((make-locks (body direction
)
69 ((iobuf-lock (input-iobuf-of ,buffer
)))
73 ((iobuf-lock (output-iobuf-of ,buffer
)))
76 (make-locks (make-locks body
:output
) :input
)))))
77 `(flet ((,body-fun
() ,@body
))
78 (if (synchronizedp ,buffer
)
79 ,(make-locks `(,body-fun
) direction
)
83 ;;;-------------------------------------------------------------------------
85 ;;;-------------------------------------------------------------------------
87 (defmethod initialize-instance :after
88 ((buffer single-channel-buffer
) &key data size
)
89 (with-accessors ((device device-of
)
90 (input-iobuf input-iobuf-of
)
91 (output-iobuf output-iobuf-of
))
93 (check-type device device
)
94 (check-type data
(or null iobuf
))
95 (setf input-iobuf
(or data
(make-iobuf size
))
96 output-iobuf input-iobuf
)))
98 (defmethod initialize-instance :after
99 ((buffer dual-channel-buffer
)
100 &key input-data output-data input-size output-size
)
101 (with-accessors ((device device-of
)
102 (input-iobuf input-iobuf-of
)
103 (output-iobuf output-iobuf-of
))
105 (check-type device device
)
106 (check-type input-data
(or null iobuf
))
107 (check-type output-data
(or null iobuf
))
108 (setf input-iobuf
(or input-data
(make-iobuf input-size
)))
109 (setf output-iobuf
(or output-data
(make-iobuf output-size
)))))
112 ;;;-------------------------------------------------------------------------
114 ;;;-------------------------------------------------------------------------
116 (defmethod relinquish ((buffer single-channel-buffer
) &key abort
)
117 (with-accessors ((device device-of
))
119 (with-synchronized-buffer (buffer :input
)
120 (unless (or abort
(eql :read
(last-io-op-of buffer
)))
121 (%buffer-flush buffer
0))
122 (relinquish device
)))
125 (defmethod relinquish ((buffer dual-channel-buffer
) &key abort
)
126 (with-accessors ((device device-of
))
128 (with-synchronized-buffer (buffer :io
)
130 (%buffer-flush buffer
0))
131 (relinquish device
)))
135 ;;;-------------------------------------------------------------------------
137 ;;;-------------------------------------------------------------------------
139 (defmethod device-read :around
((buffer buffer
) vector
&key
140 (start 0) end timeout
)
141 (check-bounds vector start end
)
144 (call-next-method buffer vector
:start start
145 :end end
:timeout timeout
)))
147 (defmethod device-read ((buffer single-channel-buffer
) vector
148 &key start end timeout
)
149 (with-synchronized-buffer (buffer :input
)
150 (%buffer-read-vector buffer vector start end timeout
)))
152 (defmethod device-read ((buffer dual-channel-buffer
) vector
153 &key start end timeout
)
154 (with-synchronized-buffer (buffer :input
)
155 (%buffer-read-vector buffer vector start end timeout
)))
157 (defmethod %buffer-read-vector
((buffer buffer
) vector start end timeout
)
158 (with-accessors ((input-iobuf input-iobuf-of
)
159 (output-iobuf output-iobuf-of
))
162 ((iobuf-empty-p input-iobuf
)
163 (let ((nbytes (%buffer-fill buffer timeout
)))
164 (if (iobuf-empty-p input-iobuf
)
165 (if (eql :eof nbytes
) :eof
0)
166 (iobuf->vector input-iobuf vector start end
))))
168 (iobuf->vector input-iobuf vector start end
)))))
171 ;;;-------------------------------------------------------------------------
173 ;;;-------------------------------------------------------------------------
175 (defmethod device-write :around
((buffer buffer
) vector
176 &key
(start 0) end timeout
)
177 (check-bounds vector start end
)
180 (call-next-method buffer vector
:start start
181 :end end
:timeout timeout
)))
183 (defmethod device-write ((buffer single-channel-buffer
) vector
184 &key start end timeout
)
185 (with-synchronized-buffer (buffer :output
)
186 ;; If the previous operation was a read, flush the read buffer
187 ;; and reposition the file offset accordingly
188 (%buffer-clear-input buffer
)
189 (%buffer-write-vector buffer vector start end timeout
)))
191 (defmethod device-write ((buffer dual-channel-buffer
) vector
192 &key start end timeout
)
193 (with-synchronized-buffer (buffer :output
)
194 (%buffer-write-vector buffer vector start end timeout
)))
196 (defmethod %buffer-write-vector
((buffer buffer
) vector start end timeout
)
197 (with-accessors ((output-iobuf output-iobuf-of
))
199 (multiple-value-prog1
200 (vector->iobuf output-iobuf vector start end
)
201 (setf (last-io-op-of buffer
) :write
)
202 (when (iobuf-full-p output-iobuf
)
203 (%buffer-flush buffer timeout
)))))
206 ;;;-------------------------------------------------------------------------
208 ;;;-------------------------------------------------------------------------
210 (defmethod device-position ((buffer single-channel-buffer
))
211 (with-synchronized-buffer (buffer :input
)
212 (%buffer-position buffer
)))
214 (defun %buffer-position
(buffer)
215 (let ((position (device-position (device-of buffer
))))
216 (ecase (last-io-op-of buffer
)
218 (- position
(iobuf-available-octets (input-iobuf-of buffer
))))
220 (+ position
(iobuf-available-octets (output-iobuf-of buffer
)))))))
222 (defmethod (setf device-position
)
223 (position (buffer single-channel-buffer
) &optional
(from :start
))
224 (setf (%buffer-position buffer from
) position
))
226 (defun (setf %buffer-position
) (position buffer from
)
227 (setf (device-position (device-of buffer
) from
) position
))
230 ;;;-------------------------------------------------------------------------
232 ;;;-------------------------------------------------------------------------
234 (defmethod buffer-clear-input ((buffer single-channel-buffer
))
235 (with-synchronized-buffer (buffer :input
)
236 (%buffer-clear-input buffer
)))
238 (defmethod %buffer-clear-input
((buffer single-channel-buffer
))
239 (when (eql :read
(last-io-op-of buffer
))
240 (let ((nbytes (iobuf-available-octets (input-iobuf-of buffer
))))
241 (unless (zerop nbytes
)
242 (setf (%buffer-position buffer
:current
) (- nbytes
)))
243 (iobuf-reset (input-iobuf-of buffer
)))))
245 (defmethod buffer-clear-input ((buffer buffer
))
246 (with-synchronized-buffer (buffer :input
)
247 (%buffer-clear-input buffer
)))
249 (defmethod %buffer-clear-input
((buffer dual-channel-buffer
))
250 (iobuf-reset (input-iobuf-of buffer
)))
253 ;;;-------------------------------------------------------------------------
255 ;;;-------------------------------------------------------------------------
257 (defmethod buffer-clear-output ((buffer single-channel-buffer
))
258 (with-synchronized-buffer (buffer :output
)
259 (%buffer-clear-output buffer
)))
261 (defmethod %buffer-clear-output
((buffer single-channel-buffer
))
262 (when (eql :write
(last-io-op-of buffer
))
263 (iobuf-reset (output-iobuf-of buffer
))))
265 (defmethod buffer-clear-output ((buffer dual-channel-buffer
))
266 (with-synchronized-buffer (buffer :output
)
267 (iobuf-reset (output-iobuf-of buffer
))))
270 ;;;-------------------------------------------------------------------------
272 ;;;-------------------------------------------------------------------------
274 (defmethod buffer-fill ((buffer single-channel-buffer
) &key timeout
)
275 (with-synchronized-buffer (buffer :input
)
276 (%buffer-clear-output buffer
)
277 (%buffer-fill buffer timeout
)))
279 (defmethod buffer-fill ((buffer dual-channel-buffer
) &key timeout
)
280 (with-synchronized-buffer (buffer :input
)
281 (%buffer-fill buffer timeout
)))
283 (defmethod %buffer-fill
((buffer buffer
) timeout
)
284 (with-accessors ((device device-of
)
285 (input-iobuf input-iobuf-of
))
287 (multiple-value-bind (data start end
)
288 (iobuf-next-empty-zone input-iobuf
)
290 (device-read device data
:start start
291 :end end
:timeout timeout
)))
292 (setf (iobuf-end input-iobuf
) (+ start nbytes
))
293 (setf (last-io-op-of buffer
) :read
)
297 ;;;-------------------------------------------------------------------------
299 ;;;-------------------------------------------------------------------------
301 (defmethod buffer-flush ((buffer single-channel-buffer
) &key timeout
)
302 (with-synchronized-buffer (buffer :output
)
303 (when (eql :write
(last-io-op-of buffer
))
304 (%buffer-flush buffer timeout
))))
306 (defmethod buffer-flush ((buffer dual-channel-buffer
) &key timeout
)
307 (with-synchronized-buffer (buffer :output
)
308 (%buffer-flush buffer timeout
)))
310 (defmethod %buffer-flush
((buffer buffer
) timeout
)
311 (with-accessors ((device device-of
)
312 (output-iobuf output-iobuf-of
))
314 (multiple-value-bind (data start end
)
315 (iobuf-next-data-zone output-iobuf
)
317 (device-write device data
:start start
318 :end end
:timeout timeout
)))
319 (setf (iobuf-start output-iobuf
) (+ start nbytes
))
320 (setf (last-io-op-of buffer
) :write
)
321 (iobuf-available-octets output-iobuf
)))))
324 ;;;-------------------------------------------------------------------------
326 ;;;-------------------------------------------------------------------------
328 (defmethod buffer-wait-until-flushable ((buffer buffer
) &key timeout
)
329 (device-poll-output (device-of buffer
) :timeout timeout
))