1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- epoll(2) multiplexer implementation.
6 (in-package :io.multiplex
)
8 (defconstant +epoll-priority
+ 1)
10 (define-multiplexer epoll-multiplexer
+epoll-priority
+ (multiplexer)
13 (defmethod print-object ((mux epoll-multiplexer
) stream
)
14 (print-unreadable-object (mux stream
:type nil
:identity nil
)
15 (format stream
"epoll(4) multiplexer")))
17 (defconstant +epoll-default-size-hint
+ 25)
18 (defconstant +epoll-max-events
+ 1024)
20 (defmethod initialize-instance :after
((mux epoll-multiplexer
)
21 &key
(size +epoll-default-size-hint
+))
22 (setf (slot-value mux
'fd
) (isys:%sys-epoll-create size
)))
24 (defun calc-epoll-flags (fd-entry)
25 (logior (if (fd-entry-read-handler fd-entry
)
28 (if (fd-entry-write-handler fd-entry
)
33 (defmethod monitor-fd ((mux epoll-multiplexer
) fd-entry
)
34 (assert fd-entry
(fd-entry) "Must supply an FD-ENTRY!")
35 (let ((flags (calc-epoll-flags fd-entry
))
36 (fd (fd-entry-fd fd-entry
)))
37 (with-foreign-object (ev 'isys
:epoll-event
)
38 (isys:%sys-bzero ev isys
:size-of-epoll-event
)
39 (setf (foreign-slot-value ev
'isys
:epoll-event
'isys
:events
) flags
)
40 (setf (foreign-slot-value
41 (foreign-slot-value ev
'isys
:epoll-event
'isys
:data
)
42 'isys
:epoll-data
'isys
:fd
)
45 (isys:%sys-epoll-ctl
(fd-of mux
) isys
:epoll-ctl-add fd ev
)
47 (warn "FD ~A is invalid, cannot monitor it." fd
))
49 (warn "FD ~A is already monitored." fd
))))))
51 (defmethod update-fd ((mux epoll-multiplexer
) fd-entry event-type edge-change
)
52 (declare (ignore event-type edge-change
))
53 (assert fd-entry
(fd-entry) "Must supply an FD-ENTRY!")
54 (let ((flags (calc-epoll-flags fd-entry
))
55 (fd (fd-entry-fd fd-entry
)))
56 (with-foreign-object (ev 'isys
:epoll-event
)
57 (isys:%sys-bzero ev isys
:size-of-epoll-event
)
58 (setf (foreign-slot-value ev
'isys
:epoll-event
'isys
:events
) flags
)
59 (setf (foreign-slot-value
60 (foreign-slot-value ev
'isys
:epoll-event
'isys
:data
)
61 'isys
:epoll-data
'isys
:fd
)
64 (isys:%sys-epoll-ctl
(fd-of mux
) isys
:epoll-ctl-mod fd ev
)
66 (warn "FD ~A is invalid, cannot update its status." fd
))
68 (warn "FD ~A was not monitored, cannot update its status." fd
))))
71 (defmethod unmonitor-fd ((mux epoll-multiplexer
) fd-entry
)
73 (isys:%sys-epoll-ctl
(fd-of mux
)
75 (fd-entry-fd fd-entry
)
78 (warn "FD ~A is invalid, cannot unmonitor it." (fd-entry-fd fd-entry
)))
80 (warn "FD ~A was not monitored, cannot unmonitor it."
81 (fd-entry-fd fd-entry
)))))
83 (defmethod harvest-events ((mux epoll-multiplexer
) timeout
)
84 (with-foreign-object (events 'isys
:epoll-event
+epoll-max-events
+)
85 (isys:%sys-bzero events
(* +epoll-max-events
+ isys
:size-of-epoll-event
))
87 (isys:repeat-upon-condition-decreasing-timeout
88 ((isys:eintr
) tmp-timeout timeout
)
89 (setf ready-fds
(isys:%sys-epoll-wait
(fd-of mux
) events
+epoll-max-events
+
90 (timeout->milisec tmp-timeout
))))
91 (macrolet ((epoll-slot (slot-name)
92 `(foreign-slot-value (mem-aref events
'isys
:epoll-event i
)
93 'isys
:epoll-event
',slot-name
)))
95 (loop :for i
:below ready-fds
96 :for fd
:= (foreign-slot-value (epoll-slot isys
:data
) 'isys
:epoll-data
'isys
:fd
)
97 :for event-mask
:= (epoll-slot isys
:events
)
98 :for epoll-event
:= (make-epoll-event fd event-mask
)
99 :when epoll-event
:collect epoll-event
))))))
101 (defun make-epoll-event (fd mask
)
104 ((isys:epollout isys
:epollhup
)
106 ((isys:epollin isys
:epollpri isys
:epollhup
)
109 (push :error event
)))