Add TGS3 style process suspend/resume while swapping

This commit is contained in:
Jordan Brown
2020-01-19 02:32:00 -05:00
parent 02b220ab7b
commit 4ba539a4b1
6 changed files with 111 additions and 7 deletions
@@ -130,11 +130,12 @@ namespace Tgstation.Server.Host.Components.Repository
if (disposed)
return;
logger.LogTrace("Disposing...");
disposed = true;
repository.Dispose();
onDispose();
}
logger.LogTrace("Disposing...");
repository.Dispose();
onDispose();
}
void GetRepositoryOwnerName(string remote, out string owner, out string name)
@@ -549,6 +549,12 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <inheritdoc />
public void SetHighPriority() => process.SetHighPriority();
/// <inheritdoc />
public void Suspend() => process.Suspend();
/// <inheritdoc />
public void Resume() => process.Resume();
/// <inheritdoc />
public void ReplaceDmbProvider(IDmbProvider dmbProvider)
{
@@ -120,7 +120,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (pendingSwappable != null)
{
Logger.LogTrace("Replacing activeSwappable with pendingSwappable");
Server.ReplaceDmbProvider(pendingSwappable);
activeSwappable = pendingSwappable;
pendingSwappable = null;
@@ -139,7 +138,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
windowsProvider = new WindowsSwappableDmbProvider(compileJobProvider, ioManager, symlinkFactory);
Logger.LogDebug("Swapping to compile job {0}...", windowsProvider.CompileJob.Id);
Server.Suspend();
await windowsProvider.MakeActive(cancellationToken).ConfigureAwait(false);
Server.Resume();
}
catch
{
@@ -24,6 +24,14 @@ namespace Tgstation.Server.Host
AllowUnprivilegedCreate = 2
}
/// <summary>
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx
/// </summary>
public enum ThreadAccess : int
{
SuspendResume = 0x0002,
}
/// <summary>
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowthreadprocessid
/// </summary>
@@ -70,5 +78,29 @@ namespace Tgstation.Server.Host
/// </summary>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, CreateSymbolicLinkFlags dwFlags);
/// <summary>
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v=vs.85).aspx
/// </summary>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
/// <summary>
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
/// </summary>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
/// <summary>
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686345(v=vs.85).aspx
/// </summary>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint SuspendThread(IntPtr hThread);
/// <summary>
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms685086(v=vs.85).aspx
/// </summary>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint ResumeThread(IntPtr hThread);
}
}
@@ -17,5 +17,15 @@ namespace Tgstation.Server.Host.System
/// Set's the owned <see cref="global::System.Diagnostics.Process.PriorityClass"/> to <see cref="global::System.Diagnostics.ProcessPriorityClass.AboveNormal"/>
/// </summary>
void SetHighPriority();
/// <summary>
/// Suspends the process.
/// </summary>
void Suspend();
/// <summary>
/// Resumes the process.
/// </summary>
void Resume();
}
}
+57 -3
View File
@@ -1,5 +1,7 @@
using Microsoft.Extensions.Logging;
using BetterWin32Errors;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
@@ -133,13 +135,65 @@ namespace Tgstation.Server.Host.System
{
try
{
handle.PriorityClass = global::System.Diagnostics.ProcessPriorityClass.AboveNormal;
logger.LogTrace("Set to above normal priority", handle.Id);
handle.PriorityClass = ProcessPriorityClass.AboveNormal;
logger.LogTrace("Set PID {0} to above normal priority", Id);
}
catch (Exception e)
{
logger.LogWarning("Unable to raise process priority! Exception: {0}", e);
}
}
/// <inheritdoc />
public void Suspend()
{
try
{
foreach (ProcessThread thread in handle.Threads)
{
var pOpenThread = NativeMethods.OpenThread(NativeMethods.ThreadAccess.SuspendResume, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
continue;
if (NativeMethods.SuspendThread(pOpenThread) == UInt32.MaxValue)
throw new Win32Exception();
NativeMethods.CloseHandle(pOpenThread);
}
logger.LogTrace("Suspended PID {0}", Id);
}
catch (Exception e)
{
logger.LogError(e, "Failed to suspend PID {0}!", Id);
throw;
}
}
/// <inheritdoc />
public void Resume()
{
try
{
foreach (ProcessThread thread in handle.Threads)
{
var pOpenThread = NativeMethods.OpenThread(NativeMethods.ThreadAccess.SuspendResume, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
continue;
if (NativeMethods.ResumeThread(pOpenThread) == UInt32.MaxValue)
throw new Win32Exception();
NativeMethods.CloseHandle(pOpenThread);
}
logger.LogTrace("Resumed PID {0}", Id);
}
catch (Exception e)
{
logger.LogError(e, "Failed to resume PID {0}!", Id);
throw;
}
}
}
}