4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -14,8 +14,8 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# os: [macos-latest, ubuntu-latest]
|
os: [macos-latest, ubuntu-latest]
|
||||||
os: [macos-latest]
|
# os: [macos-latest]
|
||||||
llvm: [18]
|
llvm: [18]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
152
c/libuv/error.go
152
c/libuv/error.go
@@ -9,85 +9,85 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
E2BIG Errno = Errno(syscall.E2BIG)
|
E2BIG = Errno(syscall.E2BIG)
|
||||||
EACCES Errno = Errno(syscall.EACCES)
|
EACCES = Errno(syscall.EACCES)
|
||||||
EADDRINUSE Errno = Errno(syscall.EADDRINUSE)
|
EADDRINUSE = Errno(syscall.EADDRINUSE)
|
||||||
EADDRNOTAVAIL Errno = Errno(syscall.EADDRNOTAVAIL)
|
EADDRNOTAVAIL = Errno(syscall.EADDRNOTAVAIL)
|
||||||
EAFNOSUPPORT Errno = Errno(syscall.EAFNOSUPPORT)
|
EAFNOSUPPORT = Errno(syscall.EAFNOSUPPORT)
|
||||||
EAGAIN Errno = Errno(syscall.EAGAIN)
|
EAGAIN = Errno(syscall.EAGAIN)
|
||||||
EALREADY Errno = Errno(syscall.EALREADY)
|
EALREADY = Errno(syscall.EALREADY)
|
||||||
EBADF Errno = Errno(syscall.EBADF)
|
EBADF = Errno(syscall.EBADF)
|
||||||
EBUSY Errno = Errno(syscall.EBUSY)
|
EBUSY = Errno(syscall.EBUSY)
|
||||||
ECANCELED Errno = Errno(syscall.ECANCELED)
|
ECANCELED = Errno(syscall.ECANCELED)
|
||||||
ECONNABORTED Errno = Errno(syscall.ECONNABORTED)
|
ECONNABORTED = Errno(syscall.ECONNABORTED)
|
||||||
ECONNREFUSED Errno = Errno(syscall.ECONNREFUSED)
|
ECONNREFUSED = Errno(syscall.ECONNREFUSED)
|
||||||
ECONNRESET Errno = Errno(syscall.ECONNRESET)
|
ECONNRESET = Errno(syscall.ECONNRESET)
|
||||||
EDESTADDRREQ Errno = Errno(syscall.EDESTADDRREQ)
|
EDESTADDRREQ = Errno(syscall.EDESTADDRREQ)
|
||||||
EEXIST Errno = Errno(syscall.EEXIST)
|
EEXIST = Errno(syscall.EEXIST)
|
||||||
EFAULT Errno = Errno(syscall.EFAULT)
|
EFAULT = Errno(syscall.EFAULT)
|
||||||
EFBIG Errno = Errno(syscall.EFBIG)
|
EFBIG = Errno(syscall.EFBIG)
|
||||||
EHOSTUNREACH Errno = Errno(syscall.EHOSTUNREACH)
|
EHOSTUNREACH = Errno(syscall.EHOSTUNREACH)
|
||||||
EINTR Errno = Errno(syscall.EINTR)
|
EINTR = Errno(syscall.EINTR)
|
||||||
EINVAL Errno = Errno(syscall.EINVAL)
|
EINVAL = Errno(syscall.EINVAL)
|
||||||
EIO Errno = Errno(syscall.EIO)
|
EIO = Errno(syscall.EIO)
|
||||||
EISCONN Errno = Errno(syscall.EISCONN)
|
EISCONN = Errno(syscall.EISCONN)
|
||||||
EISDIR Errno = Errno(syscall.EISDIR)
|
EISDIR = Errno(syscall.EISDIR)
|
||||||
ELOOP Errno = Errno(syscall.ELOOP)
|
ELOOP = Errno(syscall.ELOOP)
|
||||||
EMFILE Errno = Errno(syscall.EMFILE)
|
EMFILE = Errno(syscall.EMFILE)
|
||||||
EMSGSIZE Errno = Errno(syscall.EMSGSIZE)
|
EMSGSIZE = Errno(syscall.EMSGSIZE)
|
||||||
ENAMETOOLONG Errno = Errno(syscall.ENAMETOOLONG)
|
ENAMETOOLONG = Errno(syscall.ENAMETOOLONG)
|
||||||
ENETDOWN Errno = Errno(syscall.ENETDOWN)
|
ENETDOWN = Errno(syscall.ENETDOWN)
|
||||||
ENETUNREACH Errno = Errno(syscall.ENETUNREACH)
|
ENETUNREACH = Errno(syscall.ENETUNREACH)
|
||||||
ENFILE Errno = Errno(syscall.ENFILE)
|
ENFILE = Errno(syscall.ENFILE)
|
||||||
ENOBUFS Errno = Errno(syscall.ENOBUFS)
|
ENOBUFS = Errno(syscall.ENOBUFS)
|
||||||
ENODEV Errno = Errno(syscall.ENODEV)
|
ENODEV = Errno(syscall.ENODEV)
|
||||||
ENOENT Errno = Errno(syscall.ENOENT)
|
ENOENT = Errno(syscall.ENOENT)
|
||||||
ENOMEM Errno = Errno(syscall.ENOMEM)
|
ENOMEM = Errno(syscall.ENOMEM)
|
||||||
ENOPROTOOPT Errno = Errno(syscall.ENOPROTOOPT)
|
ENOPROTOOPT = Errno(syscall.ENOPROTOOPT)
|
||||||
ENOSPC Errno = Errno(syscall.ENOSPC)
|
ENOSPC = Errno(syscall.ENOSPC)
|
||||||
ENOSYS Errno = Errno(syscall.ENOSYS)
|
ENOSYS = Errno(syscall.ENOSYS)
|
||||||
ENOTCONN Errno = Errno(syscall.ENOTCONN)
|
ENOTCONN = Errno(syscall.ENOTCONN)
|
||||||
ENOTDIR Errno = Errno(syscall.ENOTDIR)
|
ENOTDIR = Errno(syscall.ENOTDIR)
|
||||||
ENOTEMPTY Errno = Errno(syscall.ENOTEMPTY)
|
ENOTEMPTY = Errno(syscall.ENOTEMPTY)
|
||||||
ENOTSOCK Errno = Errno(syscall.ENOTSOCK)
|
ENOTSOCK = Errno(syscall.ENOTSOCK)
|
||||||
ENOTSUP Errno = Errno(syscall.ENOTSUP)
|
ENOTSUP = Errno(syscall.ENOTSUP)
|
||||||
EOVERFLOW Errno = Errno(syscall.EOVERFLOW)
|
EOVERFLOW = Errno(syscall.EOVERFLOW)
|
||||||
EPERM Errno = Errno(syscall.EPERM)
|
EPERM = Errno(syscall.EPERM)
|
||||||
EPIPE Errno = Errno(syscall.EPIPE)
|
EPIPE = Errno(syscall.EPIPE)
|
||||||
EPROTO Errno = Errno(syscall.EPROTO)
|
EPROTO = Errno(syscall.EPROTO)
|
||||||
EPROTONOSUPPORT Errno = Errno(syscall.EPROTONOSUPPORT)
|
EPROTONOSUPPORT = Errno(syscall.EPROTONOSUPPORT)
|
||||||
EPROTOTYPE Errno = Errno(syscall.EPROTOTYPE)
|
EPROTOTYPE = Errno(syscall.EPROTOTYPE)
|
||||||
ERANGE Errno = Errno(syscall.ERANGE)
|
ERANGE = Errno(syscall.ERANGE)
|
||||||
EROFS Errno = Errno(syscall.EROFS)
|
EROFS = Errno(syscall.EROFS)
|
||||||
ESHUTDOWN Errno = Errno(syscall.ESHUTDOWN)
|
ESHUTDOWN = Errno(syscall.ESHUTDOWN)
|
||||||
ESPIPE Errno = Errno(syscall.ESPIPE)
|
ESPIPE = Errno(syscall.ESPIPE)
|
||||||
ESRCH Errno = Errno(syscall.ESRCH)
|
ESRCH = Errno(syscall.ESRCH)
|
||||||
ETIMEDOUT Errno = Errno(syscall.ETIMEDOUT)
|
ETIMEDOUT = Errno(syscall.ETIMEDOUT)
|
||||||
ETXTBSY Errno = Errno(syscall.ETXTBSY)
|
ETXTBSY = Errno(syscall.ETXTBSY)
|
||||||
EXDEV Errno = Errno(syscall.EXDEV)
|
EXDEV = Errno(syscall.EXDEV)
|
||||||
ENXIO Errno = Errno(syscall.ENXIO)
|
ENXIO = Errno(syscall.ENXIO)
|
||||||
EMLINK Errno = Errno(syscall.EMLINK)
|
EMLINK = Errno(syscall.EMLINK)
|
||||||
EHOSTDOWN Errno = Errno(syscall.EHOSTDOWN)
|
EHOSTDOWN = Errno(syscall.EHOSTDOWN)
|
||||||
ENOTTY Errno = Errno(syscall.ENOTTY)
|
ENOTTY = Errno(syscall.ENOTTY)
|
||||||
EFTYPE Errno = Errno(syscall.EFTYPE)
|
//EFTYPE = Errno(syscall.EFTYPE)
|
||||||
EILSEQ Errno = Errno(syscall.EILSEQ)
|
EILSEQ = Errno(syscall.EILSEQ)
|
||||||
ESOCKTNOSUPPORT Errno = Errno(syscall.ESOCKTNOSUPPORT)
|
ESOCKTNOSUPPORT = Errno(syscall.ESOCKTNOSUPPORT)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EAI_ADDRFAMILY Errno = Errno(net.EAI_ADDRFAMILY)
|
EAI_ADDRFAMILY = Errno(net.EAI_ADDRFAMILY)
|
||||||
EAI_AGAIN Errno = Errno(net.EAI_AGAIN)
|
EAI_AGAIN = Errno(net.EAI_AGAIN)
|
||||||
EAI_BADFLAGS Errno = Errno(net.EAI_BADFLAGS)
|
EAI_BADFLAGS = Errno(net.EAI_BADFLAGS)
|
||||||
EAI_BADHINTS Errno = Errno(net.EAI_BADHINTS)
|
EAI_BADHINTS = Errno(net.EAI_BADHINTS)
|
||||||
EAI_FAIL Errno = Errno(net.EAI_FAIL)
|
EAI_FAIL = Errno(net.EAI_FAIL)
|
||||||
EAI_FAMILY Errno = Errno(net.EAI_FAMILY)
|
EAI_FAMILY = Errno(net.EAI_FAMILY)
|
||||||
EAI_MEMORY Errno = Errno(net.EAI_MEMORY)
|
EAI_MEMORY = Errno(net.EAI_MEMORY)
|
||||||
EAI_NODATA Errno = Errno(net.EAI_NODATA)
|
EAI_NODATA = Errno(net.EAI_NODATA)
|
||||||
EAI_NONAME Errno = Errno(net.EAI_NONAME)
|
EAI_NONAME = Errno(net.EAI_NONAME)
|
||||||
EAI_OVERFLOW Errno = Errno(net.EAI_OVERFLOW)
|
EAI_OVERFLOW = Errno(net.EAI_OVERFLOW)
|
||||||
EAI_PROTOCOL Errno = Errno(net.EAI_PROTOCOL)
|
EAI_PROTOCOL = Errno(net.EAI_PROTOCOL)
|
||||||
EAI_SERVICE Errno = Errno(net.EAI_SERVICE)
|
EAI_SERVICE = Errno(net.EAI_SERVICE)
|
||||||
EAI_SOCKTYPE Errno = Errno(net.EAI_SOCKTYPE)
|
EAI_SOCKTYPE = Errno(net.EAI_SOCKTYPE)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
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 (
|
||||||
|
"syscall"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 *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))
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ package syscall
|
|||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SysProcAttr struct {
|
type SysProcAttr struct {
|
||||||
@@ -77,8 +79,8 @@ func init() {
|
|||||||
// split the stack, or acquire mutexes). We can't call RawSyscall
|
// split the stack, or acquire mutexes). We can't call RawSyscall
|
||||||
// because it's not safe even for BSD-subsystem calls.
|
// because it's not safe even for BSD-subsystem calls.
|
||||||
//
|
//
|
||||||
//go:norace
|
// func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||||
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
func forkAndExecInChild(argv0 *c.Char, argv, envv **c.Char, chroot, dir *c.Char, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||||
// Declare all variables at top in case any
|
// Declare all variables at top in case any
|
||||||
// declarations require heap allocation (e.g., err1).
|
// declarations require heap allocation (e.g., err1).
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ func runtime_AfterForkInChild()
|
|||||||
// For the same reason compiler does not race instrument it.
|
// For the same reason compiler does not race instrument it.
|
||||||
// The calls to rawSyscall are okay because they are assembly
|
// The calls to rawSyscall are okay because they are assembly
|
||||||
// functions that do not grow the stack.
|
// functions that do not grow the stack.
|
||||||
//
|
|
||||||
//go:norace
|
|
||||||
func forkAndExecInChild(argv0 *c.Char, argv, envv **c.Char, chroot, dir *c.Char, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err1 Errno) {
|
func forkAndExecInChild(argv0 *c.Char, argv, envv **c.Char, chroot, dir *c.Char, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err1 Errno) {
|
||||||
// Declare all variables at top in case any
|
// Declare all variables at top in case any
|
||||||
// declarations require heap allocation (e.g., err1).
|
// declarations require heap allocation (e.g., err1).
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
package syscall
|
package syscall
|
||||||
|
|
||||||
|
import "github.com/goplus/llgo/c"
|
||||||
|
|
||||||
// Linux unshare/clone/clone2/clone3 flags, architecture-independent,
|
// Linux unshare/clone/clone2/clone3 flags, architecture-independent,
|
||||||
// copied from linux/sched.h.
|
// copied from linux/sched.h.
|
||||||
const (
|
const (
|
||||||
@@ -119,8 +121,8 @@ func runtime_AfterForkInChild()
|
|||||||
// The calls to RawSyscall are okay because they are assembly
|
// The calls to RawSyscall are okay because they are assembly
|
||||||
// functions that do not grow the stack.
|
// functions that do not grow the stack.
|
||||||
//
|
//
|
||||||
//go:norace
|
// func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||||
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
func forkAndExecInChild(argv0 *c.Char, argv, envv **c.Char, chroot, dir *c.Char, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
|
||||||
/* TODO(xsw):
|
/* TODO(xsw):
|
||||||
// Set up and fork. This returns immediately in the parent or
|
// Set up and fork. This returns immediately in the parent or
|
||||||
// if there's an error.
|
// if there's an error.
|
||||||
|
|||||||
105
internal/lib/syscall/forkpipe2.go
Normal file
105
internal/lib/syscall/forkpipe2.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c/syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// forkExecPipe atomically opens a pipe with O_CLOEXEC set on both file
|
||||||
|
// descriptors.
|
||||||
|
func forkExecPipe(p []int) error {
|
||||||
|
return Pipe2(p, syscall.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,108 @@
|
|||||||
|
|
||||||
package syscall
|
package syscall
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/c/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 Wait4(pid int, wstatus *WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error) {
|
||||||
|
var status c.Int
|
||||||
|
wpid, err = wait4(pid, &status, options, rusage)
|
||||||
|
if wstatus != nil {
|
||||||
|
*wstatus = WaitStatus(status)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// int pipe2(int pipefd[2], int flags);
|
||||||
|
//
|
||||||
|
//go:linkname pipe2 C.pipe2
|
||||||
|
func pipe2(pipefd *[2]c.Int, flags c.Int) c.Int
|
||||||
|
|
||||||
|
func Pipe2(p []int, flags int) error {
|
||||||
|
if len(p) != 2 {
|
||||||
|
return Errno(syscall.EINVAL)
|
||||||
|
}
|
||||||
|
var pp [2]c.Int
|
||||||
|
ret := pipe2(&pp, c.Int(flags))
|
||||||
|
if ret == 0 {
|
||||||
|
p[0] = int(pp[0])
|
||||||
|
p[1] = int(pp[1])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Errno(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
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