Add option to send a SIGINT to the process being wrapped

pull/29/head
Ed Frey 2014-01-02 14:00:34 -05:00
parent ab4a373038
commit 1ed045b817
4 changed files with 93 additions and 2 deletions

20
Main.cs
View File

@ -340,7 +340,25 @@ namespace winsw
try
{
var proc = Process.GetProcessById(pid);
proc.Kill();
if (descriptor.SendSIGINT)
{
WriteEvent("Send SIGINT " + process.Id);
bool successful = SigIntHelper.SendSIGINTToProcess(proc);
if (successful)
{
WriteEvent("SIGINT to" + process.Id + " successful");
}
else
{
WriteEvent("SIGINT to " + process.Id + " failed - Killing as fallback");
proc.Kill();
}
}
else
{
WriteEvent("ProcessKill " + process.Id);
proc.Kill();
}
}
catch (ArgumentException)
{

View File

@ -561,5 +561,15 @@ namespace winsw
return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName);
}
/// <summary>
/// True if the service can interact with the desktop.
/// </summary>
public bool SendSIGINT
{
get
{
return dom.SelectSingleNode("//sendsigint") != null;
}
}
}
}

62
SigIntHelper.cs Normal file
View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace winsw
{
public static class SigIntHelper
{
private const string KERNEL32 = "kernel32.dll";
[DllImport(KERNEL32, SetLastError = true)]
private static extern bool AttachConsole(uint dwProcessId);
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true)]
private static extern bool FreeConsole();
[DllImport(KERNEL32)]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
// Enumerated type for the control messages sent to the handler routine
private enum CtrlTypes : uint
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
[DllImport(KERNEL32)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);
/// <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)
{
if (AttachConsole((uint)process.Id))
{
//Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(null, true);
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
process.WaitForExit(15000);
return process.HasExited;
}
else
{
return false;
}
}
}
}

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0DE77F55-ADE5-43C1-999A-0BC81153B039}</ProjectGuid>
<OutputType>Exe</OutputType>
@ -56,6 +56,7 @@
<Compile Include="PeriodicRollingCalendar.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceDescriptor.cs" />
<Compile Include="SigIntHelper.cs" />
<Compile Include="Wmi.cs" />
<Compile Include="WmiSchema.cs" />
</ItemGroup>