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 }