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  }