Task: Auto kill all child processes if parent process terminate. Parent procees can be terminated not only in correct way, but also by killing in ProcessExplorer, for example. How can I do it?
Similar question in С topic advice to use Job objects. How to use it in C# without exporting external DLL?
I tried to use Job Objects. But this code doesn't work properly:
var job = PInvoke.CreateJobObject(null, null);
var jobli = new PInvoke.JOBOBJECT_BASIC_LIMIT_INFORMATION();
jobli.LimitFlags = PInvoke.LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_PRIORITY_CLASS
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_TIME
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_MEMORY;
var res = PInvoke.SetInformationJobObject(job, PInvoke.JOBOBJECTINFOCLASS.JobObjectBasicLimitInformation, jobli, 48);
if (!res)
{
int b = PInvoke.GetLastError();
Console.WriteLine("Error " + b);
}
var Prc = Process.Start(...);
PInvoke.AssignProcessToJobObject(job, Prc.Handle);
PInvoke.SetInformationJobObject returns with error. GetLastError returns error 24. However, PInvoke.AssignProcessToJobObject works and child process added to Job Queue (I can see it in ProcessExplorer). But, because PInvoke.SetInformationJobObject don't work - spawned process stay alive when I kill parent one.
What do I have incorrect in this code?
When a parent process dies before a child process, the kernel knows that it's not going to get a wait call, so instead it makes these processes "orphans" and puts them under the care of init (remember mother of all processes). Init will eventually perform the wait system call for these orphans so they can die.
A child process may be terminated if its parent process requests for its termination. A process can be terminated if it tries to use a resource that it is not allowed to. For example - A process can be terminated for trying to write into a read only file. If an I/O failure occurs for a process, it can be terminated.
If the process calling _exit() is a controlling process, _exit() disassociates the associated controlling terminal from the session. A new controlling process can then acquire the terminal. Exiting from a process does not end its child processes directly.
To kill a process tree on windows, given only the parent process or process id, you'll need to walk the process tree.
For that, you'll need a way to get the parent process id for a given process.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Management;
namespace KillProcessTree
{
public static class MyExtensions
{
public static int GetParentProcessId(this Process p)
{
int parentId = 0;
try
{
ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
mo.Get();
parentId = Convert.ToInt32(mo["ParentProcessId"]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
parentId = 0;
}
return parentId;
}
}
Once you have that, actually killing the tree is not hard.
class Program
{
/// <summary>
/// Kill specified process and all child processes
/// </summary>
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: KillProcessTree <pid>");
return;
}
int pid = int.Parse(args[0]);
Process root = Process.GetProcessById(pid);
if (root != null)
{
Console.WriteLine("KillProcessTree " + pid);
var list = new List<Process>();
GetProcessAndChildren(Process.GetProcesses(), root, list, 1);
// kill each process
foreach (Process p in list)
{
try
{
p.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
else
{
Console.WriteLine("Unknown process id: " + root);
}
}
/// <summary>
/// Get process and children
/// We use postorder (bottom up) traversal; good as any when you kill a process tree </summary>
/// </summary>
/// <param name="plist">Array of all processes</param>
/// <param name="parent">Parent process</param>
/// <param name="output">Output list</param>
/// <param name="indent">Indent level</param>
private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
{
foreach (Process p in plist)
{
if (p.GetParentProcessId() == parent.Id)
{
GetProcessAndChildren(plist, p, output, indent + 1);
}
}
output.Add(parent);
Console.WriteLine(String.Format("{0," + indent*4 + "} {1}", parent.Id, parent.MainModule.ModuleName));
}
}
} // namespace
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With