1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Base class for multiplexers.
6 (in-package :iolib.multiplex
)
8 (defvar *available-multiplexers
* nil
9 "An alist of (PRIORITY . MULTIPLEXER). Smaller values mean higher priority.")
11 (defvar *default-multiplexer
* nil
12 "The default multiplexer for the current OS.")
14 (defun get-fd-limit ()
15 "Return the maximum number of FDs available for the current process."
16 (let ((fd-limit (isys:getrlimit isys
:rlimit-nofile
)))
17 (if (= fd-limit isys
:rlim-infinity
)
18 65536 ; 64K should be enough for anybody
21 (defclass multiplexer
()
23 (fd-limit :initform
(get-fd-limit)
26 (closedp :accessor multiplexer-closedp
28 (:documentation
"Base class for I/O multiplexers."))
30 (defgeneric close-multiplexer
(mux)
31 (:method-combination progn
:most-specific-last
)
32 (:documentation
"Close multiplexer MUX, calling close() on the multiplexer's FD if bound."))
34 (defgeneric monitor-fd
(mux fd-entry
)
35 (:documentation
"Add the descriptor represented by FD-ENTRY to multiplexer MUX.
36 Must return NIL on failure, T otherwise."))
38 (defgeneric update-fd
(mux fd-entry event-type edge-change
)
39 (:documentation
"Update the status of the descriptor represented by FD-ENTRY in multiplexer MUX.
40 Must return NIL on failure, T otherwise."))
42 (defgeneric unmonitor-fd
(mux fd-entry
)
43 (:documentation
"Remove the descriptor represented by FD-ENTRY from multiplexer MUX.
44 Must return NIL on failure, T otherwise."))
46 (defgeneric harvest-events
(mux timeout
)
47 (:documentation
"Wait for events on multiplexer MUX for a maximum time of TIMEOUT seconds.
48 Returns a list of fd/result pairs which have one of these forms:
54 (defmethod close-multiplexer :around
((mux multiplexer
))
55 (unless (multiplexer-closedp mux
)
57 (setf (multiplexer-closedp mux
) t
)))
59 (defmethod close-multiplexer progn
((mux multiplexer
))
60 (when (and (slot-boundp mux
'fd
) (not (null (fd-of mux
))))
61 (isys:close
(fd-of mux
))
62 (setf (slot-value mux
'fd
) nil
))
65 (defmethod monitor-fd :before
((mux multiplexer
) fd-entry
)
66 (with-accessors ((fd-limit fd-limit-of
))
68 (let ((fd (fd-entry-fd fd-entry
)))
69 (when (and fd-limit
(> fd fd-limit
))
70 (error "Cannot add such a large FD: ~A" fd
)))))
72 (defmacro define-multiplexer
(name priority superclasses slots
&rest options
)
74 (defclass ,name
,superclasses
,slots
,@options
)
75 (pushnew (cons ,priority
',name
) *available-multiplexers
*