How can I handle SIGCHLD? - c

I need to handle SIGCHLD properly. How can I use it with my existing code? at the moment I cant wait for the child process unless I use 0 instead of WNOHANG|WUNTRACED.
status = 0;
pid_t child, endID;
if(amp == 1)
signal( SIGCHLD, SIG_IGN );
child = fork();
if (child < 0) {
perror("fork() error\n");
exit(EXIT_FAILURE);
} else if (child == 0) {
// do sth here
perror("error\n");
} else {
//sleep(1)
If I remove sleep then parent is executed 1st.. why?

Here is a start (but read below):
static void
child_handler(int sig)
{
pid_t pid;
int status;
/* EEEEXTEERMINAAATE! */
while((pid = waitpid(-1, &status, WNOHANG)) > 0)
;
}
/* Establish handler. */
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = child_handler;
sigaction(SIGCHLD, &sa, NULL);
Of course, this is all pointless. If the parent simply ignores SIGCHLD, the children are silently reaped and won't turn into zombies.
Quoting TLPI:
Explicitly setting the disposition of SIGCHLD to SIG_IGN causes any
child process that subsequently terminates to be immediately removed
from the system instead of being converted into a zombie.
So something like this should do the trick for you:
signal(SIGCHLD, SIG_IGN); /* Silently (and portably) reap children. */

Related

How to restart a child process from parent process in c

How to restart the child process from parent process when child process terminates. In one application I have created a child process which has an infinite while loop. The application runs in a router. When some event happens my child process terminates. But after rebooting the router everything works fine. Is it possible to restart my child process from parent process(parent process always works).
int main()
{
pid_t pid;
pid = fork();
if (pid == 0)
{
while(1)
{
printf("Child process\n");
sleep(1);
}
}
else
{
while(1)
{
printf("parrent process\n");
}
}
return 0;
}
Assuming you only start one process and it's another executable:
pid_t pid = 0;
void sigchld(int unused)
{
if (pid) {
int status = 0;
waitpid(pid, &status, WNOHANG);
if (WIFSTOPPED(status) || WIFCONTINUED(status)) return;
if (!WIFSIGNALED(status)) return; // It exited rather than terminated
pid = 0;
}
if ((pid = vfork() == 0) {
/* fork() isn't really signal safe anymore but vfork() still is! */
execle(...);
_exit(0);
}
}
int main()
{
pid = 0;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchld;
sa.sa_flags = SA_NODEFER;
sigaction(SIGCHLD, &sa, NULL);
kill(SIGCHLD, getpid());
while(1)
{
printf("parrent process\n");
}
}
Trivially adaptable to more than one, but if it's not another executable you have your work cut out from you. Attempting to fork() and run more code inside the signal handler is fraught with pearl. fork() itself is only safe if you haven't installed any pthread_atfork() handlers (which don't run in vfork()). You cannot call malloc() in a signal handler, and stdio is unreasonably tricky and best to assume it just doesn't work.

How to determine a child process is a a background process or foreground process by looking at code?

we know that if a parents process wait for the termnination of its child processes first, then the child processes are called foreground process, for example:
int main() {
int status;
...
if ((pid = fork()) == 0){
...// Child runs
exit(0);
}
waitpid(pid, &status, 0); //parent wait for its child to reap it
}
since the parent process uses waitpid to wait and reap its child, so the child process is foreground process.
But what if I use signal handler to reap child processes as:
void sigchld_handler(int s){
int olderrno = errno;
pid = waitpid(-1, NULL, 0);
errno = olderrno;
}
volatile sig_atomic_t pid;
int main() {
sigset_t mask, prev;
signal(SIGCHLD, sigchld_handler);
sigemptyset(&mask);
while(1) {
sigprocmask(SIG_BLOCK, &mask, &prev); // Block SIGCHLD
if ((pid = Fork()) == 0){
...// Child runs
exit(0);
}
// Wait for SIGCHLD to be received
pid = 0;
while (!pid)
sigsuspend(&prev);
...//Do some work after receiving SIGCHLD
}
exit(0);
}
then can I say the child process in latter is a foreground process, because the parent wait for it using while (!pid) sigsuspend(&prev);?
But my understanding is that a child can be a foreground process only if the parents explicitly the child's process id in waitpid like waitpid(pid, &status, 0);, bu in the latter example, the parents doesn't specify child process's id to reap (use -1 in waitpid)?

UNIX signal handling. Wait in SIGCHLD handler. C

I've a parent and a child processes. In the parent I established a signal handler for a SIGCHLD. I send SIGTSTP signal to the child, that trigers SIGCHLD and in SIGCHLD siganl handler in parent I call wait function to get a status of the stopped child. But instead of returning immediately it blocks. Then I send a SIGCONT signal to the child and wait returns with errno set to Interuppted system call. I can't understand what I'm missing.
pid_t pid;
static void sig_chld(int signo);
int main() {
struct sigaction act, savechld;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sig_chld;
if (sigaction(SIGCHLD, &act, &savechld) < 0){
return errno;
}
pid = fork();
switch (pid){
case -1:{
perror("fork failed");
return errno;
}
case 0:{ //child
if (sigaction(SIGCHLD, &savechld, NULL) < 0)
return errno;
execlp(path, name_of_executable, (char*)NULL);
return errno;
}
default:{
for (;;)
pause();
}
}
return 0;
}
void sig_chld(int signo) {
int statol;
if (wait(&statol) < 0){
perror("waitt error");
exit(errno);
}
if (WIFSTOPPED(statol)){
puts("Child is stopped");
} else if (WIFEXITED(statol)){
puts("Child exited");
} else if (WIFCONTINUED(statol)){
puts("Child continued");
} else if (WIFSIGNALED(statol)){
puts("Child is signaled");
int sig = WTERMSIG(statol);
psignal(sig, NULL);
}
}
You have to use waitpid() instead of wait(), and you need to specify the option WUNTRACED to also have stopped children reported with waitpid(), like this:
if (waitpid(-1, &statol, WUNTRACED) < 0) {
Now waitpid() should return immediately and your macro WIFSTOPPED(&statol) should be true.

Why does waitpid() only return 1 for all child processes?

I have a handler for SIGCHLD in a process that spawns off many children.
This code is inside my handler and pid is always 1. I've read that pid should be the child process id. Why do I keep getting back 1?
int status;
pid_t pid;
while(pid = waitpid(-1, &status, WNOHANG) > 0)
{
if (WIFEXITED(status))
printf("Child %ld: Ended properly and returned %d\n", pid, WEXITSTATUS(status));
else
printf("Child crashed\n");
}
Code to initialize the handler.
void initSIGCHLDSignalHandler()
{
struct sigaction act;
memset(&act,'\0',sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
act.sa_handler = SIGCHLD_SignalHandler;
sigaction(SIGCHLD, &act, NULL);
}
I imagine you want
while((pid = waitpid(-1, &status, WNOHANG)) > 0)
since right now all you're getting is "true". (Your compiler probably warns about this, so be reading your compiler warnings.)

Linux child process signal loss

I have two child processes and one parent process. The two child send a SIGUSR1 signal at the same time. The handler handles only one of them, and the parent receives only one of them too. I think it can be solved by using real time signal, but i don't now how to do it. Thank you for your help.
void handler(int signalnumber)
{
//do stuff
}
int main()
{
sigset_t blockset;
sigfillset(&blockset);
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
sigaction(SIGUSR1, &action, NULL);
pid_t pid = getpid();
pid_t pids[2];
for(i = 0; i < 2; ++i)
{
if(getpid() == pid)
pids[i] = fork();
}
if(getpid() != pid)
{
while(1)
{
kill(getppid(), SIGUSR1);
}
} else
{
while(1)
{
sigdelset(&blockset, SIGUSR1);
sigsuspend(&blockset);
//do stuff
}
}
}
Edit: I replaced SIGUSR1 with SIGRTMIN+1. Now the handler receives both signals, but the parent does not. (I think, because it's not waiting for any.)
From man sigaction
sa_mask specifies a mask of signals which should be blocked (i.e.,
added to the signal mask of the thread in which the signal handler is
invoked) during execution of the signal handler. In addition, the sig‐
nal which triggered the handler will be blocked, unless the SA_NODEFER
flag is used.`
So, use SA_NODEFER.

Resources