|  | // 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 | 
|  | } | 
|  | } |