Question

I have to kill/clean a zombie process in linux C. All I know is the PID of the zombie.

I'm creating a few zombie processes in a loop:

int i = 0;
for (i; i<5; i++)
{
  system("(: & exec sleep 30) &"); // create zombie for 30 sec
}

I can get their PID number using:

system("ps aux | awk '{ print $8 " " $2 }' | grep -w Z");

But how to kill/clean them using just the PID? I'm saving the PID in a variable and standard signal:

kill(PID,9) 

Doesn't even work, because the process is dead already. Any other way to achieve it? Please don't ask me why the hell I'm creating zombies to kill them later. It's not the case.

Was it helpful?

Solution

Here is a script I created to kill ALL zombie processes. It uses the GDB debugger to attach to the parent process and send a waitpid to kill the zombie process. This will leave the parent live and only slay the zombie.

GDB debugger will need to be installed and you will need to be logged in with permissions to attach to a process. This has been tested on Centos 6.3

#!/bin/bash
##################################################################
# Script: Zombie Slayer
# Author: Mitch Milner
# Date:   03/13/2013 ---> A good day to slay zombies
#
# Requirements: yum install gdb
#               permissions to attach to the parent process
#
# This script works by using a debugger to
# attach to the parent process and then issuing
# a waitpid to the dead zombie. This will not kill
# the living parent process.
##################################################################

clear
# Wait for user input to proceed, give user a chance to cancel script
echo "***********************************************************"
echo -e "This script will terminate all zombie process."
echo -e "Press [ENTER] to continue or [CTRL] + C to cancel:"
echo "***********************************************************"
read cmd_string
echo -e "\n"

# initialize variables
intcount=0
lastparentid=0

# remove old gdb command file
rm -f /tmp/zombie_slayer.txt

# create the gdb command file
echo "***********************************************************"
echo "Creating command file..."
echo "***********************************************************"
ps -e -o ppid,pid,stat,command | grep Z | sort | while read LINE; do
  intcount=$((intcount+1))
  parentid=`echo $LINE | awk '{print $1}'`
  zombieid=`echo $LINE | awk '{print $2}'`
  verifyzombie=`echo $LINE | awk '{print $3}'`

  # make sure this is a zombie file and we are not getting a Z from
  # the command field of the ps -e -o ppid,pid,stat,command
  if [ "$verifyzombie" == "Z" ]
  then
    if [ "$parentid" != "$lastparentid" ]
    then
      if [ "$lastparentid" != "0" ]
      then
        echo "detach" >> /tmp/zombie_slayer.txt
      fi
    echo "attach $parentid" >> /tmp/zombie_slayer.txt
    fi
    echo "call waitpid ($zombieid,0,0)" >> /tmp/zombie_slayer.txt
    echo "Logging: Parent: $parentid  Zombie: $zombieid"
    lastparentid=$parentid
  fi
done
if [ "$lastparentid" != "0" ]
then
  echo "detach" >> /tmp/zombie_slayer.txt
fi

# Slay the zombies with gdb and the created command file
echo -e "\n\n"
echo "***********************************************************"
echo "Slaying zombie processes..."
echo "***********************************************************"
gdb -batch -x /tmp/zombie_slayer.txt
echo -e "\n\n"
echo "***********************************************************"
echo "Script complete."
echo "***********************************************************"

Enjoy.

OTHER TIPS

A "zombie" is a process that is already dead. You can't kill it again.

A "zombie" is actually just an entry in the process table containing the exit status of the process. To get rid of it, the parent process has to call wait() to retrieve that information. Alternatively the parent process can exit itself; then the child becomes a so called "orphan" and gets adopted by init, the process with ID 1. init automatically reaps all dead children.

You're correct that you can't kill zombies because they're already dead.

The reason they're zombies is because the process has finished but the parent has not harvested the exit code.

Eventually, init should do this for you if and when the zombie becomes an orphan. A true zombie, a process that still has a parent but that parent has yet to harvest the exit code, will persist until either:

  • the parent does harvest the exit code; or
  • it becomes an orphan when the parent exits.

What you are doing seems quite twisted. I am going to assume you have tried to create a minimal test case to show a broader problem and answer anyway - A zombie is created when a feather process does not clean (calls waitpid and friends) its child process resources.

So, either write the father process code correctly to respond to SIGCHLD and calling waitpid or, if you have no control over the father process, as I am guessing is the case here, kill the father process (send SIGTERM to the father).

The reason the latter will work is that all fatherless children are re-parented to init (PID 1) that will perform the needed clean up.

You can try using the SIGCHLD signal.For eg in C:

signal(SIGCHLD, handleSIGCHLD);


  void handleSIGCHLD(int signum) {
  int stat;

 /*Kills all the zombie processes*/
  while(waitpid(-1, &stat, WNOHANG) > 0);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top