Linux inotify support work in progress

db4
sheeple 2008-02-02 11:51:16 -06:00
parent d58cc176fe
commit ff46bfaa96
3 changed files with 138 additions and 8 deletions

View File

@ -1,15 +1,136 @@
! 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: kernel io.backend io.monitor io.monitor.private io.files
io.buffers io.nonblocking io.unix.backend io.unix.select
io.unix.launcher unix.linux.inotify assocs namespaces threads
continuations init math alien.c-types alien ;
IN: io.unix.linux IN: io.unix.linux
USING: io.backend io.unix.backend io.unix.launcher io.unix.select
namespaces kernel assocs unix.process init ;
TUPLE: linux-io ; TUPLE: linux-io ;
INSTANCE: linux-io unix-io INSTANCE: linux-io unix-io
TUPLE: linux-monitor path wd callback ;
: <linux-monitor> ( path wd -- monitor )
f (monitor) {
set-linux-monitor-path
set-linux-monitor-wd
set-delegate
} linux-monitor construct ;
TUPLE: inotify watches ;
: wd>path ( wd -- path )
inotify get-global inotify-watches at linux-monitor-path ;
: <inotify> ( -- port )
H{ } clone
inotify_init dup io-error inotify <buffered-port>
{ set-inotify-watches set-delegate } inotify construct ;
: inotify-fd inotify get-global port-handle ;
: watches inotify get-global inotify-watches ;
: (add-watch) ( path mask -- wd )
inotify-fd -rot inotify_add_watch dup io-error ;
: check-existing ( wd -- )
watches key? [
"Cannot open multiple monitors for the same file" throw
] when ;
: add-watch ( path mask -- monitor )
dupd (add-watch)
dup check-existing
[ <linux-monitor> dup ] keep watches set-at ;
: remove-watch ( monitor -- )
dup linux-monitor-wd watches delete-at
linux-monitor-wd inotify-fd swap inotify_rm_watch io-error ;
M: linux-io <monitor> ( path recursive? -- monitor )
drop IN_CHANGE_EVENTS add-watch ;
: notify-callback ( assoc monitor -- )
linux-monitor-callback dup
[ schedule-thread-with ] [ 2drop ] if ;
M: linux-io fill-queue ( monitor -- assoc )
dup linux-monitor-callback [
"Cannot wait for changes on the same file from multiple threads" throw
] when
[ swap set-linux-monitor-callback stop ] callcc1
swap check-monitor ;
M: linux-monitor dispose ( monitor -- )
dup check-monitor
t over set-monitor-closed?
H{ } over notify-callback
remove-watch ;
: ?flag ( n mask symbol -- n )
pick rot bitand 0 > [ , ] [ drop ] if ;
: parse-action ( mask -- changed )
[
IN_CREATE +add-file+ ?flag
IN_DELETE +remove-file+ ?flag
IN_DELETE_SELF +remove-file+ ?flag
IN_MODIFY +modify-file+ ?flag
IN_ATTRIB +modify-file+ ?flag
IN_MOVED_FROM +rename-file+ ?flag
IN_MOVED_TO +rename-file+ ?flag
IN_MOVE_SELF +rename-file+ ?flag
drop
] { } make ;
: parse-file-notify ( buffer -- changed path )
{
inotify-event-wd
inotify-event-name
inotify-event-mask
} get-slots
parse-action -rot alien>char-string >r wd>path r> path+ ;
: events-exhausted? ( i buffer -- ? )
buffer-fill >= ;
: inotify-event@ ( i buffer -- alien )
buffer-ptr <displaced-alien> ;
: next-event ( i buffer -- i buffer )
2dup inotify-event@
inotify-event-len "inotify-event" heap-size +
swap >r + r> ;
: parse-file-notifications ( i buffer -- )
2dup events-exhausted? [ 2drop ] [
2dup inotify-event@ parse-file-notify changed-file
next-event parse-file-notifications
] if ;
: read-notifications ( port -- )
dup refill drop
0 over parse-file-notifications
0 swap buffer-reset ;
TUPLE: inotify-task ;
: <inotify-task> ( port -- task )
f inotify-task <input-task> ;
: init-inotify ( mx -- )
<inotify>
dup inotify set-global
<inotify-task> swap register-io-task ;
M: inotify-task do-io-task ( task -- )
io-task-port read-notifications f ;
M: linux-io init-io ( -- ) M: linux-io init-io ( -- )
<select-mx> mx set-global ; <select-mx> mx set-global ; ! init-inotify ;
T{ linux-io } set-io-backend T{ linux-io } set-io-backend

View File

@ -1,6 +1,6 @@
! 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.syntax ; USING: alien.syntax math math.bitfields ;
IN: unix.linux.inotify IN: unix.linux.inotify
C-STRUCT: inotify-event C-STRUCT: inotify-event
@ -8,7 +8,7 @@ C-STRUCT: inotify-event
{ "uint" "mask" } ! watch mask { "uint" "mask" } ! watch mask
{ "uint" "cookie" } ! cookie to synchronize two events { "uint" "cookie" } ! cookie to synchronize two events
{ "uint" "len" } ! length (including nulls) of name { "uint" "len" } ! length (including nulls) of name
{ "char[1]" "name" } ! stub for possible name { "char[0]" "name" } ! stub for possible name
; ;
: IN_ACCESS HEX: 1 ; inline ! File was accessed : IN_ACCESS HEX: 1 ; inline ! File was accessed
@ -37,6 +37,13 @@ C-STRUCT: inotify-event
: IN_ISDIR HEX: 40000000 ; inline ! event occurred against dir : IN_ISDIR HEX: 40000000 ; inline ! event occurred against dir
: IN_ONESHOT HEX: 80000000 ; inline ! only send event once : IN_ONESHOT HEX: 80000000 ; inline ! only send event once
: IN_CHANGE_EVENTS
{
IN_MODIFY IN_ATTRIB IN_MOVED_FROM
IN_MOVED_TO IN_DELETE IN_CREATE IN_DELETE_SELF
IN_MOVE_SELF
} flags ; foldable
: IN_ALL_EVENTS : IN_ALL_EVENTS
{ {
IN_ACCESS IN_MODIFY IN_ATTRIB IN_CLOSE_WRITE IN_ACCESS IN_MODIFY IN_ATTRIB IN_CLOSE_WRITE
@ -45,6 +52,6 @@ C-STRUCT: inotify-event
IN_MOVE_SELF IN_MOVE_SELF
} flags ; foldable } flags ; foldable
FUNCTION: int inotify_init ( void ) ; FUNCTION: int inotify_init ( ) ;
FUNCTION: int inotify_add_watch ( int fd, char* name, u32 mask ) ; FUNCTION: int inotify_add_watch ( int fd, char* name, uint mask ) ;
FUNCTION: int inotify_rm_watch ( int fd, u32 wd ) ; FUNCTION: int inotify_rm_watch ( int fd, uint wd ) ;

View File

@ -1,3 +1,5 @@
#include <sys/syscall.h>
#define UNKNOWN_TYPE_P(file) ((file)->d_type == DT_UNKNOWN) #define UNKNOWN_TYPE_P(file) ((file)->d_type == DT_UNKNOWN)
#define DIRECTORY_P(file) ((file)->d_type == DT_DIR) #define DIRECTORY_P(file) ((file)->d_type == DT_DIR)