zhangmeng
2019-08-26 a0123f163eddcea3e6b9f9d36f1f3fb3aa2c835a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 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
}