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.
Related
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.
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.
I am a newbie and have basic understanding of linux.
Whenever the kernel encounters a signal for a particular process, first it checks the signal handler table in the process control block(PCB) of the particular process. If the signal handler is registered it calls the function. if the flag is SIG_DEFAULT then it calls the signal handler registered in the global signal table of kernel. If the flag is SIG_IGNORE then kernel just ignores the signal for the particular process.
All signals have default signal handlers already registered in signal table by kernel.
I just want to know how a process can change the flag from SIG_DEFAULT TO SIG_IGNORE. Please explain the mechanism(either using system call or changes in the signal table or PCB). Next time when the signal is again captured what optimizations does the kernel do.
Call the signal function. Note that some signals may not be ultimately ignoreable.
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.