1
0
mirror of https://github.com/golang/go synced 2024-10-05 00:21:21 -06:00
go/src/lib/once.go
Russ Cox 983f06bdb6 update code to follow new semicolon rules:
*  1. all statements and declarations are terminated by semicolons
 *  2. semicolons can be omitted at top level.
 *  3. semicolons can be omitted before and after the closing ) or }
 *	on a list of statements or declarations.

/home/rsc/bin/addsemi and then diff+tweak.

R=r,gri
OCL=16620
CL=16643
2008-10-07 12:31:31 -07:00

80 lines
1.7 KiB
Go

// 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()
}