library: os, syscall
This commit is contained in:
101
internal/lib/syscall/forkpipe2.go
Normal file
101
internal/lib/syscall/forkpipe2.go
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
|
||||
package syscall
|
||||
|
||||
import "sync"
|
||||
|
||||
// forkExecPipe atomically opens a pipe with O_CLOEXEC set on both file
|
||||
// descriptors.
|
||||
func forkExecPipe(p []int) error {
|
||||
return Pipe2(p, O_CLOEXEC)
|
||||
}
|
||||
|
||||
var (
|
||||
// Guard the forking variable.
|
||||
forkingLock sync.Mutex
|
||||
// Number of goroutines currently forking, and thus the
|
||||
// number of goroutines holding a conceptual write lock
|
||||
// on ForkLock.
|
||||
forking int
|
||||
)
|
||||
|
||||
// TODO(xsw):
|
||||
// hasWaitingReaders reports whether any goroutine is waiting
|
||||
// to acquire a read lock on rw. It is defined in the sync package.
|
||||
func hasWaitingReaders(rw *sync.RWMutex) bool {
|
||||
panic("todo: syscall.hasWaitingReaders in sync package")
|
||||
}
|
||||
|
||||
// acquireForkLock acquires a write lock on ForkLock.
|
||||
// ForkLock is exported and we've promised that during a fork
|
||||
// we will call ForkLock.Lock, so that no other threads create
|
||||
// new fds that are not yet close-on-exec before we fork.
|
||||
// But that forces all fork calls to be serialized, which is bad.
|
||||
// But we haven't promised that serialization, and it is essentially
|
||||
// undetectable by other users of ForkLock, which is good.
|
||||
// Avoid the serialization by ensuring that ForkLock is locked
|
||||
// at the first fork and unlocked when there are no more forks.
|
||||
func acquireForkLock() {
|
||||
forkingLock.Lock()
|
||||
defer forkingLock.Unlock()
|
||||
|
||||
if forking == 0 {
|
||||
// There is no current write lock on ForkLock.
|
||||
ForkLock.Lock()
|
||||
forking++
|
||||
return
|
||||
}
|
||||
|
||||
// ForkLock is currently locked for writing.
|
||||
|
||||
if hasWaitingReaders(&ForkLock) {
|
||||
// ForkLock is locked for writing, and at least one
|
||||
// goroutine is waiting to read from it.
|
||||
// To avoid lock starvation, allow readers to proceed.
|
||||
// The simple way to do this is for us to acquire a
|
||||
// read lock. That will block us until all current
|
||||
// conceptual write locks are released.
|
||||
//
|
||||
// Note that this case is unusual on modern systems
|
||||
// with O_CLOEXEC and SOCK_CLOEXEC. On those systems
|
||||
// the standard library should never take a read
|
||||
// lock on ForkLock.
|
||||
|
||||
forkingLock.Unlock()
|
||||
|
||||
ForkLock.RLock()
|
||||
ForkLock.RUnlock()
|
||||
|
||||
forkingLock.Lock()
|
||||
|
||||
// Readers got a chance, so now take the write lock.
|
||||
|
||||
if forking == 0 {
|
||||
ForkLock.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
forking++
|
||||
}
|
||||
|
||||
// releaseForkLock releases the conceptual write lock on ForkLock
|
||||
// acquired by acquireForkLock.
|
||||
func releaseForkLock() {
|
||||
forkingLock.Lock()
|
||||
defer forkingLock.Unlock()
|
||||
|
||||
if forking <= 0 {
|
||||
panic("syscall.releaseForkLock: negative count")
|
||||
}
|
||||
|
||||
forking--
|
||||
|
||||
if forking == 0 {
|
||||
// No more conceptual write locks.
|
||||
ForkLock.Unlock()
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,65 @@
|
||||
|
||||
package syscall
|
||||
|
||||
type WaitStatus uint32
|
||||
|
||||
// Wait status is 7 bits at bottom, either 0 (exited),
|
||||
// 0x7F (stopped), or a signal number that caused an exit.
|
||||
// The 0x80 bit is whether there was a core dump.
|
||||
// An extra number (exit code, signal causing a stop)
|
||||
// is in the high bits. At least that's the idea.
|
||||
// There are various irregularities. For example, the
|
||||
// "continued" status is 0xFFFF, distinguishing itself
|
||||
// from stopped via the core dump bit.
|
||||
|
||||
const (
|
||||
mask = 0x7F
|
||||
core = 0x80
|
||||
exited = 0x00
|
||||
stopped = 0x7F
|
||||
shift = 8
|
||||
)
|
||||
|
||||
func (w WaitStatus) Exited() bool { return w&mask == exited }
|
||||
|
||||
func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != exited }
|
||||
|
||||
func (w WaitStatus) Stopped() bool { return w&0xFF == stopped }
|
||||
|
||||
func (w WaitStatus) Continued() bool { return w == 0xFFFF }
|
||||
|
||||
func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
|
||||
|
||||
func (w WaitStatus) ExitStatus() int {
|
||||
if !w.Exited() {
|
||||
return -1
|
||||
}
|
||||
return int(w>>shift) & 0xFF
|
||||
}
|
||||
|
||||
func (w WaitStatus) Signal() Signal {
|
||||
if !w.Signaled() {
|
||||
return -1
|
||||
}
|
||||
return Signal(w & mask)
|
||||
}
|
||||
|
||||
func (w WaitStatus) StopSignal() Signal {
|
||||
if !w.Stopped() {
|
||||
return -1
|
||||
}
|
||||
return Signal(w>>shift) & 0xFF
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
func (w WaitStatus) TrapCause() int {
|
||||
if w.StopSignal() != SIGTRAP {
|
||||
return -1
|
||||
}
|
||||
return int(w>>shift) >> 8
|
||||
}
|
||||
*/
|
||||
|
||||
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
||||
panic("todo: syscall.Faccessat")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user