go.talks: Inside the Go playground

LGTM=rsc, adg
R=adg, rsc, dsymonds
CC=golang-codereviews
https://golang.org/cl/118070043
diff --git a/2014/playground.slide b/2014/playground.slide
new file mode 100644
index 0000000..aa976a8
--- /dev/null
+++ b/2014/playground.slide
@@ -0,0 +1,314 @@
+Inside the Go playground
+
+Francesc Campoy Flores
+Developer Advocate, Gopher
+@francesc
+campoy@golang.org
+http://campoy.cat
+
+* Agenda
+
+- What is the Go playground
+
+- What could go wrong
+
+- What did we do to avoid it
+
+- An animated ASCII train
+
+* The Go playground
+
+.image playground/img/play.png 500 _
+.caption [[http://play.golang.org][play.golang.org]]
+
+* De facto pastebin of the Go community
+
+.image playground/img/share.png 500 _
+.caption [[http://play.golang.org/p/bJYnajZ6Kp]]
+
+* The Go tour
+
+.image playground/img/tour.png 500 _
+.caption [[http://tour.golang.org][tour.golang.org]]
+
+* Executable examples on documentation
+
+.image playground/img/examples.png 500 _
+.caption [[http://golang.org/pkg/strings/#example_Fields][golang.org/pkg/strings]]
+
+* Executable code on blog posts
+
+.image playground/img/blog.png 500 _
+.caption [[http://blog.golang.org/slices]]
+
+* Executable slides
+
+.play playground/hello.go
+
+These slides are driven by the `present` Go tool
+
+	go get code.google.com/go.tools/cmd/present
+
+* Naive implementation
+
+* Architecture
+
+.image playground/img/arch.png 500 _
+
+* Backend
+
+Let's start with something simple
+
+- receive code
+- compile it
+- run it
+
+* What could go wrong?
+
+.image playground/img/areyousure.png 500 _
+
+###########
+## Issues #
+###########
+
+* Resource exhaustion
+
+* Exhausting memory on the stack
+
+`stack`overflow`
+
+.play playground/stack.go
+
+The runtime catches the error and panics.
+
+* Too much memory on the heap
+
+`out`of`memory`
+
+.play playground/heap.go
+
+Again the runtime catches the error and panics.
+
+* Too much CPU time
+
+.play playground/loop.go
+
+* Stealing resources by sleeping
+
+.play playground/sleep.go
+
+A sleeping program still consumes resources.
+
+Easy way of having a Denial of Service attack.
+
+* Accessing things you shouldn't
+
+* File system access
+
+User code shouldn't be able to modify the backend's file system.
+
+- Reading sensitive information
+
+- Installing backdoors
+
+- General mayhem
+
+.play playground/removeall.go /func main/,/^}/
+
+* Network access
+
+.play playground/http.go /func main/,/^}/
+
+* Use your imagination
+
+.image playground/img/cat.jpg 500 _
+
+###################
+# Countermeasures #
+###################
+
+* Countermeasures
+
+* Restricting resource usage with ulimit
+
+Default limits are not safe enough.
+
+`ulimit` could solve this.
+
+	-d    maximum size of data segment or heap (in kbytes)
+
+	-s    maximum size of stack segment (in kbytes)
+
+	-t    maximum CPU time (in seconds)
+
+	-v    maximum size of virtual memory (in kbytes)
+
+* Native Client
+
+Originally designed to execute native code in Chrome safely.
+
+NaCl defines restrictions on the binaries being executed.
+
+The code runs in a sandbox isolated from the underlying OS.
+
+- No file access
+- No network access
+
+.image playground/img/nacl.png 300 _
+
+* Isolating process execution with NaCl
+
+We use NaCl to:
+
+- limit CPU time
+
+- limit memory
+
+- isolate from the filesystem
+
+- isolate from the network
+
+Process can only write to stdout/stderr.
+
+* Limiting user time
+
+"No sleeping in the playground."
+
+Custom runtime with a fake `time` package.
+
+	func Sleep(d time.Duration) {
+		panic("No sleeping in the playground")
+	}
+
+* Restoring functionality
+
+* Faking the file system
+
+The `syscall` package is the only link between user code and the OS kernel.
+
+The playground runtime has a custom `syscall` package.
+
+File system operations operate on a fake in-memory file system.
+
+.play playground/file.go /func main/,
+
+* Faking the network
+
+All network operations also use the `syscall` package.
+
+The network stack is also faked in-memory.
+
+.play playground/net.go /func main/,/^}/
+
+* Faking the network (continued)
+
+.play playground/net.go /func dial/,/^}/
+
+##########
+## TIME ##
+##########
+
+* Sleeping int the playground
+
+Go is about concurrency.
+
+We need to demonstrate concurrency in blog posts and talks.
+
+And demonstrating concurrency without `time` is hard.
+
+* What to do if an open source project lacks a feature?
+
+.image playground/img/gopherbw.png 500 _
+
+* File a bug!
+
+.image playground/img/bug.png 500 _
+.caption [[https://code.google.com/p/go/issues/detail?id=4280][bug 4280]]
+
+* Normal behavior
+
+There's a special goroutine managing timers `T`.
+
+A goroutine `G` calls `time.Sleep`:
+
+1. `G` adds a timer to the timer heap.
+
+2. `G` puts itself to sleep.
+
+3. `T` tells the OS to wake it when the next timer expires and puts itself to sleep.
+
+4. When `T` is woken up it looks at the timer on the top of the heap, and wakes the corresponding goroutine.
+
+* Intermission: deadlocks
+
+.play playground/deadlock.go
+
+Many flavors of deadlocks.
+
+One common property: all goroutines are asleep.
+
+* New behavior
+
+A goroutine `G` calls `time.Sleep`:
+
+1. `G` adds a timer to the timer heap.
+
+2. `G` puts itself to sleep.
+
+3. The scheduler detects a deadlock, checks the timer heap for pending timers.
+
+4. The internal clock is advanced to the next timer expiration.
+
+5. The corresponding goroutines are woken up.
+
+* So there's no actual sleep?
+
+The playground's `write` syscall inserts a timestamp before each write.
+
+The front end translates that into a series of "events" that the browser can play back.
+
+.play playground/sleep.go /func main/,
+
+Returns directly
+
+	{
+		"Errors":"",
+		"Events":[
+			{"Message":"Good night\n","Delay":0},
+			{"Message":"Good morning\n","Delay":28800000000000}
+		]
+	}
+
+* So the bug was fixed
+
+.image playground/img/andrew.png _ 1000
+.caption [[http://play.golang.org/p/3fv0L3-z0s]]
+
+* And people were happy
+
+.image playground/img/brad.png _ 1000
+.caption [[http://play.golang.org/p/rX_3WcpUOZ]]
+
+* Very happy
+
+.image playground/img/jan.png _ 1000
+.caption [[http://play.golang.org/p/P-Dk0NH_vf]]
+
+.image playground/img/mattn.png _ 1000
+.caption [[http://play.golang.org/p/NOycgN2i6b]]
+
+* References
+
+These slides: [[http://talks.golang.org/2014/playground.slide]]
+
+More about the Go tour:
+
+- Inside the Go: playground [[http://blog.golang.org/playground]]
+
+- The Go tour: [[http://tour.golang.org]]
+
+More about Go on NaCl:
+
+- Running Go under Native Client: [[https://code.google.com/p/go-wiki/wiki/NativeClient]]
+
+- Go 1.3 Native Client Support: [[http://golang.org/s/go13nacl]]
\ No newline at end of file
diff --git a/2014/playground/deadlock.go b/2014/playground/deadlock.go
new file mode 100644
index 0000000..2cafec8
--- /dev/null
+++ b/2014/playground/deadlock.go
@@ -0,0 +1,7 @@
+package main
+
+func main() {
+	c := make(chan int)
+
+	<-c
+}
diff --git a/2014/playground/file.go b/2014/playground/file.go
new file mode 100644
index 0000000..a73beb0
--- /dev/null
+++ b/2014/playground/file.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+)
+
+func main() {
+	const filename = "/tmp/file.txt"
+
+	err := ioutil.WriteFile(filename, []byte("Hello, file system\n"), 0644)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	b, err := ioutil.ReadFile(filename)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Printf("%s", b)
+}
diff --git a/2014/playground/heap.go b/2014/playground/heap.go
new file mode 100644
index 0000000..bd83db1
--- /dev/null
+++ b/2014/playground/heap.go
@@ -0,0 +1,13 @@
+package main
+
+type list struct {
+	buf  [1000]byte
+	next *list
+}
+
+func main() {
+	var l *list
+	for {
+		l = &list{next: l}
+	}
+}
diff --git a/2014/playground/hello.go b/2014/playground/hello.go
new file mode 100644
index 0000000..4ffebac
--- /dev/null
+++ b/2014/playground/hello.go
@@ -0,0 +1,7 @@
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("Hello, gophers!")
+}
diff --git a/2014/playground/http.go b/2014/playground/http.go
new file mode 100644
index 0000000..863b00b
--- /dev/null
+++ b/2014/playground/http.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+)
+
+func main() {
+	res, err := http.Get("http://api.openweathermap.org/data/2.5/weather?q=Portland")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer res.Body.Close()
+
+	var w struct {
+		Weather []struct {
+			Desc string `json:"description"`
+		} `json:"weather"`
+	}
+	if err := json.NewDecoder(res.Body).Decode(&w); err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Printf("No need to rush outside, we have %v.", w.Weather[0].Desc)
+}
diff --git a/2014/playground/img/andrew.png b/2014/playground/img/andrew.png
new file mode 100644
index 0000000..1731823
--- /dev/null
+++ b/2014/playground/img/andrew.png
Binary files differ
diff --git a/2014/playground/img/arch.png b/2014/playground/img/arch.png
new file mode 100644
index 0000000..9f1dfd1
--- /dev/null
+++ b/2014/playground/img/arch.png
Binary files differ
diff --git a/2014/playground/img/areyousure.png b/2014/playground/img/areyousure.png
new file mode 100644
index 0000000..b0555ed
--- /dev/null
+++ b/2014/playground/img/areyousure.png
Binary files differ
diff --git a/2014/playground/img/blog.png b/2014/playground/img/blog.png
new file mode 100644
index 0000000..14a78d2
--- /dev/null
+++ b/2014/playground/img/blog.png
Binary files differ
diff --git a/2014/playground/img/brad.png b/2014/playground/img/brad.png
new file mode 100644
index 0000000..0da6995
--- /dev/null
+++ b/2014/playground/img/brad.png
Binary files differ
diff --git a/2014/playground/img/bug.png b/2014/playground/img/bug.png
new file mode 100644
index 0000000..2711556
--- /dev/null
+++ b/2014/playground/img/bug.png
Binary files differ
diff --git a/2014/playground/img/cat.jpg b/2014/playground/img/cat.jpg
new file mode 100644
index 0000000..022cc53
--- /dev/null
+++ b/2014/playground/img/cat.jpg
Binary files differ
diff --git a/2014/playground/img/examples.png b/2014/playground/img/examples.png
new file mode 100644
index 0000000..7766e68
--- /dev/null
+++ b/2014/playground/img/examples.png
Binary files differ
diff --git a/2014/playground/img/gopherbw.png b/2014/playground/img/gopherbw.png
new file mode 100644
index 0000000..23c425f
--- /dev/null
+++ b/2014/playground/img/gopherbw.png
Binary files differ
diff --git a/2014/playground/img/jan.png b/2014/playground/img/jan.png
new file mode 100644
index 0000000..e0afdee
--- /dev/null
+++ b/2014/playground/img/jan.png
Binary files differ
diff --git a/2014/playground/img/mattn.png b/2014/playground/img/mattn.png
new file mode 100644
index 0000000..501359f
--- /dev/null
+++ b/2014/playground/img/mattn.png
Binary files differ
diff --git a/2014/playground/img/nacl.png b/2014/playground/img/nacl.png
new file mode 100644
index 0000000..46d5ca6
--- /dev/null
+++ b/2014/playground/img/nacl.png
Binary files differ
diff --git a/2014/playground/img/play.png b/2014/playground/img/play.png
new file mode 100644
index 0000000..8e7119e
--- /dev/null
+++ b/2014/playground/img/play.png
Binary files differ
diff --git a/2014/playground/img/share.png b/2014/playground/img/share.png
new file mode 100644
index 0000000..8973ce6
--- /dev/null
+++ b/2014/playground/img/share.png
Binary files differ
diff --git a/2014/playground/img/sleepbug.png b/2014/playground/img/sleepbug.png
new file mode 100644
index 0000000..9b74227
--- /dev/null
+++ b/2014/playground/img/sleepbug.png
Binary files differ
diff --git a/2014/playground/img/tour.png b/2014/playground/img/tour.png
new file mode 100644
index 0000000..3999bdf
--- /dev/null
+++ b/2014/playground/img/tour.png
Binary files differ
diff --git a/2014/playground/loop.go b/2014/playground/loop.go
new file mode 100644
index 0000000..06c48fd
--- /dev/null
+++ b/2014/playground/loop.go
@@ -0,0 +1,6 @@
+package main
+
+func main() {
+	for {
+	}
+}
diff --git a/2014/playground/net.go b/2014/playground/net.go
new file mode 100644
index 0000000..2728055
--- /dev/null
+++ b/2014/playground/net.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"io"
+	"log"
+	"net"
+	"os"
+)
+
+func main() {
+	l, err := net.Listen("tcp", "127.0.0.1:4000")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer l.Close()
+
+	go dial()
+
+	c, err := l.Accept()
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer c.Close()
+
+	io.Copy(os.Stdout, c)
+}
+
+func dial() {
+	c, err := net.Dial("tcp", "127.0.0.1:4000")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer c.Close()
+	c.Write([]byte("Hello, network\n"))
+}
diff --git a/2014/playground/removeall.go b/2014/playground/removeall.go
new file mode 100644
index 0000000..d69032d
--- /dev/null
+++ b/2014/playground/removeall.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+	"log"
+	"os"
+)
+
+func main() {
+	err := os.RemoveAll("/foo")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/2014/playground/rm.go b/2014/playground/rm.go
new file mode 100644
index 0000000..ee5f946
--- /dev/null
+++ b/2014/playground/rm.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+	"log"
+	"os/exec"
+)
+
+func main() {
+	err := exec.Command("mkdir", "/tmp/foo").Run()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	err = exec.Command("rm", "-rf", "/tmp/foo").Run()
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/2014/playground/sleep.go b/2014/playground/sleep.go
new file mode 100644
index 0000000..da2cad8
--- /dev/null
+++ b/2014/playground/sleep.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+func main() {
+	fmt.Println("Good night")
+	time.Sleep(8 * time.Hour)
+	fmt.Println("Good morning")
+}
diff --git a/2014/playground/stack.go b/2014/playground/stack.go
new file mode 100644
index 0000000..4279a21
--- /dev/null
+++ b/2014/playground/stack.go
@@ -0,0 +1,9 @@
+package main
+
+func foo(a [1000]byte) {
+	foo(a)
+}
+
+func main() {
+	foo([1000]byte{})
+}