Improve signal-related logging

pull/554/head
NextTurn 2020-03-16 00:00:00 +08:00 committed by Next Turn
parent 0bdd21b6c0
commit f9e0126cf8
4 changed files with 53 additions and 48 deletions

View File

@ -2,6 +2,9 @@
{
internal static class Errors
{
internal const int ERROR_ACCESS_DENIED = 5;
internal const int ERROR_INVALID_HANDLE = 6;
internal const int ERROR_INVALID_PARAMETER = 7;
internal const int ERROR_CANCELLED = 1223;
}
}

View File

@ -64,17 +64,18 @@ namespace winsw.Util
return;
}
Logger.Info("Send SIGINT " + pid);
bool successful = SigIntHelper.SendSIGINTToProcess(proc, stopTimeout);
if (successful)
{
Logger.Info("SIGINT to " + pid + " successful");
}
else
// (bool sent, bool exited)
KeyValuePair<bool, bool> result = SignalHelper.SendCtrlCToProcess(proc, stopTimeout);
bool exited = result.Value;
if (!exited)
{
try
{
Logger.Warn("SIGINT to " + pid + " failed - Killing as fallback");
bool sent = result.Key;
if (sent)
{
Logger.Warn("Process " + pid + " did not respond to Ctrl+C signal - Killing as fallback");
}
proc.Kill();
}
catch (Exception ex)

View File

@ -1,40 +0,0 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using log4net;
using winsw.Native;
namespace winsw.Util
{
public static class SigIntHelper
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(SigIntHelper));
/// <summary>
/// Uses the native funciton "AttachConsole" to attach the thread to the executing process to try to trigger a CTRL_C event (SIGINT). If the application
/// doesn't honor the event and shut down gracefully, the. wait period will time out after 15 seconds.
/// </summary>
/// <param name="process">The process to attach to and send the SIGINT</param>
/// <returns>True if the process shut down successfully to the SIGINT, false if it did not.</returns>
public static bool SendSIGINTToProcess(Process process, TimeSpan shutdownTimeout)
{
if (!ConsoleApis.AttachConsole(process.Id))
{
Logger.Warn("Failed to attach to console. Error code: " + Marshal.GetLastWin32Error());
return false;
}
// Disable Ctrl-C handling for our program
_ = ConsoleApis.SetConsoleCtrlHandler(null, true);
_ = ConsoleApis.GenerateConsoleCtrlEvent(ConsoleApis.CtrlEvents.CTRL_C_EVENT, 0);
process.WaitForExit((int)shutdownTimeout.TotalMilliseconds);
// Detach from console. Causes child console process to be automatically closed.
bool succeeded = ConsoleApis.FreeConsole();
Debug.Assert(succeeded);
return process.HasExited;
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using log4net;
using winsw.Native;
namespace winsw.Util
{
internal static class SignalHelper
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(SignalHelper));
// (bool sent, bool exited)
internal static KeyValuePair<bool, bool> SendCtrlCToProcess(Process process, TimeSpan shutdownTimeout)
{
if (!ConsoleApis.AttachConsole(process.Id))
{
int error = Marshal.GetLastWin32Error();
Logger.Warn("Failed to attach to console. " + error switch
{
Errors.ERROR_ACCESS_DENIED => "WinSW is already attached to a console.", // TODO: test mode
Errors.ERROR_INVALID_HANDLE => "The process does not have a console.",
Errors.ERROR_INVALID_PARAMETER => "The process has exited.",
_ => new Win32Exception(error).Message // unreachable
});
return new KeyValuePair<bool, bool>(false, error == Errors.ERROR_INVALID_PARAMETER);
}
_ = ConsoleApis.SetConsoleCtrlHandler(null, true);
_ = ConsoleApis.GenerateConsoleCtrlEvent(ConsoleApis.CtrlEvents.CTRL_C_EVENT, 0);
_ = ConsoleApis.SetConsoleCtrlHandler(null, false);
bool succeeded = ConsoleApis.FreeConsole();
Debug.Assert(succeeded);
return new KeyValuePair<bool, bool>(true, process.WaitForExit((int)shutdownTimeout.TotalMilliseconds));
}
}
}