Child process won't suicide if parent dies - macos

I have a subprocess (running on MacOS) that I want to kill itself if the parent quits, exits, terminates, is killed or crashes. Having followed the advice from How to make child process die after parent exits? I can't get it to quietly kill itself if the parent program crashes. It will go to 100% CPU until I manually kill it.
Here are the key points of the code:
int main(int argc, char *argv[])
{
// Catch signals
signal(SIGINT, interruptHandler);
signal(SIGABRT, interruptHandler);
signal(SIGTERM, interruptHandler);
signal(SIGPIPE, interruptHandler);
// Create kqueue event filter
int kqueue_fd = kqueue();
struct kevent kev, recv_kev;
EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
kevent(kqueue_fd, &kev, 1, NULL, 0, NULL);
struct pollfd kqpoll;
kqpoll.fd = kqueue_fd;
kqpoll.events = POLLIN;
// Start a run loop
while(processEvents())
{
if(kill(parent_pid, 0) == -1)
if(errno == ESRCH)
break;
if(poll(&kqpoll, 1, 0) == 1)
if(kevent(kqueue_fd, NULL, 0, &recv_kev, 1, NULL))
break;
parent_pid = getppid();
if(parent_pid == 1)
break;
sleep(a_short_time);
// (simple code here causes subprocess to sleep longer if it hasn't
// received any events recently)
}
}

Answering my own question here:
The reason for this problem was not down to detecting whether the parent process had died. In processEvents() I was polling the pipe from the parent process to see if there was any communication. When the parent died, poll() returned a value of 1 and the read loop thought there was infinite data waiting to be read.
The solution was to detect whether the pipe had been disconnected or not.

Related

How to CancelSynchronousIo() on WaitForSingleObject() waiting on stdin?

On Windows 10, I'm waiting for input from the console using
WaitForSingleObject( GetStdHandle(STD_INPUT_HANDLE), ... )
and to cancel this waiting using CancelSynchronousIo().
But the cancellation does nothing (returns 0 and GetLastError() is ERROR_NOT_FOUND).
Any idea what I could be doing wrong?
Should I be able to cancel this waiting for new input on stdin?
(I actually want to do this with any HANDLE whose GetFileType() is FILE_TYPE_CHAR, not only stdin, but stdin is certainly the most important use case and the simplest to test with).
Related discussions I've found:
Synchronous ReadFile() on stdin cannot be unblocked by CancelSynchronousIo()
win32: how stop ReadFile (stdin|pipe)
But unfortunately they only discuss ReadFile(), not WaitForSingleObject(). I've also tried WaitForMultipleObjects() (with just a single object in the array), same problem.
(Background: I'm trying to improve input handling in the GHC Haskell compiler runtime.)
CancelSynchronousIo cancel I/O operations that are issued by the specified thread. more concrete it cancel IRP packets which associated with specified thread via call IoCancelIrp. if use undocumented NtCancelSynchronousIoFile (CancelSynchronousIo internally call it with IoRequestToCancel = 0) we can be more selective - cancel only i/o request which used specified IoRequestToCancel (system check that Irp->UserIosb == IoRequestToCancel and cancel only this requests)
but WaitForSingleObject this is not I/O request. this call not create any IRP which can be canceled. so - no way do this.
however if you use WaitForSingleObjectEx with bAlertable set to TRUE - you can break wait by queue apc to thread by using QueueUserAPC . also if use NtWaitForSingleObject instead WaitForSingleObjectEx we can also alert thread by using undocumented call NtAlertThread. in this case NtWaitForSingleObject will break with STATUS_ALERTED (note that WaitForSingleObjectEx which internally call NtWaitForSingleObject do special check for STATUS_ALERTED and in case this status - again run NtWaitForSingleObject - as result we can not break WaitForSingleObjectEx by call NtAlertThread, but NtWaitForSingleObject will be breaked.
so if you need break waiting for std input - create additional thread, which must call not CancelSynchronousIo (this senseless) but QueueUserAPC or NtAlertThread (only if you use NtWaitForSingleObject for wait). and input thread must wait in alertable state. so demo code can look like:
extern "C" NTSYSCALLAPI NTSTATUS NTAPI NtAlertThread(HANDLE ThreadHandle);
VOID NTAPI OnApc(ULONG_PTR Parameter)
{
DbgPrint("OnApc(%p)\n", Parameter);
}
DWORD CALLBACK BreakWaitThread(HANDLE hThread)
{
switch (LONG status = MessageBoxW(0, L"Use Apc(yes) or Alert(No) ?", L"BreakWaitThread",
MB_ICONQUESTION|MB_YESNOCANCEL|MB_DEFBUTTON3))
{
case IDYES:
if (!QueueUserAPC(OnApc, hThread, 0))
{
DbgPrint("QueueUserAPC=%u\n", GetLastError());
}
break;
case IDNO:
if (0 > (status = NtAlertThread(hThread)))
{
DbgPrint("AlertThread=%x\n", status);
}
break;
case IDCANCEL:
DbgPrint("canceled\n");
break;
default:
DbgPrint("MessageBox=%x\n", status);
}
CloseHandle(hThread);
return 0;
}
void ConsoleLoop(HANDLE hStdIn)
{
ULONG NumberOfEvents, NumberOfEventsRead, n;
INPUT_RECORD buf[8], *p;
for (;;)
{
switch (ZwWaitForSingleObject(hStdIn, TRUE, 0))
//switch (WaitForSingleObjectEx(hStdIn, INFINITE, TRUE))
{
case WAIT_OBJECT_0:
while (GetNumberOfConsoleInputEvents(hStdIn, &NumberOfEvents) && NumberOfEvents)
{
do
{
NumberOfEventsRead = min(RTL_NUMBER_OF(buf), NumberOfEvents);
if (ReadConsoleInput(hStdIn, buf, NumberOfEventsRead, &NumberOfEventsRead) && NumberOfEventsRead)
{
n = NumberOfEventsRead;
p = buf;
do
{
if (p->EventType == KEY_EVENT)
{
DbgPrint("%u(%u) %C %x %x %x\n",
p->Event.KeyEvent.bKeyDown,
p->Event.KeyEvent.wRepeatCount,
p->Event.KeyEvent.uChar.UnicodeChar,
p->Event.KeyEvent.wVirtualKeyCode,
p->Event.KeyEvent.wVirtualScanCode,
p->Event.KeyEvent.dwControlKeyState);
if (VK_OEM_PERIOD == p->Event.KeyEvent.wVirtualKeyCode)
{
return ;//if user type '.' return for demo
}
}
} while (p++, --n);
}
else
{
FlushConsoleInputBuffer(hStdIn);
break;
}
} while (NumberOfEvents -= NumberOfEventsRead);
}
continue;
case STATUS_USER_APC:
DbgPrint("\nUSER_APC\n");
return;
case STATUS_ALERTED:
DbgPrint("\nALERTED\n");
return;
case WAIT_FAILED :
DbgPrint("\nWAIT_FAILED=%u\n", GetLastError());
return;
default:
__debugbreak();
return;
}
}
}
void SimpleDemo()
{
if (HANDLE hCurrentThread = OpenThread(THREAD_ALERT|THREAD_SET_CONTEXT , FALSE, GetCurrentThreadId()))
{
ULONG dwThreadId;
HANDLE hThread = CreateThread(0, 0, BreakWaitThread, hCurrentThread, 0, &dwThreadId);
if (hThread)
{
ConsoleLoop(GetStdHandle(STD_INPUT_HANDLE));
PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
else
{
CloseHandle(hCurrentThread);
}
}
}
Console I/O is difficult to use asynchronously, it is simply not designed for it. See IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR for some possible workarounds.
If that is not an option for you, then you will have to either:
use WaitForSingleObject() in a loop with a short timeout. Create a flag variable that your loop can look at on each iteration to break the loop if the flag is set.
use WaitForMutipleObjects(), giving it 2 HANDLEs to wait on - one for the console (or whatever), and one for an event object from CreateEvent(). Then you can signal the event with SetEvent() when you want to break the wait. The return value of WaitForMutipleObjects() will tell you which HANDLE was signaled.

Detecting named pipe disconnects with I/O completion

I have a question about the correct approach for detecting client disconnects using named pipes with I/O completion ports. We have a server that creates child processes with stdin/stdout redirected to named pipes. The pipes are opened OVERLAPPED.
We've seen that after the client issues CreateFile() the I/O completion port
receives a packet with lpNumberOfBytes of zero -- which quite effectively indicates a connection from the client. But detecting when the child process has closed its' stdin/stdout and exited does not generate a similar event.
We've come up with two approaches to detecting the named pipe disconnects;
1) periodically poll the process HANDLE of the child process to detect when the process has ended,
OR
2) create a separate thread which blocks on WaitForSingleObject() on the child process's HANDLE and when it becomes signaled the process has ended, to then generate PostQueuedCompletionStatus() to the I/O completion port with a prearranged COMPLETION_KEY.
Neither of these is difficult -- but I wanted to make sure I wasn't missing something obvious. Has anyone found an alternative to being notified when a named pipe associated with IOCP has been closed?
Ok, I discovered why the IOCP was not delivering disconnect packets, and it had todo with how I was testing the issue. We had developed a unittest harness and our unittest was acting as both server and client. When the child process ended, the child's write-pipe handle was still open in the unittest, and therefore IOCP did not unblock any handler threads.
To effectively run a pipe server requires you create a new thread and within that thread to do the work of connecting to the pipe, creating the child process and waiting for the process to end. After the child ends to then close the pipe handle which causes IOCP to then deliver a dequeue packet with lpNumberOfBytes set to zero.
Here is a sample of how we did this from a thread created with _beginthread().
void __cdecl childproc(void* p) {
TCHAR* pipename = (TCHAR*)p;
/* make sure pipe handle is "inheritable" */
SECURITY_ATTRIBUTES sattr;
sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
sattr.bInheritHandle = TRUE;
sattr.lpSecurityDescriptor = NULL;
HANDLE pipe = ::CreateFile(
pipename,
GENERIC_READ | GENERIC_WRITE,
0,
&sattr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (pipe == INVALID_HANDLE_VALUE) {
_tprintf(_T("connect to named pipe failed %ld\n", GetLastError());
_endthread();
}
/* redirect stdin/stdout/stderr to pipe */
PROCESS_INFORMATION procinfo;
STARTUPINFO startinfo;
memset(&procinfo, 0, sizeof(procinfo));
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);
startinfo.hStdError = pipe;
startinfo.hStdOutput = pipe;
startinfo.hStdInput = pipe;
startinfo.dwFlags |= STARTF_USESTDHANDLES;
/* create child to do a simple "cmd.exe /c dir" */
DWORD rc = ::CreateProcess(
_T("C:\\Windows\\System32\\cmd.exe"),
_T("C:\\Windows\\System32\\cmd.exe /C dir"),
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&startinfo,
&procinfo);
if (rc == 0) {
_tprintf(_T("cannot create child process: %ld\n"), GetLastError());
_endthread();
}
if (::WaitForSingleObject(procinfo.hProcess, INFINITE) != WAIT_OBJECT_0) {
_tprintf(_T("error waiting for child to end: %ld\n"), GetLastError());
}
/* cleanup */
::CloseHandle(procinfo.hProcess);
::CloseHandle(procinfo.hThread);
::CloseHandle(pipe);
_endthread();
}

Prevent terminal prompt from printing on exec() call

SO,
There are many similar questions, however none that I have been able to use. My code snippet is as follows:
for(int j=0; j<N; j++) {
pid_t pid = fork();
if (pid == -1) {
exit(-1); //err
} else if (pid == 0) {//kid
stringstream ss;
ss<<j;
execlp("./sub","sub",ss.str().c_str(),NULL);
exit(0);
} else {
/* parent */
}
}
my executing code in sub(.cpp) is:
int main( int argc, char **argv )
{
cout<<argv[i]<<endl;
exit(0);
}
my output is as such:
[terminal prompt '$'] 4
2
3
etc.
Is there a way I could prevent the prompt from displaying on the exec call? and why is it ONLY displaying on the first exec call, and not on every one?
What you see is the normal prompt of your shell, because the parent process terminates very quickly. It is not the output of the exec call. The forked processes print their output after the parent process has terminated.
You can use waitpid() in the parent process to "wait" until all forked process have terminated.

Multithreaded Win32 GUI message loop

When do you need to use this type of modified message loop in multithreaded application?
DWORD nWaitCount;
HANDLE hWaitArray[4];
BOOL quit;
int exitCode;
while (!quit)
{
MSG msg;
int rc;
rc = MsgWaitForMultipleObjects(nWaitCount, hWaitArray, FALSE, INFINITE,QS_ALLINPUT);
if (rc == WAIT_OBJECT_O + nWaitCount)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
quit = TRUE;
exitCode = msg.wParam;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + nwaitCount)
{
int nlndex = rc - WAIT_OBJECT_0;
}
else if (rc >= WAIT_ABANDONED_0 && rc < WAIT_ABANDONED_0+ nWaitCount)
{
int nlndex = rc - WAIT_ABANDONED_O;
}
}
Hopefully never. But it is the kind of code you have to write when you want the UI thread to block on synchronization objects. A UI thread is not permitted to block, Windows prevents you from calling WaitForMultipleObjects(). The reason is that it is very likely to cause deadlock.
The reason for that is COM. COM is everywhere in Windows, the most common examples are the clipboard, drag+drop and the shell dialogs. COM marshals interface method calls made from a worker thread for COM objects that live on the STA (Single Threaded Apartment) by using the message loop. If the STA thread isn't pumping messages then the call won't complete. And calls that can't complete are ingredient number one for deadlock. Add a UI thread that waits for the worker thread to complete and deadlock is assured.
You avoid this kind of code by having a worker thread use PostMessage() to signal the UI thread that something important happened.

Waiting for grandchild processes in windows

Is it possible to wait for all processes launched by a child process in Windows? I can't modify the child or grandchild processes.
Specifically, here's what I want to do. My process launches uninstallA.exe. The process uninistallA.exe launches uninstallB.exe and immediately exits, and uninstallB.exe runs for a while. I'd like to wait for uninstallB.exe to exit so that I can know when the uninstall is finished.
Create a Job Object with CreateJobObject. Use CreateProcess to start UninstallA.exe in a suspended state. Assign that new process to your job object with AssignProcessToJobObject. Start UninstallA.exe running by calling ResumeThread on the handle of the thread you got back from CreateProcess.
Then the hard part: wait for the job object to complete its execution. Unfortunately, this is quite a bit more complex than anybody would reasonably hope for. The basic idea is that you create an I/O completion port, then you create the object object, associate it with the I/O completion port, and finally wait on the I/O completion port (getting its status with GetQueuedCompletionStatus). Raymond Chen has a demonstration (and explanation of how this came about) on his blog.
Here's a technique that, while not infallible, can be useful if for some reason you can't use a job object. The idea is to create an anonymous pipe and let the child process inherit the handle to the write end of the pipe.
Typically, grandchild processes will also inherit the write end of the pipe. In particular, processes launched by cmd.exe (e.g., from a batch file) will inherit handles.
Once the child process has exited, the parent process closes its handle to the write end of the pipe, and then attempts to read from the pipe. Since nobody is writing to the pipe, the read operation will block indefinitely. (Of course you can use threads or asynchronous I/O if you want to keep doing stuff while waiting for the grandchildren.)
When (and only when) the last handle to the write end of the pipe is closed, the write end of the pipe is automatically destroyed. This breaks the pipe and the read operation completes and reports an ERROR_BROKEN_PIPE failure.
I've been using this code (and earlier versions of the same code) in production for a number of years.
// pwatch.c
//
// Written in 2011 by Harry Johnston, University of Waikato, New Zealand.
// This code has been placed in the public domain. It may be freely
// used, modified, and distributed. However it is provided with no
// warranty, either express or implied.
//
// Launches a process with an inherited pipe handle,
// and doesn't exit until (a) the process has exited
// and (b) all instances of the pipe handle have been closed.
//
// This effectively waits for any child processes to exit,
// PROVIDED the child processes were created with handle
// inheritance enabled. This is usually but not always
// true.
//
// In particular if you launch a command shell (cmd.exe)
// any commands launched from that command shell will be
// waited on.
#include <windows.h>
#include <stdio.h>
void error(const wchar_t * message, DWORD err) {
wchar_t msg[512];
swprintf_s(msg, sizeof(msg)/sizeof(*msg), message, err);
printf("pwatch: %ws\n", msg);
MessageBox(NULL, msg, L"Error in pwatch utility", MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
ExitProcess(err);
}
int main(int argc, char ** argv) {
LPWSTR lpCmdLine = GetCommandLine();
wchar_t ch;
DWORD dw, returncode;
HANDLE piperead, pipewrite;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
char buffer[1];
while (ch = *(lpCmdLine++)) {
if (ch == '"') while (ch = *(lpCmdLine++)) if (ch == '"') break;
if (ch == ' ') break;
}
while (*lpCmdLine == ' ') lpCmdLine++;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&piperead, &pipewrite, &sa, 1)) error(L"Unable to create pipes: %u", GetLastError());
GetStartupInfo(&si);
if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
error(L"Error %u creating process.", GetLastError());
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) error(L"Error %u waiting for process.", GetLastError());
if (!GetExitCodeProcess(pi.hProcess, &returncode)) error(L"Error %u getting exit code.", GetLastError());
CloseHandle(pipewrite);
if (ReadFile(piperead, buffer, 1, &dw, NULL)) {
error(L"Unexpected data received from pipe; bug in application being watched?", ERROR_INVALID_HANDLE);
}
dw = GetLastError();
if (dw != ERROR_BROKEN_PIPE) error(L"Unexpected error %u reading from pipe.", dw);
return returncode;
}
There is not a generic way to wait for all grandchildren but for your specific case you may be able to hack something together. You know you are looking for a specific process instance. I would first wait for uninstallA.exe to exit (using WaitForSingleObject) because at that point you know that uninstallB.exe has been started. Then use EnumProcesses and GetProcessImageFileName from PSAPI to find the running uninstallB.exe instance. If you don't find it you know it has already finished, otherwise you can wait for it.
An additional complication is that if you need to support versions of Windows older than XP you can't use GetProcessImageFileName, and for Windows NT you can't use PSAPI at all. For Windows 2000 you can use GetModuleFileNameEx but it has some caveats that mean it might fail sometimes (check docs). If you have to support NT then look up Toolhelp32.
Yes this is super ugly.
Use a named mutex.
One possibility is to install Cygwin and then use the ps command to watch for the grandchild to exit

Resources