-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
os: on GNU/Linux use waitid to avoid wait/kill race
On systems that support the POSIX.1-2008 waitid function, we can use it to block until a wait will succeed. This avoids a possible race condition: if a program calls p.Kill/p.Signal and p.Wait from two different goroutines, then it is possible for the wait to complete just before the signal is sent. In that case, it is possible that the system will start a new process using the same PID between the wait and the signal, causing the signal to be sent to the wrong process. The Process.isdone field attempts to avoid that race, but there is a small gap of time between when wait returns and isdone is set when the race can occur. This CL avoids that race by using waitid to wait until the process has exited without actually collecting the PID. Then it sets isdone, then waits for any active signals to complete, and only then collects the PID. No test because any plausible test would require starting enough processes to recycle all the process IDs. Update #13987. Update #16028. Change-Id: Id2939431991d3b355dfb22f08793585fc0568ce8 Reviewed-on: https://go-review.googlesource.com/23967 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
- Loading branch information
1 parent
e980a3d
commit cea29c4
Showing
4 changed files
with
67 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2016 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package os | ||
|
||
import ( | ||
"runtime" | ||
"syscall" | ||
"unsafe" | ||
) | ||
|
||
const _P_PID = 1 | ||
|
||
// blockUntilWaitable attempts to block until a call to p.Wait will | ||
// succeed immediately, and returns whether it has done so. | ||
// It does not actually call p.Wait. | ||
func (p *Process) blockUntilWaitable() (bool, error) { | ||
// waitid expects a pointer to a siginfo_t, which is 128 bytes | ||
// on all systems. We don't care about the values it returns. | ||
var siginfo [128]byte | ||
psig := &siginfo[0] | ||
_, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0) | ||
runtime.KeepAlive(psig) | ||
if e != 0 { | ||
return false, NewSyscallError("waitid", e) | ||
} | ||
return true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2016 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// +build darwin dragonfly freebsd nacl netbsd openbsd solaris | ||
|
||
package os | ||
|
||
// blockUntilWaitable attempts to block until a call to p.Wait will | ||
// succeed immediately, and returns whether it has done so. | ||
// It does not actually call p.Wait. | ||
// This version is used on systems that do not implement waitid, | ||
// or where we have not implemented it yet. | ||
func (p *Process) blockUntilWaitable() (bool, error) { | ||
return false, nil | ||
} |