| // run |
| |
| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "fmt" |
| "runtime" |
| ) |
| |
| const N = 100000 |
| |
| func main() { |
| // Allocate more Ps than processors. This raises |
| // the chance that we get interrupted by the OS |
| // in exactly the right (wrong!) place. |
| p := runtime.NumCPU() |
| runtime.GOMAXPROCS(2 * p) |
| |
| // Allocate some pointers. |
| ptrs := make([]*int, p) |
| for i := 0; i < p; i++ { |
| ptrs[i] = new(int) |
| } |
| |
| // Arena where we read and write pointers like crazy. |
| collider := make([]*int, p) |
| |
| done := make(chan struct{}, 2*p) |
| |
| // Start writers. They alternately write a pointer |
| // and nil to a slot in the collider. |
| for i := 0; i < p; i++ { |
| i := i |
| go func() { |
| for j := 0; j < N; j++ { |
| // Write a pointer using memmove. |
| copy(collider[i:i+1], ptrs[i:i+1]) |
| // Write nil using memclr. |
| // (This is a magic loop that gets lowered to memclr.) |
| r := collider[i : i+1] |
| for k := range r { |
| r[k] = nil |
| } |
| } |
| done <- struct{}{} |
| }() |
| } |
| // Start readers. They read pointers from slots |
| // and make sure they are valid. |
| for i := 0; i < p; i++ { |
| i := i |
| go func() { |
| for j := 0; j < N; j++ { |
| var ptr [1]*int |
| copy(ptr[:], collider[i:i+1]) |
| if ptr[0] != nil && ptr[0] != ptrs[i] { |
| panic(fmt.Sprintf("bad pointer read %p!", ptr[0])) |
| } |
| } |
| done <- struct{}{} |
| }() |
| } |
| for i := 0; i < 2*p; i++ { |
| <-done |
| } |
| } |