Skip to content

Commit

Permalink
changes to ensure working ReactiveUI in WASM (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
richbryant authored and glennawatson committed Jan 1, 2020
1 parent a72fa6f commit cd969a1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Threading;

Expand Down Expand Up @@ -41,7 +40,7 @@ public IDisposable StartPeriodicTimer(Action action, TimeSpan period)
/// <inheritdoc />
public IDisposable QueueUserWorkItem(Action<object> action, object state)
{
System.Threading.ThreadPool.QueueUserWorkItem(_ => action(_), state);
ThreadPool.QueueUserWorkItem(_ => action(_), state);
return Disposable.Empty;
}

Expand Down Expand Up @@ -148,20 +147,22 @@ public Timer(Action<object> action, object state, TimeSpan dueTime)
{
// Rooting of the timer happens through the this.Tick delegate's target object,
// which is the current instance and has a field to store the Timer instance.
_timer = new System.Threading.Timer(Tick, state, dueTime, TimeSpan.FromMilliseconds(System.Threading.Timeout.Infinite));
_timer = new System.Threading.Timer(Tick, state, dueTime, TimeSpan.FromMilliseconds(Timeout.Infinite));
}
}

public void Dispose()
{
var timer = _timer;
if (timer != TimerStubs.Never)
System.Threading.Timer timer = _timer;
if (timer == TimerStubs.Never)
{
_action = Stubs<object>.Ignore;
_timer = TimerStubs.Never;

timer.Dispose();
return;
}

_action = Stubs<object>.Ignore;
_timer = TimerStubs.Never;

timer.Dispose();
}

private void Tick(object state)
Expand Down Expand Up @@ -196,14 +197,16 @@ public PeriodicTimer(Action action, TimeSpan period)

public void Dispose()
{
var timer = _timer;
if (timer != null)
System.Threading.Timer timer = _timer;
if (timer == null)
{
_action = Stubs.Nop;
_timer = null;

timer.Dispose();
return;
}

_action = Stubs.Nop;
_timer = null;

timer.Dispose();
}

private void Tick(object state) => _action();
Expand All @@ -218,7 +221,7 @@ public FastPeriodicTimer(Action action)
{
_action = action;

new System.Threading.Thread(Loop)
new Thread(Loop)
{
Name = "Rx-FastPeriodicTimer",
IsBackground = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,15 @@ namespace System.Reactive.PlatformServices
public class WasmPlatformEnlightenmentProvider : CurrentPlatformEnlightenmentProvider
{
private static Lazy<bool> _isWasm = new Lazy<bool>(
() =>
{
if (ModeDetector.InUnitTestRunner())
{
return true;
}
try
{
new Thread(() => { }).Start();
return false;
}
catch (Exception)
{
// Usually a TypeInitializationException, however be safe by considering any platform
// that does not support threading as "Wasm".
return true;
}
}, LazyThreadSafetyMode.PublicationOnly);
() => ModeDetector.InUnitTestRunner() || MonoTest, LazyThreadSafetyMode.PublicationOnly);

/// <summary>Gets a value indicating whether the current executable is processing under WASM.</summary>
public static bool IsWasm => _isWasm.Value;

/// <summary> Gets a value indicating whether we're running on mono, hence wasm. </summary>
private static bool MonoTest =>
Type.GetType("Mono.Runtime") != null;

/// <summary>
/// (Infastructure) Tries to gets the specified service.
/// </summary>
Expand All @@ -49,18 +35,21 @@ public class WasmPlatformEnlightenmentProvider : CurrentPlatformEnlightenmentPro
/// <returns>Service instance or <c>null</c> if not found.</returns>
public override T GetService<T>(object[] args)
{
if (IsWasm)
if (!IsWasm)
{
Type t = typeof(T);
return base.GetService<T>(args);
}

Type t = typeof(T);

if (t == typeof(IConcurrencyAbstractionLayer))
{
return (T)(object)new ConcurrencyAbstractionLayerWasmImpl();
}
else if (t == typeof(IScheduler))
{
return (T)(object)WasmScheduler.Default;
}
if (t == typeof(IConcurrencyAbstractionLayer))
{
return (T)(object)new ConcurrencyAbstractionLayerWasmImpl();
}

if (t == typeof(IScheduler))
{
return (T)(object)WasmScheduler.Default;
}

return base.GetService<T>(args);
Expand Down
26 changes: 11 additions & 15 deletions src/System.Reactive.Wasm/Internal/WasmScheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TSta
throw new ArgumentNullException(nameof(action));
}

var d = new SingleAssignmentDisposable();
SingleAssignmentDisposable d = new SingleAssignmentDisposable();

WasmRuntime.ScheduleTimeout(0, () =>
{
Expand Down Expand Up @@ -68,26 +68,22 @@ public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<
throw new ArgumentNullException(nameof(action));
}

var state1 = state;
var gate = new AsyncLock();
TState state1 = state;
AsyncLock gate = new AsyncLock();

WasmRuntime.ScheduleTimeout(
(int)period.TotalMilliseconds,
() =>
{
Action run = null;
run = () =>
void Run()
{
gate.Wait(() =>
{
state1 = action(state1);
WasmRuntime.ScheduleTimeout(
(int)period.TotalMilliseconds,
run);
WasmRuntime.ScheduleTimeout((int)period.TotalMilliseconds, Run);
});
};
}
});

return Disposable.Create(() =>
Expand All @@ -105,14 +101,14 @@ public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Fun
throw new ArgumentNullException(nameof(action));
}

var dt = Scheduler.Normalize(dueTime);
TimeSpan dt = Scheduler.Normalize(dueTime);

if (dt.Ticks == 0)
{
return Schedule(state, action);
}

var d = new SingleAssignmentDisposable();
SingleAssignmentDisposable d = new SingleAssignmentDisposable();

WasmRuntime.ScheduleTimeout(
(int)dt.TotalMilliseconds,
Expand All @@ -131,7 +127,7 @@ public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Fun
internal static class WasmRuntime
{
private static Dictionary<int, Action> _callbacks;
private static int _next_id;
private static int _nextId;

internal static void ScheduleTimeout(int timeout, Action action)
{
Expand All @@ -140,7 +136,7 @@ internal static void ScheduleTimeout(int timeout, Action action)
_callbacks = new Dictionary<int, Action>();
}

int id = ++_next_id;
int id = ++_nextId;
_callbacks[id] = action;
SetTimeout(timeout, id);
}
Expand All @@ -151,7 +147,7 @@ internal static void ScheduleTimeout(int timeout, Action action)
// XXX Keep this in sync with mini-wasm.c:mono_set_timeout_exec
private static void TimeoutCallback(int id)
{
var cb = _callbacks[id];
Action cb = _callbacks[id];
_callbacks.Remove(id);
cb();
}
Expand Down

0 comments on commit cd969a1

Please sign in to comment.