Skip to content

Commit 8eeef6f

Browse files
committed
Add an example running Lwt and FIFOs in a single program
1 parent 2ef88a0 commit 8eeef6f

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

lib/picos_lwt/dune

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,19 @@
1111
(documentation
1212
(package picos_lwt)
1313
(mld_files index))
14+
15+
(mdx
16+
(package picos_meta)
17+
(enabled_if
18+
(and
19+
(>= %{ocaml_version} 5.0.0)
20+
(<> %{os_type} Win32)))
21+
(libraries
22+
lwt.unix
23+
picos_io.select
24+
picos_lwt
25+
picos_lwt.unix
26+
picos_mux.fifo
27+
picos_std.finally
28+
picos_std.sync)
29+
(files index.mld))

lib/picos_lwt/index.mld

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,102 @@
33
This package provides an alternative direct style interface to programming with
44
Lwt via {!Picos}.
55

6+
{1 Libraries}
7+
68
{!modules:
79
Picos_lwt
810
Picos_lwt_unix
911
}
12+
13+
{1 Examples}
14+
15+
Perhaps one of the main reasons someone might want to use a {!Picos} based
16+
direct style interface to programming with Lwt is for the purpose of working
17+
with an existing codebase and gradually porting the codebase to be effects based
18+
and to use an effects based scheduler. So, as an example, let's construct a
19+
program that runs both Lwt and, in another domain, an effects based scheduler.
20+
21+
As an aside, {!Picos} is specifically designed to allow an application to run
22+
multiple schedulers and for code running on those schedulers to be able to
23+
communicate and synchronize. Specifically, {!Picos} is an interface to
24+
communicating with schedulers. A concurrent abstraction implemented in terms of
25+
the {!Picos} interface automatically works with any {!Picos} compatible
26+
scheduler. Furthermore, a correctly implemented scheduler allows certain
27+
operations, such as operations that cause fibers running on the scheduler to be
28+
resumed, to work across schedulers.
29+
30+
For the example, we first open a couple of libraries:
31+
32+
{[
33+
# open Picos_std_finally (* let@, finally, lastly *)
34+
# open Picos_std_sync (* Stream, Ivar *)
35+
]}
36+
37+
{{!Picos_mux_fifo} The FIFO scheduler} we will use normally automatically checks
38+
that the {{!Picos_io_select} IO event loop library} it uses for timeouts has
39+
been configured. However, as we will be spawning a new domain for the
40+
scheduler, we need to make sure to configure the IO library from the main thread
41+
of the application:
42+
43+
{[
44+
Picos_io_select.check_configured ()
45+
]}
46+
47+
Below is our example program:
48+
49+
{[
50+
let main () =
51+
let stream = Stream.create () in
52+
53+
let@ _ =
54+
finally Domain.join @@ fun () ->
55+
let cursor = Stream.tap stream in
56+
Domain.spawn @@ fun () ->
57+
Picos_mux_fifo.run @@ fun () ->
58+
let rec loop cursor =
59+
let ((who, out), cursor) =
60+
Stream.read cursor
61+
in
62+
Printf.sprintf "Hello, %s!" who
63+
|> Ivar.fill out;
64+
loop cursor
65+
in
66+
try loop cursor with Exit -> ()
67+
in
68+
69+
let@ _ = lastly @@ fun () ->
70+
Stream.poison stream Exit
71+
in
72+
73+
["Mii"; "Uuu"]
74+
|> List.iter (fun who ->
75+
let reply = Ivar.create () in
76+
Stream.push stream (who, reply);
77+
Ivar.read reply
78+
|> Lwt_io.printl
79+
|> Picos_lwt.await);
80+
81+
Picos_lwt.await Lwt_io.(flush stdout)
82+
]}
83+
84+
The above program first creates a stream for communication. Then it spawns a
85+
domain for running the FIFO scheduler making sure that the domain will be joined
86+
and that a cursor to the stream is obtained before the rest of the program
87+
pushes messages to the stream. The loop running on the FIFO scheduler reads
88+
messages from the stream and responds to them until the stream is poisoned. The
89+
rest of the program runs on Lwt on the main thread. It first makes sure to
90+
poison the stream at the end. Then it runs a loop that sends a couple of
91+
messages to the stream, reads the responses, and prints them using Lwt.
92+
93+
Finally we run the program with Lwt:
94+
95+
{[
96+
# Picos_lwt_unix.run_main main
97+
Hello, Mii!
98+
Hello, Uuu!
99+
- : unit = ()
100+
]}
101+
102+
Importantly, the above program shows that one can use communication and
103+
synchronization primitives like {{!Picos_std_sync.Stream} [Stream]} and
104+
{{!Picos_std_sync.Ivar} [Ivar]} across schedulers.

0 commit comments

Comments
 (0)