| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | // run | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Copyright 2014 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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Test finalizers work for tiny (combined) allocations. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"runtime" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func main() { | 
					
						
							| 
									
										
										
										
											2015-11-02 07:46:44 -08:00
										 |  |  | 	// Does not work on gccgo due to partially conservative GC. | 
					
						
							| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | 	// Try to enable when we have fully precise GC. | 
					
						
							|  |  |  | 	if runtime.Compiler == "gccgo" { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-03 12:19:15 +01:00
										 |  |  | 	const N = 100 | 
					
						
							|  |  |  | 	finalized := make(chan int32, N) | 
					
						
							|  |  |  | 	for i := 0; i < N; i++ { | 
					
						
							| 
									
										
										
										
											2015-11-02 07:46:44 -08:00
										 |  |  | 		x := new(int32) // subject to tiny alloc | 
					
						
							| 
									
										
										
										
											2015-11-03 12:19:15 +01:00
										 |  |  | 		*x = int32(i) | 
					
						
							| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | 		// the closure must be big enough to be combined | 
					
						
							| 
									
										
										
										
											2015-11-02 07:46:44 -08:00
										 |  |  | 		runtime.SetFinalizer(x, func(p *int32) { | 
					
						
							| 
									
										
										
										
											2015-11-03 12:19:15 +01:00
										 |  |  | 			finalized <- *p | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	runtime.GC() | 
					
						
							|  |  |  | 	count := 0 | 
					
						
							|  |  |  | 	done := make([]bool, N) | 
					
						
							|  |  |  | 	timeout := time.After(5*time.Second) | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-timeout: | 
					
						
							|  |  |  | 			println("timeout,", count, "finalized so far") | 
					
						
							|  |  |  | 			panic("not all finalizers are called") | 
					
						
							|  |  |  | 		case x := <-finalized: | 
					
						
							| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | 			// Check that p points to the correct subobject of the tiny allocation. | 
					
						
							|  |  |  | 			// It's a bit tricky, because we can't capture another variable | 
					
						
							|  |  |  | 			// with the expected value (it would be combined as well). | 
					
						
							| 
									
										
										
										
											2015-11-03 12:19:15 +01:00
										 |  |  | 			if x < 0 || x >= N { | 
					
						
							|  |  |  | 				println("got", x) | 
					
						
							| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | 				panic("corrupted") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-11-03 12:19:15 +01:00
										 |  |  | 			if done[x] { | 
					
						
							|  |  |  | 				println("got", x) | 
					
						
							| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | 				panic("already finalized") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-11-03 12:19:15 +01:00
										 |  |  | 			done[x] = true | 
					
						
							|  |  |  | 			count++ | 
					
						
							|  |  |  | 			if count > N/10*9 { | 
					
						
							|  |  |  | 				// Some of the finalizers may not be executed, | 
					
						
							|  |  |  | 				// if the outermost allocations are combined with something persistent. | 
					
						
							|  |  |  | 				// Currently 4 int32's are combined into a 16-byte block, | 
					
						
							|  |  |  | 				// ensure that most of them are finalized. | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-01-24 22:35:11 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |