This PR fixes a memleak caused by the Lean based `IO.waitAny`
implementation by reverting it.
This the faulty Lean implementation:
```lean
def IO.waitAny (tasks : @& List (Task α)) (h : tasks.length > 0 := by exact Nat.zero_lt_succ _) :
BaseIO α := do
have : Nonempty α := ⟨tasks[0].get⟩
let promise : IO.Promise α ← IO.Promise.new
tasks.forM <| fun t => BaseIO.chainTask (sync := true) t promise.resolve
return promise.result!.get
```
In a situation where we call this function repeatedly in a loop with a
pair of tasks `[t1, t2]`
where `t2` is a long lived task that we pass every time and `t1` is
fresh a short lived task, `t2` will
accumlate more and more children from `BaseIO.chainTask` that fill
memory over time. The old C++
implementation did not have this issue so we are reverting.
32 lines
786 B
Text
32 lines
786 B
Text
/-
|
||
Copyright (c) 2025 Lean FRO. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Sebastian Ullrich
|
||
|
||
Additional `Task` definitions.
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Init.System.Promise
|
||
|
||
public section
|
||
|
||
namespace Task
|
||
|
||
/--
|
||
Creates a task that, when all `tasks` have finished, computes the result of `f` applied to their
|
||
results.
|
||
-/
|
||
def mapList (f : List α → β) (tasks : List (Task α)) (prio := Task.Priority.default)
|
||
(sync := false) : Task β :=
|
||
go tasks []
|
||
where
|
||
go
|
||
| [], as =>
|
||
if sync then
|
||
.pure <| f as.reverse
|
||
else
|
||
Task.spawn (prio := prio) fun _ => f as.reverse
|
||
| [t], as => t.map (fun a => f (a :: as).reverse) prio sync
|
||
| t::ts, as => t.bind (fun a => go ts (a :: as)) prio sync
|