github.com/grailbio/base@v0.0.11/errors/once.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package errors
     6  
     7  import (
     8  	"sync"
     9  	"sync/atomic"
    10  	"unsafe"
    11  )
    12  
    13  // Once captures at most one error. Errors are safely set across
    14  // multiple goroutines.
    15  //
    16  // A zero Once is ready to use.
    17  //
    18  // Example:
    19  // 	var e errors.Once
    20  // 	e.Set(errors.New("test error 0"))
    21  type Once struct {
    22  	// Ignored is a list of errors that will be dropped in Set(). Ignored
    23  	// typically includes io.EOF.
    24  	Ignored []error
    25  	mu      sync.Mutex
    26  	err     unsafe.Pointer // stores *error
    27  }
    28  
    29  // Err returns the first non-nil error passed to Set.  Calling Err is
    30  // cheap (~1ns).
    31  func (e *Once) Err() error {
    32  	p := atomic.LoadPointer(&e.err) // Acquire load
    33  	if p == nil {
    34  		return nil
    35  	}
    36  	return *(*error)(p)
    37  }
    38  
    39  // Set sets this instance's error to err. Only the first error
    40  // is set; subsequent calls are ignored.
    41  func (e *Once) Set(err error) {
    42  	if err != nil {
    43  		for _, ignored := range e.Ignored {
    44  			if err == ignored {
    45  				return
    46  			}
    47  		}
    48  		e.mu.Lock()
    49  		if e.err == nil && err != nil {
    50  			atomic.StorePointer(&e.err, unsafe.Pointer(&err)) // Release store
    51  		}
    52  		e.mu.Unlock()
    53  	}
    54  }