// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using System.Diagnostics; // for TraceInformation
using System.Runtime.CompilerServices;
public int upgradecount;
// Next RWC in this thread's list.
- public ReaderWriterCount next;
+ public ReaderWriterCount? next;
}
/// <summary>
private int _writeLockOwnerId;
// conditions we wait on.
- private EventWaitHandle _writeEvent; // threads waiting to acquire a write lock go here.
- private EventWaitHandle _readEvent; // threads waiting to acquire a read lock go here (will be released in bulk)
- private EventWaitHandle _upgradeEvent; // thread waiting to acquire the upgrade lock
- private EventWaitHandle _waitUpgradeEvent; // thread waiting to upgrade from the upgrade lock to a write lock go here (at most one)
+ private EventWaitHandle? _writeEvent; // threads waiting to acquire a write lock go here.
+ private EventWaitHandle? _readEvent; // threads waiting to acquire a read lock go here (will be released in bulk)
+ private EventWaitHandle? _upgradeEvent; // thread waiting to acquire the upgrade lock
+ private EventWaitHandle? _waitUpgradeEvent; // thread waiting to upgrade from the upgrade lock to a write lock go here (at most one)
// Every lock instance has a unique ID, which is used by ReaderWriterCount to associate itself with the lock
// without holding a reference to it.
// See comments on ReaderWriterCount.
[ThreadStatic]
- private static ReaderWriterCount t_rwc;
+ private static ReaderWriterCount? t_rwc;
private bool _fUpgradeThreadHoldingRead;
/// could not be found.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private ReaderWriterCount GetThreadRWCount(bool dontAllocate)
+ private ReaderWriterCount? GetThreadRWCount(bool dontAllocate) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
{
- ReaderWriterCount rwc = t_rwc;
- ReaderWriterCount empty = null;
+ ReaderWriterCount? rwc = t_rwc;
+ ReaderWriterCount? empty = null;
while (rwc != null)
{
if (rwc.lockID == _lockID)
if (_fDisposed)
throw new ObjectDisposedException(null);
- ReaderWriterCount lrwc = null;
+ ReaderWriterCount lrwc;
int id = Environment.CurrentManagedThreadId;
if (!_fIsReentrant)
_spinLock.Enter(EnterSpinLockReason.EnterAnyRead);
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
//Check if the reader lock is already acquired. Note, we could
//check the presence of a reader by not allocating rwc (But that
else
{
_spinLock.Enter(EnterSpinLockReason.EnterAnyRead);
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
if (lrwc.readercount > 0)
{
lrwc.readercount++;
_spinLock.Enter(EnterSpinLockReason.EnterAnyRead);
//The per-thread structure may have been recycled as the lock is acquired (due to message pumping), load again.
if (IsRwHashEntryChanged(lrwc))
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
continue;
}
{
LazyCreateEvent(ref _readEvent, EnterLockType.Read);
if (IsRwHashEntryChanged(lrwc))
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
continue; // since we left the lock, start over.
}
return false;
}
if (IsRwHashEntryChanged(lrwc))
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
}
_spinLock.Exit();
throw new ObjectDisposedException(null);
int id = Environment.CurrentManagedThreadId;
- ReaderWriterCount lrwc;
+ ReaderWriterCount? lrwc;
bool upgradingToWrite = false;
if (!_fIsReentrant)
}
_spinLock.Enter(enterMyLockReason);
- lrwc = GetThreadRWCount(true);
+ lrwc = GetThreadRWCount(dontAllocate: true);
//Can't acquire write lock with reader lock held.
if (lrwc != null && lrwc.readercount > 0)
}
_spinLock.Enter(enterMyLockReason);
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
if (id == _writeLockOwnerId)
{
if (lrwc != null)
{
if (IsRwHashEntryChanged(lrwc))
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
if (lrwc.readercount > 0)
{
if (_fIsReentrant)
{
+ Debug.Assert(lrwc != null, "Initialized based on _fIsReentrant earlier in the method");
if (IsRwHashEntryChanged(lrwc))
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
lrwc.writercount++;
}
throw new ObjectDisposedException(null);
int id = Environment.CurrentManagedThreadId;
- ReaderWriterCount lrwc;
+ ReaderWriterCount? lrwc;
if (!_fIsReentrant)
{
}
_spinLock.Enter(EnterSpinLockReason.EnterAnyRead);
- lrwc = GetThreadRWCount(true);
+ lrwc = GetThreadRWCount(dontAllocate: true);
//Can't acquire upgrade lock with reader lock held.
if (lrwc != null && lrwc.readercount > 0)
{
else
{
_spinLock.Enter(EnterSpinLockReason.EnterAnyRead);
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
if (id == _upgradeLockOwnerId)
{
{
//The lock may have been dropped getting here, so make a quick check to see whether some other
//thread did not grab the entry.
+ Debug.Assert(lrwc != null, "Initialized based on _fIsReentrant earlier in the method");
if (IsRwHashEntryChanged(lrwc))
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
lrwc.upgradecount++;
}
public void ExitReadLock()
{
- ReaderWriterCount lrwc = null;
-
_spinLock.Enter(EnterSpinLockReason.ExitAnyRead);
- lrwc = GetThreadRWCount(true);
+ ReaderWriterCount? lrwc = GetThreadRWCount(dontAllocate: true);
if (lrwc == null || lrwc.readercount < 1)
{
else
{
_spinLock.Enter(EnterSpinLockReason.ExitAnyWrite);
- lrwc = GetThreadRWCount(false);
+ lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
if (lrwc == null)
{
public void ExitUpgradeableReadLock()
{
- ReaderWriterCount lrwc;
+ ReaderWriterCount? lrwc;
if (!_fIsReentrant)
{
if (Environment.CurrentManagedThreadId != _upgradeLockOwnerId)
else
{
_spinLock.Enter(EnterSpinLockReason.ExitAnyRead);
- lrwc = GetThreadRWCount(true);
+ lrwc = GetThreadRWCount(dontAllocate: true);
if (lrwc == null)
{
/// while holding a spin lock). If all goes well, reenter the lock and
/// set 'waitEvent'
/// </summary>
- private void LazyCreateEvent(ref EventWaitHandle waitEvent, EnterLockType enterLockType)
+ private void LazyCreateEvent(ref EventWaitHandle? waitEvent, EnterLockType enterLockType) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
{
#if DEBUG
Debug.Assert(_spinLock.IsHeld);
if (_numWriteUpgradeWaiters > 0 && _fUpgradeThreadHoldingRead && readercount == 2)
{
_spinLock.Exit(); // Exit before signaling to improve efficiency (wakee will need the lock)
- _waitUpgradeEvent.Set(); // release all upgraders (however there can be at most one).
+ _waitUpgradeEvent!.Set(); // release all upgraders (however there can be at most one). Known non-null because _numWriteUpgradeWaiters > 0.
return;
}
}
{
//We have to be careful now, as we are dropping the lock.
//No new writes should be allowed to sneak in if an upgrade
- //was pending.
+ //was pending.
_spinLock.Exit(); // Exit before signaling to improve efficiency (wakee will need the lock)
- _waitUpgradeEvent.Set(); // release all upgraders (however there can be at most one).
+ _waitUpgradeEvent!.Set(); // release all upgraders (however there can be at most one). Known non-null because _numWriteUpgradeWaiters > 0.
}
else if (readercount == 0 && _numWriteWaiters > 0)
{
if (signaled == WaiterStates.None)
{
- _writeEvent.Set(); // release one writer.
+ _writeEvent!.Set(); // release one writer. Known non-null because _numWriteWaiters > 0.
}
}
else
_spinLock.Exit(); // Exit before signaling to improve efficiency (wakee will need the lock)
if (setReadEvent)
- _readEvent.Set(); // release all readers.
+ _readEvent!.Set(); // release all readers. Known non-null because _numUpgradeWaiters != 0.
if (setUpgradeEvent)
- _upgradeEvent.Set(); //release one upgrader.
+ _upgradeEvent!.Set(); //release one upgrader.
}
private bool IsWriterAcquired()
get
{
int count = 0;
- ReaderWriterCount lrwc = GetThreadRWCount(true);
+ ReaderWriterCount? lrwc = GetThreadRWCount(dontAllocate: true);
if (lrwc != null)
count = lrwc.readercount;
{
int count = 0;
- ReaderWriterCount lrwc = GetThreadRWCount(true);
+ ReaderWriterCount? lrwc = GetThreadRWCount(dontAllocate: true);
if (lrwc != null)
count = lrwc.upgradecount;
{
int count = 0;
- ReaderWriterCount lrwc = GetThreadRWCount(true);
+ ReaderWriterCount? lrwc = GetThreadRWCount(dontAllocate: true);
if (lrwc != null)
count = lrwc.writercount;