Skip to content

Commit 37ea182

Browse files
Zachary Amsdenbradfitz
Zachary Amsden
authored andcommitted
runtime: catch concurrent stacks more often
If two goroutines are racing on a map, one of them will exit cleanly, clearing the hashWriting bit, and the other will likely notice and panic. If we use XOR instead of OR to set the bit in the first place, even numbers of racers will hopefully all see the bit cleared and panic simultaneously, giving the full set of available stacks. If a third racer sneaks in, we are no worse than the current code, and the generated code should be no more expensive. In practice, this catches most racing goroutines even in very tight races. See the demonstration program posted on #26703 for an example. Fixes #26703 Change-Id: Idad17841a3127c24bd0a659b754734f70e307434 Reviewed-on: https://go-review.googlesource.com/126936 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 773e894 commit 37ea182

File tree

4 files changed

+11
-11
lines changed

4 files changed

+11
-11
lines changed

src/runtime/map.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
567567

568568
// Set hashWriting after calling alg.hash, since alg.hash may panic,
569569
// in which case we have not actually done a write.
570-
h.flags |= hashWriting
570+
h.flags ^= hashWriting
571571

572572
if h.buckets == nil {
573573
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
@@ -679,7 +679,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
679679

680680
// Set hashWriting after calling alg.hash, since alg.hash may panic,
681681
// in which case we have not actually done a write (delete).
682-
h.flags |= hashWriting
682+
h.flags ^= hashWriting
683683

684684
bucket := hash & bucketMask(h.B)
685685
if h.growing() {
@@ -921,7 +921,7 @@ func mapclear(t *maptype, h *hmap) {
921921
throw("concurrent map writes")
922922
}
923923

924-
h.flags |= hashWriting
924+
h.flags ^= hashWriting
925925

926926
h.flags &^= sameSizeGrow
927927
h.oldbuckets = nil

src/runtime/map_fast32.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
103103
hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
104104

105105
// Set hashWriting after calling alg.hash for consistency with mapassign.
106-
h.flags |= hashWriting
106+
h.flags ^= hashWriting
107107

108108
if h.buckets == nil {
109109
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
@@ -189,7 +189,7 @@ func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
189189
hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
190190

191191
// Set hashWriting after calling alg.hash for consistency with mapassign.
192-
h.flags |= hashWriting
192+
h.flags ^= hashWriting
193193

194194
if h.buckets == nil {
195195
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
@@ -276,7 +276,7 @@ func mapdelete_fast32(t *maptype, h *hmap, key uint32) {
276276
hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
277277

278278
// Set hashWriting after calling alg.hash for consistency with mapdelete
279-
h.flags |= hashWriting
279+
h.flags ^= hashWriting
280280

281281
bucket := hash & bucketMask(h.B)
282282
if h.growing() {

src/runtime/map_fast64.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
103103
hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
104104

105105
// Set hashWriting after calling alg.hash for consistency with mapassign.
106-
h.flags |= hashWriting
106+
h.flags ^= hashWriting
107107

108108
if h.buckets == nil {
109109
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
@@ -189,7 +189,7 @@ func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
189189
hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
190190

191191
// Set hashWriting after calling alg.hash for consistency with mapassign.
192-
h.flags |= hashWriting
192+
h.flags ^= hashWriting
193193

194194
if h.buckets == nil {
195195
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
@@ -276,7 +276,7 @@ func mapdelete_fast64(t *maptype, h *hmap, key uint64) {
276276
hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
277277

278278
// Set hashWriting after calling alg.hash for consistency with mapdelete
279-
h.flags |= hashWriting
279+
h.flags ^= hashWriting
280280

281281
bucket := hash & bucketMask(h.B)
282282
if h.growing() {

src/runtime/map_faststr.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer {
202202
hash := t.key.alg.hash(noescape(unsafe.Pointer(&s)), uintptr(h.hash0))
203203

204204
// Set hashWriting after calling alg.hash for consistency with mapassign.
205-
h.flags |= hashWriting
205+
h.flags ^= hashWriting
206206

207207
if h.buckets == nil {
208208
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
@@ -294,7 +294,7 @@ func mapdelete_faststr(t *maptype, h *hmap, ky string) {
294294
hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
295295

296296
// Set hashWriting after calling alg.hash for consistency with mapdelete
297-
h.flags |= hashWriting
297+
h.flags ^= hashWriting
298298

299299
bucket := hash & bucketMask(h.B)
300300
if h.growing() {

0 commit comments

Comments
 (0)