Browse Source

New option to shutdown parent process first.

Option name = stopparentprocessfirst

Signed-off-by: Oleg Nenashev <[email protected]>
Oleg Demchenko 11 years ago
parent
commit
350fa99749
3 changed files with 65 additions and 5 deletions
  1. 43 3
      Main.cs
  2. 6 0
      README.markdown
  3. 16 2
      ServiceDescriptor.cs

+ 43 - 3
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<int> GetChildPids(int pid)
         {
             var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
+            var childPids = new List<int>();
             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");

+ 6 - 0
README.markdown

@@ -292,3 +292,9 @@ Possible values are `idle`, `belownormal`, `normal`, `abovenormal`, `high`, `rea
     <priority>idle</priority>
 
 Specifying a priority higher than normal has unintended consequences. See <a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.processpriorityclass(v=vs.110).aspx">MSDN discussion</a> 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
+```
+<stopparentprocessfirst>true</stopparentprocessfirst>
+```

+ 16 - 2
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"
         /// </summary>
-        public readonly string BasePath;
+        public string BasePath { get; set; }
         /// <summary>
         /// The file name portion of the configuration file.
         /// 
         /// In the above example, this would be "ghi".
         /// </summary>
-        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;
+            }
+        }
+
         /// <summary>
         /// Desired process priority or null if not specified.
         /// </summary>