1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Wait for events on single FDs.
6 (in-package :io.multiplex
)
8 ;;; FIXME: Until a way to autodetect platform features is implemented
10 (define-constant pollrdhup
0)
12 (define-condition poll-error
(error)
13 ((fd :initarg
:fd
:reader poll-error-fd
)
14 (identifier :initarg
:identifier
:initform
"Unknown error"
15 :reader poll-error-identifier
))
16 (:report
(lambda (condition stream
)
17 (format stream
"Error caught while polling file descriptor ~A: ~A"
18 (poll-error-fd condition
)
19 (poll-error-identifier condition
))))
21 "Signaled when an error occurs while polling for I/O readiness
22 of a file descriptor."))
24 (define-condition poll-timeout
(condition)
25 ((fd :initarg
:fd
:reader poll-timeout-fd
)
26 (event-type :initarg
:event-type
:reader poll-timeout-event-type
))
27 (:report
(lambda (condition stream
)
28 (format stream
"Timeout occurred while polling file descriptor ~A for event ~S"
29 (poll-timeout-fd condition
)
30 (poll-timeout-event-type condition
))))
32 "Signaled when a timeout occurs while polling for I/O readiness
33 of a file descriptor."))
35 (defun compute-poll-flags (type)
37 (:input
(logior pollin pollrdhup pollpri
))
38 (:output
(logior pollout
))
39 (:io
(logior pollin pollrdhup pollpri pollout
))))
41 (defun process-poll-revents (revents fd
)
42 (let ((readp nil
) (writep nil
))
44 ((pollin pollrdhup pollpri
)
46 ((pollout pollhup
) (setf writep t
))
47 ((pollerr) (error 'poll-error
:fd fd
))
48 ((pollnval) (error 'poll-error
:fd fd
49 :identifier
"Invalid file descriptor")))
50 (values readp writep
)))
52 (defun wait-until-fd-ready (file-descriptor event-type
&optional timeout errorp
)
53 "Poll file descriptor `FILE-DESCRIPTOR' for I/O readiness.
54 `EVENT-TYPE' must be either :INPUT, :OUTPUT or :IO.
55 `TIMEOUT' must be either a non-negative integer measured in seconds,
56 or `NIL' meaning no timeout at all. If `ERRORP' is not NIL and a timeout
57 occurs, then a condition of type `POLL-TIMEOUT' is signaled.
58 Returns two boolean values indicating readability and writeability of `FILE-DESCRIPTOR'."
59 (flet ((poll-error (unix-err)
60 (error 'poll-error
:fd file-descriptor
61 :identifier
(osicat-sys:system-error-identifier unix-err
))))
62 (with-foreign-object (pollfd 'pollfd
)
63 (bzero pollfd size-of-pollfd
)
64 (with-foreign-slots ((fd events revents
) pollfd pollfd
)
65 (setf fd file-descriptor
66 events
(compute-poll-flags event-type
))
68 (let ((ret (nix:repeat-upon-condition-decreasing-timeout
69 ((nix:eintr
) remaining-time timeout
)
70 (poll pollfd
1 (timeout->milisec remaining-time
)))))
73 (error 'poll-timeout
:fd file-descriptor
:event-type event-type
)
74 (return* (values nil nil
)))))
75 (nix:posix-error
(err) (poll-error err
)))
76 (process-poll-revents revents file-descriptor
)))))
78 (defun fd-ready-p (fd &optional
(event-type :input
))
79 "Tests file-descriptor `FD' for I/O readiness.
80 `EVENT-TYPE' must be either :INPUT, :OUTPUT or :IO ."
81 (multiple-value-bind (readp writep
)
82 (wait-until-fd-ready fd event-type
0)
86 (:io
(or readp writep
)))))
88 (defun fd-readablep (fd)
89 (nth-value 0 (wait-until-fd-ready fd
:input
0)))
91 (defun fd-writablep (fd)
92 (nth-value 1 (wait-until-fd-ready fd
:output
0)))