Use global mutex to ensure driver access are sequential

This commit is contained in:
Kamil Trzciński 2022-11-20 21:17:21 +01:00
parent a1a438c3f8
commit f7e3e70c2b
6 changed files with 148 additions and 74 deletions

View file

@ -6,6 +6,7 @@ using System.Security;
using System.Security.Principal;
using System.Security.AccessControl;
using System.Windows.Forms;
using System.Runtime.CompilerServices;
namespace CommonHelpers
{
@ -21,10 +22,44 @@ namespace CommonHelpers
};
private static Mutex? runOnceMutex;
private static Mutex? globalLockMutex;
private const String GLOBAL_MUTEX_NAME = "Global\\SteamDeckToolsCommonHelpers";
private const int GLOBAL_DEFAULT_TIMEOUT = 5000;
public static Mutex? WaitGlobalMutex(int timeoutMs)
{
if (globalLockMutex == null)
globalLockMutex = TryCreateOrOpenExistingMutex(GLOBAL_MUTEX_NAME);
try
{
if (globalLockMutex.WaitOne(timeoutMs))
return globalLockMutex;
return null;
}
catch(AbandonedMutexException)
{
return globalLockMutex;
}
}
public static T WithGlobalMutex<T>(int timeoutMs, Func<T> func)
{
var mutex = WaitGlobalMutex(timeoutMs);
if (mutex is null)
return default(T);
try
{
return func();
}
finally
{
mutex.ReleaseMutex();
}
}
public static void Open(String title, String? runOnce = null, int runOnceTimeout = 100)
{
if (runOnce is not null)
@ -32,9 +67,11 @@ namespace CommonHelpers
RunOnce(title, runOnce, runOnceTimeout);
}
using (var globalLock = TryCreateOrOpenExistingMutex(GLOBAL_MUTEX_NAME))
var mutex = WaitGlobalMutex(GLOBAL_DEFAULT_TIMEOUT);
try
{
if (!globalLock.WaitOne(GLOBAL_DEFAULT_TIMEOUT))
if (mutex is null)
{
Fatal(title, "Failed to acquire global mutex.");
}
@ -51,8 +88,10 @@ namespace CommonHelpers
}
HardwareComputer.Open();
globalLock.ReleaseMutex();
}
finally
{
mutex.ReleaseMutex();
}
}

View file

@ -73,11 +73,27 @@ namespace FanControl
public void Update()
{
foreach (var sensor in allSensors.Values)
sensor.Reset();
var mutex = Instance.WaitGlobalMutex(200);
foreach (var hardware in Instance.HardwareComputer.Hardware)
visitHardware(hardware);
if (mutex is null)
{
// If we cannot acquire mutex slightly increase FAN to compensate just in case
Vlv0100.SetFanDesiredRPM((ushort)(Vlv0100.GetFanDesiredRPM() * 110 / 100));
return;
}
try
{
foreach (var sensor in allSensors.Values)
sensor.Reset();
foreach (var hardware in Instance.HardwareComputer.Hardware)
visitHardware(hardware);
}
finally
{
mutex.ReleaseMutex();
}
allSensors["Batt"].Update("VLV0100", Vlv0100.GetBattTemperature(), Mode);

View file

@ -334,19 +334,23 @@ namespace PerformanceOverlay
public void Update()
{
var allSensors = new List<ISensor>();
foreach (IHardware hardware in Instance.HardwareComputer.Hardware)
Instance.WithGlobalMutex(200, () =>
{
try
{
hardware.Update();
}
catch (SystemException) { }
hardware.Accept(new SensorVisitor(sensor => allSensors.Add(sensor)));
}
var allSensors = new List<ISensor>();
this.AllHardwareSensors = allSensors;
foreach (IHardware hardware in Instance.HardwareComputer.Hardware)
{
try
{
hardware.Update();
}
catch (SystemException) { }
hardware.Accept(new SensorVisitor(sensor => allSensors.Add(sensor)));
}
this.AllHardwareSensors = allSensors;
return true;
});
}
public string? GetValue(String name)

View file

@ -51,21 +51,25 @@ namespace PowerControl.Helpers.GPU
return true;
}
public VangoghGPU? Open()
public VangoghGPU? Open(bool validateSMU = true)
{
var gpu = VangoghGPU.OpenMMIO(MMIOAddress, MMIOSize);
if (gpu == null)
return null;
// Check supported SMU version
var smuVersion = gpu.SMUVersion;
if (smuVersion != SMUVersion)
if (validateSMU)
{
Log("SMU: {0:X8} => not supported", smuVersion);
return null;
// Check supported SMU version
var smuVersion = gpu.SMUVersion;
if (smuVersion != SMUVersion)
{
Log("SMU: {0:X8} => not supported", smuVersion);
return null;
}
Log("SMU: {0:X8} => detected", smuVersion);
}
Log("SMU: {0:X8} => detected", smuVersion);
return gpu;
}
};
@ -85,7 +89,7 @@ namespace PowerControl.Helpers.GPU
public static VangoghGPU? Open()
{
return DetectedDevice?.Open();
return DetectedDevice?.Open(false);
}
public static bool Detect()

View file

@ -160,14 +160,19 @@ namespace PowerControl
if (VangoghGPU.IsSupported)
{
using (var sd = VangoghGPU.Open())
return Instance.WithGlobalMutex<object>(200, () =>
{
if (sd is null)
return null;
using (var sd = VangoghGPU.Open())
{
if (sd is null)
return null;
sd.SlowTDP = mW;
sd.FastTDP = mW;
}
sd.SlowTDP = mW;
sd.FastTDP = mW;
}
return selected;
});
}
else
{
@ -185,9 +190,9 @@ namespace PowerControl
UseShellExecute = false,
CreateNoWindow = true
});
}
return selected;
return selected;
}
}
},
new Menu.MenuItemWithOptions()
@ -200,20 +205,23 @@ namespace PowerControl
ResetValue = () => { return "Default"; },
ApplyValue = delegate(object selected)
{
using (var sd = VangoghGPU.Open())
return Instance.WithGlobalMutex<object>(200, () =>
{
if (sd is null)
return null;
if (selected.ToString() == "Default")
using (var sd = VangoghGPU.Open())
{
sd.HardMinGfxClock = 200;
if (sd is null)
return null;
if (selected.ToString() == "Default")
{
sd.HardMinGfxClock = 200;
return selected;
}
sd.HardMinGfxClock = uint.Parse(selected.ToString().Replace("MHz", ""));
return selected;
}
sd.HardMinGfxClock = uint.Parse(selected.ToString().Replace("MHz", ""));
return selected;
}
});
}
},
new Menu.MenuItemWithOptions()
@ -226,38 +234,41 @@ namespace PowerControl
ResetValue = () => { return "Default"; },
ApplyValue = delegate(object selected)
{
using (var sd = VangoghGPU.Open())
return Instance.WithGlobalMutex<object>(200, () =>
{
if (sd is null)
return null;
switch(selected.ToString())
using (var sd = VangoghGPU.Open())
{
case "Default":
sd.MinCPUClock = 1400;
sd.MaxCPUClock = 3500;
break;
case "Power-Save":
sd.MinCPUClock = 1400;
sd.MaxCPUClock = 1800;
break;
case "Balanced":
sd.MinCPUClock = 2200;
sd.MaxCPUClock = 2800;
break;
case "Max":
sd.MinCPUClock = 3000;
sd.MaxCPUClock = 3500;
break;
default:
if (sd is null)
return null;
switch(selected.ToString())
{
case "Default":
sd.MinCPUClock = 1400;
sd.MaxCPUClock = 3500;
break;
case "Power-Save":
sd.MinCPUClock = 1400;
sd.MaxCPUClock = 1800;
break;
case "Balanced":
sd.MinCPUClock = 2200;
sd.MaxCPUClock = 2800;
break;
case "Max":
sd.MinCPUClock = 3000;
sd.MaxCPUClock = 3500;
break;
default:
return null;
}
return selected;
}
return selected;
}
});
}
},
new Menu.MenuItemWithOptions()

View file

@ -20,7 +20,7 @@ namespace PowerControl
{
Trace.WriteLine("WinRing0 initialized=" + WinRing0.InitializeOls().ToString());
VangoghGPU.Detect();
Instance.WithGlobalMutex(1000, () => VangoghGPU.Detect());
}
// To customize application configuration such as set high DPI settings or default font,