diff options
author | Camil Staps | 2016-05-21 10:48:26 +0200 |
---|---|---|
committer | Camil Staps | 2016-05-21 10:48:26 +0200 |
commit | f2edfd5037e6dd4fa10e00b64cbd62f6cc50daa1 (patch) | |
tree | b99defa2382d269cd502bafaa3c05dd265e01a7e | |
parent | 80 chars (diff) |
Also pass event->name through; inotify_loop_forever
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Inotify.dcl | 4 | ||||
-rw-r--r-- | Inotify.icl | 38 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | inotify_c.c | 16 | ||||
-rw-r--r-- | test.icl | 29 | ||||
-rw-r--r-- | test_reload.icl | 69 | ||||
-rw-r--r-- | test_reload.prj | 59 |
8 files changed, 196 insertions, 29 deletions
@@ -1,7 +1,6 @@ # Executables *.exe *.out -test # Directory used to store object files, abc files and assembly files Clean System Files/ @@ -9,3 +8,6 @@ Clean System Files/ # iTasks environment extra data *-data/ sapl/ + +test +test_reload diff --git a/Inotify.dcl b/Inotify.dcl index e021c45..3811abc 100644 --- a/Inotify.dcl +++ b/Inotify.dcl @@ -9,7 +9,7 @@ from Data.Maybe import ::Maybe :: INMask :== Int :: INEvent :== Int -:: INCallback st :== INEvent st *World -> *(st, *World) +:: INCallback st :== INEvent (Maybe String) st *World -> *(st, *World) (|-) infixl 6 :: (INMask INMask -> INMask) @@ -23,6 +23,8 @@ inotify_rm_watch :: !INWatch !*(Inotify st) -> *(Bool, *Inotify st) inotify_poll :: *(Inotify st) -> *Inotify st inotify_check :: *(Inotify st) *World -> *(*Inotify st, *World) +inotify_loop_forever :: *(Inotify st) *World -> *(*Inotify st, *World) + IN_ACCESS :== 0x00000001 // File was accessed IN_MODIFY :== 0x00000002 // File was modified IN_ATTRIB :== 0x00000004 // Metadata changed diff --git a/Inotify.icl b/Inotify.icl index 20ce3e9..e676f03 100644 --- a/Inotify.icl +++ b/Inotify.icl @@ -1,6 +1,7 @@ implementation module Inotify import Data.Either +import Data.List import Data.Maybe import StdArray @@ -74,22 +75,25 @@ where inotify_check :: *(Inotify st) *World -> *(*Inotify st, *World) inotify_check inot=:{fd,watches,state} w - # (ok, wds, masks, fd) = c_check fd + # (ok, wds, masks, fnames, fd) = c_check fd inot = { inot & fd=fd } | not ok = (inot, w) | (size wds) rem 4 <> 0 || (size masks) rem 4 <> 0 = (inot,w) - # (wds,masks) = (split 4 wds, split 4 masks) + # (wds,masks,fnames) = (split 4 wds, split 4 masks, splitOn '\0' fnames) | length wds <> length masks = (inot, w) - # wdsmasks = zip2 (map bytesToInt wds) (map bytesToInt masks) - # (fd,st,w`) = seq (map (check wdsmasks) watches) (inot.fd, state, w) + # infos = zip3 (map bytesToInt wds) (map bytesToInt masks) fnames + # (fd,st,w`) = seq (map (check infos) watches) (inot.fd, state, w) = ({ inot & fd=fd, state=st }, w`) where - check :: [(Int,Int)] (INWatch, INCallback st) *(*Int, st, *World) + check :: [(Int,Int,String)] (INWatch, INCallback st) *(*Int, st, *World) -> *(*Int, st, *World) - check wdsmasks (watch,f) (fd,st,w) - # (st,w) = seq [\(st,w) -> f mask st w - \\ (wd,mask) <- wdsmasks | wd == watch] (st,w) + check infos (watch,f) (fd,st,w) + # (st,w) = seq [\(st,w) -> f mask (toMaybe name) st w + \\ (wd,mask,name) <- infos | wd == watch] (st,w) = (fd,st,w) + where + toMaybe :: String -> Maybe String + toMaybe s = if (s=="") Nothing (Just s) bytesToInt :: {#Char} -> Int bytesToInt cs = sum [toInt c * (8 ^ p) \\ c <-: cs & p <- [0..]] @@ -99,12 +103,26 @@ where | size s > n = [s % (0,n-1) : split n (s % (n, size s - 1))] | size s == n = [s] | s == "" = [] + + splitOn :: Char String -> [String] + splitOn c s = map toString (split` c [c \\ c <-: s]) + where + split` :: Char [Char] -> [[Char]] + split` c [] = [] + split` c cs=:[x:xs] + = let (l,r) = span ((<>)c) cs in [l:split` c (removeMember c r)] - c_check :: !*Int -> *(!Bool, !String, !String, !*Int) + c_check :: !*Int -> *(!Bool, !String, !String, !String, !*Int) c_check fd = code { - ccall clean_inotify_check "I:VISSI" + ccall clean_inotify_check "I:VISSSI" } +inotify_loop_forever :: *(Inotify st) *World -> *(*Inotify st, *World) +inotify_loop_forever inot w + # inot = inotify_poll inot + # (inot,w) = inotify_check inot w + = inotify_loop_forever inot w + errno :: Int errno = err 0 where @@ -11,9 +11,15 @@ $(INO_OBJ): inotify_c.c test: test.icl $(wildcard *.*cl) $(INO_OBJ) $(CPM) project $@.prj build +test_reload: test_reload.icl $(wildcard *.*cl) $(INO_OBJ) + $(CPM) project $@.prj build + run_test: test ./test +run_test_reload: test_reload + while :; do ./test_reload; done + clean: rm -rfv Clean\ System\ Files diff --git a/inotify_c.c b/inotify_c.c index f178fa6..c81f57d 100644 --- a/inotify_c.c +++ b/inotify_c.c @@ -54,9 +54,11 @@ void clean_poll(int fd, int *re_nrevents, int *re_fd) { static CleanStringVariable(wds_string, 1024); static CleanStringVariable(masks_string, 1024); +static CleanStringVariable(names_string, 4096); void clean_inotify_check(int fd, - int *re_ok, CleanString* re_wds, CleanString* re_masks, int *re_fd) { + int *re_ok, CleanString* re_wds, CleanString* re_masks, + CleanString* re_fnames, int *re_fd) { char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); const struct inotify_event *ev; ssize_t len; @@ -67,17 +69,20 @@ void clean_inotify_check(int fd, char *wds_ptr = CleanStringCharacters(wds_string); char *masks_ptr = CleanStringCharacters(masks_string); + char *names_ptr = CleanStringCharacters(names_string); CleanStringLength(wds_string) = 0; CleanStringLength(masks_string) = 0; + CleanStringLength(names_string) = 0; *re_ok = 0; *re_fd = fd; *re_wds = (CleanString) &empty_string; *re_masks = (CleanString) &empty_string; + *re_fnames = (CleanString) &empty_string; for (;;) { - poll_n = poll(&pfd, 1, 50); + poll_n = poll(&pfd, 1, 0); if (poll_n < 0) { return; } else if (poll_n == 0) { @@ -103,11 +108,18 @@ void clean_inotify_check(int fd, memcpy(wds_ptr, &ev->wd, sizeof(int)); wds_ptr += sizeof(int); CleanStringLength(wds_string) += sizeof(int); + + int len = strlen(ev->name); + memcpy(names_ptr, &ev->name, len); + names_ptr += len + 1; + *(names_ptr - 1) = '\00'; + CleanStringLength(names_string) += len + 1; } } *re_wds = (CleanString) wds_string; *re_masks = (CleanString) masks_string; + *re_fnames = (CleanString) names_string; *re_ok = 1; } @@ -11,21 +11,20 @@ Start w = inotify_add_watch (echo "file1") IN_ALL_EVENTS "file1" inot # (Right watch, inot) = inotify_add_watch (echo "file2") IN_ALL_EVENTS "file2" inot -# (io,w) = stdio w -# io = io <<< "Do something with file1 or file2\n" -# (ok,w) = fclose io w -# (inot, w) = loop inot w +# (io,w) = stdio w +# io = io <<< "Do something with file1 or file2\n" +# (ok,w) = fclose io w +# (inot, w) = inotify_loop_forever inot w = inotify_close inot where - loop :: !*(Inotify st) !*World -> *(*Inotify st, *World) - loop inot w - # inot = inotify_poll inot - # (inot, w) = inotify_check inot w - = loop inot w - - echo :: String INEvent Int *World -> *(Int, *World) - echo fname ev i w - # (io,w) = stdio w - # io = io <<< "EVENT: [" <<< fname <<< "; " <<< ev <<< "]\n" - # (ok,w) = fclose io w + echo :: String INEvent (Maybe String) Int *World -> *(Int, *World) + echo fname ev f i w + # (io,w) = stdio w + # io = io <<< "EVENT: ["<<< fname <<<"; "<<< ev <<<"; "<<< f <<<"]\n" + # (ok,w) = fclose io w = (i, w) + +instance <<< (Maybe a) | <<< a +where + (<<<) f Nothing = f + (<<<) f (Just x) = f <<< x diff --git a/test_reload.icl b/test_reload.icl new file mode 100644 index 0000000..052c4c9 --- /dev/null +++ b/test_reload.icl @@ -0,0 +1,69 @@ +module test_reload + +import StdBool +import StdClass +import StdFile +import StdFunc +import StdInt +import StdString +import Data.Either +import Data.Maybe +import Inotify + +/** test_reload + * + * This module will watch the directory it is in. Whenever the attributes of + * its own binaries change, it will exit. Hence, putting it in a loop: + * + * while :; do ./test_reload; done + * + * will give a program that automatically reloads itself when its binary has + * changed. + * + * Test it by running `make run_test_reload`, then editing `changeme` below and + * running `make test_reload` to recompile. + */ + +my_name :== "test_reload" +my_dir :== "." +changeme :== 42 +verbose :== False + +:: Void = Void + +Start w +# (io,w) = stdio w +# io = io <<< changeme <<< "\n" +# (ok,w) = fclose io w +# (Just inot) = inotify_init Void +# (Right watch,inot) = inotify_add_watch reload IN_ALL_EVENTS my_dir inot +# (inot,w) = inotify_loop_forever inot w += inotify_close inot +where + reload :: !INEvent (Maybe String) Void !*World -> *(Void, *World) + reload ev mbName _ w + # w = echo (\f -> f <<< "event: " <<< ev <<< "; " <<< mbName) w + | isNothing mbName = (Void, w) + # (Just name) = mbName + | ev bitand IN_ATTRIB <> 0 && name == my_name + # w = echo (\f -> f <<< "reloading...") w + # w = exit 127 w + = (Void, w) + = (Void, w) + + echo :: (*File -> *File) *World -> *World + echo f w + # (io,w) = stdio w + # io = if verbose (flip (<<<) "\n" o f) id io + # (ok,w) = fclose io w + = w + + exit :: !Int !*World -> *World + exit c w = code { + ccall exit "I:V:A" + } + +instance <<< (Maybe x) | <<< x +where + (<<<) f Nothing = f + (<<<) f (Just x) = f <<< x diff --git a/test_reload.prj b/test_reload.prj new file mode 100644 index 0000000..fa8ddec --- /dev/null +++ b/test_reload.prj @@ -0,0 +1,59 @@ +Version: 1.4 +Global + ProjectRoot: . + Target: StdEnv + Exec: {Project}/test_reload + CodeGen + CheckStacks: False + CheckIndexes: True + Application + HeapSize: 2097152 + StackSize: 512000 + ExtraMemory: 8192 + IntialHeapSize: 204800 + HeapSizeMultiplier: 4096 + ShowExecutionTime: False + ShowGC: False + ShowStackSize: False + MarkingCollector: False + DisableRTSFlags: False + StandardRuntimeEnv: True + Profile + Memory: False + MemoryMinimumHeapSize: 0 + Time: False + Stack: False + Output + Output: ShowConstructors + Font: Monaco + FontSize: 9 + WriteStdErr: False + Link + LinkMethod: Static + GenerateRelocations: False + GenerateSymbolTable: False + GenerateLinkMap: False + LinkResources: False + ResourceSource: + GenerateDLL: False + ExportedNames: + Paths + Path: {Project} + Path: {Application}/lib/clean-platform/OS-Independent + Path: {Application}/lib/Generics + Precompile: + Postlink: +MainModule + Name: test_reload + Dir: {Project} + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False |