Skip to content

Commit eb9dc39

Browse files
authored
Merge pull request #738 from akarnokd/ObserveOnLongRunFix
4.x: Fix long sequence ObserveOn StackOverflowException upon Dispose
2 parents 907ef16 + 53096fb commit eb9dc39

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

Rx.NET/Source/src/System.Reactive/Internal/ScheduledObserver.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,10 @@ private IDisposable DrainShortRunning(IScheduler recursiveScheduler)
536536

537537
if (Interlocked.Decrement(ref _wip) != 0)
538538
{
539-
return recursiveScheduler.Schedule(this, DRAIN_SHORT_RUNNING);
539+
// Don't return the disposable of Schedule() because that may chain together
540+
// a long string of ScheduledItems causing StackOverflowException upon Dispose()
541+
var d = recursiveScheduler.Schedule(this, DRAIN_SHORT_RUNNING);
542+
Disposable.TrySetMultiple(ref _task, d);
540543
}
541544
return Disposable.Empty;
542545
}

Rx.NET/Source/tests/Tests.System.Reactive/Tests/Linq/Observable/ObserveOnTest.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,19 @@ public void ObserveOn_SynchronizationContext_Simple()
645645
);
646646
}
647647

648+
[Fact]
649+
public void ObserveOn_EventLoop_Long()
650+
{
651+
var _scheduler1 = new EventLoopScheduler();
652+
var N = 1_000_000;
653+
654+
var cde = new CountdownEvent(1);
655+
656+
Observable.Range(1, N).ObserveOn(_scheduler1)
657+
.Subscribe(v => { }, () => cde.Signal());
658+
659+
Assert.True(cde.Wait(5000), "Timeout!");
660+
}
648661
}
649662

650663
internal class MyCtx : SynchronizationContext

0 commit comments

Comments
 (0)