1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel io.backend io.monitors io.monitors.recursive
4 io.files io.pathnames io.buffers io.ports io.timeouts
5 io.backend.unix io.encodings.utf8 unix.linux.inotify assocs
6 namespaces make threads continuations init math math.bitwise
7 sets alien alien.strings alien.c-types vocabs.loader accessors
8 system hashtables destructors unix classes.struct ;
15 TUPLE: linux-monitor < monitor wd inotify watches ;
17 : <linux-monitor> ( wd path mailbox -- monitor )
18 linux-monitor new-monitor
23 : wd>monitor ( wd -- monitor ) watches get at ;
25 : <inotify> ( -- port/f )
26 inotify_init dup 0 < [ drop f ] [ <fd> init-fd <input-port> ] if ;
28 : inotify-fd ( -- fd ) inotify get handle>> handle-fd ;
30 : check-existing ( wd -- )
32 "Cannot open multiple monitors for the same file" throw
35 : (add-watch) ( path mask -- wd )
36 inotify-fd -rot inotify_add_watch dup io-error dup check-existing ;
38 : add-watch ( path mask mailbox -- monitor )
39 [ [ absolute-path ] dip [ (add-watch) ] [ drop ] 2bi ] dip
40 <linux-monitor> [ ] [ ] [ wd>> ] tri watches get set-at ;
42 : check-inotify ( -- )
44 "Calling <monitor> outside with-monitors" throw
47 M: linux (monitor) ( path recursive? mailbox -- monitor )
52 IN_CHANGE_EVENTS swap add-watch
55 M: linux-monitor dispose* ( monitor -- )
56 [ [ wd>> ] [ watches>> ] bi delete-at ]
58 dup inotify>> disposed>> [ drop ] [
59 [ inotify>> handle>> handle-fd ] [ wd>> ] bi
60 inotify_rm_watch io-error
64 : ignore-flags? ( mask -- ? )
73 : parse-action ( mask -- changed )
75 IN_CREATE +add-file+ ?flag
76 IN_DELETE +remove-file+ ?flag
77 IN_MODIFY +modify-file+ ?flag
78 IN_ATTRIB +modify-file+ ?flag
79 IN_MOVED_FROM +rename-file-old+ ?flag
80 IN_MOVED_TO +rename-file-new+ ?flag
84 : parse-event-name ( event -- name )
86 [ drop "" ] [ name>> utf8 alien>string ] if ;
88 : parse-file-notify ( buffer -- path changed )
89 dup mask>> ignore-flags? [
92 [ parse-event-name ] [ mask>> parse-action ] bi
95 : events-exhausted? ( i buffer -- ? )
98 : inotify-event@ ( i buffer -- inotify-event )
99 ptr>> <displaced-alien> inotify-event memory>struct ;
101 : next-event ( i buffer -- i buffer )
103 len>> inotify-event heap-size +
106 : parse-file-notifications ( i buffer -- )
107 2dup events-exhausted? [ 2drop ] [
108 2dup inotify-event@ dup wd>> wd>monitor
109 [ parse-file-notify ] dip queue-change
110 next-event parse-file-notifications
113 : inotify-read-loop ( port -- )
115 dup wait-to-read drop
116 0 over buffer>> parse-file-notifications
117 0 over buffer>> buffer-reset
120 : inotify-read-thread ( port -- )
121 [ inotify-read-loop ] curry ignore-errors ;
123 M: linux init-monitors
124 H{ } clone watches set
128 [ inotify-read-thread ] curry
129 "Linux monitor thread" spawn drop
132 "Linux kernel version is too old" throw
135 M: linux dispose-monitors
136 inotify get dispose ;