1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
3 ;;; --- poll(2) multiplexer implementation.
6 (in-package :iolib.multiplex
)
8 (defconstant +poll-priority
+ 2)
10 (define-multiplexer poll-multiplexer
+poll-priority
+ (multiplexer)
11 ((fd-set :initform
(allocate-pollfd-set) :accessor fd-set-of
)
12 (fd-set-size :initform
5 :accessor fd-set-size-of
)
13 (fd-count :initform
0 :accessor fd-count-of
)))
15 (defun allocate-pollfd-set (&optional
(count 5))
16 (let ((fds (foreign-alloc 'nix
::pollfd
:count count
)))
17 (nix:bzero fds
(* nix
::size-of-pollfd count
))
20 (defmethod print-object ((mux poll-multiplexer
) stream
)
21 (print-unreadable-object (mux stream
:type nil
:identity nil
)
22 (format stream
"poll(2) multiplexer")))
24 (defmethod close-multiplexer progn
((mux poll-multiplexer
))
25 (foreign-free (fd-set-of mux
))
26 (setf (fd-set-of mux
) nil
))
28 (defvar *pollfd-table
* (make-hash-table :test
#'eql
))
30 (defun calc-pollfd-flags (readp writep
)
32 (when readp
(setf flags
(logior nix
:pollin nix
:pollrdhup nix
:pollpri
)))
33 (when writep
(setf flags
(logior flags nix
:pollout nix
:pollhup
)))
36 (defun set-pollfd-entry (fd-set index fd readp writep
)
37 (with-foreign-slots ((nix::fd nix
::events nix
::revents
)
38 (mem-aref fd-set
'nix
::pollfd index
)
42 nix
::events
(calc-pollfd-flags readp writep
))))
44 (defun extend-pollfd-set (fd-set size
)
45 (let* ((new-size (+ size
5))
46 (new-fd-set (foreign-alloc 'nix
::pollfd
:count new-size
)))
47 (nix:memcpy new-fd-set fd-set
(* size nix
::size-of-pollfd
))
49 (values new-fd-set new-size
)))
51 (defmethod monitor-fd ((mux poll-multiplexer
) fd-entry
)
52 (let ((fd (fd-entry-fd fd-entry
))
53 (readp (fd-entry-read-handler fd-entry
))
54 (writep (fd-entry-write-handler fd-entry
)))
55 (with-accessors ((fd-set fd-set-of
) (size fd-set-size-of
)
56 (count fd-count-of
)) mux
58 (setf (values fd-set size
) (extend-pollfd-set fd-set size
)))
59 (set-pollfd-entry fd-set count fd readp writep
)
60 (setf (gethash fd
*pollfd-table
*) count
)
63 (defmethod update-fd ((mux poll-multiplexer
) fd-entry event-type edge-change
)
64 (declare (ignore event-type edge-change
))
65 (let* ((fd (fd-entry-fd fd-entry
))
66 (pos (gethash fd
*pollfd-table
*))
67 (readp (fd-entry-read-handler fd-entry
))
68 (writep (fd-entry-write-handler fd-entry
)))
69 (with-accessors ((fd-set fd-set-of
)) mux
70 (set-pollfd-entry fd-set pos fd readp writep
))))
72 (defun shrink-pollfd-set (fd-set count size pos
)
73 (let* ((new-size (if (> 5 (- size count
)) (- size
5) size
))
74 (new-fd-set (foreign-alloc 'nix
::pollfd
:count new-size
)))
76 (nix:memcpy new-fd-set fd-set
(* pos nix
::size-of-pollfd
)))
78 (nix:memcpy new-fd-set fd-set
(* (- count pos
) nix
::size-of-pollfd
)))
80 (values new-fd-set new-size
)))
82 (defmethod unmonitor-fd ((mux poll-multiplexer
) fd-entry
)
83 (let* ((fd (fd-entry-fd fd-entry
))
84 (pos (gethash fd
*pollfd-table
*)))
85 (with-accessors ((fd-set fd-set-of
) (size fd-set-size-of
)
86 (count fd-count-of
)) mux
87 (setf (values fd-set size
) (shrink-pollfd-set fd-set
(1- count
) size pos
))
88 (remhash fd
*pollfd-table
*)
91 (defmethod harvest-events ((mux poll-multiplexer
) timeout
)
92 (with-accessors ((fd-set fd-set-of
) (size fd-set-size-of
)
93 (count fd-count-of
)) mux
94 ;; if there are no fds set and timeout is NULL
95 ;; poll() blocks forever
96 (when (and (zerop count
)
98 (warn "Non fds to monitor and no timeout set !")
100 ;; FIXME: when does poll() return EBADF ?
101 (nix:repeat-upon-condition-decreasing-timeout
102 ((nix:eintr
) tmp-timeout timeout
)
103 (nix:poll fd-set count
(timeout->milliseconds tmp-timeout
)))
104 (harvest-pollfd-events fd-set count
)))
106 (defun harvest-pollfd-events (fd-set count
)
107 (macrolet ((pollfd-slot (name index
)
108 `(foreign-slot-value (mem-aref fd-set
'nix
::pollfd
,index
)
109 'nix
::pollfd
,name
)))
110 (loop :for i
:below count
112 :for fd
:= (pollfd-slot 'nix
::fd i
)
113 :for revents
:= (pollfd-slot 'nix
::revents i
)
114 :do
(flags-case revents
115 ((nix:pollout nix
:pollhup
) (push :write event
))
116 ((nix:pollin nix
:pollrdhup nix
:pollpri
) (push :read event
))
117 ((nix:pollerr nix
:pollnval
) (push :error event
)))
118 :when event
:collect
(list fd event
))))