Files
ryujinx-ryubing/src/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs
TSRBerry 326749498b [Ryujinx.HLE] Address dotnet-format issues (#5380)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA2211 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address dotnet format CA2208 warnings properly

* Make ProcessResult readonly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix a few disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Use using declaration instead of block syntax

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Fix typo

* Add trailing commas, use targeted new and use array initializer

* Fix build issues

* Fix remaining build issues

* Remove SuppressMessage for CA1069 where possible

* Address dotnet format issues

* Address formatting issues

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Add GetHashCode implementation for RenderingSurfaceInfo

* Explicitly silence CA1822 for every affected method in Syscall

* Address formatting issues in Demangler.cs

* Address review feedback

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Revert marking service methods as static

* Next dotnet format pass

* Address review feedback

---------

Co-authored-by: Ac_K <acoustik666@gmail.com>
2023-07-16 19:31:14 +02:00

219 lines
7.0 KiB
C#

using Ryujinx.Common;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Common
{
class KTimeManager : IDisposable
{
public static readonly long DefaultTimeIncrementNanoseconds = ConvertGuestTicksToNanoseconds(2);
private class WaitingObject
{
public IKFutureSchedulerObject Object { get; }
public long TimePoint { get; }
public WaitingObject(IKFutureSchedulerObject schedulerObj, long timePoint)
{
Object = schedulerObj;
TimePoint = timePoint;
}
}
private readonly KernelContext _context;
private readonly List<WaitingObject> _waitingObjects;
private AutoResetEvent _waitEvent;
private bool _keepRunning;
private long _enforceWakeupFromSpinWait;
private const long NanosecondsPerSecond = 1000000000L;
private const long NanosecondsPerMillisecond = 1000000L;
public KTimeManager(KernelContext context)
{
_context = context;
_waitingObjects = new List<WaitingObject>();
_keepRunning = true;
Thread work = new(WaitAndCheckScheduledObjects)
{
Name = "HLE.TimeManager",
};
work.Start();
}
public void ScheduleFutureInvocation(IKFutureSchedulerObject schedulerObj, long timeout)
{
long startTime = PerformanceCounter.ElapsedTicks;
long timePoint = startTime + ConvertNanosecondsToHostTicks(timeout);
if (timePoint < startTime)
{
timePoint = long.MaxValue;
}
lock (_context.CriticalSection.Lock)
{
_waitingObjects.Add(new WaitingObject(schedulerObj, timePoint));
if (timeout < NanosecondsPerMillisecond)
{
Interlocked.Exchange(ref _enforceWakeupFromSpinWait, 1);
}
}
_waitEvent.Set();
}
public void UnscheduleFutureInvocation(IKFutureSchedulerObject schedulerObj)
{
lock (_context.CriticalSection.Lock)
{
for (int index = _waitingObjects.Count - 1; index >= 0; index--)
{
if (_waitingObjects[index].Object == schedulerObj)
{
_waitingObjects.RemoveAt(index);
}
}
}
}
private void WaitAndCheckScheduledObjects()
{
SpinWait spinWait = new();
WaitingObject next;
using (_waitEvent = new AutoResetEvent(false))
{
while (_keepRunning)
{
lock (_context.CriticalSection.Lock)
{
Interlocked.Exchange(ref _enforceWakeupFromSpinWait, 0);
next = GetNextWaitingObject();
}
if (next != null)
{
long timePoint = PerformanceCounter.ElapsedTicks;
if (next.TimePoint > timePoint)
{
long ms = Math.Min((next.TimePoint - timePoint) / PerformanceCounter.TicksPerMillisecond, int.MaxValue);
if (ms > 0)
{
_waitEvent.WaitOne((int)ms);
}
else
{
while (Interlocked.Read(ref _enforceWakeupFromSpinWait) != 1 && PerformanceCounter.ElapsedTicks < next.TimePoint)
{
// Our time is close - don't let SpinWait go off and potentially Thread.Sleep().
if (spinWait.NextSpinWillYield)
{
Thread.Yield();
spinWait.Reset();
}
else
{
spinWait.SpinOnce();
}
}
spinWait.Reset();
}
}
bool timeUp = PerformanceCounter.ElapsedTicks >= next.TimePoint;
if (timeUp)
{
lock (_context.CriticalSection.Lock)
{
if (_waitingObjects.Remove(next))
{
next.Object.TimeUp();
}
}
}
}
else
{
_waitEvent.WaitOne();
}
}
}
}
private WaitingObject GetNextWaitingObject()
{
WaitingObject selected = null;
long lowestTimePoint = long.MaxValue;
for (int index = _waitingObjects.Count - 1; index >= 0; index--)
{
WaitingObject current = _waitingObjects[index];
if (current.TimePoint <= lowestTimePoint)
{
selected = current;
lowestTimePoint = current.TimePoint;
}
}
return selected;
}
public static long ConvertNanosecondsToMilliseconds(long time)
{
time /= NanosecondsPerMillisecond;
if ((ulong)time > int.MaxValue)
{
return int.MaxValue;
}
return time;
}
public static long ConvertMillisecondsToNanoseconds(long time)
{
return time * NanosecondsPerMillisecond;
}
public static long ConvertNanosecondsToHostTicks(long ns)
{
long nsDiv = ns / NanosecondsPerSecond;
long nsMod = ns % NanosecondsPerSecond;
long tickDiv = PerformanceCounter.TicksPerSecond / NanosecondsPerSecond;
long tickMod = PerformanceCounter.TicksPerSecond % NanosecondsPerSecond;
long baseTicks = (nsMod * tickMod + PerformanceCounter.TicksPerSecond - 1) / NanosecondsPerSecond;
return (nsDiv * tickDiv) * NanosecondsPerSecond + nsDiv * tickMod + nsMod * tickDiv + baseTicks;
}
public static long ConvertGuestTicksToNanoseconds(long ticks)
{
return (long)Math.Ceiling(ticks * (1000000000.0 / 19200000.0));
}
public static long ConvertHostTicksToTicks(long time)
{
return (long)((time / (double)PerformanceCounter.TicksPerSecond) * 19200000.0);
}
public void Dispose()
{
_keepRunning = false;
_waitEvent?.Set();
}
}
}