diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockContextWriter.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockContextWriter.cs new file mode 100644 index 0000000000..14d3cb244a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockContextWriter.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class EphemeralNetworkSystemClockContextWriter : SystemClockContextUpdateCallback + { + protected override ResultCode Update() + { + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs index 8ab8a002b0..003863e4cf 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs @@ -3,10 +3,5 @@ class EphemeralNetworkSystemClockCore : SystemClockCore { public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { } - - protected override ResultCode Flush(SystemClockContext context) - { - return ResultCode.Success; - } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/LocalSystemClockContextWriter.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/LocalSystemClockContextWriter.cs new file mode 100644 index 0000000000..d91084f852 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/LocalSystemClockContextWriter.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class LocalSystemClockContextWriter : SystemClockContextUpdateCallback + { + private TimeSharedMemory _sharedMemory; + + public LocalSystemClockContextWriter(TimeSharedMemory sharedMemory) + { + _sharedMemory = sharedMemory; + } + + protected override ResultCode Update() + { + _sharedMemory.UpdateLocalSystemClockContext(_context); + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/NetworkSystemClockContextWriter.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/NetworkSystemClockContextWriter.cs new file mode 100644 index 0000000000..c47203538c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/NetworkSystemClockContextWriter.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + class NetworkSystemClockContextWriter : SystemClockContextUpdateCallback + { + private TimeSharedMemory _sharedMemory; + + public NetworkSystemClockContextWriter(TimeSharedMemory sharedMemory) + { + _sharedMemory = sharedMemory; + } + + protected override ResultCode Update() + { + _sharedMemory.UpdateNetworkSystemClockContext(_context); + return ResultCode.Success; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs index 7c91de4bc7..20c334e862 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs @@ -3,12 +3,5 @@ class StandardLocalSystemClockCore : SystemClockCore { public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {} - - protected override ResultCode Flush(SystemClockContext context) - { - // TODO: set:sys SetUserSystemClockContext - - return ResultCode.Success; - } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs index bdd45e2e0c..b86f703dbe 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -11,13 +11,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _standardNetworkClockSufficientAccuracy = new TimeSpanType(0); } - protected override ResultCode Flush(SystemClockContext context) - { - // TODO: set:sys SetNetworkSystemClockContext - - return ResultCode.Success; - } - public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread) { SteadyClockCore steadyClockCore = GetSteadyClockCore(); diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs index 7b2249cc26..5605fe6043 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs @@ -1,4 +1,5 @@ using Ryujinx.HLE.HOS.Kernel.Threading; +using System; namespace Ryujinx.HLE.HOS.Services.Time.Clock { @@ -16,13 +17,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _networkSystemClockCore = networkSystemClockCore; _autoCorrectionEnabled = false; _autoCorrectionTime = SteadyClockTimePoint.GetRandom(); - - _autoCorrectionEvent = null; + _autoCorrectionEvent = null; } protected override ResultCode Flush(SystemClockContext context) { - return ResultCode.NotImplemented; + // As UserSystemClock isn't a real system clock, this shouldn't happens. + throw new NotImplementedException(); } public override ResultCode GetClockContext(KThread thread, out SystemClockContext context) @@ -83,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return _autoCorrectionEnabled; } + public KReadableEvent GetAutomaticCorrectionReadableEvent() + { + return _autoCorrectionEvent.ReadableEvent; + } + public void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steadyClockTimePoint) { _autoCorrectionTime = steadyClockTimePoint; diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockContextUpdateCallback.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockContextUpdateCallback.cs new file mode 100644 index 0000000000..554dc911c3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockContextUpdateCallback.cs @@ -0,0 +1,64 @@ +using Ryujinx.HLE.HOS.Kernel.Threading; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + abstract class SystemClockContextUpdateCallback + { + private List _operationEventList; + protected SystemClockContext _context; + private bool _hasContext; + + public SystemClockContextUpdateCallback() + { + _operationEventList = new List(); + _context = new SystemClockContext(); + _hasContext = false; + } + + private bool NeedUpdate(SystemClockContext context) + { + if (_hasContext) + { + return _context.Offset != context.Offset || _context.SteadyTimePoint.ClockSourceId != context.SteadyTimePoint.ClockSourceId; + } + + return true; + } + + private void BroadcastOperationEvent() + { + Monitor.Enter(_operationEventList); + + foreach (KEvent e in _operationEventList) + { + e.WritableEvent.Signal(); + } + + Monitor.Exit(_operationEventList); + } + + protected abstract ResultCode Update(); + + public ResultCode Update(SystemClockContext context) + { + ResultCode result = ResultCode.Success; + + if (NeedUpdate(context)) + { + _context = context; + _hasContext = true; + + result = Update(); + + if (result == ResultCode.Success) + { + BroadcastOperationEvent(); + } + } + + return result; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs index 39f5180bd7..76ab575928 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs @@ -4,9 +4,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { abstract class SystemClockCore { - private SteadyClockCore _steadyClockCore; - private SystemClockContext _context; - private bool _isInitialized; + private SteadyClockCore _steadyClockCore; + private SystemClockContext _context; + private bool _isInitialized; + private SystemClockContextUpdateCallback _systemClockContextUpdateCallback; public SystemClockCore(SteadyClockCore steadyClockCore) { @@ -15,6 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _isInitialized = false; _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId(); + _systemClockContextUpdateCallback = null; } public virtual SteadyClockCore GetSteadyClockCore() @@ -79,7 +81,20 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return ResultCode.Success; } - protected abstract ResultCode Flush(SystemClockContext context); + protected virtual ResultCode Flush(SystemClockContext context) + { + if (_systemClockContextUpdateCallback == null) + { + return ResultCode.Success; + } + + return _systemClockContextUpdateCallback.Update(context); + } + + public void SetUpdateCallbackInstance(SystemClockContextUpdateCallback systemClockContextUpdateCallback) + { + _systemClockContextUpdateCallback = systemClockContextUpdateCallback; + } public ResultCode SetSystemClockContext(SystemClockContext context) { diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs index 7caea7540f..372f55dd7e 100644 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs @@ -154,7 +154,7 @@ namespace Ryujinx.HLE.HOS.Services.Time { if (_automaticCorrectionEvent == 0) { - if (context.Process.HandleTable.GenerateHandle(_timeManager.SharedMemory.GetSharedMemory(), out _automaticCorrectionEvent) != KernelResult.Success) + if (context.Process.HandleTable.GenerateHandle(_timeManager.StandardUserSystemClock.GetAutomaticCorrectionReadableEvent(), out _automaticCorrectionEvent) != KernelResult.Success) { throw new InvalidOperationException("Out of handles!"); } diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs index ca8c7857c3..0964132168 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs @@ -24,16 +24,18 @@ namespace Ryujinx.HLE.HOS.Services.Time } } - public StandardSteadyClockCore StandardSteadyClock { get; private set; } - public TickBasedSteadyClockCore TickBasedSteadyClock { get; private set; } - public StandardLocalSystemClockCore StandardLocalSystemClock { get; private set; } - public StandardNetworkSystemClockCore StandardNetworkSystemClock { get; private set; } - public StandardUserSystemClockCore StandardUserSystemClock { get; private set; } - public TimeZoneManager TimeZone { get; private set; } - public EphemeralNetworkSystemClockCore EphemeralNetworkSystemClock { get; private set; } - public TimeSharedMemory SharedMemory { get; private set; } - - // TODO: 9.0.0+ power state, alarms, clock writers + public StandardSteadyClockCore StandardSteadyClock { get; private set; } + public TickBasedSteadyClockCore TickBasedSteadyClock { get; private set; } + public StandardLocalSystemClockCore StandardLocalSystemClock { get; private set; } + public StandardNetworkSystemClockCore StandardNetworkSystemClock { get; private set; } + public StandardUserSystemClockCore StandardUserSystemClock { get; private set; } + public TimeZoneManager TimeZone { get; private set; } + public EphemeralNetworkSystemClockCore EphemeralNetworkSystemClock { get; private set; } + public TimeSharedMemory SharedMemory { get; private set; } + // TODO: 9.0.0+ power states and alarms + public LocalSystemClockContextWriter LocalClockContextWriter { get; private set; } + public NetworkSystemClockContextWriter NetworkClockContextWriter { get; private set; } + public EphemeralNetworkSystemClockContextWriter EphemeralClockContextWriter { get; private set; } public TimeManager() { @@ -45,6 +47,9 @@ namespace Ryujinx.HLE.HOS.Services.Time TimeZone = new TimeZoneManager(); EphemeralNetworkSystemClock = new EphemeralNetworkSystemClockCore(StandardSteadyClock); SharedMemory = new TimeSharedMemory(); + LocalClockContextWriter = new LocalSystemClockContextWriter(SharedMemory); + NetworkClockContextWriter = new NetworkSystemClockContextWriter(SharedMemory); + EphemeralClockContextWriter = new EphemeralNetworkSystemClockContextWriter(); } public void Initialize(Switch device, Horizon system, KSharedMemory sharedMemory, long timeSharedMemoryAddress, int timeSharedMemorySize) @@ -87,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Services.Time public void SetupStandardLocalSystemClock(KThread thread, SystemClockContext clockContext, long posixTime) { + StandardLocalSystemClock.SetUpdateCallbackInstance(LocalClockContextWriter); + SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(thread); if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) { @@ -106,6 +113,8 @@ namespace Ryujinx.HLE.HOS.Services.Time public void SetupStandardNetworkSystemClock(SystemClockContext clockContext, TimeSpanType sufficientAccuracy) { + StandardNetworkSystemClock.SetUpdateCallbackInstance(NetworkClockContextWriter); + // TODO: if the result of this is wrong, abort StandardNetworkSystemClock.SetSystemClockContext(clockContext); @@ -118,6 +127,7 @@ namespace Ryujinx.HLE.HOS.Services.Time public void SetupEphemeralNetworkSystemClock() { + EphemeralNetworkSystemClock.SetUpdateCallbackInstance(EphemeralClockContextWriter); EphemeralNetworkSystemClock.MarkInitialized(); // TODO: propagate IPC late binding of "time:s" and "time:p" diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs b/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs index 8b51206323..4c2d4f614e 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs @@ -42,5 +42,15 @@ namespace Ryujinx.HLE.HOS.Services.Time { // TODO } + + public void UpdateLocalSystemClockContext(SystemClockContext context) + { + // TODO + } + + public void UpdateNetworkSystemClockContext(SystemClockContext context) + { + // TODO + } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs index 28aed3d262..a1fc6646ae 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs @@ -13,6 +13,7 @@ using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { + // TODO: rewrite it for psc/glue changes + readd a correct locking around this public sealed class TimeZoneManager { private const long TimeZoneBinaryTitleId = 0x010000000000080E;