package os
import (
"errors"
"internal/syscall/unix"
"sync"
"syscall"
"unsafe"
)
func ensurePidfd(sysAttr *syscall .SysProcAttr ) *syscall .SysProcAttr {
if !pidfdWorks () {
return sysAttr
}
var pidfd int
if sysAttr == nil {
return &syscall .SysProcAttr {
PidFD : &pidfd ,
}
}
if sysAttr .PidFD == nil {
newSys := *sysAttr
newSys .PidFD = &pidfd
return &newSys
}
return sysAttr
}
func getPidfd(sysAttr *syscall .SysProcAttr ) (uintptr , bool ) {
if !pidfdWorks () {
return 0 , false
}
return uintptr (*sysAttr .PidFD ), true
}
func pidfdFind(pid int ) (uintptr , error ) {
if !pidfdWorks () {
return 0 , syscall .ENOSYS
}
h , err := unix .PidFDOpen (pid , 0 )
if err != nil {
return 0 , convertESRCH (err )
}
return h , nil
}
const _P_PIDFD = 3
func (p *Process ) pidfdWait () (*ProcessState , error ) {
handle , status := p .handleTransientAcquire ()
switch status {
case statusDone :
return nil , NewSyscallError ("wait" , syscall .ECHILD )
case statusReleased :
return nil , syscall .EINVAL
}
defer p .handleTransientRelease ()
var (
info unix .SiginfoChild
rusage syscall .Rusage
e syscall .Errno
)
for {
_, _, e = syscall .Syscall6 (syscall .SYS_WAITID , _P_PIDFD , handle , uintptr (unsafe .Pointer (&info )), syscall .WEXITED , uintptr (unsafe .Pointer (&rusage )), 0 )
if e != syscall .EINTR {
break
}
}
if e != 0 {
return nil , NewSyscallError ("waitid" , e )
}
p .handlePersistentRelease (statusDone )
return &ProcessState {
pid : int (info .Pid ),
status : info .WaitStatus (),
rusage : &rusage ,
}, nil
}
func (p *Process ) pidfdSendSignal (s syscall .Signal ) error {
handle , status := p .handleTransientAcquire ()
switch status {
case statusDone :
return ErrProcessDone
case statusReleased :
return errors .New ("os: process already released" )
}
defer p .handleTransientRelease ()
return convertESRCH (unix .PidFDSendSignal (handle , s ))
}
func pidfdWorks() bool {
return checkPidfdOnce () == nil
}
var checkPidfdOnce = sync .OnceValue (checkPidfd )
func checkPidfd() error {
fd , err := unix .PidFDOpen (syscall .Getpid (), 0 )
if err != nil {
return NewSyscallError ("pidfd_open" , err )
}
defer syscall .Close (int (fd ))
for {
_, _, err = syscall .Syscall6 (syscall .SYS_WAITID , _P_PIDFD , fd , 0 , syscall .WEXITED , 0 , 0 )
if err != syscall .EINTR {
break
}
}
if err != syscall .ECHILD {
return NewSyscallError ("pidfd_wait" , err )
}
if err := unix .PidFDSendSignal (fd , 0 ); err != nil {
return NewSyscallError ("pidfd_send_signal" , err )
}
return nil
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .