Sending SIGSTOP to a child process stops all execution. C - c

When I call kill(Child_PID, SIGSTOP); from the parent, I expect the child to halt execution and the parent to continue. Is that the expected behavior or do I have to explicitly declare the SIGSTOP handler in the child? I have searched everywhere and not been able to find this information.
Thanks.
Braden

POSIX says:
The system shall not allow a process to catch the signals SIGKILL and SIGSTOP.
So, the child has no option but to stop - if the signal is sent successfully. And you cannot set a SIGSTOP handler in the child (or parent, or any other) process.

This is the expected behavior.
Use strace your_program to see what's happening.

That's the expected behaviour. Quoting from the unix man page:
The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
And the BSD man page mentions that:
The signal() function will fail and no action will take place
if one of the following occur:
[EINVAL] The sig argument is not a valid signal number.
[EINVAL] An attempt is made to ignore or supply a handler
for SIGKILL or SIGSTOP.
Concluding, you're not permitted to install a handler for SIGSTOP. And the process will remain in the suspended state until it receives a SIGCONT.

Related

In the Linux kernel, why does the SIGCHLD signal not interrupt the wait() system call?

Consider a scenario like this: The parent process calls wait() to wait for the child process to exit, and the signal handler is registered for SIGCHLD. When the parent process blocks at wait(), the child process ends, at which point the parent process receives a SIGCHLD signal (regardless of setting special fields).
After I tested, I found that wait() was not interrupted by the SIGCHLD` signal to fail and return -1, but returned successfully after executing the signal processing function. Why is that?
man wait
ERRORS
EINTR: WNOHANG was not set and an unblocked signal or a SIGCHLD was caught
Since you've established a signal handler for SIGCHLD, wait does not get interrupted.
For more info, see: signal, especially:
Waiting for a signal to be caught
Synchronously accepting a signal
Signal mask and pending signals
A signal may be blocked, which means that it will not be
delivered until it is later unblocked. ...
Execution of signal handlers
Interruption of system calls and library functions by signal handlers
If a signal handler is invoked while a system call or library function call is blocked, then either:
the call is automatically restarted after the signal handler returns; or
the call fails with the error EINTR.
Which of these two behaviors occurs depends on the interface and whether or not the signal handler was established using the SA_RESTART flag (see sigaction(2)). The details vary across UNIX systems; below, the details for Linux.
If a blocked call to one of the following interfaces is
interrupted by a signal handler, then the call is automatically
restarted after the signal handler returns if the SA_RESTART flag was used; otherwise the call fails with the error EINTR:
wait
After I tested, I found that wait() was not interrupted by the SIGCHLD` signal to fail and return -1, but returned successfully after executing the signal processing function. Why is that?
Well, if the signal handler ran while the thread was blocked in wait() then that call was interrupted. I guess the question is why wait() then went ahead with collecting the child and returned successfully instead of failing with EINTR.
I can reproduce that behavior. The specifics of how you register the handler are unclear, but in my tests I see the handler running and wait() thereafter returning successfully even when the SA_RESTART flag is not set for SIGCHLD, which is generally a major factor in whether restartable system calls such as wait() fail with EINTR when interrupted by a signal.
I'm having trouble locating any documentation that specifically prescribes the observed combination of results for wait() + handler function + SIGCHLD, but the bottom line is that SIGCHLD is special. In particular, it has a special relationship with wait(), because the events that a system-generated SIGCHLD reports on are exactly the ones that a blocking wait() call is waiting for. Some of the manifestations of that specialness are
The sigaction() function defines two flags modulating behavior related specifically to SIGCHLD, and none specific to any other signal.
Even though the default disposition of SIGCHLD is documented as SIG_IGN, its actual default behavior is unique to that signal and distinct from the behavior obtained by explicitly setting the disposition to SIG_IGN.
POSIX has special provisos for the behavior of the wait-family functions, as described in the notes in the wait() manual page, about how these functions are affected by the disposition and flags associated with SIGCHLD.
I don't think either POSIX or Linux explicitly says so, but it all comes around to a pending SIGCHLD being how the wait-family functions recognize that there is a child to collect. POSIX is sufficiently unspecific that I think other POSIX systems could do it differently, but to the best of my knowledge, using SIGCHLD for this purpose is both traditional and what Linux does. Enough so that signal-handling behavior is specifically designed to accommodate the common behavior of using wait() inside a handler for SIGCHLD to provide for central processing of terminated children.
It is also notable that wait() will collect the child and clear the pending SIGCHLD even if that signal is blocked, analogously to how sigwait() will receive blocked signals. In that case, any registered handler is bypassed.
Your case of establishing a handler for SIGCHLD that does not collect the status information for the child is unusual, but consider what needs to happen here:
a SIGCHLD has been received, it is not blocked, and a signal handler has been registered for it, so the signal handler must run and the SIGCHLD must be removed from the pending list.
after your particular handler runs, the status information for the child has not yet been consumed, so it must be consumed when control returns to wait(). Otherwise, it can never be consumed and reported, for receipt of a SIGCHLD is how the system is triggered to do that, and the context in which the status information is delivered.
I anticipate that your wait() would fail with either ECHILD or EINTR if the signal handler collected the waited-for child via its own wait() call. Which one depends in part on whether the SA_RESTART flag is set for SIGCHLD. I anticipate that it would fail with EINTR if there was a running child, and the wait() was interrupted by a synthetic SIGCHLD, and the SA_RESTART flag was not set.

Signal that can be used just by my application

I am programming a tree of processes in Linux and I wonder if there is any signal that can be used just to send from A process to B process without affecting B process.
For example, assume B_pid is the process B's ID, if process A calls kill(B_pid, SIGSTOP); then A will pause B. What I am looking for is a signal, let's say SIGNOTHING, that when A calls kill(B_pid, SIGNOTHING), then it just simply sends a message to B rather than doing something to both B and the system.
SIGUSR1 and SIGUSR2 are designed for that purpose.
If you invoke the following command on your shell:
kill -l
you get a full list of signals available for your system.
Most of the signals can be used to simply "receive" them on the target side. BUT: Most signals are also used by the system itself to tell the application that something special happened, like SIGSEGV. So it makes no sense to use signals, which have a fixed meaning as they are used to communicate from kernel/OS to the application.
For user signals, you have two signals reserved, which can be used for everything you like: SIGUSR1 and SIGUSR2.
Not all Unix systems have these signals! So first take a look which signals can be used on your current system!
Additional hint:
Check you signal handlers and the context on which they are running. On some implementations it is not allowed to call non-reentrant functions from the context of the handler. So it is maybe more useful to communicate via a pipe or any other IPC method.
There are signals that are meant for use for user programs. From man signal:
The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
SIGSTOP will always stop the program and SIGKILL will always terminate the program.
There are two user-defined signals commonly used for signal communication between processes:
SIGUSR1 ... User-defined signal 1
SIGUSR2 ... User-defined signal 2
And there is also a whole range of real-time signals for use as user-defined signals between SIGRTMIN and SIGRTMAX, that have to be at least 8 signals (ie. SIGRTMAX - SIGRTMIN >= 8) and linux supports 33 signals. These are all for use for user-application to do anything it desires.
Basically each signal in Linux has a action associated with it.
Man page of signal:
Signal dispositions
Each signal has a current disposition, which determines how the
process behaves when it is delivered the signal.
The entries in the "Action" column of the table below specify the
default disposition for each signal, as follows:
Term Default action is to terminate the process.
Ign Default action is to ignore the signal.
Core Default action is to terminate the process and dump core (see
core(5)).
Stop Default action is to stop the process.
Cont Default action is to continue the process if it is currently
stopped.
SIGSTOP
SIGSTOP P1990 Stop Stop process
A process can change the disposition of a signal using sigaction(2)
or signal(2). (The latter is less portable when establishing a
signal handler; see signal(2) for details.) Using these system
calls, a process can elect one of the following behaviors to occur on
delivery of the signal: perform the default action; ignore the
signal; or catch the signal with a signal handler, a programmer-
defined function that is automatically invoked when the signal is
delivered.
You can define your own signal handler and define the behavior of your process.
Note: SIGKILL and SIGSTOP cannot be caught

Stoping a process then using it again without killing it

Is there any way in C programming language , to stop a child process , and then call it again to start from the beginning? I have realised that if I use SIGKILL and then call the child process again nothing happens.
void handler {
printf(“entered handler”);
kill(getpid(),SIGKILL);
}
int main () {
pid_t child;
child=fork();
if (child<0) printf(“error”);
else if (child==0) {
signal(SIGINT,handler);
pause();
}
else {
kill(child,SIGINT);
kill(child,SIGINT);
}
This should print two times “Entered Handler” but it does not. Probably because it cannot call child again . Could I correct this in some way?
This should print two times “Entered Handler” but it does not.
Probably because it cannot call child again .
There are several problems here, but a general inability to deliver SIGINT twice to the same process is not one of them. The problems include:
The signal handler delivers a SIGKILL to the process in which it is running, effecting that process's immediate termination. Once terminated, the process will not respond to further signals, so there is no reason to expect that the child would ever print "entered handler" twice.
There is a race condition between the child installing a handler for SIGINT and the parent sending it that signal. If the child receives the signal before installing a handler for it, then the child will terminate without producing any output.
There is a race condition between the the first signal being accepted by the child and the second being delivered to it. Normal signals do not queue, so the second will be lost if delivered while the first is still pending.
There is a race condition between the child blocking in pause() and the parent signaling. If the signal handler were not killing the child, then it would be possible for the child to receive both signals before reaching the pause() call, and therefore fail to terminate at all.
In the event that the child made it to blocking in pause() before the parent first signaled it, and if it did not commit suicide by delivering itself a SIGKILL, then the signal should cause it to unblock and return from pause(), on a path to terminating normally. Thus, there would then also be a race condition between delivery of the second signal and normal termination of the child.
The printf() function is not async-signal safe. Calling it from a signal handler produces undefined behavior.
You should always use sigaction() to install signal handlers, not signal(), because the behavior of signal() is underspecified and varies in practice. The only safe use for signal() is to reset the disposition of a signal to its default.
Could I correct this in
some way?
Remove the kill() call from the signal handler.
Replace the printf() call in the signal handler with a corresponding write() call.
Use sigaction() instead of signal() to install the handler. The default flags should be appropriate for your use.
Solve the various race conditions by
Having the parent block SIGINT (via sigprocmask()) before forking, so that it will initially be blocked in the child.
Have the child use sigsuspend(), with an appropriate signal mask, instead of pause().
Have the child send some kind of response to the parent after returning from sigsuspend() (a signal of its own, perhaps, or a write to a pipe that the parent can read), and have parent await that response before sending the second signal.
Have the child call sigsuspend() a second time to receive the second signal.

Can we assign signal handler to every signal in linux user space program?

If we assign different handler to say SIGABRT, etc.. We might not be able to kill the process, conspicuously, it's not a good idea unless we can. So, the manual says SIGSTOP and SIGKILL cannot be blocked or ignored, does it mean that it must kill or stop the process no matter what handler you assign?
The SIGSTOP and SIGKILL signals cannot be caught or ignored. It is possible to set handlers for them using signal() or sigaction(), but those handlers will never be called, so there is no point in doing so.

Process terminated when signaling a pthread waiting on "join"

I'm trying to implement a signal handler.
each pthread is created joinable, and is blocked upon all signals using sigprocmask.
The problem occurs when I send the thread a signal from another thread, using
pthread_kill(_threads[threadIndex], SIGHALT);
If the called pthread is waiting on pthread_join at the time the signal is sent, the whole proccess is terminated immidiately. However, if the thread is not waiting on join, it ignores the signal as expected. Any idea why does it happen and how to change it?
Thank you!
Regarding the use of sigprocmask() in a mutithreaded environment please see this excerpt from the methods's man page:
The use of sigprocmask() is unspecified in a multithreaded process;
see pthread_sigmask(3).
I'm a bit unsure about SIGHALT, but assuming it's a synonym to SIGSTOP the following from pthread_kill()'s man page might be of interest:
Signal dispositions are process-wide: if a signal handler is
installed, the handler will be invoked in the thread thread, but if
the disposition of the signal is "stop", "continue", or "terminate",
this action will affect the whole process.

Resources