container: start from locked thread
Some checks failed
Test / Create distribution (push) Successful in 33s
Test / Hakurei (push) Failing after 1m1s
Test / Sandbox (race detector) (push) Failing after 1m41s
Test / Hakurei (race detector) (push) Failing after 2m42s
Test / Sandbox (push) Failing after 1m19s
Test / Hpkg (push) Failing after 1m39s
Test / Flake checks (push) Has been skipped

This allows setup that relies on per-thread state like securebits and landlock, from the parent side.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-08-17 17:26:20 +09:00
parent f35733810e
commit 0ba993ec39
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q

View File

@ -9,6 +9,7 @@ import (
"io" "io"
"os" "os"
"os/exec" "os/exec"
"runtime"
"strconv" "strconv"
. "syscall" . "syscall"
"time" "time"
@ -36,6 +37,8 @@ type (
setup *gob.Encoder setup *gob.Encoder
// cancels cmd // cancels cmd
cancel context.CancelFunc cancel context.CancelFunc
// closed after Wait returns
wait chan struct{}
Stdin io.Reader Stdin io.Reader
Stdout io.Writer Stdout io.Writer
@ -170,11 +173,23 @@ func (p *Container) Start() error {
} }
p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, p.ExtraFiles...) p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, p.ExtraFiles...)
msg.Verbose("starting container init") done := make(chan error, 1)
if err := p.cmd.Start(); err != nil { go func() {
return msg.WrapErr(err, err.Error()) runtime.LockOSThread()
} p.wait = make(chan struct{})
return nil
done <- func() error { // setup depending on per-thread state must happen here
msg.Verbose("starting container init")
if err := p.cmd.Start(); err != nil {
return msg.WrapErr(err, err.Error())
}
return nil
}()
// keep this thread alive until Wait returns for cancel
<-p.wait
}()
return <-done
} }
// Serve serves [Container.Params] to the container init. // Serve serves [Container.Params] to the container init.
@ -215,8 +230,14 @@ func (p *Container) Serve() error {
return err return err
} }
// Wait waits for the container init process to exit. // Wait waits for the container init process to exit and releases any resources associated with the [Container].
func (p *Container) Wait() error { defer p.cancel(); return p.cmd.Wait() } func (p *Container) Wait() error {
if p.wait == nil {
return EINVAL
}
defer func() { close(p.wait); p.cancel(); p.wait = nil }()
return p.cmd.Wait()
}
func (p *Container) String() string { func (p *Container) String() string {
return fmt.Sprintf("argv: %q, filter: %v, rules: %d, flags: %#x, presets: %#x", return fmt.Sprintf("argv: %q, filter: %v, rules: %d, flags: %#x, presets: %#x",