Implement monitors for BSD
							parent
							
								
									82d793b141
								
							
						
					
					
						commit
						d132bce5a3
					
				| 
						 | 
					@ -42,13 +42,17 @@ HELP: +rename-file-old+
 | 
				
			||||||
HELP: +rename-file-new+
 | 
					HELP: +rename-file-new+
 | 
				
			||||||
{ $description "Indicates that a file has been renamed, and this is the new name." } ;
 | 
					{ $description "Indicates that a file has been renamed, and this is the new name." } ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HELP: +rename-file+
 | 
				
			||||||
 | 
					{ $description "Indicates that a file has been renamed." } ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARTICLE: "io.monitors.descriptors" "File system change descriptors"
 | 
					ARTICLE: "io.monitors.descriptors" "File system change descriptors"
 | 
				
			||||||
"Change descriptors output by " { $link next-change } ":"
 | 
					"Change descriptors output by " { $link next-change } ":"
 | 
				
			||||||
{ $subsection +add-file+ }
 | 
					{ $subsection +add-file+ }
 | 
				
			||||||
{ $subsection +remove-file+ }
 | 
					{ $subsection +remove-file+ }
 | 
				
			||||||
{ $subsection +modify-file+ }
 | 
					{ $subsection +modify-file+ }
 | 
				
			||||||
{ $subsection +rename-file-old+ }
 | 
					{ $subsection +rename-file-old+ }
 | 
				
			||||||
{ $subsection +rename-file-new+ } ;
 | 
					{ $subsection +rename-file-new+ }
 | 
				
			||||||
 | 
					{ $subsection +rename-file+ } ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARTICLE: "io.monitors.platforms" "Monitors on different platforms"
 | 
					ARTICLE: "io.monitors.platforms" "Monitors on different platforms"
 | 
				
			||||||
"Whether the " { $snippet "path" } " output value of " { $link next-change } " contains an absolute path or a path relative to the path given to " { $link <monitor> } " is platform-specific. User code should not assume either case."
 | 
					"Whether the " { $snippet "path" } " output value of " { $link next-change } " contains an absolute path or a path relative to the path given to " { $link <monitor> } " is platform-specific. User code should not assume either case."
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ USING: io.monitors tools.test io.files system sequences
 | 
				
			||||||
continuations namespaces concurrency.count-downs kernel io
 | 
					continuations namespaces concurrency.count-downs kernel io
 | 
				
			||||||
threads calendar prettyprint ;
 | 
					threads calendar prettyprint ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
os wince? [
 | 
					os { winnt linux macosx } member? [
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        [ "monitor-test" temp-file delete-tree ] ignore-errors
 | 
					        [ "monitor-test" temp-file delete-tree ] ignore-errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,4 +88,4 @@ os wince? [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [ ] [ "m" get dispose ] unit-test
 | 
					        [ ] [ "m" get dispose ] unit-test
 | 
				
			||||||
    ] with-monitors
 | 
					    ] with-monitors
 | 
				
			||||||
] unless
 | 
					] when
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,7 @@ SYMBOL: +remove-file+
 | 
				
			||||||
SYMBOL: +modify-file+
 | 
					SYMBOL: +modify-file+
 | 
				
			||||||
SYMBOL: +rename-file-old+
 | 
					SYMBOL: +rename-file-old+
 | 
				
			||||||
SYMBOL: +rename-file-new+
 | 
					SYMBOL: +rename-file-new+
 | 
				
			||||||
 | 
					SYMBOL: +rename-file+
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: with-monitor ( path recursive? quot -- )
 | 
					: with-monitor ( path recursive? quot -- )
 | 
				
			||||||
    >r <monitor> r> with-disposal ; inline
 | 
					    >r <monitor> r> with-disposal ; inline
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,3 +203,6 @@ M: mx-task do-io-task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: multiplexer-error ( n -- )
 | 
					: multiplexer-error ( n -- )
 | 
				
			||||||
    0 < [ err_no ignorable-error? [ (io-error) ] unless ] when ;
 | 
					    0 < [ err_no ignorable-error? [ (io-error) ] unless ] when ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					: ?flag ( n mask symbol -- n )
 | 
				
			||||||
 | 
					    pick rot bitand 0 > [ , ] [ drop ] if ;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,21 @@
 | 
				
			||||||
! Copyright (C) 2008 Slava Pestov.
 | 
					! Copyright (C) 2008 Slava Pestov.
 | 
				
			||||||
! See http://factorcode.org/license.txt for BSD license.
 | 
					! See http://factorcode.org/license.txt for BSD license.
 | 
				
			||||||
IN: io.unix.bsd
 | 
					IN: io.unix.bsd
 | 
				
			||||||
USING: io.backend io.unix.backend io.unix.select
 | 
					USING: namespaces system kernel accessors assocs continuations
 | 
				
			||||||
namespaces system ;
 | 
					unix
 | 
				
			||||||
 | 
					io.backend io.unix.backend io.unix.select io.unix.kqueue io.monitors ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
M: bsd init-io ( -- )
 | 
					M: bsd init-io ( -- )
 | 
				
			||||||
    <select-mx> mx set-global ;
 | 
					    <select-mx> mx set-global
 | 
				
			||||||
 | 
					    <kqueue-mx> kqueue-mx set-global
 | 
				
			||||||
 | 
					    kqueue-mx get-global <mx-port> <mx-task>
 | 
				
			||||||
 | 
					    dup io-task-fd
 | 
				
			||||||
 | 
					    [ mx get-global reads>> set-at ]
 | 
				
			||||||
 | 
					    [ mx get-global writes>> set-at ] 2bi ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					M: bsd init-monitors ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					M: bsd dispose-monitors ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					M: bsd (monitor) ( path recursive? mailbox -- )
 | 
				
			||||||
 | 
					    nip <vnode-monitor> ;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,14 @@
 | 
				
			||||||
! Copyright (C) 2008 Slava Pestov.
 | 
					! Copyright (C) 2008 Slava Pestov.
 | 
				
			||||||
! See http://factorcode.org/license.txt for BSD license.
 | 
					! See http://factorcode.org/license.txt for BSD license.
 | 
				
			||||||
USING: alien.c-types kernel io.nonblocking io.unix.backend
 | 
					USING: alien.c-types kernel math math.bitfields namespaces
 | 
				
			||||||
sequences assocs unix unix.time unix.kqueue unix.process math namespaces
 | 
					locals accessors combinators threads vectors hashtables
 | 
				
			||||||
combinators threads vectors io.launcher
 | 
					sequences assocs continuations
 | 
				
			||||||
io.unix.launcher ;
 | 
					unix unix.time unix.kqueue unix.process
 | 
				
			||||||
 | 
					io.nonblocking io.unix.backend io.launcher io.unix.launcher
 | 
				
			||||||
 | 
					io.monitors ;
 | 
				
			||||||
IN: io.unix.kqueue
 | 
					IN: io.unix.kqueue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TUPLE: kqueue-mx events ;
 | 
					TUPLE: kqueue-mx events monitors ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: max-events ( -- n )
 | 
					: max-events ( -- n )
 | 
				
			||||||
    #! We read up to 256 events at a time. This is an arbitrary
 | 
					    #! We read up to 256 events at a time. This is an arbitrary
 | 
				
			||||||
| 
						 | 
					@ -15,8 +17,9 @@ TUPLE: kqueue-mx events ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: <kqueue-mx> ( -- mx )
 | 
					: <kqueue-mx> ( -- mx )
 | 
				
			||||||
    kqueue-mx construct-mx
 | 
					    kqueue-mx construct-mx
 | 
				
			||||||
    kqueue dup io-error over set-mx-fd
 | 
					        H{ } clone >>monitors
 | 
				
			||||||
    max-events "kevent" <c-array> over set-kqueue-mx-events ;
 | 
					        kqueue dup io-error >>fd
 | 
				
			||||||
 | 
					        max-events "kevent" <c-array> >>events ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GENERIC: io-task-filter ( task -- n )
 | 
					GENERIC: io-task-filter ( task -- n )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,14 +27,19 @@ M: input-task io-task-filter drop EVFILT_READ ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
M: output-task io-task-filter drop EVFILT_WRITE ;
 | 
					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 )
 | 
					: make-kevent ( task flags -- event )
 | 
				
			||||||
    "kevent" <c-object>
 | 
					    "kevent" <c-object>
 | 
				
			||||||
    tuck set-kevent-flags
 | 
					    tuck set-kevent-flags
 | 
				
			||||||
    over io-task-fd over set-kevent-ident
 | 
					    over io-task-fd over set-kevent-ident
 | 
				
			||||||
 | 
					    over io-task-fflags over set-kevent-fflags
 | 
				
			||||||
    swap io-task-filter over set-kevent-filter ;
 | 
					    swap io-task-filter over set-kevent-filter ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: register-kevent ( kevent mx -- )
 | 
					: register-kevent ( kevent mx -- )
 | 
				
			||||||
    mx-fd swap 1 f 0 f kevent
 | 
					    fd>> swap 1 f 0 f kevent
 | 
				
			||||||
    0 < [ err_no ESRCH = [ (io-error) ] unless ] when ;
 | 
					    0 < [ err_no ESRCH = [ (io-error) ] unless ] when ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
M: kqueue-mx register-io-task ( task mx -- )
 | 
					M: kqueue-mx register-io-task ( task mx -- )
 | 
				
			||||||
| 
						 | 
					@ -43,33 +51,52 @@ M: kqueue-mx unregister-io-task ( task mx -- )
 | 
				
			||||||
    swap EV_DELETE make-kevent swap register-kevent ;
 | 
					    swap EV_DELETE make-kevent swap register-kevent ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: wait-kevent ( mx timespec -- n )
 | 
					: wait-kevent ( mx timespec -- n )
 | 
				
			||||||
    >r dup mx-fd f 0 roll kqueue-mx-events max-events r> kevent
 | 
					    >r [ fd>> f 0 ] keep events>> max-events r> kevent
 | 
				
			||||||
    dup multiplexer-error ;
 | 
					    dup multiplexer-error ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: kevent-read-task ( mx fd -- )
 | 
					:: kevent-read-task ( mx fd kevent -- )
 | 
				
			||||||
    over mx-reads at handle-io-task ;
 | 
					    mx fd mx reads>> at handle-io-task ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: kevent-write-task ( mx fd -- )
 | 
					:: kevent-write-task ( mx fd kevent -- )
 | 
				
			||||||
    over mx-reads at handle-io-task ;
 | 
					    mx fd mx writes>> at handle-io-task ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: kevent-proc-task ( pid -- )
 | 
					:: kevent-proc-task ( mx pid kevent -- )
 | 
				
			||||||
    dup wait-for-pid swap find-process
 | 
					    pid wait-for-pid
 | 
				
			||||||
 | 
					    pid find-process
 | 
				
			||||||
    dup [ swap notify-exit ] [ 2drop ] if ;
 | 
					    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 -- )
 | 
					: handle-kevent ( mx kevent -- )
 | 
				
			||||||
    dup kevent-ident swap kevent-filter {
 | 
					    [ ] [ kevent-ident ] [ kevent-filter ] tri {
 | 
				
			||||||
        { [ dup EVFILT_READ = ] [ drop kevent-read-task ] }
 | 
					        { [ dup EVFILT_READ = ] [ drop kevent-read-task ] }
 | 
				
			||||||
        { [ dup EVFILT_WRITE = ] [ drop kevent-write-task ] }
 | 
					        { [ dup EVFILT_WRITE = ] [ drop kevent-write-task ] }
 | 
				
			||||||
        { [ dup EVFILT_PROC = ] [ drop kevent-proc-task drop ] }
 | 
					        { [ dup EVFILT_PROC = ] [ drop kevent-proc-task ] }
 | 
				
			||||||
 | 
					        { [ dup EVFILT_VNODE = ] [ drop kevent-vnode-task ] }
 | 
				
			||||||
    } cond ;
 | 
					    } cond ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: handle-kevents ( mx n -- )
 | 
					: handle-kevents ( mx n -- )
 | 
				
			||||||
    [ over kqueue-mx-events kevent-nth handle-kevent ] with each ;
 | 
					    [ over events>> kevent-nth handle-kevent ] with each ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
M: kqueue-mx wait-for-events ( ms mx -- )
 | 
					M: kqueue-mx wait-for-events ( ms mx -- )
 | 
				
			||||||
    swap dup [ make-timespec ] when
 | 
					    swap dup [ make-timespec ] when
 | 
				
			||||||
    dupd wait-kevent handle-kevents ;
 | 
					    dupd wait-kevent handle-kevents ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					! Procs
 | 
				
			||||||
: make-proc-kevent ( pid -- kevent )
 | 
					: make-proc-kevent ( pid -- kevent )
 | 
				
			||||||
    "kevent" <c-object>
 | 
					    "kevent" <c-object>
 | 
				
			||||||
    tuck set-kevent-ident
 | 
					    tuck set-kevent-ident
 | 
				
			||||||
| 
						 | 
					@ -77,5 +104,44 @@ M: kqueue-mx wait-for-events ( ms mx -- )
 | 
				
			||||||
    EVFILT_PROC over set-kevent-filter
 | 
					    EVFILT_PROC over set-kevent-filter
 | 
				
			||||||
    NOTE_EXIT over set-kevent-fflags ;
 | 
					    NOTE_EXIT over set-kevent-fflags ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: add-pid-task ( pid mx -- )
 | 
					: register-pid-task ( pid mx -- )
 | 
				
			||||||
    swap make-proc-kevent swap register-kevent ;
 | 
					    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 construct-monitor swap >>fd
 | 
				
			||||||
 | 
					    [ dup kqueue-mx get register-monitor ] [ ] [ fd>> close ] cleanup ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					M: vnode-monitor dispose
 | 
				
			||||||
 | 
					    [ kqueue-mx get unregister-monitor ] [ fd>> close ] bi ;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,9 +55,6 @@ M: linux-monitor dispose ( monitor -- )
 | 
				
			||||||
    [ wd>> watches get delete-at ]
 | 
					    [ wd>> watches get delete-at ]
 | 
				
			||||||
    [ wd>> inotify-fd swap inotify_rm_watch io-error ] bi ;
 | 
					    [ wd>> inotify-fd swap inotify_rm_watch io-error ] bi ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: ?flag ( n mask symbol -- n )
 | 
					 | 
				
			||||||
    pick rot bitand 0 > [ , ] [ drop ] if ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
: ignore-flags? ( mask -- ? )
 | 
					: ignore-flags? ( mask -- ? )
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IN_DELETE_SELF
 | 
					        IN_DELETE_SELF
 | 
				
			||||||
| 
						 | 
					@ -76,7 +73,7 @@ M: linux-monitor dispose ( monitor -- )
 | 
				
			||||||
        IN_MOVED_FROM +rename-file-old+ ?flag
 | 
					        IN_MOVED_FROM +rename-file-old+ ?flag
 | 
				
			||||||
        IN_MOVED_TO +rename-file-new+ ?flag
 | 
					        IN_MOVED_TO +rename-file-new+ ?flag
 | 
				
			||||||
        drop
 | 
					        drop
 | 
				
			||||||
    ] { } make ;
 | 
					    ] { } make prune ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
: parse-file-notify ( buffer -- path changed )
 | 
					: parse-file-notify ( buffer -- path changed )
 | 
				
			||||||
    dup inotify-event-mask ignore-flags? [
 | 
					    dup inotify-event-mask ignore-flags? [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue