runtime: impose thread count limit

Actually working to stay within the limit could cause subtle deadlocks.
Crashing avoids the subtlety.

Fixes #4056.

R=golang-dev, r, dvyukov
CC=golang-dev
https://golang.org/cl/13037043
diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go
index 7ea1b6b..e07810b 100644
--- a/src/pkg/runtime/crash_test.go
+++ b/src/pkg/runtime/crash_test.go
@@ -125,6 +125,14 @@
 	}
 }
 
+func TestThreadExhaustion(t *testing.T) {
+	output := executeTest(t, threadExhaustionSource, nil)
+	want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
+	if !strings.HasPrefix(output, want) {
+		t.Fatalf("output does not start with %q:\n%s", want, output)
+	}
+}
+
 const crashSource = `
 package main
 
@@ -243,3 +251,25 @@
 	return x[0] + f(buf[:])
 }
 `
+
+const threadExhaustionSource = `
+package main
+
+import (
+	"runtime"
+	"runtime/debug"
+)
+
+func main() {
+	debug.SetMaxThreads(10)
+	c := make(chan int)
+	for i := 0; i < 100; i++ {
+		go func() {
+			runtime.LockOSThread()
+			c <- 0
+			select{}
+		}()
+		<-c
+	}
+}
+`