zhangmeng
2019-08-26 a0123f163eddcea3e6b9f9d36f1f3fb3aa2c835a
提交 | 用户 | age
a0123f 1 // Created by cgo -godefs - DO NOT EDIT
Z 2 // cgo -godefs sem_linux.go
3
4 package shm
5
6 import (
7     "sync/atomic"
8     "syscall"
9     "unsafe"
10
11     "golang.org/x/sys/unix"
12 )
13
14 type Semaphore [32]byte
15
16 type newSem struct {
17     Value    uint32
18     Private  int32
19     NWaiters uint64
20 }
21
22 func New(value uint) (*Semaphore, error) {
23     sem := new(Semaphore)
24
25     if err := sem.Init(value); err != nil {
26         return nil, err
27     }
28
29     return sem, nil
30 }
31
32 func atomicDecrementIfPositive(mem *uint32) uint32 {
33     for {
34         if old := atomic.LoadUint32(mem); old == 0 || atomic.CompareAndSwapUint32(mem, old, old-1) {
35             return old
36         }
37     }
38 }
39
40 func (sem *Semaphore) Wait() error {
41     isem := (*newSem)(unsafe.Pointer(sem))
42
43     if atomicDecrementIfPositive(&isem.Value) > 0 {
44         return nil
45     }
46
47     atomic.AddUint64(&isem.NWaiters, 1)
48
49     for {
50         t := syscall.Timeval{3 /*sec*/, 0 /*usec*/}
51         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 {
52             atomic.AddUint64(&isem.NWaiters, ^uint64(0))
53             return err
54         }
55
56         if atomicDecrementIfPositive(&isem.Value) > 0 {
57             atomic.AddUint64(&isem.NWaiters, ^uint64(0))
58             return nil
59         }
60     }
61 }
62
63 func (sem *Semaphore) TryWait() error {
64     isem := (*newSem)(unsafe.Pointer(sem))
65
66     if atomicDecrementIfPositive(&isem.Value) > 0 {
67         return nil
68     }
69
70     return unix.EAGAIN
71 }
72
73 func (sem *Semaphore) Post() error {
74     isem := (*newSem)(unsafe.Pointer(sem))
75
76     for {
77         cur := atomic.LoadUint32(&isem.Value)
78
79         if cur == 0x7fffffff {
80             return unix.EOVERFLOW
81         }
82
83         if atomic.CompareAndSwapUint32(&isem.Value, cur, cur+1) {
84             break
85         }
86     }
87
88     if atomic.LoadUint64(&isem.NWaiters) <= 0 {
89         return nil
90     }
91
92     if _, _, err := unix.Syscall6(unix.SYS_FUTEX, uintptr(unsafe.Pointer(&isem.Value)), uintptr(0x1), 1, 0, 0, 0); err != 0 {
93         return err
94     }
95
96     return nil
97 }
98
99 func (sem *Semaphore) Init(value uint) error {
100     if value > 0x7fffffff {
101         return unix.EINVAL
102     }
103
104     isem := (*newSem)(unsafe.Pointer(sem))
105     isem.Value = uint32(value)
106     isem.Private = 0
107     isem.NWaiters = 0
108
109     return nil
110 }
111
112 func (sem *Semaphore) Destroy() error {
113     return nil
114 }