Get the status of a specific PID
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.
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 eitherwait
orwaitpid
, whichever is really appropriate for your needs. You do not needlesslywait
or repeated poll (waitpid
) this way.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.
Achim Schmitz
Updated on August 15, 2022Comments
-
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 statementexit(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 over 10 yearswaitpid() 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 over 10 yearsDid you read the manpage I linked to? That's what you have WNOHANG for, which is described on that page.
-
wildplasser over 10 yearswaitpid() only works for your child processes, you cannot wait for unrelated processes.
-
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 over 10 yearsWether 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 over 10 yearsThis 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 over 10 years@AchimSchmitz please, have you checked my answer? You probably find it useful.
-
Devolus over 10 yearsSo 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 over 10 yearsIf 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 over 10 yearsBut OP said he doesn't want to
wait()
for the child doesn't he? -
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 over 10 yearsHe wants to, he just doesn't know it. :)
-
Achim Schmitz over 10 yearsI'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 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 over 10 yearsI'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 over 10 yearsThis is more or less how I did do it in the end. See answer below.
-
Duck over 10 yearsHonestly 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 theexec
family was unstated - this won't work for that. Ifexec
is used your child code will be overlaid - no chance tokill
. Ifsystem
, 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 over 10 yearsSome more helpful insights and some elegant examples are to be found at cs.rutgers.edu/~pxk/416/notes/c-tutorials/signal.html
-
Achim Schmitz over 10 yearsHmm... 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 over 10 yearsI 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 thefork().
This has the same pid as the child process created byfork().
-
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 over 10 yearsAchem, I added a second answer.
-
vonbrand about 10 yearswaitpid(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 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 bepid != 0
, and call changed towaitpid(pid,0, WNOHANG)