1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- *NIX-specific routines.
6 (in-package :io.zeta-streams
)
8 ;;;-------------------------------------------------------------------------
10 ;;;-------------------------------------------------------------------------
12 (defun compute-poll-flags (type)
14 (:input
(logior pollin pollrdhup pollpri
))
15 (:output
(logior pollout
))
16 (:io
(logior pollin pollrdhup pollpri pollout
))))
18 (defun process-poll-revents (fd event-type revents
)
20 (error 'poll-error
:code ebadf
:identifier
:ebadf
21 :event-type event-type
:os-handle fd
22 :message
"invalid OS handle")))
23 (let ((readp nil
) (rhupp nil
)
24 (writep nil
) (whupp nil
))
26 ((pollin pollpri
) (setf readp t
))
27 ((pollrdhup) (setf rhupp t
))
28 ((pollout) (setf writep t
))
29 ((pollhup) (setf whupp t
))
30 ((pollerr pollnval
) (poll-error)))
31 (values readp rhupp writep whupp
))))
33 (defun timeout->milisec
(timeout)
34 (multiple-value-bind (sec usec
)
35 (decode-timeout timeout
)
36 (+ (* sec
1000) (truncate usec
1000))))
38 (defun %poll
(fds timeout
)
39 (repeat-upon-condition-decreasing-timeout
40 ((eintr) remaining-time timeout
)
41 (%sys-poll fds
1 (timeout->milisec remaining-time
))))
43 (defun poll-fd (file-descriptor event-type timeout
)
44 "Poll file descriptor `FD' for I/O readiness. `EVENT-TYPE' must be either
45 :INPUT, :OUTPUT or :IO. `TIMEOUT' must be a non-negative real measured
46 in seconds. If a timeout occurs `POLL-TIMEOUT' is signaled.
47 Returns two boolean values indicating readability and writeability of `FD'."
48 (flet ((poll-error (posix-err)
50 :code
(posix-file-error-code posix-err
)
51 :identifier
(posix-file-error-identifier posix-err
)
52 :event-type event-type
53 :os-handle file-descriptor
54 :message
(format nil
"OS error ~A"
55 (posix-file-error-identifier posix-err
)))))
56 (with-foreign-object (pollfd 'pollfd
)
57 (%sys-bzero pollfd size-of-pollfd
)
58 (with-foreign-slots ((fd events revents
) pollfd pollfd
)
59 (setf fd file-descriptor
60 events
(compute-poll-flags event-type
))
63 ((plusp (%poll pollfd timeout
))
64 (process-poll-revents fd event-type revents
))
67 :os-handle file-descriptor
68 :event-type event-type
)))
69 (posix-error (err) (poll-error err
)))))))
72 ;;;-------------------------------------------------------------------------
73 ;;; Set FD nonblocking
74 ;;;-------------------------------------------------------------------------
76 (defun %set-fd-nonblock
(fd)
77 (declare (special *device
*))
79 (with-foreign-object (arg :int
)
80 (setf (mem-aref arg
:int
) 1)
81 (%sys-ioctl
/3 fd fionbio arg
))
83 (posix-file-error err
*device
* "issuing FIONBIO IOCTL on")))
87 ;;;-------------------------------------------------------------------------
88 ;;; Get number of bytes availabe on FD
89 ;;;-------------------------------------------------------------------------
91 (defun %get-fd-nbytes
(fd)
92 (declare (special *device
*))
94 (with-foreign-object (arg :int
)
95 (%sys-ioctl
/3 fd fionread arg
)
98 (posix-file-error err
*device
* "issuing FIONREAD IOCTL on"))))
101 ;;;-------------------------------------------------------------------------
102 ;;; File Descriptor reading
103 ;;;-------------------------------------------------------------------------
105 (defun %read-octets
/non-blocking
(fd vector start end
)
106 (declare (type ub8-simple-vector vector
)
108 (with-pointer-to-vector-data (buf vector
)
110 (%sys-read fd
(inc-pointer buf start
) (- end start
))
113 (posix-file-error err
*device
* "reading data from"))
115 (if (zerop nbytes
) :eof nbytes
)))))
117 (defun %read-octets
/timeout
(fd vector start end timeout
)
118 (declare (type ub8-simple-vector vector
)
120 (with-pointer-to-vector-data (buf vector
)
121 (repeat-decreasing-timeout (remaining (clamp-timeout timeout
) :rloop
)
122 (flet ((check-timeout ()
123 (if (plusp remaining
)
124 (poll-fd fd
:input remaining
)
125 (return-from :rloop
0))))
127 (%sys-read fd
(inc-pointer buf start
) (- end start
))
128 (ewouldblock () (check-timeout))
130 (posix-file-error err
*device
* "reading data from"))
133 (if (zerop nbytes
) :eof nbytes
))))))))
136 ;;;-------------------------------------------------------------------------
137 ;;; File Descriptor writing
138 ;;;-------------------------------------------------------------------------
140 (defun %write-octets
/non-blocking
(fd vector start end
)
141 (declare (type ub8-simple-vector vector
)
143 (with-pointer-to-vector-data (buf vector
)
145 (%sys-write fd
(inc-pointer buf start
) (- end start
))
149 (posix-file-error err
*device
* "writing data to"))
151 (if (zerop nbytes
) :hangup nbytes
)))))
153 (defun %write-octets
/timeout
(fd vector start end timeout
)
154 (declare (type ub8-simple-vector vector
)
156 (with-pointer-to-vector-data (buf vector
)
157 (repeat-decreasing-timeout (remaining (clamp-timeout timeout
) :rloop
)
158 (flet ((check-timeout ()
159 (if (plusp remaining
)
160 (poll-fd fd
:output remaining
)
161 (return-from :rloop
0))))
163 (%sys-write fd
(inc-pointer buf start
) (- end start
))
164 (ewouldblock () (check-timeout))
165 (epipe () (return-from :rloop
:hangup
))
167 (posix-file-error err
*device
* "writing data to"))
170 (if (zerop nbytes
) :hangup nbytes
))))))))