I have a main process that has forked some kid processes.
Each kid does something and blocks itself. By blocking itself every child sends a SICHLD signal to the parent process.
I also have declared a sigaction action, in the main process code, in order to catch the SIGCLHD that the kids will send.
static struct sigaction action;
action.sa_handler = handler
sigfillset(&(action.sa_mask));
sigaction(SIGCHLD, &action, NULL);
The SIGCHLD handler when called, checks which kid sent the SIGCHLD signal and does something for that kid.
The question is, what happens if multiple kids send signals at the same time? Let's say that kid(1) sent SIGCHLD. The handler catches it and before he completes the handle, kid(2) and kid(3) both send signals. Will the handler run for each of these signals after he is done with kid(1) or will these signals get ignored?
SIGCHLD is somewhat special in that you get exactly one signal per exiting child; these signals are tied to the corresponding zombies/wait-status left behind by the child processes they correspond to. But in general most signals are just flags, not queues. If possible it's best not to use SIGCHLD and instead just use waitpid and track child exit in some other way (e.g. by observing EOF status on a pipe from the child in your poll loop or such).
Related
There is a way to look when pid/tid status change with waitpid but this is blocking function.
I want to monitor all threads in specific pid and get signal when one of them change and print the tid.
For now I open threads as count of threads in that process and each 1 make waitpid on 1 tid and after that blocking function finish I print that tid that changed.
How can I get a signal that tid change so I can monitor all tid's in 1 thread.
I didn't want to monitor all pid in system only specific pid/tid.
Those tids/pids are not children of my process.
You can call
int status;
pid_t waitpid(-1, &status, 0);
to wait for any child process change.
So you do not have to specify in advance, which pid to monitor, and can react on any status change. This way you do not need to start one thread for each pid.
As to the signal part of your question: A SIGCHLD is sent to your process when a child process exits. This signal is ignored by default, but you can install a custom signal handler for it, of course.
If you only want to reap specific pids, linux provides the option WNOWAIT, which only reports the state, but does not really reap the child process. Now you can check, if the pid is one of those you want to monitor, and if so, call waitpid() again without the option.
If the processes are not children, waitpid() cannot be used in general. One option is, to attach with ptrace() to these 40 processes to get signalled, if one of these processes exit. This might have unwanted side-effects, however.
If you're using POSIX threads, then you could use pthread_cleanup_push and pthread_cleanup_pop to call a "cleanup" function when your thread is exiting.
This "cleanup" function could then send one of the user signals (SIGUSR1 or SIGUSR2) to the process which then catches it and treats it as a signal about thread termination.
If you use sigqueue you can add the thread-id for the signal handler so it knows which thread just exited.
You can use pthread_sigmask to block the user signal in all threads, to make sure it's only delivered to the main process thread (or use pthread_sigqueue to send to the main process thread specifically).
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.
I have a child process which might receive sigterm signal from its parent or from somewhere else. I have to take appropriate action if the signal is from parent.
How can i find if the received signal is from parent in c(linux)?
You set up your signal handler with sigaction using the SA_SIGINFO flag. Your handler will accept a parameter of siginfo_t. Within the siginfo_t struct is the field si_pid. This is the process id of the sending process. Match that against the child's ppid().
I am dealing with some issue, I have a function that's handling a signal and like that:
void sigChld(int noSig)
{
//some action here
}
void F1 () // some child process
{
struct sigaction action;
.... // initialisation of the structure with sigChld as the function handler
sigaction(SIGCHLD, &action, 0);
while(1)
callToFunction();
}
In my child process F1, I am attaching the handler to SIGCHLD to sigChld() and then I do callToFunction() that creates another process and do some treatment. At the end of its execution, It sends me a SIGCHLD which I need to treat in my handler.
Now my question is : I need the return value of callToFunction() so I thought about using a waitpid in the handler of sigchld before doing some actions. But what if during waitpid() or the actions, callToFunction() send another signal ? will the current handler stop ? or will continue its execution and then treat the next signal ?
In my problem, I need to treat completely the signals one after another one like if I was executing the handler in parallel.
I'm not sure it's actually possible for a waitpid() in a SIGCHLD handler to get interrupted by a signal, since it should return instantly if there's a child available, but in general signals can occur during a signal handler just like anywhere else.
I have a simple program under Linux which sends SIGUSR1 signal to its child process in a cycle. But when I send e.g. 10 signals, sometimes happens, that the child received only 3 of them. Last sent signal is always SIGUSR2 and that is received every time.
Are the signals queuing, or when process didn't process the previous, it is simply overwritten? Is there a way I can send signals in a queue?
What happens is the following:
First signal received, namely SIGUSR1, handler is called and is running
Second signal received, since handler from nr1 is still running, the signal nr2 gets pending and blocked.
Third signal received, since handler from nr1 is still running, the signal 3 gets discarded.
Fourth, fifth...etc signal of the same type as the signal nr1 are discarded.
Once signal handler is done with signal nr1, it will process signal nr2, and then signal handler will process the SIGUSR2.
Basically, pending signals of the same type are not queued, but discarded. And no, there is no easy way to "burst" send signals that way. One always assumes that there can be several signals that are discarded, and tries to let the handler do the work of cleaning and finding out what to do (such as reaping children, if all children die at the same time).
If multiple signals of the same type are sent and not handled, they aren't queued. Say the program masks SIGUSR1, calls kill(getpid(), SIGUSR1) 10 times and unmasks SIGUSR1. It will receive SIGUSR1 just once.
Your problem is probably that SIGUSR2 is a signal that is delivered right away, while other signals are blocked or queued (in status pending).
Here's how you can check for pending signals: http://www.gnu.org/s/libc/manual/html_node/Checking-for-Pending-Signals.html
So doing simultaneous I/O of many files with SIGIO seems possible only if one uses flag SA_NODEFER for struct sigaction sa_flags field and never blocks signals.
So then, one could get interrupt from inside a signal handler and create new thread for each individual signal being handled. That gets complicated :) So no wonder why no one seems to use SIGIO.