How to tell if a forked process is done?

J

John Lin

Howdy,

I want to know how to tell if a forked process is done.

Actually, my real question is that I want to run a shell script inside
of a python script, and after the shell script has finished running, I
want to do more stuff *condition* on the fact that the shell script
has finished running, inside the same python script.

The only way I can think of is to fork a process and then call the
shell script, as in:
pid = os.fork()
if pid == 0:
os.execl(shellscript_name.sh, "")
but how can I know if the shell script is finished?

In sum, my two questions are:
1. How can I know if a forked shell script is finished?
2. How can I run a shell script inside a python script without
forking a new process, so that I can know the shell script is done
from within the same python script?

thanks in advance,

John
 
N

Nick Welch

You can just do os.system("some command"), it will block until the shell
command is done, and return the exit code. If you need more control,
perhaps look into the popen2 module and the Popen3/4 classes inside it.
 
D

Donn Cave

I want to know how to tell if a forked process is done.

Actually, my real question is that I want to run a shell script inside
of a python script, and after the shell script has finished running, I
want to do more stuff *condition* on the fact that the shell script
has finished running, inside the same python script.

The only way I can think of is to fork a process and then call the
shell script, as in:
pid = os.fork()
if pid == 0:
os.execl(shellscript_name.sh, "")
but how can I know if the shell script is finished?

In sum, my two questions are:
1. How can I know if a forked shell script is finished?
2. How can I run a shell script inside a python script without
forking a new process, so that I can know the shell script is done
from within the same python script?

The simplest way to do what you appear to want is
os.system("shellscript_path")

If any of the command line is actually going to come
from input data, or you have some other reason to prefer
an argument list like exec, see os.spawnv and similar,
with os.P_WAIT as first parameter. Or if your next
question is going to be how to read from a pipe between
the two processes, see os.popen() for starters.

All of these functions will fork a process, but they use
waitpid or some similar function to suspend the calling
process until the fork exits. See man 2 waitpid, which
is available from python as posix.waitpid() or os.waitpid().

Donn Cave, (e-mail address removed)
 
?

=?iso-8859-1?Q?Fran=E7ois?= Pinard

[John Lin]
I want to know how to tell if a forked process is done.

A few people suggested `os.system()' already, and I presume this is what
you want and need.

In the less usual case you want concurrency between Python and the
forked shell command, for only later checking if the forked process is
done, the usual way is to send a zero signal to the child using
`os.kill()'. The zero signal would not do any damage in case your
forked process is still running. But if the process does not exist, the
parent will get an exception for the `os.kill()', which you may
intercept. So you know if the child is running or finished.
 
D

David M. Cooke

At said:
Howdy,

I want to know how to tell if a forked process is done.

Actually, my real question is that I want to run a shell script inside
of a python script, and after the shell script has finished running, I
want to do more stuff *condition* on the fact that the shell script
has finished running, inside the same python script.

The only way I can think of is to fork a process and then call the
shell script, as in:
pid = os.fork()
if pid == 0:
os.execl(shellscript_name.sh, "")
but how can I know if the shell script is finished?

Look up os.wait and os.waitpid in the Python Library Reference. Or,
for this case, use os.system().
 
J

Jules Dubois

On 23 Sep 2003 16:47:40 -0700, in article
The only way I can think of is to fork a process and then call the
shell script, as in:
pid = os.fork()
[...]
In sum, my two questions are:
1. How can I know if a forked shell script is finished?

Under Unix, there's a wait() system call to go along with fork(). I'll bet
Python was something similar.
2. How can I run a shell script inside a python script without
forking a new process, so that I can know the shell script is done
from within the same python script?

Something like system()?
 
K

Klaus Alexander Seistrup

François Pinard said:
In the less usual case you want concurrency between Python and the
forked shell command, for only later checking if the forked process
is done, the usual way is to send a zero signal to the child using
`os.kill()'. The zero signal would not do any damage in case your
forked process is still running. But if the process does not exist,
the parent will get an exception for the `os.kill()', which you may
intercept. So you know if the child is running or finished.

This will yield a false positive and potential damage if the OS has
spawned another process with the same pid, and running under your uid,
as the task you wanted to supervise.


// Klaus

--
 
J

Jeff Epler

os.waitpid() can tell whether a child has exited, and return its status
if so. It can either enter a blocking wait, or it can return
immediately.
pid = os.spawnv(os.P_NOWAIT, "/bin/sleep", ["sleep", "30"])

With WNOHANG, it returns immediately. The returned pid is 0 to show
that the process has not exited yet.(0, 0)

Wait for the process to return. The second number is related to the
exit status and should be managed with os.WEXITSTATUS() etc.(29202, 0)

Waiting again produces a traceback (no danger from another process
created with the same pid)Traceback (most recent call last):
File "<stdin>", line 1, in ?
OSError: [Errno 10] No child processes

If you want to use an argument list instead of an argument string, but
always want to wait for the program to complete, use os.spawn* with
P_WAIT.

Jeff
 
?

=?iso-8859-1?Q?Fran=E7ois?= Pinard

[Klaus Alexander Seistrup]
This will yield a false positive and potential damage if the OS has
spawned another process with the same pid, and running under your uid,
as the task you wanted to supervise.

Granted in theory, yet this does not seem to be considered a real
problem in practice. To generate another process with the same pid, the
system would need to generate so many intermediate processes that the
process counter would overflow and come back to its current value. The
`kill(pid, 0)' trick is still the way people seem to do it.

Do you know anything reasonably simple, safer, and that does the job?
 
C

Christos TZOTZIOY Georgiou

This will yield a false positive and potential damage if the OS has
spawned another process with the same pid, and running under your uid,
as the task you wanted to supervise.

This *could* happen (I have seen 16-bit-pid systems with a couple of
stupid processes spawning children too rapidly), but if you are not root
and you are sure that your own processes do not breed like rabbits, then
you can be almost sure that os.kill(pid, 0) will throw an EPERM if your
child has died.
 
C

Christos TZOTZIOY Georgiou

Granted in theory, yet this does not seem to be considered a real
problem in practice. To generate another process with the same pid, the
system would need to generate so many intermediate processes that the
process counter would overflow and come back to its current value. The
`kill(pid, 0)' trick is still the way people seem to do it.

Do you know anything reasonably simple, safer, and that does the job?

Not that simple: a semaphore.
Not that safe: the existence of a semaphore file.

kill(pid,0) is ok; but a pipe and select would be useful too, safe and
relatively simple (for old Unix programmers at least :).
 
T

Thomas Bellman

François Pinard said:
[Klaus Alexander Seistrup]
This will yield a false positive and potential damage if the OS has
spawned another process with the same pid, and running under your uid,
as the task you wanted to supervise.
Granted in theory, yet this does not seem to be considered a real
problem in practice. To generate another process with the same pid, the
system would need to generate so many intermediate processes that the
process counter would overflow and come back to its current value.

There it least one Unix that reuse process ids immediately when
they are free. A vague memory says that it is AIX that does
this, but I'm not sure; it could be some of the BSD dialects too.

And on most other Unices start to reuse process ids *long* before
they reach 2^31.

However, in this very case, *that* isn't a problem. The process
id won't be free to reuse until the parent has called wait(2) to
reap its child. On the other hand, that means that kill(pid, 0)
won't signal an error even after the child has died; the zombie
is still there...
... child = os.fork()
... if child == 0:
... time.sleep(10)
... print "Exit:", time.ctime()
... os._exit(0)
... else:
... return child
... Traceback (most recent call last):
The
`kill(pid, 0)' trick is still the way people seem to do it.

If they do so when waiting for a child process to exit, they will
have problems...
Do you know anything reasonably simple, safer, and that does the job?

See my .signature. :)
 
D

Donn Cave

....
There it least one Unix that reuse process ids immediately when
they are free. A vague memory says that it is AIX that does
this, but I'm not sure; it could be some of the BSD dialects too.

Not AIX 4 or 5, and no BSD I've seen- cursory inspection suggests
it is not the case with FreeBSD 5.1 nor MacOS X 10.2.6.
However, in this very case, *that* isn't a problem. The process
id won't be free to reuse until the parent has called wait(2) to
reap its child. On the other hand, that means that kill(pid, 0)
won't signal an error even after the child has died; the zombie
is still there...

Good points.

Donn Cave, (e-mail address removed)
 
K

Klaus Alexander Seistrup

François Pinard said:
Do you know anything reasonably simple, safer, and that does the job?

I'd always use fork() + wait() so I know I killing the right process if
I have to kill something. Killing blindly is gambling.


// Klaus

--
 
K

Klaus Alexander Seistrup

Christos said:
if you are not root and you are sure that your own processes
do not breed like rabbits, then you can be almost sure that
os.kill(pid, 0) will throw an EPERM if your child has died.

That's too many ifs to my taste.

Your own processes needn't breed like rabbits - other's processes
can breed like rabbits, too, and if you're unlucky, your next
spawn will have the same pid as a previous process of yours.

Anyway you look at it, killing blindly is bad programming practice.


// Klaus

--
 
C

Christos TZOTZIOY Georgiou

That's too many ifs to my taste.

I agree with that --that's what the 'almost' was about. But...
Your own processes needn't breed like rabbits - other's processes
can breed like rabbits, too, and if you're unlucky, your next
spawn will have the same pid as a previous process of yours.

....here there is a little inconsistency with the flaw of this thread; I
discussed the chance of /another user's process/ using the pid of a
child between two kill(pid,0) attempts, not /another child/, because the
/original point/ was: parent process spawns a single child and then
checks for its existence (see also my mentioning of EPERM). If anybody
mentioned multiple spawning of the parent process, I'm afraid the post
didn't show up in my newsreader. Thus "your next spawn" seems not
relevant.
Anyway you look at it, killing blindly is bad programming practice.

Yes, it is; I have used kill(pid,0) in the past, aware that it's a quick
and dirty solution. Semaphores are much more safe in such a situation.
 
E

Erik Max Francis

Klaus said:
Anyway you look at it, killing blindly is bad programming practice.

But he's killing with a signal of 0. From kill(2):

If sig is 0, then no signal is sent, but error checking is
still performed.

It's perfectly reasonable behavior to kill a process with a 0 signal; it
does no harm.
 
K

Klaus Alexander Seistrup

Christos said:
Thus "your next spawn" seems not relevant.

I beg to differ. By "your next spawn" I'm not talking about spawning
from the current process. It could be a job on a nother terminal, a
cron job etc.
Yes, it is; I have used kill(pid,0) in the past, aware that it's a
quick and dirty solution. Semaphores are much more safe in such a
situation.

I fully agree.


// Klaus

--
 
K

Klaus Alexander Seistrup

Erik said:
But he's killing with a signal of 0. From kill(2):

If sig is 0, then no signal is sent, but error checking is
still performed.

It's perfectly reasonable behavior to kill a process with a 0 signal;
it does no harm.

I overlooked that detail, thanks for correcting me.


// Klaus

--
 
D

Donn Cave

Erik Max Francis said:
But he's killing with a signal of 0. From kill(2):

If sig is 0, then no signal is sent, but error checking is
still performed.

It's perfectly reasonable behavior to kill a process with a 0 signal; it
does no harm.

I think it would be reasonable to posit an implied context
for discussion of any programming technique, that said
technique would be deployed for some purpose.

If that is not too bold of an assumption, I think it follows
that our standard for a good programming practice has to be
a little more stringent that just whether deployment of the
technique causes any harm. In this case, for example, the
proposed technique is use the information returned from kill(0)
to decide whether some process is still alive, and according
to our theory of purposeful programming, we may guess that
the program then acts on the basis of that decision.

If kill(0) actually does not reliably indicate that the process
is alive because process IDs are not unique over time, then
it is arguably harmful as a programming practice even if it
is harmless as a system call.

What actually happens with processes that exited but haven't
been reaped by their parent with wait(2) or similar? Seems
to vary quite a bit, here's what I found -

FreeBSD 5.1 - No such process, ps PID=0, owned by me
Linux 2.4 - kill -0 works
MacOS X/Darwin - No such process, ps original PID, owner root

Donn Cave, (e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top