aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/sync
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-03-02 20:01:37 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-03-02 20:01:37 +0000
commit501699af1603287b1b47ac450fd6eeb826aa76b1 (patch)
tree3eeb8918d39d675108073c8b76d6dd10586a608c /libgo/go/sync
parent34c5f21a387dc461042bafc3052ce6e1af786a77 (diff)
downloadgcc-501699af1603287b1b47ac450fd6eeb826aa76b1.zip
gcc-501699af1603287b1b47ac450fd6eeb826aa76b1.tar.gz
gcc-501699af1603287b1b47ac450fd6eeb826aa76b1.tar.bz2
libgo: Update to weekly.2012-02-22 release.
From-SVN: r184819
Diffstat (limited to 'libgo/go/sync')
-rw-r--r--libgo/go/sync/cond.go15
-rw-r--r--libgo/go/sync/example_test.go34
-rw-r--r--libgo/go/sync/export_test.go9
-rw-r--r--libgo/go/sync/mutex.go9
-rw-r--r--libgo/go/sync/mutex_test.go4
-rw-r--r--libgo/go/sync/runtime.go18
-rw-r--r--libgo/go/sync/runtime_sema_test.go101
-rw-r--r--libgo/go/sync/rwmutex.go13
-rw-r--r--libgo/go/sync/waitgroup.go9
9 files changed, 182 insertions, 30 deletions
diff --git a/libgo/go/sync/cond.go b/libgo/go/sync/cond.go
index 75494b5..1fc3dea 100644
--- a/libgo/go/sync/cond.go
+++ b/libgo/go/sync/cond.go
@@ -4,8 +4,6 @@
package sync
-import "runtime"
-
// Cond implements a condition variable, a rendezvous point
// for goroutines waiting for or announcing the occurrence
// of an event.
@@ -43,9 +41,10 @@ func NewCond(l Locker) *Cond {
// Wait atomically unlocks c.L and suspends execution
// of the calling goroutine. After later resuming execution,
-// Wait locks c.L before returning.
+// Wait locks c.L before returning. Unlike in other systems,
+// Wait cannot return unless awoken by Broadcast or Signal.
//
-// Because L is not locked when Wait first resumes, the caller
+// Because c.L is not locked when Wait first resumes, the caller
// typically cannot assume that the condition is true when
// Wait returns. Instead, the caller should Wait in a loop:
//
@@ -65,7 +64,7 @@ func (c *Cond) Wait() {
c.newWaiters++
c.m.Unlock()
c.L.Unlock()
- runtime.Semacquire(s)
+ runtime_Semacquire(s)
c.L.Lock()
}
@@ -84,7 +83,7 @@ func (c *Cond) Signal() {
}
if c.oldWaiters > 0 {
c.oldWaiters--
- runtime.Semrelease(c.oldSema)
+ runtime_Semrelease(c.oldSema)
}
c.m.Unlock()
}
@@ -98,13 +97,13 @@ func (c *Cond) Broadcast() {
// Wake both generations.
if c.oldWaiters > 0 {
for i := 0; i < c.oldWaiters; i++ {
- runtime.Semrelease(c.oldSema)
+ runtime_Semrelease(c.oldSema)
}
c.oldWaiters = 0
}
if c.newWaiters > 0 {
for i := 0; i < c.newWaiters; i++ {
- runtime.Semrelease(c.newSema)
+ runtime_Semrelease(c.newSema)
}
c.newWaiters = 0
c.newSema = nil
diff --git a/libgo/go/sync/example_test.go b/libgo/go/sync/example_test.go
new file mode 100644
index 0000000..1424b1e
--- /dev/null
+++ b/libgo/go/sync/example_test.go
@@ -0,0 +1,34 @@
+// Copyright 2012 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.
+
+package sync_test
+
+import (
+ "net/http"
+ "sync"
+)
+
+// This example fetches several URLs concurrently,
+// using a WaitGroup to block until all the fetches are complete.
+func ExampleWaitGroup() {
+ var wg sync.WaitGroup
+ var urls = []string{
+ "http://www.golang.org/",
+ "http://www.google.com/",
+ "http://www.somestupidname.com/",
+ }
+ for _, url := range urls {
+ // Increment the WaitGroup counter.
+ wg.Add(1)
+ // Launch a goroutine to fetch the URL.
+ go func(url string) {
+ // Fetch the URL.
+ http.Get(url)
+ // Decrement the counter.
+ wg.Done()
+ }(url)
+ }
+ // Wait for all HTTP fetches to complete.
+ wg.Wait()
+}
diff --git a/libgo/go/sync/export_test.go b/libgo/go/sync/export_test.go
new file mode 100644
index 0000000..fa5983a
--- /dev/null
+++ b/libgo/go/sync/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2012 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.
+
+package sync
+
+// Export for testing.
+var Runtime_Semacquire = runtime_Semacquire
+var Runtime_Semrelease = runtime_Semrelease
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
index 4fc0274..9494cc3 100644
--- a/libgo/go/sync/mutex.go
+++ b/libgo/go/sync/mutex.go
@@ -10,10 +10,7 @@
// Values containing the types defined in this package should not be copied.
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// A Mutex is a mutual exclusion lock.
// Mutexes can be created as part of other structures;
@@ -60,7 +57,7 @@ func (m *Mutex) Lock() {
if old&mutexLocked == 0 {
break
}
- runtime.Semacquire(&m.sema)
+ runtime_Semacquire(&m.sema)
awoke = true
}
}
@@ -89,7 +86,7 @@ func (m *Mutex) Unlock() {
// Grab the right to wake someone.
new = (old - 1<<mutexWaiterShift) | mutexWoken
if atomic.CompareAndSwapInt32(&m.state, old, new) {
- runtime.Semrelease(&m.sema)
+ runtime_Semrelease(&m.sema)
return
}
old = m.state
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
index a514b4a..bf78c6f 100644
--- a/libgo/go/sync/mutex_test.go
+++ b/libgo/go/sync/mutex_test.go
@@ -15,8 +15,8 @@ import (
func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
for i := 0; i < loops; i++ {
- runtime.Semacquire(s)
- runtime.Semrelease(s)
+ Runtime_Semacquire(s)
+ Runtime_Semrelease(s)
}
cdone <- true
}
diff --git a/libgo/go/sync/runtime.go b/libgo/go/sync/runtime.go
new file mode 100644
index 0000000..e99599c
--- /dev/null
+++ b/libgo/go/sync/runtime.go
@@ -0,0 +1,18 @@
+// Copyright 2012 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.
+
+package sync
+
+// defined in package runtime
+
+// Semacquire waits until *s > 0 and then atomically decrements it.
+// It is intended as a simple sleep primitive for use by the synchronization
+// library and should not be used directly.
+func runtime_Semacquire(s *uint32)
+
+// Semrelease atomically increments *s and notifies a waiting goroutine
+// if one is blocked in Semacquire.
+// It is intended as a simple wakeup primitive for use by the synchronization
+// library and should not be used directly.
+func runtime_Semrelease(s *uint32)
diff --git a/libgo/go/sync/runtime_sema_test.go b/libgo/go/sync/runtime_sema_test.go
new file mode 100644
index 0000000..57a8dbe
--- /dev/null
+++ b/libgo/go/sync/runtime_sema_test.go
@@ -0,0 +1,101 @@
+// 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.
+
+package sync_test
+
+import (
+ "runtime"
+ . "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func BenchmarkSemaUncontended(b *testing.B) {
+ type PaddedSem struct {
+ sem uint32
+ pad [32]uint32
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ sem := new(PaddedSem)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ Runtime_Semrelease(&sem.sem)
+ Runtime_Semacquire(&sem.sem)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkSema(b *testing.B, block, work bool) {
+ const CallsPerSched = 1000
+ const LocalWork = 100
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ c2 := make(chan bool, procs/2)
+ sem := uint32(0)
+ if block {
+ for p := 0; p < procs/2; p++ {
+ go func() {
+ Runtime_Semacquire(&sem)
+ c2 <- true
+ }()
+ }
+ }
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ Runtime_Semrelease(&sem)
+ if work {
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ Runtime_Semacquire(&sem)
+ }
+ }
+ c <- foo == 42
+ Runtime_Semrelease(&sem)
+ }()
+ }
+ if block {
+ for p := 0; p < procs/2; p++ {
+ <-c2
+ }
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSemaSyntNonblock(b *testing.B) {
+ benchmarkSema(b, false, false)
+}
+
+func BenchmarkSemaSyntBlock(b *testing.B) {
+ benchmarkSema(b, true, false)
+}
+
+func BenchmarkSemaWorkNonblock(b *testing.B) {
+ benchmarkSema(b, false, true)
+}
+
+func BenchmarkSemaWorkBlock(b *testing.B) {
+ benchmarkSema(b, true, true)
+}
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
index cb1a477..782a9c3 100644
--- a/libgo/go/sync/rwmutex.go
+++ b/libgo/go/sync/rwmutex.go
@@ -4,10 +4,7 @@
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// An RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers
@@ -29,7 +26,7 @@ const rwmutexMaxReaders = 1 << 30
func (rw *RWMutex) RLock() {
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// A writer is pending, wait for it.
- runtime.Semacquire(&rw.readerSem)
+ runtime_Semacquire(&rw.readerSem)
}
}
@@ -42,7 +39,7 @@ func (rw *RWMutex) RUnlock() {
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
// The last reader unblocks the writer.
- runtime.Semrelease(&rw.writerSem)
+ runtime_Semrelease(&rw.writerSem)
}
}
}
@@ -60,7 +57,7 @@ func (rw *RWMutex) Lock() {
r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
// Wait for active readers.
if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
- runtime.Semacquire(&rw.writerSem)
+ runtime_Semacquire(&rw.writerSem)
}
}
@@ -75,7 +72,7 @@ func (rw *RWMutex) Unlock() {
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
- runtime.Semrelease(&rw.readerSem)
+ runtime_Semrelease(&rw.readerSem)
}
// Allow other writers to proceed.
rw.w.Unlock()
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go
index a4c9b7e..3e7d9d3 100644
--- a/libgo/go/sync/waitgroup.go
+++ b/libgo/go/sync/waitgroup.go
@@ -4,10 +4,7 @@
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
@@ -60,7 +57,7 @@ func (wg *WaitGroup) Add(delta int) {
}
wg.m.Lock()
for i := int32(0); i < wg.waiters; i++ {
- runtime.Semrelease(wg.sema)
+ runtime_Semrelease(wg.sema)
}
wg.waiters = 0
wg.sema = nil
@@ -93,5 +90,5 @@ func (wg *WaitGroup) Wait() {
}
s := wg.sema
wg.m.Unlock()
- runtime.Semacquire(s)
+ runtime_Semacquire(s)
}