M .hgignore +5 -1
@@ 7,4 7,8 @@ presentation/byocm.log
 presentation/byocm.nav
 presentation/byocm.out
 presentation/byocm.pdf
-presentation/byocm.toc
  No newline at end of file
+presentation/byocm.toc
+
+code/build/
+code/pds.mk
+code/Ocamlrules.mk.in
  No newline at end of file

          
M Makefile +8 -2
@@ 1,6 1,12 @@ 
-.PHONY: all presentation
+.PHONY: all presentation code test
 
-all: presentation
+all: presentation code
 
 presentation:
 	$(MAKE) -C presentation
+
+code:
+	$(MAKE) -C code
+
+test: code
+	$(MAKE) -C code test

          
A => code/Makefile +9 -0
@@ 0,0 1,9 @@ 
+.PHONY:
+
+all:
+	pds
+	$(MAKE) -f pds.mk all
+
+%:
+	pds
+	$(MAKE) -f pds.mk $*

          
A => code/pds.conf +26 -0
@@ 0,0 1,26 @@ 
+[global]
+selector = ["opam", "config", "var", "os"]
+
+[global.release]
+extra_compiler_opts = "-bin-annot -strict-sequence -strict-formats -safe-string -noassert"
+
+[global.debug]
+extra_compiler_opts = "-g -bin-annot -strict-sequence -strict-formats -safe-string -w '@d@f@p@u@s@40'"
+
+[global.profile]
+extra_compiler_opts = "-safe-string"
+
+[global.test-release]
+extra_compiler_opts = "-safe-string"
+
+[global.test-debug]
+extra_compiler_opts = "-safe-string"
+
+[global.test-profile]
+extra_compiler_opts = "-safe-string"
+
+[src.byocm_fut]
+install = false
+
+[tests.byocm_fut]
+deps = [ "byocm_fut" ]
  No newline at end of file

          
A => code/src/byocm_fut/byocm_fut.ml +53 -0
@@ 0,0 1,53 @@ 
+type +'a t
+
+type 'a u = { mutable state : 'a state }
+and 'a state = [ `Det of 'a
+               | `Undet of 'a undet
+               | `Alias of 'a u
+               ]
+and 'a undet = { mutable watchers : ('a -> unit) list }
+
+external t_of_u : 'a u -> 'a t = "%identity"
+external u_of_t : 'a t -> 'a u = "%identity"
+
+module Promise = struct
+  type 'a fut = 'a t
+  type 'a t = 'a fut
+  let create () = t_of_u { state = `Undet { watchers = [] } }
+  external future : 'a t -> 'a fut = "%identity"
+  let set t v =
+    let u = u_of_t t in
+    match u with
+      | { state = `Undet { watchers = watchers } } ->
+        u.state <- `Det v;
+        List.iter (fun w -> w v) watchers
+      | { state = `Det _ }
+      | { state = `Alias _ } ->
+        assert false
+end
+
+let rec collapse_alias = function
+  | { state = `Alias u } -> collapse_alias u
+  | u -> u
+
+let return v = t_of_u { state = `Det v }
+let bind t f =
+  let u = collapse_alias (u_of_t t) in
+  match u with
+    | { state = `Det v } ->
+      f v
+    | { state = `Undet { watchers = watchers } } ->
+      failwith "nyi"
+    | { state = `Alias _ } ->
+      assert false
+
+let state t =
+  let u = collapse_alias (u_of_t t) in
+  match u with
+    | { state = `Det v } -> `Det v
+    | { state = `Undet _ } -> `Undet
+    | { state = `Alias _ } -> assert false
+
+module Infix_monad = struct
+  let (>>=) = bind
+end

          
A => code/src/byocm_fut/byocm_fut.mli +17 -0
@@ 0,0 1,17 @@ 
+type +'a t
+
+module Promise : sig
+  type 'a fut = 'a t
+  type 'a t
+  val create : unit -> 'a t
+  val future : 'a t -> 'a fut
+  val set : 'a t -> 'a -> unit
+end
+
+val return : 'a -> 'a t
+val bind : 'a t -> ('a -> 'b t) -> 'b t
+val state : 'a t -> [ `Det of 'a | `Undet ]
+
+module Infix_monad : sig
+  val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
+end

          
A => code/tests/byocm_fut/test.ml +31 -0
@@ 0,0 1,31 @@ 
+let test1 () =
+  let fut = Byocm_fut.return "hello" in
+  let res = Byocm_fut.bind fut (fun s -> Byocm_fut.return (s ^ " world")) in
+  assert (Byocm_fut.state res = `Det "hello world")
+
+let test2 () =
+  let open Byocm_fut.Infix_monad in
+  let res =
+    Byocm_fut.return "hello"
+    >>= fun s ->
+    Byocm_fut.return (s ^ " world")
+  in
+  assert (Byocm_fut.state res = `Det "hello world")
+
+let test3 () =
+  let open Byocm_fut.Infix_monad in
+  let p = Byocm_fut.Promise.create () in
+  let fut = Byocm_fut.Promise.future p in
+  let res =
+    fut
+    >>= fun s ->
+    Byocm_fut.return (s ^ " world")
+  in
+  assert (Byocm_fut.state res = `Undet);
+  Byocm_fut.Promise.set p "hello";
+  assert (Byocm_fut.state res = `Det "hello world")
+
+let () =
+  test1 ();
+  test2 ();
+  test3 ()

          
M presentation/byocm.tex +197 -5
@@ 1,5 1,27 @@ 
 \documentclass{beamer}
 \usepackage{hyperref}
+\usepackage{color}
+\usepackage{alltt}
+\usepackage[T1]{fontenc}
+\usepackage[latin1]{inputenc}
+
+% highlight theme: Kwrite Editor
+\newcommand{\hlstd}[1]{\textcolor[rgb]{0,0,0}{#1}}
+\newcommand{\hlnum}[1]{\textcolor[rgb]{0.69,0.49,0}{#1}}
+\newcommand{\hlesc}[1]{\textcolor[rgb]{1,0,1}{#1}}
+\newcommand{\hlstr}[1]{\textcolor[rgb]{0.75,0.01,0.01}{#1}}
+\newcommand{\hlpps}[1]{\textcolor[rgb]{0.51,0.51,0}{#1}}
+\newcommand{\hlslc}[1]{\textcolor[rgb]{0.51,0.51,0.51}{\it{#1}}}
+\newcommand{\hlcom}[1]{\textcolor[rgb]{0.51,0.51,0.51}{\it{#1}}}
+\newcommand{\hlppc}[1]{\textcolor[rgb]{0,0.51,0}{#1}}
+\newcommand{\hlopt}[1]{\textcolor[rgb]{0,0,0}{#1}}
+\newcommand{\hlipl}[1]{\textcolor[rgb]{0,0.34,0.68}{#1}}
+\newcommand{\hllin}[1]{\textcolor[rgb]{0.33,0.33,0.33}{#1}}
+\newcommand{\hlkwa}[1]{\textcolor[rgb]{0,0,0}{\bf{#1}}}
+\newcommand{\hlkwb}[1]{\textcolor[rgb]{0,0.34,0.68}{#1}}
+\newcommand{\hlkwc}[1]{\textcolor[rgb]{0,0,0}{\bf{#1}}}
+\newcommand{\hlkwd}[1]{\textcolor[rgb]{0,0,0.51}{#1}}
+\definecolor{bgcolor}{rgb}{0.88,0.92,0.93}
 
 \usetheme{metropolis}
 \title{Build Your Own Concurrency Monad}

          
@@ 9,13 31,183 @@ 
 \begin{document}
 \maketitle
 
-\begin{frame}{This}
-  \begin{enumerate}
-  \item Foo bar
-  \end{enumerate}
+\section{Background}
+
+\begin{frame}{The Problem}
+  We want to maximize the number of I/O bound operations a single machine can
+  perform with a programming model people can understand.
+\end{frame}
+
+\begin{frame}{Why do we want a Concurrency Monad?}
+  \begin{itemize}
+  \item C10K problem.
+  \item Code was historically written to be synchronous.
+  \item OS threads were a transition step but didn't scale.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}{OS Threads (Synchronous)}
+  \begin{itemize}
+  \item Makes concurrency the problem of the OS.
+  \item Seems like a nice abstraction: I don't really need to change my
+    synchronous code that much.
+  \item OS threads are very heavy, they are really meant to utilize all cores.
+    Good for CPU-bound tasks.
+  \item Expensive to switch between, user space \( \rightarrow \) kernel space \(
+    \rightarrow \) user space.
+  \item With lots of concurrency, we spend all our time context switching.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}{In User Space (Asynchronous)}
+  \begin{itemize}
+  \item Handle multiple connections in a single thread.
+  \item Use OS APIs to get a list of events, process them, ask again (fewer
+    context switches).
+  \item Event Loop.
+  \item Basic model the same across OS's but specific API calls change.
+  \item Go, Erlang, Mozart/Oz do this for you.  Async/Await in Rust, C\#, and
+    JavaScript do a similar thing.
+  \item In Ocaml we can do this as a library, no need to spend 3 years in
+    language standards meetings!
+  \end{itemize}
+\end{frame}
+
+\begin{frame}{Anatomy of Concurrency In User Space}
+  \begin{itemize}
+  \item The game is to turn kernel calls that can wait an unbounded amount of
+    time into two calls: One where you tell the kernel to do something and
+    another when it tells you when it's done.
+  \item Start the event loop with some initial work.
+  \item Perform a bit of user-space work then give control back to the event
+    loop.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}{Anatomy of Concurrency In User Space}
+  \center{\includegraphics[scale=0.4]{images/event_loop.png}}
+\end{frame}
+
+\begin{frame}{Comparing Synchronous \& Asynchronous}
+  \begin{columns}[T]
+    \begin{column}{0.5\textwidth}
+      \begin{block}{\underline{Semantically}}
+        \begin{itemize}
+        \item Function: \emph{slow\_echo}
+        \item Read from socket.
+        \item Wait 1 second.
+        \item Write text back to socket.
+        \end{itemize}
+      \end{block}
+    \end{column}
+    \begin{column}{0.5\textwidth}
+      \begin{block}{\underline{Synchronous}}
+        \center{\includegraphics[scale=0.3]{images/slow_echo_sync.png}}
+      \end{block}
+    \end{column}
+  \end{columns}
 \end{frame}
 
-\section{Foobar}
+\begin{frame}{Comparing Synchronous \& Asynchronous}
+  \begin{columns}[T]
+    \begin{column}{0.5\textwidth}
+      \begin{block}{\underline{Synchronous}}
+        \center{\includegraphics[scale=0.3]{images/slow_echo_sync.png}}
+      \end{block}
+    \end{column}
+    \begin{column}{0.5\textwidth}
+      \begin{block}{\underline{Asynchronous}}
+        \center{\includegraphics[scale=0.3]{images/slow_echo_event_loop.png}}
+      \end{block}
+    \end{column}
+  \end{columns}
+\end{frame}
+
+\begin{frame}{Comparing Synchronous \& Asynchronous}
+  \begin{block}{\underline{Synchronous}}
+    \noindent
+    \ttfamily
+    \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{slow\textunderscore echo\ }\hlstd{fd\ }\hlopt{=}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{bytes\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Bytes}\hlstd{}\hlopt{.}\hlstd{create\ }\hlnum{1024\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{n\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Unix}\hlstd{}\hlopt{.}\hlstd{recv\ fd\ }\hlkwd{bytes\ }\hlstd{}\hlnum{0\ 1024\ }\hlstd{}\hlopt{{[}{]}\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Unix}\hlstd{}\hlopt{.}\hlstd{sleep\ }\hlnum{1}\hlstd{}\hlopt{;}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Unix}\hlstd{}\hlopt{.}\hlstd{send\ fd\ }\hlkwd{bytes\ }\hlstd{}\hlnum{0\ }\hlstd{}\hlkwd{n\ }\hlstd{}\hlopt{{[}{]}}\hlstd{}\hspace*{\fill}\\
+    \mbox{}
+  \end{block}
+\end{frame}
+
+\begin{frame}{Comparing Synchronous \& Asynchronous}
+  \begin{block}{\underline{Asynchronous Bind}}
+    \noindent
+    \ttfamily
+    \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{slow\textunderscore echo\ }\hlstd{fd\ }\hlopt{=}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{bytes\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Bytes}\hlstd{}\hlopt{.}\hlstd{create\ }\hlnum{1024\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{bind}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{(}\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{recv\ fd\ }\hlkwd{bytes\ }\hlstd{}\hlnum{0\ 1024\ }\hlstd{}\hlopt{{[}{]})}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{(}\hlstd{}\hlkwa{fun\ }\hlstd{n\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ \ \ \ \ \ }\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{bind}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ }\hlstd{}\hlopt{(}\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{sleep\ }\hlnum{1}\hlstd{}\hlopt{)}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ }\hlstd{}\hlopt{(}\hlstd{}\hlkwa{fun\ }\hlstd{}\hlopt{()\ {-}$>$}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ \ \ }\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{send\ fd\ }\hlkwd{bytes\ }\hlstd{}\hlnum{0\ }\hlstd{n\ }\hlopt{{[}{]}))}\hlstd{}\hspace*{\fill}\\
+    \mbox{}
+  \end{block}
+\end{frame}
+
+\begin{frame}{Comparing Synchronous \& Asynchronous}
+  \begin{block}{\underline{Asynchronous}}
+    \noindent
+    \ttfamily
+    \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{slow\textunderscore echo\ }\hlstd{fd\ }\hlopt{=}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{bytes\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Bytes}\hlstd{}\hlopt{.}\hlstd{create\ }\hlnum{1024\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{recv\ fd\ }\hlkwd{bytes\ }\hlstd{}\hlnum{0\ 1024}\hlstd{}\hlopt{)\ {[}{]}}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlopt{$>$$>$=\ }\hlstd{}\hlkwa{fun\ }\hlstd{n\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{sleep\ }\hlnum{1}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlopt{$>$$>$=\ }\hlstd{}\hlkwa{fun\ }\hlstd{}\hlopt{()\ {-}$>$}\hspace*{\fill}\\
+    \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Async}\hlstd{}\hlopt{.}\hlstd{send\ fd\ }\hlkwd{bytes\ }\hlstd{}\hlnum{0\ }\hlstd{n\ }\hlopt{{[}{]}}\hlstd{}\hspace*{\fill}\\
+    \mbox{}
+  \end{block}
+\end{frame}
+
+\begin{frame}{It's all about the concurrency}
+  \begin{itemize}
+  \item The above example is just sequential code.
+  \item What's actually important is we can do \emph{a lot} of those at the same
+    time.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}{Two Components}
+  \begin{itemize}
+  \item \textbf{Promises} - Define a graph of things-that-are-not-done and
+    things-that-want-to-know-when-they-are-done.
+  \item \textbf{Event loop/Scheduler} - Handle waiting for events and telling
+    kernel about new events and fulfilling promises.
+  \end{itemize}
+\end{frame}
+
+\begin{frame}{Promise API}
+  \noindent
+  \ttfamily
+  \hlstd{}\hlkwa{type\ }\hlstd{}\hlopt{+}\hlstd{'a\ t}\hspace*{\fill}\\
+  \hlstd{}\hspace*{\fill}\\
+  \hlstd{}\hlkwa{val\ }\hlstd{return\ }\hlopt{:\ }\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{'a\ t}\hspace*{\fill}\\
+  \hlstd{}\hlkwa{val\ }\hlstd{bind\ }\hlopt{:\ }\hlstd{'a\ t\ }\hlopt{{-}$>$\ (}\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{'b\ t}\hlopt{)\ {-}$>$\ }\hlstd{'b\ t}\hspace*{\fill}\\
+  \hlstd{}\hspace*{\fill}\\
+  \hlstd{}\hlkwa{module\ }\hlstd{Infix\textunderscore monad\ }\hlopt{:\ }\hlstd{}\hlkwa{sig}\hspace*{\fill}\\
+  \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{val\ }\hlstd{}\hlopt{($>$$>$=)\ :\ }\hlstd{'a\ t\ }\hlopt{{-}$>$\ (}\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{'b\ t}\hlopt{)\ {-}$>$\ }\hlstd{'b\ t}\hspace*{\fill}\\
+  \hlstd{}\hlkwa{end}\hlstd{}\hspace*{\fill}\\
+  \mbox{}
+\end{frame}
+
+\begin{frame}{Promise API}
+  \hlstd{}\hlkwa{module\ }\hlstd{Promise\ }\hlopt{:\ }\hlstd{}\hlkwa{sig}\hspace*{\fill}\\
+  \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{type\ }\hlstd{'a\ fut\ }\hlopt{=\ }\hlstd{'a\ t}\hspace*{\fill}\\
+  \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{type\ }\hlstd{'a\ t}\hspace*{\fill}\\
+  \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{val\ }\hlstd{create\ }\hlopt{:\ }\hlstd{}\hlkwb{unit\ }\hlstd{}\hlopt{{-}$>$\ }\hlstd{'a\ t}\hspace*{\fill}\\
+  \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{val\ }\hlstd{future\ }\hlopt{:\ }\hlstd{'a\ t\ }\hlopt{{-}$>$\ }\hlstd{'a\ fut}\hspace*{\fill}\\
+  \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{val\ }\hlstd{set\ }\hlopt{:\ }\hlstd{'a\ t\ }\hlopt{{-}$>$\ }\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{}\hlkwb{unit\ }\hlstd{fut}\hspace*{\fill}\\
+  \hlstd{}\hlkwa{end}\hspace*{\fill}\\
+\end{frame}
 
 \end{document}
 

          
A => presentation/images/event_loop.png +0 -0

        
A => presentation/images/slow_echo_event_loop.png +0 -0

        
A => presentation/images/slow_echo_sync.png +0 -0

        
A => presentation_code/slow_echo_event_loop.ml +7 -0
@@ 0,0 1,7 @@ 
+let slow_echo fd =
+  let bytes = Bytes.create 1024 in
+  Async.recv fd bytes 0 1024) []
+  >>= fun n ->
+  Async.sleep 1
+  >>= fun () ->
+  Async.send fd bytes 0 n []

          
A => presentation_code/slow_echo_event_loop_bind.ml +9 -0
@@ 0,0 1,9 @@ 
+let slow_echo fd =
+  let bytes = Bytes.create 1024 in
+  Async.bind
+    (Async.recv fd bytes 0 1024 [])
+    (fun n ->
+       Async.bind
+         (Async.sleep 1)
+         (fun () ->
+            Async.send fd bytes 0 n []))

          
A => presentation_code/slow_echo_sync.ml +5 -0
@@ 0,0 1,5 @@ 
+let slow_echo fd =
+  let bytes = Bytes.create 1024 in
+  let n = Unix.recv fd bytes 0 1024 [] in
+  Unix.sleep 1;
+  Unix.send fd bytes 0 n []