Skip to content

Commit

Permalink
Added detailed error for LoadLib exceptions + Added support for LoadL…
Browse files Browse the repository at this point in the history
…ibraryEx
  • Loading branch information
sandrohanea committed Mar 18, 2023
1 parent 0d1f691 commit e8c49a8
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Whisper.net.Demo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using System;
using System.IO;
Expand Down
2 changes: 1 addition & 1 deletion Whisper.net/Internals/Native/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal struct WhisperParamBeamSearch
internal delegate bool WhisperEncoderBeginCallback(IntPtr ctx, IntPtr state, IntPtr user_data);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool WhisperLogitsFilterCallback(IntPtr ctx, IntPtr tokens, int tokens_count, IntPtr logits, IntPtr user_data);
internal delegate bool WhisperLogitsFilterCallback(IntPtr ctx, IntPtr tokens, int tokens_count, IntPtr logits, IntPtr user_data);

[StructLayout(LayoutKind.Sequential)]
internal struct WhisperFullParams
Expand Down
8 changes: 5 additions & 3 deletions Whisper.net/Internals/Native/LibraryLoader/ILibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using Whisper.net.Internals.Native.LibraryLoader;

namespace Whisper.net.Native.LibraryLoader;

internal interface ILibraryLoader
{
IntPtr OpenLibrary(string filename, int flags);
}
LoadResult OpenLibrary(string filename);
}
36 changes: 31 additions & 5 deletions Whisper.net/Internals/Native/LibraryLoader/LinuxLibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using System.Runtime.InteropServices;
using Whisper.net.Internals.Native.LibraryLoader;

namespace Whisper.net.Native.LibraryLoader;

Expand All @@ -12,15 +13,40 @@ internal class LinuxLibraryLoader : ILibraryLoader
[DllImport("libdl.so.2", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlopen")]
public static extern IntPtr NativeOpenLibraryLibdl2(string filename, int flags);

public IntPtr OpenLibrary(string filename, int flags)
[DllImport("libdl.so", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlerror")]
public static extern IntPtr GetLoadError();

[DllImport("libdl.so.2", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlerror")]
public static extern IntPtr GetLoadError2();

public LoadResult OpenLibrary(string filename)
{
IntPtr loadedLib;
try
{
return NativeOpenLibraryLibdl2(filename, flags);
// open with rtls lazy flag
loadedLib = NativeOpenLibraryLibdl2(filename, 0x00001);
}
catch (DllNotFoundException)
{
return NativeOpenLibraryLibdl(filename, flags);
loadedLib = NativeOpenLibraryLibdl(filename, 0x00001);
}

if (loadedLib == IntPtr.Zero)
{
string errorMessage;
try
{
errorMessage = Marshal.PtrToStringAnsi(GetLoadError2()) ?? "Unknown error";
}
catch (DllNotFoundException)
{
errorMessage = Marshal.PtrToStringAnsi(GetLoadError()) ?? "Unknown error";
}

return LoadResult.Failure(errorMessage);
}

return LoadResult.Success;
}
}
}
22 changes: 22 additions & 0 deletions Whisper.net/Internals/Native/LibraryLoader/LoadResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT

namespace Whisper.net.Internals.Native.LibraryLoader;

internal class LoadResult
{
private LoadResult(bool isSuccess, string? errorMessage)
{
IsSuccess = isSuccess;
ErrorMessage = errorMessage;
}

public static LoadResult Success { get; } = new(true, null);

public static LoadResult Failure(string errorMessage)
{
return new(false, errorMessage);
}

public bool IsSuccess { get; }
public string? ErrorMessage { get; }
}
19 changes: 16 additions & 3 deletions Whisper.net/Internals/Native/LibraryLoader/MacOsLibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using System.Runtime.InteropServices;
using Whisper.net.Internals.Native.LibraryLoader;

namespace Whisper.net.Native.LibraryLoader;

Expand All @@ -9,8 +10,20 @@ internal class MacOsLibraryLoader : ILibraryLoader
[DllImport("libdl.dylib", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlopen")]
public static extern IntPtr NativeOpenLibraryLibdl(string filename, int flags);

public IntPtr OpenLibrary(string filename, int flags)
[DllImport("libdl.dylib", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlerror")]
public static extern IntPtr GetLoadError();

public LoadResult OpenLibrary(string filename)
{
return NativeOpenLibraryLibdl(filename, flags);
var loadedLib = NativeOpenLibraryLibdl(filename, 0x00001);

if (loadedLib == IntPtr.Zero)
{
var errorMessage = Marshal.PtrToStringAnsi(GetLoadError()) ?? "Unknown error";

return LoadResult.Failure(errorMessage);
}

return LoadResult.Success;
}
}
}
30 changes: 27 additions & 3 deletions Whisper.net/Internals/Native/LibraryLoader/WindowsLibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using System.ComponentModel;
using System.Runtime.InteropServices;
using Whisper.net.Internals.Native.LibraryLoader;

namespace Whisper.net.Native.LibraryLoader;

internal class WindowsLibraryLoader : ILibraryLoader
{
public IntPtr OpenLibrary(string filename, int flags)
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000;
public LoadResult OpenLibrary(string filename)
{
return LoadLibrary(filename);
IntPtr loadedLib;

try
{
loadedLib = LoadLibraryEx(filename, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
}
catch (DllNotFoundException)
{
loadedLib = LoadLibrary(filename);
}

if (loadedLib == IntPtr.Zero)
{
var errorCode = Marshal.GetLastWin32Error();
var errorMessage = new Win32Exception(errorCode).Message;
return LoadResult.Failure(errorMessage);
}

return LoadResult.Success;
}

[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPTStr)] string lpFileName);

[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibraryEx([MarshalAs(UnmanagedType.LPTStr)] string lpFileName, IntPtr hFile, uint dwFlags);
}
8 changes: 4 additions & 4 deletions Whisper.net/Internals/Native/NativeLibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using System.Runtime.InteropServices;
using Whisper.net.Internals.Native.LibraryLoader;
using Whisper.net.Native.LibraryLoader;

namespace Whisper.net.Native;

internal static class NativeLibraryLoader
{
internal static bool LoadNativeLibrary()
internal static LoadResult LoadNativeLibrary()
{
var architecture = RuntimeInformation.OSArchitecture switch
{
Expand Down Expand Up @@ -47,8 +48,7 @@ internal static bool LoadNativeLibrary()
_ => throw new PlatformNotSupportedException($"Currently {platform} platform is not supported")
};

// open with rtls lazy flag
var result = libraryLoader.OpenLibrary(path, 0x00001);
return result != IntPtr.Zero;
var result = libraryLoader.OpenLibrary(path);
return result;
}
}
9 changes: 5 additions & 4 deletions Whisper.net/WhisperFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed under the MIT license: https://opensource.org/licenses/MIT
// Licensed under the MIT license: https://opensource.org/licenses/MIT

using Whisper.net.Internals.ModelLoader;
using Whisper.net.Internals.Native.LibraryLoader;
using Whisper.net.Native;

namespace Whisper.net;
Expand All @@ -17,16 +18,16 @@ public sealed class WhisperFactory : IDisposable
private readonly Lazy<IntPtr> contextLazy;
private bool wasDisposed = false;

private static readonly Lazy<bool> libraryLoaded = new(() =>
private static readonly Lazy<LoadResult> libraryLoaded = new(() =>
{
return NativeLibraryLoader.LoadNativeLibrary();
}, true);

private WhisperFactory(IWhisperProcessorModelLoader loader, bool delayInit)
{
if (!libraryLoaded.Value)
if (!libraryLoaded.Value.IsSuccess)
{
throw new Exception("Failed to load native whisper library.");
throw new Exception($"Failed to load native whisper library. Error: {libraryLoaded.Value.ErrorMessage}");
}

this.loader = loader;
Expand Down

0 comments on commit e8c49a8

Please sign in to comment.