mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
- Add new command executorserver as the draft executor server - Move shared pool logic into /pkg/pool
100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
package envexec
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
|
|
"github.com/criyle/go-sandbox/container"
|
|
"github.com/criyle/go-sandbox/runner"
|
|
)
|
|
|
|
// runSingle runs Cmd inside the given environment and cgroup
|
|
func runSingle(m container.Environment, cg Cgroup, c *Cmd, fds []*os.File, ptc []pipeCollector) (result Result, err error) {
|
|
fdToClose := fds
|
|
defer func() { closeFiles(fdToClose) }()
|
|
|
|
// setup cgroup limits
|
|
if err := cg.SetMemoryLimit(runner.Size(uint64(c.MemoryLimit) + memoryLimitExtra)); err != nil {
|
|
return result, err
|
|
}
|
|
if err := cg.SetProcLimit(c.ProcLimit); err != nil {
|
|
return result, err
|
|
}
|
|
|
|
// copyin
|
|
if len(c.CopyIn) > 0 {
|
|
if err := copyIn(m, c.CopyIn); err != nil {
|
|
return result, err
|
|
}
|
|
}
|
|
|
|
// set running parameters
|
|
execParam := container.ExecveParam{
|
|
Args: c.Args,
|
|
Env: c.Env,
|
|
Files: getFdArray(fds),
|
|
SyncFunc: cg.AddProc,
|
|
}
|
|
|
|
// start the cmd (they will be canceled in other goroutines)
|
|
ctx, cancel := context.WithCancel(context.TODO())
|
|
waiterCtx, waiterCancel := context.WithCancel(ctx)
|
|
|
|
rc := m.Execve(ctx, execParam)
|
|
|
|
// close files
|
|
closeFiles(fds)
|
|
fdToClose = nil
|
|
|
|
// starts waiter to periodically check cpu usage
|
|
go func() {
|
|
c.Waiter(waiterCtx, cg)
|
|
cancel()
|
|
}()
|
|
|
|
rt := <-rc
|
|
waiterCancel()
|
|
|
|
// collect result
|
|
files, err := copyOutAndCollect(m, c, ptc)
|
|
result = Result{
|
|
Status: convertStatus(rt.Status),
|
|
Error: rt.Error,
|
|
Time: rt.Time,
|
|
Memory: rt.Memory,
|
|
Files: files,
|
|
}
|
|
// collect error
|
|
if err != nil && result.Error == "" {
|
|
switch err := err.(type) {
|
|
case runner.Status:
|
|
result.Status = convertStatus(err)
|
|
default:
|
|
result.Status = StatusFileError
|
|
}
|
|
result.Error = err.Error()
|
|
}
|
|
// time
|
|
cpuUsage, err := cg.CPUUsage()
|
|
if err != nil {
|
|
result.Status = StatusInternalError
|
|
result.Error = err.Error()
|
|
} else {
|
|
result.Time = cpuUsage
|
|
}
|
|
// memory
|
|
memoryUsage, err := cg.MemoryUsage()
|
|
if err != nil {
|
|
result.Status = StatusInternalError
|
|
result.Error = err.Error()
|
|
} else {
|
|
result.Memory = memoryUsage
|
|
}
|
|
if result.Memory > c.MemoryLimit {
|
|
result.Status = StatusMemoryLimitExceeded
|
|
}
|
|
// make sure waiter exit
|
|
<-ctx.Done()
|
|
return result, nil
|
|
}
|