When LOCAL-PORT or REMOTE-PORT are not numbers, MAKE-SOCKET now uses LOOKUP-SERVICE...
[iolib.git] / io-multiplex / epoll.lisp
blob9d4aabe80935af94899f91658297b179ec4d0adc
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Indent-tabs-mode: NIL -*-
2 ;;;
3 ;;; epoll.lisp --- epoll()-based multiplexer implementation.
4 ;;;
5 ;;; Copyright (C) 2006-2007, Stelian Ionescu <sionescu@common-lisp.net>
6 ;;;
7 ;;; This code is free software; you can redistribute it and/or
8 ;;; modify it under the terms of the version 2.1 of
9 ;;; the GNU Lesser General Public License as published by
10 ;;; the Free Software Foundation, as clarified by the
11 ;;; preamble found here:
12 ;;; http://opensource.franz.com/preamble.html
13 ;;;
14 ;;; This program is distributed in the hope that it will be useful,
15 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;;; GNU General Public License for more details.
18 ;;;
19 ;;; You should have received a copy of the GNU Lesser General
20 ;;; Public License along with this library; if not, write to the
21 ;;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 ;;; Boston, MA 02110-1301, USA
24 (in-package :io.multiplex)
26 (defconstant +epoll-priority+ 1)
28 (define-multiplexer epoll-multiplexer +epoll-priority+ (multiplexer)
29 ())
31 (defmethod print-object ((mux epoll-multiplexer) stream)
32 (print-unreadable-object (mux stream :type nil :identity nil)
33 (format stream "epoll(4) multiplexer")))
35 (defconstant +epoll-default-size-hint+ 25)
36 (defvar *epoll-max-events* 200)
38 (defmethod initialize-instance :after ((mux epoll-multiplexer)
39 &key (size +epoll-default-size-hint+))
40 (setf (slot-value mux 'fd) (nix:epoll-create size)))
42 (defun calc-epoll-flags (fd-entry)
43 (logior (if (fd-entry-read-event fd-entry)
44 nix::epollin 0)
45 (if (fd-entry-write-event fd-entry)
46 nix::epollout 0)
47 nix::epollpri))
49 (defmethod monitor-fd ((mux epoll-multiplexer) fd-entry)
50 (assert fd-entry)
51 (let ((flags (calc-epoll-flags fd-entry))
52 (fd (fd-entry-fd fd-entry)))
53 (with-foreign-object (ev 'nix::epoll-event)
54 (nix:bzero ev nix::size-of-epoll-event)
55 (setf (foreign-slot-value ev 'nix::epoll-event 'nix::events)
56 flags)
57 (setf (foreign-slot-value
58 (foreign-slot-value ev 'nix::epoll-event 'nix::data)
59 'nix::epoll-data 'nix::fd)
60 fd)
61 (handler-case
62 (nix:epoll-ctl (fd-of mux) nix:epoll-ctl-add fd ev)
63 (nix:ebadf ()
64 (warn "FD ~A is invalid, cannot monitor it." fd))
65 (nix:eexist ()
66 (warn "FD ~A is already monitored." fd))))))
68 (defmethod update-fd ((mux epoll-multiplexer) fd-entry event-type edge-change)
69 (declare (ignore event-type edge-change))
70 (assert fd-entry)
71 (let ((flags (calc-epoll-flags fd-entry))
72 (fd (fd-entry-fd fd-entry)))
73 (with-foreign-object (ev 'nix::epoll-event)
74 (nix:bzero ev nix::size-of-epoll-event)
75 (setf (foreign-slot-value ev 'nix::epoll-event 'nix::events)
76 flags)
77 (setf (foreign-slot-value
78 (foreign-slot-value ev 'nix::epoll-event 'nix::data)
79 'nix::epoll-data 'nix::fd)
80 fd)
81 (handler-case
82 (nix:epoll-ctl (fd-of mux) nix::epoll-ctl-mod fd ev)
83 (nix:ebadf ()
84 (warn "FD ~A is invalid, cannot update its status." fd))
85 (nix:enoent ()
86 (warn "FD ~A was not monitored, cannot update its status." fd))))
87 (values fd-entry)))
89 (defmethod unmonitor-fd ((mux epoll-multiplexer) fd-entry)
90 (handler-case
91 (nix:epoll-ctl (fd-of mux)
92 nix::epoll-ctl-del
93 (fd-entry-fd fd-entry)
94 (null-pointer))
95 (nix:ebadf ()
96 (warn "FD ~A is invalid, cannot unmonitor it." (fd-entry-fd fd-entry)))
97 (nix:enoent ()
98 (warn "FD ~A was not monitored, cannot unmonitor it."
99 (fd-entry-fd fd-entry)))))
101 (defmethod harvest-events ((mux epoll-multiplexer) timeout)
102 (with-foreign-object (events 'nix::epoll-event *epoll-max-events*)
103 (nix:bzero events (* *epoll-max-events* nix::size-of-epoll-event))
104 (let (ready-fds)
105 (nix:repeat-upon-condition-decreasing-timeout
106 ((nix:eintr) tmp-timeout timeout)
107 (setf ready-fds (nix:epoll-wait (fd-of mux) events *epoll-max-events*
108 (timeout->milisec tmp-timeout))))
109 (macrolet ((epoll-slot (slot-name)
110 `(foreign-slot-value (mem-aref events 'nix::epoll-event i)
111 'nix::epoll-event ',slot-name)))
112 (return-from harvest-events
113 (loop :for i :below ready-fds
114 :for fd := (foreign-slot-value (epoll-slot nix::data)
115 'nix::epoll-data 'nix::fd)
116 :for event-mask := (epoll-slot nix::events)
117 :for epoll-event := (make-epoll-event fd event-mask)
118 :when epoll-event :collect epoll-event))))))
120 (defun make-epoll-event (fd mask)
121 (let ((event ()))
122 (flags-case mask
123 ((nix::epollout nix::epollhup)
124 (push :write event))
125 ((nix::epollin nix::epollpri nix::epollhup)
126 (push :read event))
127 (nix::epollerr
128 (push :error event)))
129 (when event
130 (list fd event))))