Fork, Execlp and Kill. Zombie Process

Fork, execlp and kill. Zombie process

You should call waitpid(2) or some other waiting system call (wait4(2)...) to avoid having zombie processes. BTW you may also handle the SIGCHLD signal to be notified when a child process has terminated (or changed state).

Generally, you'll better first kill(2) a process with SIGTERM (and only later, with SIGKILL) since that process -your backup.sh script- could handle correctly (using trap builtin in the shell script) the signal (but SIGKILL cannot be caught, and the backup could e.g. leave clutter or useless files on the disk). See also signal(7) & signal-safety(7)

Read Advanced Linux Programming (we can't explain what is taught by that freely available book in several chapters in only a few paragraphs).

BTW, better use perror(3) or strerror(errno) in messages when a system call fails.

Perl fork(), exec() and then kill creating zombie process

You should use waitpid in parent process after killing the child process. That's because you use fork to get a new process, Perl wouldn't do the clean-up job for you as in system.
But I recommend a better module in CPAN which does the whole messy thing, I find it very convenient.

Fork / exec leaving zombie processes even with signal

The SIG_IGN setting is not retained across fork(), so you need to call signal(SIGCHLD, SIG_IGN); in the child process with the loop that spawns all the commands, not the original parent process.

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
pid_t pid, sid;
pid = fork();
if (pid < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid > 0)
{
exit(EXIT_SUCCESS);
}
signal(SIGCHLD, SIG_IGN);
umask(0);
sid = setsid();
if (sid < 0)
{
perror("setsid");
exit(EXIT_FAILURE);
}
if ((chdir("/")) < 0)
{
perror("chdir");
exit(EXIT_FAILURE);
}
while (1)
{
// Check conditions
if (true)
{
pid_t pid2, sid2;
pid2 = fork();
if (pid2 == 0)
{
sid2 = setsid();
// Define command_argv
execlp("sleep", "sleep", "1", (char*)0);
}
}
sleep(60);
}
exit(EXIT_SUCCESS);
}

fork 100 processes at same time and sometimes some processes become zombie

Signals are not queued. If a SIGCHLD is raised while one is pending (probably while your code is in the write syscall), the program will receive just one notification.

The correct way to handle this is to loop in your handler, until all finished children are reaped:

void sig_handler(int signo) {
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG) > 0)
if (WIFEXITED(stat))
{
// Don't actually do this: you should
// avoid buffered I/O in signal handlers.
std::cout << "count:" << ++cnt
<< ", pid:" << pid
<< " signal:" << signo
<< std::endl;
}
}

As mentioned in comments, you should stick to the documented async-signal-safe functions in signal handlers. Buffered I/O (including use of std::cout) can be risky, as the signal handler could be invoked whilst it's manipulating its internal structures. The best way to avoid problems is to limit yourself to communicating with the main code using volatile sig_atomic_t variables.

Why does a process create a zombie if execv fails, but not if execv is successful and terminates?

If you don't want to create zombies, your program has to reap zombie processes no matter if they call execv or not call it or no matter if the execv call succeeds. To reap zombie processes "automagically" handle SIGCHLD signal:

void handle_sigchld(int sig) {
int saved_errno = errno;
while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {}
errno = saved_errno;
}

int main() {
signal(SIGCHLD, handle_sigchld);
// rest of your program....
}

Inspired (no... ripped off) from: this link.

Or maybe you want only to reap only this specified child, because later you want to call fork() and handle childs return value. Then pass the returned pid from fork() in your parent to the signal handler and wait on this pid in sigchld if needed (with some checking, ex. if the pid already finished then ignore future SIGCHLD etc...).

C: Exec/fork Defunct processes

First your second question!

Your children stay in 'zombie' mode because the kernel thinks you might still want to retrieve a return value from them..

If you have no intention to get return values from your child processes, you should set the SIGCHLD signal handler in the parent process to SIG_IGN to have the kernel automatically reap your children.

signal(SIGCHLD, SIG_IGN);

The first question depends a it on your implementation..

But general speaking, just after you fork() you should use close() to close the old file descriptors for 0 and 1 and then use dup2() to set them to your wanted values.. No time for an example right now, but hope this pushes you in the right direction..

How to kill a zombie process which always initiated whenever geany does

You can't kill a zombie process since it's already dead.

On Unix and Unix-like computer operating systems, a zombie process or
defunct process is a process that has completed execution (via the
exit system call) but still has an entry in the process table: it is a
process in the "Terminated state".

(from Wikipedia)

It's simply an entry in the process table with no associated process. It exists because the spawning (parent) process has yet to collect the return status (via wait()). Other than that it will consume no resources.

So I suspect the parent process is either busy or not working properly. I would first of all try to identify that process (via the PPID column in ps, for example)

EDIT: I note there's a geany issue raised/resolved around this



Related Topics



Leave a reply



Submit