1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- *NIX-specific routines.
6 (in-package :iolib.zstreams
)
8 ;;;-------------------------------------------------------------------------
10 ;;;-------------------------------------------------------------------------
12 (defun compute-poll-flags (type)
14 (:input
(logior isys
:pollin isys
:pollrdhup isys
:pollpri
))
15 (:output
(logior isys
:pollout
))
16 (:io
(logior isys
:pollin isys
:pollrdhup isys
:pollpri isys
:pollout
))))
18 (defun process-poll-revents (fd event-type revents
)
20 (error 'isys
:poll-error
:code isys
:ebadf
:identifier
:ebadf
21 :os-handle fd
:event-type event-type
22 :message
"invalid OS handle")))
23 (let ((readp nil
) (rhupp nil
)
24 (writep nil
) (whupp nil
))
26 ((isys:pollin isys
:pollpri
) (setf readp t
))
27 ((isys:pollrdhup
) (setf rhupp t
))
28 ((isys:pollout
) (setf writep t
))
29 ((isys:pollhup
) (setf whupp t
))
30 ((isys:pollerr isys
: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 (isys:repeat-upon-condition-decreasing-timeout
40 ((isys:eintr
) remaining-time timeout
)
41 (isys: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 'isys
:pollfd
)
57 (isys:bzero pollfd isys
:size-of-pollfd
)
58 (with-foreign-slots ((isys:fd isys
:events isys
:revents
)
60 (setf isys
:fd file-descriptor
61 isys
:events
(compute-poll-flags event-type
))
64 ((plusp (%poll pollfd timeout
))
65 (process-poll-revents isys
:fd event-type isys
:revents
))
67 (error 'isys
:poll-timeout
68 :os-handle file-descriptor
69 :event-type event-type
)))
70 (isys:syscall-error
(err) (poll-error err
)))))))
73 ;;;-------------------------------------------------------------------------
74 ;;; Set FD nonblocking
75 ;;;-------------------------------------------------------------------------
77 (defun %set-fd-nonblock
(fd)
78 (declare (special *device
*))
80 (with-foreign-object (arg :int
)
81 (setf (mem-aref arg
:int
) 1)
82 (isys:ioctl fd isys
:fionbio arg
))
83 (isys:syscall-error
(err)
84 (posix-file-error err
*device
* "issuing FIONBIO IOCTL on")))
88 ;;;-------------------------------------------------------------------------
89 ;;; Get number of bytes availabe on FD
90 ;;;-------------------------------------------------------------------------
92 (defun %get-fd-nbytes
(fd)
93 (declare (special *device
*))
95 (with-foreign-object (arg :int
)
96 (isys:ioctl fd isys
:fionread arg
)
98 (isys:syscall-error
(err)
99 (posix-file-error err
*device
* "issuing FIONREAD IOCTL on"))))
102 ;;;-------------------------------------------------------------------------
103 ;;; File Descriptor reading
104 ;;;-------------------------------------------------------------------------
106 (defun %read-octets
/non-blocking
(fd vector start end
)
107 (declare (type ub8-simple-vector vector
)
109 (with-pointer-to-vector-data (buf vector
)
111 (isys:read fd
(inc-pointer buf start
) (- end start
))
112 (isys:ewouldblock
() 0)
113 (isys:syscall-error
(err)
114 (posix-file-error err
*device
* "reading data from"))
116 (if (zerop nbytes
) :eof nbytes
)))))
118 (defun %read-octets
/timeout
(fd vector start end timeout
)
119 (declare (type ub8-simple-vector vector
)
121 (with-pointer-to-vector-data (buf vector
)
122 (isys:repeat-decreasing-timeout
123 (remaining (clamp-timeout timeout
) :rloop
)
124 (flet ((check-timeout ()
125 (if (plusp remaining
)
126 (poll-fd fd
:input remaining
)
127 (return-from :rloop
0))))
129 (isys:read fd
(inc-pointer buf start
) (- end start
))
130 (isys:ewouldblock
() (check-timeout))
131 (isys:syscall-error
(err)
132 (posix-file-error err
*device
* "reading data from"))
135 (if (zerop nbytes
) :eof nbytes
))))))))
138 ;;;-------------------------------------------------------------------------
139 ;;; File Descriptor writing
140 ;;;-------------------------------------------------------------------------
142 (defun %write-octets
/non-blocking
(fd vector start end
)
143 (declare (type ub8-simple-vector vector
)
145 (with-pointer-to-vector-data (buf vector
)
147 (isys:write fd
(inc-pointer buf start
) (- end start
))
148 (isys:ewouldblock
() 0)
149 (isys:epipe
() :hangup
)
150 (isys:syscall-error
(err)
151 (posix-file-error err
*device
* "writing data to"))
153 (if (zerop nbytes
) :hangup nbytes
)))))
155 (defun %write-octets
/timeout
(fd vector start end timeout
)
156 (declare (type ub8-simple-vector vector
)
158 (with-pointer-to-vector-data (buf vector
)
159 (isys:repeat-decreasing-timeout
160 (remaining (clamp-timeout timeout
) :rloop
)
161 (flet ((check-timeout ()
162 (if (plusp remaining
)
163 (poll-fd fd
:output remaining
)
164 (return-from :rloop
0))))
166 (isys:write fd
(inc-pointer buf start
) (- end start
))
167 (isys:ewouldblock
() (check-timeout))
168 (isys:epipe
() (return-from :rloop
:hangup
))
169 (isys:syscall-error
(err)
170 (posix-file-error err
*device
* "writing data to"))
173 (if (zerop nbytes
) :hangup nbytes
))))))))