Skip to content

Commit a4a229b

Browse files
committed
Remove WhileDynamic, it's already implicitly present, and add debug logging to the new code
1 parent 5bd3813 commit a4a229b

File tree

3 files changed

+86
-123
lines changed

3 files changed

+86
-123
lines changed

src/FSharp.Control.TaskSeq/TaskExtensions.fs

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,6 @@ open FSharp.Control.TaskSeqBuilders
1616
[<AutoOpen>]
1717
module TaskExtensions =
1818

19-
let rec WhileDynamic
20-
(
21-
sm: byref<TaskStateMachine<'Data>>,
22-
condition: unit -> ValueTask<bool>,
23-
body: TaskCode<'Data, unit>
24-
) : bool =
25-
let vt = condition ()
26-
27-
TaskBuilderBase.BindDynamic(
28-
&sm,
29-
vt,
30-
fun result ->
31-
TaskCode<_, _>(fun sm ->
32-
if result then
33-
if body.Invoke(&sm) then
34-
WhileDynamic(&sm, condition, body)
35-
else
36-
let rf = sm.ResumptionDynamicInfo.ResumptionFunc
37-
38-
sm.ResumptionDynamicInfo.ResumptionFunc <-
39-
(TaskResumptionFunc<'Data>(fun sm -> WhileBodyDynamicAux(&sm, condition, body, rf)))
40-
41-
false
42-
else
43-
true)
44-
)
45-
46-
47-
and WhileBodyDynamicAux
48-
(
49-
sm: byref<TaskStateMachine<'Data>>,
50-
condition: unit -> ValueTask<bool>,
51-
body: TaskCode<'Data, unit>,
52-
rf: TaskResumptionFunc<_>
53-
) : bool =
54-
if rf.Invoke(&sm) then
55-
WhileDynamic(&sm, condition, body)
56-
else
57-
let rf = sm.ResumptionDynamicInfo.ResumptionFunc
58-
59-
sm.ResumptionDynamicInfo.ResumptionFunc <-
60-
(TaskResumptionFunc<'Data>(fun sm -> WhileBodyDynamicAux(&sm, condition, body, rf)))
61-
62-
false
63-
6419
// Add asynchronous for loop to the 'task' computation builder
6520
type Microsoft.FSharp.Control.TaskBuilder with
6621

@@ -73,6 +28,8 @@ module TaskExtensions =
7328
) : TaskCode<_, _> =
7429
let mutable condition_res = true
7530

31+
// note that this While itself has both a dynamic and static implementation
32+
// so we don't need to add that here (TODO: how to verify?).
7633
ResumableCode.While(
7734
(fun () -> condition_res),
7835
TaskCode<_, _>(fun sm ->
@@ -82,12 +39,12 @@ module TaskExtensions =
8239
let mutable awaiter = __stack_vtask.GetAwaiter()
8340

8441
if awaiter.IsCompleted then
85-
// logInfo "at WhileAsync: returning completed task"
42+
Debug.logInfo "at Task.WhileAsync: returning completed task"
8643

8744
__stack_condition_fin <- true
8845
condition_res <- awaiter.GetResult()
8946
else
90-
// logInfo "at WhileAsync: awaiting non-completed task"
47+
Debug.logInfo "at Task.WhileAsync: awaiting non-completed task"
9148

9249
// This will yield with __stack_fin = false
9350
// This will resume with __stack_fin = true

src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs

Lines changed: 30 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -36,50 +36,6 @@ module Internal = // cannot be marked with 'internal' scope
3636
with _ ->
3737
false
3838

39-
type Debug =
40-
41-
[<DefaultValue(false)>]
42-
static val mutable private verbose: bool option
43-
44-
/// Setting from environment variable TASKSEQ_LOG_VERBOSE, which,
45-
/// when set, enables (very) verbose printing of flow and state
46-
static member private getVerboseSetting() =
47-
match Debug.verbose with
48-
| None ->
49-
let verboseEnv =
50-
try
51-
match Environment.GetEnvironmentVariable "TASKSEQ_LOG_VERBOSE" with
52-
| null -> false
53-
| x ->
54-
match x.ToLowerInvariant().Trim() with
55-
| "1"
56-
| "true"
57-
| "on"
58-
| "yes" -> true
59-
| _ -> false
60-
61-
with _ ->
62-
false
63-
64-
Debug.verbose <- Some verboseEnv
65-
verboseEnv
66-
67-
| Some setting -> setting
68-
69-
[<Conditional("DEBUG")>]
70-
static member private print value =
71-
match Debug.getVerboseSetting () with
72-
| false -> ()
73-
| true ->
74-
// don't use ksprintf here, because the compiler does not remove all allocations due to
75-
// the way PrintfFormat types are compiled, even if we set the Conditional attribute.
76-
printfn "%i (%b): %s" Thread.CurrentThread.ManagedThreadId Thread.CurrentThread.IsThreadPoolThread value
77-
78-
[<Conditional("DEBUG")>]
79-
static member logInfo(str) = Debug.print str
80-
81-
[<Conditional("DEBUG")>]
82-
static member logInfo(str, data) = Debug.print $"%s{str}{data}"
8339

8440
/// Call MoveNext on an IAsyncStateMachine by reference
8541
let inline moveNextRef (x: byref<'T> when 'T :> IAsyncStateMachine) = x.MoveNext()
@@ -89,8 +45,6 @@ module Internal = // cannot be marked with 'internal' scope
8945
NotImplementedException "Abstract Class: method or property not implemented"
9046
|> raise
9147

92-
open type Debug
93-
9448
type taskSeq<'T> = IAsyncEnumerable<'T>
9549

9650
type IPriority1 =
@@ -244,7 +198,7 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
244198
this // just return 'self' here
245199

246200
| _ ->
247-
logInfo "GetAsyncEnumerator, start cloning..."
201+
Debug.logInfo "GetAsyncEnumerator, start cloning..."
248202

249203
// We need to reset state, but only to the "initial machine", resetting the _machine to
250204
// Unchecked.defaultof<_> is wrong, as the compiler uses this to track state. However,
@@ -260,7 +214,7 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
260214
clone._machine <- this._initialMachine
261215
clone._initialMachine <- this._initialMachine // TODO: proof with a test that this is necessary: probably not
262216
clone.InitMachineData(ct, &clone._machine)
263-
logInfo "GetAsyncEnumerator, finished cloning..."
217+
Debug.logInfo "GetAsyncEnumerator, finished cloning..."
264218
clone
265219

266220
interface System.Collections.Generic.IAsyncEnumerator<'T> with
@@ -275,39 +229,39 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
275229
Unchecked.defaultof<'T>
276230

277231
member this.MoveNextAsync() =
278-
logInfo "MoveNextAsync..."
232+
Debug.logInfo "MoveNextAsync..."
279233

280234
if this._machine.ResumptionPoint = -1 then // can't use as IAsyncEnumerator before IAsyncEnumerable
281-
logInfo "at MoveNextAsync: Resumption point = -1"
235+
Debug.logInfo "at MoveNextAsync: Resumption point = -1"
282236

283237
ValueTask.False
284238

285239
elif this._machine.Data.completed then
286-
logInfo "at MoveNextAsync: completed = true"
240+
Debug.logInfo "at MoveNextAsync: completed = true"
287241

288242
// return False when beyond the last item
289243
this._machine.Data.promiseOfValueOrEnd.Reset()
290244
ValueTask.False
291245

292246
else
293-
logInfo "at MoveNextAsync: normal resumption scenario"
247+
Debug.logInfo "at MoveNextAsync: normal resumption scenario"
294248

295249
let data = this._machine.Data
296250
data.promiseOfValueOrEnd.Reset()
297251
let mutable ts = this
298252

299-
logInfo "at MoveNextAsync: start calling builder.MoveNext()"
253+
Debug.logInfo "at MoveNextAsync: start calling builder.MoveNext()"
300254

301255
data.builder.MoveNext(&ts)
302256

303-
logInfo "at MoveNextAsync: finished calling builder.MoveNext()"
257+
Debug.logInfo "at MoveNextAsync: finished calling builder.MoveNext()"
304258

305259
this.MoveNextAsyncResult()
306260

307261
/// Disposes of the IAsyncEnumerator (*not* the IAsyncEnumerable!!!)
308262
member this.DisposeAsync() =
309263
task {
310-
logInfo "DisposeAsync..."
264+
Debug.logInfo "DisposeAsync..."
311265

312266
match this._machine.Data.disposalStack with
313267
| null -> ()
@@ -335,7 +289,7 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
335289

336290
match status with
337291
| ValueTaskSourceStatus.Succeeded ->
338-
logInfo "at MoveNextAsyncResult: case succeeded..."
292+
Debug.logInfo "at MoveNextAsyncResult: case succeeded..."
339293

340294
let result = data.promiseOfValueOrEnd.GetResult(version)
341295

@@ -349,11 +303,11 @@ and [<NoComparison; NoEquality>] TaskSeq<'Machine, 'T
349303
| ValueTaskSourceStatus.Faulted
350304
| ValueTaskSourceStatus.Canceled
351305
| ValueTaskSourceStatus.Pending as state ->
352-
logInfo ("at MoveNextAsyncResult: case ", state)
306+
Debug.logInfo ("at MoveNextAsyncResult: case ", state)
353307

354308
ValueTask.ofIValueTaskSource this version
355309
| _ ->
356-
logInfo "at MoveNextAsyncResult: Unexpected state"
310+
Debug.logInfo "at MoveNextAsyncResult: Unexpected state"
357311
// assume it's a possibly new, not yet supported case, treat as default
358312
ValueTask.ofIValueTaskSource this version
359313

@@ -376,12 +330,12 @@ type TaskSeqBuilder() =
376330
__resumeAt sm.ResumptionPoint
377331

378332
try
379-
logInfo "at Run.MoveNext start"
333+
Debug.logInfo "at Run.MoveNext start"
380334

381335
let __stack_code_fin = code.Invoke(&sm)
382336

383337
if __stack_code_fin then
384-
logInfo $"at Run.MoveNext, done"
338+
Debug.logInfo $"at Run.MoveNext, done"
385339

386340
// Signal we're at the end
387341
// NOTE: if we don't do it here, as well as in IValueTaskSource<bool>.GetResult
@@ -392,14 +346,14 @@ type TaskSeqBuilder() =
392346
sm.Data.completed <- true
393347

394348
elif sm.Data.current.IsSome then
395-
logInfo $"at Run.MoveNext, still more items in enumerator"
349+
Debug.logInfo $"at Run.MoveNext, still more items in enumerator"
396350

397351
// Signal there's more data:
398352
sm.Data.promiseOfValueOrEnd.SetResult(true)
399353

400354
else
401355
// Goto request
402-
logInfo $"at Run.MoveNext, await, MoveNextAsync has not completed yet"
356+
Debug.logInfo $"at Run.MoveNext, await, MoveNextAsync has not completed yet"
403357

404358
// don't capture the full object in the next closure (won't work because: byref)
405359
// but only a reference to itself.
@@ -412,15 +366,15 @@ type TaskSeqBuilder() =
412366
)
413367

414368
with exn ->
415-
logInfo ("Setting exception of PromiseOfValueOrEnd to: ", exn.Message)
369+
Debug.logInfo ("Setting exception of PromiseOfValueOrEnd to: ", exn.Message)
416370
sm.Data.promiseOfValueOrEnd.SetException(exn)
417371
sm.Data.builder.Complete()
418372

419373
//-- RESUMABLE CODE END
420374
))
421375
(SetStateMachineMethodImpl<_>(fun sm state -> ())) // not used in reference impl
422376
(AfterCode<_, _>(fun sm ->
423-
logInfo "at AfterCode<_, _>, after F# inits the sm, and we can attach extra info"
377+
Debug.logInfo "at AfterCode<_, _>, after F# inits the sm, and we can attach extra info"
424378

425379
let ts = TaskSeq<TaskSeqStateMachine<'T>, 'T>()
426380
ts._initialMachine <- sm
@@ -440,11 +394,11 @@ type TaskSeqBuilder() =
440394

441395

442396
member inline _.Zero() : TaskSeqCode<'T> =
443-
logInfo "at Zero()"
397+
Debug.logInfo "at Zero()"
444398
ResumableCode.Zero()
445399

446400
member inline _.Combine(task1: TaskSeqCode<'T>, task2: TaskSeqCode<'T>) : TaskSeqCode<'T> =
447-
logInfo "at Combine(.., ..)"
401+
Debug.logInfo "at Combine(.., ..)"
448402

449403
ResumableCode.Combine(task1, task2)
450404

@@ -463,12 +417,12 @@ type TaskSeqBuilder() =
463417
let __stack_vtask = condition ()
464418

465419
if __stack_vtask.IsCompleted then
466-
logInfo "at WhileAsync: returning completed task"
420+
Debug.logInfo "at WhileAsync: returning completed task"
467421

468422
__stack_condition_fin <- true
469423
condition_res <- __stack_vtask.Result
470424
else
471-
logInfo "at WhileAsync: awaiting non-completed task"
425+
Debug.logInfo "at WhileAsync: awaiting non-completed task"
472426

473427
let task = __stack_vtask.AsTask()
474428
let mutable awaiter = task.GetAwaiter()
@@ -490,7 +444,7 @@ type TaskSeqBuilder() =
490444
)
491445

492446
member inline b.While([<InlineIfLambda>] condition: unit -> bool, body: TaskSeqCode<'T>) : TaskSeqCode<'T> =
493-
logInfo "at While(...)"
447+
Debug.logInfo "at While(...)"
494448
ResumableCode.While(condition, body)
495449

496450
member inline _.TryWith(body: TaskSeqCode<'T>, catch: exn -> TaskSeqCode<'T>) : TaskSeqCode<'T> =
@@ -595,7 +549,7 @@ type TaskSeqBuilder() =
595549
TaskSeqCode<'T>(fun sm ->
596550
// This will yield with __stack_fin = false
597551
// This will resume with __stack_fin = true
598-
logInfo "at Yield"
552+
Debug.logInfo "at Yield"
599553

600554
let __stack_fin = ResumableCode.Yield().Invoke(&sm)
601555
sm.Data.current <- ValueSome v
@@ -612,23 +566,23 @@ type TaskSeqBuilder() =
612566
let mutable awaiter = task.GetAwaiter()
613567
let mutable __stack_fin = true
614568

615-
logInfo "at Bind"
569+
Debug.logInfo "at Bind"
616570

617571
if not awaiter.IsCompleted then
618572
// This will yield with __stack_fin2 = false
619573
// This will resume with __stack_fin2 = true
620574
let __stack_fin2 = ResumableCode.Yield().Invoke(&sm)
621575
__stack_fin <- __stack_fin2
622576

623-
logInfo ("at Bind: with __stack_fin = ", __stack_fin)
624-
logInfo ("at Bind: this.completed = ", sm.Data.completed)
577+
Debug.logInfo ("at Bind: with __stack_fin = ", __stack_fin)
578+
Debug.logInfo ("at Bind: this.completed = ", sm.Data.completed)
625579

626580
if __stack_fin then
627581
let result = awaiter.GetResult()
628582
(continuation result).Invoke(&sm)
629583

630584
else
631-
logInfo "at Bind: calling AwaitUnsafeOnCompleted"
585+
Debug.logInfo "at Bind: calling AwaitUnsafeOnCompleted"
632586

633587
sm.Data.awaiter <- awaiter
634588
sm.Data.current <- ValueNone
@@ -639,7 +593,7 @@ type TaskSeqBuilder() =
639593
let mutable awaiter = task.GetAwaiter()
640594
let mutable __stack_fin = true
641595

642-
logInfo "at BindV"
596+
Debug.logInfo "at BindV"
643597

644598
if not awaiter.IsCompleted then
645599
// This will yield with __stack_fin2 = false
@@ -651,7 +605,7 @@ type TaskSeqBuilder() =
651605
let result = awaiter.GetResult()
652606
(continuation result).Invoke(&sm)
653607
else
654-
logInfo "at BindV: calling AwaitUnsafeOnCompleted"
608+
Debug.logInfo "at BindV: calling AwaitUnsafeOnCompleted"
655609

656610
sm.Data.awaiter <- awaiter
657611
sm.Data.current <- ValueNone

0 commit comments

Comments
 (0)