1// Copyright (c) 2017 Couchbase, Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 4// except in compliance with the License. You may obtain a copy of the License at 5// http://www.apache.org/licenses/LICENSE-2.0 6// Unless required by applicable law or agreed to in writing, software distributed under the 7// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 8// either express or implied. See the License for the specific language governing permissions 9// and limitations under the License. 10 11package util 12 13// We implement here sync types that in sync don't do exactly what we want. 14// Our implementation tends to be leaner too. 15 16import ( 17 atomic "github.com/couchbase/go-couchbase/platform" 18) 19 20// Once is an object that will perform exactly one action. 21type Once struct { 22 done uint32 23} 24 25// Do calls the function f if and only if Do is being called for the 26// first time for this instance of Once. In other words, given 27// var once Once 28// if once.Do(f) is called multiple times, only the first call will invoke f, 29// even if f has a different value in each invocation. A new instance of 30// Once is required for each function to execute. 31// 32// Do is intended for initialization that must be run exactly once. Since f 33// is niladic, it may be necessary to use a function literal to capture the 34// arguments to a function to be invoked by Do: 35// config.once.Do(func() { config.init(filename) }) 36// 37// Because no call to Do returns until the one call to f returns, if f causes 38// Do to be called, it will deadlock. 39// 40// If f panics, Do considers it to have returned; future calls of Do return 41// without calling f. 42// 43// Our Once type can be reset 44func (o *Once) Do(f func()) { 45 if atomic.LoadUint32(&o.done) > 0 { 46 return 47 } 48 49 // Slow-path. 50 if atomic.AddUint32(&o.done, 1) == 1 { 51 f() 52 } 53} 54 55func (o *Once) Reset() { 56 atomic.StoreUint32(&o.done, 0) 57} 58