From ff46bfaa9610a95299a3afb0bac745c9825f7852 Mon Sep 17 00:00:00 2001 From: sheeple Date: Sat, 2 Feb 2008 11:51:16 -0600 Subject: [PATCH] Linux inotify support work in progress --- extra/io/unix/linux/linux.factor | 127 +++++++++++++++++++++++- extra/unix/linux/inotify/inotify.factor | 17 +++- vm/os-linux.h | 2 + 3 files changed, 138 insertions(+), 8 deletions(-) diff --git a/extra/io/unix/linux/linux.factor b/extra/io/unix/linux/linux.factor index 6d55decb5a..01d6159e45 100755 --- a/extra/io/unix/linux/linux.factor +++ b/extra/io/unix/linux/linux.factor @@ -1,15 +1,136 @@ ! Copyright (C) 2008 Slava Pestov. ! 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 -USING: io.backend io.unix.backend io.unix.launcher io.unix.select -namespaces kernel assocs unix.process init ; TUPLE: linux-io ; INSTANCE: linux-io unix-io +TUPLE: linux-monitor path wd callback ; + +: ( 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 ; + +: ( -- port ) + H{ } clone + inotify_init dup io-error inotify + { 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 + [ 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 ( 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 ; + +: 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 ; + +: ( port -- task ) + f inotify-task ; + +: init-inotify ( mx -- ) + + dup inotify set-global + swap register-io-task ; + +M: inotify-task do-io-task ( task -- ) + io-task-port read-notifications f ; + M: linux-io init-io ( -- ) - mx set-global ; + mx set-global ; ! init-inotify ; T{ linux-io } set-io-backend diff --git a/extra/unix/linux/inotify/inotify.factor b/extra/unix/linux/inotify/inotify.factor index 14840b380a..b7b721efc7 100644 --- a/extra/unix/linux/inotify/inotify.factor +++ b/extra/unix/linux/inotify/inotify.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: alien.syntax ; +USING: alien.syntax math math.bitfields ; IN: unix.linux.inotify C-STRUCT: inotify-event @@ -8,7 +8,7 @@ C-STRUCT: inotify-event { "uint" "mask" } ! watch mask { "uint" "cookie" } ! cookie to synchronize two events { "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 @@ -37,6 +37,13 @@ C-STRUCT: inotify-event : IN_ISDIR HEX: 40000000 ; inline ! event occurred against dir : 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_ACCESS IN_MODIFY IN_ATTRIB IN_CLOSE_WRITE @@ -45,6 +52,6 @@ C-STRUCT: inotify-event IN_MOVE_SELF } flags ; foldable -FUNCTION: int inotify_init ( void ) ; -FUNCTION: int inotify_add_watch ( int fd, char* name, u32 mask ) ; -FUNCTION: int inotify_rm_watch ( int fd, u32 wd ) ; +FUNCTION: int inotify_init ( ) ; +FUNCTION: int inotify_add_watch ( int fd, char* name, uint mask ) ; +FUNCTION: int inotify_rm_watch ( int fd, uint wd ) ; diff --git a/vm/os-linux.h b/vm/os-linux.h index 2b5371ff1b..1a1e088359 100644 --- a/vm/os-linux.h +++ b/vm/os-linux.h @@ -1,3 +1,5 @@ +#include + #define UNKNOWN_TYPE_P(file) ((file)->d_type == DT_UNKNOWN) #define DIRECTORY_P(file) ((file)->d_type == DT_DIR)