doc/news.texi | 8 ++++++++ js.go | 26 ++++++++++---------------- main.go | 16 ++++++++++++++++ run.go | 9 +++++++++ usage.go | 2 +- diff --git a/doc/news.texi b/doc/news.texi index faf7c77072a06d626a142879516664096b7c4af6e134afa3fb4d2287412a776c..34d3156f3a07c8f589541eaeaa0f32531f4a25a780d828038bd410874c13fbd9 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -1,6 +1,14 @@ @node News @unnumbered News +@anchor{Release 1_17_0} +@section Release 1.17.0 +@itemize +@item + If @command{redo*} process is killed, then it sends @code{SIGTERM} + to all his children too, properly terminating the whole job queue. +@end itemize + @anchor{Release 1_16_0} @section Release 1.16.0 @itemize diff --git a/js.go b/js.go index 4ab392a8f3dc174e575c052e8a5ca96e6eefd0d2e1e1389c4cc3e12ecba59724..c7123f41d71942b864ef2c4017152d95d33208fed368a57cae9bf575faf23210 100644 --- a/js.go +++ b/js.go @@ -24,11 +24,9 @@ "flag" "fmt" "log" "os" - "os/signal" "regexp" "strconv" "sync" - "syscall" ) const ( @@ -170,20 +168,6 @@ jsToken = byte(jsTokenInt) jsTokens[jsToken]++ jsRelease("ifchange entered", jsToken) } - - killed := make(chan os.Signal, 0) - signal.Notify(killed, syscall.SIGTERM, syscall.SIGINT) - go func() { - <-killed - jsTokensM.Lock() - for token, i := range jsTokens { - for ; i > 0; i-- { - jsReleaseNoLock(token) - } - } - jsTokensM.Unlock() - os.Exit(1) - }() } func jsReleaseNoLock(token byte) { @@ -200,6 +184,16 @@ trace(CJS, "release from %s", ctx) jsTokensM.Lock() jsTokens[token]-- jsReleaseNoLock(token) + jsTokensM.Unlock() +} + +func jsReleaseAll() { + jsTokensM.Lock() + for token, i := range jsTokens { + for ; i > 0; i-- { + jsReleaseNoLock(token) + } + } jsTokensM.Unlock() } diff --git a/main.go b/main.go index 9db16649b67d9c2c2b8e8c04e895973fa2a7b0a17700ffe8bb1cdbfd262ce17e..bc62bc436b3f6dccef4022fdb56bc23aefae72f9a4dee82745ebc588e1646f49 100644 --- a/main.go +++ b/main.go @@ -27,11 +27,13 @@ "io" "io/ioutil" "log" "os" + "os/signal" "path" "path/filepath" "runtime" "sort" "strconv" + "syscall" "go.cypherpunks.ru/recfile" "golang.org/x/sys/unix" @@ -281,6 +283,20 @@ if path.IsAbs(tgt) { tgts[i] = cwdMustRel(tgt) } } + + killed := make(chan os.Signal, 0) + signal.Notify(killed, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) + go func() { + <-killed + trace(CDebug, "[%s] killed", BuildUUID) + jsReleaseAll() + RunningProcsM.Lock() + for pid, proc := range RunningProcs { + trace(CDebug, "[%s] killing child %d", BuildUUID, pid) + proc.Signal(syscall.SIGTERM) + } + os.Exit(1) + }() ok := true err = nil diff --git a/run.go b/run.go index 4055dcd4bc2c9668098f26b592ff9b043bee20299a6bc268aa9c40a42dfa76f9..78032c31869cd7f84bf5b1d67ff81992fde5e90d9591acab863609c6cdc53df1 100644 --- a/run.go +++ b/run.go @@ -73,6 +73,9 @@ flagStderrKeep *bool flagStderrSilent *bool TracedAll bool + + RunningProcs = map[int]*os.Process{} + RunningProcsM sync.Mutex ) func init() { @@ -546,6 +549,9 @@ runErr.Err = err errs <- runErr return } + RunningProcsM.Lock() + RunningProcs[cmd.Process.Pid] = cmd.Process + RunningProcsM.Unlock() pid := fmt.Sprintf("[%d]", cmd.Process.Pid) trace(CDebug, "%s runs %s", tgtOrig, pid) @@ -582,6 +588,9 @@ // Wait for job completion <-stderrTerm err = cmd.Wait() + RunningProcsM.Lock() + delete(RunningProcs, cmd.Process.Pid) + RunningProcsM.Unlock() finished = time.Now() runErr.Finished = &finished if err != nil { diff --git a/usage.go b/usage.go index d196b5c37cc8bcb88dd8acd7a43018ebfa99dfcd0b46e07f6fd7fb48c2dde4c0..db5d24d709a551a8caee95ad16047b4e4cce5a84dde86d12f51d634beecd2306 100644 --- a/usage.go +++ b/usage.go @@ -24,7 +24,7 @@ "os" ) const ( - Version = "1.16.0" + Version = "1.17.0" Warranty = `Copyright (C) 2020-2021 Sergey Matveev This program is free software: you can redistribute it and/or modify