Przeglądaj źródła

Merge pull request #45 from shiftbot/fix-deadlock

Attempt to fix deadlocks when running tests.
Oren Novotny 9 lat temu
rodzic
commit
f62aa25fc5

+ 1 - 9
Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/ConcurrencyAbstractionLayer.cs

@@ -10,18 +10,10 @@ namespace System.Reactive.Concurrency
     /// </summary>
     internal static class ConcurrencyAbstractionLayer
     {
-        private static Lazy<IConcurrencyAbstractionLayer> s_current = new Lazy<IConcurrencyAbstractionLayer>(Initialize);
-
         /// <summary>
         /// Gets the current CAL. If no CAL has been set yet, it will be initialized to the default.
         /// </summary>
-        public static IConcurrencyAbstractionLayer Current
-        {
-            get
-            {
-                return s_current.Value;
-            }
-        }
+        public static IConcurrencyAbstractionLayer Current { get; } = Initialize();
 
         private static IConcurrencyAbstractionLayer Initialize()
         {

+ 2 - 2
Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/CurrentThreadScheduler.cs

@@ -12,7 +12,7 @@ namespace System.Reactive.Concurrency
     /// <seealso cref="Scheduler.CurrentThread">Singleton instance of this type exposed through this static property.</seealso>
     public sealed class CurrentThreadScheduler : LocalScheduler
     {
-        private static readonly CurrentThreadScheduler s_instance = new CurrentThreadScheduler();
+        private static readonly Lazy<CurrentThreadScheduler> s_instance = new Lazy<CurrentThreadScheduler>(() => new CurrentThreadScheduler());
 
         CurrentThreadScheduler()
         {
@@ -23,7 +23,7 @@ namespace System.Reactive.Concurrency
         /// </summary>
         public static CurrentThreadScheduler Instance
         {
-            get { return s_instance; }
+            get { return s_instance.Value; }
         }
 
 #if !NO_TLS

+ 2 - 2
Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/DefaultScheduler.cs

@@ -12,7 +12,7 @@ namespace System.Reactive.Concurrency
     /// <seealso cref="Scheduler.Default">Singleton instance of this type exposed through this static property.</seealso>
     public sealed class DefaultScheduler : LocalScheduler, ISchedulerPeriodic
     {
-        private static readonly DefaultScheduler s_instance = new DefaultScheduler();
+        private static readonly Lazy<DefaultScheduler> s_instance = new Lazy<DefaultScheduler>(() => new DefaultScheduler());
         private static IConcurrencyAbstractionLayer s_cal = ConcurrencyAbstractionLayer.Current;
 
         /// <summary>
@@ -22,7 +22,7 @@ namespace System.Reactive.Concurrency
         {
             get
             {
-                return s_instance;
+                return s_instance.Value;
             }
         }
 

+ 2 - 2
Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/ImmediateScheduler.cs

@@ -11,7 +11,7 @@ namespace System.Reactive.Concurrency
     /// <seealso cref="Scheduler.Immediate">Singleton instance of this type exposed through this static property.</seealso>
     public sealed class ImmediateScheduler : LocalScheduler
     {
-        private static readonly ImmediateScheduler s_instance = new ImmediateScheduler();
+        private static readonly Lazy<ImmediateScheduler> s_instance = new Lazy<ImmediateScheduler>(() => new ImmediateScheduler());
 
         ImmediateScheduler()
         {
@@ -22,7 +22,7 @@ namespace System.Reactive.Concurrency
         /// </summary>
         public static ImmediateScheduler Instance
         {
-            get { return s_instance; }
+            get { return s_instance.Value; }
         }
 
         /// <summary>

+ 5 - 2
Rx.NET/Source/System.Reactive.Core/Reactive/Concurrency/Scheduler.cs

@@ -14,7 +14,10 @@ namespace System.Reactive.Concurrency
     {
         // TODO - Review whether this is too eager.
         // Make first use of Scheduler trigger access to and initialization of the CAL.
-        private static DefaultScheduler s_default = DefaultScheduler.Instance;
+
+        // HACK: Causes race condition with Locks in DefaultScheduler's static ctor chain
+        // private static DefaultScheduler s_default = DefaultScheduler.Instance;
+        
 
         /// <summary>
         /// Gets the current time according to the local machine's system clock.
@@ -68,7 +71,7 @@ namespace System.Reactive.Concurrency
         {
             get
             {
-                return s_default;
+                return DefaultScheduler.Instance;
             }
         }
 

+ 23 - 37
Rx.NET/Source/System.Reactive.Core/Reactive/Internal/PlatformEnlightenmentProvider.cs

@@ -33,8 +33,7 @@ namespace System.Reactive.PlatformServices
     [EditorBrowsable(EditorBrowsableState.Never)]
     public static class PlatformEnlightenmentProvider
     {
-        private static readonly object s_gate = new object();
-        private static IPlatformEnlightenmentProvider s_current;
+        private static readonly IPlatformEnlightenmentProvider s_current = CreatePlatformProvider();
 
         /// <summary>
         /// (Infrastructure) Gets the current enlightenment provider. If none is loaded yet, accessing this property triggers provider resolution.
@@ -46,49 +45,36 @@ namespace System.Reactive.PlatformServices
         {
             get
             {
-                if (s_current == null)
-                {
-                    lock (s_gate)
-                    {
-                        if (s_current == null)
-                        {
-                            //
-                            // TODO: Investigate whether we can simplify this logic to just use "System.Reactive.PlatformServices.PlatformEnlightenmentProvider, System.Reactive.PlatformServices".
-                            //       It turns out this doesn't quite work on Silverlight. On the other hand, in .NET Compact Framework 3.5, we mysteriously have to use that path.
-                            //
+                return s_current;
+            }
+            
+        }
+
+        private static IPlatformEnlightenmentProvider CreatePlatformProvider()
+        {
+            //
+            // TODO: Investigate whether we can simplify this logic to just use "System.Reactive.PlatformServices.PlatformEnlightenmentProvider, System.Reactive.PlatformServices".
+            //       It turns out this doesn't quite work on Silverlight. On the other hand, in .NET Compact Framework 3.5, we mysteriously have to use that path.
+            //
 
 #if NETCF35
-                            var name = "System.Reactive.PlatformServices.CurrentPlatformEnlightenmentProvider, System.Reactive.PlatformServices";
+            var name = "System.Reactive.PlatformServices.CurrentPlatformEnlightenmentProvider, System.Reactive.PlatformServices";
 #else
 #if CRIPPLED_REFLECTION && HAS_WINRT
-                            var ifType = typeof(IPlatformEnlightenmentProvider).GetTypeInfo();
+            var ifType = typeof(IPlatformEnlightenmentProvider).GetTypeInfo();
 #else
-                            var ifType = typeof(IPlatformEnlightenmentProvider);
+            var ifType = typeof(IPlatformEnlightenmentProvider);
 #endif
-                            var asm = new AssemblyName(ifType.Assembly.FullName);
-                            asm.Name = "System.Reactive.PlatformServices";
-                            var name = "System.Reactive.PlatformServices.CurrentPlatformEnlightenmentProvider, " + asm.FullName;
+            var asm = new AssemblyName(ifType.Assembly.FullName);
+            asm.Name = "System.Reactive.PlatformServices";
+            var name = "System.Reactive.PlatformServices.CurrentPlatformEnlightenmentProvider, " + asm.FullName;
 #endif
 
-                            var t = Type.GetType(name, false);
-                            if (t != null)
-                                s_current = (IPlatformEnlightenmentProvider)Activator.CreateInstance(t);
-                            else
-                                s_current = new DefaultPlatformEnlightenmentProvider();
-                        }
-                    }
-                }
-
-                return s_current;
-            }
-
-            set
-            {
-                lock (s_gate)
-                {
-                    s_current = value;
-                }
-            }
+            var t = Type.GetType(name, false);
+            if (t != null)
+                return (IPlatformEnlightenmentProvider)Activator.CreateInstance(t);
+            else
+                return new DefaultPlatformEnlightenmentProvider();
         }
     }
 

+ 2 - 2
Rx.NET/Source/System.Reactive.Linq/Reactive/Internal/QueryServices.cs

@@ -7,11 +7,11 @@ namespace System.Reactive.Linq
 {
     internal static class QueryServices
     {
-        private static Lazy<IQueryServices> s_services = new Lazy<IQueryServices>(Initialize);
+        private static IQueryServices s_services = Initialize();
 
         public static T GetQueryImpl<T>(T defaultInstance)
         {
-            return s_services.Value.Extend(defaultInstance);
+            return s_services.Extend(defaultInstance);
         }
 
         private static IQueryServices Initialize()

+ 2 - 2
Rx.NET/Source/System.Reactive.PlatformServices/Reactive/Concurrency/NewThreadScheduler.cs

@@ -10,7 +10,7 @@ namespace System.Reactive.Concurrency
     /// </summary>
     public sealed class NewThreadScheduler : LocalScheduler, ISchedulerLongRunning, ISchedulerPeriodic
     {
-        internal static readonly NewThreadScheduler s_instance = new NewThreadScheduler();
+        internal static readonly Lazy<NewThreadScheduler> s_instance = new Lazy<NewThreadScheduler>(() => new NewThreadScheduler());
 
         private readonly Func<ThreadStart, Thread> _threadFactory;
 
@@ -29,7 +29,7 @@ namespace System.Reactive.Concurrency
         {
             get
             {
-                return s_instance;
+                return s_instance.Value;
             }
         }
 

+ 2 - 2
Rx.NET/Source/System.Reactive.PlatformServices/Reactive/Concurrency/TaskPoolScheduler.cs

@@ -13,7 +13,7 @@ namespace System.Reactive.Concurrency
     /// <seealso cref="TaskPoolScheduler.Default">Instance of this type using the default TaskScheduler to schedule work on the TPL task pool.</seealso>
     public sealed class TaskPoolScheduler : LocalScheduler, ISchedulerLongRunning, ISchedulerPeriodic
     {
-        private static readonly TaskPoolScheduler s_instance = new TaskPoolScheduler(new TaskFactory(TaskScheduler.Default));
+        private static readonly Lazy<TaskPoolScheduler> s_instance = new Lazy<TaskPoolScheduler>(() => new TaskPoolScheduler(new TaskFactory(TaskScheduler.Default)));
         private readonly TaskFactory taskFactory;
 
         /// <summary>
@@ -36,7 +36,7 @@ namespace System.Reactive.Concurrency
         {
             get
             {
-                return s_instance;
+                return s_instance.Value;
             }
         }
 

+ 4 - 4
Rx.NET/Source/System.Reactive.PlatformServices/Reactive/Concurrency/ThreadPoolScheduler.cs

@@ -13,8 +13,8 @@ namespace System.Reactive.Concurrency
     /// <seealso cref="ThreadPoolScheduler.Instance">Singleton instance of this type exposed through this static property.</seealso>
     public sealed class ThreadPoolScheduler : LocalScheduler, ISchedulerLongRunning, ISchedulerPeriodic
     {
-        private static readonly ThreadPoolScheduler s_instance = new ThreadPoolScheduler();
-        private static readonly NewThreadScheduler s_newBackgroundThread = new NewThreadScheduler(action => new Thread(action) { IsBackground = true });
+        private static readonly Lazy<ThreadPoolScheduler> s_instance = new Lazy<ThreadPoolScheduler>(() => new ThreadPoolScheduler());
+        private static readonly Lazy<NewThreadScheduler> s_newBackgroundThread = new Lazy<NewThreadScheduler>(() => new NewThreadScheduler(action => new Thread(action) { IsBackground = true }));
 
         /// <summary>
         /// Gets the singleton instance of the CLR thread pool scheduler.
@@ -23,7 +23,7 @@ namespace System.Reactive.Concurrency
         {
             get
             {
-                return s_instance;
+                return s_instance.Value;
             }
         }
 
@@ -89,7 +89,7 @@ namespace System.Reactive.Concurrency
             if (action == null)
                 throw new ArgumentNullException("action");
 
-            return s_newBackgroundThread.ScheduleLongRunning(state, action);
+            return s_newBackgroundThread.Value.ScheduleLongRunning(state, action);
         }
 
 #if !NO_STOPWATCH

+ 1 - 1
Rx.NET/Source/Tests.System.Reactive/project.json

@@ -40,7 +40,7 @@
     "System.Reactive.Providers": { "target": "project" },
     "System.Reactive.Observable.Aliases": { "target": "project" },
     "xunit": "2.1.0",
-    "dotnet-test-xunit": "1.0.0-rc2-*"
+    "dotnet-test-xunit": "1.0.0-rc2-build10025"
   },
   "testRunner": "xunit",
   "frameworks": {

+ 1 - 2
Rx.NET/Source/Tests.System.Reactive/xunit.runner.json

@@ -1,5 +1,4 @@
 {
   "diagnosticMessages": true,
-  "methodDisplay": "classAndMethod",
-  "maxParallelThreads": 2
+  "methodDisplay": "classAndMethod"  
 }