diff --git a/Main.cs b/Main.cs index 2912f41..559b794 100644 --- a/Main.cs +++ b/Main.cs @@ -304,16 +304,56 @@ namespace winsw } private void StopProcessAndChildren(int pid) + { + var childPids = GetChildPids(pid); + + if (descriptor.StopParentProcessFirst) + { + StopProcess(pid); + foreach (var childPid in childPids) + { + StopProcessAndChildren(childPid); + } + } + else + { + foreach (var childPid in childPids) + { + StopProcessAndChildren(childPid); + } + StopProcess(pid); + } + } + + private List GetChildPids(int pid) { var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid); + var childPids = new List(); foreach (var mo in searcher.Get()) { - StopProcessAndChildren(Convert.ToInt32(mo["ProcessID"])); + var childProcessId = mo["ProcessID"]; + WriteEvent("Found child process: " + childProcessId + " Name: " + mo["Name"]); + childPids.Add(Convert.ToInt32(childProcessId)); } + return childPids; + } - var proc = Process.GetProcessById(pid); + private void StopProcess(int pid) + { + WriteEvent("Stopping process " + pid); + Process proc; + try + { + proc = Process.GetProcessById(pid); + } + catch (ArgumentException) + { + WriteEvent("Process " + pid + " is already stopped"); + return; + } + WriteEvent("Send SIGINT " + pid); - bool successful = SigIntHelper.SendSIGINTToProcess(proc,descriptor.StopTimeout); + bool successful = SigIntHelper.SendSIGINTToProcess(proc, descriptor.StopTimeout); if (successful) { WriteEvent("SIGINT to" + pid + " successful"); diff --git a/README.markdown b/README.markdown index 4177afd..97118f0 100644 --- a/README.markdown +++ b/README.markdown @@ -292,3 +292,9 @@ Possible values are `idle`, `belownormal`, `normal`, `abovenormal`, `high`, `rea idle Specifying a priority higher than normal has unintended consequences. See MSDN discussion for details. This feature is intended primarily to launch a process in a lower priority so as not to interfere with the computer's interactive usage. + +###stopparentprocessfirst +Optionally specify the order of service shutdown. If true, the parent process is shutdown first. This is useful when the main process is a console, which can respond to Ctrol+C command and will gracefully shutdown child processes +``` +true +``` diff --git a/ServiceDescriptor.cs b/ServiceDescriptor.cs index 12f2b81..9319fa9 100755 --- a/ServiceDescriptor.cs +++ b/ServiceDescriptor.cs @@ -28,13 +28,13 @@ namespace winsw /// /// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml" /// - public readonly string BasePath; + public string BasePath { get; set; } /// /// The file name portion of the configuration file. /// /// In the above example, this would be "ghi". /// - public readonly string BaseName; + public string BaseName { get; set; } public virtual string ExecutablePath { @@ -584,6 +584,20 @@ namespace winsw } } + public bool StopParentProcessFirst + { + get + { + var value = SingleElement("stopparentprocessfirst", true); + bool result; + if (bool.TryParse(value, out result)) + { + return result; + } + return false; + } + } + /// /// Desired process priority or null if not specified. ///