From 5a34896b75f102f51c32f3bc153810c7b0fc813f Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 30 Jun 2021 21:07:23 +0100 Subject: [PATCH] Prevent zombie processes (#16314) Unfortunately go doesn't always ensure that execd processes are completely waited for. On linux this means that zombie processes can occur. This PR ensures that these are waited for by using signal notifier in serv and passing a context elsewhere. Signed-off-by: Andrew Thornton --- cmd/serv.go | 26 ++++++++++++++++++++++++-- modules/markup/external/external.go | 10 +++++++++- modules/ssh/ssh.go | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/cmd/serv.go b/cmd/serv.go index 1c9f5dc44e9d..40f8b89c9a98 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -6,14 +6,17 @@ package cmd import ( + "context" "fmt" "net/http" "net/url" "os" "os/exec" + "os/signal" "regexp" "strconv" "strings" + "syscall" "time" "code.gitea.io/gitea/models" @@ -273,12 +276,31 @@ func runServ(c *cli.Context) error { verb = strings.Replace(verb, "-", " ", 1) } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + // install notify + signalChannel := make(chan os.Signal, 1) + + signal.Notify( + signalChannel, + syscall.SIGINT, + syscall.SIGTERM, + ) + select { + case <-signalChannel: + case <-ctx.Done(): + } + cancel() + signal.Reset() + }() + var gitcmd *exec.Cmd verbs := strings.Split(verb, " ") if len(verbs) == 2 { - gitcmd = exec.Command(verbs[0], verbs[1], repoPath) + gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath) } else { - gitcmd = exec.Command(verb, repoPath) + gitcmd = exec.CommandContext(ctx, verb, repoPath) } gitcmd.Dir = setting.RepoRootPath diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index c849f505e7ee..e35a1b99c0fd 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -5,6 +5,7 @@ package external import ( + "context" "fmt" "io" "io/ioutil" @@ -15,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -96,7 +98,13 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. args = append(args, f.Name()) } - cmd := exec.Command(commands[0], args...) + processCtx, cancel := context.WithCancel(ctx.Ctx) + defer cancel() + + pid := process.GetManager().Add(fmt.Sprintf("Render [%s] for %s", commands[0], ctx.URLPrefix), cancel) + defer process.GetManager().Remove(pid) + + cmd := exec.CommandContext(processCtx, commands[0], args...) cmd.Env = append( os.Environ(), "GITEA_PREFIX_SRC="+ctx.URLPrefix, diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index bcaae5a1806d..c0897377c56f 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -66,7 +66,7 @@ func sessionHandler(session ssh.Session) { args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf} log.Trace("SSH: Arguments: %v", args) - cmd := exec.Command(setting.AppPath, args...) + cmd := exec.CommandContext(session.Context(), setting.AppPath, args...) cmd.Env = append( os.Environ(), "SSH_ORIGINAL_COMMAND="+command,