150 lines
4.1 KiB
Factor
Executable File
150 lines
4.1 KiB
Factor
Executable File
! Copyright (C) 2008 Slava Pestov.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: alien.c-types kernel math math.bitwise namespaces
|
|
locals accessors combinators threads vectors hashtables
|
|
sequences assocs continuations sets
|
|
unix unix.time unix.kqueue unix.process
|
|
io.ports io.unix.backend io.launcher io.unix.launcher
|
|
io.monitors ;
|
|
IN: io.unix.kqueue
|
|
|
|
TUPLE: kqueue-mx < mx events monitors ;
|
|
|
|
: max-events ( -- n )
|
|
#! We read up to 256 events at a time. This is an arbitrary
|
|
#! constant...
|
|
256 ; inline
|
|
|
|
: <kqueue-mx> ( -- mx )
|
|
kqueue-mx new-mx
|
|
H{ } clone >>monitors
|
|
kqueue dup io-error >>fd
|
|
max-events "kevent" <c-array> >>events ;
|
|
|
|
GENERIC: io-task-filter ( task -- n )
|
|
|
|
M: input-task io-task-filter drop EVFILT_READ ;
|
|
|
|
M: output-task io-task-filter drop EVFILT_WRITE ;
|
|
|
|
GENERIC: io-task-fflags ( task -- n )
|
|
|
|
M: io-task io-task-fflags drop 0 ;
|
|
|
|
: make-kevent ( task flags -- event )
|
|
"kevent" <c-object>
|
|
tuck set-kevent-flags
|
|
over io-task-fd over set-kevent-ident
|
|
over io-task-fflags over set-kevent-fflags
|
|
swap io-task-filter over set-kevent-filter ;
|
|
|
|
: register-kevent ( kevent mx -- )
|
|
fd>> swap 1 f 0 f kevent
|
|
0 < [ err_no ESRCH = [ (io-error) ] unless ] when ;
|
|
|
|
M: kqueue-mx register-io-task ( task mx -- )
|
|
[ >r EV_ADD make-kevent r> register-kevent ]
|
|
[ call-next-method ]
|
|
2bi ;
|
|
|
|
M: kqueue-mx unregister-io-task ( task mx -- )
|
|
[ call-next-method ]
|
|
[ >r EV_DELETE make-kevent r> register-kevent ]
|
|
2bi ;
|
|
|
|
: wait-kevent ( mx timespec -- n )
|
|
>r [ fd>> f 0 ] keep events>> max-events r> kevent
|
|
dup multiplexer-error ;
|
|
|
|
:: kevent-read-task ( mx fd kevent -- )
|
|
mx fd mx reads>> at perform-io-task ;
|
|
|
|
:: kevent-write-task ( mx fd kevent -- )
|
|
mx fd mx writes>> at perform-io-task ;
|
|
|
|
:: kevent-proc-task ( mx pid kevent -- )
|
|
pid wait-for-pid
|
|
pid find-process
|
|
dup [ swap notify-exit ] [ 2drop ] if ;
|
|
|
|
: parse-action ( mask -- changed )
|
|
[
|
|
NOTE_DELETE +remove-file+ ?flag
|
|
NOTE_WRITE +modify-file+ ?flag
|
|
NOTE_EXTEND +modify-file+ ?flag
|
|
NOTE_ATTRIB +modify-file+ ?flag
|
|
NOTE_RENAME +rename-file+ ?flag
|
|
NOTE_REVOKE +remove-file+ ?flag
|
|
drop
|
|
] { } make prune ;
|
|
|
|
:: kevent-vnode-task ( mx kevent fd -- )
|
|
""
|
|
kevent kevent-fflags parse-action
|
|
fd mx monitors>> at queue-change ;
|
|
|
|
: handle-kevent ( mx kevent -- )
|
|
[ ] [ kevent-ident ] [ kevent-filter ] tri {
|
|
{ [ dup EVFILT_READ = ] [ drop kevent-read-task ] }
|
|
{ [ dup EVFILT_WRITE = ] [ drop kevent-write-task ] }
|
|
{ [ dup EVFILT_PROC = ] [ drop kevent-proc-task ] }
|
|
{ [ dup EVFILT_VNODE = ] [ drop kevent-vnode-task ] }
|
|
} cond ;
|
|
|
|
: handle-kevents ( mx n -- )
|
|
[ over events>> kevent-nth handle-kevent ] with each ;
|
|
|
|
M: kqueue-mx wait-for-events ( ms mx -- )
|
|
swap dup [ make-timespec ] when
|
|
dupd wait-kevent handle-kevents ;
|
|
|
|
! Procs
|
|
: make-proc-kevent ( pid -- kevent )
|
|
"kevent" <c-object>
|
|
tuck set-kevent-ident
|
|
EV_ADD over set-kevent-flags
|
|
EVFILT_PROC over set-kevent-filter
|
|
NOTE_EXIT over set-kevent-fflags ;
|
|
|
|
: register-pid-task ( pid mx -- )
|
|
swap make-proc-kevent swap register-kevent ;
|
|
|
|
! VNodes
|
|
TUPLE: vnode-monitor < monitor fd ;
|
|
|
|
: vnode-fflags ( -- n )
|
|
{
|
|
NOTE_DELETE
|
|
NOTE_WRITE
|
|
NOTE_EXTEND
|
|
NOTE_ATTRIB
|
|
NOTE_LINK
|
|
NOTE_RENAME
|
|
NOTE_REVOKE
|
|
} flags ;
|
|
|
|
: make-vnode-kevent ( fd flags -- kevent )
|
|
"kevent" <c-object>
|
|
tuck set-kevent-flags
|
|
tuck set-kevent-ident
|
|
EVFILT_VNODE over set-kevent-filter
|
|
vnode-fflags over set-kevent-fflags ;
|
|
|
|
: register-monitor ( monitor mx -- )
|
|
>r dup fd>> r>
|
|
[ >r EV_ADD EV_CLEAR bitor make-vnode-kevent r> register-kevent drop ]
|
|
[ monitors>> set-at ] 3bi ;
|
|
|
|
: unregister-monitor ( monitor mx -- )
|
|
>r fd>> r>
|
|
[ monitors>> delete-at ]
|
|
[ >r EV_DELETE make-vnode-kevent r> register-kevent ] 2bi ;
|
|
|
|
: <vnode-monitor> ( path mailbox -- monitor )
|
|
>r [ O_RDONLY 0 open dup io-error ] keep r>
|
|
vnode-monitor new-monitor swap >>fd
|
|
[ dup kqueue-mx get register-monitor ] [ ] [ fd>> close ] cleanup ;
|
|
|
|
M: vnode-monitor dispose
|
|
[ kqueue-mx get unregister-monitor ] [ fd>> close ] bi ;
|