build: separate compiler and libs
This commit is contained in:
105
compiler/internal/lib/syscall/forkpipe2.go
Normal file
105
compiler/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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user