M .builds/alpine.yml +2 -2
@@ 21,12 21,12 @@ tasks:
- build: |
eval $(opam env)
cd byocm/code
- time gmake -j4
+ time make -j4
- test: |
eval $(opam env)
cd byocm/code
set +e
- time env OCAMLRUNPARAM=b gmake -j4 -k test
+ time env OCAMLRUNPARAM=b make -j4 -k test
test_ret=$?
set -x
find . -name '*.tap' -exec cat '{}' \;
A => byocm_js_example.html +11 -0
@@ 0,0 1,11 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>Byocm js example</title>
+ <script type="text/javascript" src="code/build/release/byocm_js_example/byocm_js_example.js"></script>
+ </head>
+ <body onload="javascript:byocmJsRun()">
+ <div id="changeme"></div>
+ </body>
+</html>
M code/pds.conf +22 -0
@@ 26,6 26,28 @@ install = false
install = false
deps = [ "byocm_fut" ]
+[src.byocm_slow_print]
+type = "exec"
+install = false
+deps = [ "byocm_fut", "byocm_sched" ]
+
+[src.byocm_js_example]
+type = "exec"
+install = false
+deps = [ "byocm_fut", "js_of_ocaml", "js_of_ocaml.ppx" ]
+extra_makefile_lines = [ "OCAMLC_LINK_OPTS=",
+ "OCAMLOPT_LINK_OPTS=",
+ "all: $(SRC_DIR)/byocm_js_example.js",
+ "$(SRC_DIR)/byocm_js_example.js: $(BYTE_TARGET)",
+ "\tjs_of_ocaml $(BYTE_TARGET)" ]
+
+debug = { extra_makefile_lines = [ "OCAMLC_LINK_OPTS=",
+ "OCAMLOPT_LINK_OPTS=",
+ "all: $(SRC_DIR)/byocm_js_example.js",
+ "$(SRC_DIR)/byocm_js_example.js: $(BYTE_TARGET)",
+ "\tjs_of_ocaml $(BYTE_TARGET)" ]}
+
+
[tests.byocm_fut]
deps = [ "byocm_fut" ]
A => code/src/byocm_js_example/byocm_js_example.ml +33 -0
@@ 0,0 1,33 @@
+open Js_of_ocaml
+
+let sleep msecs =
+ let p = Byocm_fut.Promise.create () in
+ let f () = Byocm_fut.Promise.set p () in
+ ignore
+ (Dom_html.window##setTimeout
+ (Js.wrap_callback f)
+ msecs);
+ Byocm_fut.Promise.future p
+
+let rec run' elm = function
+ | 0 ->
+ elm##.innerHTML := Js.string "All done";
+ Byocm_fut.return ()
+ | n ->
+ let open Byocm_fut.Infix_monad in
+ elm##.innerHTML := Js.string (string_of_int n);
+ sleep 1000.0
+ >>= fun () ->
+ run' elm (n - 1)
+
+let run n =
+ let elm = Js.Opt.to_option (Dom_html.(CoerceTo.element (getElementById "changeme"))) in
+ match elm with
+ | Some elm -> run' elm n
+ | None -> Js.Unsafe.(fun_call (js_expr "alert") [| inject (Js.string "Could not find element") |])
+
+let _ =
+ Js.export_all
+ (object%js
+ method byocmJsRun = run 10
+ end)
A => code/src/byocm_slow_print/byocm_slow_print.ml +12 -0
@@ 0,0 1,12 @@
+let () =
+ let open Byocm_fut.Infix_monad in
+ let rec f = function
+ | 0 ->
+ Byocm_fut.return ()
+ | n ->
+ print_endline "Hi";
+ Byocm_sched.sleep 1.0
+ >>= fun () ->
+ f (n - 1)
+ in
+ Byocm_sched.run (fun () -> f 10)
M presentation/byocm.tex +69 -7
@@ 64,12 64,10 @@
\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 Scheduler (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}
@@ 78,9 76,8 @@
\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.
+ \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}
\end{frame}
@@ 180,7 177,7 @@
\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
+ \item \textbf{Scheduler} - Handle waiting for events and telling
kernel about new events and fulfilling promises.
\end{itemize}
\end{frame}
@@ 209,5 206,70 @@
\hlstd{}\hlkwa{end}\hspace*{\fill}\\
\end{frame}
+\begin{frame}{Scheduler}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{val\ }\hlstd{sleep\ }\hlopt{:\ }\hlstd{}\hlkwb{float\ }\hlstd{}\hlopt{{-}$>$\ }\hlstd{}\hlkwb{unit\ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{t}\hspace*{\fill}\\
+ \hlstd{}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{val\ }\hlstd{run\ }\hlopt{:\ (}\hlstd{}\hlkwb{unit\ }\hlstd{}\hlopt{{-}$>$\ }\hlstd{'a\ }\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{t}\hlopt{)\ {-}$>$\ }\hlstd{'a}\hspace*{\fill}\\
+ \mbox{}
+\end{frame}
+
+\begin{frame}{Scheduler Example}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{f\ }\hlstd{}\hlopt{()\ =\ }\hlstd{}\hlkwc{Byocm\textunderscore sched}\hlstd{}\hlopt{.}\hlstd{sleep\ }\hlnum{1.0\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{v\ }\hlstd{}\hlopt{=\ }\hlstd{}\hlkwc{Byocm\textunderscore sched}\hlstd{}\hlopt{.}\hlstd{run\ }\hlkwd{f\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlkwa{assert\ }\hlstd{}\hlopt{(}\hlstd{}\hlkwd{v\ }\hlstd{}\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.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Extra Wild: Byocm\_fut + js\_of\_ocaml}
+ \begin{itemize}
+ \item Byocm\_fut is pure Ocaml, can compile to JS just fine.
+ \item Don't need Byocm\_sched, JS engine comes with one
+ \item Let's make a little page that updates a value every second.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{sleep}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{let\ }\hlstd{}\hlkwd{sleep\ }\hlstd{msecs\ }\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{}\hlkwa{let\ }\hlstd{}\hlkwd{f\ }\hlstd{}\hlopt{()\ =\ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{}\hlkwc{Promise}\hlstd{}\hlopt{.}\hlstd{set\ }\hlkwd{p\ }\hlstd{}\hlopt{()\ }\hlstd{}\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{ignore}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{(}\hlstd{}\hlkwc{Dom\textunderscore html}\hlstd{}\hlopt{.}\hlstd{window\#\#setTimeout}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ }\hlstd{}\hlopt{(}\hlstd{}\hlkwc{Js}\hlstd{}\hlopt{.}\hlstd{wrap\textunderscore callback\ }\hlkwd{f}\hlstd{}\hlopt{)}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ \ \ \ }\hlstd{msecs}\hlopt{);}\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}{Final Countdown}
+ \noindent
+ \ttfamily
+ \hlstd{}\hlkwa{let\ rec\ }\hlstd{}\hlkwd{run}\hlstd{'\ elm\ }\hlopt{=\ }\hlstd{}\hlkwa{function}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{}\hlnum{0\ }\hlstd{}\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{elm\#\#}\hlopt{.}\hlstd{innerHTML\ }\hlopt{:=\ }\hlstd{}\hlkwc{Js}\hlstd{}\hlopt{.}\hlstd{}\hlkwb{string\ }\hlstd{}\hlstr{"All\ done"}\hlstd{}\hlopt{;}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{return\ }\hlopt{()}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ }\hlstd{}\hlopt{\textbar \ }\hlstd{n\ }\hlopt{{-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlkwa{let\ open\ }\hlstd{}\hlkwc{Byocm\textunderscore fut}\hlstd{}\hlopt{.}\hlstd{Infix\textunderscore monad\ }\hlkwa{in}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{elm\#\#}\hlopt{.}\hlstd{innerHTML\ }\hlopt{:=\ }\hlstd{}\hlkwc{Js}\hlstd{}\hlopt{.}\hlstd{}\hlkwb{string\ }\hlstd{}\hlopt{(}\hlstd{string\textunderscore of\textunderscore int\ n}\hlopt{);}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{sleep\ }\hlnum{1000.0}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlopt{$>$$>$=\ }\hlstd{}\hlkwa{fun\ }\hlstd{}\hlopt{()\ {-}$>$}\hspace*{\fill}\\
+ \hlstd{}\hlstd{\ \ \ \ }\hlstd{}\hlkwd{run}\hlstd{'\ elm\ }\hlopt{(}\hlstd{n\ }\hlopt{{-}\ }\hlstd{}\hlnum{1}\hlstd{}\hlopt{)}\hlstd{}\hspace*{\fill}\\
+\mbox{}
+
+\end{frame}
+
\end{document}
A => presentation_code/js_loop.ml +10 -0
@@ 0,0 1,10 @@
+let rec run' elm = function
+ | 0 ->
+ elm##.innerHTML := Js.string "All done";
+ Byocm_fut.return ()
+ | n ->
+ let open Byocm_fut.Infix_monad in
+ elm##.innerHTML := Js.string (string_of_int n);
+ sleep 1000.0
+ >>= fun () ->
+ run' elm (n - 1)
A => presentation_code/js_sleep.ml +8 -0
@@ 0,0 1,8 @@
+let sleep msecs =
+ let p = Byocm_fut.Promise.create () in
+ let f () = Byocm_fut.Promise.set p () in
+ ignore
+ (Dom_html.window##setTimeout
+ (Js.wrap_callback f)
+ msecs);
+ Byocm_fut.Promise.future p