diff --git a/src/wpilibsharp/DataLogManager.cs b/src/wpilibsharp/DataLogManager.cs index 7b0fcb0d..a829af21 100644 --- a/src/wpilibsharp/DataLogManager.cs +++ b/src/wpilibsharp/DataLogManager.cs @@ -10,7 +10,7 @@ namespace WPILib; public static class DataLogManger { - private static DataLog? m_log; + private static DataLogBackgroundWriter? m_log; private static bool m_stopped; private static string? m_logDir; private static bool m_filenameOverride; @@ -51,7 +51,7 @@ public static void Start(string dir = "", string filename = "", double period = Console.Error.WriteLine($"DataLogManager: could not delete {file}"); } } - m_log = new DataLog(m_logDir, MakeLogFilename(filename), period); + m_log = new(m_logDir, MakeLogFilename(filename), period); m_messageLog = new StringLogEntry(m_log, "messages"); if (m_ntLoggerEnabled) diff --git a/src/wpiutil/Logging/DataLog.cs b/src/wpiutil/Logging/DataLog.cs index f4b9baa6..a8832d59 100644 --- a/src/wpiutil/Logging/DataLog.cs +++ b/src/wpiutil/Logging/DataLog.cs @@ -1,6 +1,4 @@ using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using WPIUtil.Handles; using WPIUtil.Natives; using WPIUtil.Serialization.Protobuf; @@ -8,50 +6,16 @@ namespace WPIUtil.Logging; -public sealed unsafe class DataLog : IDisposable +public unsafe class DataLog : IDisposable { - [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] - private static void NativeDataLogCallback(void* ptr, byte* data, nuint len) - { - GCHandle handle = GCHandle.FromIntPtr((nint)ptr); - if (handle.Target is DataLog datalog) - { - datalog.callback?.Invoke(new ReadOnlySpan(data, (int)len)); - } - } - - private GCHandle? gcHandle; - private readonly DataLogCallback? callback; - - public delegate void DataLogCallback(ReadOnlySpan data); - - public DataLog(string dir = "", string filename = "", double period = 0.25, string extraHeader = "") - { - NativeHandle = DataLogNative.Create(dir, filename, period, extraHeader); + protected DataLog(OpaqueDataLog* impl) { + NativeHandle = impl; } - public DataLog(DataLogCallback callback, double period = 0.25, string extraHeader = "") - { - gcHandle = GCHandle.Alloc(this); - this.callback = callback; - NativeHandle = DataLogNative.CreateFunc(&NativeDataLogCallback, (void*)GCHandle.ToIntPtr(gcHandle.Value), period, extraHeader); - } - - public void Dispose() + public virtual void Dispose() { + GC.SuppressFinalize(this); DataLogNative.Release(NativeHandle); - if (gcHandle.HasValue) - { - gcHandle.Value.Free(); - } - } - - public string Filename - { - set - { - DataLogNative.SetFilename(NativeHandle, value); - } } public void Flush() @@ -228,6 +192,5 @@ private void AddSchemaImpl(IStructBase value, long timestamp, HashSet se } private readonly ConcurrentDictionary m_schemaMap = []; - - public unsafe OpaqueDataLog* NativeHandle { get; } = null; + public unsafe OpaqueDataLog* NativeHandle { get; protected init;} } diff --git a/src/wpiutil/Logging/DataLogBackgroundWriter.cs b/src/wpiutil/Logging/DataLogBackgroundWriter.cs new file mode 100644 index 00000000..eb7527bb --- /dev/null +++ b/src/wpiutil/Logging/DataLogBackgroundWriter.cs @@ -0,0 +1,50 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using WPIUtil.Natives; + +namespace WPIUtil.Logging; + +public sealed unsafe class DataLogBackgroundWriter : DataLog +{ + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + private static void NativeDataLogCallback(void* ptr, byte* data, nuint len) + { + GCHandle handle = GCHandle.FromIntPtr((nint)ptr); + if (handle.Target is DataLogBackgroundWriter datalog) + { + datalog.callback?.Invoke(new ReadOnlySpan(data, (int)len)); + } + } + + private GCHandle? gcHandle; + private readonly DataLogCallback? callback; + + public delegate void DataLogCallback(ReadOnlySpan data); + + public DataLogBackgroundWriter(string dir = "", string filename = "", double period = 0.25, string extraHeader = "") : base(DataLogNative.CreateBg(dir, filename, period, extraHeader)) { + + } + + public DataLogBackgroundWriter(DataLogCallback callback, double period = 0.25, string extraHeader = "") : base(null) + { + gcHandle = GCHandle.Alloc(this); + this.callback = callback; + NativeHandle = DataLogNative.CreateBgFunc(&NativeDataLogCallback, (void*)GCHandle.ToIntPtr(gcHandle.Value), period, extraHeader); + } + + public override void Dispose() + { + base.Dispose(); + if (gcHandle.HasValue) { + gcHandle.Value.Free(); + } + } + + public string Filename + { + set + { + DataLogNative.SetFilename(NativeHandle, value); + } + } +} diff --git a/src/wpiutil/Logging/DataLogWriter.cs b/src/wpiutil/Logging/DataLogWriter.cs new file mode 100644 index 00000000..bcc846b9 --- /dev/null +++ b/src/wpiutil/Logging/DataLogWriter.cs @@ -0,0 +1,9 @@ +using WPIUtil.Natives; + +namespace WPIUtil.Logging; + +public unsafe class DataLogWriter : DataLog +{ + public DataLogWriter(string filename, string extraHeader = "") : base(DataLogNative.Create(filename, extraHeader)) { + } +} diff --git a/src/wpiutil/Natives/DataLogNative.cs b/src/wpiutil/Natives/DataLogNative.cs index adaf0e30..f251ef12 100644 --- a/src/wpiutil/Natives/DataLogNative.cs +++ b/src/wpiutil/Natives/DataLogNative.cs @@ -10,13 +10,17 @@ public struct OpaqueDataLog { } public static partial class DataLogNative { - [LibraryImport("wpiutil", EntryPoint = "WPI_DataLog_Create")] + [LibraryImport("wpiutil", EntryPoint = "WPI_DataLog_CreateWriter")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static unsafe partial OpaqueDataLog* Create(WpiString dir, WpiString filename, double period, WpiString extraHeader); + public static unsafe partial OpaqueDataLog* Create(WpiString dir, WpiString filename); - [LibraryImport("wpiutil", EntryPoint = "WPI_DataLog_Create_Func")] + [LibraryImport("wpiutil", EntryPoint = "WPI_DataLog_CreateBackgroundWriter")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static unsafe partial OpaqueDataLog* CreateFunc(delegate* unmanaged[Cdecl] write, void* ptr, double period, WpiString extraHeader); + public static unsafe partial OpaqueDataLog* CreateBg(WpiString dir, WpiString filename, double period, WpiString extraHeader); + + [LibraryImport("wpiutil", EntryPoint = "WPI_DataLog_CreateBackgroundWriter_Func")] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static unsafe partial OpaqueDataLog* CreateBgFunc(delegate* unmanaged[Cdecl] write, void* ptr, double period, WpiString extraHeader); [LibraryImport("wpiutil", EntryPoint = "WPI_DataLog_Release")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] diff --git a/test/wpiutil.test/DataLogTest.cs b/test/wpiutil.test/DataLogTest.cs index 51362bba..2fa672b7 100644 --- a/test/wpiutil.test/DataLogTest.cs +++ b/test/wpiutil.test/DataLogTest.cs @@ -20,7 +20,7 @@ public void TestDoesntCrash() { CallbackData cb = new(); { - using DataLog dl = new(cb.Callback); + using var dl = new DataLogBackgroundWriter(cb.Callback); } } }