aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ipc/ipc.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-04-23 13:19:45 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-04-23 16:26:26 +0200
commitff12bea91c22bba93d3ffc3034d813d686bc7eeb (patch)
tree4683d8c6eb9d273becb576b39ce0789ab1f4824c /pkg/ipc/ipc.go
parentc7b0bb14c0629cd3d4a1c153efa0e0a3e55a6e66 (diff)
pkg/ipc: fix data race on config.Timeout
Diffstat (limited to 'pkg/ipc/ipc.go')
-rw-r--r--pkg/ipc/ipc.go54
1 files changed, 30 insertions, 24 deletions
diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go
index 320352a84..5128c61ef 100644
--- a/pkg/ipc/ipc.go
+++ b/pkg/ipc/ipc.go
@@ -189,26 +189,6 @@ const (
)
func MakeEnv(config *Config, pid int) (*Env, error) {
- const (
- executorTimeout = 5 * time.Second
- minTimeout = executorTimeout + 2*time.Second
- )
- if config.Timeout == 0 {
- // Executor protects against most hangs, so we use quite large timeout here.
- // Executor can be slow due to global locks in namespaces and other things,
- // so let's better wait than report false misleading crashes.
- config.Timeout = time.Minute
- if config.Flags&FlagUseForkServer == 0 {
- // If there is no fork server, executor does not have internal timeout.
- config.Timeout = executorTimeout
- }
- }
- // IPC timeout must be larger then executor timeout.
- // Otherwise IPC will kill parent executor but leave child executor alive.
- if config.Flags&FlagUseForkServer != 0 && config.Timeout < minTimeout {
- config.Timeout = minTimeout
- }
-
var inf, outf *os.File
var inmem, outmem []byte
if config.Flags&FlagUseShmem != 0 {
@@ -486,6 +466,7 @@ func (env *Env) readOutCoverage(p *prog.Prog) (info []CallInfo, err0 error) {
type command struct {
pid int
config *Config
+ timeout time.Duration
cmd *exec.Cmd
dir string
readDone chan []byte
@@ -550,9 +531,10 @@ func makeCommand(pid int, bin []string, config *Config, inFile *os.File, outFile
}
c := &command{
- pid: pid,
- config: config,
- dir: dir,
+ pid: pid,
+ config: config,
+ timeout: sanitizeTimeout(config),
+ dir: dir,
}
defer func() {
if c != nil {
@@ -775,7 +757,7 @@ func (c *command) exec(opts *ExecOpts, progData []byte) (output []byte, failed,
done := make(chan bool)
hang := make(chan bool)
go func() {
- t := time.NewTimer(c.config.Timeout)
+ t := time.NewTimer(c.timeout)
select {
case <-t.C:
c.abort()
@@ -852,3 +834,27 @@ func (c *command) exec(opts *ExecOpts, progData []byte) (output []byte, failed,
}
return
}
+
+func sanitizeTimeout(config *Config) time.Duration {
+ const (
+ executorTimeout = 5 * time.Second
+ minTimeout = executorTimeout + 2*time.Second
+ )
+ timeout := config.Timeout
+ if timeout == 0 {
+ // Executor protects against most hangs, so we use quite large timeout here.
+ // Executor can be slow due to global locks in namespaces and other things,
+ // so let's better wait than report false misleading crashes.
+ timeout = time.Minute
+ if config.Flags&FlagUseForkServer == 0 {
+ // If there is no fork server, executor does not have internal timeout.
+ timeout = executorTimeout
+ }
+ }
+ // IPC timeout must be larger then executor timeout.
+ // Otherwise IPC will kill parent executor but leave child executor alive.
+ if config.Flags&FlagUseForkServer != 0 && timeout < minTimeout {
+ timeout = minTimeout
+ }
+ return timeout
+}