@@ -61,29 +61,49 @@ type poolLocal struct {
61
61
pad [128 ]byte // Prevents false sharing.
62
62
}
63
63
64
+ // from runtime
65
+ func fastrand () uint32
66
+
67
+ var poolRaceHash [128 ]uint64
68
+
69
+ // poolRaceAddr returns an address to use as the synchronization point
70
+ // for race detector logic. We don't use the actual pointer stored in x
71
+ // directly, for fear of conflicting with other synchronization on that address.
72
+ // Instead, we hash the pointer to get an index into poolRaceHash.
73
+ // See discussion on golang.org/cl/31589.
74
+ func poolRaceAddr (x interface {}) unsafe.Pointer {
75
+ ptr := uintptr ((* [2 ]unsafe.Pointer )(unsafe .Pointer (& x ))[1 ])
76
+ h := uint32 ((uint64 (uint32 (ptr )) * 0x85ebca6b ) >> 16 )
77
+ return unsafe .Pointer (& poolRaceHash [h % uint32 (len (poolRaceHash ))])
78
+ }
79
+
64
80
// Put adds x to the pool.
65
81
func (p * Pool ) Put (x interface {}) {
66
- if race .Enabled {
67
- // Under race detector the Pool degenerates into no-op.
68
- // It's conforming, simple and does not introduce excessive
69
- // happens-before edges between unrelated goroutines.
70
- return
71
- }
72
82
if x == nil {
73
83
return
74
84
}
85
+ if race .Enabled {
86
+ if fastrand ()% 4 == 0 {
87
+ // Randomly drop x on floor.
88
+ return
89
+ }
90
+ race .ReleaseMerge (poolRaceAddr (x ))
91
+ race .Disable ()
92
+ }
75
93
l := p .pin ()
76
94
if l .private == nil {
77
95
l .private = x
78
96
x = nil
79
97
}
80
98
runtime_procUnpin ()
81
- if x == nil {
82
- return
99
+ if x != nil {
100
+ l .Lock ()
101
+ l .shared = append (l .shared , x )
102
+ l .Unlock ()
103
+ }
104
+ if race .Enabled {
105
+ race .Enable ()
83
106
}
84
- l .Lock ()
85
- l .shared = append (l .shared , x )
86
- l .Unlock ()
87
107
}
88
108
89
109
// Get selects an arbitrary item from the Pool, removes it from the
@@ -96,29 +116,34 @@ func (p *Pool) Put(x interface{}) {
96
116
// the result of calling p.New.
97
117
func (p * Pool ) Get () interface {} {
98
118
if race .Enabled {
99
- if p .New != nil {
100
- return p .New ()
101
- }
102
- return nil
119
+ race .Disable ()
103
120
}
104
121
l := p .pin ()
105
122
x := l .private
106
123
l .private = nil
107
124
runtime_procUnpin ()
108
- if x != nil {
109
- return x
125
+ if x == nil {
126
+ l .Lock ()
127
+ last := len (l .shared ) - 1
128
+ if last >= 0 {
129
+ x = l .shared [last ]
130
+ l .shared = l .shared [:last ]
131
+ }
132
+ l .Unlock ()
133
+ if x == nil {
134
+ x = p .getSlow ()
135
+ }
110
136
}
111
- l . Lock ()
112
- last := len ( l . shared ) - 1
113
- if last >= 0 {
114
- x = l . shared [ last ]
115
- l . shared = l . shared [: last ]
137
+ if race . Enabled {
138
+ race . Enable ()
139
+ if x != nil {
140
+ race . Acquire ( poolRaceAddr ( x ))
141
+ }
116
142
}
117
- l .Unlock ()
118
- if x != nil {
119
- return x
143
+ if x == nil && p .New != nil {
144
+ x = p .New ()
120
145
}
121
- return p . getSlow ()
146
+ return x
122
147
}
123
148
124
149
func (p * Pool ) getSlow () (x interface {}) {
@@ -140,10 +165,6 @@ func (p *Pool) getSlow() (x interface{}) {
140
165
}
141
166
l .Unlock ()
142
167
}
143
-
144
- if x == nil && p .New != nil {
145
- x = p .New ()
146
- }
147
168
return x
148
169
}
149
170
0 commit comments