Skip to content

Commit

Permalink
Make epoll-multiplexer thread safe
Browse files Browse the repository at this point in the history
Instead of a preallocated slot use WITH-FOREIGN-OBJECT to allocate
the events array, and thus make HARVEST-EVENTS safe for concurrent calls.
  • Loading branch information
attila-lendvai committed Aug 27, 2015
1 parent 2b93a8a commit 57f603a
Showing 1 changed file with 19 additions and 28 deletions.
47 changes: 19 additions & 28 deletions src/multiplex/backend-epoll.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,14 @@
(defconstant +epoll-priority+ 1)

(define-multiplexer epoll-multiplexer +epoll-priority+ (multiplexer)
((events :reader event-set-of)))
())

(defmethod print-object ((mux epoll-multiplexer) stream)
(print-unreadable-object (mux stream :type nil :identity nil)
(format stream "epoll(4) multiplexer")))

(defmethod initialize-instance :after ((mux epoll-multiplexer) &key (size 25))
(setf (slot-value mux 'fd) (isys:epoll-create size))
(setf (slot-value mux 'events)
(foreign-alloc 'isys:epoll-event :count (fd-limit-of mux))))

(defmethod close :after ((mux epoll-multiplexer) &key abort)
(declare (ignore abort))
(with-slots (events) mux
(when events
(foreign-free events)
(setf events nil))))
(setf (slot-value mux 'fd) (isys:epoll-create size)))

(defun calc-epoll-flags (fd-entry)
(logior (if (fd-entry-read-handler fd-entry)
Expand Down Expand Up @@ -86,24 +77,24 @@
(fd-entry-fd fd-entry)))))

(defmethod harvest-events ((mux epoll-multiplexer) timeout)
(with-accessors ((events event-set-of)
(fd-limit fd-limit-of))
(with-accessors ((fd-limit fd-limit-of))
mux
(isys:bzero events (* fd-limit (isys:sizeof 'isys:epoll-event)))
(let (ready-fds)
(isys:repeat-upon-condition-decreasing-timeout
((isys:eintr) tmp-timeout timeout)
(setf ready-fds (isys:epoll-wait (fd-of mux) events fd-limit
(timeout->milliseconds tmp-timeout))))
(macrolet ((epoll-slot (slot-name)
`(foreign-slot-value (mem-aref events 'isys:epoll-event i)
'isys:epoll-event ',slot-name)))
(return*
(loop :for i :below ready-fds
:for fd := (foreign-slot-value (epoll-slot isys:data) 'isys:epoll-data 'isys:fd)
:for event-mask := (epoll-slot isys:events)
:for epoll-event := (make-epoll-event fd event-mask)
:when epoll-event :collect epoll-event))))))
(with-foreign-object (events 'isys:epoll-event fd-limit)
(isys:bzero events (* fd-limit (isys:sizeof 'isys:epoll-event)))
(let (ready-fds)
(isys:repeat-upon-condition-decreasing-timeout
((isys:eintr) tmp-timeout timeout)
(setf ready-fds (isys:epoll-wait (fd-of mux) events fd-limit
(timeout->milliseconds tmp-timeout))))
(macrolet ((epoll-slot (slot-name)
`(foreign-slot-value (mem-aref events 'isys:epoll-event i)
'isys:epoll-event ',slot-name)))
(return*
(loop :for i :below ready-fds
:for fd := (foreign-slot-value (epoll-slot isys:data) 'isys:epoll-data 'isys:fd)
:for event-mask := (epoll-slot isys:events)
:for epoll-event := (make-epoll-event fd event-mask)
:when epoll-event :collect epoll-event)))))))

(defun make-epoll-event (fd mask)
(let ((event ()))
Expand Down

0 comments on commit 57f603a

Please sign in to comment.