Add generic system for shared resource locks to maker

This should fix concurrent access to go packages causing problems on
windows.

Change-Id: Ic43c4dcc301269abbcc2577d1e351bbf0d788250
diff --git a/make.go b/make.go
index 36c209c..5551337 100644
--- a/make.go
+++ b/make.go
@@ -186,5 +186,5 @@
 }
 
 func Codergen(name string, args ...string) {
-	Command(Tools.Codergen, args...).Creates(Virtual(name)).DependsOn("rpcapi", "apic")
+	Command(Tools.Codergen, args...).Creates(Virtual(name)).DependsOn("rpcapi", "apic").Access(GoPkgResources)
 }
diff --git a/maker/access.go b/maker/access.go
new file mode 100644
index 0000000..92d196a
--- /dev/null
+++ b/maker/access.go
@@ -0,0 +1,48 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package maker
+
+import (
+	"sort"
+	"sync"
+)
+
+type lock struct {
+	name string
+	mu   sync.Mutex
+}
+
+var locks = map[string]*lock{}
+
+func addLock(name string) {
+	_, ok := locks[name]
+	if !ok {
+		locks[name] = &lock{name: name}
+	}
+}
+
+func withLocks(accesses []string, do func()) {
+	// sort the names for consistent aquire order
+	sort.Strings(accesses)
+	// aquire all the mutexes in order
+	for _, name := range accesses {
+		locks[name].mu.Lock()
+	}
+	do()
+	// unlock order does not matter
+	for _, name := range accesses {
+		locks[name].mu.Unlock()
+	}
+}
diff --git a/maker/go.go b/maker/go.go
index c263655..54c8dbf 100644
--- a/maker/go.go
+++ b/maker/go.go
@@ -14,15 +14,11 @@
 
 package maker
 
-import "sync"
-
-var golock sync.Mutex
+const GoPkgResources = "go_packages"
 
 // GoCommand runs "go" with the specified arguments.
 func GoCommand(args ...string) *Step {
-	golock.Lock()
-	defer golock.Unlock()
-	return Command(goTool, args...)
+	return Command(goTool, args...).Access(GoPkgResources)
 }
 
 // GoInstall builds a new Step that runs "go install" on the supplied module.
diff --git a/maker/step.go b/maker/step.go
index 42e9516..00c2d42 100644
--- a/maker/step.go
+++ b/maker/step.go
@@ -30,13 +30,14 @@
 // and may depend on many entities.
 // It is an error to have a cycle in the build graph.
 type Step struct {
-	inputs  []Entity
-	outputs []Entity
-	always  bool
-	action  func(*Step) error
-	once    sync.Once
-	done    chan struct{}
-	err     error
+	inputs   []Entity
+	outputs  []Entity
+	always   bool
+	action   func(*Step) error
+	once     sync.Once
+	done     chan struct{}
+	err      error
+	accesses []string
 }
 
 var (
@@ -64,6 +65,9 @@
 		action: a,
 		done:   make(chan struct{}),
 	}
+	if Config.DisableParallel {
+		s.Access("single_thread")
+	}
 	for _, h := range stepHooks {
 		h(s)
 	}
@@ -101,6 +105,16 @@
 	return s
 }
 
+// Access adds the supplied shared resource names to the list of resources
+// accessed by this step.
+func (s *Step) Access(v ...string) *Step {
+	s.accesses = append(s.accesses, v...)
+	for _, name := range v {
+		addLock(name)
+	}
+	return s
+}
+
 // HasInput returns true if the step already has the supplied entity in it's inputs.
 func (s *Step) HasInput(e Entity) bool {
 	for _, in := range s.inputs {
@@ -181,11 +195,7 @@
 		dep := Creator(e)
 		if dep != nil {
 			deps = append(deps, dep)
-			if Config.DisableParallel {
-				dep.start()
-			} else {
-				go dep.start()
-			}
+			go dep.start()
 		}
 	}
 	// Wait for all inputs to be ready
@@ -236,7 +246,7 @@
 	s.once.Do(func() {
 		s.updateInputs()
 		if s.err == nil && s.shouldRun() {
-			s.run()
+			withLocks(s.accesses, s.run)
 		}
 		// Signal we are complete
 		close(s.done)