SchedulerWrapper.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System;
  3. #if !NO_WEAKTABLE
  4. using System.Runtime.CompilerServices;
  5. #endif
  6. namespace System.Reactive.Concurrency
  7. {
  8. internal abstract class SchedulerWrapper : IScheduler, IServiceProvider
  9. {
  10. protected readonly IScheduler _scheduler;
  11. public SchedulerWrapper(IScheduler scheduler)
  12. {
  13. _scheduler = scheduler;
  14. #if !NO_WEAKTABLE
  15. _cache = new ConditionalWeakTable<IScheduler, IScheduler>();
  16. #endif
  17. }
  18. public DateTimeOffset Now
  19. {
  20. get { return _scheduler.Now; }
  21. }
  22. public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  23. {
  24. if (action == null)
  25. throw new ArgumentNullException("action");
  26. return _scheduler.Schedule(state, Wrap(action));
  27. }
  28. public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  29. {
  30. if (action == null)
  31. throw new ArgumentNullException("action");
  32. return _scheduler.Schedule(state, dueTime, Wrap(action));
  33. }
  34. public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
  35. {
  36. if (action == null)
  37. throw new ArgumentNullException("action");
  38. return _scheduler.Schedule(state, dueTime, Wrap(action));
  39. }
  40. protected virtual Func<IScheduler, TState, IDisposable> Wrap<TState>(Func<IScheduler, TState, IDisposable> action)
  41. {
  42. return (self, state) => action(GetRecursiveWrapper(self), state);
  43. }
  44. #if !NO_WEAKTABLE
  45. private readonly ConditionalWeakTable<IScheduler, IScheduler> _cache;
  46. public SchedulerWrapper(IScheduler scheduler, ConditionalWeakTable<IScheduler, IScheduler> cache)
  47. {
  48. _scheduler = scheduler;
  49. _cache = cache;
  50. }
  51. protected IScheduler GetRecursiveWrapper(IScheduler scheduler)
  52. {
  53. return _cache.GetValue(scheduler, s => Clone(s, _cache));
  54. }
  55. protected abstract SchedulerWrapper Clone(IScheduler scheduler, ConditionalWeakTable<IScheduler, IScheduler> cache);
  56. #else
  57. private readonly object _gate = new object();
  58. private IScheduler _recursiveOriginal;
  59. private IScheduler _recursiveWrapper;
  60. protected IScheduler GetRecursiveWrapper(IScheduler scheduler)
  61. {
  62. var recursiveWrapper = default(IScheduler);
  63. lock (_gate)
  64. {
  65. //
  66. // Chances are the recursive scheduler will remain the same. In practice, this
  67. // single-shot caching scheme works out quite well. Notice we propagate our
  68. // mini-cache to recursive raw scheduler wrappers too.
  69. //
  70. if (!object.ReferenceEquals(scheduler, _recursiveOriginal))
  71. {
  72. _recursiveOriginal = scheduler;
  73. var wrapper = Clone(scheduler);
  74. wrapper._recursiveOriginal = scheduler;
  75. wrapper._recursiveWrapper = wrapper;
  76. _recursiveWrapper = wrapper;
  77. }
  78. recursiveWrapper = _recursiveWrapper;
  79. }
  80. return recursiveWrapper;
  81. }
  82. protected abstract SchedulerWrapper Clone(IScheduler scheduler);
  83. #endif
  84. public object GetService(Type serviceType)
  85. {
  86. var serviceProvider = _scheduler as IServiceProvider;
  87. if (serviceProvider == null)
  88. return null;
  89. var result = default(object);
  90. if (TryGetService(serviceProvider, serviceType, out result))
  91. return result;
  92. return serviceProvider.GetService(serviceType);
  93. }
  94. protected abstract bool TryGetService(IServiceProvider provider, Type serviceType, out object service);
  95. }
  96. }