library: os, syscall
This commit is contained in:
32
internal/lib/os/wait_wait6.go
Normal file
32
internal/lib/os/wait_wait6.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build dragonfly || freebsd || netbsd
|
||||||
|
|
||||||
|
package os
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// blockUntilWaitable attempts to block until a call to p.Wait will
|
||||||
|
// succeed immediately, and reports whether it has done so.
|
||||||
|
// It does not actually call p.Wait.
|
||||||
|
func (p *Process) blockUntilWaitable() (bool, error) {
|
||||||
|
var errno syscall.Errno
|
||||||
|
for {
|
||||||
|
_, errno = wait6(_P_PID, p.Pid, syscall.WEXITED|syscall.WNOWAIT)
|
||||||
|
if errno != syscall.EINTR {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(xsw):
|
||||||
|
// runtime.KeepAlive(p)
|
||||||
|
if errno == syscall.ENOSYS {
|
||||||
|
return false, nil
|
||||||
|
} else if errno != 0 {
|
||||||
|
return false, NewSyscallError("wait6", errno)
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
55
internal/lib/os/wait_waitid.go
Normal file
55
internal/lib/os/wait_waitid.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// We used to used this code for Darwin, but according to issue #19314
|
||||||
|
// waitid returns if the process is stopped, even when using WEXITED.
|
||||||
|
|
||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package os
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/c/syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const _P_PID = 1
|
||||||
|
|
||||||
|
// int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
|
||||||
|
//
|
||||||
|
//go:linkname waitid C.waitid
|
||||||
|
func waitid(idtype, id uintptr, infop *[16]uint64, options c.Int) c.Int
|
||||||
|
|
||||||
|
// blockUntilWaitable attempts to block until a call to p.Wait will
|
||||||
|
// succeed immediately, and reports whether it has done so.
|
||||||
|
// It does not actually call p.Wait.
|
||||||
|
func (p *Process) blockUntilWaitable() (bool, error) {
|
||||||
|
// The waitid system call expects a pointer to a siginfo_t,
|
||||||
|
// which is 128 bytes on all Linux systems.
|
||||||
|
// On darwin/amd64, it requires 104 bytes.
|
||||||
|
// We don't care about the values it returns.
|
||||||
|
var siginfo [16]uint64
|
||||||
|
psig := &siginfo[0]
|
||||||
|
var e syscall.Errno
|
||||||
|
for {
|
||||||
|
e = syscall.Errno(waitid(_P_PID, uintptr(p.Pid), psig, syscall.WEXITED|syscall.WNOWAIT, 0, 0))
|
||||||
|
if e != syscall.EINTR {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(xsw):
|
||||||
|
// runtime.KeepAlive(p)
|
||||||
|
if e != 0 {
|
||||||
|
// waitid has been available since Linux 2.6.9, but
|
||||||
|
// reportedly is not available in Ubuntu on Windows.
|
||||||
|
// See issue 16610.
|
||||||
|
if e == syscall.ENOSYS {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, NewSyscallError("waitid", e)
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
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
|
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) {
|
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
||||||
panic("todo: syscall.Faccessat")
|
panic("todo: syscall.Faccessat")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user