Skip to content

Instantly share code, notes, and snippets.

@filipnavara
Created February 7, 2019 22:26
Show Gist options
  • Save filipnavara/86cf7b27f0f20d86d6ebde9aebf158e1 to your computer and use it in GitHub Desktop.
Save filipnavara/86cf7b27f0f20d86d6ebde9aebf158e1 to your computer and use it in GitHub Desktop.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace System.Threading
{
/// <summary>
/// A LIFO semaphore.
/// Waits on this semaphore are uninterruptible.
/// </summary>
internal sealed partial class LowLevelLifoSemaphore : IDisposable
{
private LowLevelLock _waiterStackLock;
private WaiterListEntry _waiterStackHead;
private LowLevelMonitor _fallbackMonitor;
[ThreadStatic]
private static WaiterListEntry t_waitEntry;
private void Create(int maximumSignalCount)
{
_waiterStackLock = new LowLevelLock();
_fallbackMonitor = new LowLevelMonitor();
}
public void Dispose()
{
}
private bool WaitCore(int timeoutMs)
{
try
{
WaiterListEntry waitEntry = t_waitEntry ?? (t_waitEntry = new WaiterListEntry());
waitEntry._monitor.Acquire();
try
{
_waiterStackLock.Acquire();
waitEntry._next = _waiterStackHead;
_waiterStackHead = waitEntry;
_waiterStackLock.Release();
return waitEntry._monitor.Wait(timeoutMs);
}
finally
{
waitEntry._monitor.Release();
}
}
catch (OutOfMemoryException)
{
_fallbackMonitor.Acquire();
try
{
return _fallbackMonitor.Wait(timeoutMs);
}
finally
{
_fallbackMonitor.Release();
}
}
}
private void ReleaseCore(int count)
{
while (count > 0)
{
_waiterStackLock.Acquire();
WaiterListEntry waitEntry = _waiterStackHead;
_waiterStackHead = waitEntry?._next;
_waiterStackLock.Release();
if (waitEntry != null)
{
waitEntry._monitor.Acquire();
waitEntry._monitor.Signal_Release();
count--;
}
else
{
break;
}
}
while (count-- > 0)
{
_fallbackMonitor.Acquire();
_fallbackMonitor.Signal_Release();
}
}
class WaiterListEntry
{
public LowLevelMonitor _monitor;
public WaiterListEntry _next;
public WaiterListEntry()
{
this._monitor = new LowLevelMonitor();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment