merge trunk;
diff --git a/.bzrignore b/.bzrignore
index 340cde7..e39772e 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,2 +1,3 @@
 _*
 [856].out
+[856].out.exe
diff --git a/LICENSE b/LICENSE
index d106fac..545cf2d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,29 +1,25 @@
 Gocheck - A rich testing framework for Go
-
-Copyright (c) 2010, Gustavo Niemeyer <gustavo@niemeyer.net>
+ 
+Copyright (c) 2010-2013 Gustavo Niemeyer <gustavo@niemeyer.net>
 
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+modification, are permitted provided that the following conditions are met: 
 
-    * Redistributions of source code must retain the above copyright notice,
-      this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright notice,
-      this list of conditions and the following disclaimer in the documentation
-      and/or other materials provided with the distribution.
-    * Neither the name of the copyright holder nor the names of its
-      contributors may be used to endorse or promote products derived from
-      this software without specific prior written permission.
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution. 
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/benchmark.go b/benchmark.go
index 58fc41a..dcd426f 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -6,8 +6,6 @@
 
 import (
 	"fmt"
-	"reflect"
-	"runtime"
 	"time"
 )
 
@@ -136,41 +134,3 @@
 	}
 	return 10 * base
 }
-
-// benchmarkN runs a single benchmark for the specified number of iterations.
-func benchmarkN(c *C, n int) {
-	// Try to get a comparable environment for each run
-	// by clearing garbage from previous runs.
-	runtime.GC()
-	c.N = n
-	c.ResetTimer()
-	c.StartTimer()
-	c.method.Call([]reflect.Value{reflect.ValueOf(c)})
-	c.StopTimer()
-}
-
-// benchmark runs the benchmark function.  It gradually increases the number
-// of benchmark iterations until the benchmark runs for a second in order
-// to get a reasonable measurement.
-func benchmark(c *C) {
-	// Run the benchmark for a single iteration in case it's expensive.
-	n := 1
-	benchmarkN(c, n)
-	// Run the benchmark for at least the specified amount of time.
-	for c.status == succeededSt && c.duration < c.benchTime && n < 1e9 {
-		last := n
-		// Predict iterations/sec.
-		if c.nsPerOp() == 0 {
-			n = 1e9
-		} else {
-			n = int(c.benchTime.Nanoseconds() / c.nsPerOp())
-		}
-		// Run more iterations than we think we'll need for a second (1.5x).
-		// Don't grow too fast in case we had timing errors previously.
-		// Be sure to run at least one more than last time.
-		n = max(min(n+n/2, 100*last), last+1)
-		// Round up to something easy to read.
-		n = roundUp(n)
-		benchmarkN(c, n)
-	}
-}
diff --git a/benchmark_test.go b/benchmark_test.go
index ed6a8fa..336243f 100644
--- a/benchmark_test.go
+++ b/benchmark_test.go
@@ -36,8 +36,6 @@
 	c.Assert(output.value, Matches, expected)
 }
 
-// Quite unfortunate that these two tests alone account for most of the 
-
 func (s *BenchmarkS) TestBenchmark(c *C) {
 	helper := FixtureHelper{sleep: 100000}
 	output := String{}
@@ -48,6 +46,14 @@
 		Filter:        "Benchmark1",
 	}
 	Run(&helper, &runConf)
+	c.Check(helper.calls[0], Equals, "SetUpSuite")
+	c.Check(helper.calls[1], Equals, "SetUpTest")
+	c.Check(helper.calls[2], Equals, "Benchmark1")
+	c.Check(helper.calls[3], Equals, "TearDownTest")
+	c.Check(helper.calls[4], Equals, "SetUpTest")
+	c.Check(helper.calls[5], Equals, "Benchmark1")
+	c.Check(helper.calls[6], Equals, "TearDownTest")
+	// ... and more.
 
 	expected := "PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Benchmark1\t *100\t *[12][0-9]{5} ns/op\n"
 	c.Assert(output.value, Matches, expected)
diff --git a/fixture_test.go b/fixture_test.go
index cd66118..63f392e 100644
--- a/fixture_test.go
+++ b/fixture_test.go
@@ -31,7 +31,7 @@
 	c.Check(helper.calls[5], Equals, "Test2")
 	c.Check(helper.calls[6], Equals, "TearDownTest")
 	c.Check(helper.calls[7], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 8)
+	c.Check(len(helper.calls), Equals, 8)
 }
 
 // -----------------------------------------------------------------------
@@ -49,7 +49,7 @@
 	c.Check(helper.calls[5], Equals, "Test2")
 	c.Check(helper.calls[6], Equals, "TearDownTest")
 	c.Check(helper.calls[7], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 8)
+	c.Check(len(helper.calls), Equals, 8)
 
 	expected := "^\n-+\n" +
 		"PANIC: gocheck_test\\.go:[0-9]+: FixtureHelper.Test1\n\n" +
@@ -72,7 +72,7 @@
 	c.Check(helper.calls[1], Equals, "SetUpTest")
 	c.Check(helper.calls[2], Equals, "TearDownTest")
 	c.Check(helper.calls[3], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 4)
+	c.Check(len(helper.calls), Equals, 4)
 
 	expected := "^\n-+\n" +
 		"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -102,7 +102,7 @@
 	c.Check(helper.calls[2], Equals, "Test1")
 	c.Check(helper.calls[3], Equals, "TearDownTest")
 	c.Check(helper.calls[4], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 5)
+	c.Check(len(helper.calls), Equals, 5)
 
 	expected := "^\n-+\n" +
 		"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -129,7 +129,7 @@
 	Run(&helper, &RunConf{Output: &output})
 	c.Check(helper.calls[0], Equals, "SetUpSuite")
 	c.Check(helper.calls[1], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 2)
+	c.Check(len(helper.calls), Equals, 2)
 
 	expected := "^\n-+\n" +
 		"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -157,7 +157,7 @@
 	c.Check(helper.calls[5], Equals, "Test2")
 	c.Check(helper.calls[6], Equals, "TearDownTest")
 	c.Check(helper.calls[7], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 8)
+	c.Check(len(helper.calls), Equals, 8)
 
 	expected := "^\n-+\n" +
 		"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -187,7 +187,7 @@
 	c.Check(helper.calls[4], Equals, "Test2")
 	c.Check(helper.calls[5], Equals, "TearDownTest")
 	c.Check(helper.calls[6], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 7)
+	c.Check(len(helper.calls), Equals, 7)
 
 	expected := "^\n-+\n" +
 		"PANIC: fixture_test\\.go:[0-9]+: " +
@@ -202,7 +202,7 @@
 	helper := WrongSetUpTestArgHelper{}
 	output := String{}
 	Run(&helper, &RunConf{Output: &output})
-	c.Check(helper.n, Equals, 0)
+	c.Check(len(helper.calls), Equals, 0)
 
 	expected :=
 		"^\n-+\n" +
@@ -218,7 +218,7 @@
 	helper := WrongSetUpSuiteArgHelper{}
 	output := String{}
 	Run(&helper, &RunConf{Output: &output})
-	c.Check(helper.n, Equals, 0)
+	c.Check(len(helper.calls), Equals, 0)
 
 	expected :=
 		"^\n-+\n" +
@@ -244,7 +244,7 @@
 	c.Check(helper.calls[4], Equals, "Test2")
 	c.Check(helper.calls[5], Equals, "TearDownTest")
 	c.Check(helper.calls[6], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 7)
+	c.Check(len(helper.calls), Equals, 7)
 
 	expected := "^\n-+\n" +
 		"PANIC: fixture_test\\.go:[0-9]+: " +
@@ -259,7 +259,7 @@
 	helper := WrongSetUpTestArgCountHelper{}
 	output := String{}
 	Run(&helper, &RunConf{Output: &output})
-	c.Check(helper.n, Equals, 0)
+	c.Check(len(helper.calls), Equals, 0)
 
 	expected :=
 		"^\n-+\n" +
@@ -275,7 +275,7 @@
 	helper := WrongSetUpSuiteArgCountHelper{}
 	output := String{}
 	Run(&helper, &RunConf{Output: &output})
-	c.Check(helper.n, Equals, 0)
+	c.Check(len(helper.calls), Equals, 0)
 
 	expected :=
 		"^\n-+\n" +
@@ -460,7 +460,7 @@
 	c.Assert(output.value, Equals, "")
 	c.Assert(helper.calls[0], Equals, "SetUpSuite")
 	c.Assert(helper.calls[1], Equals, "TearDownSuite")
-	c.Assert(helper.n, Equals, 2)
+	c.Assert(len(helper.calls), Equals, 2)
 	c.Assert(result.Skipped, Equals, 2)
 }
 
@@ -474,6 +474,6 @@
 	c.Assert(helper.calls[3], Equals, "Test2")
 	c.Assert(helper.calls[4], Equals, "TearDownTest")
 	c.Assert(helper.calls[5], Equals, "TearDownSuite")
-	c.Assert(helper.n, Equals, 6)
+	c.Assert(len(helper.calls), Equals, 6)
 	c.Assert(result.Skipped, Equals, 1)
 }
diff --git a/gocheck.go b/gocheck.go
index e5403ac..90ad97e 100644
--- a/gocheck.go
+++ b/gocheck.go
@@ -53,11 +53,29 @@
 	return method.Info.Func.Pointer()
 }
 
+func (method *methodType) suiteName() string {
+	t := method.Info.Type.In(0)
+	if t.Kind() == reflect.Ptr {
+		t = t.Elem()
+	}
+	return t.Name()
+}
+
+func (method *methodType) String() string {
+	return method.suiteName()+"."+method.Info.Name
+}
+
+func (method *methodType) matches(re *regexp.Regexp) bool {
+	return (re.MatchString(method.Info.Name) ||
+		re.MatchString(method.suiteName()) ||
+		re.MatchString(method.String()))
+}
+
 type C struct {
 	method    *methodType
 	kind      funcKind
 	status    funcStatus
-	logb      *bytes.Buffer
+	logb      *logger
 	logw      io.Writer
 	done      chan *C
 	reason    string
@@ -71,6 +89,30 @@
 	runtime.Goexit()
 }
 
+// logger is a concurrency safe byte.Buffer
+type logger struct {
+	sync.Mutex
+	writer bytes.Buffer
+}
+
+func (l *logger) Write(buf []byte) (int, error) {
+	l.Lock()
+	defer l.Unlock()
+	return l.writer.Write(buf)
+}
+
+func (l *logger) WriteTo(w io.Writer) (int64, error) {
+	l.Lock()
+	defer l.Unlock()
+	return l.writer.WriteTo(w)
+}
+
+func (l *logger) String() string {
+	l.Lock()
+	defer l.Unlock()
+	return l.writer.String()
+}
+
 // -----------------------------------------------------------------------
 // Handling of temporary files and directories.
 
@@ -294,10 +336,16 @@
 
 var initWD, initWDErr = os.Getwd()
 
+func init() {
+	if initWDErr == nil {
+		initWD = strings.Replace(initWD, "\\", "/", -1) + "/"
+	}
+}
+
 func nicePath(path string) string {
 	if initWDErr == nil {
-		if strings.HasPrefix(path, initWD+"/") {
-			return path[len(initWD)+1:]
+		if strings.HasPrefix(path, initWD) {
+			return path[len(initWD):]
 		}
 	}
 	return path
@@ -499,24 +547,8 @@
 		}
 	}
 
-	// This map will be used to filter out duplicated methods.  This
-	// looks like a bug in Go, described on issue 906:
-	// http://code.google.com/p/go/issues/detail?id=906
-	seen := make(map[uintptr]bool, suiteNumMethods)
-
-	// XXX Shouldn't Name() work here? Why does it return an empty string?
-	suiteName := suiteType.String()
-	if index := strings.LastIndex(suiteName, "."); index != -1 {
-		suiteName = suiteName[index+1:]
-	}
-
 	for i := 0; i != suiteNumMethods; i++ {
 		method := newMethod(suiteValue, i)
-		methodPC := method.PC()
-		if _, found := seen[methodPC]; found {
-			continue
-		}
-		seen[methodPC] = true
 		switch method.Info.Name {
 		case "SetUpSuite":
 			runner.setUpSuite = method
@@ -527,7 +559,14 @@
 		case "TearDownTest":
 			runner.tearDownTest = method
 		default:
-			if isWanted(conf.Benchmark, suiteName, method.Info.Name, filterRegexp) {
+			prefix := "Test"
+			if conf.Benchmark {
+				prefix = "Benchmark"
+			}
+			if !strings.HasPrefix(method.Info.Name, prefix) {
+				continue
+			}
+			if filterRegexp == nil || method.matches(filterRegexp) {
 				runner.tests = append(runner.tests, method)
 			}
 		}
@@ -535,25 +574,6 @@
 	return runner
 }
 
-// isWanted returns true if the given suite and method names should be run.
-// The bench result indicates whether the method is a benchmark rather than
-// a test.
-func isWanted(benchmark bool, suiteName, methodName string, filterRegexp *regexp.Regexp) bool {
-	prefix := "Test"
-	if benchmark {
-		prefix = "Benchmark"
-	}
-	if !strings.HasPrefix(methodName, prefix) {
-		return false
-	}
-	if filterRegexp == nil {
-		return true
-	}
-	return (filterRegexp.MatchString(methodName) ||
-		filterRegexp.MatchString(suiteName) ||
-		filterRegexp.MatchString(suiteName+"."+methodName))
-}
-
 // Run all methods in the given suite.
 func (runner *suiteRunner) run() *Result {
 	if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
@@ -585,13 +605,13 @@
 
 // Create a call object with the given suite method, and fork a
 // goroutine with the provided dispatcher for running it.
-func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, logb *bytes.Buffer, dispatcher func(c *C)) *C {
+func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, logb *logger, dispatcher func(c *C)) *C {
 	var logw io.Writer
 	if runner.output.Stream {
 		logw = runner.output
 	}
 	if logb == nil {
-		logb = bytes.NewBuffer(nil)
+		logb = new(logger)
 	}
 	c := &C{
 		method:    method,
@@ -613,7 +633,7 @@
 }
 
 // Same as forkCall(), but wait for call to finish before returning.
-func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, logb *bytes.Buffer, dispatcher func(c *C)) *C {
+func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, logb *logger, dispatcher func(c *C)) *C {
 	c := runner.forkCall(method, kind, logb, dispatcher)
 	<-c.done
 	return c
@@ -656,7 +676,7 @@
 // goroutine like all suite methods, but this method will not return
 // while the fixture goroutine is not done, because the fixture must be
 // run in a desired order.
-func (runner *suiteRunner) runFixture(method *methodType, logb *bytes.Buffer) *C {
+func (runner *suiteRunner) runFixture(method *methodType, logb *logger) *C {
 	if method != nil {
 		c := runner.runFunc(method, fixtureKd, logb, func(c *C) {
 			c.ResetTimer()
@@ -672,13 +692,15 @@
 // Run the fixture method with runFixture(), but panic with a fixturePanic{}
 // in case the fixture method panics.  This makes it easier to track the
 // fixture panic together with other call panics within forkTest().
-func (runner *suiteRunner) runFixtureWithPanic(method *methodType, logb *bytes.Buffer, skipped *bool) *C {
-	if *skipped {
+func (runner *suiteRunner) runFixtureWithPanic(method *methodType, logb *logger, skipped *bool) *C {
+	if skipped != nil && *skipped {
 		return nil
 	}
 	c := runner.runFixture(method, logb)
 	if c != nil && c.status != succeededSt {
-		*skipped = c.status == skippedSt
+		if skipped != nil {
+			*skipped = c.status == skippedSt
+		}
 		panic(&fixturePanic{c.status, method})
 	}
 	return c
@@ -695,27 +717,53 @@
 	return runner.forkCall(method, testKd, nil, func(c *C) {
 		var skipped bool
 		defer runner.runFixtureWithPanic(runner.tearDownTest, nil, &skipped)
-		runner.runFixtureWithPanic(runner.setUpTest, c.logb, &skipped)
-		mt := c.method.Type()
-		if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
-			// Rather than a plain panic, provide a more helpful message when
-			// the argument type is incorrect.
-			c.status = panickedSt
-			c.logArgPanic(c.method, "*gocheck.C")
-			return
-		}
-		if strings.HasPrefix(c.method.Info.Name, "Test") {
+		defer c.StopTimer()
+		benchN := 1
+		for {
+			runner.runFixtureWithPanic(runner.setUpTest, c.logb, &skipped)
+			mt := c.method.Type()
+			if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
+				// Rather than a plain panic, provide a more helpful message when
+				// the argument type is incorrect.
+				c.status = panickedSt
+				c.logArgPanic(c.method, "*gocheck.C")
+				return
+			}
+			if strings.HasPrefix(c.method.Info.Name, "Test") {
+				c.ResetTimer()
+				c.StartTimer()
+				c.method.Call([]reflect.Value{reflect.ValueOf(c)})
+				return
+			}
+			if !strings.HasPrefix(c.method.Info.Name, "Benchmark") {
+				panic("unexpected method prefix: " + c.method.Info.Name)
+			}
+
+			runtime.GC()
+			c.N = benchN
 			c.ResetTimer()
 			c.StartTimer()
-			defer c.StopTimer()
 			c.method.Call([]reflect.Value{reflect.ValueOf(c)})
-			return
+			c.StopTimer()
+			if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
+				return
+			}
+			perOpN := int(1e9)
+			if c.nsPerOp() != 0 {
+				perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp())
+			}
+
+			// Logic taken from the stock testing package:
+			// - Run more iterations than we think we'll need for a second (1.5x).
+			// - Don't grow too fast in case we had timing errors previously.
+			// - Be sure to run at least one more than last time.
+			benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1)
+			benchN = roundUp(benchN)
+
+			skipped = true // Don't run the deferred one if this panics.
+			runner.runFixtureWithPanic(runner.tearDownTest, nil, nil)
+			skipped = false
 		}
-		if strings.HasPrefix(c.method.Info.Name, "Benchmark") {
-			benchmark(c)
-			return
-		}
-		panic("unexpected method prefix: " + c.method.Info.Name)
 	})
 }
 
@@ -867,3 +915,4 @@
 	return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
 		niceFuncName(pc), suffix)
 }
+
diff --git a/gocheck_test.go b/gocheck_test.go
index 484832a..7575df4 100644
--- a/gocheck_test.go
+++ b/gocheck_test.go
@@ -94,27 +94,24 @@
 // Helper suite for testing ordering and behavior of fixture.
 
 type FixtureHelper struct {
-	calls   [64]string
-	n       int
-	panicOn string
-	skip    bool
-	skipOnN int
-	sleepOn string
-	sleep   time.Duration
-	bytes   int64
+	calls    []string
+	panicOn  string
+	skip     bool
+	skipOnN  int
+	sleepOn  string
+	sleep    time.Duration
+	bytes    int64
 }
 
 func (s *FixtureHelper) trace(name string, c *gocheck.C) {
-	n := s.n
-	s.calls[n] = name
-	s.n += 1
+	s.calls = append(s.calls, name)
 	if name == s.panicOn {
 		panic(name)
 	}
 	if s.sleep > 0 && s.sleepOn == name {
 		time.Sleep(s.sleep)
 	}
-	if s.skip && s.skipOnN == n {
+	if s.skip && s.skipOnN == len(s.calls)-1 {
 		c.Skip("skipOnN == n")
 	}
 }
diff --git a/helpers_test.go b/helpers_test.go
index 79348bc..fb9ef8e 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -7,6 +7,8 @@
 	"launchpad.net/gocheck"
 	"os"
 	"reflect"
+	"runtime"
+	"sync"
 )
 
 var helpersS = gocheck.Suite(&HelpersS{})
@@ -428,6 +430,26 @@
 	return false
 }
 
+// Concurrent logging should not corrupt the underling buffer.
+// Use go test -race to detect the race in this test.
+func (s *HelpersS) TestConcurrentLogging(c *gocheck.C) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
+	var start, stop sync.WaitGroup
+	start.Add(1)
+	for i, n := 0, runtime.NumCPU()*2; i < n; i++ {
+		stop.Add(1)
+		go func(i int) {
+			start.Wait()
+			for j := 0; j < 30; j++ {
+				c.Logf("Worker %d: line %d", i, j)
+			}
+			stop.Done()
+		}(i)
+	}
+	start.Done()
+	stop.Wait()
+}
+
 // -----------------------------------------------------------------------
 // A couple of helper functions to test helper functions. :-)
 
diff --git a/run.go b/run.go
index 2f6ebed..9e08152 100644
--- a/run.go
+++ b/run.go
@@ -1,8 +1,10 @@
 package gocheck
 
 import (
+	"bufio"
 	"flag"
 	"fmt"
+	"os"
 	"testing"
 	"time"
 )
@@ -24,11 +26,12 @@
 // Public running interface.
 
 var (
-	filterFlag  = flag.String("gocheck.f", "", "Regular expression selecting what to run")
+	filterFlag  = flag.String("gocheck.f", "", "Regular expression selecting which tests and/or suites to run")
 	verboseFlag = flag.Bool("gocheck.v", false, "Verbose mode")
 	streamFlag  = flag.Bool("gocheck.vv", false, "Super verbose mode (disables output caching)")
 	benchFlag   = flag.Bool("gocheck.b", false, "Run benchmarks")
-	benchTime   = flag.Duration("gocheck.btime", 1*time.Second, "approximate run time for each benchmark")
+	benchTime   = flag.Duration("gocheck.btime", 1 * time.Second, "approximate run time for each benchmark")
+	listFlag    = flag.Bool("gocheck.list", false, "List the names of all tests that will be run")
 )
 
 // Run all test suites registered with the Suite() function, printing
@@ -42,6 +45,14 @@
 		Benchmark:     *benchFlag,
 		BenchmarkTime: *benchTime,
 	}
+	if *listFlag {
+		w := bufio.NewWriter(os.Stdout)
+		for _, name := range ListAll(conf) {
+			fmt.Fprintln(w, name)
+		}
+		w.Flush()
+		return
+	}
 	result := RunAll(conf)
 	println(result.String())
 	if !result.Passed() {
@@ -49,7 +60,7 @@
 	}
 }
 
-// Run all test suites registered with the Suite() function, using the
+// RunAll runs all test suites registered with the Suite() function, using the
 // given run configuration.
 func RunAll(runConf *RunConf) *Result {
 	result := Result{}
@@ -59,12 +70,34 @@
 	return &result
 }
 
-// Run the given test suite using the provided run configuration.
+// Run runs the given test suite using the provided run configuration.
 func Run(suite interface{}, runConf *RunConf) *Result {
 	runner := newSuiteRunner(suite, runConf)
 	return runner.run()
 }
 
+// ListAll returns the names of all the test functions registered with the
+// Suite function that will be run with the provided run configuration.
+func ListAll(runConf *RunConf) []string {
+	var names []string
+	for _, suite := range allSuites {
+		names = append(names, List(suite, runConf)...)
+	}
+	return names
+}
+
+// List prints the names of the test functions in the given
+// suite that will be run with the provided run configuration
+// to the given Writer.
+func List(suite interface{}, runConf *RunConf) []string {
+	var names []string
+	runner := newSuiteRunner(suite, runConf)
+	for _, t := range runner.tests {
+		names = append(names, t.String())
+	}
+	return names
+}
+
 // -----------------------------------------------------------------------
 // Result methods.
 
diff --git a/run_test.go b/run_test.go
index 79f696d..6793e4c 100644
--- a/run_test.go
+++ b/run_test.go
@@ -2,6 +2,7 @@
 
 package gocheck_test
 
+
 import (
 	"errors"
 	. "launchpad.net/gocheck"
@@ -205,7 +206,7 @@
 	c.Check(helper.calls[2], Equals, "Test1")
 	c.Check(helper.calls[3], Equals, "TearDownTest")
 	c.Check(helper.calls[4], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 5)
+	c.Check(len(helper.calls), Equals, 5)
 }
 
 func (s *RunS) TestFilterTestNameWithAll(c *C) {
@@ -221,7 +222,7 @@
 	c.Check(helper.calls[5], Equals, "Test2")
 	c.Check(helper.calls[6], Equals, "TearDownTest")
 	c.Check(helper.calls[7], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 8)
+	c.Check(len(helper.calls), Equals, 8)
 }
 
 func (s *RunS) TestFilterSuiteName(c *C) {
@@ -237,7 +238,7 @@
 	c.Check(helper.calls[5], Equals, "Test2")
 	c.Check(helper.calls[6], Equals, "TearDownTest")
 	c.Check(helper.calls[7], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 8)
+	c.Check(len(helper.calls), Equals, 8)
 }
 
 func (s *RunS) TestFilterSuiteNameAndTestName(c *C) {
@@ -250,7 +251,7 @@
 	c.Check(helper.calls[2], Equals, "Test2")
 	c.Check(helper.calls[3], Equals, "TearDownTest")
 	c.Check(helper.calls[4], Equals, "TearDownSuite")
-	c.Check(helper.n, Equals, 5)
+	c.Check(len(helper.calls), Equals, 5)
 }
 
 func (s *RunS) TestFilterAllOut(c *C) {
@@ -258,7 +259,7 @@
 	output := String{}
 	runConf := RunConf{Output: &output, Filter: "NotFound"}
 	Run(&helper, &runConf)
-	c.Check(helper.n, Equals, 0)
+	c.Check(len(helper.calls), Equals, 0)
 }
 
 func (s *RunS) TestRequirePartialMatch(c *C) {
@@ -266,7 +267,7 @@
 	output := String{}
 	runConf := RunConf{Output: &output, Filter: "est"}
 	Run(&helper, &runConf)
-	c.Check(helper.n, Equals, 8)
+	c.Check(len(helper.calls), Equals, 8)
 }
 
 func (s *RunS) TestFilterError(c *C) {
@@ -276,7 +277,25 @@
 	result := Run(&helper, &runConf)
 	c.Check(result.String(), Equals,
 		"ERROR: Bad filter expression: error parsing regexp: missing closing ]: `[`")
-	c.Check(helper.n, Equals, 0)
+	c.Check(len(helper.calls), Equals, 0)
+}
+
+// -----------------------------------------------------------------------
+// Verify that List works correctly.
+
+func (s *RunS) TestListFiltered(c *C) {
+	names := List(&FixtureHelper{}, &RunConf{Filter: "1"})
+	c.Assert(names, DeepEquals, []string{
+		"FixtureHelper.Test1",
+	})
+}
+
+func (s *RunS) TestList(c *C) {
+	names := List(&FixtureHelper{}, &RunConf{})
+	c.Assert(names, DeepEquals, []string{
+		"FixtureHelper.Test1",
+		"FixtureHelper.Test2",
+	})
 }
 
 // -----------------------------------------------------------------------