Skip to content

Commit

Permalink
Make EqualityComparer thread-safe for Mono (dotnet#31990)
Browse files Browse the repository at this point in the history
* Make EqualityComparer thread-safe for Mono

Fixes dotnet#3009
Fixes dotnet#31988

* Use Interlocked.CompareExchange
  • Loading branch information
jkotas authored Feb 9, 2020
1 parent 3b72a4d commit a1bc3cc
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,31 @@
// See the LICENSE file in the project root for more information.

using System.Runtime.CompilerServices;
using System.Threading;

namespace System.Collections.Generic
{
partial class Comparer<T>
{
static volatile Comparer<T> defaultComparer;
static volatile Comparer<T> defaultComparer;

public static Comparer<T> Default {
get {
Comparer<T> comparer = defaultComparer;
if (comparer == null) {
comparer = CreateComparer();
defaultComparer = comparer;
}
return comparer;
Comparer<T> comparer = defaultComparer;
if (comparer == null) {
// Do not use static constructor. Generic static constructors are problematic for Mono AOT.
Interlocked.CompareExchange(ref defaultComparer, CreateComparer(), null);
comparer = defaultComparer;
}
return comparer;
}
}

static Comparer<T> CreateComparer() {
RuntimeType t = (RuntimeType)typeof(T);
static Comparer<T> CreateComparer() {
RuntimeType t = (RuntimeType)typeof(T);

if (typeof(IComparable<T>).IsAssignableFrom(t))
return (Comparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(GenericComparer<>), t);
if (typeof(IComparable<T>).IsAssignableFrom(t))
return (Comparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(GenericComparer<>), t);

// If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U>
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Runtime.CompilerServices;
using System.Threading;

namespace System.Collections.Generic
{
Expand All @@ -15,8 +16,9 @@ public static EqualityComparer<T> Default {
get {
EqualityComparer<T> comparer = defaultComparer;
if (comparer == null) {
comparer = CreateComparer();
defaultComparer = comparer;
// Do not use static constructor. Generic static constructors are problematic for Mono AOT.
Interlocked.CompareExchange(ref defaultComparer, CreateComparer(), null);
comparer = defaultComparer;
}
return comparer;
}
Expand Down

0 comments on commit a1bc3cc

Please sign in to comment.