github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/atomickit/once.go (about)

     1  /*
     2   * Copyright 2020 Insolar Network Ltd.
     3   * All rights reserved.
     4   * This material is licensed under the Insolar License version 1.0,
     5   * available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md.
     6   */
     7  
     8  package atomickit
     9  
    10  import (
    11  	"sync"
    12  	"sync/atomic"
    13  )
    14  
    15  type Once struct {
    16  	done uint32
    17  	m    sync.Mutex
    18  }
    19  
    20  func (p *Once) IsDone() bool {
    21  	return atomic.LoadUint32(&p.done) != 0
    22  }
    23  
    24  func (p *Once) GetDone() uint32 {
    25  	return atomic.LoadUint32(&p.done)
    26  }
    27  
    28  func (p *Once) Do(f func()) {
    29  	if atomic.LoadUint32(&p.done) == 0 {
    30  		p.doSlow(func() uint32 {
    31  			f()
    32  			return 1
    33  		})
    34  	}
    35  }
    36  
    37  func (p *Once) DoWithValue(f func() uint32) {
    38  	if atomic.LoadUint32(&p.done) == 0 {
    39  		p.doSlow(f)
    40  	}
    41  }
    42  
    43  func (p *Once) doSlow(f func() uint32) {
    44  	p.m.Lock()
    45  	defer p.m.Unlock()
    46  	if atomic.LoadUint32(&p.done) == 0 {
    47  		defer atomic.CompareAndSwapUint32(&p.done, 0, 1) // set 1 when f() has returned 0
    48  		atomic.StoreUint32(&p.done, f())
    49  	}
    50  }