Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
77dcee1
allow multiple schduler to run in parallel
raphael-proust Jun 4, 2025
dbe6815
shorter basic multidomain test output
raphael-proust Jun 6, 2025
cfc7243
addiiotnal multidomain test
raphael-proust Jun 6, 2025
288ea06
multidomain tests moving promises and resolvers across domains
raphael-proust Jun 10, 2025
f88057a
better domainworker test
raphael-proust Jun 10, 2025
802a58a
tests: terser output, relevant exit codes
raphael-proust Jun 10, 2025
76add85
bump dependency to 5.3
raphael-proust Jun 10, 2025
d8d2249
don't auto-init domains on main.run
raphael-proust Jun 10, 2025
fb102c5
a bit mroe doc
raphael-proust Jun 10, 2025
48b9b51
make storage a domain-local thing, allow cross domain cancel
raphael-proust Jun 10, 2025
836cce7
replace `run_in_main` with `run_in_domain` (and misc imporvements)
raphael-proust Jun 10, 2025
b53a4be
don't double register implicitly
raphael-proust Jun 23, 2025
77384ef
some fixes and some deactivate tests
raphael-proust Jun 24, 2025
4478ace
restore some unix tests
raphael-proust Jun 24, 2025
ba710d1
more refs become atomics
raphael-proust Jun 24, 2025
e266af5
remove test-only primitive
raphael-proust Jun 24, 2025
cd0e502
add the `lwt_direct` package, for direct-style control flow
c-cube Jul 8, 2025
7145d61
Apply suggestions from code review
c-cube Jul 10, 2025
8cab71e
some docs
c-cube Jul 10, 2025
0978471
doc
c-cube Jul 10, 2025
5b746aa
lwt: expose some storage primitives in `Private`
c-cube Jul 11, 2025
33527db
lwt_direct: expose basic storage primitives
c-cube Jul 11, 2025
b869daa
add tests for Lwt_direct
c-cube Jul 11, 2025
495852e
more tests for Lwt_direct
c-cube Jul 11, 2025
d776f41
CI: see if --best-effort helps
c-cube Jul 11, 2025
dc85027
CI
c-cube Jul 11, 2025
9bee283
only test lwt_direct if OCaml >= 5.0
c-cube Jul 11, 2025
c5aa6c5
fix test on 4.xx
c-cube Jul 11, 2025
cdf51ce
dune
c-cube Jul 11, 2025
6e408a8
some improvements as discussed in PR's review
raphael-proust Jul 11, 2025
020ae8b
purely cosmetics tweaks
raphael-proust Jul 11, 2025
92c1d3e
opam stuff
c-cube Jul 12, 2025
61f338d
tighten a bit Lwt_direct, use Lwt.async_exception_hook
c-cube Jul 12, 2025
05d3233
test: increase coverage
c-cube Jul 12, 2025
d696674
add TODO in comment
raphael-proust Jul 15, 2025
8587e96
CHAGNELOG
raphael-proust Jul 15, 2025
e133852
mark versions in dune file
raphael-proust Jul 15, 2025
09fba3a
rename `run` to `spawn`
c-cube Jul 17, 2025
7080eb2
Merge branch 'simon/lwt-direct' into lwt-6
raphael-proust Jul 18, 2025
fda2814
ocaml.4.14 compat (via domain_shims)
raphael-proust Jul 18, 2025
7dd7151
Merge branch 'domains' into lwt-6
raphael-proust Jul 18, 2025
392336e
make lwt-direct compatible with multi-domain
raphael-proust Jul 18, 2025
1d89906
also run CI on 4.14
raphael-proust Jul 18, 2025
65f8ebd
trying to fix the notification system
raphael-proust Jul 21, 2025
51236bd
fix jobs' domain_id not being initialised
raphael-proust Jul 22, 2025
2027bc1
restore windows (untested)
raphael-proust Jul 22, 2025
f56fcce
more fix windows
raphael-proust Jul 22, 2025
aa442e2
clean-up unneeded flag
raphael-proust Jul 22, 2025
3dfa600
Merge pull request #1064 from ocsigen/lwt-6-draft
raphael-proust Jul 22, 2025
7fe46b8
prepare for 6alpha01
raphael-proust Jul 22, 2025
ab07965
additional test for multidomain: pipe communications
raphael-proust Sep 5, 2025
9bd9f9d
Merge branch 'master' into lwt-6
raphael-proust Sep 5, 2025
3142c9e
remove coverage/bisect
raphael-proust Sep 5, 2025
6568544
test/direct: use `test` stanza so executable is associated to pkg
raphael-proust Sep 5, 2025
b06ed14
adapt workflow to mish mash of compatibility to ocaml versions
raphael-proust Sep 5, 2025
94a397f
restore `Lwt_engine.fake_event`
raphael-proust Sep 5, 2025
8722710
direct: rewrite some parts of the documentation
raphael-proust Sep 5, 2025
1cc2803
multidomain pipe test: deactivate on windows
raphael-proust Sep 8, 2025
a5c0881
better encapsulation of multidomain-sync internals
raphael-proust Sep 8, 2025
9a538c5
notifications now work with an abstract id
raphael-proust Sep 11, 2025
e6efdd7
better domain-specificity in preemptive
raphael-proust Sep 12, 2025
205581f
fix preemptive test: but needs new primitive in preemptive
raphael-proust Sep 15, 2025
5261258
make_notification's domain.id parameter now optional
raphael-proust Sep 16, 2025
f4aa151
address some TODOs and then make new ones
raphael-proust Sep 16, 2025
75ba144
Lwt_preemptive better name for worker termination
raphael-proust Sep 19, 2025
2bb5c46
Merge pull request #1077 from ocsigen/lwt-6-default-domain
raphael-proust Sep 19, 2025
aa2a346
remove Async_switch, fix documentation regarding async_method
raphael-proust Sep 19, 2025
47bcbfd
set version to 6beta0
raphael-proust Sep 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 28 additions & 25 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ jobs:
os:
- ubuntu-latest
ocaml-compiler:
- "4.08"
- "4.09"
- "4.10"
- "4.11"
- "4.12"
- "4.13"
- "4.14"
- "5.0"
- "5.1"
Expand All @@ -43,24 +37,42 @@ jobs:
runs-on: ${{ matrix.os }}

steps:
- name: set ppx-related variables
id: configppx
- name: set version-dependent variables
id: configpkgs
shell: bash
run: |
opampkgs="./lwt.opam ./lwt_react.opam ./lwt_retry.opam ./lwt_ppx.opam"
dunepkgs="lwt,lwt_react,lwt_retry,lwt_ppx"
case ${{ matrix.ocaml-compiler }} in
"4.08"|"4.09"|"4.10"|"4.11"|"4.12"|"4.13"|"4.14"|"5.0")
echo "letppx=false"
echo "letppx=false" >> "$GITHUB_OUTPUT"
"4.14"|"5.0")
:
;;
"5.1"|"5.2"|"5.3")
echo "letppx=true"
echo "letppx=true" >> "$GITHUB_OUTPUT"
opampkgs="${opampkgs} ./lwt_ppx__ppx_let_tests.opam"
dunepkgs="${dunepkgs},lwt_ppx__ppx_let_tests"
;;
*)
printf "unrecognised version %s\n" "${{ matrix.ocaml-compiler }}";
exit 1
;;
esac
case ${{ matrix.ocaml-compiler }} in
"4.14")
:
;;
"5.0"|"5.1"|"5.2"|"5.3")
opampkgs="${opampkgs} ./lwt_direct.opam"
dunepkgs="${dunepkgs},lwt_direct"
;;
*)
printf "unrecognised version %s\n" "${{ matrix.ocaml-compiler }}";
exit 1
;;
esac
echo "opampkgs=${opampkgs}"
echo "opampkgs=${opampkgs}" >> "$GITHUB_OUTPUT"
echo "dunepkgs=${dunepkgs}"
echo "dunepkgs=${dunepkgs}" >> "$GITHUB_OUTPUT"

- name: Checkout tree
uses: actions/checkout@v5
Expand All @@ -73,20 +85,11 @@ jobs:
- run: opam install conf-libev
if: ${{ matrix.libev == true }}

- run: opam install ./lwt.opam ./lwt_react.opam ./lwt_retry.opam ./lwt_ppx.opam --deps-only --with-test

- run: opam install ./lwt_ppx__ppx_let_tests.opam --deps-only --with-test
if: ${{ fromJSON(steps.configppx.outputs.letppx) }}

- run: opam exec -- dune build --only-packages lwt,lwt_react,lwt_retry

- run: opam exec -- dune build --only-packages lwt,lwt_ppx__ppx_let_tests
if: ${{ fromJSON(steps.configppx.outputs.letppx) }}
- run: opam install --deps-only --with-test ${{ steps.configpkgs.outputs.opampkgs }}

- run: opam exec -- dune runtest --only-packages lwt,lwt_react,lwt_retry,lwt_ppx
- run: opam exec -- dune build --only-packages ${{ steps.configpkgs.outputs.dunepkgs }}

- run: opam exec -- dune runtest --only-packages lwt,lwt_ppx__ppx_let_tests
if: ${{ fromJSON(steps.configppx.outputs.letppx) }}
- run: opam exec -- dune runtest --only-packages ${{ steps.configpkgs.outputs.dunepkgs }}

lint-opam:
runs-on: ubuntu-latest
Expand Down
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ src/unix/discover_arguments
# OPAM 2.0 local switches.
_opam

# Coverage analysis.
bisect*.out
_coverage/

# For local work, tests, etc.
scratch/

Expand Down
12 changes: 11 additions & 1 deletion CHANGES
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
===== 5.10.0 =====
===== 6.0.0+dev =====

====== Additions ======

* Lwt_direct using Lwt in direct-style. (Simon Cruanes, #1060)

* Support multiple scheduler running in parallel in separate domains.

* Exception filter defaults to letting systems exceptions through.

===== 5.10.0+dev =====

====== Misc

Expand Down
8 changes: 0 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ clean :
dune clean
rm -fr docs/api
rm -f src/unix/discover_arguments
rm -rf _coverage/

EXPECTED_FILES := \
--expect src/core/ \
Expand All @@ -65,10 +64,3 @@ EXPECTED_FILES := \
--do-not-expect src/unix/lwt_gc.ml \
--do-not-expect src/unix/lwt_throttle.ml \
--do-not-expect src/unix/unix_c/

.PHONY: coverage
coverage :
dune runtest --instrument-with bisect_ppx --force
bisect-ppx-report html $(EXPECTED_FILES)
bisect-ppx-report summary
@echo See _coverage/index.html
15 changes: 13 additions & 2 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,19 @@
(lwt (>= 3.0))
(react (>= 1.0))))

(package
(name lwt_direct)
(version 6.0.0~beta00)
(synopsis "Direct-style control-flow and `await` for Lwt")
(authors "Simon Cruanes")
(depends
(ocaml (>= 5.0))
base-unix
(lwt (>= 6))))

(package
(name lwt)
(version 5.9.2+dev)
(version 6.0.0~beta00)
(synopsis "Promises and event-driven I/O")
(description "A promise is a value that may become determined in the future.

Expand All @@ -66,7 +76,8 @@ a single thread by default. This reduces the need for locks or other
synchronization primitives. Code can be run in parallel on an opt-in basis.
")
(depends
(ocaml (>= 4.08))
(ocaml (>= 4.14))
domain_shims
(cppo (and :build (>= 1.1)))
(ocamlfind (and :dev (>= 1.7.3-1)))
(odoc (and :with-doc (>= 2.3)))
Expand Down
5 changes: 3 additions & 2 deletions lwt.opam
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "5.9.2+dev"
version: "6.0.0~beta00"
synopsis: "Promises and event-driven I/O"
description: """
A promise is a value that may become determined in the future.
Expand All @@ -22,7 +22,8 @@ doc: "https://ocsigen.org/lwt"
bug-reports: "https://github.com/ocsigen/lwt/issues"
depends: [
"dune" {>= "3.15"}
"ocaml" {>= "4.08"}
"ocaml" {>= "4.14"}
"domain_shims"
"cppo" {build & >= "1.1"}
"ocamlfind" {dev & >= "1.7.3-1"}
"odoc" {with-doc & >= "2.3"}
Expand Down
34 changes: 34 additions & 0 deletions lwt_direct.opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "6.0.0~beta00"
synopsis: "Direct-style control-flow and `await` for Lwt"
maintainer: [
"Raphaël Proust <[email protected]>" "Anton Bachin <[email protected]>"
]
authors: ["Simon Cruanes"]
license: "MIT"
homepage: "https://github.com/ocsigen/lwt"
doc: "https://ocsigen.org/lwt"
bug-reports: "https://github.com/ocsigen/lwt/issues"
depends: [
"dune" {>= "3.15"}
"ocaml" {>= "5.0"}
"base-unix"
"lwt" {>= "6"}
"odoc" {with-doc}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/ocsigen/lwt.git"
57 changes: 57 additions & 0 deletions src/core/domain_map.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module Domain_map : Map.S with type key = Domain.id = Map.Make(struct
type t = Domain.id
let compare d1 d2 = Int.compare (d1 : Domain.id :> int) (d2 : Domain.id :> int)
end)

(* Protected domain map reference with per-reference mutex *)
type 'a protected_map = {
mutex : Mutex.t;
mutable map : 'a Domain_map.t;
}

let create_protected_map () = {
mutex = Mutex.create ();
map = Domain_map.empty;
}

let with_lock protected_map f =
Mutex.lock protected_map.mutex;
Fun.protect f ~finally:(fun () -> Mutex.unlock protected_map.mutex)

let update_map protected_map f =
with_lock protected_map (fun () ->
let old_map = protected_map.map in
let new_map = f old_map in
protected_map.map <- new_map)

let add protected_map key value =
update_map protected_map (Domain_map.add key value)

let remove protected_map key =
update_map protected_map (Domain_map.remove key)

let update protected_map key f =
update_map protected_map (Domain_map.update key f)

let find protected_map key =
with_lock protected_map (fun () -> Domain_map.find_opt key protected_map.map)

let extract protected_map key =
with_lock protected_map (fun () ->
match Domain_map.find_opt key protected_map.map with
| None -> None
| Some v ->
protected_map.map <- Domain_map.remove key protected_map.map;
Some v)

let size protected_map =
with_lock protected_map (fun () -> Domain_map.cardinal protected_map.map)

let init protected_map key init_value =
with_lock protected_map (fun () ->
match Domain_map.find_opt key protected_map.map with
| Some existing -> existing
| None ->
let new_value = init_value () in
protected_map.map <- Domain_map.add key new_value protected_map.map;
new_value)
38 changes: 38 additions & 0 deletions src/core/domain_map.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
(** Domain-indexed maps with thread-safe operations

Only intended to use internally, not for general release.

Note that these function use a lock. A single lock.
- Probably not optimal
- Deadlock if you call one of those functions inside another (e.g., use
`init` rather than `find`+`update`
*)

(** Thread-safe wrapper for domain maps *)
type 'a protected_map

(** Create a new protected map with an empty map inside and a dedicated mutex,
the map is keyed on domain ids, and operations are synchronised via a mutex.
*)
val create_protected_map : unit -> 'a protected_map

(** Add a key-value binding to the map *)
val add : 'a protected_map -> Domain.id -> 'a -> unit

(** Remove a key from the map *)
val remove : 'a protected_map -> Domain.id -> unit

(** Update a binding using the underlying map's update function *)
val update : 'a protected_map -> Domain.id -> ('a option -> 'a option) -> unit

(** Find a value by key, returning None if not found *)
val find : 'a protected_map -> Domain.id -> 'a option

(** Find + remove but hit the mutex only once *)
val extract : 'a protected_map -> Domain.id -> 'a option

(** Get the number of bindings in the map *)
val size : 'a protected_map -> int

(** Initialize a key with a value if it doesn't exist, return existing or new value *)
val init : 'a protected_map -> Domain.id -> (unit -> 'a) -> 'a
3 changes: 1 addition & 2 deletions src/core/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
(public_name lwt)
(synopsis "Monadic promises and concurrent I/O")
(wrapped false)
(instrumentation
(backend bisect_ppx)))
(libraries domain_shims))

(documentation
(package lwt))
Loading
Loading