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{})
+}