2008-09-22 17:26:57 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2009-03-06 04:36:50 -07:00
|
|
|
// This package provides a single function, Do, to run a function
|
|
|
|
// exactly once, usually used as part of initialization.
|
2008-09-22 17:26:57 -06:00
|
|
|
package once
|
|
|
|
|
2009-02-15 23:12:35 -07:00
|
|
|
import "sync"
|
2008-09-22 17:26:57 -06:00
|
|
|
|
2009-02-15 23:12:35 -07:00
|
|
|
type job struct {
|
2009-12-15 16:40:16 -07:00
|
|
|
done bool
|
|
|
|
sync.Mutex // should probably be sync.Notification or some such
|
2008-09-22 17:26:57 -06:00
|
|
|
}
|
|
|
|
|
2009-02-15 23:12:35 -07:00
|
|
|
var jobs = make(map[func()]*job)
|
2009-10-06 20:40:35 -06:00
|
|
|
var joblock sync.Mutex
|
2008-09-22 17:26:57 -06:00
|
|
|
|
2009-03-06 04:36:50 -07:00
|
|
|
// Do is the the only exported piece of the package.
|
|
|
|
// For one-time initialization that is not done during init,
|
|
|
|
// wrap the initialization in a niladic function f() and call
|
|
|
|
// Do(f)
|
|
|
|
// If multiple processes call Do(f) simultaneously
|
|
|
|
// with the same f argument, only one will call f, and the
|
|
|
|
// others will block until f finishes running.
|
2009-07-13 16:54:41 -06:00
|
|
|
//
|
|
|
|
// Since a func() expression typically evaluates to a differerent
|
|
|
|
// function value each time it is evaluated, it is incorrect to
|
|
|
|
// pass such values to Do. For example,
|
2009-10-06 20:40:35 -06:00
|
|
|
// func f(x int) {
|
2009-07-13 16:54:41 -06:00
|
|
|
// Do(func() { fmt.Println(x) })
|
|
|
|
// }
|
|
|
|
// behaves the same as
|
|
|
|
// func f(x int) {
|
|
|
|
// fmt.Println(x)
|
|
|
|
// }
|
|
|
|
// because the func() expression in the first creates a new
|
|
|
|
// func each time f runs, and each of those funcs is run once.
|
2009-01-30 15:39:31 -07:00
|
|
|
func Do(f func()) {
|
2009-12-15 16:40:16 -07:00
|
|
|
joblock.Lock()
|
2010-03-30 11:51:11 -06:00
|
|
|
j := jobs[f]
|
|
|
|
if j == nil {
|
2009-02-15 23:12:35 -07:00
|
|
|
// run it
|
2009-12-15 16:40:16 -07:00
|
|
|
j = new(job)
|
|
|
|
j.Lock()
|
|
|
|
jobs[f] = j
|
|
|
|
joblock.Unlock()
|
|
|
|
f()
|
|
|
|
j.done = true
|
|
|
|
j.Unlock()
|
2009-02-15 23:12:35 -07:00
|
|
|
} else {
|
|
|
|
// wait for it
|
2009-12-15 16:40:16 -07:00
|
|
|
joblock.Unlock()
|
2009-02-15 23:12:35 -07:00
|
|
|
if j.done != true {
|
2009-12-15 16:40:16 -07:00
|
|
|
j.Lock()
|
|
|
|
j.Unlock()
|
2009-02-15 23:12:35 -07:00
|
|
|
}
|
2008-09-22 17:26:57 -06:00
|
|
|
}
|
|
|
|
}
|