Fix AccessViolationException when closing and reopening a NvidiaGpu instance (#221)

Thanks to @hirschmann
This commit is contained in:
Stefan Hirschmann
2020-03-30 11:26:50 +02:00
committed by GitHub
parent 17da2cb9ed
commit b0e7ea96b1
2 changed files with 56 additions and 41 deletions
@@ -107,7 +107,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu
_control.Control = _fanControl;
}
if (NvidiaML.IsAvailable)
if (NvidiaML.IsAvailable || NvidiaML.Initialize())
{
if (hasPciBusId)
_nvmlDevice = NvidiaML.NvmlDeviceGetHandleByPciBusId($" 0000:{busId:X2}:00.0") ?? NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex);
+55 -40
View File
@@ -14,6 +14,8 @@ namespace LibreHardwareMonitor.Interop
private const string LinuxDllName = "nvidia-ml";
private const string WindowsDllName = "nvml.dll";
private static readonly object SyncRoot = new object();
private static WindowsNvmlGetHandleDelegate _windowsNvmlDeviceGetHandleByIndex;
private static WindowsNvmlGetPowerUsageDelegate _windowsNvmlDeviceGetPowerUsage;
private static WindowsNvmlDeviceGetPcieThroughputDelegate _windowsNvmlDeviceGetPcieThroughputDelegate;
@@ -21,56 +23,64 @@ namespace LibreHardwareMonitor.Interop
private static WindowsNvmlDelegate _windowsNvmlInit;
private static WindowsNvmlDelegate _windowsNvmlShutdown;
private static readonly IntPtr WindowsDll;
private static IntPtr WindowsDll;
static NvidiaML()
internal static bool IsAvailable { get; private set; }
internal static bool Initialize()
{
if (Software.OperatingSystem.IsLinux)
lock (SyncRoot)
{
try
if (IsAvailable)
{
IsAvailable = nvmlInit() == NvmlReturn.Success;
return true;
}
catch (DllNotFoundException)
{ }
catch (EntryPointNotFoundException)
if (Software.OperatingSystem.IsLinux)
{
try
{
IsAvailable = nvmlInitLegacy() == NvmlReturn.Success;
IsAvailable = nvmlInit() == NvmlReturn.Success;
}
catch (EntryPointNotFoundException)
catch (DllNotFoundException)
{ }
catch (EntryPointNotFoundException)
{
try
{
IsAvailable = nvmlInitLegacy() == NvmlReturn.Success;
}
catch (EntryPointNotFoundException)
{ }
}
}
}
else if (IsNvmlCompatibleWindowsVersion())
{
// Attempt to load the Nvidia Management Library from the
// windows standard search order for applications. This will
// help installations that either have the library in
// %windir%/system32 or provide their own library
WindowsDll = Kernel32.LoadLibrary(WindowsDllName);
// If there is no dll in the path, then attempt to load it
// from program files
if (WindowsDll == IntPtr.Zero)
else if (IsNvmlCompatibleWindowsVersion())
{
string programFilesDirectory = Environment.ExpandEnvironmentVariables("%ProgramW6432%");
string dllPath = Path.Combine(programFilesDirectory, @"NVIDIA Corporation\NVSMI", WindowsDllName);
// Attempt to load the Nvidia Management Library from the
// windows standard search order for applications. This will
// help installations that either have the library in
// %windir%/system32 or provide their own library
WindowsDll = Kernel32.LoadLibrary(WindowsDllName);
WindowsDll = Kernel32.LoadLibrary(dllPath);
// If there is no dll in the path, then attempt to load it
// from program files
if (WindowsDll == IntPtr.Zero)
{
string programFilesDirectory = Environment.ExpandEnvironmentVariables("%ProgramW6432%");
string dllPath = Path.Combine(programFilesDirectory, @"NVIDIA Corporation\NVSMI", WindowsDllName);
WindowsDll = Kernel32.LoadLibrary(dllPath);
}
IsAvailable = (WindowsDll != IntPtr.Zero)
&& InitialiseDelegates()
&& (_windowsNvmlInit() == NvmlReturn.Success);
}
if (WindowsDll == IntPtr.Zero)
return;
IsAvailable = InitialiseDelegates() && (_windowsNvmlInit() == NvmlReturn.Success);
return IsAvailable;
}
}
internal static bool IsAvailable { get; }
private static bool IsNvmlCompatibleWindowsVersion()
{
return Software.OperatingSystem.Is64Bit && ((Environment.OSVersion.Version.Major > 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1));
@@ -137,16 +147,21 @@ namespace LibreHardwareMonitor.Interop
internal static void Close()
{
if (IsAvailable)
lock (SyncRoot)
{
if (Software.OperatingSystem.IsLinux)
if (IsAvailable)
{
nvmlShutdown();
}
else if (WindowsDll != IntPtr.Zero)
{
_windowsNvmlShutdown();
Kernel32.FreeLibrary(WindowsDll);
if (Software.OperatingSystem.IsLinux)
{
nvmlShutdown();
}
else if (WindowsDll != IntPtr.Zero)
{
_windowsNvmlShutdown();
Kernel32.FreeLibrary(WindowsDll);
}
IsAvailable = false;
}
}
}