I read some documentation but it isn't clear enough to me. I know that both "end" a process and that kill() is meant to force it to end, but what is terminate() supposed to do then?
Dunno what's not clear if you have written:
void QProcess::kill()
Kills the current process, causing it to exit immediately.
On Windows, kill() uses TerminateProcess, and on Unix and OS X, the SIGKILL signal is sent to the process.
http://doc.qt.io/qt-5/qprocess.html#kill
void QProcess::terminate()
Attempts to terminate the process.
The process may not exit as a result of calling this function (it is given the chance to prompt the user for any unsaved files, etc).
On Windows, terminate() posts a WM_CLOSE message to all toplevel windows of the process and then to the main thread of the process itself. On Unix and OS X the SIGTERM signal is sent.
Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill().
http://doc.qt.io/qt-5/qprocess.html#terminate
So, basically terminate() is less brutal, but does not guarantee that process will be terminated.
On Unix terminate() uses SIGTERM signal, while kill() sends SIGKILL to the process. The difference between them is that SIGTERM can be caught by a process, which allows it to perform cleanup etc. SIGTERM can be ignored. SIGKILL will literally kill process, process can not ignore it.
On Windows WM_CLOSE message is posted, when you call terminate(), so application can also gracefully handle it. kill() calls TerminateProcess(), which is more or less Windows equvalent of SIGKILL.
I think terminate() SIGTERM and WM_CLOSE could be handled by Qt and translated into normal Qt events, but you have to try it yourself. You can of course handle them by system specific functions.
"what causes terminate() to not exit the process."
It is you, because you can catch terminate() signals/messages and do whatever you want, or it can be user of your application if he is prompted if he really wants to quit app. Yet another resource on WM_CLOSE.
Related
I am writing a program that needs to catch the ctrl-c event. And I learned that I can call signal function or sigaction function in signal.h to customize what to do when the process receives a SIGINT signal. But I am also curious what is the mechanism for such a signal listener. In other words, how can a process keep waiting for a specific signal while continuing to execute its code?
The process doesn't "wait" for the signal. Calling sigaction() tells the operating system to force the process to take the specified action when the process receives the specified signal. When this happens, the process is interrupted and forced to call the registered handler.
Suppose we have small program, written in C++, which looks like below.
This program itself intentionally does NOT perform signal handling via WinAPI call SetConsoleCtrlHandler - it's important part of question.
#include <stdio.h>
#include <stdlib.h>
int main() {
while(true) {
int status = system("EXTERNAL COMMAND");
printf("RESULT STATUS = %d\n", status);
}
}
When Ctrl+C key combination have been pressed in terminal, program above have quite different behavior depend on which "EXTERNAL COMMAND" had been invoked
1) If external command is pause, program will stand in infinite loop, invoking pause command step by step, and will print "RESULT STATUS = 0" many times, while not terminated forced via process kill.
2) If external command in choice, program will terminate immediately after Ctrl+C pressure. It will not print anything and does not return from system call.
3) If external command is set /P VAR=, program has much interesting behavior. When Ctrl+C pressed, program prints `"RESULT STATUS = 1" and continue working until first async call is performed.
First and second case can be explained in following manner. Terminal windows is proxt between user input and target program, so when user presses Ctrl+C, terminal window perform dispatch signal itself to target process.
So some subprocesses can take manually terminal handler via hConsole = GetStdHandle(STD_OUTPUT_HANDLE) and perform own signal handling. Another subprocess does not do this, so signal passed into parent process and terminate it.
But third case causes big question. If child process intercepts SIGINT, why parent process perform terminating after first async call. If not, why it does not terminate immediately and why and how it prints `"RESULT STATUS = 1" and continue working.
Thanks
There are no Unix signals in Windows, at least not from the kernel. That said, Windows and the Windows API are fundamentally based on the C programming language, which, having been developed in tandem with Unix, does require six signals. The C runtime in Windows emulates SIGABRT and SIGTERM within process (e.g. for use with C raise). For SIGSEGV, SIGILL, and SIGFPE it uses an OS exception handler. In a console application, standardSIGINT and non-standard SIGBREAK are associated with the C runtime's console control handler, which is usually the first handler registered via SetConsoleCtrlHandler. CTRL_C_EVENT is mapped to the SIGINT signal handler, and all others (CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT) are mapped to the SIGBREAK handler.
Console control events are sent by the console host (conhost.exe), which implements this by having the session server (csrss.exe) create a thread in a client process. This thread begins at the undocumented CtrlRoutine function in kernelbase.dll, which walks the registered control handlers until one of them handles the event by returning true. If none of them handles the event, the default handler calls ExitProcess(STATUS_CONTROL_C_EXIT). Note that SetConsoleCtrlHandler(NULL, TRUE) sets a flag that makes CtrlRoutine ignore CTRL_C_EVENT, and this flag is inherited by child processes and enabled by default when a process is created with the flag CREATE_NEW_PROCESS_GROUP. Also, for CTRL_CLOSE_EVENT, the session server gives each process 5 seconds to handle the event and exit on its own, else it terminates the process forcefully.
To understand what's happening with CMD's internal PAUSE command, see SetConsoleMode, and, in particular, ENABLE_PROCESSED_INPUT. PAUSE calls C _getch, which temporarily sets the console input mode to 0. With the processed-input mode disabled, Ctrl+C is simply read as "\x03" instead of generating a CTRL_C_EVENT.
if a user decides to force close my application(like through the task manager) is there a way i can quickly execute some clean up code before the application closes? i'm coding in c++ btw
It depends on how the process is instructed to close. It is possible to do this upon graceful exit, but not for anything forcefully closed.
If the process is closed via TerminateProcess or ExitProcess, you won't be able to perform any graceful cleanup. TerminateProcess is how Task Manager and utilities like Sysinternals pskill end a target process. ExitProcess is called within a process but is not typically used to exit.
If the process has a message pump on one thread (typically the first thread in the process) and no other threads running that are running code whose lifetimes are independent of activity in that thread, then a WM_QUIT message will signal that the process should close (semantically, that the app should close, your process might conceivably stick around for a while for other reasons), and you can run cleanup code upon receiving the message. Depending on your needs, in a windowed app you might consider performing cleanup operations as early as WM_CLOSE or WM_DESTROY.
If you have written code in a DLL, there are notifications that you can handle in DllMain that will allow you to perform last-chance cleanup (DLL_PROCESS_DETACH), which can potentially cover the case of a process exiting without having a message pump. However, this is not a great way to perform cleanup for code that strictly relies on any C/C++ runtime (or any other DLL), as the runtime might be unloaded first.
Last, for any graceful close where you control what runs in WinMain or main, you can always do whatever cleanup you need to do before either function returns, sending control back to the windows subsystem. This is preferred and usually safest for most application needs.
If you are using a message pump, handle the WM_QUIT message.
Also: What is the difference between WM_QUIT, WM_CLOSE, and WM_DESTROY in a windows program?
EDIT
Im sorry, I read over the fact that you want to handle termination, eg by the task manager.
This might help you though: How to catch event when Task manager kill your C++ application
In my Qt C++ program I created a process as follows:
myProcess = new QProcess();
myProcess->start(programpath, arguments);
Terminating the process is handled as follows:
myProcess->terminate();
Terminating the child process with QProcess::kill(),terminate() or close() works, but I don't want to use it because it doesn't give the child process a chance to clean up before exiting.
Is there any other way to exit the process? Thanks!
The polite way would be for the parent process to politely ask the child process to go away. Then when the child process exits (of its own volition), the QProcess object will emit a finished(int, QProcess::ExitStatus) signal, and you can have a slot connected to that signal that will continue your process (e.g. by deleting the QProcess object at that time). (Or if you don't mind blocking your Qt event loop for a little while, you could just call waitForFinished() on the QProcess object after asking it to exit, and waitForFinished() won't return until the process has gone away or the timeout period has elapsed)
Of course for the above to work you need some way to ask the child process to exit. How you go about doing that will depend on what the child process is running. If you're lucky, you are in control of the child process's code, in which case you can modify it to exit in response to some action of the parent process -- for example, you could code the child process to exit when its stdin descriptor is closed, and have the parent process call closeWriteChannel() on the QProcess object to cause that to happen. Or if you're running under Linux/Unix you could send a SIGINT signal to the child process and the child process could set up a handler that would catch the signal and start an orderly shutdown. Or if you want something really stupid-quick and dirty, have the child process periodically check for the presence of a file at a well-known location (e.g. "/tmp/hey-child-process-PIDNUMBERHERE-go-away.txt" or something) and the parent process would create such a file when it wants the child to go away. Not that I'd recommend that last method as I don't think it would be very robust, except maybe as a proof of concept.
terminate actually gives the process an chance to clean up. The program being terminated just has to take that chance i.e. the system sents a SIGTERM and the application and it can ignore that and exit cleanly on its own. If this is still not nice enough then you have to implement your own way of asking the application to quit. Jeremy Friesner made some good successions. If the application code is not written by yourself you'll have to read the documentation for that program closer, maybe its documented how to do that.
I want my program to react on being killed by the 'killall myApplication' command.
So that it can save something and then terminate.
I know this must be done by signal handling but I am not sure which Singal it gets when being killed.
killall or killall -9? Because -9 would mean SIGKILL, which cannot be handled nor masked (your process would be terminated right away in the scheduler, without it having any notion that any signal was sent to it).
Without -9, it would be SIGTERM, which can be handled. Have a look at man signal.