Skip to content

Commit

Permalink
Suspend and Resume handler (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwalkiewicz authored Aug 13, 2024
1 parent cece46f commit 37249f0
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 1 deletion.
115 changes: 114 additions & 1 deletion Golem/Golem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

#if OS_WINDOWS
using Microsoft.Win32;
using System.Runtime.Versioning;
#endif

namespace Golem
{
public class Golem : IGolem, IAsyncDisposable, IGolemTesting
Expand Down Expand Up @@ -87,6 +92,11 @@ public bool FilterRequestors
}

private GolemStatus status;

private SemaphoreSlim SuspendHandlerLock { get; } = new SemaphoreSlim(1, 1);

private bool _isSuspendHandlerSetUp;

public GolemStatus Status
{
get { return status; }
Expand Down Expand Up @@ -183,6 +193,15 @@ public async Task Start()
if (IsRunning())
return;

await SetupSuspendHandlerAsync();

await InternalStart();
}

private async Task InternalStart() {
if (IsRunning())
return;

_logger.LogInformation("Starting Golem");

Status = GolemStatus.Starting;
Expand Down Expand Up @@ -230,6 +249,15 @@ public async Task Stop()
if (!IsRunning() && Status != GolemStatus.Error)
return;

await DetachSuspendHandler();

await InternalStop();
}

private async Task InternalStop() {
if (!IsRunning() && Status != GolemStatus.Error)
return;

_logger.LogInformation("Stopping Golem");

// Timeout is shorter when Stop was already called earlier.
Expand Down Expand Up @@ -353,6 +381,8 @@ Func<int, string, Task> ExitCleanupHandler(CancellationTokenSource yagnaCancella
}

Status = GolemStatus.Error;

await DetachSuspendHandler();
}
};
}
Expand Down Expand Up @@ -451,5 +481,88 @@ public List<String> LogFiles()
{
return Provider.ProviderProcess?.Id;
}

private async Task SetupSuspendHandlerAsync()
{
await SuspendHandlerLock.WaitAsync();
try {
if (_isSuspendHandlerSetUp) {
return;
}
#pragma warning disable CA1416 // Validate platform compatibility ensured by #if
SetupSuspendHandler_Impl();
#pragma warning restore CA1416 // Validate platform compatibility
_isSuspendHandlerSetUp = true;
} finally {
SuspendHandlerLock.Release();
}

}
private async Task DetachSuspendHandler()
{
await SuspendHandlerLock.WaitAsync();
try {
#pragma warning disable CA1416 // Validate platform compatibility ensured by #if
DetachSuspendHandler_Impl();
#pragma warning restore CA1416 // Validate platform compatibility
_isSuspendHandlerSetUp = false;
} finally {
SuspendHandlerLock.Release();
}
}

#if OS_WINDOWS

[SupportedOSPlatform("Windows")]
private void SetupSuspendHandler_Impl()
{
_logger.LogInformation("Setting up Suspend handler (Windows).");
SystemEvents.PowerModeChanged += OnPowerModeChanged;
}

[SupportedOSPlatform("Windows")]
private void DetachSuspendHandler_Impl()
{
_logger.LogInformation("Detaching Suspend handler (Windows).");
SystemEvents.PowerModeChanged -= OnPowerModeChanged;
}

[SupportedOSPlatform("Windows")]
private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
// Start and Stop tasks won't be waited upon in this event handler.
switch (e.Mode) {
case PowerModes.Suspend:
_logger.LogInformation("Received Suspend event - stopping Golem.");
InternalStop().ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
break;
case PowerModes.Resume:
_logger.LogInformation("Received Resume event - starting Golem.");
RestartOnResume().ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
break;
}
}

private async Task RestartOnResume()
{
// We are trying to stop Golem when the system is Resumed from a sleep
// because we cannot ensure that Suspend handler will execute to completion
// before the system is suspended.
await InternalStop();
await InternalStart();
}

#else // OS_WINDOWS

private void SetupSuspendHandler_Impl()
{
_logger.LogInformation("Suspend handler cannot be set on current platform.");
}

private void DetachSuspendHandler_Impl()
{
}

#endif // OS_WINDOWS
}
}
}
11 changes: 11 additions & 0 deletions Golem/Golem.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@
<PackageReference Include="AsyncKeyedLock" Version="6.4.2" />
</ItemGroup>

<Choose>
<When Condition=" '$(OS)' == 'Windows_NT' ">
<PropertyGroup>
<DefineConstants>OS_WINDOWS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.SystemEvents" Version="8.0.0" />
</ItemGroup>
</When>
</Choose>

<ItemGroup>
<ProjectReference Include="..\GolemLib\GolemLib.csproj" />
</ItemGroup>
Expand Down

0 comments on commit 37249f0

Please sign in to comment.