M presentation/byocm.tex +124 -2
@@ 75,7 75,7 @@
\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.
+ another where you ask it if it's done.
\item Start the scheduler with some initial work.
\item Perform a bit of user-space work then give control back to the scheduler.
\end{itemize}
@@ 173,6 173,8 @@
\end{itemize}
\end{frame}
+\section{Implementation}
+
\begin{frame}{Two Components}
\begin{itemize}
\item \textbf{Promises} - Define a graph of things-that-are-not-done and
@@ 224,12 226,128 @@
\mbox{}
\end{frame}
+\begin{frame}{Futures}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{type\ }\hlstd{'a\ t\ }\hlopt{=\ \{\ }\hlstd{}\hlkwa{mutable\ }\hlstd{state\ }\hlopt{:\ }\hlstd{'a\ state\ }\hlopt{\}}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{and\ }\hlstd{'a\ state\ }\hlopt{=\ {[}\ }\hlstd{`Det\ }\hlkwa{of\ }\hlstd{'a}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{`Undet\ }\hlkwa{of\ }\hlstd{'a\ undet}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{`Alias\ }\hlkwa{of\ }\hlstd{'a\ t}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }\hlstd{}\hlopt{{]}}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{and\ }\hlstd{'a\ undet\ }\hlopt{=\ \{\ }\hlstd{}\hlkwa{mutable\ }\hlstd{watchers\ }\hlopt{:\ (}\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{}\hlkwb{unit}\hlstd{}\hlopt{)\ }\hlstd{list\ }\hlopt{\}}\hspace*{\fill}\\
+ \hlstd{}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{return\ }\hlstd{v\ }\hlopt{=\ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Det\ v\ }\hlopt{\}}\hspace*{\fill}\\
+ \hlstd{}\hspace*{\fill}\\
+ \mbox{}
+\end{frame}
+
+\begin{frame}{Bind}
+ \begin{itemize}
+ \item \hlstd{}\hlkwd{bind\ }\hlstd{}\hlopt{:\ }\hlstd{'a\ t\ }\hlopt{{-}$>$\ (}\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{'b\ t}\hlopt{)\ {-}$>$\ }\hlstd{'b\ t\ }\hspace*{\fill}
+ \item If future is determined, apply function and return its value
+ \item Otherwise, create a new promise/future
+ \item make a watcher that waits for the value of the future passed into bind
+ and sets the future created to its value
+ \item Add watcher to the input future
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Bind}
+ \noindent
+ \ttfamily
+ \hlstd{}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{bind\ }\hlstd{}\hlopt{:\ }\hlstd{'a\ t\ }\hlopt{{-}$>$\ (}\hlstd{'a\ }\hlopt{{-}$>$\ }\hlstd{'b\ t}\hlopt{)\ {-}$>$\ }\hlstd{'b\ t\ }\hlopt{=\ }\hlstd{}\hlkwa{fun\ }\hlstd{t\ f\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{match\ }\hlstd{t\ }\hlkwa{with}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Det\ v\ }\hlopt{\}\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{f\ v}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Undet\ undet\ }\hlopt{\}\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{p\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Promise}\hlstd{}\hlopt{.}\hlstd{create\ }\hlopt{()\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{fut\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Promise}\hlstd{}\hlopt{.}\hlstd{future\ }\hlkwd{p\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{w\ }\hlstd{}\hlopt{=\ }\hlstd{make\textunderscore watcher\ }\hlkwd{p\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{undet}\hlopt{.}\hlstd{watchers\ }\hlopt{$<${-}\ }\hlstd{}\hlkwd{w}\hlstd{}\hlopt{::}\hlstd{undet}\hlopt{.}\hlstd{watchers}\hlopt{;}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwd{fut}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Alias\ \textunderscore \ }\hlopt{\}\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwa{assert\ false}\hlstd{}\hspace*{\fill}\\
+ \mbox{}
+\end{frame}
+
+\begin{frame}{make watcher}
+ \begin{itemize}
+ \item Apply the value to the function
+ \item If the future the function returned is determined, then set the promise
+ to it
+ \item If not, make one future an alias to the other and smash their watchers
+ together.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{make watcher}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{make\textunderscore watcher\ }\hlstd{p\ v\ }\hlopt{=}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{u\ }\hlstd{}\hlopt{=\ (}\hlstd{f\ v}\hlopt{)\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{match\ }\hlstd{}\hlkwd{u\ }\hlstd{}\hlkwa{with}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Det\ v'\ }\hlopt{\}\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwc{Promise}\hlstd{}\hlopt{.}\hlstd{set\ p\ v'}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Undet\ undet'\ }\hlopt{\}\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwa{begin\ match\ }\hlstd{p\ }\hlkwa{with}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Undet\ undet''\ }\hlopt{\}\ }\hlstd{}\hlkwa{as\ }\hlstd{fut'\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ }\hlstd{undet'}\hlopt{.}\hlstd{watchers\ }\hlopt{$<${-}\ }\hlstd{undet'}\hlopt{.}\hlstd{watchers\ }\hlopt{@\ }\hlstd{undet''}\hlopt{.}\hlstd{watchers}\hlopt{;}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ }\hlstd{fut'}\hlopt{.}\hlstd{state\ }\hlopt{$<${-}\ }\hlstd{`Alias\ }\hlkwd{u}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=\ }\hlstd{`Det\ \textunderscore \ }\hlopt{\}}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ }\hlstd{}\hlopt{\textbar \ \{\ }\hlstd{state\ }\hlopt{=}\hlstd{\ \ }\hlopt{}\hlstd{`Alias\ \textunderscore \ }\hlopt{\}\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ \ \ }\hlstd{}\hlkwa{assert\ false}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwa{end}\hspace*{\fill}\\
+ \mbox{}
+\end{frame}
+
+\begin{frame}{sleep}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{sleep\ }\hlstd{time\ }\hlopt{=}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{trigger\textunderscore time\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Unix}\hlstd{}\hlopt{.}\hlstd{time\ }\hlopt{()\ +.\ }\hlstd{time\ }\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{p\ }\hlstd{}\hlopt{=}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlkwa{try}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwc{Float\textunderscore map}\hlstd{}\hlopt{.}\hlstd{find\ }\hlkwd{trigger\textunderscore time\ }\hlstd{}\hlopt{!}\hlstd{timers}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlkwa{with}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{Not\textunderscore found\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{p\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{}\hlkwc{Promise}\hlstd{}\hlopt{.}\hlstd{create\ }\hlopt{()\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ }\hlstd{timers\ }\hlopt{:=\ }\hlstd{}\hlkwc{Float\textunderscore map}\hlstd{}\hlopt{.}\hlstd{add\ }\hlkwd{trigger\textunderscore time\ p\ }\hlstd{}\hlopt{!}\hlstd{timers}\hlopt{;}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ \ }\hlstd{}\hlkwd{p}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{}\hlkwc{Promise}\hlstd{}\hlopt{.}\hlstd{future\ }\hlkwd{p}\hlstd{}\hspace*{\fill}\\
+ \mbox{}
+\end{frame}
+
+\begin{frame}{run}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{let\ rec\ }\hlstd{}\hlkwd{loop\ }\hlstd{finished\ }\hlopt{=}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{match\ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{state\ finished\ }\hlkwa{with}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{`Det\ v\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{v}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{`Undet\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{next\textunderscore iter\ }\hlopt{();}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{}\hlkwd{loop\ }\hlstd{finished}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{and\ }\hlstd{next\textunderscore iter\ }\hlopt{()\ =}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{now\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Unix}\hlstd{}\hlopt{.}\hlstd{time\ }\hlopt{()\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlkwa{match\ }\hlstd{}\hlkwc{Float\textunderscore map}\hlstd{}\hlopt{.}\hlstd{min\textunderscore binding\textunderscore opt\ }\hlopt{!}\hlstd{timers\ }\hlkwa{with}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{Some\ }\hlopt{(}\hlstd{n}\hlopt{,\ }\hlstd{\textunderscore }\hlopt{)\ }\hlstd{}\hlkwa{when\ }\hlstd{n\ }\hlopt{$>$\ }\hlstd{}\hlkwd{now\ }\hlstd{}\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{ignore\ }\hlopt{(}\hlstd{}\hlkwc{Unix}\hlstd{}\hlopt{.}\hlstd{select\ }\hlopt{{[}{]}\ {[}{]}\ {[}{]}\ (}\hlstd{n\ }\hlopt{{-}.\ }\hlstd{}\hlkwd{now}\hlstd{}\hlopt{))}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{\textunderscore \ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ }\hlstd{exec\textunderscore timers\ }\hlkwd{now}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{run\ }\hlstd{f\ }\hlopt{=\ }\hlstd{}\hlkwd{loop\ }\hlstd{}\hlopt{(}\hlstd{f\ }\hlopt{())}\hlstd{}\hspace*{\fill}\\
+ \mbox{}
+\end{frame}
+
\begin{frame}{Exercises For The Reader}
\begin{itemize}
\item Add some Unix APIs (send/recv/connect/accept).
\item Switch to something other than \texttt{Unix.select}.
\item Support canceling operations.
\item Applicatives.
+ \item Less side-effecty scheduler.
+ \item Support Binding operators in 4.08.0.
\end{itemize}
\end{frame}
@@ 272,7 390,11 @@
\end{frame}
\begin{frame}{Conclusion}
-
+ \begin{itemize}
+ \item Now you can sleep as much as you want concurrently.
+ \item We can write user-space concurrent code.
+ \item With a slight visual/syntax cost.
+ \end{itemize}
\end{frame}
\end{document}
A => presentation_code/bind.ml +13 -0
@@ 0,0 1,13 @@
+
+let bind : 'a t -> ('a -> 'b t) -> 'b t = fun t f ->
+ match t with
+ | { state = `Det v } ->
+ f v
+ | { state = `Undet undet } ->
+ let p = Promise.create () in
+ let fut = Promise.future p in
+ let w = make_watcher p in
+ undet.watchers <- w::undet.watchers;
+ fut
+ | { state = `Alias _ } ->
+ assert false
A => presentation_code/fut.ml +8 -0
@@ 0,0 1,8 @@
+type 'a t = { mutable state : 'a state }
+and 'a state = [ `Det of 'a
+ | `Undet of 'a undet
+ | `Alias of 'a t
+ ]
+and 'a undet = { mutable watchers : ('a -> unit) list }
+
+let return v = { state = `Det v }
A => presentation_code/run.ml +15 -0
@@ 0,0 1,15 @@
+let rec loop finished =
+ match Byocm_fut.state finished with
+ | `Det v ->
+ v
+ | `Undet ->
+ next_iter ();
+ loop finished
+and next_iter () =
+ let now = Unix.time () in
+ match Float_map.min_binding_opt !timers with
+ | Some (n, _) when n > now ->
+ ignore (Unix.select [] [] [] (n -. now))
+ | _ ->
+ exec_timers now
+let run f = loop (f ())
A => presentation_code/sleep.ml +12 -0
@@ 0,0 1,12 @@
+let sleep time =
+ let trigger_time = Unix.time () +. time in
+ let p =
+ try
+ Float_map.find trigger_time !timers
+ with
+ | Not_found ->
+ let p = Byocm_fut.Promise.create () in
+ timers := Float_map.add trigger_time p !timers;
+ p
+ in
+ Byocm_fut.Promise.future p
A => presentation_code/watcher.ml +16 -0
@@ 0,0 1,16 @@
+let make_watcher p v =
+ let u = (f v) in
+ match u with
+ | { state = `Det v' } ->
+ Promise.set p v'
+ | { state = `Undet undet' } ->
+ begin match p with
+ | { state = `Undet undet'' } as fut' ->
+ undet'.watchers <- undet'.watchers @ undet''.watchers;
+ fut'.state <- `Alias u
+ | { state = `Det _ }
+ | { state = `Alias _ } ->
+ assert false
+ end
+ | _ ->
+ assert false