feat(executor/local): rlimit on CPU, Memory, Stack (#84)
This commit is contained in:
parent
bc31485de5
commit
1df6bf57df
|
@ -70,7 +70,16 @@ func (e *Local) generateResult(
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||||
result.Status = stage.StatusNonzeroExitStatus
|
status := exitErr.Sys().(syscall.WaitStatus)
|
||||||
|
if status.Signaled() {
|
||||||
|
signal := status.Signal()
|
||||||
|
switch signal {
|
||||||
|
case syscall.SIGXCPU:
|
||||||
|
result.Status = stage.StatusTimeLimitExceeded
|
||||||
|
default:
|
||||||
|
result.Status = stage.StatusNonzeroExitStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
result.Error = exitErr.Error()
|
result.Error = exitErr.Error()
|
||||||
} else {
|
} else {
|
||||||
result.Status = stage.StatusInternalError
|
result.Status = stage.StatusInternalError
|
||||||
|
@ -96,6 +105,57 @@ func (e *Local) generateResult(
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToRlimit(cmd stage.Cmd) ([]syscall.Rlimit, []int, error) {
|
||||||
|
var rlimits []syscall.Rlimit
|
||||||
|
var resources []int
|
||||||
|
if cmd.CPULimit > 0 {
|
||||||
|
var current syscall.Rlimit
|
||||||
|
if err := syscall.Getrlimit(syscall.RLIMIT_CPU, ¤t); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("getrlimit RLIMIT_CPU failed: %w", err)
|
||||||
|
}
|
||||||
|
userTimeLimit := (uint64(cmd.CPULimit) + 1e9 - 1) / 1e9 // ns to s
|
||||||
|
if userTimeLimit > current.Max {
|
||||||
|
userTimeLimit = current.Max
|
||||||
|
}
|
||||||
|
rlimits = append(rlimits, syscall.Rlimit{
|
||||||
|
Cur: userTimeLimit,
|
||||||
|
Max: current.Max,
|
||||||
|
})
|
||||||
|
resources = append(resources, syscall.RLIMIT_CPU)
|
||||||
|
}
|
||||||
|
if cmd.MemoryLimit > 0 {
|
||||||
|
var current syscall.Rlimit
|
||||||
|
if err := syscall.Getrlimit(syscall.RLIMIT_DATA, ¤t); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("getrlimit RLIMIT_DATA failed: %w", err)
|
||||||
|
}
|
||||||
|
userMemLimit := cmd.MemoryLimit
|
||||||
|
if userMemLimit > current.Max {
|
||||||
|
userMemLimit = current.Max
|
||||||
|
}
|
||||||
|
rlimits = append(rlimits, syscall.Rlimit{
|
||||||
|
Cur: userMemLimit,
|
||||||
|
Max: current.Max,
|
||||||
|
})
|
||||||
|
resources = append(resources, syscall.RLIMIT_DATA)
|
||||||
|
}
|
||||||
|
if cmd.StackLimit > 0 {
|
||||||
|
var current syscall.Rlimit
|
||||||
|
if err := syscall.Getrlimit(syscall.RLIMIT_STACK, ¤t); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("getrlimit RLIMIT_STACK failed: %w", err)
|
||||||
|
}
|
||||||
|
userStackLimit := cmd.StackLimit
|
||||||
|
if userStackLimit > current.Max {
|
||||||
|
userStackLimit = current.Max
|
||||||
|
}
|
||||||
|
rlimits = append(rlimits, syscall.Rlimit{
|
||||||
|
Cur: userStackLimit,
|
||||||
|
Max: current.Max,
|
||||||
|
})
|
||||||
|
resources = append(resources, syscall.RLIMIT_STACK)
|
||||||
|
}
|
||||||
|
return rlimits, resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
var results []stage.ExecutorResult
|
var results []stage.ExecutorResult
|
||||||
|
|
||||||
|
@ -111,6 +171,17 @@ func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
}
|
}
|
||||||
execCmd.Env = env
|
execCmd.Env = env
|
||||||
|
|
||||||
|
rlimits, resources, err := ToRlimit(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to convert rlimits: %v", err)
|
||||||
|
}
|
||||||
|
for i, resource := range resources {
|
||||||
|
limit := rlimits[i]
|
||||||
|
if err := syscall.Setrlimit(resource, &limit); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to set rlimit %d: %v", resource, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if cmd.Stdin != nil {
|
if cmd.Stdin != nil {
|
||||||
if cmd.Stdin.Content != nil {
|
if cmd.Stdin.Content != nil {
|
||||||
execCmd.Stdin = strings.NewReader(*cmd.Stdin.Content)
|
execCmd.Stdin = strings.NewReader(*cmd.Stdin.Content)
|
||||||
|
@ -128,7 +199,7 @@ func (e *Local) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
execCmd.Stderr = &stderrBuffer
|
execCmd.Stderr = &stderrBuffer
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
err := execCmd.Start()
|
err = execCmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to start command: %v", err)
|
return nil, fmt.Errorf("failed to start command: %v", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user