You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.1 KiB
161 lines
4.1 KiB
5 years ago
|
#if FAT
|
||
|
|
||
|
using System;
|
||
|
using System.Threading;
|
||
|
using LinqInternal.Collections;
|
||
|
using LinqInternal.Collections.Specialized;
|
||
|
using LinqInternal.Threading.Needles;
|
||
|
|
||
|
namespace LinqInternal.Threading
|
||
|
{
|
||
|
internal sealed class NeedleLock<T> : IReadOnlyNeedle<T>
|
||
|
{
|
||
|
private readonly LockContext<T> _context;
|
||
|
private readonly int _hashCode;
|
||
|
private FlagArray _capture;
|
||
|
private int _owner;
|
||
|
private T _target;
|
||
|
|
||
|
internal NeedleLock(LockContext<T> context)
|
||
|
{
|
||
|
if (context == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("context");
|
||
|
}
|
||
|
_context = context;
|
||
|
_hashCode = base.GetHashCode();
|
||
|
_capture = new FlagArray(_context.Capacity);
|
||
|
_owner = -1;
|
||
|
}
|
||
|
|
||
|
internal NeedleLock(LockContext<T> context, T target)
|
||
|
{
|
||
|
if (context == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("context");
|
||
|
}
|
||
|
_context = context;
|
||
|
if (ReferenceEquals(target, null))
|
||
|
{
|
||
|
_hashCode = base.GetHashCode();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_target = target;
|
||
|
_hashCode = target.GetHashCode();
|
||
|
}
|
||
|
_capture = new FlagArray(_context.Capacity);
|
||
|
_owner = -1;
|
||
|
}
|
||
|
|
||
|
bool IReadOnlyNeedle<T>.IsAlive
|
||
|
{
|
||
|
get { return !ReferenceEquals(_target, null); }
|
||
|
}
|
||
|
|
||
|
public T Value
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
LockSlot<T> slot;
|
||
|
if (_context.Read(_capture, ref _owner, out slot))
|
||
|
{
|
||
|
_target = slot.Value;
|
||
|
}
|
||
|
return _target;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static explicit operator T(NeedleLock<T> needle)
|
||
|
{
|
||
|
if (needle == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("needle");
|
||
|
}
|
||
|
return needle.Value;
|
||
|
}
|
||
|
|
||
|
public static bool operator !=(NeedleLock<T> left, NeedleLock<T> right)
|
||
|
{
|
||
|
return NotEqualsExtracted(left, right);
|
||
|
}
|
||
|
|
||
|
public static bool operator ==(NeedleLock<T> left, NeedleLock<T> right)
|
||
|
{
|
||
|
return EqualsExtracted(left, right);
|
||
|
}
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
var needle = obj as NeedleLock<T>;
|
||
|
if (needle == null)
|
||
|
{
|
||
|
return _target.Equals(obj);
|
||
|
}
|
||
|
return EqualsExtracted(this, needle);
|
||
|
}
|
||
|
|
||
|
public bool Equals(NeedleLock<T> other)
|
||
|
{
|
||
|
return EqualsExtracted(this, other);
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return _hashCode;
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
var target = Value;
|
||
|
if ((this as IReadOnlyNeedle<T>).IsAlive)
|
||
|
{
|
||
|
return target.ToString();
|
||
|
}
|
||
|
return "<Dead Needle>";
|
||
|
}
|
||
|
|
||
|
internal void Capture(LockSlot<T> slot)
|
||
|
{
|
||
|
_capture[slot._id] = true;
|
||
|
}
|
||
|
|
||
|
internal void Release()
|
||
|
{
|
||
|
if (Volatile.Read(ref _capture).Flags.IsEmpty())
|
||
|
{
|
||
|
_target = default(T);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void Uncapture(LockSlot<T> slot)
|
||
|
{
|
||
|
Interlocked.CompareExchange(ref _owner, -1, slot._id);
|
||
|
_capture[slot._id] = false;
|
||
|
}
|
||
|
|
||
|
private static bool EqualsExtracted(NeedleLock<T> left, NeedleLock<T> right)
|
||
|
{
|
||
|
if (left == null)
|
||
|
{
|
||
|
return right == null;
|
||
|
}
|
||
|
return left._target.Equals(right._target);
|
||
|
}
|
||
|
|
||
|
private static bool NotEqualsExtracted(NeedleLock<T> left, NeedleLock<T> right)
|
||
|
{
|
||
|
if (left == null)
|
||
|
{
|
||
|
if (right == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return !left._target.Equals(right._target);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|