CreateProcess such that child process is killed when parent is killed?
Asked Answered
S

6

21

Is there a way to call CreateProcess such that killing the parent process automatically kills the child process?

Perhaps using Create Process Flags?

Edit
The solution is to create a job object, place both parent and child in the job object. Whent he parent is killed the child is killed. I got the code from here: Kill child process when parent process is killed Take note of @wilx's comment about inherited handles.

Skantze answered 6/6, 2011 at 23:13 Comment(0)
T
13

Using jobs as Neil says is IMHO the best way. You can make the child processes get killed when the job owning process dies by setting JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE on the job object using SetInformationJobObject(). The job object handle will be closed when your parent process exits/dies. For this to work it is essential that the job handle is not inherited by the child processes. If you want to track also the grand-child processes then you will have to create your child processes suspended, add them to your job object and only then let them run.

Tarra answered 7/6, 2011 at 10:9 Comment(1)
+1, thanks! As luck would have it, the library I'm using to create the child process does not inherit job handles, so it worked out well.Skantze
I
6

The best you can do is to put both processes in the same job, so that killing the job kills both processes.

Indeed answered 6/6, 2011 at 23:18 Comment(8)
@Indeed - Can I place both in the same job after they are launched?Skantze
@SFun28 I think AssignProcessToJobObject may be what you need.Indeed
@SFun28: Yes -- CreateJobObject and AssignProcessToJobObject.Accompanyist
@Jerry/Neil - tried that. I confirmed that I got a job handle and that assigning process to job succeeded, but killing one process does not kill the other. maybe I'm doing something wrong.Skantze
@SFun28: In this case, killing the parent process doesn't automatically kill the child. The parent will have to call TerminateJobObject as it exits to kill the other process(es) in the job object.Accompanyist
@Jerry: If the parent is killed (per the question), it can't call anything. The OS or a driver could run code when the parent process dies, however.Ruyle
@Ben: Yes, that's why I recommended using debugging instead of this method. If the parent exits normally, it can terminate the job object (and thereby the child). This method will work if you really only need to kill the child when the parent exits normally. You could probably also run a second child that waits on the parent's process ID, and calls TerminateJobObject when the parent's process ID is signaled. I think the debugger approach is cleaner though.Accompanyist
@Indeed - +1, got it to work! Added solution to edit. Thanks for the suggestion to look into Jobs.Skantze
R
4

Do you need the child process to be killed, or merely detect the parent process exit so it can terminate cleanly? The parent process can create an inheritable handle to itself, which the child can then pass to WaitForMultipleObjects(Ex) along with its own objects.

If the child process isn't written specifically for this, you could attach its stdin to a pipe, the other end of which is held by the parent process. If the parent dies, the pipe is automatically closed.

This closely parallels the Unix behavior, in which a child isn't killed when its parent dies, it generally exits in response to SIGHUP (but it can handle that signal and implement any behavior). On Linux, the parent PID of an orphan is changed to 1 (init).

Ruyle answered 6/6, 2011 at 23:43 Comment(6)
@Ben - good question! I need the child process to be killed. I don't own the child process in the sense that its not my source code, so I cannot tailor the child in any way.Skantze
Good idea with stdin...might be a bit above my skill level. Ultimately I'm doing all of the Win32 Api stuff through .net pinvoke.Skantze
@SFun28: .NET makes redirecting stdin pretty simple, just use System.Diagnostics.Process class and use the RedirectStandardInput option when calling Process.Start.Ruyle
@Ben - I would but I didn't start the process =) I can get a Process object by pid, but my understanding is that I won't have access to standard input (I know that I don't for standard output/error)Skantze
@SFun28: If your program doesn't launch the child process, I'm not sure what you mean by "parent" and "child". Since you're asking about CreateProcess, I'm pretty sure you are starting the child process.Ruyle
@Ben - sorry...just call it process 1 and process 2. Process 1 does in fact create process 2, but its done in a third-party library and not directly so I don't have access to the Process object.Skantze
H
2

A different approach

Not useful in all situations, however I had one particular scenario where an application was controlling a child process completely. For communication & API interception, a DLL injection was required so a DLL is running in the actual child processes to report back to the parent.

Note: Now, this is not for the creativity award. Background here is: An application that needed to be wrapped, however that was a legacy application and could neither be modified, nor rewritten in a satisfying manner. We needed to keep this system running, while still intercepting outputs from it.

Also, the child process was poorly written, launching itself again immediately and then terminating, so the parent process is actually not our main application.

If you control the child processes and have an injected DLL anyway, you can extend this DLL by monitoring the parent process to check if it is running. If not, ExitProcess.

If you don't need a DLL in the child process, the other solutions are most likely far better.


You can transfer the parentProcessID through, for instance, a registry key that you use by your application already. Or you can pass a commandline, if this doesn't break the child process.

This has to run in its own thread. My DLL had two threads: This code here and the controlling & communication code.

DLL

bool IsProcessRunning(HANDLE hProcess)
{
    DWORD exitCode;
    GetExitCodeProcess(hProcess, &exitCode);
    return exitCode == STILL_ACTIVE;
}

bool WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        int parentProcessID = [...]
        
        HANDLE parentProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, parentProcessID);
        while (IsProcessRunning(parentHandle)) Sleep(100);
        ExitProcess(0);
    }

    return true;
}
Hendry answered 14/8, 2017 at 21:34 Comment(0)
A
1

I suppose DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS would do that as an almost-accidental side-effect. Windows doesn't create processes in a tree the way Unix-like systems do though.

Accompanyist answered 6/6, 2011 at 23:16 Comment(5)
I tried this and it seems to pause the child process. Whereas before I was seeing the child process' standard output in the same console window, now I see nothing. Perhaps I need to combine with some other flags?Skantze
@SFun28: It's (probably) not a matter of another flag, but of putting a small loop in the parent, calling WaitForDebugEvent and ContinueDebugEvent so the child can run until you decide to kill it.Accompanyist
This is getting messy...seems that the best way to call the debugging APIs from .net is to use this: blogs.msdn.com/b/jmstall/archive/2006/11/22/…Skantze
@SFun28: Yes, from .NET this probably is/will be a pain.Accompanyist
thanks for the suggestion. I ultimately abandoned this approach in favor of the Job approach which I now have working. Thanks for all of your help.Skantze
K
0

Dont know about windows, but this will work on linux: prctl(PR_SET_PDEATHSIG, SIGHUP);

Koehler answered 6/6, 2011 at 23:42 Comment(1)
Just a note: this should be called in the child process.Nailhead

© 2022 - 2024 — McMap. All rights reserved.