-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathopenChan.go
106 lines (95 loc) · 2.49 KB
/
openChan.go
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
// openChan.go
package openc
import (
"reflect"
"sync/atomic"
"unsafe"
)
type sudog struct {
// The following fields are protected by the hchan.lock of the
// channel this sudog is blocking on. shrinkstack depends on
// this.
g *unsafe.Pointer
selectdone *uint32 // CAS to 1 to win select race (may point to stack)
next *sudog
prev *sudog
elem unsafe.Pointer // data element (may point to stack)
// The following fields are never accessed concurrently.
// waitlink is only accessed by g.
releasetime int64
ticket uint32
waitlink *sudog // g.waiting list
c *hchan // channel
}
type waitq struct {
first *sudog
last *sudog
}
type mutex struct {
// Futex-based impl treats it as uint32 key,
// while sema-based impl as M* waitm.
// Used to be a union, but unions break precise GC.
key uintptr
}
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf uintptr // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *int // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
func Open(c interface{}) {
if c == nil {
return
}
if v := reflect.ValueOf(c); v.Kind() == reflect.Chan {
c := (*hchan)(unsafe.Pointer(v.Pointer()))
atomic.CompareAndSwapUint32(&c.closed, 1, 0)
}
}
func init() {
c := make(chan struct{})
p := (*unsafe.Pointer)(unsafe.Pointer(&c))
h := (*hchan)(*p)
if h.qcount != 0 ||
h.dataqsiz != 0 ||
h.elemsize != 0 ||
h.closed != 0 ||
*h.elemtype != 0 ||
h.sendx != 0 ||
h.recvx != 0 ||
h.recvq.first != nil ||
h.recvq.last != nil ||
h.sendq.first != nil ||
h.sendq.last != nil ||
h.lock.key != 0 {
panic("After checks found the Go kernel is changed, pleace check openc and update")
}
close(c)
if h.qcount != 0 ||
h.dataqsiz != 0 ||
h.elemsize != 0 ||
h.closed != 1 ||
*h.elemtype != 0 ||
h.sendx != 0 ||
h.recvx != 0 ||
h.recvq.first != nil ||
h.recvq.last != nil ||
h.sendq.first != nil ||
h.sendq.last != nil ||
h.lock.key != 0 {
panic("After checks found the Go kernel is changed, pleace check openc and update")
}
}