From 3d8ed3905e9ef029d01e3484330a23d939c2698c Mon Sep 17 00:00:00 2001 From: Den Delimarsky <1389609+dend@users.noreply.github.com> Date: Tue, 11 May 2021 19:10:15 -0700 Subject: [PATCH] Proper threading support for all parts of the keep-awake process --- .../espresso/Espresso/Core/APIHelper.cs | 60 ++++++++++++++----- src/modules/espresso/Espresso/Program.cs | 40 +++---------- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/modules/espresso/Espresso/Core/APIHelper.cs b/src/modules/espresso/Espresso/Core/APIHelper.cs index ac7b67e064..b56025286e 100644 --- a/src/modules/espresso/Espresso/Core/APIHelper.cs +++ b/src/modules/espresso/Espresso/Core/APIHelper.cs @@ -78,21 +78,14 @@ namespace Espresso.Shell.Core return SetAwakeState(EXECUTION_STATE.ES_CONTINUOUS); } - /// - /// Sets up the machine to be awake indefinitely. - /// - /// Determines whether the display should be kept on while the machine is awake. - /// Status of the attempt. True if successful, false if not. - public static bool SetIndefiniteKeepAwake(bool keepDisplayOn = true) + public static void SetIndefiniteKeepAwake(Action callback, Action failureCallback, bool keepDisplayOn = true) { - if (keepDisplayOn) - { - return SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS); - } - else - { - return SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS); - } + _tokenSource = new CancellationTokenSource(); + _threadToken = _tokenSource.Token; + + Task.Run(() => RunIndefiniteLoop(keepDisplayOn), _threadToken) + .ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion) + .ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion); } public static void SetTimedKeepAwake(long seconds, Action callback, Action failureCallback, bool keepDisplayOn = true) @@ -105,6 +98,45 @@ namespace Espresso.Shell.Core .ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion); } + private static bool RunIndefiniteLoop(bool keepDisplayOn = true) + { + bool success; + if (keepDisplayOn) + { + success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS); + } + else + { + success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS); + } + + try + { + if (success) + { + _log.Info("Initiated indefinite keep awake in background thread."); + while (true) + { + if (_threadToken.IsCancellationRequested) + { + _threadToken.ThrowIfCancellationRequested(); + } + } + } + else + { + _log.Info("Could not successfully set up indefinite keep awake."); + return success; + } + } + catch (OperationCanceledException ex) + { + // Task was clearly cancelled. + _log.Info($"Background thread termination. Message: {ex.Message}"); + return success; + } + } + private static bool RunTimedLoop(long seconds, bool keepDisplayOn = true) { bool success = false; diff --git a/src/modules/espresso/Espresso/Program.cs b/src/modules/espresso/Espresso/Program.cs index 025d163d88..2e3f06cb39 100644 --- a/src/modules/espresso/Espresso/Program.cs +++ b/src/modules/espresso/Espresso/Program.cs @@ -186,38 +186,29 @@ namespace Espresso.Shell } } + var exitSignal = new ManualResetEvent(false); if (pid != 0) { RunnerHelper.WaitForPowerToysRunner(pid, () => { + exitSignal.Set(); Environment.Exit(0); }); } - new ManualResetEvent(false).WaitOne(); + exitSignal.WaitOne(); } private static void SetupIndefiniteKeepAwake(bool displayOn) { // Indefinite keep awake. - bool success = APIHelper.SetIndefiniteKeepAwake(displayOn); - if (success) - { - _log.Info($"Currently in indefinite keep awake. Display always on: {displayOn}"); - } - else - { - var errorMessage = "Could not set up the state to be indefinite keep awake."; - _log.Info(errorMessage); - _log.Debug(errorMessage); - } + APIHelper.SetIndefiniteKeepAwake(LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn); } private static void HandleEspressoConfigChange(FileSystemEventArgs fileEvent) { _log.Info("Detected a settings file change. Updating configuration..."); _log.Info("Resetting keep-awake to normal state due to settings change."); - ResetNormalPowerState(); ProcessSettings(); } @@ -277,34 +268,19 @@ namespace Espresso.Shell { _log.Info($"Timed keep-awake. Expected runtime: {time} seconds with display on setting set to {displayOn}."); - APIHelper.SetTimedKeepAwake(time, LogTimedKeepAwakeCompletion, LogUnexpectedOrCancelledKeepAwakeCompletion, displayOn); + APIHelper.SetTimedKeepAwake(time, LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn); } - private static void LogUnexpectedOrCancelledKeepAwakeCompletion() + private static void LogUnexpectedOrCancelledKeepAwakeThreadCompletion() { var errorMessage = "The keep-awake thread was terminated early."; _log.Info(errorMessage); _log.Debug(errorMessage); } - private static void LogTimedKeepAwakeCompletion(bool result) + private static void LogCompletedKeepAwakeThread(bool result) { - _log.Info($"Completed timed keep-awake successfully: {result}"); - } - - private static void ResetNormalPowerState() - { - bool success = APIHelper.SetNormalKeepAwake(); - if (success) - { - _log.Info("Returned to normal keep-awake state."); - } - else - { - var errorMessage = "Could not return to normal keep-awake state."; - _log.Info(errorMessage); - _log.Debug(errorMessage); - } + _log.Info($"Exited keep-awake thread successfully: {result}"); } } }