LEFT | RIGHT |
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package sync | 5 package sync |
6 | 6 |
7 import "unsafe" | 7 // A Pool is a set of temporary objects that may be individually saved |
| 8 // and retrieved. |
| 9 // |
| 10 // Any item stored in the Pool may be removed automatically by the |
| 11 // implementation at any time without notification. |
| 12 // If the Pool holds the only reference when this happens, the item |
| 13 // might be deallocated. |
| 14 // |
| 15 // A Pool is safe for use by multiple goroutines simultaneously. |
| 16 // |
| 17 // This is an experimental package and might not be released. |
| 18 type Pool struct { |
| 19 » next *Pool // for use by runtime. must be first. |
| 20 » list []interface{} // offset known to runtime |
| 21 » mu Mutex // guards list |
8 | 22 |
9 // A Pool is a set of allocated objects to be reused. | 23 » // New optionally specifies a function to generate |
10 // It may be used by multiple goroutines simultaneously. | 24 » // a value when Get would otherwise return nil. |
11 // The Pool is drained during garbage collection. | 25 » // It may not be changed concurrently with calls to Get. |
12 type Pool struct { | |
13 » // New optionally specifies a function to return a new value | |
14 » // when Get would otherwise return nil. | |
15 New func() interface{} | 26 New func() interface{} |
16 | |
17 mu Mutex // guards rest | |
18 cur uint32 | |
19 gen uint32 // free is only valid if numgc == gen | |
20 free []poolItem | |
21 } | 27 } |
22 | 28 |
23 // A poolItem contains the two words of an interface{} value, xored to | 29 func runtime_registerPool(*Pool) |
24 // hide it from the garbage collector. It is only xor'd back to an | |
25 // interface{} if the pool's generation (numgc) matches. | |
26 // | |
27 // TODO(bradfitz): This is a temporary hacky mechanism until dvyukov | |
28 // re-implements the Pool in an efficient way. | |
29 type poolItem struct { | |
30 » i1, i2 uintptr | |
31 } | |
32 | |
33 func newPoolItem(x interface{}) (pi poolItem) { | |
34 » pi = *((*poolItem)(unsafe.Pointer(&x))) | |
35 » pi.i1 = ^pi.i1 | |
36 » pi.i2 = ^pi.i2 | |
37 » return | |
38 } | |
39 | |
40 func (pi *poolItem) Interface() (x interface{}) { | |
41 » return *(*interface{})(unsafe.Pointer(&poolItem{^pi.i1, ^pi.i2})) | |
42 } | |
43 | |
44 func readNumGC(*uint32) // implemented in runtime/mgc0.c | |
45 | |
46 var alwaysFalse = false | |
47 var globalI interface{} | |
48 | 30 |
49 // Put adds x to the pool. | 31 // Put adds x to the pool. |
50 func (p *Pool) Put(x interface{}) { | 32 func (p *Pool) Put(x interface{}) { |
51 » pi := newPoolItem(x) | 33 » if x == nil { |
52 | 34 » » return |
| 35 » } |
53 p.mu.Lock() | 36 p.mu.Lock() |
54 » readNumGC(&p.cur) | 37 » if p.list == nil { |
55 » if p.cur != p.gen { | 38 » » runtime_registerPool(p) |
56 » » p.gen = p.cur | |
57 » » p.free = p.free[:0] | |
58 } | 39 } |
59 » p.free = append(p.free, pi) | 40 » p.list = append(p.list, x) |
60 p.mu.Unlock() | 41 p.mu.Unlock() |
61 | |
62 // Force x to stay live throughout, | |
63 // but don't actually race on globalI. | |
64 if alwaysFalse { | |
65 globalI = x | |
66 } | |
67 } | 42 } |
68 | 43 |
69 // Get removes and returns a value from the pool. | 44 // Get selects an arbitrary item from the Pool, removes it from the |
70 // If the pool is empty, Get returns nil, or the return | 45 // Pool, and returns it to the caller. |
71 // value of calling p.New. | 46 // Get may choose to ignore the pool and treat it as empty. |
| 47 // Callers should not assume any relation between values passed to Put and |
| 48 // the values returned by Get. |
| 49 // |
| 50 // If Get would otherwise return nil and p.New is non-nil, Get returns |
| 51 // the result of calling p.New. |
72 func (p *Pool) Get() interface{} { | 52 func (p *Pool) Get() interface{} { |
| 53 p.mu.Lock() |
73 var x interface{} | 54 var x interface{} |
74 | 55 » if n := len(p.list); n > 0 { |
75 » p.mu.Lock() | 56 » » x = p.list[n-1] |
76 | 57 » » p.list[n-1] = nil // Just to be safe |
77 » if len(p.free) > 0 { | 58 » » p.list = p.list[:n-1] |
78 » » last := p.free[len(p.free)-1] | |
79 » » p.free = p.free[:len(p.free)-1] | |
80 » » x = last.Interface() | |
81 | |
82 » » // Now that we have x, double-check that no GC has occured | |
83 » » // even in the past few lines. | |
84 » » readNumGC(&p.cur) | |
85 » » if p.gen != p.cur { | |
86 » » » x = nil | |
87 » » » p.gen = p.cur | |
88 » » » p.free = p.free[:0] | |
89 » » } | |
90 } | 59 } |
91 p.mu.Unlock() | 60 p.mu.Unlock() |
92 | |
93 if x == nil && p.New != nil { | 61 if x == nil && p.New != nil { |
94 x = p.New() | 62 x = p.New() |
95 } | 63 } |
96 return x | 64 return x |
97 } | 65 } |
LEFT | RIGHT |