Is it possible that signal handling can be done for a particular process only.
For Ex:-
2 Independent different process A & B are running in background & signal handling for SIGTERM has been done only in the code for process A. So, if I will send the SIGTERM to process B to terminate it then the signal handler function in process A will execute & I want that the signal handler will execute only when the SIGTERM is sent to process A.
Note:- I am using Linux OS.
So, is there any way for achieving the above.
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.
In a system running Linux 2.6.35+ my program creates many child processes and monitors them. If a child process dies I do some clean-up and spawn the process again. I use signalfd() to get the SIGCHLD signal in my process. signalfd is used asynchronously using libevent.
When using signal handlers for non-real time signals, while the signal handler is running for a particular signal further occurrence of the same signal has to be blocked to avoid getting into recursive handlers. If multiple signals arrive at that time then kernel invokes the handler only once (when the signal is unblocked).
Is it the same behavior when using signalfd() as well? Since signalfd based handling doesn't have the typical problems associated with the asynchronous execution of the normal signal handlers I was thinking kernel can queue all the further occurrences of SIGCHLD?
Can anyone clarify the Linux behavior in this case ...
On Linux, multiple children terminating before you read a SIGCHLD with signalfd() will be compressed into a single SIGCHLD. This means that when you read the SIGCHLD signal, you have to clean up after all children that have terminated:
// Do this after you've read() a SIGCHLD from the signalfd file descriptor:
while (1) {
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0) {
break;
}
// something happened with child 'pid', do something about it...
// Details are in 'status', see waitpid() manpage
}
I should note that I have in fact seen this signal compression when two child processed terminated at the same time. If I did only a single waitpid(), one of the children that terminated was not handled; and the above loop fixed it.
Corresponding documentation:
http://man7.org/linux/man-pages/man7/signal.7.html "By contrast, if multiple instances of a standard signal are delivered while that signal is currently blocked, then only one instance is queued"
http://man7.org/linux/man-pages/man3/sigwait.3p.html "If prior to the call to sigwait() there are multiple pending instances of a single signal number, it is implementation-defined whether upon successful return there are any remaining pending signals for that signal number."
Actually the hassle-free way would be the waitfd functionally that would allow you to add a specific pid to poll()/epoll(). Unfortunately, it wasn't accepted to Linux years ago when it was proposed.
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.
Sometimes when I am debugging I get message like this.
Program received signal SIG44, Real-time event 44.
What does it means?
Thank you.
EDIT :
Platform is linux
A signal is a message sent by the kernel to a process in order to notify the process that event of some kind has occurred in the system.
Usual signals on linux are for example SIGINT (value 2, interrupt from keyboard) or SIGKILL ( value 9, kill a program).
Signals are received either when the kernel detects a system event (like division by zero is SIGFPE, value 8) or when a process invokes the kill() function to explicitly tell the kernel to send a signal to a process (or to the process itself that called the kill() ).
A signal can often be caught by the process in order to do something.
So to answer to your question, the code is most likely calling the kill() function and sending it a signal with value 44 when something happens. Since you are getting that message, it means that the process has received the signal and is going to exit or do what is written in the code in case that signal comes.
Unlike standard signals, real-time
signals have no predefined meanings:
the entire set of real-time signals
can be used for application-defined
purposes. (Note, however, that the
LinuxThreads implementation uses the
first three real-time signals.)
Source for the quote here
The GNU C++ library uses SIG44 to awaken sleeping threads when signalling condition variables.