Hello, Here are some patches that make it easier to just use the multiplexer object without having to go through the provided event loop/timer machinery. This is done in three steps: make the monitor/harvest etc. methods on multiplexer accept just file descriptors as well as FD-ENTRYs (note that I've only done that for epoll in this set of patches, others to come!), export the handler methods, and add an optional flags parameter to the MONITOR-FD method (really useful for epoll, the other backends I'm not sure about).
Let me know what you think. I'd like to get these patches (or at least the equivalent functionality of being able to use the multiplexer without having to make FD-ENTRYs) into IOlib as I'm about to release some software that uses it. Thanks, Vladimir
From 782310cb5a9655be9316299e65a61ab4ace16d11 Mon Sep 17 00:00:00 2001 From: Vladimir Sedach <[email protected]> Date: Fri, 13 Nov 2009 23:09:26 -0500 Subject: [PATCH 1/5] Added writev system call. --- src/syscalls/ffi-functions-unix.lisp | 7 +++++++ src/syscalls/pkgdcl.lisp | 1 + 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/src/syscalls/ffi-functions-unix.lisp b/src/syscalls/ffi-functions-unix.lisp index 22efcae..8cbe5fb 100644 --- a/src/syscalls/ffi-functions-unix.lisp +++ b/src/syscalls/ffi-functions-unix.lisp @@ -94,6 +94,13 @@ The two memory areas may overlap." (buf :pointer) (count size-t)) +(defsyscall (%sys-writev "writev") + (ssize-t :restart t :handle fd) + "Writes the contents of the first IOVCOUNT buffers of the IOV array to the FD." + (fd :int) + (iov :pointer) + (iovcount :int)) + (defsyscall (%sys-pread (#+linux "pread64" "pread")) (ssize-t :restart t :handle fd) "Read at most COUNT bytes from FD at offset OFFSET into the foreign area BUF." diff --git a/src/syscalls/pkgdcl.lisp b/src/syscalls/pkgdcl.lisp index f7e2928..f9f2723 100644 --- a/src/syscalls/pkgdcl.lisp +++ b/src/syscalls/pkgdcl.lisp @@ -87,6 +87,7 @@ ;; Files #:%sys-read #:%sys-write + #:%sys-writev #:%sys-pread #:%sys-pwrite #:%sys-open -- 1.6.3.3
From 81ab7f000963fdfaa3ba66766d7766406ca2d86a Mon Sep 17 00:00:00 2001 From: Vladimir Sedach <[email protected]> Date: Sat, 14 Nov 2009 01:06:21 -0500 Subject: [PATCH 2/5] Made return value of HARVEST-EVENTS consistent across all mux backends (was buggy previously). --- src/multiplex/backend-epoll.lisp | 4 ++-- src/multiplex/backend-kqueue.lisp | 4 ++-- src/multiplex/backend-poll.lisp | 2 +- src/multiplex/backend-select.lisp | 4 ++-- src/multiplex/multiplexer.lisp | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/multiplex/backend-epoll.lisp b/src/multiplex/backend-epoll.lisp index 9c2d5e3..091e916 100644 --- a/src/multiplex/backend-epoll.lisp +++ b/src/multiplex/backend-epoll.lisp @@ -99,7 +99,7 @@ :when epoll-event :collect epoll-event)))))) (defun make-epoll-event (fd mask) - (let ((event ())) + (let (event) (flags-case mask ((isys:epollout isys:epollhup) (push :write event)) @@ -108,4 +108,4 @@ (isys:epollerr (push :error event))) (when event - (list fd event)))) + (cons fd event)))) diff --git a/src/multiplex/backend-kqueue.lisp b/src/multiplex/backend-kqueue.lisp index 3741275..7954328 100644 --- a/src/multiplex/backend-kqueue.lisp +++ b/src/multiplex/backend-kqueue.lisp @@ -109,7 +109,7 @@ ;;; TODO: do something with DATA (defun make-kqueue-event (fd flags filter data) (declare (ignore data)) - (let ((event ())) + (let (event) (switch (filter :test #'=) (isys:evfilt-write (push :write event)) (isys:evfilt-read (push :read event))) @@ -118,4 +118,4 @@ ;; (ev-eof (pushnew :read event)) (isys:ev-error (push :error event))) (when event - (list fd event)))) + (cons fd event)))) diff --git a/src/multiplex/backend-poll.lisp b/src/multiplex/backend-poll.lisp index 34f6b63..f89e356 100644 --- a/src/multiplex/backend-poll.lisp +++ b/src/multiplex/backend-poll.lisp @@ -115,4 +115,4 @@ ((nix:pollout nix:pollhup) (push :write event)) ((nix:pollin nix:pollrdhup nix:pollpri) (push :read event)) ((nix:pollerr nix:pollnval) (push :error event))) - :when event :collect (list fd event)))) + :when event :collect (cons fd event)))) diff --git a/src/multiplex/backend-select.lisp b/src/multiplex/backend-select.lisp index daab596..56f0ea3 100644 --- a/src/multiplex/backend-select.lisp +++ b/src/multiplex/backend-select.lisp @@ -114,7 +114,7 @@ :when (or (isys:%sys-fd-isset fd read-fds) (isys:%sys-fd-isset fd except-fds)) :do (push :read event) :when (isys:%sys-fd-isset fd write-fds) :do (push :write event) - :when event :collect (list fd event))) + :when event :collect (cons fd event))) ;;; FIXME: I don't know whether on all *nix systems select() ;;; returns EBADF only when a given FD present in some fd-set @@ -128,4 +128,4 @@ :when (and (or (isys:%sys-fd-isset fd read-fds) (isys:%sys-fd-isset fd write-fds)) (fd-error-p fd)) - :collect (cons fd :error))) + :collect (cons fd '(:error)))) diff --git a/src/multiplex/multiplexer.lisp b/src/multiplex/multiplexer.lisp index 141d6c3..331c29e 100644 --- a/src/multiplex/multiplexer.lisp +++ b/src/multiplex/multiplexer.lisp @@ -45,10 +45,10 @@ Must return NIL on failure, T otherwise.")) (defgeneric harvest-events (mux timeout) (:documentation "Wait for events on multiplexer MUX for a maximum time of TIMEOUT seconds. Returns a list of fd/result pairs which have one of these forms: - (fd (:read)) - (fd (:write)) - (fd (:read :write)) - (fd . :error)")) + (fd :read) + (fd :write) + (fd :read :write) + (fd :error)")) (defmethod close-multiplexer :around ((mux multiplexer)) (unless (multiplexer-closedp mux) -- 1.6.3.3
From 1516a814c11587dbe49cad9da3f097e8acac7591 Mon Sep 17 00:00:00 2001 From: Vladimir Sedach <[email protected]> Date: Mon, 16 Nov 2009 02:50:42 -0500 Subject: [PATCH 3/5] Exported the monitor/update/harvest etc. operations on the multiplexer object. --- src/multiplex/pkgdcl.lisp | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/src/multiplex/pkgdcl.lisp b/src/multiplex/pkgdcl.lisp index 6004374..95023db 100644 --- a/src/multiplex/pkgdcl.lisp +++ b/src/multiplex/pkgdcl.lisp @@ -18,6 +18,13 @@ #+bsd #:kqueue-multiplexer #+linux #:epoll-multiplexer + ;; Multiplexor operations + #:close-multiplexer + #:monitor-fd + #:update-fd + #:unmonitor-fd + #:harvest-events + ;; Event-base Operations #:*available-multiplexers* #:*default-multiplexer* -- 1.6.3.3
From 0576e90fe46eade354e7b0f0ead0c03a9b916621 Mon Sep 17 00:00:00 2001 From: Vladimir Sedach <[email protected]> Date: Mon, 16 Nov 2009 02:52:04 -0500 Subject: [PATCH 4/5] Added a flags parameter to MONITOR-FD multiplexer method. --- src/multiplex/backend-kqueue.lisp | 4 ++-- src/multiplex/backend-poll.lisp | 2 +- src/multiplex/backend-select.lisp | 2 +- src/multiplex/multiplexer.lisp | 15 ++++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/multiplex/backend-kqueue.lisp b/src/multiplex/backend-kqueue.lisp index 7954328..e54b71a 100644 --- a/src/multiplex/backend-kqueue.lisp +++ b/src/multiplex/backend-kqueue.lisp @@ -34,8 +34,8 @@ isys:evfilt-write isys:evfilt-read)) -(defmethod monitor-fd ((mux kqueue-multiplexer) fd-entry) - (assert fd-entry (fd-entry) "Must supply an FD-ENTRY!") +(defmethod monitor-fd ((mux kqueue-multiplexer) (fd-entry fd-entry) &optional flags) + (declare (ignore flags)) (handler-case (do-kqueue-event-request (fd-of mux) fd-entry (calc-kqueue-monitor-filter fd-entry) diff --git a/src/multiplex/backend-poll.lisp b/src/multiplex/backend-poll.lisp index f89e356..6ca4d4c 100644 --- a/src/multiplex/backend-poll.lisp +++ b/src/multiplex/backend-poll.lisp @@ -48,7 +48,7 @@ (foreign-free fd-set) (values new-fd-set new-size))) -(defmethod monitor-fd ((mux poll-multiplexer) fd-entry) +(defmethod monitor-fd ((mux poll-multiplexer) (fd-entry fd-entry) &optional flags) (let ((fd (fd-entry-fd fd-entry)) (readp (fd-entry-read-handler fd-entry)) (writep (fd-entry-write-handler fd-entry))) diff --git a/src/multiplex/backend-select.lisp b/src/multiplex/backend-select.lisp index 56f0ea3..4da03c0 100644 --- a/src/multiplex/backend-select.lisp +++ b/src/multiplex/backend-select.lisp @@ -61,7 +61,7 @@ (find-max-fd ws end)))) t)) -(defmethod monitor-fd ((mux select-multiplexer) fd-entry) +(defmethod monitor-fd ((mux select-multiplexer) (fd-entry fd-entry) &optional flags) (recalc-fd-masks mux (fd-entry-fd fd-entry) (fd-entry-read-handler fd-entry) (fd-entry-write-handler fd-entry))) diff --git a/src/multiplex/multiplexer.lisp b/src/multiplex/multiplexer.lisp index 331c29e..76d536d 100644 --- a/src/multiplex/multiplexer.lisp +++ b/src/multiplex/multiplexer.lisp @@ -30,7 +30,7 @@ (:method-combination progn :most-specific-last) (:documentation "Close multiplexer MUX, calling close() on the multiplexer's FD if bound.")) -(defgeneric monitor-fd (mux fd-entry) +(defgeneric monitor-fd (mux fd-entry &optional flags) (:documentation "Add the descriptor reppresented by FD-ENTRY to multiplexer MUX. Must return NIL on failure, T otherwise.")) @@ -61,12 +61,13 @@ Returns a list of fd/result pairs which have one of these forms: (setf (slot-value mux 'fd) nil)) (values mux)) -(defmethod monitor-fd :before ((mux multiplexer) fd-entry) - (with-accessors ((fd-limit fd-limit-of)) - mux - (let ((fd (fd-entry-fd fd-entry))) - (when (and fd-limit (> fd fd-limit)) - (error "Cannot add such a large FD: ~A" fd))))) +(defmethod monitor-fd :before ((mux multiplexer) fd-entry &optional flags) + (declare (ignore flags)) + (let ((fd (if (integerp fd-entry) + fd-entry + (fd-entry-fd fd-entry)))) + (when (and (fd-limit-of mux) (> fd (fd-limit-of mux))) + (error "Cannot add such a large FD: ~A" fd)))) (defmacro define-multiplexer (name priority superclasses slots &rest options) `(progn -- 1.6.3.3
From a63d2dfbac79c17bf9b9b3f495ad959d76620faa Mon Sep 17 00:00:00 2001 From: Vladimir Sedach <[email protected]> Date: Mon, 16 Nov 2009 02:52:42 -0500 Subject: [PATCH 5/5] Made epoll multiplexer take a simple integer file descriptor in addition to the FD-ENTRY structure. --- src/multiplex/backend-epoll.lisp | 99 +++++++++++++++++++------------------- 1 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/multiplex/backend-epoll.lisp b/src/multiplex/backend-epoll.lisp index 091e916..2e1296d 100644 --- a/src/multiplex/backend-epoll.lisp +++ b/src/multiplex/backend-epoll.lisp @@ -21,64 +21,65 @@ &key (size +epoll-default-size-hint+)) (setf (slot-value mux 'fd) (isys:%sys-epoll-create size))) -(defun calc-epoll-flags (fd-entry) - (logior (if (fd-entry-read-handler fd-entry) - isys:epollin - 0) - (if (fd-entry-write-handler fd-entry) - isys:epollout - 0) - isys:epollpri)) - -(defmethod monitor-fd ((mux epoll-multiplexer) fd-entry) - (assert fd-entry (fd-entry) "Must supply an FD-ENTRY!") - (let ((flags (calc-epoll-flags fd-entry)) - (fd (fd-entry-fd fd-entry))) - (with-foreign-object (ev 'isys:epoll-event) - (isys:%sys-bzero ev isys:size-of-epoll-event) - (setf (foreign-slot-value ev 'isys:epoll-event 'isys:events) flags) - (setf (foreign-slot-value - (foreign-slot-value ev 'isys:epoll-event 'isys:data) - 'isys:epoll-data 'isys:fd) - fd) - (handler-case - (isys:%sys-epoll-ctl (fd-of mux) isys:epoll-ctl-add fd ev) - (isys:ebadf () - (warn "FD ~A is invalid, cannot monitor it." fd)) - (isys:eexist () - (warn "FD ~A is already monitored." fd)))))) - -(defmethod update-fd ((mux epoll-multiplexer) fd-entry event-type edge-change) - (declare (ignore event-type edge-change)) - (assert fd-entry (fd-entry) "Must supply an FD-ENTRY!") - (let ((flags (calc-epoll-flags fd-entry)) - (fd (fd-entry-fd fd-entry))) - (with-foreign-object (ev 'isys:epoll-event) - (isys:%sys-bzero ev isys:size-of-epoll-event) - (setf (foreign-slot-value ev 'isys:epoll-event 'isys:events) flags) - (setf (foreign-slot-value - (foreign-slot-value ev 'isys:epoll-event 'isys:data) - 'isys:epoll-data 'isys:fd) - fd) - (handler-case - (isys:%sys-epoll-ctl (fd-of mux) isys:epoll-ctl-mod fd ev) - (isys:ebadf () - (warn "FD ~A is invalid, cannot update its status." fd)) - (isys:enoent () - (warn "FD ~A was not monitored, cannot update its status." fd)))) - (values fd-entry))) - -(defmethod unmonitor-fd ((mux epoll-multiplexer) fd-entry) +(defun calc-epoll-flags (flags) + (logior (if (member :read flags) isys:epollin 0) + (if (member :write flags) isys:epollout 0) + (if (member :epoll-oneshot flags) isys:epolloneshot 0) + isys:epollpri)) ;; what to do about EPOLLPRI? + +(defmethod monitor-fd ((mux epoll-multiplexer) (fd-entry fd-entry) &optional flags) + (declare (ignore flags)) + (monitor-fd mux + (fd-entry-fd fd-entry) + (list (when (fd-entry-read-handler fd-entry) :read) + (when (fd-entry-write-handler fd-entry) :write)))) + +(defmacro with-epoll-event ((ev fd flags) &body body) + `(with-foreign-object (,ev 'isys:epoll-event) + (isys:%sys-bzero ,ev isys:size-of-epoll-event) + (setf (foreign-slot-value ,ev 'isys:epoll-event 'isys:events) + (calc-epoll-flags ,flags) + (foreign-slot-value + (foreign-slot-value ,ev 'isys:epoll-event 'isys:data) + 'isys:epoll-data 'isys:fd) + ,fd) + ,@body)) + +(defmethod monitor-fd ((mux epoll-multiplexer) (fd integer) &optional flags) + (with-epoll-event (ev fd flags) + (handler-case + (isys:%sys-epoll-ctl (fd-of mux) isys:epoll-ctl-add fd ev) + (isys:ebadf () + (warn "FD ~A is invalid, cannot monitor it." fd)) + (isys:eexist () + (warn "FD ~A is already monitored." fd))))) + +(defmethod update-fd ((mux epoll-multiplexer) (fd-entry fd-entry) flags edge-change) + (update-fd mux (fd-entry-fd fd-entry) flags edge-change)) + +(defmethod update-fd ((mux epoll-multiplexer) (fd integer) flags edge-change) + (declare (ignore edge-change)) + (with-epoll-event (ev fd flags) + (handler-case + (isys:%sys-epoll-ctl (fd-of mux) isys:epoll-ctl-mod fd ev) + (isys:ebadf () + (warn "FD ~A is invalid, cannot update its status." fd)) + (isys:enoent () + (warn "FD ~A was not monitored, cannot update its status." fd))))) + +(defmethod unmonitor-fd ((mux epoll-multiplexer) (fd-entry fd-entry)) + (unmonitor-fd mux (fd-entry-fd fd))) + +(defmethod unmonitor-fd ((mux epoll-multiplexer) (fd integer)) (handler-case (isys:%sys-epoll-ctl (fd-of mux) isys:epoll-ctl-del - (fd-entry-fd fd-entry) + fd (null-pointer)) (isys:ebadf () - (warn "FD ~A is invalid, cannot unmonitor it." (fd-entry-fd fd-entry))) + (warn "FD ~A is invalid, cannot unmonitor it." fd)) (isys:enoent () - (warn "FD ~A was not monitored, cannot unmonitor it." - (fd-entry-fd fd-entry))))) + (warn "FD ~A was not monitored, cannot unmonitor it." fd)))) (defmethod harvest-events ((mux epoll-multiplexer) timeout) (with-foreign-object (events 'isys:epoll-event +epoll-max-events+) -- 1.6.3.3
_______________________________________________ IOLib-devel mailing list [email protected] http://common-lisp.net/cgi-bin/mailman/listinfo/iolib-devel
