v8.run/go/exp@v0.0.26-0.20230226010534-afcdbd3f782d/pool2/gopool2/gopool2.go (about) 1 package gopool2 2 3 import ( 4 "runtime" 5 "sync" 6 "sync/atomic" 7 ) 8 9 type goroutine struct { 10 job chan func() 11 ref int64 12 isClosed int32 13 } 14 15 func (g *goroutine) evict() { 16 if atomic.CompareAndSwapInt32(&g.isClosed, 0, 1) { 17 close(g.job) 18 } 19 } 20 21 func newGoroutine(p *GoPool2) *goroutine { 22 ch := make(chan func()) 23 g := &goroutine{ 24 job: ch, 25 } 26 go worker(p, g) 27 return g 28 } 29 30 type GoPool2 struct { 31 pool sync.Pool 32 } 33 34 type activeGoroutine struct { 35 g *goroutine 36 } 37 38 func (g *goroutine) activate() *activeGoroutine { 39 atomic.AddInt64(&g.ref, 1) 40 a := &activeGoroutine{g} 41 42 runtime.SetFinalizer(a, func(a *activeGoroutine) { 43 if atomic.AddInt64(&a.g.ref, -1) == 0 { 44 a.g.evict() 45 } 46 }) 47 48 return a 49 } 50 51 func worker(p *GoPool2, g *goroutine) { 52 for j := range g.job { 53 j() 54 p.pool.Put(g) 55 } 56 } 57 58 func New() *GoPool2 { 59 p := &GoPool2{} 60 p.pool.New = func() interface{} { 61 return newGoroutine(p) 62 } 63 return p 64 } 65 66 func (p *GoPool2) Do(f func()) { 67 retry: 68 g := p.pool.Get().(*goroutine) 69 ag := g.activate() 70 if atomic.LoadInt32(&ag.g.isClosed) == 0 { 71 ag.g.job <- f 72 } else { 73 goto retry 74 } 75 }