// 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. // For one-time initialization that is not done during init. // Wrap the initialization in a niladic function f() and call // once.Do(&f) // If multiple processes call once.Do(&f) simultaneously // with the same f argument, only one will call f, and the // others will block until f finishes running. package once type Job struct { done bool; doit *chan bool; // buffer of 1 } type Request struct { f *(); reply *chan *Job } // TODO: Would like to use chan Request but 6g rejects it. var service = new(chan *Request) var jobmap = new(map[*()]*Job) // Moderate access to the jobmap. // Even if accesses were thread-safe (they should be but are not) // something needs to serialize creation of new jobs. // That's what the Server does. func Server() { for { req := <-service; job, present := jobmap[req.f]; if !present { job = new(Job); job.doit = new(chan bool, 1); job.doit <- true; jobmap[req.f] = job } req.reply <- job } } export func Do(f *()) { // Look for job in map (avoids channel communication). // If not there, ask map server to make one. // TODO: Uncomment use of jobmap[f] once // maps are thread-safe. var job *Job; var present bool; // job, present = jobmap[f] if !present { c := new(chan *Job); req := Request{f, c}; service <- &req; job = <-c } // Optimization if job.done { return } // If we're the first one, job.doit has a true waiting. if <-job.doit { f(); job.done = true } // Leave a false waiting for the next guy. job.doit <- false } func init() { go Server() }