// Created by cgo -godefs - DO NOT EDIT
|
// cgo -godefs sem_linux.go
|
|
package shm
|
|
import (
|
"sync/atomic"
|
"syscall"
|
"unsafe"
|
|
"golang.org/x/sys/unix"
|
)
|
|
type Semaphore [32]byte
|
|
type newSem struct {
|
Value uint32
|
Private int32
|
NWaiters uint64
|
}
|
|
func New(value uint) (*Semaphore, error) {
|
sem := new(Semaphore)
|
|
if err := sem.Init(value); err != nil {
|
return nil, err
|
}
|
|
return sem, nil
|
}
|
|
func atomicDecrementIfPositive(mem *uint32) uint32 {
|
for {
|
if old := atomic.LoadUint32(mem); old == 0 || atomic.CompareAndSwapUint32(mem, old, old-1) {
|
return old
|
}
|
}
|
}
|
|
func (sem *Semaphore) Wait() error {
|
isem := (*newSem)(unsafe.Pointer(sem))
|
|
if atomicDecrementIfPositive(&isem.Value) > 0 {
|
return nil
|
}
|
|
atomic.AddUint64(&isem.NWaiters, 1)
|
|
for {
|
t := syscall.Timeval{3 /*sec*/, 0 /*usec*/}
|
if _, _, err := unix.Syscall6(unix.SYS_FUTEX, uintptr(unsafe.Pointer(&isem.Value)), uintptr(0x0), 0, uintptr(unsafe.Pointer(&t)), 0, 0); err != 0 && err != unix.EWOULDBLOCK {
|
atomic.AddUint64(&isem.NWaiters, ^uint64(0))
|
return err
|
}
|
|
if atomicDecrementIfPositive(&isem.Value) > 0 {
|
atomic.AddUint64(&isem.NWaiters, ^uint64(0))
|
return nil
|
}
|
}
|
}
|
|
func (sem *Semaphore) TryWait() error {
|
isem := (*newSem)(unsafe.Pointer(sem))
|
|
if atomicDecrementIfPositive(&isem.Value) > 0 {
|
return nil
|
}
|
|
return unix.EAGAIN
|
}
|
|
func (sem *Semaphore) Post() error {
|
isem := (*newSem)(unsafe.Pointer(sem))
|
|
for {
|
cur := atomic.LoadUint32(&isem.Value)
|
|
if cur == 0x7fffffff {
|
return unix.EOVERFLOW
|
}
|
|
if atomic.CompareAndSwapUint32(&isem.Value, cur, cur+1) {
|
break
|
}
|
}
|
|
if atomic.LoadUint64(&isem.NWaiters) <= 0 {
|
return nil
|
}
|
|
if _, _, err := unix.Syscall6(unix.SYS_FUTEX, uintptr(unsafe.Pointer(&isem.Value)), uintptr(0x1), 1, 0, 0, 0); err != 0 {
|
return err
|
}
|
|
return nil
|
}
|
|
func (sem *Semaphore) Init(value uint) error {
|
if value > 0x7fffffff {
|
return unix.EINVAL
|
}
|
|
isem := (*newSem)(unsafe.Pointer(sem))
|
isem.Value = uint32(value)
|
isem.Private = 0
|
isem.NWaiters = 0
|
|
return nil
|
}
|
|
func (sem *Semaphore) Destroy() error {
|
return nil
|
}
|