thunderboltsid

golang_sync_Once_TryDo

Jan 22nd, 2021 (edited)
938
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package internal
  2.  
  3. import (
  4.     "sync"
  5.     "sync/atomic"
  6. )
  7.  
  8. // Once is an object that will perform exactly one action unless the action fails.
  9. type Once struct {
  10.     // done indicates whether the action has been performed.
  11.     // It is first in the struct because it is used in the hot path.
  12.     // The hot path is inlined at every call site.
  13.     // Placing done first allows more compact instructions on some architectures (amd64/x86),
  14.     // and fewer instructions (to calculate offset) on other architectures.
  15.     done uint32
  16.     m    sync.Mutex
  17. }
  18.  
  19. // TryDo calls the function f if and only if TryDo is being called for the
  20. // first time for this instance of Once. In other words, given
  21. //  var once Once
  22. // if once.TryDo(f) is called multiple times, only the first call will invoke f,
  23. // unless the invocation results in an error A new instance of
  24. // Once is required for each function to execute.
  25. //
  26. // TryDo is intended for initialization that must be run exactly once. Since f
  27. // is niladic, it may be necessary to use a function literal to capture the
  28. // arguments to a function to be invoked by Do:
  29. //  config.once.TryDo(func() error { return config.init(filename) })
  30. //
  31. // Because no call to TryDo returns until the one call to f returns, if f causes
  32. // TryDo to be called, it will deadlock.
  33. //
  34. // If f panics, TryDo considers it to have failed.
  35. //
  36. func (o *Once) TryDo(f func() error) error {
  37.     // Note: Here is an incorrect implementation of Do:
  38.     //
  39.     //  if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
  40.     //      f()
  41.     //  }
  42.     //
  43.     // TryDo guarantees that when it returns, f has finished.
  44.     // This implementation would not implement that guarantee:
  45.     // given two simultaneous calls, the winner of the cas would
  46.     // call f, and the second would return immediately, without
  47.     // waiting for the first's call to f to complete.
  48.     // This is why the slow path falls back to a mutex, and why
  49.     // the atomic.StoreUint32 must be delayed until after f returns.
  50.  
  51.     if atomic.LoadUint32(&o.done) == 0 {
  52.         // Outlined slow-path to allow inlining of the fast-path.
  53.         return o.doSlow(f)
  54.     }
  55.  
  56.     return nil
  57. }
  58.  
  59. func (o *Once) doSlow(f func() error) error {
  60.     o.m.Lock()
  61.     defer o.m.Unlock()
  62.     if o.done == 0 {
  63.         if err := f(); err != nil {
  64.             return err
  65.         }
  66.         defer atomic.StoreUint32(&o.done, 1)
  67.     }
  68.     return nil
  69. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×