Skip to content

Commit 68b7b09

Browse files
committed
- Many changes to async code (File Swapper, Logging) and greatly sped up the file swapping process
- Task Scheduler entries no longer only run while plugged in
1 parent 757b0a9 commit 68b7b09

File tree

5 files changed

+49
-31
lines changed

5 files changed

+49
-31
lines changed

GPUPrefSwitcher/AppLogger.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -212,14 +212,14 @@ public int GlobalLogLevel
212212
/// <param name="str"></param>
213213
/// <param name="logLevel"></param>
214214
/// <returns></returns>
215-
public Task Log(string str, int logLevel = 1000)
215+
public void Log(string str, int logLevel = 1000)
216216
{
217217

218218
if(logLevel < 0) { throw new ArgumentOutOfRangeException("logLevel must be positive"); }
219219
if(logLevel > GlobalLogLevel)
220220
{
221221
skippedLogs++;
222-
return Task.CompletedTask;
222+
return;
223223
}
224224

225225
standardLogCount += 1;
@@ -228,12 +228,12 @@ public Task Log(string str, int logLevel = 1000)
228228

229229
if (EnableRealtimeStandardLogWrites)
230230
{
231-
semaphoreSlim_Standard.AvailableWaitHandle.WaitOne();//block if unavailable
232-
return WriteAsyncInternal_Standard(toWrite);
231+
semaphoreSlim_Standard.AvailableWaitHandle.WaitOne();//block if there's still a write in progress
232+
_ = WriteAsyncInternal_Standard(toWrite);
233233
}
234234

235235
StandardLogBuffer.Add(toWrite);
236-
return Task.CompletedTask;
236+
return;
237237

238238
}
239239

@@ -261,7 +261,6 @@ public string FormatMessageForStandardLog(string str, int logLevel)
261261
/// <returns></returns>
262262
private async Task WriteAsyncInternal_Standard(string str)
263263
{
264-
265264
await semaphoreSlim_Standard.WaitAsync();
266265

267266
try
@@ -274,6 +273,7 @@ private async Task WriteAsyncInternal_Standard(string str)
274273
{
275274
semaphoreSlim_Standard.Release();
276275
}
276+
277277
}
278278

279279
/// <summary>

GPUPrefSwitcher/FileSwapper.cs

+29-16
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public FileSwapper(AppEntry appEntry, PreferencesXML preferencesXML)
7070

7171
public async Task InitiateFileSwaps(PowerLineStatus forPowerLineStatus, PreferencesXML preferencesXML)
7272
{
73-
Logger.inst.Log($"Initiating FileSwap for AppEntry with target path {AppEntry.AppPath}");
73+
Logger.inst.Log($"Initiating File Swaps for AppEntry with target path {AppEntry.AppPath}");
7474

7575
//if the AppEntry doesn't yet have its own FileSwap folder, create it
7676
bool appEntryFolderExists = Directory.Exists(SettingsBankFolderPath);
@@ -80,6 +80,7 @@ public async Task InitiateFileSwaps(PowerLineStatus forPowerLineStatus, Preferen
8080
File.Create(Path.Combine(SettingsBankFolderPath, $"{AppEntry.AppName} settings are in {SettingsBankFolderPath}"));
8181
}
8282

83+
List<Task> fileSwapTasks = new();
8384
//commence the swap for each FileSwapPath
8485
for (int i = 0; i < AppEntry.FileSwapperPaths.Length; i++)
8586
{
@@ -99,7 +100,7 @@ public async Task InitiateFileSwaps(PowerLineStatus forPowerLineStatus, Preferen
99100

100101
try
101102
{
102-
Task singleFileSwap = InitiateSingleFileSwap(current, i);
103+
fileSwapTasks.Add(InitiateSingleFileSwap(current, i));
103104
}
104105
catch (AggregateException)
105106
{
@@ -108,7 +109,11 @@ public async Task InitiateFileSwaps(PowerLineStatus forPowerLineStatus, Preferen
108109

109110
} //...repeat for every SwapPath
110111

111-
Logger.inst.Log($"Finished firing FileSwap logic for AppEntry with target path {AppEntry.AppPath}");
112+
Logger.inst.Log($"Finished firing single FileSwap tasks for AppEntry with target path {AppEntry.AppPath}");
113+
114+
await Task.WhenAll(fileSwapTasks);
115+
116+
Logger.inst.Log($"Completed all FileSwap tasks for AppEntry with target path {AppEntry.AppPath}");
112117

113118
}
114119

@@ -154,15 +159,15 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
154159
WaitForOlderFileSwaps:
155160
if (OngoingFileSwapTasks.Any(x => x.FileSwapPath == fileSwapPathTask.FileSwapPath && x.ID < fileSwapPathTask.ID))
156161
{
157-
Task log = Logger.inst.Log($"An older FileSwap task for {swapPath} already exists, delaying");
162+
Logger.inst.Log($"An older FileSwap task for {swapPath} already exists, delaying");
158163
await Task.Delay(10000);
159164
goto WaitForOlderFileSwaps;
160165
}
161166

162167
WaitForAppToClose:
163-
if (IsProcessRunning(AppEntry.AppPath))
168+
if (await IsProcessRunning(AppEntry.AppPath)) //IsProcessRunning is apparently VERY expensive
164169
{
165-
Task log = Logger.inst.Log($"Target app {AppEntry.AppPath} is still running, delaying File Swap for {swapPath}");
170+
Logger.inst.Log($"Target app {AppEntry.AppPath} is still running, delaying File Swap for {swapPath}");
166171
await Task.Delay(5000);
167172
goto WaitForAppToClose;
168173
}
@@ -184,7 +189,7 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
184189
StoreFile_OnBattery:
185190
try
186191
{
187-
FileCopyConsiderAccessRules(swapPath, onBatteryStoredFilePath, true, false);
192+
await FileCopyConsiderAccessRules(swapPath, onBatteryStoredFilePath, true, false);
188193
File.Create(Path.Combine(SettingsBankFolderPath, $"{Path.GetFileName(swapPath)} is in {swapPathHash}"));
189194
}
190195
catch (IOException)
@@ -203,7 +208,7 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
203208
StoreFile_PluggedIn:
204209
try
205210
{
206-
FileCopyConsiderAccessRules(swapPath, pluggedInStoredFilePath, true, false);
211+
await FileCopyConsiderAccessRules(swapPath, pluggedInStoredFilePath, true, false);
207212
File.Create(Path.Combine(SettingsBankFolderPath, $"{Path.GetFileName(swapPath)} is in {swapPathHash}"));
208213
}
209214
catch (IOException)
@@ -224,13 +229,13 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
224229
try
225230
{
226231
//no need to cancel the save if the substitution fails
227-
FileCopyConsiderAccessRules(swapPath, pluggedInStoredFilePath, true, false); //save current config to PluggedIn store
232+
await FileCopyConsiderAccessRules(swapPath, pluggedInStoredFilePath, true, false); //save current config to PluggedIn store
228233
string s1 = $"Saved SwapPath {swapPath} for app {AppEntry.AppPath} as PluggedIn";
229234
Logger.inst.Log(s1);
230235

231236
errorFlag = 1;
232237

233-
FileCopyConsiderAccessRules(onBatteryStoredFilePath, swapPath, true, true); //then substitute with OnBattery config
238+
await FileCopyConsiderAccessRules(onBatteryStoredFilePath, swapPath, true, true); //then substitute with OnBattery config
234239
string s2 = $"Substituted OnBattery config into SwapPath {swapPath} for app {AppEntry.AppPath}";
235240
Logger.inst.Log(s2);
236241

@@ -256,6 +261,9 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
256261
preferencesXML.ModifyAppEntryAndSave(AppEntry.AppPath, modified);
257262
string s3 = $"Saved SwapPath state for SwapPath {swapPath} for app {AppEntry.AppPath}";
258263
Logger.inst.Log(s3);
264+
} else
265+
{
266+
Logger.inst.Log($"Skipped operations for File Swap path {swapPath} because it's already in its correct state.");
259267
}
260268
}
261269
else if (forPowerLineStatus == PowerLineStatus.Online)
@@ -268,13 +276,13 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
268276
{
269277

270278
//no need to cancel the save if the substitution fails
271-
FileCopyConsiderAccessRules(swapPath, onBatteryStoredFilePath, true, false); //save current config to OnBattery store
279+
await FileCopyConsiderAccessRules(swapPath, onBatteryStoredFilePath, true, false); //save current config to OnBattery store
272280
string s1 = $"Saved SwapPath {swapPath} for app {AppEntry.AppPath} as OnBattery";
273281
Logger.inst.Log(s1);
274282

275283
errorFlag = 1;
276284

277-
FileCopyConsiderAccessRules(pluggedInStoredFilePath, swapPath, true, true); //then substitute with PluggedIn config
285+
await FileCopyConsiderAccessRules(pluggedInStoredFilePath, swapPath, true, true); //then substitute with PluggedIn config
278286
string s2 = $"Substituted PluggedIn config into SwapPath {swapPath} for app {AppEntry.AppPath}";
279287
Logger.inst.Log(s2);
280288
}
@@ -298,20 +306,23 @@ private async Task InitiateSingleFileSwap(FileSwapPathTask fileSwapPathTask, int
298306
preferencesXML.ModifyAppEntryAndSave(AppEntry.AppPath, modified);
299307
string s3 = $"Saved SwapPath state for SwapPath {swapPath} for app {AppEntry.AppPath}";
300308
Logger.inst.Log(s3);
309+
} else
310+
{
311+
Logger.inst.Log($"Skipped operations for File Swap path {swapPath} because it's already in its correct state.");
301312
}
302313
}
303314
else
304315
{
305316
Debug.WriteLine($"Unknown power state: " + forPowerLineStatus.ToString());
306317
}
307318

308-
await Logger.inst.Log($"FileSwaps Task finished for {AppEntry.AppPath}");
319+
Logger.inst.Log($"FileSwap Task {fileSwapPathTask.FileSwapPath} finished for {AppEntry.AppPath}");
309320

310321
OngoingFileSwapTasks.Remove(fileSwapPathTask);
311322

312323
}
313324

314-
static bool IsProcessRunning(string processPath)
325+
static async Task<bool> IsProcessRunning(string processPath) //this function is apparently VERY expensive to run (many mores times than this app itself) so await it!
315326
{
316327
Process[] processes = Process.GetProcesses();
317328

@@ -320,7 +331,7 @@ static bool IsProcessRunning(string processPath)
320331
try
321332
{
322333
// Compare the process's main module file name with the specified process path
323-
if (string.Equals(process.MainModule.FileName, processPath, StringComparison.OrdinalIgnoreCase))
334+
if (await Task.Run(() => string.Equals(process.MainModule.FileName, processPath, StringComparison.OrdinalIgnoreCase))) //the expensive line in question
324335
{
325336
return true;
326337
}
@@ -379,7 +390,7 @@ static byte[] GetHash(string str)
379390
/// </summary>
380391
///
381392
/// And yes, I think it's clearer to throw exceptions instead of returning false, unless there is a better way (in which I have tried TWICE; this is perfectly functional)
382-
public static void FileCopyConsiderAccessRules(string sourceFileName, string destinationFileName, bool overwrite, bool ensureDestinationExists = true)
393+
public static Task FileCopyConsiderAccessRules(string sourceFileName, string destinationFileName, bool overwrite, bool ensureDestinationExists = true)
383394
{
384395

385396
FileInfo sourceInfo = new FileInfo(sourceFileName);
@@ -437,6 +448,8 @@ public static void FileCopyConsiderAccessRules(string sourceFileName, string des
437448
sourceFileSecurity.SetAccessRuleProtection(true, true); //supposedly this doesn't change the existing file's security settings?
438449
File.Copy(sourceFileName, destinationFileName, true);
439450
destinationInfo.SetAccessControl(sourceFileSecurity); //requires the file to exist, duh
451+
452+
return Task.CompletedTask;
440453
}
441454

442455
/*

GPUPrefSwitcher/Switcher.cs

+7-6
Original file line numberDiff line numberDiff line change
@@ -251,29 +251,30 @@ private static void UpdateSeenInRegistryStatuses()
251251
}
252252
}
253253

254-
private static Task BeginFileSwapLogic(PowerLineStatus forPowerLineStatus, IEnumerable<AppEntry> forAppEntries)
254+
private static async Task BeginFileSwapLogic(PowerLineStatus forPowerLineStatus, IEnumerable<AppEntry> forAppEntries)
255255
{
256256
Logger.inst.Log("Commence file swap logic.");
257-
//shorten these long names
258257

259258
//create the SettingsBank directory if it doesn't exist
260259
bool fileSwapperFolderExists = Directory.Exists(FileSwapper.SwapPathFolder);
261260
if (!fileSwapperFolderExists) { Directory.CreateDirectory(FileSwapper.SwapPathFolder); }
262261

262+
List<Task> fileSwapTasks = new();
263263
foreach (AppEntry appEntry in forAppEntries)
264264
{
265265
var fileSwap = new FileSwapper(appEntry, preferencesXML);
266266

267267
if (!appEntry.EnableFileSwapper) continue;
268268
if (appEntry.FileSwapperPaths.Length == 0) continue;
269269

270-
fileSwap.InitiateFileSwaps(forPowerLineStatus, preferencesXML);
270+
Task fileSwapTask = fileSwap.InitiateFileSwaps(forPowerLineStatus, preferencesXML);
271+
fileSwapTasks.Add(fileSwapTask);
271272

272-
} //...repeat for every AppEntry
273+
}
273274

274-
Logger.inst.Log("File swap logic finished.");
275+
await Task.WhenAll(fileSwapTasks);
275276

276-
return Task.CompletedTask;
277+
Logger.inst.Log("File swap logic finished.");
277278
}
278279

279280
static string[] ignoreList = RegistryHelper.ignoreValues;

GPUPrefSwitcher/SwitcherService.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public Task StartAsync(CancellationToken cancellationToken)
3030
private void OnSessionEnd(object sender, SessionEndingEventArgs e)
3131
{
3232
e.Cancel = true;
33-
Logger.inst.Log($"OnSessionEnd received (reason: {e.Reason})").Wait();
33+
Logger.inst.Log($"OnSessionEnd received (reason: {e.Reason})");
3434
if (e.Reason == SessionEndReasons.SystemShutdown)
3535
{
3636
CleanUpService();
@@ -41,7 +41,7 @@ private void OnSessionEnd(object sender, SessionEndingEventArgs e)
4141
public Task StopAsync(CancellationToken cancellationToken)
4242
{
4343

44-
Logger.inst.Log("Service StopAsync called").Wait();
44+
Logger.inst.Log("Service StopAsync called");
4545

4646
CleanUpService();
4747

@@ -55,7 +55,7 @@ public void Dispose()
5555

5656
private void CleanUpService()
5757
{
58-
Logger.inst.Log("Service ending cleanup called.").Wait();
58+
Logger.inst.Log("Service ending cleanup called.");
5959

6060
Logger.inst.DumpStandardLogBufferToStandardLog().Wait();
6161

GPUPrefSwitcher/TaskSchedulerUtils.cs

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public static void RunOnBatteryTask()
1717
string description = "The GPUPrefSwitcher service runs this task once when the system is considered on battery." +
1818
"\n It is up to you to add actions (e.g. start a script).";
1919
CreateTask(TASK_NAME_ON_BATTERY, description, FOLDER_NAME);
20+
Logger.inst.Log("Created On Battery Task Scheduler entry because it doesn't exist yet");
2021
}
2122

2223
RunTask(TASK_NAME_ON_BATTERY);
@@ -29,6 +30,7 @@ public static void RunPluggedInTask()
2930
string description = "The GPUPrefSwitcher service runs this task once when the system is considered plugged in." +
3031
"\n It is up to you to add actions (e.g. start a script).";
3132
CreateTask(TASK_NAME_PLUGGED_IN, description, FOLDER_NAME);
33+
Logger.inst.Log("Created Plugged In Task Scheduler entry because it doesn't exist yet");
3234
}
3335

3436
RunTask(TASK_NAME_PLUGGED_IN);
@@ -52,6 +54,8 @@ public static void CreateTask(string taskName, string description, string folder
5254
//we need to create at least one action otherwise it complains
5355
taskDefinition.Actions.Add(new ExecAction("cmd.exe", "/c echo Dummy task executed", null));
5456

57+
taskDefinition.Settings.DisallowStartIfOnBatteries = false;
58+
taskDefinition.Settings.StopIfGoingOnBatteries = false;
5559

5660
TaskFolder folder = taskService.GetFolder(folderPath);
5761
if (folder == null)

0 commit comments

Comments
 (0)