mirror of https://github.com/winsw/winsw
				
				
				
			Improve signal-related logging
							parent
							
								
									0bdd21b6c0
								
							
						
					
					
						commit
						f9e0126cf8
					
				| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue