Home | History | Annotate | Download | only in fixedbugs
      1 // run
      2 
      3 // Copyright 2014 The Go Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style
      5 // license that can be found in the LICENSE file.
      6 
      7 // Scenario that used to leak arbitrarily many SudoG structs.
      8 // See golang.org/issue/9110.
      9 
     10 package main
     11 
     12 import (
     13 	"runtime"
     14 	"runtime/debug"
     15 	"sync"
     16 	"time"
     17 )
     18 
     19 func main() {
     20 	runtime.GOMAXPROCS(1)
     21 	debug.SetGCPercent(1000000) // only GC when we ask for GC
     22 
     23 	var stats, stats1, stats2 runtime.MemStats
     24 
     25 	release := func() {}
     26 	for i := 0; i < 20; i++ {
     27 		if i == 10 {
     28 			// Should be warmed up by now.
     29 			runtime.ReadMemStats(&stats1)
     30 		}
     31 
     32 		c := make(chan int)
     33 		for i := 0; i < 10; i++ {
     34 			go func() {
     35 				select {
     36 				case <-c:
     37 				case <-c:
     38 				case <-c:
     39 				}
     40 			}()
     41 		}
     42 		time.Sleep(1 * time.Millisecond)
     43 		release()
     44 
     45 		close(c) // let select put its sudog's into the cache
     46 		time.Sleep(1 * time.Millisecond)
     47 
     48 		// pick up top sudog
     49 		var cond1 sync.Cond
     50 		var mu1 sync.Mutex
     51 		cond1.L = &mu1
     52 		go func() {
     53 			mu1.Lock()
     54 			cond1.Wait()
     55 			mu1.Unlock()
     56 		}()
     57 		time.Sleep(1 * time.Millisecond)
     58 
     59 		// pick up next sudog
     60 		var cond2 sync.Cond
     61 		var mu2 sync.Mutex
     62 		cond2.L = &mu2
     63 		go func() {
     64 			mu2.Lock()
     65 			cond2.Wait()
     66 			mu2.Unlock()
     67 		}()
     68 		time.Sleep(1 * time.Millisecond)
     69 
     70 		// put top sudog back
     71 		cond1.Broadcast()
     72 		time.Sleep(1 * time.Millisecond)
     73 
     74 		// drop cache on floor
     75 		runtime.GC()
     76 
     77 		// release cond2 after select has gotten to run
     78 		release = func() {
     79 			cond2.Broadcast()
     80 			time.Sleep(1 * time.Millisecond)
     81 		}
     82 	}
     83 
     84 	runtime.GC()
     85 
     86 	runtime.ReadMemStats(&stats2)
     87 
     88 	if int(stats2.HeapObjects)-int(stats1.HeapObjects) > 20 { // normally at most 1 or 2; was 300 with leak
     89 		print("BUG: object leak: ", stats.HeapObjects, " -> ", stats1.HeapObjects, " -> ", stats2.HeapObjects, "\n")
     90 	}
     91 }
     92