mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2025-02-09 13:14:46 +01:00
Add IDeviceEventSimulator and implement some of the Os namespace
This commit is contained in:
parent
981b902606
commit
b315e14da0
@ -160,6 +160,8 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
||||
2,2500,2999,,,GameCardAccessFailed,
|
||||
2,2503,,,,InvalidBufferForGameCard,
|
||||
2,2520,,,,GameCardNotInserted,
|
||||
2,2531,,,,GameCardCardAccessTimeout,
|
||||
|
||||
2,2951,,,,GameCardNotInsertedOnGetHandle,
|
||||
2,2952,,,,InvalidGameCardHandleOnRead,
|
||||
2,2954,,,,InvalidGameCardHandleOnGetCardInfo,
|
||||
@ -517,6 +519,7 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
||||
|
||||
2,4771,4779,,,SignedSystemPartitionDataCorrupted,
|
||||
2,4781,,,,GameCardLogoDataCorrupted,
|
||||
2,4785,,,,SimulatedDeviceDataCorrupted,
|
||||
|
||||
2,4790,4799,,,MultiCommitContextCorrupted,
|
||||
2,4791,,,,InvalidMultiCommitContextVersion,The version of the multi-commit context file is too high for the current MultiCommitManager implementation.
|
||||
@ -863,10 +866,11 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
|
||||
10,811,819,a,,RequestDeferred,
|
||||
10,812,,,,RequestDeferredByUser,
|
||||
|
||||
11,1,,,,NotSupported,
|
||||
11,100,299,a,,OutOfResource,
|
||||
11,102,,,,OutOfSessionMemory,
|
||||
11,131,139,,,OutOfSessions,
|
||||
11,141,,,,PointerBufferTooSmall,
|
||||
11,141,,,,InsufficientPointerTransferBuffer,
|
||||
|
||||
11,200,,,,OutOfDomains,
|
||||
11,301,,,,SessionClosed,
|
||||
|
|
95
src/LibHac/Common/InitializationGuard.cs
Normal file
95
src/LibHac/Common/InitializationGuard.cs
Normal file
@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibHac.Common
|
||||
{
|
||||
internal readonly ref struct InitializationGuard
|
||||
{
|
||||
private readonly Ref<nint> _guard;
|
||||
private readonly object _mutex;
|
||||
public bool IsInitialized => _mutex == null;
|
||||
|
||||
private const byte GuardBitComplete = 1 << 0;
|
||||
|
||||
[Flags]
|
||||
private enum InitStatus : byte
|
||||
{
|
||||
Complete = 1 << 0,
|
||||
Pending = 1 << 1,
|
||||
Waiting = 1 << 2
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public InitializationGuard(ref nint guard, object mutex)
|
||||
{
|
||||
if (IsGuardInitialized(guard) || !AcquireGuard(ref guard, mutex))
|
||||
{
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
|
||||
_guard = new Ref<nint>(ref guard);
|
||||
_mutex = mutex;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose()
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
ReleaseGuard(ref _guard.Value, _mutex);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AcquireGuard(ref nint guard, object mutex)
|
||||
{
|
||||
if (SpanHelpers.AsByteSpan(ref guard)[0] == GuardBitComplete)
|
||||
return false;
|
||||
|
||||
return AcquireInitByte(ref Unsafe.As<byte, InitStatus>(ref SpanHelpers.AsByteSpan(ref guard)[1]), mutex);
|
||||
}
|
||||
|
||||
public static void ReleaseGuard(ref nint guard, object mutex)
|
||||
{
|
||||
SpanHelpers.AsByteSpan(ref guard)[0] = GuardBitComplete;
|
||||
|
||||
ReleaseInitByte(ref Unsafe.As<byte, InitStatus>(ref SpanHelpers.AsByteSpan(ref guard)[1]), mutex);
|
||||
}
|
||||
|
||||
private static bool AcquireInitByte(ref InitStatus initByte, object mutex)
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
while (initByte.HasFlag(InitStatus.Pending))
|
||||
{
|
||||
initByte |= InitStatus.Waiting;
|
||||
Monitor.Wait(mutex);
|
||||
}
|
||||
|
||||
if (initByte == InitStatus.Complete)
|
||||
return false;
|
||||
|
||||
initByte = InitStatus.Pending;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReleaseInitByte(ref InitStatus initByte, object mutex)
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
bool hasWaiting = initByte.HasFlag(InitStatus.Waiting);
|
||||
initByte = InitStatus.Complete;
|
||||
|
||||
if (hasWaiting)
|
||||
Monitor.PulseAll(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsGuardInitialized(nint guard)
|
||||
{
|
||||
return (guard & 1) != 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.Fs
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public static class AccessLogHelpers
|
||||
{
|
||||
public static string BuildDefaultLogLine(Result result, TimeSpan startTime, TimeSpan endTime, int handleId,
|
||||
public static string BuildDefaultLogLine(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId,
|
||||
string message, string caller)
|
||||
{
|
||||
return
|
||||
$"FS_ACCESS: {{ start: {(long) startTime.TotalMilliseconds,9}, end: {(long) endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}";
|
||||
$"FS_ACCESS: {{ start: {(long)startTime.TotalMilliseconds,9}, end: {(long)endTime.TotalMilliseconds,9}, result: 0x{result.Value:x8}, handle: 0x{handleId:x8}, function: \"{caller}\"{message} }}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,13 @@ namespace LibHac.Fs
|
||||
[FieldOffset(0x28)] public int RomFsRecoveredByInvalidateCacheCount;
|
||||
[FieldOffset(0x2C)] public int SaveDataIndexCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x10)]
|
||||
public struct StorageErrorInfo
|
||||
{
|
||||
[FieldOffset(0x00)] public int NumActivationFailures;
|
||||
[FieldOffset(0x04)] public int NumActivationErrorCorrections;
|
||||
[FieldOffset(0x08)] public int NumReadWriteFailures;
|
||||
[FieldOffset(0x0C)] public int NumReadWriteErrorCorrections;
|
||||
}
|
||||
}
|
@ -136,22 +136,22 @@ namespace LibHac.Fs
|
||||
return handle.Directory.Parent.IsAccessLogEnabled;
|
||||
}
|
||||
|
||||
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "")
|
||||
internal void OutputAccessLog(Result result, System.TimeSpan startTime, System.TimeSpan endTime, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
OutputAccessLogImpl(result, startTime, endTime, 0, message, caller);
|
||||
}
|
||||
|
||||
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
internal void OutputAccessLog(Result result, System.TimeSpan startTime, System.TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
OutputAccessLogImpl(result, startTime, endTime, handle.GetId(), message, caller);
|
||||
}
|
||||
|
||||
internal void OutputAccessLog(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
internal void OutputAccessLog(Result result, System.TimeSpan startTime, System.TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
OutputAccessLogImpl(result, startTime, endTime, handle.GetId(), message, caller);
|
||||
}
|
||||
|
||||
internal void OutputAccessLogUnlessResultSuccess(Result result, TimeSpan startTime, TimeSpan endTime, string message, [CallerMemberName] string caller = "")
|
||||
internal void OutputAccessLogUnlessResultSuccess(Result result, System.TimeSpan startTime, System.TimeSpan endTime, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (result.IsFailure())
|
||||
{
|
||||
@ -159,7 +159,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
internal void OutputAccessLogUnlessResultSuccess(Result result, TimeSpan startTime, TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
internal void OutputAccessLogUnlessResultSuccess(Result result, System.TimeSpan startTime, System.TimeSpan endTime, FileHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (result.IsFailure())
|
||||
{
|
||||
@ -167,7 +167,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
internal void OutputAccessLogUnlessResultSuccess(Result result, TimeSpan startTime, TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
internal void OutputAccessLogUnlessResultSuccess(Result result, System.TimeSpan startTime, System.TimeSpan endTime, DirectoryHandle handle, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (result.IsFailure())
|
||||
{
|
||||
@ -175,7 +175,7 @@ namespace LibHac.Fs
|
||||
}
|
||||
}
|
||||
|
||||
internal void OutputAccessLogImpl(Result result, TimeSpan startTime, TimeSpan endTime, int handleId,
|
||||
internal void OutputAccessLogImpl(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId,
|
||||
string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (GlobalAccessLogMode.HasFlag(GlobalAccessLogMode.Log))
|
||||
@ -199,9 +199,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog(logTarget))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = operation();
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, textGenerator(), caller);
|
||||
}
|
||||
@ -220,9 +220,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog(logTarget) && handle.File.Parent.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = operation();
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, handle, textGenerator(), caller);
|
||||
}
|
||||
@ -241,9 +241,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog(logTarget))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = operation();
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLogUnlessResultSuccess(rc, startTime, endTime, textGenerator(), caller);
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = handle.Directory.Read(out entriesRead, entryBuffer);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, handle, string.Empty);
|
||||
}
|
||||
@ -33,9 +33,9 @@ namespace LibHac.Fs
|
||||
{
|
||||
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
handle.Directory.Dispose();
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(Result.Success, startTime, endTime, handle, string.Empty);
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = handle.File.Read(out bytesRead, offset, destination, in option);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}");
|
||||
}
|
||||
@ -55,9 +55,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = handle.File.Write(offset, source, in option);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
string optionString = option.HasFlushFlag() ? "" : $", write_option: {option}";
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Accessors;
|
||||
using LibHac.Fs.Fsa;
|
||||
@ -14,9 +13,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.CreateDirectory(subPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
|
||||
}
|
||||
@ -40,9 +39,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.CreateFile(subPath, size, options);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\", size: {size}");
|
||||
}
|
||||
@ -61,9 +60,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.DeleteDirectory(subPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
|
||||
}
|
||||
@ -82,9 +81,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.DeleteDirectoryRecursively(subPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
|
||||
}
|
||||
@ -103,9 +102,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.CleanDirectoryRecursively(subPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
|
||||
}
|
||||
@ -124,9 +123,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.DeleteFile(subPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
|
||||
}
|
||||
@ -153,9 +152,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = oldFileSystem.RenameDirectory(oldSubPath, newSubPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath.ToString()}\", new_path: \"{newPath.ToString()}\"");
|
||||
}
|
||||
@ -182,9 +181,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = oldFileSystem.RenameFile(oldSubPath, newSubPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath.ToString()}\", new_path: \"{newPath.ToString()}\"");
|
||||
}
|
||||
@ -205,9 +204,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.GetEntryType(out type, subPath);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\"");
|
||||
}
|
||||
@ -228,10 +227,10 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.OpenFile(out FileAccessor file, subPath, mode);
|
||||
handle = new FileHandle(file);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path.ToString()}\", open_mode: {mode}");
|
||||
}
|
||||
@ -253,10 +252,10 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath, mode);
|
||||
handle = new DirectoryHandle(dir);
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path.ToString()}\", open_mode: {mode}");
|
||||
}
|
||||
@ -306,9 +305,9 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled)
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
rc = fileSystem.Commit();
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
|
||||
OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\"");
|
||||
}
|
||||
|
@ -156,11 +156,11 @@ namespace LibHac.Fs
|
||||
|
||||
if (IsEnabledAccessLog() && IsEnabledFileSystemAccessorAccessLog(mountName))
|
||||
{
|
||||
TimeSpan startTime = Time.GetCurrent();
|
||||
System.TimeSpan startTime = Time.GetCurrent();
|
||||
|
||||
rc = MountTable.Unmount(mountNameStr);
|
||||
|
||||
TimeSpan endTime = Time.GetCurrent();
|
||||
System.TimeSpan endTime = Time.GetCurrent();
|
||||
OutputAccessLog(rc, startTime, endTime, $", name: \"{mountNameStr}\"");
|
||||
}
|
||||
else
|
||||
|
@ -199,10 +199,26 @@ namespace LibHac.Fs
|
||||
}
|
||||
|
||||
public enum SimulatingDeviceDetectionMode
|
||||
{
|
||||
NoSimulation = 0,
|
||||
DeviceAttached = 1,
|
||||
DeviceRemoved = 2
|
||||
}
|
||||
|
||||
public enum SimulatingDeviceAccessFailureEventType
|
||||
{
|
||||
None = 0,
|
||||
Inserted = 1,
|
||||
NotInserted = 2
|
||||
AccessTimeoutFailure = 1,
|
||||
AccessFailure = 2,
|
||||
DataCorruption = 3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SimulatingDeviceTargetOperation
|
||||
{
|
||||
None = 0,
|
||||
Read = 1 << 0,
|
||||
Write = 1 << 1
|
||||
}
|
||||
|
||||
public enum FsStackUsageThreadType
|
||||
@ -211,4 +227,34 @@ namespace LibHac.Fs
|
||||
IpcWorker = 1,
|
||||
PipelineWorker = 2
|
||||
}
|
||||
|
||||
public enum MmcPartition
|
||||
{
|
||||
UserData = 0,
|
||||
BootPartition1 = 1,
|
||||
BootPartition2 = 2
|
||||
}
|
||||
|
||||
public enum MmcSpeedMode
|
||||
{
|
||||
Identification = 0,
|
||||
LegacySpeed = 1,
|
||||
HighSpeed = 2,
|
||||
Hs200 = 3,
|
||||
Hs400 = 4,
|
||||
Unknown = 5
|
||||
}
|
||||
|
||||
public enum SdCardSpeedMode
|
||||
{
|
||||
Identification = 0,
|
||||
DefaultSpeed = 1,
|
||||
HighSpeed = 2,
|
||||
Sdr12 = 3,
|
||||
Sdr25 = 4,
|
||||
Sdr50 = 5,
|
||||
Sdr104 = 6,
|
||||
Ddr50 = 7,
|
||||
Unknown = 8,
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public interface IAccessLog
|
||||
{
|
||||
void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "");
|
||||
void Log(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "");
|
||||
}
|
||||
}
|
@ -17,6 +17,18 @@ namespace LibHac.Fs.Impl
|
||||
{
|
||||
BaseStorage = baseStorage.AddReference();
|
||||
}
|
||||
|
||||
protected StorageServiceObjectAdapter(ref ReferenceCountedDisposable<IStorageSf> baseStorage)
|
||||
{
|
||||
BaseStorage = Shared.Move(ref baseStorage);
|
||||
}
|
||||
|
||||
public static ReferenceCountedDisposable<IStorage> CreateShared(
|
||||
ref ReferenceCountedDisposable<IStorageSf> baseStorage)
|
||||
{
|
||||
return new ReferenceCountedDisposable<IStorage>(new StorageServiceObjectAdapter(ref baseStorage));
|
||||
}
|
||||
|
||||
protected override Result DoRead(long offset, Span<byte> destination)
|
||||
{
|
||||
return BaseStorage.Target.Read(offset, destination);
|
||||
|
@ -232,6 +232,8 @@ namespace LibHac.Fs
|
||||
public static Result.Base InvalidBufferForGameCard => new Result.Base(ModuleFs, 2503);
|
||||
/// <summary>Error code: 2002-2520; Inner value: 0x13b002</summary>
|
||||
public static Result.Base GameCardNotInserted => new Result.Base(ModuleFs, 2520);
|
||||
/// <summary>Error code: 2002-2531; Inner value: 0x13c602</summary>
|
||||
public static Result.Base GameCardCardAccessTimeout => new Result.Base(ModuleFs, 2531);
|
||||
/// <summary>Error code: 2002-2951; Inner value: 0x170e02</summary>
|
||||
public static Result.Base GameCardNotInsertedOnGetHandle => new Result.Base(ModuleFs, 2951);
|
||||
/// <summary>Error code: 2002-2952; Inner value: 0x171002</summary>
|
||||
@ -907,6 +909,8 @@ namespace LibHac.Fs
|
||||
|
||||
/// <summary>Error code: 2002-4781; Inner value: 0x255a02</summary>
|
||||
public static Result.Base GameCardLogoDataCorrupted => new Result.Base(ModuleFs, 4781);
|
||||
/// <summary>Error code: 2002-4785; Inner value: 0x256202</summary>
|
||||
public static Result.Base SimulatedDeviceDataCorrupted => new Result.Base(ModuleFs, 4785);
|
||||
|
||||
/// <summary>Error code: 2002-4790; Range: 4790-4799; Inner value: 0x256c02</summary>
|
||||
public static Result.Base MultiCommitContextCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4790, 4799); }
|
||||
|
@ -8,7 +8,7 @@ namespace LibHac.Fs
|
||||
/// </summary>
|
||||
public class SdCardAccessLog : IAccessLog
|
||||
{
|
||||
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, string caller = "")
|
||||
public void Log(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId, string message, string caller = "")
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
|
||||
@ -14,9 +13,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = Run(fs, mountName, path);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, "");
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
|
||||
@ -14,9 +13,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountBcatSaveDataImpl(fs, mountName, applicationId);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
string logMessage = $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}\"";
|
||||
|
||||
|
@ -59,9 +59,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountBisImpl(fs, mountName, partitionId, rootPath);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
string logMessage = $", name: \"{mountName.ToString()}\", bispartitionid: {partitionId}, path: \"{rootPath.ToString()}\"";
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
@ -17,9 +16,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountCodeImpl(fs, out verificationData, mountName, path, programId);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime,
|
||||
$", name: \"{mountName.ToString()}\", name: \"{path.ToString()}\", programid: 0x{programId}");
|
||||
|
@ -205,9 +205,9 @@ namespace LibHac.Fs.Shim
|
||||
logMessage = $", name: \"{mountName.ToString()}\"";
|
||||
}
|
||||
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = PreMountHost(out nameGenerator, mountName, path);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLogUnlessResultSuccess(rc, startTime, endTime, logMessage, caller);
|
||||
}
|
||||
@ -222,9 +222,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = OpenHostFileSystem(fs, out hostFileSystem, mountName, path, option);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLogUnlessResultSuccess(rc, startTime, endTime, logMessage, caller);
|
||||
}
|
||||
@ -237,9 +237,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = fs.Register(mountName, hostFileSystem, nameGenerator);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, logMessage, caller);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Ncm;
|
||||
@ -15,9 +14,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, userId, SaveDataType.Account, false, 0);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}, userid: 0x{userId}");
|
||||
}
|
||||
@ -40,9 +39,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, userId, SaveDataType.Account, true, 0);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}, userid: 0x{userId}");
|
||||
}
|
||||
@ -65,9 +64,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.Temporary, default, default, SaveDataType.Temporary, false, 0);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\"");
|
||||
}
|
||||
@ -90,9 +89,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, default, default, SaveDataType.Cache, false, 0);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\"");
|
||||
}
|
||||
@ -115,9 +114,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, default, default, SaveDataType.Cache, false, (ushort)index);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", index: {index}");
|
||||
}
|
||||
@ -140,9 +139,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, default, SaveDataType.Cache, false, 0);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}");
|
||||
}
|
||||
@ -165,9 +164,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, default, SaveDataType.Cache, false, (ushort)index);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}, index: {index}");
|
||||
}
|
||||
|
@ -421,9 +421,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (FsClient.IsEnabledAccessLog(AccessLogTarget.System))
|
||||
{
|
||||
TimeSpan startTime = FsClient.Time.GetCurrent();
|
||||
System.TimeSpan startTime = FsClient.Time.GetCurrent();
|
||||
rc = Reader.Target.Read(out readCount, byteBuffer);
|
||||
TimeSpan endTime = FsClient.Time.GetCurrent();
|
||||
System.TimeSpan endTime = FsClient.Time.GetCurrent();
|
||||
|
||||
FsClient.OutputAccessLog(rc, startTime, endTime, $", size: {buffer.Length}");
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
|
||||
@ -14,9 +13,9 @@ namespace LibHac.Fs.Shim
|
||||
|
||||
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
|
||||
{
|
||||
TimeSpan startTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan startTime = fs.Time.GetCurrent();
|
||||
rc = Run(fs, mountName);
|
||||
TimeSpan endTime = fs.Time.GetCurrent();
|
||||
System.TimeSpan endTime = fs.Time.GetCurrent();
|
||||
|
||||
fs.OutputAccessLog(rc, startTime, endTime, "");
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ namespace LibHac.FsSrv
|
||||
public bool IsDebugMode { get; }
|
||||
private ITimeSpanGenerator Timer { get; }
|
||||
|
||||
// Functions in the nn::fssrv::detail namespace use this field.
|
||||
// Possibly move this to the main class if the separation doesn't seem necessary.
|
||||
internal FileSystemServerImpl Impl;
|
||||
internal ref FileSystemServerGlobals Globals => ref Impl.Globals;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="FileSystemServer"/> and registers its services using the provided HOS client.
|
||||
/// </summary>
|
||||
@ -37,6 +42,10 @@ namespace LibHac.FsSrv
|
||||
if (config.DeviceOperator == null)
|
||||
throw new ArgumentException("DeviceOperator must not be null");
|
||||
|
||||
Impl = new FileSystemServerImpl();
|
||||
Impl.Globals.Hos = horizonClient;
|
||||
Impl.Globals.InitMutex = new object();
|
||||
|
||||
Hos = horizonClient;
|
||||
|
||||
IsDebugMode = false;
|
||||
@ -258,4 +267,18 @@ namespace LibHac.FsSrv
|
||||
/// </summary>
|
||||
public ITimeSpanGenerator TimeSpanGenerator { get; set; }
|
||||
}
|
||||
|
||||
// Functions in the nn::fssrv::detail namespace use this struct.
|
||||
// Possibly move this to the main class if the separation doesn't seem necessary.
|
||||
internal struct FileSystemServerImpl
|
||||
{
|
||||
public FileSystemServerGlobals Globals;
|
||||
}
|
||||
|
||||
internal struct FileSystemServerGlobals
|
||||
{
|
||||
public HorizonClient Hos;
|
||||
public object InitMutex;
|
||||
public DeviceEventSimulatorGlobals DeviceEventSimulator;
|
||||
}
|
||||
}
|
||||
|
186
src/LibHac/FsSrv/Impl/IDeviceEventSimulator.cs
Normal file
186
src/LibHac/FsSrv/Impl/IDeviceEventSimulator.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Os;
|
||||
|
||||
namespace LibHac.FsSrv.Impl
|
||||
{
|
||||
internal struct DeviceEventSimulatorGlobals
|
||||
{
|
||||
public GameCardEventSimulator GameCardEventSimulator;
|
||||
public SdCardEventSimulator SdCardEventSimulator;
|
||||
public nint GameCardEventSimulatorInit;
|
||||
public nint SdCardEventSimulatorInit;
|
||||
}
|
||||
|
||||
internal static class DeviceEventSimulatorGlobalMethods
|
||||
{
|
||||
public static SdCardEventSimulator GetSdCardEventSimulator(this ref FileSystemServerImpl fs)
|
||||
{
|
||||
ref DeviceEventSimulatorGlobals g = ref fs.Globals.DeviceEventSimulator;
|
||||
using var guard = new InitializationGuard(ref g.SdCardEventSimulatorInit, fs.Globals.InitMutex);
|
||||
|
||||
if (guard.IsInitialized)
|
||||
return g.SdCardEventSimulator;
|
||||
|
||||
g.SdCardEventSimulator = new SdCardEventSimulator(fs.Globals.Hos.Os);
|
||||
return g.SdCardEventSimulator;
|
||||
}
|
||||
|
||||
public static GameCardEventSimulator GetGameCardEventSimulator(this ref FileSystemServerImpl fs)
|
||||
{
|
||||
ref DeviceEventSimulatorGlobals g = ref fs.Globals.DeviceEventSimulator;
|
||||
using var guard = new InitializationGuard(ref g.GameCardEventSimulatorInit, fs.Globals.InitMutex);
|
||||
|
||||
if (guard.IsInitialized)
|
||||
return g.GameCardEventSimulator;
|
||||
|
||||
g.GameCardEventSimulator = new GameCardEventSimulator(fs.Globals.Hos.Os);
|
||||
return g.GameCardEventSimulator;
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public abstract class IDeviceEventSimulator
|
||||
{
|
||||
private bool _isEventSet;
|
||||
private bool _isDetectionSimulationEnabled;
|
||||
private SdkRecursiveMutex _mutex;
|
||||
private SimulatingDeviceDetectionMode _detectionSimulationMode;
|
||||
private SimulatingDeviceAccessFailureEventType _simulatedFailureType;
|
||||
private SimulatingDeviceTargetOperation _simulatedOperation;
|
||||
private Result _failureResult;
|
||||
private bool _isRecurringEvent;
|
||||
private int _timeoutLengthMs;
|
||||
|
||||
private OsState _os;
|
||||
|
||||
public IDeviceEventSimulator(OsState os, int timeoutMs)
|
||||
{
|
||||
_os = os;
|
||||
_timeoutLengthMs = timeoutMs;
|
||||
_mutex = new SdkRecursiveMutex();
|
||||
}
|
||||
|
||||
public virtual Result GetCorrespondingResult(SimulatingDeviceAccessFailureEventType eventType)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void SetDeviceEvent(SimulatingDeviceTargetOperation operation,
|
||||
SimulatingDeviceAccessFailureEventType failureType, Result failureResult, bool isRecurringEvent)
|
||||
{
|
||||
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (failureResult.IsFailure())
|
||||
_failureResult = failureResult;
|
||||
|
||||
_isEventSet = true;
|
||||
_simulatedFailureType = failureType;
|
||||
_simulatedOperation = operation;
|
||||
_isRecurringEvent = isRecurringEvent;
|
||||
}
|
||||
|
||||
public void ClearDeviceEvent()
|
||||
{
|
||||
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
_isEventSet = false;
|
||||
_simulatedFailureType = SimulatingDeviceAccessFailureEventType.None;
|
||||
_simulatedOperation = SimulatingDeviceTargetOperation.None;
|
||||
_failureResult = Result.Success;
|
||||
_isRecurringEvent = false;
|
||||
}
|
||||
|
||||
public void SetDetectionSimulationMode(SimulatingDeviceDetectionMode mode)
|
||||
{
|
||||
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
_isDetectionSimulationEnabled = mode != SimulatingDeviceDetectionMode.NoSimulation;
|
||||
_detectionSimulationMode = mode;
|
||||
}
|
||||
|
||||
public void ClearDetectionSimulationMode()
|
||||
{
|
||||
SetDetectionSimulationMode(SimulatingDeviceDetectionMode.NoSimulation);
|
||||
}
|
||||
|
||||
public Result CheckSimulatedAccessFailureEvent(SimulatingDeviceTargetOperation operation)
|
||||
{
|
||||
if (_isEventSet)
|
||||
return Result.Success;
|
||||
|
||||
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if ((_simulatedOperation & operation) == 0)
|
||||
return Result.Success;
|
||||
|
||||
Result result = GetCorrespondingResult(_simulatedFailureType);
|
||||
|
||||
if (result.IsFailure() && _failureResult.IsFailure())
|
||||
result = _failureResult;
|
||||
|
||||
if (_simulatedFailureType == SimulatingDeviceAccessFailureEventType.AccessTimeoutFailure)
|
||||
SimulateTimeout();
|
||||
|
||||
if (!_isRecurringEvent)
|
||||
ClearDeviceEvent();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool FilterDetectionState(bool actualState)
|
||||
{
|
||||
if (!_isDetectionSimulationEnabled)
|
||||
return actualState;
|
||||
|
||||
bool simulatedState = _detectionSimulationMode switch
|
||||
{
|
||||
SimulatingDeviceDetectionMode.NoSimulation => actualState,
|
||||
SimulatingDeviceDetectionMode.DeviceAttached => true,
|
||||
SimulatingDeviceDetectionMode.DeviceRemoved => false,
|
||||
_ => actualState
|
||||
};
|
||||
|
||||
return simulatedState;
|
||||
}
|
||||
|
||||
protected virtual void SimulateTimeout()
|
||||
{
|
||||
_os.SleepThread(TimeSpan.FromMilliSeconds(_timeoutLengthMs));
|
||||
}
|
||||
}
|
||||
|
||||
public class GameCardEventSimulator : IDeviceEventSimulator
|
||||
{
|
||||
public GameCardEventSimulator(OsState os) : base(os, 2000) { }
|
||||
|
||||
public override Result GetCorrespondingResult(SimulatingDeviceAccessFailureEventType eventType)
|
||||
{
|
||||
return eventType switch
|
||||
{
|
||||
SimulatingDeviceAccessFailureEventType.None => Result.Success,
|
||||
SimulatingDeviceAccessFailureEventType.AccessTimeoutFailure => ResultFs.GameCardCardAccessTimeout.Log(),
|
||||
SimulatingDeviceAccessFailureEventType.AccessFailure => ResultFs.GameCardAccessFailed.Log(),
|
||||
SimulatingDeviceAccessFailureEventType.DataCorruption => ResultFs.SimulatedDeviceDataCorrupted.Log(),
|
||||
_ => ResultFs.InvalidArgument.Log()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class SdCardEventSimulator : IDeviceEventSimulator
|
||||
{
|
||||
public SdCardEventSimulator(OsState os) : base(os, 2000) { }
|
||||
|
||||
public override Result GetCorrespondingResult(SimulatingDeviceAccessFailureEventType eventType)
|
||||
{
|
||||
return eventType switch
|
||||
{
|
||||
SimulatingDeviceAccessFailureEventType.None => Result.Success,
|
||||
SimulatingDeviceAccessFailureEventType.AccessTimeoutFailure => ResultFs.PortSdCardResponseTimeoutError.Log(),
|
||||
SimulatingDeviceAccessFailureEventType.AccessFailure => ResultFs.SdCardAccessFailed.Log(),
|
||||
SimulatingDeviceAccessFailureEventType.DataCorruption => ResultFs.SimulatedDeviceDataCorrupted.Log(),
|
||||
_ => ResultFs.InvalidArgument.Log()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace LibHac.FsSystem
|
||||
|
||||
public bool TryLock()
|
||||
{
|
||||
return _semaphore.Wait(TimeSpan.Zero);
|
||||
return _semaphore.Wait(System.TimeSpan.Zero);
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using LibHac.Bcat;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
@ -14,20 +15,24 @@ namespace LibHac
|
||||
public class Horizon
|
||||
{
|
||||
private const int InitialProcessCountMax = 0x50;
|
||||
internal long StartTick { get; }
|
||||
internal ITimeSpanGenerator Time { get; }
|
||||
internal ServiceManager ServiceManager { get; }
|
||||
private HorizonClient LoaderClient { get; }
|
||||
|
||||
// long instead of ulong because the ulong Interlocked.Increment overload
|
||||
// wasn't added until .NET 5
|
||||
private long _currentInitialProcessId;
|
||||
private long _currentProcessId;
|
||||
private ulong _currentInitialProcessId;
|
||||
private ulong _currentProcessId;
|
||||
|
||||
|
||||
// Todo: Initialize with a configuration object
|
||||
public Horizon(ITimeSpanGenerator timer, FileSystemServerConfig fsServerConfig)
|
||||
{
|
||||
_currentProcessId = InitialProcessCountMax;
|
||||
|
||||
Time = timer ?? new StopWatchTimeSpanGenerator();
|
||||
StartTick = Stopwatch.GetTimestamp();
|
||||
ServiceManager = new ServiceManager();
|
||||
|
||||
// ReSharper disable ObjectCreationAsStatement
|
||||
@ -40,7 +45,7 @@ namespace LibHac
|
||||
|
||||
public HorizonClient CreatePrivilegedHorizonClient()
|
||||
{
|
||||
ulong processId = (ulong)Interlocked.Increment(ref _currentInitialProcessId);
|
||||
ulong processId = Interlocked.Increment(ref _currentInitialProcessId);
|
||||
|
||||
Abort.DoAbortUnless(processId <= InitialProcessCountMax, "Created too many privileged clients.");
|
||||
|
||||
@ -51,7 +56,7 @@ namespace LibHac
|
||||
|
||||
public HorizonClient CreateHorizonClient()
|
||||
{
|
||||
ulong processId = (ulong)Interlocked.Increment(ref _currentProcessId);
|
||||
ulong processId = Interlocked.Increment(ref _currentProcessId);
|
||||
|
||||
// Todo: Register process with FS
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace LibHac
|
||||
|
||||
public FileSystemClient Fs { get; }
|
||||
public ServiceManagerClient Sm { get; }
|
||||
public OsClient Os { get; }
|
||||
public OsState Os { get; }
|
||||
public LrClient Lr { get; }
|
||||
public ArpClient Arp => ArpLazy.Value;
|
||||
|
||||
@ -30,7 +30,7 @@ namespace LibHac
|
||||
|
||||
Fs = new FileSystemClient(this);
|
||||
Sm = new ServiceManagerClient(horizon.ServiceManager);
|
||||
Os = new OsClient(this);
|
||||
Os = new OsState(this, horizon.StartTick);
|
||||
Lr = new LrClient(this);
|
||||
|
||||
ArpLazy = new Lazy<ArpClient>(InitArpClient, true);
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac
|
||||
namespace LibHac
|
||||
{
|
||||
public interface ITimeSpanGenerator
|
||||
{
|
||||
TimeSpan GetCurrent();
|
||||
System.TimeSpan GetCurrent();
|
||||
}
|
||||
}
|
8
src/LibHac/Os/ConditionVariable.cs
Normal file
8
src/LibHac/Os/ConditionVariable.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public enum ConditionVariableStatus
|
||||
{
|
||||
TimedOut = 0,
|
||||
Success = 1
|
||||
}
|
||||
}
|
13
src/LibHac/Os/ILockable.cs
Normal file
13
src/LibHac/Os/ILockable.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public interface IBasicLockable
|
||||
{
|
||||
void Lock();
|
||||
void Unlock();
|
||||
}
|
||||
|
||||
public interface ILockable : IBasicLockable
|
||||
{
|
||||
bool TryLock();
|
||||
}
|
||||
}
|
77
src/LibHac/Os/Impl/InternalConditionVariable-os.net.cs
Normal file
77
src/LibHac/Os/Impl/InternalConditionVariable-os.net.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System.Threading;
|
||||
using LibHac.Diag;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal struct InternalConditionVariableImpl
|
||||
{
|
||||
private object _obj;
|
||||
|
||||
public InternalConditionVariableImpl(nint _ = 0) => _obj = new object();
|
||||
public void Initialize() => _obj = new object();
|
||||
|
||||
public void Signal()
|
||||
{
|
||||
Assert.False(Monitor.IsEntered(_obj));
|
||||
|
||||
Monitor.Enter(_obj);
|
||||
Monitor.Pulse(_obj);
|
||||
Monitor.Exit(_obj);
|
||||
}
|
||||
|
||||
public void Broadcast()
|
||||
{
|
||||
Assert.False(Monitor.IsEntered(_obj));
|
||||
|
||||
Monitor.Enter(_obj);
|
||||
Monitor.PulseAll(_obj);
|
||||
Monitor.Exit(_obj);
|
||||
}
|
||||
|
||||
public void Wait(ref InternalCriticalSection cs)
|
||||
{
|
||||
Assert.False(Monitor.IsEntered(_obj));
|
||||
Abort.DoAbortUnless(cs.IsLockedByCurrentThread());
|
||||
|
||||
// Monitor.Wait doesn't allow specifying a separate mutex object. Workaround this by manually
|
||||
// unlocking and locking the separate mutex object. Due to this, the order the waiting threads
|
||||
// will resume is not guaranteed, and 5 Monitor calls are required instead of 1.
|
||||
cs.Leave();
|
||||
Monitor.Enter(_obj);
|
||||
Monitor.Wait(_obj);
|
||||
Monitor.Exit(_obj);
|
||||
cs.Enter();
|
||||
}
|
||||
|
||||
public ConditionVariableStatus TimedWait(ref InternalCriticalSection cs, in TimeoutHelper timeoutHelper)
|
||||
{
|
||||
Assert.False(Monitor.IsEntered(_obj));
|
||||
Abort.DoAbortUnless(cs.IsLockedByCurrentThread());
|
||||
|
||||
TimeSpan remainingTime = timeoutHelper.GetTimeLeftOnTarget();
|
||||
|
||||
if (remainingTime <= new TimeSpan(0))
|
||||
return ConditionVariableStatus.TimedOut;
|
||||
|
||||
// Casting to an int won't lose any data because the .NET implementation of
|
||||
// GetTimeLeftOnTarget always returns a value that fits in an int.
|
||||
int remainingTimeMs = (int)remainingTime.GetMilliSeconds();
|
||||
|
||||
cs.Leave();
|
||||
Monitor.Enter(_obj);
|
||||
bool acquiredBeforeTimeout = Monitor.Wait(_obj, remainingTimeMs);
|
||||
Monitor.Exit(_obj);
|
||||
cs.Enter();
|
||||
|
||||
// Short code path if we timed out even before waiting on the mutex.
|
||||
if (!acquiredBeforeTimeout)
|
||||
return ConditionVariableStatus.TimedOut;
|
||||
|
||||
// We may have timed out waiting to Enter the mutex. Check the time left again.
|
||||
if (timeoutHelper.GetTimeLeftOnTarget() <= new TimeSpan(0))
|
||||
return ConditionVariableStatus.TimedOut;
|
||||
|
||||
return ConditionVariableStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
20
src/LibHac/Os/Impl/InternalConditionVariable.cs
Normal file
20
src/LibHac/Os/Impl/InternalConditionVariable.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal struct InternalConditionVariable
|
||||
{
|
||||
private InternalConditionVariableImpl _impl;
|
||||
|
||||
public InternalConditionVariable(nint _ = 0)
|
||||
{
|
||||
_impl = new InternalConditionVariableImpl();
|
||||
}
|
||||
|
||||
public void Initialize() => _impl.Initialize();
|
||||
public void Signal() => _impl.Signal();
|
||||
public void Broadcast() => _impl.Broadcast();
|
||||
public void Wait(ref InternalCriticalSection cs) => _impl.Wait(ref cs);
|
||||
|
||||
public void TimedWait(ref InternalCriticalSection cs, in TimeoutHelper timeoutHelper) =>
|
||||
_impl.TimedWait(ref cs, in timeoutHelper);
|
||||
}
|
||||
}
|
36
src/LibHac/Os/Impl/InternalCriticalSection-os.net.cs
Normal file
36
src/LibHac/Os/Impl/InternalCriticalSection-os.net.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Threading;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal struct InternalCriticalSectionImpl
|
||||
{
|
||||
private object _obj;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_obj = new object();
|
||||
}
|
||||
|
||||
public void FinalizeObject() { }
|
||||
|
||||
public void Enter()
|
||||
{
|
||||
Monitor.Enter(_obj);
|
||||
}
|
||||
|
||||
public bool TryEnter()
|
||||
{
|
||||
return Monitor.TryEnter(_obj);
|
||||
}
|
||||
|
||||
public void Leave()
|
||||
{
|
||||
Monitor.Exit(_obj);
|
||||
}
|
||||
|
||||
public bool IsLockedByCurrentThread()
|
||||
{
|
||||
return Monitor.IsEntered(_obj);
|
||||
}
|
||||
}
|
||||
}
|
20
src/LibHac/Os/Impl/InternalCriticalSection.cs
Normal file
20
src/LibHac/Os/Impl/InternalCriticalSection.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
public struct InternalCriticalSection : ILockable
|
||||
{
|
||||
private InternalCriticalSectionImpl _impl;
|
||||
|
||||
public void Initialize() => _impl.Initialize();
|
||||
public void FinalizeObject() => _impl.FinalizeObject();
|
||||
|
||||
public void Enter() => _impl.Enter();
|
||||
public bool TryEnter() => _impl.TryEnter();
|
||||
public void Leave() => _impl.Leave();
|
||||
|
||||
public void Lock() => _impl.Enter();
|
||||
public bool TryLock() => _impl.TryEnter();
|
||||
public void Unlock() => _impl.Leave();
|
||||
|
||||
public bool IsLockedByCurrentThread() => _impl.IsLockedByCurrentThread();
|
||||
}
|
||||
}
|
28
src/LibHac/Os/Impl/OsResourceManager.cs
Normal file
28
src/LibHac/Os/Impl/OsResourceManager.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal class OsResourceManager : IDisposable
|
||||
{
|
||||
public TickManager TickManager { get; }
|
||||
|
||||
// Todo: Use configuration object if/when more options are added
|
||||
public OsResourceManager(long startTick)
|
||||
{
|
||||
TickManager = new TickManager(startTick);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
TickManager.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class OsResourceManagerApi
|
||||
{
|
||||
public static OsResourceManager GetOsResourceManager(this OsState os)
|
||||
{
|
||||
return os.ResourceManager;
|
||||
}
|
||||
}
|
||||
}
|
59
src/LibHac/Os/Impl/TickManager-os.net.cs
Normal file
59
src/LibHac/Os/Impl/TickManager-os.net.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal struct TickManagerImpl : IDisposable
|
||||
{
|
||||
private long _tickFrequency;
|
||||
private long _startTick;
|
||||
private TimeSpan _maxTimeSpan;
|
||||
private long _maxTick;
|
||||
|
||||
public TickManagerImpl(long startTick)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
TimeBeginPeriod(1);
|
||||
}
|
||||
|
||||
_tickFrequency = Stopwatch.Frequency;
|
||||
_startTick = startTick;
|
||||
|
||||
long nanoSecondsPerSecond = TimeSpan.FromSeconds(1).GetNanoSeconds();
|
||||
|
||||
if (_tickFrequency <= nanoSecondsPerSecond)
|
||||
{
|
||||
_maxTick = _tickFrequency * (long.MaxValue / nanoSecondsPerSecond);
|
||||
_maxTimeSpan = TimeSpan.FromNanoSeconds(long.MaxValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
_maxTick = long.MaxValue;
|
||||
_maxTimeSpan = TimeSpan.FromSeconds(long.MaxValue / _tickFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
TimeEndPeriod(1);
|
||||
}
|
||||
}
|
||||
|
||||
public Tick GetTick() => new Tick(Stopwatch.GetTimestamp() - _startTick);
|
||||
public Tick GetSystemTickOrdered() => new Tick(Stopwatch.GetTimestamp() - _startTick);
|
||||
public long GetTickFrequency() => _tickFrequency;
|
||||
public long GetMaxTick() => _maxTick;
|
||||
public long GetMaxTimeSpanNs() => _maxTimeSpan.GetNanoSeconds();
|
||||
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
private static extern uint TimeBeginPeriod(uint milliseconds);
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
||||
private static extern uint TimeEndPeriod(uint milliseconds);
|
||||
}
|
||||
}
|
118
src/LibHac/Os/Impl/TickManager.cs
Normal file
118
src/LibHac/Os/Impl/TickManager.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using LibHac.Diag;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal static class TickManagerApi
|
||||
{
|
||||
public static TickManager GetTickManager(this OsState os) => os.GetOsResourceManager().TickManager;
|
||||
public static Tick GetCurrentTick(this OsState os) => os.GetTickManager().GetTick();
|
||||
public static Tick GetCurrentTickOrdered(this OsState os) => os.GetTickManager().GetSystemTickOrdered();
|
||||
}
|
||||
|
||||
public class TickManager : IDisposable
|
||||
{
|
||||
private static readonly long MaxTickFrequency = long.MaxValue / TimeSpan.FromSeconds(1).GetNanoSeconds() - 1;
|
||||
|
||||
private TickManagerImpl _impl;
|
||||
|
||||
public TickManager(long startTick) => _impl = new TickManagerImpl(startTick);
|
||||
|
||||
~TickManager()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_impl.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public Tick GetTick() => _impl.GetTick();
|
||||
public Tick GetSystemTickOrdered() => _impl.GetSystemTickOrdered();
|
||||
public long GetTickFrequency() => _impl.GetTickFrequency();
|
||||
public long GetMaxTick() => _impl.GetMaxTick();
|
||||
public long GetMaxTimeSpanNs() => _impl.GetMaxTimeSpanNs();
|
||||
|
||||
public TimeSpan ConvertToTimespan(Tick tick)
|
||||
{
|
||||
// Get the tick value.
|
||||
long ticks = tick.GetInt64Value();
|
||||
|
||||
// Get the tick frequency.
|
||||
long tickFreq = GetTickFrequency();
|
||||
Assert.True(tickFreq < MaxTickFrequency);
|
||||
|
||||
// Clamp tick to range.
|
||||
if (ticks > GetMaxTick())
|
||||
{
|
||||
return TimeSpan.FromNanoSeconds(long.MaxValue);
|
||||
}
|
||||
else if (ticks < -GetMaxTick())
|
||||
{
|
||||
return TimeSpan.FromNanoSeconds(long.MinValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert to timespan.
|
||||
long nanoSecondsPerSecond = TimeSpan.FromSeconds(1).GetNanoSeconds();
|
||||
long seconds = ticks / tickFreq;
|
||||
long frac = ticks % tickFreq;
|
||||
|
||||
TimeSpan ts = TimeSpan.FromSeconds(seconds) +
|
||||
TimeSpan.FromNanoSeconds(frac * nanoSecondsPerSecond / tickFreq);
|
||||
|
||||
Assert.True(!(ticks > 0 && ts < default(TimeSpan) || ticks < 0 && ts > default(TimeSpan)));
|
||||
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
public Tick ConvertToTick(TimeSpan ts)
|
||||
{
|
||||
// Get the TimeSpan in nanoseconds.
|
||||
long ns = ts.GetNanoSeconds();
|
||||
|
||||
// Clamp ns to range.
|
||||
if (ns > GetMaxTimeSpanNs())
|
||||
{
|
||||
return new Tick(long.MaxValue);
|
||||
}
|
||||
else if (ns < -GetMaxTimeSpanNs())
|
||||
{
|
||||
return new Tick(long.MinValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the tick frequency.
|
||||
long tickFreq = GetTickFrequency();
|
||||
Assert.True(tickFreq < MaxTickFrequency);
|
||||
|
||||
// Convert to tick.
|
||||
long nanoSecondsPerSecond = TimeSpan.FromSeconds(1).GetNanoSeconds();
|
||||
bool isNegative = ns < 0;
|
||||
long seconds = ns / nanoSecondsPerSecond;
|
||||
long frac = ns % nanoSecondsPerSecond;
|
||||
|
||||
// If negative, negate seconds/frac.
|
||||
if (isNegative)
|
||||
{
|
||||
seconds = -seconds;
|
||||
frac = -frac;
|
||||
}
|
||||
|
||||
// Calculate the tick, and invert back to negative if needed.
|
||||
long ticks = (seconds * tickFreq) +
|
||||
((frac * tickFreq + nanoSecondsPerSecond - 1) / nanoSecondsPerSecond);
|
||||
|
||||
if (isNegative)
|
||||
{
|
||||
ticks = -ticks;
|
||||
}
|
||||
|
||||
return new Tick(ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
src/LibHac/Os/Impl/TimeoutHelper-os.net.cs
Normal file
45
src/LibHac/Os/Impl/TimeoutHelper-os.net.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal static class TimeoutHelperImpl
|
||||
{
|
||||
public static void Sleep(OsState os, TimeSpan time)
|
||||
{
|
||||
if (time == new TimeSpan(0))
|
||||
return;
|
||||
|
||||
TickManager tickManager = os.GetTickManager();
|
||||
|
||||
// Attempt to avoid overflow by doing the addition unsigned
|
||||
ulong currentTick = (ulong)tickManager.GetTick().GetInt64Value();
|
||||
ulong timeoutTick = (ulong)tickManager.ConvertToTick(time).GetInt64Value();
|
||||
ulong absoluteEndTick = currentTick + timeoutTick + 1;
|
||||
|
||||
var endTick = new Tick((long)Math.Min(long.MaxValue, absoluteEndTick));
|
||||
|
||||
Tick curTick = tickManager.GetTick();
|
||||
|
||||
// Sleep in a loop until the requested time has past.
|
||||
while (curTick < endTick)
|
||||
{
|
||||
Tick remaining = endTick - curTick;
|
||||
int sleepTimeMs = (int)ConvertToImplTime(os, remaining).GetMilliSeconds();
|
||||
|
||||
System.Threading.Thread.Sleep(sleepTimeMs);
|
||||
|
||||
curTick = tickManager.GetTick();
|
||||
}
|
||||
}
|
||||
|
||||
public static TimeSpan ConvertToImplTime(OsState os, Tick tick)
|
||||
{
|
||||
TickManager tickManager = os.GetTickManager();
|
||||
TimeSpan ts = tickManager.ConvertToTimespan(tick);
|
||||
|
||||
// .NET allows sleeping up to int.MaxValue milliseconds at a time.
|
||||
long timeMs = Math.Min(int.MaxValue, ts.GetMilliSeconds());
|
||||
return TimeSpan.FromMilliSeconds(timeMs);
|
||||
}
|
||||
}
|
||||
}
|
62
src/LibHac/Os/Impl/TimeoutHelper.cs
Normal file
62
src/LibHac/Os/Impl/TimeoutHelper.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac.Os.Impl
|
||||
{
|
||||
internal readonly struct TimeoutHelper
|
||||
{
|
||||
private readonly Tick _endTick;
|
||||
private readonly OsState _os;
|
||||
|
||||
public TimeoutHelper(OsState os, TimeSpan timeout)
|
||||
{
|
||||
_os = os;
|
||||
|
||||
if (timeout == new TimeSpan(0))
|
||||
{
|
||||
// If timeout is zero, don't do relative tick calculations.
|
||||
_endTick = new Tick(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
TickManager tickManager = os.GetTickManager();
|
||||
|
||||
// Attempt to avoid overflow by doing the addition unsigned
|
||||
ulong currentTick = (ulong)tickManager.GetTick().GetInt64Value();
|
||||
ulong timeoutTick = (ulong)tickManager.ConvertToTick(timeout).GetInt64Value();
|
||||
ulong absoluteEndTick = currentTick + timeoutTick + 1;
|
||||
|
||||
_endTick = new Tick((long)Math.Min(long.MaxValue, absoluteEndTick));
|
||||
}
|
||||
}
|
||||
|
||||
public bool TimedOut()
|
||||
{
|
||||
if (_endTick.GetInt64Value() == 0)
|
||||
return true;
|
||||
|
||||
Tick currentTick = _os.GetTickManager().GetTick();
|
||||
|
||||
return currentTick >= _endTick;
|
||||
}
|
||||
|
||||
public TimeSpan GetTimeLeftOnTarget()
|
||||
{
|
||||
// If the end tick is zero, we're expired.
|
||||
if (_endTick.GetInt64Value() == 0)
|
||||
return new TimeSpan(0);
|
||||
|
||||
// Check if we've expired.
|
||||
Tick currentTick = _os.GetTickManager().GetTick();
|
||||
if (currentTick >= _endTick)
|
||||
return new TimeSpan(0);
|
||||
|
||||
// Return the converted difference as a timespan.
|
||||
return TimeoutHelperImpl.ConvertToImplTime(_os, _endTick - currentTick);
|
||||
}
|
||||
|
||||
public static void Sleep(OsState os, TimeSpan timeout)
|
||||
{
|
||||
TimeoutHelperImpl.Sleep(os, timeout);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public class OsClient
|
||||
{
|
||||
private HorizonClient Hos { get; }
|
||||
|
||||
internal OsClient(HorizonClient horizonClient)
|
||||
{
|
||||
Hos = horizonClient;
|
||||
}
|
||||
|
||||
public ProcessId GetCurrentProcessId()
|
||||
{
|
||||
return Hos.ProcessId;
|
||||
}
|
||||
}
|
||||
}
|
28
src/LibHac/Os/OsState.cs
Normal file
28
src/LibHac/Os/OsState.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using LibHac.Os.Impl;
|
||||
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public class OsState : IDisposable
|
||||
{
|
||||
private HorizonClient Hos { get; }
|
||||
internal OsResourceManager ResourceManager { get; }
|
||||
|
||||
// Todo: Use configuration object if/when more options are added
|
||||
internal OsState(HorizonClient horizonClient, long startTick)
|
||||
{
|
||||
Hos = horizonClient;
|
||||
ResourceManager = new OsResourceManager(startTick);
|
||||
}
|
||||
|
||||
public ProcessId GetCurrentProcessId()
|
||||
{
|
||||
return Hos.ProcessId;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ResourceManager.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
32
src/LibHac/Os/ScopedLock.cs
Normal file
32
src/LibHac/Os/ScopedLock.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public static class ScopedLock
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ScopedLock<TMutex> Lock<TMutex>(ref TMutex lockable) where TMutex : IBasicLockable
|
||||
{
|
||||
return new ScopedLock<TMutex>(ref lockable);
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct ScopedLock<TMutex> where TMutex : IBasicLockable
|
||||
{
|
||||
private Ref<TMutex> _mutex;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ScopedLock(ref TMutex mutex)
|
||||
{
|
||||
_mutex = new Ref<TMutex>(ref mutex);
|
||||
mutex.Lock();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose()
|
||||
{
|
||||
_mutex.Value.Unlock();
|
||||
}
|
||||
}
|
||||
}
|
148
src/LibHac/Os/SdkMutex.cs
Normal file
148
src/LibHac/Os/SdkMutex.cs
Normal file
@ -0,0 +1,148 @@
|
||||
using LibHac.Diag;
|
||||
using LibHac.Os.Impl;
|
||||
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public class SdkMutex : ILockable
|
||||
{
|
||||
private SdkMutexType _mutex;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_mutex.Initialize();
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
_mutex.Lock();
|
||||
}
|
||||
|
||||
public bool TryLock()
|
||||
{
|
||||
return _mutex.TryLock();
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
_mutex.Unlock();
|
||||
}
|
||||
|
||||
public bool IsLockedByCurrentThread()
|
||||
{
|
||||
return _mutex.IsLockedByCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
public struct SdkMutexType : ILockable
|
||||
{
|
||||
private InternalCriticalSection _cs;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_cs.Initialize();
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
Abort.DoAbortUnless(!IsLockedByCurrentThread());
|
||||
_cs.Enter();
|
||||
}
|
||||
|
||||
public bool TryLock()
|
||||
{
|
||||
Abort.DoAbortUnless(!IsLockedByCurrentThread());
|
||||
return _cs.TryEnter();
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
Abort.DoAbortUnless(!IsLockedByCurrentThread());
|
||||
_cs.Leave();
|
||||
}
|
||||
|
||||
public bool IsLockedByCurrentThread()
|
||||
{
|
||||
return _cs.IsLockedByCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
public class SdkRecursiveMutex : IBasicLockable
|
||||
{
|
||||
private SdkRecursiveMutexType _impl;
|
||||
|
||||
public SdkRecursiveMutex()
|
||||
{
|
||||
_impl.Initialize();
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
_impl.Lock();
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
_impl.Unlock();
|
||||
}
|
||||
|
||||
public bool IsLockedByCurrentThread()
|
||||
{
|
||||
return _impl.IsLockedByCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
public struct SdkRecursiveMutexType : ILockable
|
||||
{
|
||||
private InternalCriticalSection _cs;
|
||||
private int _recursiveCount;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_cs.Initialize();
|
||||
_recursiveCount = 0;
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
if (!IsLockedByCurrentThread())
|
||||
{
|
||||
_cs.Enter();
|
||||
}
|
||||
|
||||
_recursiveCount++;
|
||||
Abort.DoAbortUnless(_recursiveCount != 0);
|
||||
}
|
||||
|
||||
public bool TryLock()
|
||||
{
|
||||
if (!IsLockedByCurrentThread())
|
||||
{
|
||||
if (!_cs.TryEnter())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_recursiveCount++;
|
||||
Abort.DoAbortUnless(_recursiveCount != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
Abort.DoAbortUnless(IsLockedByCurrentThread());
|
||||
|
||||
_recursiveCount--;
|
||||
if (_recursiveCount == 0)
|
||||
{
|
||||
_cs.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLockedByCurrentThread()
|
||||
{
|
||||
return _cs.IsLockedByCurrentThread();
|
||||
}
|
||||
}
|
||||
}
|
12
src/LibHac/Os/Thread.cs
Normal file
12
src/LibHac/Os/Thread.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LibHac.Os.Impl;
|
||||
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public static class Thread
|
||||
{
|
||||
public static void SleepThread(this OsState os, TimeSpan time)
|
||||
{
|
||||
TimeoutHelperImpl.Sleep(os, time);
|
||||
}
|
||||
}
|
||||
}
|
39
src/LibHac/Os/Tick.cs
Normal file
39
src/LibHac/Os/Tick.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using LibHac.Os.Impl;
|
||||
|
||||
namespace LibHac.Os
|
||||
{
|
||||
public readonly struct Tick : IEquatable<Tick>
|
||||
{
|
||||
private readonly long _ticks;
|
||||
|
||||
public Tick(long ticks) => _ticks = ticks;
|
||||
|
||||
public long GetInt64Value() => _ticks;
|
||||
public TimeSpan ToTimeSpan(OsState os) => os.ConvertToTimeSpan(this);
|
||||
|
||||
public static Tick operator +(Tick left, Tick right) => new(left._ticks + right._ticks);
|
||||
public static Tick operator -(Tick left, Tick right) => new(left._ticks - right._ticks);
|
||||
|
||||
public static bool operator ==(Tick left, Tick right) => left._ticks == right._ticks;
|
||||
public static bool operator !=(Tick left, Tick right) => left._ticks != right._ticks;
|
||||
public static bool operator <(Tick left, Tick right) => left._ticks < right._ticks;
|
||||
public static bool operator >(Tick left, Tick right) => left._ticks > right._ticks;
|
||||
public static bool operator <=(Tick left, Tick right) => left._ticks <= right._ticks;
|
||||
public static bool operator >=(Tick left, Tick right) => left._ticks >= right._ticks;
|
||||
|
||||
public override bool Equals(object obj) => obj is Tick other && Equals(other);
|
||||
public bool Equals(Tick other) => _ticks == other._ticks;
|
||||
public override int GetHashCode() => _ticks.GetHashCode();
|
||||
public override string ToString() => _ticks.ToString();
|
||||
}
|
||||
|
||||
public static class TickApi
|
||||
{
|
||||
public static Tick GetSystemTick(this OsState os) => os.GetTickManager().GetTick();
|
||||
public static Tick GetSystemTickOrdered(this OsState os) => os.GetTickManager().GetSystemTickOrdered();
|
||||
public static long GetSystemTickFrequency(this OsState os) => os.GetTickManager().GetTickFrequency();
|
||||
public static TimeSpan ConvertToTimeSpan(this OsState os, Tick tick) => os.GetTickManager().ConvertToTimespan(tick);
|
||||
public static Tick ConvertToTick(this OsState os, TimeSpan ts) => os.GetTickManager().ConvertToTick(ts);
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ namespace LibHac
|
||||
private Stopwatch _watch;
|
||||
private long _timedBytes;
|
||||
|
||||
private readonly TimeSpan _animationInterval = TimeSpan.FromSeconds(1.0 / 30);
|
||||
private readonly System.TimeSpan _animationInterval = System.TimeSpan.FromSeconds(1.0 / 30);
|
||||
private const string Animation = @"|/-\";
|
||||
|
||||
private string _currentText = string.Empty;
|
||||
@ -87,7 +87,7 @@ namespace LibHac
|
||||
|
||||
public string GetRateString()
|
||||
{
|
||||
return Utilities.GetBytesReadable((long) (_timedBytes / _watch.Elapsed.TotalSeconds)) + "/s";
|
||||
return Utilities.GetBytesReadable((long)(_timedBytes / _watch.Elapsed.TotalSeconds)) + "/s";
|
||||
}
|
||||
|
||||
private void TimerHandler(object state)
|
||||
@ -159,7 +159,7 @@ namespace LibHac
|
||||
|
||||
private void ResetTimer()
|
||||
{
|
||||
_timer.Change(_animationInterval, TimeSpan.FromMilliseconds(-1));
|
||||
_timer.Change(_animationInterval, System.TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
@ -7,7 +6,7 @@ namespace LibHac
|
||||
{
|
||||
private Stopwatch Timer = Stopwatch.StartNew();
|
||||
|
||||
public TimeSpan GetCurrent()
|
||||
public System.TimeSpan GetCurrent()
|
||||
{
|
||||
return Timer.Elapsed;
|
||||
}
|
||||
|
85
src/LibHac/TimeSpan.cs
Normal file
85
src/LibHac/TimeSpan.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
public readonly struct TimeSpan : IEquatable<TimeSpan>, IComparable<TimeSpan>
|
||||
{
|
||||
private readonly TimeSpanType _ts;
|
||||
|
||||
public TimeSpan(nint _) => _ts = new TimeSpanType();
|
||||
public TimeSpan(TimeSpanType ts) => _ts = ts;
|
||||
|
||||
public static TimeSpan FromNanoSeconds(long nanoSeconds) => new(TimeSpanType.FromNanoSeconds(nanoSeconds));
|
||||
public static TimeSpan FromMicroSeconds(long microSeconds) => new(TimeSpanType.FromMicroSeconds(microSeconds));
|
||||
public static TimeSpan FromMilliSeconds(long milliSeconds) => new(TimeSpanType.FromMilliSeconds(milliSeconds));
|
||||
public static TimeSpan FromSeconds(long seconds) => new(TimeSpanType.FromSeconds(seconds));
|
||||
public static TimeSpan FromMinutes(long minutes) => new(TimeSpanType.FromMinutes(minutes));
|
||||
public static TimeSpan FromHours(long hours) => new(TimeSpanType.FromHours(hours));
|
||||
public static TimeSpan FromDays(long days) => new(TimeSpanType.FromDays(days));
|
||||
|
||||
public long GetNanoSeconds() => _ts.GetNanoSeconds();
|
||||
public long GetMicroSeconds() => _ts.GetMicroSeconds();
|
||||
public long GetMilliSeconds() => _ts.GetMilliSeconds();
|
||||
public long GetSeconds() => _ts.GetSeconds();
|
||||
public long GetMinutes() => _ts.GetMinutes();
|
||||
public long GetHours() => _ts.GetHours();
|
||||
public long GetDays() => _ts.GetDays();
|
||||
|
||||
public static bool operator ==(TimeSpan left, TimeSpan right) => left.Equals(right);
|
||||
public static bool operator !=(TimeSpan left, TimeSpan right) => !(left == right);
|
||||
public static bool operator <(TimeSpan left, TimeSpan right) => left._ts < right._ts;
|
||||
public static bool operator >(TimeSpan left, TimeSpan right) => left._ts > right._ts;
|
||||
public static bool operator <=(TimeSpan left, TimeSpan right) => left._ts <= right._ts;
|
||||
public static bool operator >=(TimeSpan left, TimeSpan right) => left._ts >= right._ts;
|
||||
|
||||
public static TimeSpan operator +(TimeSpan left, TimeSpan right) => new(left._ts + right._ts);
|
||||
public static TimeSpan operator -(TimeSpan left, TimeSpan right) => new(left._ts - right._ts);
|
||||
|
||||
public static implicit operator TimeSpanType(TimeSpan ts) => ts._ts;
|
||||
|
||||
public override bool Equals(object obj) => obj is TimeSpan ts && Equals(ts);
|
||||
public bool Equals(TimeSpan other) => _ts == other._ts;
|
||||
public override int GetHashCode() => _ts.GetHashCode();
|
||||
public int CompareTo(TimeSpan other) => _ts.CompareTo(other._ts);
|
||||
public override string ToString() => _ts.ToString();
|
||||
}
|
||||
|
||||
public readonly struct TimeSpanType : IEquatable<TimeSpanType>, IComparable<TimeSpanType>
|
||||
{
|
||||
private readonly long _nanoSeconds;
|
||||
|
||||
private TimeSpanType(long nanoSeconds) => _nanoSeconds = nanoSeconds;
|
||||
|
||||
public static TimeSpanType FromNanoSeconds(long nanoSeconds) => new(nanoSeconds);
|
||||
public static TimeSpanType FromMicroSeconds(long microSeconds) => new(microSeconds * 1000L);
|
||||
public static TimeSpanType FromMilliSeconds(long milliSeconds) => new(milliSeconds * (1000L * 1000));
|
||||
public static TimeSpanType FromSeconds(long seconds) => new(seconds * (1000L * 1000 * 1000));
|
||||
public static TimeSpanType FromMinutes(long minutes) => new(minutes * (1000L * 1000 * 1000 * 60));
|
||||
public static TimeSpanType FromHours(long hours) => new(hours * (1000L * 1000 * 1000 * 60 * 60));
|
||||
public static TimeSpanType FromDays(long days) => new(days * (1000L * 1000 * 1000 * 60 * 60 * 24));
|
||||
|
||||
public long GetNanoSeconds() => _nanoSeconds;
|
||||
public long GetMicroSeconds() => _nanoSeconds / 1000;
|
||||
public long GetMilliSeconds() => _nanoSeconds / (1000L * 1000);
|
||||
public long GetSeconds() => _nanoSeconds / (1000L * 1000 * 1000);
|
||||
public long GetMinutes() => _nanoSeconds / (1000L * 1000 * 1000 * 60);
|
||||
public long GetHours() => _nanoSeconds / (1000L * 1000 * 1000 * 60 * 60);
|
||||
public long GetDays() => _nanoSeconds / (1000L * 1000 * 1000 * 60 * 60 * 24);
|
||||
|
||||
public static bool operator ==(TimeSpanType left, TimeSpanType right) => left._nanoSeconds == right._nanoSeconds;
|
||||
public static bool operator !=(TimeSpanType left, TimeSpanType right) => left._nanoSeconds != right._nanoSeconds;
|
||||
public static bool operator <(TimeSpanType left, TimeSpanType right) => left._nanoSeconds < right._nanoSeconds;
|
||||
public static bool operator >(TimeSpanType left, TimeSpanType right) => left._nanoSeconds > right._nanoSeconds;
|
||||
public static bool operator <=(TimeSpanType left, TimeSpanType right) => left._nanoSeconds <= right._nanoSeconds;
|
||||
public static bool operator >=(TimeSpanType left, TimeSpanType right) => left._nanoSeconds >= right._nanoSeconds;
|
||||
|
||||
public static TimeSpanType operator +(TimeSpanType left, TimeSpanType right) => new(left._nanoSeconds + right._nanoSeconds);
|
||||
public static TimeSpanType operator -(TimeSpanType left, TimeSpanType right) => new(left._nanoSeconds - right._nanoSeconds);
|
||||
|
||||
public override bool Equals(object obj) => obj is TimeSpanType ts && Equals(ts);
|
||||
public bool Equals(TimeSpanType other) => _nanoSeconds == other._nanoSeconds;
|
||||
public override int GetHashCode() => (int)_nanoSeconds;
|
||||
public int CompareTo(TimeSpanType other) => _nanoSeconds.CompareTo(other._nanoSeconds);
|
||||
public override string ToString() => _nanoSeconds.ToString();
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ namespace hactoolnet
|
||||
{
|
||||
public class ConsoleAccessLog : IAccessLog
|
||||
{
|
||||
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
|
||||
public void Log(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
Console.WriteLine(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller));
|
||||
}
|
||||
@ -22,7 +22,7 @@ namespace hactoolnet
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
|
||||
public void Log(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
Logger.LogMessage(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller));
|
||||
}
|
||||
@ -37,7 +37,7 @@ namespace hactoolnet
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public void Log(Result result, TimeSpan startTime, TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
|
||||
public void Log(Result result, System.TimeSpan startTime, System.TimeSpan endTime, int handleId, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
Logger.WriteLine(AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user