Get the status of a specific PID

24,169

Solution 1

You are looking for waitpid which will return status information for a given PID.

For an unrelated process you can use /proc/[pid]/stat in linux and read the output.

Regarding the updated information

There are two scenarios IMO.

First:

The child process is done quickly. Use waitpid (with WNOHANG) and get it's status, then you know how it terminated and that it actually terminated.

Second:

The child process is running. Use waitpid with WNOHANG and check if it is still running. If not do whatever else the parent needs to do, after sufficient time has elapsed, and the child still runs, you can kill it, or do whatever your design sees fit as an appropriate response.

In either way, waitpid is exactly what you need here. The pseudocode just demonstrartes, that you can do other stuff in between and that you don't need to wait 10 seconds even if the child is terminated earlier, bec ause polling like this is not really appropriate.

psuedocode:

 pid_t pid;
 pid = fork();
 while(1)
 {
     if(pid == 0)
     {
         if(status = waitpid(pid, WNOHANG))
         {
             if(status != exited)
             {
                 if(checkExpiryTime() == true)
                    kill(pid, SIGKILL);
                 else
                   sleep(x); // or whatever is appropriate in your case.
             }
         }
     }
     else
     {
          // do childstuff here.
     }
 }

Solution 2

Linux doesn't remove the process descriptor once terminated, because parents could need their info later. Linux only removes them completely when the parent issue a wait()-like system call on it. Normally this is done by its father, but if the process is orphan, it becomes init's child and init eventually issues wait()-like system calls to kill zombie process.

Having said that, until the father issues a wait()-like call, the child's process descriptor is still allocated with EXIT_ZOMBIE status. This is why kill(pid, 0) works ok. It is able to find the process descriptor with pid field.

man 3 exit expands on this further and explains the relationship with wait(2) and with zombies processes.

Regarding to kill(pid, 0). It can be used to figure out if a process exists or don't. But it doesn't tell you if is running or waiting for a parent to issue a wait() system call to sweep it from kernel's memory.

If it exists kill() will return 0. If it doesn't, kill will return -1 with proper errno set (ESRCH). If you fork a process, while the father exists, it's its responsibility to issue a wait() to get their children termination info. If it doesn't, children will be wandering around until father dies.

Want to make sure? Figure out the pid of the child (allegedly) zombie and issue this command:

cat /proc/[pid]/status | grep "State"

It should show a Z for zombie (man 5 proc).

Hope this helps!

Solution 3

If I understand the question - a bit confusing now with all the comments - the solution is pretty straight forward.

  1. establish a signal handler in the parent. The default for SIGCHLD is to ignore it but by setting the handler the signal will be delivered to the parent when the child completes. When it does complete reap it with either wait or waitpid, whichever is really appropriate for your needs. You do not needlessly wait or repeated poll (waitpid) this way.

  2. set a timer (e.g. itimer, timer_create, alarm, etc). If the timer goes off before the child completes, kill it. If the child completes first, shut off the timer. There are obvious (but unavoidable) race conditions but nothing particularly complicated to handle.

Share:
24,169
Achim Schmitz
Author by

Achim Schmitz

Updated on August 15, 2022

Comments

  • Achim Schmitz
    Achim Schmitz over 1 year

    Simple problem but I haven't found an answer, yet. Given a specific PID, can I determine whether that process is active? I'm working on a C program and this is driving me nuts. I read somewhere that kill(pid,0) would do the trick, but this returns 0 regardless of whether the process is running or not (or so it seems).

    Any hints?

    Additional info: The process I'm interested it is a child initiated by a fork(). The child process should terminate when it reaches the statement exit(0). At least that's what I expected... apparently it doesn't.

    Further additional info: The child process that is created with a fork() executes a system command which can be different depending on the end-user. The whole thing is part of a batch process, so there's no chance to jump in and fix something. One of the tasks that this child process may have to perform is to establish a connection to a remote server in order to store some documents there. This might be another Linux machine or it might be a Win Server (or possibly something else). For this reason I don't want to wait for the child process. I would like the parent to wait a specific length of time (say 10 seconds) and then kill the child process if it hasn't completed by then. By the same token, I don't want the parent process to wait 10 seconds if the child completed its task in 3 milliseconds.

    It seems I'm not the first to have this problem.

  • Achim Schmitz
    Achim Schmitz over 10 years
    waitpid() doesn't do the trick, because the calling process then waits for a change of state (or so I understand). I don't want the calling process to possibly wait on one that is hung.
  • Devolus
    Devolus over 10 years
    Did you read the manpage I linked to? That's what you have WNOHANG for, which is described on that page.
  • wildplasser
    wildplasser over 10 years
    waitpid() only works for your child processes, you cannot wait for unrelated processes.
  • Achim Schmitz
    Achim Schmitz over 10 years
    @Devolus: I am familiar with that man page (though I didn't notice your link). The man page states for WNOHANG: return immediately if no child has exited. As I understand it, it means return immediately if it's still running. That's also not what I want. What I really need to know is if the process has stopped yet.
  • Devolus
    Devolus over 10 years
    Wether the child has stopped is shown by waitpid, as there are no stats if the child is still running. As has been pointed out, this works only on child processes though. On thing you might try, is to attach via ptrace and see if the process does something, but of course it requires the privileges. Other than that, what do you expect would be a status of a process if it is still in progress?
  • Achim Schmitz
    Achim Schmitz over 10 years
    This is getting a bit too complex for a comment, so please see the additional info I'm putting into the original question. Thanks for your efforts, to date.
  • Paulo Bu
    Paulo Bu over 10 years
    @AchimSchmitz please, have you checked my answer? You probably find it useful.
  • Devolus
    Devolus over 10 years
    So it IS a child anyway, in which case waitpid would be appropriate to use. It seems that you may have a wrong expectation on what it means when a process is 'active', so it would be helpfull to clarify what you are actually expecting to see. If the child is not exiting, it is doing "something" and if you want to know what that is you may have to resort to ptrace or look in the /proc fileystem to see if the child is still doing something.
  • Devolus
    Devolus over 10 years
    If the process is a zombie, then it means it already is exited, and in that case waitpid on the child will return it's exit status. As has been said, the process has not exited, so I suspect that the poster wants to somehow observe the process and see if it hangs somewhere.
  • Paulo Bu
    Paulo Bu over 10 years
    But OP said he doesn't want to wait() for the child doesn't he?
  • Achim Schmitz
    Achim Schmitz over 10 years
    @Paulo Bu: your answer only just now popped onto my screen. I'm having trouble keeping up with all the comments. :-)
  • Devolus
    Devolus over 10 years
    He wants to, he just doesn't know it. :)
  • Achim Schmitz
    Achim Schmitz over 10 years
    I'm going to try a combination like ´waitpid(pid,&status,WNOHANG | WIFEXITED(0))´ and see what that does. Jeez, I've been doing C programming for all of 3 months. What have I gotten myself into?
  • Paulo Bu
    Paulo Bu over 10 years
    @AchimSchmitz you're dealing here with system calls and processes. Not just C programming. Although simple, this demand a little OS knowledge :) Cheer up!
  • Achim Schmitz
    Achim Schmitz over 10 years
    I'm only griping, because I have to do this in C... these sort of issues don't crop up in Java or perl. But I'll keep at it. Thanks for the help.
  • Achim Schmitz
    Achim Schmitz over 10 years
    This is more or less how I did do it in the end. See answer below.
  • Duck
    Duck over 10 years
    Honestly Achim, this doesn't appear to make sense or answer your own question. The parent looping is awful but worse is the child. You originally said you wanted to execute system commands via the child - whether through the system function or the exec family was unstated - this won't work for that. If exec is used your child code will be overlaid - no chance to kill. If system, which spawns another shell and runs the command, what happens when said command runs too long? You still won't be able to kill it.
  • Achim Schmitz
    Achim Schmitz over 10 years
    Some more helpful insights and some elegant examples are to be found at cs.rutgers.edu/~pxk/416/notes/c-tutorials/signal.html
  • Achim Schmitz
    Achim Schmitz over 10 years
    Hmm... that system() spawns a new shell had not occurred to me. I guess I'll have to work on it some more. for the simple case I've used to test this on, it works, though. Besides, what's wrong with the loop? Of cousrse I don't want to print anything like in this example when it comes to the real thing.
  • Achim Schmitz
    Achim Schmitz over 10 years
    I have a working solution now. It still won't satisfy those who seek elegance in their programming but when you have a deadline: GWWW (Go with what works). The change is not major. The new version uses exec() to call an external process after the fork(). This has the same pid as the child process created by fork().
  • Duck
    Duck over 10 years
    exec is definitely a step in right direction -system is about as cheesy and dangerous as it comes - and I can appreciate that you have a deadline but what you have done will only work with child programs that are hardwired to make it work. If I get a chance later today I'll post something better for you.
  • Duck
    Duck over 10 years
    Achem, I added a second answer.
  • vonbrand
    vonbrand about 10 years
    waitpid(3) onlŷ works for child processes. It can't be used to find out about unrelated processes. Use '/proc/<pid>' on Linux (and many other Unices).
  • Mark Lakata
    Mark Lakata about 9 years
    waitpid takes 3 arguments. On top of that, in the example, pid == 0. I think the example needs to change logic to be pid != 0, and call changed to waitpid(pid,0, WNOHANG)