Skip to content

Commit 7649a04

Browse files
committed
fix: comments
1 parent 9f66953 commit 7649a04

File tree

3 files changed

+51
-37
lines changed

3 files changed

+51
-37
lines changed

src/Std/Internal/Async/Context.lean

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,77 +19,91 @@ namespace Internal
1919
namespace IO
2020
namespace Async
2121

22+
/-!
23+
# Asynchronous Context
24+
25+
This module provides `ContextAsync`, a monad for asynchronous computations with built-in
26+
cancellation support.
27+
-/
28+
2229
/--
23-
An asynchronous computation with cancellation support via a `Context`.
30+
An asynchronous computation with cancellation support via a `Context`. `ContextAsync α` is equivalent
31+
to `ReaderT Context Async α`, providing a `Context` value through async computations.
2432
-/
2533
@[expose] abbrev ContextAsync (α : Type) := ReaderT Context Async α
2634

2735
namespace ContextAsync
2836

2937
/--
30-
Run a `ContextAsync` computation with a given context.
38+
Runs a `ContextAsync` computation with a given context. Typically the context is created with
39+
`Context.new` or `Context.fork`.
3140
-/
3241
@[inline]
3342
protected def run (ctx : Context) (x : ContextAsync α) : Async α :=
3443
x ctx
3544

3645
/--
37-
Create a `ContextAsync` from an `Async` computation.
46+
Lifts an `Async` computation into `ContextAsync`.
47+
The lifted computation ignores the context and won't respect cancellation.
3848
-/
3949
@[inline]
4050
protected def lift (x : Async α) : ContextAsync α :=
4151
fun _ => x
4252

4353
/--
44-
Get the current context.
54+
Returns the current context for inspection or to pass to other functions.
4555
-/
4656
@[inline]
4757
def getContext : ContextAsync Context :=
4858
fun ctx => pure ctx
4959

5060
/--
51-
Fork a child context and run a computation within it.
61+
Forks a child context, runs a computation within it, and cancels the child context afterwards.
62+
The child inherits parent's cancellation, but cancelling the child doesn't affect the parent.
5263
-/
5364
@[inline]
5465
def fork (x : ContextAsync α) : ContextAsync α :=
5566
fun parent => do
5667
let child ← Context.fork parent
57-
x child
68+
try x child finally child.cancel .cancel
5869

5970
/--
60-
Check if the current context is cancelled.
71+
Checks if the current context is cancelled. Returns `true` if the context (or any ancestor) has been cancelled.
72+
Long-running operations should periodically check this and exit gracefully when cancelled.
6173
-/
6274
@[inline]
6375
def isCancelled : ContextAsync Bool := do
6476
let ctx ← getContext
6577
ctx.isCancelled
6678

6779
/--
68-
Get the cancellation reason if the context is cancelled.
80+
Gets the cancellation reason if the context is cancelled. Returns `some reason` if cancelled, `none` otherwise,
81+
allowing you to distinguish between different cancellation types.
6982
-/
7083
@[inline]
7184
def getCancellationReason : ContextAsync (Option CancellationReason) := do
7285
let ctx ← getContext
7386
ctx.getCancellationReason
7487

7588
/--
76-
Cancel the current context with the given reason.
89+
Cancels the current context with the given reason, cascading to all child contexts.
90+
Cancellation is cooperative, operations must explicitly check `isCancelled` or use `awaitCancellation` to respond.
7791
-/
7892
@[inline]
7993
def cancel (reason : CancellationReason) : ContextAsync Unit := do
8094
let ctx ← getContext
8195
ctx.cancel reason
8296

8397
/--
84-
Wait for the current context to be cancelled.
98+
Returns a selector that completes when the current context is cancelled.
8599
-/
86100
@[inline]
87101
def doneSelector : ContextAsync (Selector Unit) := do
88102
let ctx ← getContext
89103
return ctx.doneSelector
90104

91105
/--
92-
Wait for the current context to be cancelled.
106+
Waits for the current context to be cancelled.
93107
-/
94108
@[inline]
95109
def awaitCancellation : ContextAsync Unit := do
@@ -98,8 +112,8 @@ def awaitCancellation : ContextAsync Unit := do
98112
await task
99113

100114
/--
101-
Run two computations concurrently and return both results. If either fails or is cancelled,
102-
both are cancelled.
115+
Runs two computations concurrently and returns both results.
116+
If either fails or is cancelled, both are cancelled immediately and the exception is propagated.
103117
-/
104118
@[inline, specialize]
105119
def concurrently (x : ContextAsync α) (y : ContextAsync β)
@@ -108,8 +122,8 @@ def concurrently (x : ContextAsync α) (y : ContextAsync β)
108122
Async.concurrently (x ctx) (y ctx) prio
109123

110124
/--
111-
Run two computations concurrently and return the result of the first to complete.
112-
The loser's context is cancelled.
125+
Runs two computations concurrently and returns the result of the first to complete.
126+
Each runs in its own child context; when either completes, the other is cancelled immediately.
113127
-/
114128
@[inline, specialize]
115129
def race [Inhabited α] (x : ContextAsync α) (y : ContextAsync α)
@@ -129,8 +143,8 @@ def race [Inhabited α] (x : ContextAsync α) (y : ContextAsync α)
129143
pure result
130144

131145
/--
132-
Run all computations concurrently and collect results. If any fails or is cancelled,
133-
all are cancelled.
146+
Runs all computations concurrently and collects results in the same order.
147+
If any computation fails, all others are cancelled and the exception is propagated.
134148
-/
135149
@[inline, specialize]
136150
def concurrentlyAll (xs : Array (ContextAsync α))
@@ -139,9 +153,9 @@ def concurrentlyAll (xs : Array (ContextAsync α))
139153
Async.concurrentlyAll (xs.map (· ctx)) prio
140154

141155
/--
142-
Run all computations concurrently and return the first result. All losers are cancelled.
156+
Runs all computations concurrently and returns the first result.
157+
Each computation gets its own child context; the first successful result wins and all others are cancelled.
143158
-/
144-
@[inline, specialize]
145159
def raceAll [ForM ContextAsync c (ContextAsync α)] (xs : c)
146160
(prio := Task.Priority.default) : ContextAsync α := do
147161
let parent ← getContext
@@ -150,27 +164,27 @@ def raceAll [ForM ContextAsync c (ContextAsync α)] (xs : c)
150164
ForM.forM xs fun x => do
151165
let ctx ← Context.fork parent
152166
let task ← async (x ctx) prio
167+
153168
background do
154169
try
155170
let result ← await task
156-
-- Cancel parent to stop other tasks
157-
parent.cancel .cancel
158171
promise.resolve (.ok result)
159172
catch e =>
160-
-- Only set error if promise not already resolved
161173
discard $ promise.resolve (.error e)
162174

163175
let result ← await promise
176+
parent.cancel .cancel
164177
Async.ofExcept result
165178

166179
/--
167-
Run a computation in the background with its own forked context.
180+
Runs a computation in the background with its own forked context, returning immediately.
181+
The task continues even after the parent completes but is cancelled when the parent context is cancelled.
168182
-/
169183
@[inline]
170184
def background (x : ContextAsync α) (prio := Task.Priority.default) : ContextAsync Unit := do
171185
let parent ← getContext
172186
let child ← Context.fork parent
173-
Async.background (x child) prio
187+
Async.background (x child *> child.cancel .cancel) prio
174188

175189
instance : Functor ContextAsync where
176190
map f x := fun ctx => f <$> x ctx

src/Std/Sync/CancellationToken.lean

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ structure CancellationToken where
9595
namespace CancellationToken
9696

9797
/--
98-
Create a new cancellation token.
98+
Creates a new cancellation token.
9999
-/
100100
def new : BaseIO CancellationToken := do
101101
return { state := ← Std.Mutex.new { reason := none, consumers := ∅ } }
102102

103103
/--
104-
Cancel the token with the given reason, notifying all currently waiting consumers.
104+
Cancels the token with the given reason, notifying all currently waiting consumers.
105105
Once cancelled, the token remains cancelled.
106106
-/
107107
def cancel (x : CancellationToken) (reason : CancellationReason := .cancel) : BaseIO Unit := do
@@ -124,23 +124,23 @@ def cancel (x : CancellationToken) (reason : CancellationReason := .cancel) : Ba
124124
set st
125125

126126
/--
127-
Check if the token is cancelled.
127+
Checks if the token is cancelled.
128128
-/
129129
def isCancelled (x : CancellationToken) : BaseIO Bool := do
130130
x.state.atomically do
131131
let st ← get
132132
return st.reason.isSome
133133

134134
/--
135-
Get the cancellation reason if the token is cancelled.
135+
Gets the cancellation reason if the token is cancelled.
136136
-/
137137
def getCancellationReason (x : CancellationToken) : BaseIO (Option CancellationReason) := do
138138
x.state.atomically do
139139
let st ← get
140140
return st.reason
141141

142142
/--
143-
Wait for cancellation. Returns a task that completes when cancelled,
143+
Waits for cancellation. Returns a task that completes when cancelled.
144144
-/
145145
def wait (x : CancellationToken) : IO (AsyncTask Unit) :=
146146
x.state.atomically do
@@ -158,7 +158,7 @@ def wait (x : CancellationToken) : IO (AsyncTask Unit) :=
158158
| none => throw (IO.userError "cancellation token dropped")
159159

160160
/--
161-
Creates a selector that waits for cancellation
161+
Creates a selector that waits for cancellation.
162162
-/
163163
def selector (token : CancellationToken) : Selector Unit := {
164164
tryFn := do

src/Std/Sync/Context.lean

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ structure Context where
5050
namespace Context
5151

5252
/--
53-
Create a new root cancellation context.
53+
Creates a new root cancellation context.
5454
-/
5555
def new : BaseIO Context := do
5656
let token ← Std.CancellationToken.new
@@ -61,7 +61,7 @@ def new : BaseIO Context := do
6161
}
6262

6363
/--
64-
Fork a child context from a parent. If the parent is already cancelled, returns the parent context.
64+
Forks a child context from a parent. If the parent is already cancelled, returns the parent context.
6565
Otherwise, creates a new child that will be cancelled when the parent is cancelled.
6666
-/
6767
def fork (root : Context) : BaseIO Context := do
@@ -81,7 +81,7 @@ def fork (root : Context) : BaseIO Context := do
8181
return { state := root.state, token, id := newId }
8282

8383
/--
84-
Recursively cancel a context and all its children with the given reason.
84+
Recursively cancels a context and all its children with the given reason.
8585
-/
8686
private partial def cancelChildren (state : ContextState) (id : UInt64) (reason : CancellationReason) : BaseIO ContextState := do
8787
let mut state := state
@@ -98,7 +98,7 @@ private partial def cancelChildren (state : ContextState) (id : UInt64) (reason
9898
pure { state with tokens := state.tokens.erase id }
9999

100100
/--
101-
Cancel this context and all child contexts with the given reason.
101+
Cancels this context and all child contexts with the given reason.
102102
-/
103103
def cancel (x : Context) (reason : CancellationReason) : BaseIO Unit := do
104104
if ← x.token.isCancelled then
@@ -110,21 +110,21 @@ def cancel (x : Context) (reason : CancellationReason) : BaseIO Unit := do
110110
set st
111111

112112
/--
113-
Check if the context is cancelled.
113+
Checks if the context is cancelled.
114114
-/
115115
@[inline]
116116
def isCancelled (x : Context) : BaseIO Bool := do
117117
x.token.isCancelled
118118

119119
/--
120-
Get the cancellation reason if the context is cancelled.
120+
Returns the cancellation reason if the context is cancelled.
121121
-/
122122
@[inline]
123123
def getCancellationReason (x : Context) : BaseIO (Option CancellationReason) := do
124124
x.token.getCancellationReason
125125

126126
/--
127-
Wait for cancellation. Returns a task that completes when the context is cancelled.
127+
Waits for cancellation. Returns a task that completes when the context is cancelled.
128128
-/
129129
@[inline]
130130
def done (x : Context) : IO (AsyncTask Unit) :=

0 commit comments

Comments
 (0)