mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-09-26 23:19:11 +08:00
Handle potential wait4 EINTR & add memory cgroup
This commit is contained in:
parent
53a90d3a09
commit
cf5ebfb3ef
@ -361,9 +361,13 @@ func start() (*types.Result, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cgroup memory: %v", err)
|
||||
}
|
||||
debug("cgroup: cpu: ", cpu, " memory: ", memory)
|
||||
cache, err := cg.FindMemoryStatProperty("cache")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cgroup cache %v", err)
|
||||
}
|
||||
debug("cgroup: cpu: ", cpu, " memory: ", memory, "cache: ", cache)
|
||||
rt.Time = time.Duration(cpu)
|
||||
rt.Memory = types.Size(memory)
|
||||
rt.Memory = types.Size(memory - cache)
|
||||
debug("cgroup:", rt)
|
||||
}
|
||||
return &rt, nil
|
||||
|
@ -97,7 +97,7 @@ func (c *containerServer) handleExecve(cmd *execCmd, msg *unixsocket.Msg) error
|
||||
<-waitDone
|
||||
// collect zombies
|
||||
for {
|
||||
if pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); err != syscall.EINTR || pid <= 0 {
|
||||
if _, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); err != nil && err != syscall.EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -108,6 +108,9 @@ func (c *containerServer) handleExecve(cmd *execCmd, msg *unixsocket.Msg) error
|
||||
var rusage syscall.Rusage
|
||||
if err == nil {
|
||||
_, err = syscall.Wait4(pid, &wstatus, 0, &rusage)
|
||||
for err == syscall.EINTR {
|
||||
_, err = syscall.Wait4(pid, &wstatus, 0, &rusage)
|
||||
}
|
||||
}
|
||||
// sync with kill goroutine
|
||||
close(waitDone)
|
||||
|
2
go.mod
2
go.mod
@ -4,5 +4,5 @@ go 1.14
|
||||
|
||||
require (
|
||||
github.com/seccomp/libseccomp-golang v0.9.1
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
|
||||
golang.org/x/sys v0.0.0-20200301040627-c5d0d7b4ec88
|
||||
)
|
||||
|
4
go.sum
4
go.sum
@ -1,4 +1,4 @@
|
||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200301040627-c5d0d7b4ec88 h1:LNVdAhESTW4gWDhYvciNcGoS9CEcxRiUKE9kSgw+X3s=
|
||||
golang.org/x/sys v0.0.0-20200301040627-c5d0d7b4ec88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1,6 +1,10 @@
|
||||
package cgroup
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// additional ideas:
|
||||
// cpu share(not used): cpu.share
|
||||
@ -110,6 +114,26 @@ func (c *CGroup) SetMemoryMaxUsageInBytes(i uint64) error {
|
||||
return c.memory.WriteUint("memory.max_usage_in_bytes", i)
|
||||
}
|
||||
|
||||
// FindMemoryStatProperty find certain property from memory.stat
|
||||
func (c *CGroup) FindMemoryStatProperty(prop string) (uint64, error) {
|
||||
content, err := c.memory.ReadFile("memory.stat")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r := bytes.NewReader(content)
|
||||
for {
|
||||
var p string
|
||||
var i uint64
|
||||
_, err = fmt.Fscanln(r, &p, &i)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if p == prop {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func remove(name string) error {
|
||||
if name != "" {
|
||||
return os.Remove(name)
|
||||
|
@ -2,6 +2,7 @@ package cgroup
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -28,7 +29,7 @@ func (c *SubCGroup) WriteUint(filename string, i uint64) error {
|
||||
if c.path == "" {
|
||||
return nil
|
||||
}
|
||||
return writeFileNoInterrupt(path.Join(c.path, filename), []byte(strconv.FormatUint(i, 10)))
|
||||
return c.WriteFile(filename, []byte(strconv.FormatUint(i, 10)))
|
||||
}
|
||||
|
||||
// ReadUint read uint64 into given file
|
||||
@ -36,7 +37,7 @@ func (c *SubCGroup) ReadUint(filename string) (uint64, error) {
|
||||
if c.path == "" {
|
||||
return 0, ErrNotInitialized
|
||||
}
|
||||
b, err := readFileNoInterrupt(path.Join(c.path, filename))
|
||||
b, err := c.ReadFile(filename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -47,37 +48,24 @@ func (c *SubCGroup) ReadUint(filename string) (uint64, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// writeFileNoInterrupt handles potential EINTR error while writes to
|
||||
// WriteFile writes cgroup file and handles potential EINTR error while writes to
|
||||
// the slow device (cgroup)
|
||||
func writeFileNoInterrupt(path string, content []byte) error {
|
||||
fd, err := syscall.Open(path, syscall.O_WRONLY|syscall.O_TRUNC|syscall.O_CLOEXEC, 0664)
|
||||
if err != nil {
|
||||
return err
|
||||
func (c *SubCGroup) WriteFile(name string, content []byte) error {
|
||||
p := path.Join(c.path, name)
|
||||
err := ioutil.WriteFile(p, content, 0664)
|
||||
for err != nil && errors.Is(err, syscall.EINTR) {
|
||||
err = ioutil.WriteFile(p, content, 0664)
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
_, err = syscall.Write(fd, content)
|
||||
for err == syscall.EINTR {
|
||||
_, err = syscall.Write(fd, content)
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
const maxUintFile = 64 // max file size 64 bytes (enough for uint)
|
||||
|
||||
// readFileNoInterrupt handles potential EINTR error while read to
|
||||
// ReadFile reads cgroup file and handles potential EINTR error while read to
|
||||
// the slow device (cgroup)
|
||||
func readFileNoInterrupt(path string) ([]byte, error) {
|
||||
fd, err := syscall.Open(path, syscall.O_RDONLY|syscall.O_CLOEXEC, 0664)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (c *SubCGroup) ReadFile(name string) ([]byte, error) {
|
||||
p := path.Join(c.path, name)
|
||||
data, err := ioutil.ReadFile(p)
|
||||
for err != nil && errors.Is(err, syscall.EINTR) {
|
||||
data, err = ioutil.ReadFile(p)
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
buff := make([]byte, maxUintFile)
|
||||
n, err := syscall.Read(fd, buff)
|
||||
for err == syscall.EINTR {
|
||||
n, err = syscall.Read(fd, buff)
|
||||
}
|
||||
return buff[:n], nil
|
||||
return data, err
|
||||
}
|
||||
|
@ -82,6 +82,10 @@ func (t *Tracer) TraceRun(c context.Context) (result types.Result) {
|
||||
// Ensure the process have called setpgid
|
||||
pid, err = unix.Wait4(pgid, &wstatus, unix.WALL, &rusage)
|
||||
}
|
||||
if err == unix.EINTR {
|
||||
t.Handler.Debug("wait4 EINTR")
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Handler.Debug("wait4 failed: ", err)
|
||||
result.Status = types.StatusRunnerError
|
||||
@ -288,7 +292,7 @@ func collectZombie(pgid int) {
|
||||
var wstatus unix.WaitStatus
|
||||
// collect zombies
|
||||
for {
|
||||
if _, err := unix.Wait4(-pgid, &wstatus, unix.WALL|unix.WNOHANG, nil); err != nil {
|
||||
if _, err := unix.Wait4(-pgid, &wstatus, unix.WALL|unix.WNOHANG, nil); err != unix.EINTR && err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,9 @@ func (r *Runner) trace(c context.Context, runner *forkexec.Runner) (result types
|
||||
fTime = time.Now()
|
||||
for {
|
||||
_, err := unix.Wait4(pgid, &wstatus, 0, &rusage)
|
||||
if err == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
r.println("wait4: ", wstatus)
|
||||
if err != nil {
|
||||
result.Status = types.StatusRunnerError
|
||||
@ -150,7 +153,7 @@ func killAll(pgid int) {
|
||||
func collectZombie(pgid int) {
|
||||
var wstatus unix.WaitStatus
|
||||
for {
|
||||
if _, err := unix.Wait4(-pgid, &wstatus, unix.WALL|unix.WNOHANG, nil); err != nil {
|
||||
if _, err := unix.Wait4(-pgid, &wstatus, unix.WALL|unix.WNOHANG, nil); err != unix.EINTR && err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user