re-parenting stopped process - c

How does re-parenting of stopped process heppens? Why does stopped process just terminates after re-parenting?
More precisely, suppose I have a code like this
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <stdio.h>
int main(void) {
pid_t child;
child = fork();
if (child == 0) {
int t = 0;
while (true) {
printf("%d. I'm %d, my parent is %d\n", t++, getpid(), getppid());
sleep(1);
}
} else {
printf("I'm the parent. My pid is %d\n", getpid());
printf("Starting to wait for 30 seconds\n");
sleep(30);
printf("Done waiting, aborting\n");
}
}
When I run this code the child process works and parent process just sleeps. After 30 seconds passed the parent process terminates and the child process now becomes a child of init and just continues running. Everything is normal.
But if I run this code and in first 30 seconds of it's execution I also run
kill -SIGSTOP <child_pid>
Then the child process stops (T state in ps xaf) and the parent process sleeps. After 30 second passed the parent process returns from sleep and just terminates (as it reached the end of main) but the child process instead of being re-parented to init in stopped state just terminates. I don't see it in ps xaf and if run lastcomm I see this output:
a.out F X equi pts/5 0.00 secs Wed Mar 16 17:44
Why is this happening that stopped process dies after re-parenting? Is it possible in linux to re-parrent stopped process?

From http://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html
When a process in an orphaned process group (see Orphaned Process
Groups) receives a SIGTSTP, SIGTTIN, or SIGTTOU signal and does not
handle it, the process does not stop. Stopping the process would
probably not be very useful, since there is no shell program that will
notice it stop and allow the user to continue it. What happens instead
depends on the operating system you are using. Some systems may do
nothing; others may deliver another signal instead, such as SIGKILL or
SIGHUP. On GNU/Hurd systems, the process dies with SIGKILL; this
avoids the problem of many stopped, orphaned processes lying around
the system.
See also: What's the difference between SIGSTOP and SIGTSTP?

Related

Creating Zombie process in C (Linux) [duplicate]

This question already has answers here:
Create zombie process
(2 answers)
Closed 1 year ago.
my task is to create zombie process. My code looks like this:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == -1) {
printf("error\n");
}
else if (pid == 0) {
printf("Child %d\n", getpid());
printf("Parents %d\n", getppid());
printf("Waiting for my Child to complete\n");
exit(0);
}
else {
sleep(5);
printf("Parent %d\n",getpid());
}
return 0;
}
When I gcc and execute the file with ./a.out I get the following output:
Child 25097
Parents 25096
Waiting for my child to complete
Parent 25096 ( a few seconds later)
My task is to create a zombie process and print out the exit-state of the child process while being in parent process. Everything is a bit confusing to me because its the first time for me using Linux and C.
Do you have some tips/ hints for me, how to solve the task? Cause I'm not sure if everything is right. I also tried playing with wait(), waitpid() and WEXITSSTATUS(), but I'm not sure about it. And I used the ps x command to check if there is a different output but I didn't notice any changes.
Thanks in advance :)
This code will successfully create a zombie process.
After the call to fork, the child prints a few lines and exits, while the parent sleeps for 5 seconds. This means you'll have a zombie process for about 5 seconds while the parent is sleeping.
When the sleep is done, the parent prints something and exits. Once the parent exits the child is inherited by the init process, which will wait for the child and make it's pid disappear fro the pid list.
You can also use wait in the parent process, in which case the child is a zombie up until the parent calls wait.

what's the relationship between exit(0) and zombie process

I found that it can't create a zombie process when I remove exit(0); from the child part. Can you tell me why?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
int main() {
if(!fork()) {
printf("child pid=%d\n", getpid());
exit(0);
}
sleep(20);
printf("parent pid=%d\n",getpid());
exit(0);
}
A zombie process is a dead child process that the parent process hasn’t checked on. In the original code, the child ends 20 seconds earlier than the parent, so it’s a zombie for 20 seconds. If you remove the first exit(0), they both stay alive for 20 seconds because in the child, control passes right out the bottom of the if block unless something stops it.
Thus, if you remove the child's exit() then not only is it unlikely to go zombie for an observable amount of time, but you should see it print a "parent pid" message in addition to its "child pid" message.

Create zombie process

I am interested in creating a zombie process. To my understanding, zombie process happens when the parent process exits before the children process. However, I tried to recreate the zombie process using the following code:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main ()
{
pid_t child_pid;
child_pid = fork ();
if (child_pid > 0) {
exit(0);
}
else {
sleep(100);
exit (0);
}
return 0;
}
However, this code exits right after execute which is expected. However, as I do
ps aux | grep a.out
I found a.out is just running as a normal process, rather than a zombie process as I expected.
The OS I am using is ubuntu 14.04 64 bit
Quoting:
To my understanding, zombie process happens when the parent process exits before the children process.
This is wrong. According to man 2 wait (see NOTES) :
A child that terminates, but has not been waited for becomes a "zombie".
So, if you want to create a zombie process, after the fork(2), the child-process should exit(), and the parent-process should sleep() before exiting, giving you time to observe the output of ps(1).
For instance, you can use the code below instead of yours, and use ps(1) while sleep()ing:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
int status;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
/* Child */
if (pid == 0)
exit(0);
/* Parent
* Gives you time to observe the zombie using ps(1) ... */
sleep(100);
/* ... and after that, parent wait(2)s its child's
* exit status, and prints a relevant message. */
pid = wait(&status);
if (WIFEXITED(status))
fprintf(stderr, "\n\t[%d]\tProcess %d exited with status %d.\n",
(int) getpid(), pid, WEXITSTATUS(status));
return 0;
}
A zombie or a "defunct process" in Linux is a process that has been completed, but its entry still remains in the process table due to lack of correspondence between the parent and child processes. Usually, a parent process keeps a check on the status of its child processes through the wait() function. When the child process has finished, the wait function signals the parent to completely exit the process from the memory. However, if the parent fails to call the wait function for any of its children, the child process remains alive in the system as a dead or zombie process. These zombie processes might accumulate, in large numbers, on your system and affect its performance.
Below is a c program to creating a Zombie-Process on our system Save this file as zombie.c:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main ()
{
pid_t child_pid;
child_pid = fork ();
if (child_pid > 0) {
sleep (60);
}
else {
exit (0);
}
return 0;
}
The zombie process created through this code will run for 60 seconds. You can increase the time duration by specifying a time(in seconds) in the sleep() function.
Compile this program
gcc zombie.c
Now run the zombie program:
./a.out
The ps command will now also show this defunct process, open a new terminal and use the below command to check the defunct process:
aamir#aamir:~/process$ ps -ef | grep a.out
aamir 10171 3052 0 17:12 pts/0 00:00:00 ./a.out
aamir 10172 10171 0 17:12 pts/0 00:00:00 [a.out] <defunct> #Zombie process
aamir 10177 3096 0 17:12 pts/2 00:00:00 grep --color=auto a.out

How variables are shared between two process when the fork is involved

/* In alarm.c, the first function, ding, simulates an alarm clock. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static int alarm_fired = 0;
void ding(int sig)
{
alarm_fired = 1;
}
/* In main, we tell the child process to wait for five seconds
before sending a SIGALRM signal to its parent. */
int main()
{
pid_t pid;
printf("alarm application starting\n");
pid = fork();
switch(pid) {
case -1:
/* Failure */
perror("fork failed");
exit(1);
case 0:
/* child */
sleep(5);
printf("getppid: %d\n", getppid());
kill(getppid(), SIGALRM);
exit(0);
}
/* The parent process arranges to catch SIGALRM with a call to signal
and then waits for the inevitable. */
printf("waiting for alarm to go off\n");
(void) signal(SIGALRM, ding);
printf("pid: %d\n", getpid());
pause();
if (alarm_fired)
printf("Ding!\n");
printf("done\n");
exit(0);
}
I have run the above code under Ubuntu 10.04 LTS
> user#ubuntu:~/Documents/./alarm
> alarm application starting
> waiting for alarm to go off
> pid: 3055
> getppid: 3055
> Ding!
> done
I have read the following statement from a book.
It’s important to be clear about the
difference between the fork system
call and the creation of new threads.
When a process executes a fork call, a
new copy of the process is created
with its own variables and its own
PID. This new process is scheduled
independently, and (in general)
executes almost independently of the
process that created it.
Question:
It seems to me that the variable alarm_fired is shared between the original process and the new created process.
Is that correct?
No. Each process gets its own copy of the variable (and pretty much everything else). If you change the variable in one process, it is changed only in that process, not in both. Each process has its own address space.
Compare that with threads, where all threads share a single address space, so a change in a variable in one thread will be visible in all other threads (within that process).
From the Linux fork(2) manpage:
fork() creates a child process that differs from the parent process only in its PID and PPID, and in the fact that resource utilizations are set to 0. File locks and pending signals are not inherited.
It is shared in the sense that immediately after the fork it has the same value in both processes. BUT when either writes to it the change is not propagated to the other process (that what different .
Also, see copy on write for interesting stuff.
EDIT
It seems that the new created process
modified the variable alarm_fired
which is then later seen by the old
process
The child is sending a signal to the parent. The parent then executes the handler and personally sets alarm_fired to one. The child itself never touches that variable.
No, variables are not shared across a fork(). In your code, the child process never touches alarm_fired. What the child does is send a signal to the parent. That signal fires a signal handler in the parent process' context, setting the variable.

Child processes die when killing parent if one of them is stopped with SIGSTOP

My test code is
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
int c = fork();
if (c == 0) while(1);
c = fork();
if (c == 0) while(1);
c = fork();
if (c == 0) while(1);
c = fork();
if (c == 0) while(1);
while(1);
}
So I have one parent and 4 childs. When I kill the parent, childs are working fine with init as a parent. But if I stop (with SIGSTOP) one of the childs and then kill the parent, childs are killed too. Why this is so?
Apparently if a process in the process group is stopped, all processes are signalled with SIGHUP and then SIGCONT when the process group leader is terminated. The default handler for SIGHUP terminates the process. It is expected behaviour, as documented in e.g.
http://www.win.tue.nl/~aeb/linux/lk/lk-10.html
From the above link:
If termination of a process causes a
process group to become orphaned, and
some member is stopped, then all are
sent first SIGHUP and then SIGCONT.
The idea is that perhaps the parent of
the process group leader is a job
control shell. (In the same session
but a different process group.) As
long as this parent is alive, it can
handle the stopping and starting of
members in the process group. When it
dies, there may be nobody to continue
stopped processes. Therefore, these
stopped processes are sent SIGHUP, so
that they die unless they catch or
ignore it, and then SIGCONT to
continue them.
EDIT:
BTW, strace is a wonderful tool for getting to the bottom of stuff like this. If you attach strace to one of the child processes you will see that SIGHUP is delivered only if one of then is stopped when the parent (i.e. the process group leader) dies.
You need to change the handler for SIGHUP using e.g. sigaction(2) if you want the children processes to survive.
The children belong to the same process group as the parent process and are thus killed together with their parent process.
Hint: don't use while(1); to suspend a process. Let it sleep indefinitely.

Resources