I know I can use the trick if (fork()) exit(0); to change the pid of the current process. So, the following program would have a pid changing very quickly. How to kill a process like this? Is there some better method than executing a lot of killall procname until one get able to run kill() before it forks? I know it is not a 'process', but many processes that run for a few microseconds each.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
pid_t self = getpid();
while (1)
{
if (fork()) exit(0);
if (self + 10000 < getpid()) break; // Just to kill it after some time
usleep(1000);
}
return 0;
}
Also the only way I found to list the process was executing ps -A | grep procname a few times until one showed some output. Why isn't the process always listed?
Such a process is called a "comet" by systems administrators.
The process group ID (PGID) doesn't change on fork, so you can kill it (or SIGSTOP it) by sending a signal to the process group (you pass a negated PGID instead of a PID to kill).
The only reason I can see why you wouldn't see it is that the forked child has not been created yet but the parent has progressed far enough in it's death that it is no longer listed.
Unfortunately I don't think it's possible to kill this kind of process without some guessing. To do so would require knowing the next pid in advance. You can guess the next pid but not be certain that no other pid gets it assigned.
Related
I tried to create a zombie process, using the ps command for verification. Although the solution is good, it is not very suggestive for identifying the child as a zombie. Can anyone help me with some improvements?
this is my code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int pid=fork();
if (pid>0)
{
printf("in parent process");
sleep(30);
execlp("ps","ps",NULL);
}
else if (pid==0)
{
printf("in child process");
}
return 0;
}
A Zombie process doesn't represent anything but a dead process for which it's parent has not already wait(2)ed. It's existence is just to provide the kernel a means to pass back to it's parent process it's accounting details (like cpu time spent, or exit code) in order to make the wait(2) system call reliable.
There's nothing else, depending on the operating system, you cannot even get the command line parameters used to call it, or the name of the process that it represents.
The only thing you can do with a zombie process is for its parent to wait(2) for it, and so, pass up the accounting details, exit code and other info upto its parent. No memory is assigned to it, no system resources are dedicated or locked, all its file descriptors are already closed, only it's pid, process-group id, session-id, and accumulated system and user space cpu times (for it, and the accumulated of its children) is stored in the process table, so the wait(2) system call can also accumulate them when the parent process exit(2)s or wait(2)s for it.
As you'll probably have already detected, you cannot kill(2) a zombie process (well, you can indeed kill(2) its parent, so it will rest in peace forever ---and the parent) as it is already dead.
In order to get a better identification of the process, you have to gather that info in the parent process (the parent receives all of it in the wait(2) family of system calls) You'll get the pid_t process id, so you'll know which of your child processes is the one you have wait(2)ed for. As you (the parent) created it, you'll know everything you need to know your children (you got this pid from the fork(2) system call when you created it)
I am new to processes in linux and c.
I am using this straightforward example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char * argv[]) {
pid_t child_pid_or_zero = fork(); //fork returns twice
if(child_pid_or_zero < 0)
{
//if fork returns a number smaller than zero, something wrong happened
perror("Something wrong happened\n");
exit(-1);
}
if(child_pid_or_zero > 0)
{
//if fork returns a number greater than zero, this is the parent process
printf("I'm the parent, my pid is: %d\t My child pid is %d\n", getpid(), child_pid_or_zero);
wait(NULL);
}
else
{
//this means that fork now returned 0, the child process is running
printf("I am the child with pid: %d\t My parent pid is: %d\n",child_pid_or_zero, getppid());
}
return 0;
}
If I were to omit the wait() method in the
if(child_pid_or_zero > 0)
What would happen? I tried this myself, and apparently, there was no immediate difference. Do we always need to use a wait(), or does this only apply when the child is supposed to perform heavy calculations etc ?
Thanks in advance.
Wait is for listening to state changes and obtaining information about the child. A state change is child termination, stopping or resuming by a signal. Wait allows the system to release the resources associated with the child. If a wait is not performed, then the terminated child remains in a "zombie" state.
The kernel maintains a minimal set of information about the zombie
process (PID, termination status,
resource usage information) in order to allow the parent to later perform a wait to obtain information about the child. As long
as a zombie is not removed from the system via a
wait, it will consume a slot in the kernel process table, and if this table fills, it will not be possible to create further
processes. If a parent process terminates, then its
"zombie" children (if any) are adopted by init(1), which automatically performs a wait to remove the zombies.
The system call wait(2) is typically used to find if the child process's state has changed (i.e. whether it's still running, exited, etc).
Another purpose is to avoid "zombie" processes. If parent process doesn't wait on the child process and the child process exits before the parent process then it becomes a "zombie" process. So, a wait() call is used to "reap" the process and release the system resources associated with the process.
Imagine if the parent process is a long running one and creates several child processes at regular intervals then all the zombie processes will have entries in the process table which is an unncessary use of system resources.
after the fork, you'll have two independent process.
whit the wait() call, you tell the parent process to wait the child process to terminate.
In this example, nothing changes since the two process are not interacting with each other, so the parent can just exit after creating the child and printing the string, but in the scenario where the parent has to wait the child to do some operations and then maybe return some values to the parent, it becomes useful!
I'm new to C and I've been investigating about forks the last two weeks, I have to solve this problem for my Operative Systems class:
"You must create a "heavy weight" process using a fork, then the first process must wait for the second (the new one) to return its parent id, then it must kill its parent and finish"
I think the instructions are quite confusing, this is my code so far ( As I said, I'm new to C so I've been just investigating)
My problem seems to be that the parent is not even waiting for the child process to return its id, because after that, the child is killing the parent, so I think I'm creating the child process, and when it runs it kills the parent at the end, not letting the parent to wait for the child execution. (that's the part I think is confusing about the instructions)
I want to know more about forks and processes, like the logic behind them so I can feel more sure when coding.
Thanks!
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t idProceso;
int childState;
idProceso = fork();
if (idProceso == 0){
printf ("child id : %d. parent id %d\n",
getpid(), getppid());
int parent = getppid();
kill(parent, SIGKILL);
printf ("dead parent"); // not sure about it ??
_exit();
}
if(idProceso > 0){
sleep (1);
printf ("parent id : %d. child id %d\n",
getpid(), idProceso);
wait (&childState);
}
return 0;
}
Based on the assignment description you gave, I think the instructor or professor who assigned it does not have a good handle on either the English language or the concept of processes on a Unix machine.
The solution you presented is reasonable, but I would I remove the call to sleep. Childstate is never set correct, and you don't need it all. Additionally, don't send SIGKILL to the parent. SIGKILL is the last way to attempt to terminate a process. I suggest sending SIGTERM to the parent process. The parent process can install a signal handler with sigaction if you are using a Linux machine. In the signal handler, you can print a nice message like "Received terminate signal from child" and call exit. If you do this your professor will probably be suitably impressed with your skills to give you a passing grade.
Failing that, I would ask for a better problem. It was not uncommon for me to have to submit grammatical and punctuation corrections to professors for approval before actually solving the problem.
My problem seems to be that the parent is not even waiting for the
child process to return its id
Nowhere in your program is the child returning its id to the parent. The only comunication that is happening is the child sending a SIGKILL signal to the parent.
so I think I'm creating the child process, and when it runs it kills
the parent at the end, not letting the parent to wait for the child
execution.
Yes , you are right , the child will kill the parent process , by sending a SIGKILL signal , using the kill() function , but the parent actually waits to get killed by the child.
wait (&childState);
This here makes the parent wait(hang there) for the child to terminate , after termination , the parent will move on , but in your program , while the parent waits for the child to get terminated , the child itself will terminate the parent during the wait.
I want to know more about forks and processes, like the logic behind
them so I can feel more sure when coding.
This is something worth looking at.
$ ./foo.bin
parent id : 6629. child id 6630
child id : 6630. parent id 6629
dead parentKilled
I just removed the sleep(1) and the output seems to be reasonable.
This question already has answers here:
What is the reason for performing a double fork when creating a daemon?
(9 answers)
Closed 8 years ago.
Nagios lets me configure child_processes_fork_twice=<0/1>.
The documentation says
This option determines whether or not Nagios will fork() child processes twice when it executes host and service checks. By default, Nagios fork()s twice. However, if the use_large_installation_tweaks option is enabled, it will only fork() once.
As far as I know fork() will spawn a new child process. Why would I want to do that twice?
All right, so now first of all: what is a zombie process? It's a process that is dead, but its parent was busy doing some other work, hence it could not collect the child's exit status. In some cases, the child runs for a very long time, the parent cannot wait for that long, and will continue with it's work (note that the parent doesn't die, but continues its remaining tasks but doesn't care about the child). In this way, a zombie process is created. Now let's get down to business. How does forking twice help here? The important thing to note is that the grandchild does the work which the parent process wants its child to do. Now the first time fork is called, the first child simply forks again and exits. This way, the parent doesn't have to wait for a long time to collect the child's exit status (since the child's only job is to create another child and exit). So, the first child doesn't become a zombie. As for the grandchild, its parent has already died. Hence the grandchild will be adopted by the init process, which always collects the exit status of all its child processes. So, now the parent doesn't have to wait for very long, and no zombie process will be created. There are other ways to avoid a zombie process; this is just a common technique. Hope this helps!
In Linux, a daemon is typically created by forking twice with the intermediate process exiting after forking the grandchild. This has the effect of orphaning the grandchild process. As a result, it becomes the responsibility of the OS to clean up after it if it terminates. The reason has to do with what are known as zombie processes which continue to live and consume resources after exiting because their parent, who'd normally be responsible for the cleaning up, has also died.
Also from the documentation,
Normally Nagios will fork() twice when it executes host and service checks. This is done to (1) ensure a high level of resistance against plugins that go awry and segfault and (2) make the OS deal with cleaning up the grandchild process once it exits.
Unix Programming Faq ยง1.6.2:
1.6.2 How do I prevent them from occuring?
You need to ensure that your parent process calls wait() (or
waitpid(), wait3(), etc.) for every child process that terminates;
or, on some systems, you can instruct the system that you are
uninterested in child exit states.
Another approach is to fork() twice, and have the immediate child
process exit straight away. This causes the grandchild process to be
orphaned, so the init process is responsible for cleaning it up. For
code to do this, see the function fork2() in the examples section.
To ignore child exit states, you need to do the following (check your
system's manpages to see if this works):
struct sigaction sa;
sa.sa_handler = SIG_IGN;
#ifdef SA_NOCLDWAIT
sa.sa_flags = SA_NOCLDWAIT;
#else
sa.sa_flags = 0;
#endif
sigemptyset(&sa.sa_mask);
sigaction(SIGCHLD, &sa, NULL);
If this is successful, then the wait() functions are prevented from
working; if any of them are called, they will wait until all child
processes have terminated, then return failure with errno == ECHILD.
The other technique is to catch the SIGCHLD signal, and have the
signal handler call waitpid() or wait3(). See the examples section
for a complete program.
This code demonstrates how to use the double fork method to allow the grandchild process to become adopted by init, without risk of zombie processes.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main()
{
pid_t p1 = fork();
if (p1 != 0)
{
printf("p1 process id is %d", getpid());
wait();
system("ps");
}
else
{
pid_t p2 = fork();
int pid = getpid();
if (p2 != 0)
{
printf("p2 process id is %d", pid);
}
else
{
printf("p3 process id is %d", pid);
}
exit(0);
}
}
The parent will fork the new child process, and then wait for it to finish. The child will fork a grandchild process, and then exit(0).
In this case, the grandchild doesn't do anything except exit(0), but could be made to do whatever you'd like the daemon process to do. The grandchild may live long and will be reclaimed by the init process, when it is complete.
How the below program works and create a Zombie process under linux?
#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;
}
It creates children and doesn't wait (with one of the wait* system call) for them. And zombies are just that: children that the parents hasn't waited yet, the kernel has to maintain some information for them -- mainly the exit status -- in order to be able to return it to the parent.
The setsid() command is missing.
Every *nix process produces an exit status that must be reaped. This is supposed to be reaped by the parent process using a wait() statement, if the child is supposed to terminate first.
The setsid() command switches the parent process to init when the parent terminates before the child process.
Root should be able to remove zombies from the process list using kill -9. Inexperienced programmers sometimes omit setsid(), which will hide bugs that produce errors that would otherwise clog the disk drive.
In days of old, the system administrator would use zombies to identify inexperienced programmers that need additional training to produce good code.
The exit status harvested by init is sent to syslog when the kernel terminates a program prematurely. That exit status is used to identify the nature of the bug that caused the early termination (error conditions not handled by the programmer).
Exit status reported in this way becomes part of the syslog or klog files, which are commonly used to debug code.