1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
3 ;;; --- epoll(2) multiplexer implementation.
6 (in-package :iolib
/multiplex
)
8 (defconstant +epoll-priority
+ 1)
10 (define-multiplexer epoll-multiplexer
+epoll-priority
+ (multiplexer)
11 ((events :reader event-set-of
)))
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 (defmethod initialize-instance :after
((mux epoll-multiplexer
) &key
(size 25))
18 (setf (slot-value mux
'fd
) (isys:epoll-create size
))
19 (setf (slot-value mux
'events
)
20 (foreign-alloc 'isys
:epoll-event
:count
(fd-limit-of mux
))))
22 (defmethod close :after
((mux epoll-multiplexer
) &key abort
)
23 (declare (ignore abort
))
24 (with-slots (events) mux
29 (defun calc-epoll-flags (fd-entry)
30 (logior (if (fd-entry-read-handler fd-entry
)
33 (if (fd-entry-write-handler fd-entry
)
38 (defmethod monitor-fd ((mux epoll-multiplexer
) fd-entry
)
39 (assert fd-entry
(fd-entry) "Must supply an FD-ENTRY!")
40 (let ((flags (calc-epoll-flags fd-entry
))
41 (fd (fd-entry-fd fd-entry
)))
42 (with-foreign-object (ev 'isys
:epoll-event
)
43 (isys:bzero ev
(isys:sizeof
'isys
:epoll-event
))
44 (setf (foreign-slot-value ev
'isys
:epoll-event
'isys
:events
) flags
)
45 (setf (foreign-slot-value
46 (foreign-slot-value ev
'isys
:epoll-event
'isys
:data
)
47 'isys
:epoll-data
'isys
:fd
)
50 (isys:epoll-ctl
(fd-of mux
) isys
:epoll-ctl-add fd ev
)
52 (warn "FD ~A is invalid, cannot monitor it." fd
))
54 (warn "FD ~A is already monitored." fd
))))))
56 (defmethod update-fd ((mux epoll-multiplexer
) fd-entry event-type edge-change
)
57 (declare (ignore event-type edge-change
))
58 (assert fd-entry
(fd-entry) "Must supply an FD-ENTRY!")
59 (let ((flags (calc-epoll-flags fd-entry
))
60 (fd (fd-entry-fd fd-entry
)))
61 (with-foreign-object (ev 'isys
:epoll-event
)
62 (isys:bzero ev
(isys:sizeof
'isys
:epoll-event
))
63 (setf (foreign-slot-value ev
'isys
:epoll-event
'isys
:events
) flags
)
64 (setf (foreign-slot-value
65 (foreign-slot-value ev
'isys
:epoll-event
'isys
:data
)
66 'isys
:epoll-data
'isys
:fd
)
69 (isys:epoll-ctl
(fd-of mux
) isys
:epoll-ctl-mod fd ev
)
71 (warn "FD ~A is invalid, cannot update its status." fd
))
73 (warn "FD ~A was not monitored, cannot update its status." fd
))))
76 (defmethod unmonitor-fd ((mux epoll-multiplexer
) fd-entry
)
78 (isys:epoll-ctl
(fd-of mux
)
80 (fd-entry-fd fd-entry
)
83 (warn "FD ~A is invalid, cannot unmonitor it." (fd-entry-fd fd-entry
)))
85 (warn "FD ~A was not monitored, cannot unmonitor it."
86 (fd-entry-fd fd-entry
)))))
88 (defmethod harvest-events ((mux epoll-multiplexer
) timeout
)
89 (with-accessors ((events event-set-of
)
90 (fd-limit fd-limit-of
))
92 (isys:bzero events
(* fd-limit
(isys:sizeof
'isys
:epoll-event
)))
94 (isys:repeat-upon-condition-decreasing-timeout
95 ((isys:eintr
) tmp-timeout timeout
)
96 (setf ready-fds
(isys:epoll-wait
(fd-of mux
) events fd-limit
97 (timeout->milliseconds tmp-timeout
))))
98 (macrolet ((epoll-slot (slot-name)
99 `(foreign-slot-value (mem-aref events
'isys
:epoll-event i
)
100 'isys
:epoll-event
',slot-name
)))
102 (loop :for i
:below ready-fds
103 :for fd
:= (foreign-slot-value (epoll-slot isys
:data
) 'isys
:epoll-data
'isys
:fd
)
104 :for event-mask
:= (epoll-slot isys
:events
)
105 :for epoll-event
:= (make-epoll-event fd event-mask
)
106 :when epoll-event
:collect epoll-event
))))))
108 (defun make-epoll-event (fd mask
)
111 ((isys:epollout isys
:epollhup
)
113 ((isys:epollin isys
:epollpri isys
:epollhup
)
116 (push :error event
)))