Implement time:* 4.0.0 commands (#736)
* Abstract SteadyClockCore to follow Nintendo changes in 4.x This is the ground work for 4.0.0 support * Implement TickBasedSteadyClockCore Preparation for the ephemeral clock. * Refactor SystemClockCore to follow 4.0.0 changes * Implement EphemeralNetworkSystemClock * Implement GetSnapshotClock & GetSnapshotClockFromSystemClockContext * Implement CalculateStandardUserSystemClockDifferenceByUser & CalculateSpanBetween * Remove an outdated comment & unused import * Fix a nit and GetClockSnapshot * Address comment
This commit is contained in:
parent
d254548548
commit
54b79dffa8
13 changed files with 518 additions and 205 deletions
|
@ -7,6 +7,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct TimeSpanType
|
||||
{
|
||||
private const long NanoSecondsPerSecond = 1000000000;
|
||||
|
||||
public long NanoSeconds;
|
||||
|
||||
public TimeSpanType(long nanoSeconds)
|
||||
|
@ -16,12 +18,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
|
||||
public long ToSeconds()
|
||||
{
|
||||
return NanoSeconds / 1000000000;
|
||||
return NanoSeconds / NanoSecondsPerSecond;
|
||||
}
|
||||
|
||||
public static TimeSpanType FromSeconds(long seconds)
|
||||
{
|
||||
return new TimeSpanType(seconds * NanoSecondsPerSecond);
|
||||
}
|
||||
|
||||
public static TimeSpanType FromTicks(ulong ticks, ulong frequency)
|
||||
{
|
||||
return new TimeSpanType((long)ticks * 1000000000 / (long)frequency);
|
||||
return FromSeconds((long)ticks / (long)frequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,4 +66,40 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
public long Offset;
|
||||
public SteadyClockTimePoint SteadyTimePoint;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0xD0)]
|
||||
struct ClockSnapshot
|
||||
{
|
||||
public SystemClockContext UserContext;
|
||||
public SystemClockContext NetworkContext;
|
||||
public long UserTime;
|
||||
public long NetworkTime;
|
||||
public CalendarTime UserCalendarTime;
|
||||
public CalendarTime NetworkCalendarTime;
|
||||
public CalendarAdditionalInfo UserCalendarAdditionalTime;
|
||||
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
||||
public SteadyClockTimePoint SteadyClockTimePoint;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
|
||||
public char[] LocationName;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsAutomaticCorrectionEnabled;
|
||||
public byte Type;
|
||||
public ushort Unknown;
|
||||
|
||||
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
||||
{
|
||||
currentTime = 0;
|
||||
|
||||
if (steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId)
|
||||
{
|
||||
currentTime = steadyClockTimePoint.TimePoint + context.Offset;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
return ResultCode.TimeMismatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
class EphemeralNetworkSystemClockCore : SystemClockCore
|
||||
{
|
||||
private static EphemeralNetworkSystemClockCore _instance;
|
||||
|
||||
public static EphemeralNetworkSystemClockCore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new EphemeralNetworkSystemClockCore(TickBasedSteadyClockCore.Instance);
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { }
|
||||
|
||||
public override ResultCode Flush(SystemClockContext context)
|
||||
{
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +1,23 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
class StandardLocalSystemClockCore : SystemClockCore
|
||||
{
|
||||
private SteadyClockCore _steadyClockCore;
|
||||
private SystemClockContext _context;
|
||||
|
||||
private static StandardLocalSystemClockCore instance;
|
||||
private static StandardLocalSystemClockCore _instance;
|
||||
|
||||
public static StandardLocalSystemClockCore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
if (_instance == null)
|
||||
{
|
||||
instance = new StandardLocalSystemClockCore(SteadyClockCore.Instance);
|
||||
_instance = new StandardLocalSystemClockCore(StandardSteadyClockCore.Instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public StandardLocalSystemClockCore(SteadyClockCore steadyClockCore)
|
||||
{
|
||||
_steadyClockCore = steadyClockCore;
|
||||
_context = new SystemClockContext();
|
||||
|
||||
_context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
|
||||
}
|
||||
public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {}
|
||||
|
||||
public override ResultCode Flush(SystemClockContext context)
|
||||
{
|
||||
|
@ -36,24 +25,5 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public override SteadyClockCore GetSteadyClockCore()
|
||||
{
|
||||
return _steadyClockCore;
|
||||
}
|
||||
|
||||
public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
|
||||
{
|
||||
context = _context;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public override ResultCode SetSystemClockContext(SystemClockContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,28 @@
|
|||
using System;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
class StandardNetworkSystemClockCore : SystemClockCore
|
||||
{
|
||||
private SteadyClockCore _steadyClockCore;
|
||||
private SystemClockContext _context;
|
||||
private TimeSpanType _standardNetworkClockSufficientAccuracy;
|
||||
|
||||
private static StandardNetworkSystemClockCore instance;
|
||||
private static StandardNetworkSystemClockCore _instance;
|
||||
|
||||
public static StandardNetworkSystemClockCore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
if (_instance == null)
|
||||
{
|
||||
instance = new StandardNetworkSystemClockCore(SteadyClockCore.Instance);
|
||||
_instance = new StandardNetworkSystemClockCore(StandardSteadyClockCore.Instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public StandardNetworkSystemClockCore(SteadyClockCore steadyClockCore)
|
||||
public StandardNetworkSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore)
|
||||
{
|
||||
_steadyClockCore = steadyClockCore;
|
||||
_context = new SystemClockContext();
|
||||
|
||||
_context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
|
||||
_standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
|
||||
}
|
||||
|
||||
|
@ -40,25 +33,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public override SteadyClockCore GetSteadyClockCore()
|
||||
{
|
||||
return _steadyClockCore;
|
||||
}
|
||||
|
||||
public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
|
||||
{
|
||||
context = _context;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public override ResultCode SetSystemClockContext(SystemClockContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread)
|
||||
{
|
||||
SteadyClockCore steadyClockCore = GetSteadyClockCore();
|
||||
|
@ -66,7 +40,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
|
||||
bool isStandardNetworkClockSufficientAccuracy = false;
|
||||
|
||||
if (_context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
|
||||
ResultCode result = GetSystemClockContext(thread, out SystemClockContext context);
|
||||
|
||||
if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
|
||||
{
|
||||
isStandardNetworkClockSufficientAccuracy = outSpan * 1000000000 < _standardNetworkClockSufficientAccuracy.NanoSeconds;
|
||||
}
|
||||
|
|
107
Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs
Normal file
107
Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Bpc;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
class StandardSteadyClockCore : SteadyClockCore
|
||||
{
|
||||
private long _setupValue;
|
||||
private ResultCode _setupResultCode;
|
||||
private bool _isRtcResetDetected;
|
||||
private TimeSpanType _testOffset;
|
||||
private TimeSpanType _internalOffset;
|
||||
|
||||
private static StandardSteadyClockCore _instance;
|
||||
|
||||
public static StandardSteadyClockCore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new StandardSteadyClockCore();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private StandardSteadyClockCore()
|
||||
{
|
||||
_testOffset = new TimeSpanType(0);
|
||||
_internalOffset = new TimeSpanType(0);
|
||||
}
|
||||
|
||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
{
|
||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||
{
|
||||
TimePoint = 0,
|
||||
ClockSourceId = GetClockSourceId()
|
||||
};
|
||||
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
|
||||
|
||||
result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override TimeSpanType GetTestOffset()
|
||||
{
|
||||
return _testOffset;
|
||||
}
|
||||
|
||||
public override void SetTestOffset(TimeSpanType testOffset)
|
||||
{
|
||||
_testOffset = testOffset;
|
||||
}
|
||||
|
||||
public override ResultCode GetRtcValue(out ulong rtcValue)
|
||||
{
|
||||
return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
|
||||
}
|
||||
|
||||
public bool IsRtcResetDetected()
|
||||
{
|
||||
return _isRtcResetDetected;
|
||||
}
|
||||
|
||||
public override TimeSpanType GetInternalOffset()
|
||||
{
|
||||
return _internalOffset;
|
||||
}
|
||||
|
||||
public override void SetInternalOffset(TimeSpanType internalOffset)
|
||||
{
|
||||
_internalOffset = internalOffset;
|
||||
}
|
||||
|
||||
public override ResultCode GetSetupResultValue()
|
||||
{
|
||||
return _setupResultCode;
|
||||
}
|
||||
|
||||
public void ConfigureSetupValue()
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
ResultCode result = ResultCode.Success;
|
||||
|
||||
while (retry < 20)
|
||||
{
|
||||
result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
_setupValue = (long)rtcValue;
|
||||
break;
|
||||
}
|
||||
|
||||
retry++;
|
||||
}
|
||||
|
||||
_setupResultCode = result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,22 +8,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
private StandardNetworkSystemClockCore _networkSystemClockCore;
|
||||
private bool _autoCorrectionEnabled;
|
||||
|
||||
private static StandardUserSystemClockCore instance;
|
||||
private static StandardUserSystemClockCore _instance;
|
||||
|
||||
public static StandardUserSystemClockCore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
if (_instance == null)
|
||||
{
|
||||
instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance);
|
||||
_instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore)
|
||||
public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore) : base(localSystemClockCore.GetSteadyClockCore())
|
||||
{
|
||||
_localSystemClockCore = localSystemClockCore;
|
||||
_networkSystemClockCore = networkSystemClockCore;
|
||||
|
@ -35,11 +35,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
public override SteadyClockCore GetSteadyClockCore()
|
||||
{
|
||||
return _localSystemClockCore.GetSteadyClockCore();
|
||||
}
|
||||
|
||||
public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
|
||||
{
|
||||
ResultCode result = ApplyAutomaticCorrection(thread, false);
|
||||
|
|
|
@ -1,54 +1,16 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Bpc;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
class SteadyClockCore
|
||||
abstract class SteadyClockCore
|
||||
{
|
||||
private long _setupValue;
|
||||
private ResultCode _setupResultCode;
|
||||
private bool _isRtcResetDetected;
|
||||
private TimeSpanType _testOffset;
|
||||
private TimeSpanType _internalOffset;
|
||||
private UInt128 _clockSourceId;
|
||||
private UInt128 _clockSourceId;
|
||||
|
||||
private static SteadyClockCore instance;
|
||||
|
||||
public static SteadyClockCore Instance
|
||||
public SteadyClockCore()
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new SteadyClockCore();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private SteadyClockCore()
|
||||
{
|
||||
_testOffset = new TimeSpanType(0);
|
||||
_internalOffset = new TimeSpanType(0);
|
||||
_clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
|
||||
}
|
||||
|
||||
private SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
{
|
||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||
{
|
||||
TimePoint = 0,
|
||||
ClockSourceId = _clockSourceId
|
||||
};
|
||||
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
|
||||
|
||||
result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
|
||||
|
||||
return result;
|
||||
_clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
|
||||
}
|
||||
|
||||
public UInt128 GetClockSourceId()
|
||||
|
@ -56,76 +18,45 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
return _clockSourceId;
|
||||
}
|
||||
|
||||
public virtual TimeSpanType GetTestOffset()
|
||||
{
|
||||
return new TimeSpanType(0);
|
||||
}
|
||||
|
||||
public virtual void SetTestOffset(TimeSpanType testOffset) {}
|
||||
|
||||
public virtual ResultCode GetRtcValue(out ulong rtcValue)
|
||||
{
|
||||
rtcValue = 0;
|
||||
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
public virtual ResultCode GetSetupResultValue()
|
||||
{
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
public virtual TimeSpanType GetInternalOffset()
|
||||
{
|
||||
return new TimeSpanType(0);
|
||||
}
|
||||
|
||||
public virtual void SetInternalOffset(TimeSpanType internalOffset) {}
|
||||
|
||||
public virtual SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
|
||||
{
|
||||
SteadyClockTimePoint result = GetTimePoint(thread);
|
||||
|
||||
result.TimePoint += _testOffset.ToSeconds();
|
||||
result.TimePoint += _internalOffset.ToSeconds();
|
||||
result.TimePoint += GetTestOffset().ToSeconds();
|
||||
result.TimePoint += GetInternalOffset().ToSeconds();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public TimeSpanType GetTestOffset()
|
||||
{
|
||||
return _testOffset;
|
||||
}
|
||||
|
||||
public void SetTestOffset(TimeSpanType testOffset)
|
||||
{
|
||||
_testOffset = testOffset;
|
||||
}
|
||||
|
||||
public ResultCode GetRtcValue(out ulong rtcValue)
|
||||
{
|
||||
return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
|
||||
}
|
||||
|
||||
public bool IsRtcResetDetected()
|
||||
{
|
||||
return _isRtcResetDetected;
|
||||
}
|
||||
|
||||
public ResultCode GetSetupResultCode()
|
||||
{
|
||||
return _setupResultCode;
|
||||
}
|
||||
|
||||
public TimeSpanType GetInternalOffset()
|
||||
{
|
||||
return _internalOffset;
|
||||
}
|
||||
|
||||
public void SetInternalOffset(TimeSpanType internalOffset)
|
||||
{
|
||||
_internalOffset = internalOffset;
|
||||
}
|
||||
|
||||
public ResultCode GetSetupResultValue()
|
||||
{
|
||||
return _setupResultCode;
|
||||
}
|
||||
|
||||
public void ConfigureSetupValue()
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
ResultCode result = ResultCode.Success;
|
||||
|
||||
while (retry < 20)
|
||||
{
|
||||
result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
_setupValue = (long)rtcValue;
|
||||
break;
|
||||
}
|
||||
|
||||
retry++;
|
||||
}
|
||||
|
||||
_setupResultCode = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,35 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||
{
|
||||
abstract class SystemClockCore
|
||||
{
|
||||
public abstract SteadyClockCore GetSteadyClockCore();
|
||||
private SteadyClockCore _steadyClockCore;
|
||||
private SystemClockContext _context;
|
||||
|
||||
public abstract ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context);
|
||||
public SystemClockCore(SteadyClockCore steadyClockCore)
|
||||
{
|
||||
_steadyClockCore = steadyClockCore;
|
||||
_context = new SystemClockContext();
|
||||
|
||||
public abstract ResultCode SetSystemClockContext(SystemClockContext context);
|
||||
_context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
|
||||
}
|
||||
|
||||
public virtual SteadyClockCore GetSteadyClockCore()
|
||||
{
|
||||
return _steadyClockCore;
|
||||
}
|
||||
|
||||
public virtual ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
|
||||
{
|
||||
context = _context;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public virtual ResultCode SetSystemClockContext(SystemClockContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public abstract ResultCode Flush(SystemClockContext context);
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
class TickBasedSteadyClockCore : SteadyClockCore
|
||||
{
|
||||
private static TickBasedSteadyClockCore _instance;
|
||||
|
||||
public static TickBasedSteadyClockCore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new TickBasedSteadyClockCore();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private TickBasedSteadyClockCore() {}
|
||||
|
||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
{
|
||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||
{
|
||||
TimePoint = 0,
|
||||
ClockSourceId = GetClockSourceId()
|
||||
};
|
||||
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
|
||||
|
||||
result.TimePoint = ticksTimeSpan.ToSeconds();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue