105 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Factor
		
	
	
! Copyright (C) 2008 Slava Pestov.
 | 
						|
! See http://factorcode.org/license.txt for BSD license.
 | 
						|
USING: accessors sequences assocs arrays continuations
 | 
						|
destructors combinators kernel threads concurrency.messaging
 | 
						|
concurrency.mailboxes concurrency.promises io.files io.monitors
 | 
						|
debugger fry ;
 | 
						|
IN: io.monitors.recursive
 | 
						|
 | 
						|
! Simulate recursive monitors on platforms that don't have them
 | 
						|
 | 
						|
TUPLE: recursive-monitor < monitor children thread ready disposed ;
 | 
						|
 | 
						|
: notify? ( -- ? ) monitor tget ready>> promise-fulfilled? ;
 | 
						|
 | 
						|
DEFER: add-child-monitor
 | 
						|
 | 
						|
: qualify-path ( path -- path' )
 | 
						|
    monitor tget path>> prepend-path ;
 | 
						|
 | 
						|
: add-child-monitors ( path -- )
 | 
						|
    #! We yield since this directory scan might take a while.
 | 
						|
    dup [
 | 
						|
        [ append-path ] with map
 | 
						|
        [ add-child-monitor ] each yield
 | 
						|
    ] with-directory-files ;
 | 
						|
 | 
						|
: add-child-monitor ( path -- )
 | 
						|
    notify? [ dup { +add-file+ } monitor tget queue-change ] when
 | 
						|
    qualify-path dup link-info directory? [
 | 
						|
        [ add-child-monitors ]
 | 
						|
        [
 | 
						|
            '[
 | 
						|
                _ [ f my-mailbox (monitor) ] keep
 | 
						|
                monitor tget children>> set-at
 | 
						|
            ] ignore-errors
 | 
						|
        ] bi
 | 
						|
    ] [ drop ] if ;
 | 
						|
 | 
						|
: remove-child-monitor ( monitor -- )
 | 
						|
    monitor tget children>> delete-at* [ dispose ] [ drop ] if ;
 | 
						|
 | 
						|
M: recursive-monitor dispose*
 | 
						|
    [ "stop" swap thread>> send-synchronous drop ]
 | 
						|
    [ queue>> dispose ]
 | 
						|
    bi ;
 | 
						|
 | 
						|
: stop-pump ( -- )
 | 
						|
    monitor tget children>> [ nip dispose ] assoc-each ;
 | 
						|
 | 
						|
: pump-step ( msg -- )
 | 
						|
    first3 path>> swap [ prepend-path ] dip monitor tget 3array
 | 
						|
    monitor tget queue>>
 | 
						|
    mailbox-put ;
 | 
						|
 | 
						|
: child-added ( path monitor -- )
 | 
						|
    path>> prepend-path add-child-monitor ;
 | 
						|
 | 
						|
: child-removed ( path monitor -- )
 | 
						|
    path>> prepend-path remove-child-monitor ;
 | 
						|
 | 
						|
: update-hierarchy ( msg -- )
 | 
						|
    first3 swap [
 | 
						|
        {
 | 
						|
            { +add-file+ [ child-added ] }
 | 
						|
            { +remove-file+ [ child-removed ] }
 | 
						|
            { +rename-file-old+ [ child-removed ] }
 | 
						|
            { +rename-file-new+ [ child-added ] }
 | 
						|
            [ 3drop ]
 | 
						|
        } case
 | 
						|
    ] with with each ;
 | 
						|
 | 
						|
: pump-loop ( -- )
 | 
						|
    receive dup synchronous? [
 | 
						|
        [ stop-pump t ] dip reply-synchronous
 | 
						|
    ] [
 | 
						|
        [ '[ _ update-hierarchy ] ignore-errors ] [ pump-step ] bi
 | 
						|
        pump-loop
 | 
						|
    ] if ;
 | 
						|
 | 
						|
: monitor-ready ( error/t -- )
 | 
						|
    monitor tget ready>> fulfill ;
 | 
						|
 | 
						|
: pump-thread ( monitor -- )
 | 
						|
    monitor tset
 | 
						|
    [ "" add-child-monitor t monitor-ready ]
 | 
						|
    [ [ self <linked-error> monitor-ready ] keep rethrow ]
 | 
						|
    recover
 | 
						|
    pump-loop ;
 | 
						|
 | 
						|
: start-pump-thread ( monitor -- )
 | 
						|
    dup '[ _ pump-thread ]
 | 
						|
    "Recursive monitor pump" spawn
 | 
						|
    >>thread drop ;
 | 
						|
 | 
						|
: wait-for-ready ( monitor -- )
 | 
						|
    ready>> ?promise ?linked drop ;
 | 
						|
 | 
						|
: <recursive-monitor> ( path mailbox -- monitor )
 | 
						|
    [ (normalize-path) ] dip
 | 
						|
    recursive-monitor new-monitor
 | 
						|
        H{ } clone >>children
 | 
						|
        <promise> >>ready
 | 
						|
    dup start-pump-thread
 | 
						|
    dup wait-for-ready ;
 |