1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien.c-types kernel math math.bitwise namespaces
4 locals accessors combinators threads vectors hashtables
5 sequences assocs continuations sets
6 unix unix.time unix.kqueue unix.process
7 io.ports io.unix.backend io.launcher io.unix.launcher
11 TUPLE: kqueue-mx < mx events monitors ;
14 #! We read up to 256 events at a time. This is an arbitrary
18 : <kqueue-mx> ( -- mx )
21 kqueue dup io-error >>fd
22 max-events "kevent" <c-array> >>events ;
24 GENERIC: io-task-filter ( task -- n )
26 M: input-task io-task-filter drop EVFILT_READ ;
28 M: output-task io-task-filter drop EVFILT_WRITE ;
30 GENERIC: io-task-fflags ( task -- n )
32 M: io-task io-task-fflags drop 0 ;
34 : make-kevent ( task flags -- event )
37 over io-task-fd over set-kevent-ident
38 over io-task-fflags over set-kevent-fflags
39 swap io-task-filter over set-kevent-filter ;
41 : register-kevent ( kevent mx -- )
42 fd>> swap 1 f 0 f kevent
43 0 < [ err_no ESRCH = [ (io-error) ] unless ] when ;
45 M: kqueue-mx register-io-task ( task mx -- )
46 [ >r EV_ADD make-kevent r> register-kevent ]
50 M: kqueue-mx unregister-io-task ( task mx -- )
52 [ >r EV_DELETE make-kevent r> register-kevent ]
55 : wait-kevent ( mx timespec -- n )
56 >r [ fd>> f 0 ] keep events>> max-events r> kevent
57 dup multiplexer-error ;
59 :: kevent-read-task ( mx fd kevent -- )
60 mx fd mx reads>> at perform-io-task ;
62 :: kevent-write-task ( mx fd kevent -- )
63 mx fd mx writes>> at perform-io-task ;
65 :: kevent-proc-task ( mx pid kevent -- )
68 dup [ swap notify-exit ] [ 2drop ] if ;
70 : parse-action ( mask -- changed )
72 NOTE_DELETE +remove-file+ ?flag
73 NOTE_WRITE +modify-file+ ?flag
74 NOTE_EXTEND +modify-file+ ?flag
75 NOTE_ATTRIB +modify-file+ ?flag
76 NOTE_RENAME +rename-file+ ?flag
77 NOTE_REVOKE +remove-file+ ?flag
81 :: kevent-vnode-task ( mx kevent fd -- )
83 kevent kevent-fflags parse-action
84 fd mx monitors>> at queue-change ;
86 : handle-kevent ( mx kevent -- )
87 [ ] [ kevent-ident ] [ kevent-filter ] tri {
88 { [ dup EVFILT_READ = ] [ drop kevent-read-task ] }
89 { [ dup EVFILT_WRITE = ] [ drop kevent-write-task ] }
90 { [ dup EVFILT_PROC = ] [ drop kevent-proc-task ] }
91 { [ dup EVFILT_VNODE = ] [ drop kevent-vnode-task ] }
94 : handle-kevents ( mx n -- )
95 [ over events>> kevent-nth handle-kevent ] with each ;
97 M: kqueue-mx wait-for-events ( ms mx -- )
98 swap dup [ make-timespec ] when
99 dupd wait-kevent handle-kevents ;
102 : make-proc-kevent ( pid -- kevent )
104 tuck set-kevent-ident
105 EV_ADD over set-kevent-flags
106 EVFILT_PROC over set-kevent-filter
107 NOTE_EXIT over set-kevent-fflags ;
109 : register-pid-task ( pid mx -- )
110 swap make-proc-kevent swap register-kevent ;
113 TUPLE: vnode-monitor < monitor fd ;
115 : vnode-fflags ( -- n )
126 : make-vnode-kevent ( fd flags -- kevent )
128 tuck set-kevent-flags
129 tuck set-kevent-ident
130 EVFILT_VNODE over set-kevent-filter
131 vnode-fflags over set-kevent-fflags ;
133 : register-monitor ( monitor mx -- )
135 [ >r EV_ADD EV_CLEAR bitor make-vnode-kevent r> register-kevent drop ]
136 [ monitors>> set-at ] 3bi ;
138 : unregister-monitor ( monitor mx -- )
140 [ monitors>> delete-at ]
141 [ >r EV_DELETE make-vnode-kevent r> register-kevent ] 2bi ;
143 : <vnode-monitor> ( path mailbox -- monitor )
144 >r [ O_RDONLY 0 open dup io-error ] keep r>
145 vnode-monitor new-monitor swap >>fd
146 [ dup kqueue-mx get register-monitor ] [ ] [ fd>> close ] cleanup ;
148 M: vnode-monitor dispose
149 [ kqueue-mx get unregister-monitor ] [ fd>> close ] bi ;