os.system vs os.system inside thread -> why is there any difference?

P

przemas_r

Hello everybody.

I've found python's behaviour I can't understand. Namely the way
os.system () works depending if it's being run in Thread's run function
or run in 'normal' way.
ARPING 192.168.0.2 from 62.233.239.115 eth1
Sent 1 probes (1 broadcast(s))
Received 0 response(s)
256
Here as you can see, arping command quits sending packets after 1 second
and outputs failure (Received 0 response(s)) information.

Now the same thing, but running from thread:
.... def __init__ (self):
.... threading.Thread.__init__ (self)
.... def run (self):
.... os.system ('arping -w 1 -c 1 -I eth1 192.168.0.2')
....<lots of time and nothing happens>

Now, although the only difference is that command arping is being run in
thread, command never quits, informing about it's failure (-w 1 switch
means that it should quit in 1 second). Mistery.

Please help me if you know what's going on.
 
J

Jeff Epler

On POSIX systems, Python blocks the delivery of signals to threads, and
installs a 'pthread_atfork' handler to restore the default behavior when
fork() is called, because otherwise it leads to weird behavior in
programs started with fork+exec.

In the case of arping, I suspect the of the SIGALRM signal remains
blocked, and arping waits forever for either the signal or the return
packet.

On Linux, at least, system() never calls the pthread_atfork
handler, and the redhat maintainers have made it clear that they believe
this behavior is allowed by the Open Group unix specification.

Here's an entry-point into a python-dev thread on the subject:
http://mail.python.org/pipermail/python-dev/2003-December/041311.html
with links to the Open Group specification and the closed redhat bug.

I suggest you write a replacement for system() in terms of fork + exec
and then you should get the behavior you want.

I continue to believe this is a redhat or glibc bug but my opinion
doesn't seem to matter.

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFBm6T9Jd01MZaTXX0RAlAbAKCHMzLtJJ73ycAEkcumPFD0bhtlOgCdF/V8
QD7ZNaLYeO0rId0JDZtFqik=
=bdEp
-----END PGP SIGNATURE-----
 
P

przemas_r

Thanks for the answer.
I've rewritten my code to use fork and exec calls instead of system
call, but it still works only if run outside a thread. Here is the snippet:

def ipState (self, ip):
if os.fork () == 0:
command = 'arping -f -w %s -c %s -I %s %s' % (self.wait,
self.count, self.iface, ip)
os.execvp ('arping', command.split ())
os._exit ()
else:
status = os.wait () [1] & 0xff
print status

Changing start () to run () at the point where thread class is created
and started (and thus running in main proccess instead) will cause the
arping command to run properly. So the problem remains the same.
 
J

Jeff Epler

Thanks for the answer.

You're welcome. I'm sorry it didn't work out.

I wrote a pair of standalone programs (no need for arping) to check this
behavior. The bad news is that my program failed on 2.2.2 and 2.3.2.
It only succeed on a CVS version of Python 2.4b2.

To run the test, "python prz.py". It should print "0" twice, because
each time "alarmed.py" should exit from within the SIGALRM signal
handler. On 2.2 and 2.3, it prints "0" (works in the main thread) then
"1" (doesn't work in another thread)

Jeff

Subprogram "alarmed.py":
#------------------------------------------------------------------------
#!/usr/bin/python
import signal, time, sys, os
signal.signal(signal.SIGALRM, lambda *args: sys.exit(0))
os.kill(os.getpid(), signal.SIGALRM)
sys.exit(1)
#------------------------------------------------------------------------

Main program "prz.py":
#------------------------------------------------------------------------
import threading
import os
import signal

def system(s):
p = os.fork()
if p == 0:
os.execvp("/bin/sh", ['sh', '-c', s])
os._exit(99)
else:
p, status = os.waitpid(p, 0);
return os.WEXITSTATUS(status)

class T(threading.Thread):
def run(self):
print system("python alarmed.py")

t = T()
t.run()

t = T()
t.start()
t.join()
#------------------------------------------------------------------------

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFBnLGnJd01MZaTXX0RAiORAJ9EYMNVONRtRNy2Tw0UiggOw/hUiQCgkzz8
qZwK8VJTpTrPgTGN5Ru0Qok=
=DRf1
-----END PGP SIGNATURE-----
 
P

przemas_r

I've tested the code you sent. Obviously the result was the one, you
reffered to as python 2.2.2 or 2.3.2 specific.
Ok, so it's high time I switched to new 2.4.x release.

Thanks again for clarifying me this issue.


Jeff said:
Thanks for the answer.


You're welcome. I'm sorry it didn't work out.

I wrote a pair of standalone programs (no need for arping) to check this
behavior. The bad news is that my program failed on 2.2.2 and 2.3.2.
It only succeed on a CVS version of Python 2.4b2.

To run the test, "python prz.py". It should print "0" twice, because
each time "alarmed.py" should exit from within the SIGALRM signal
handler. On 2.2 and 2.3, it prints "0" (works in the main thread) then
"1" (doesn't work in another thread)

Jeff

Subprogram "alarmed.py":
#------------------------------------------------------------------------
#!/usr/bin/python
import signal, time, sys, os
signal.signal(signal.SIGALRM, lambda *args: sys.exit(0))
os.kill(os.getpid(), signal.SIGALRM)
sys.exit(1)
#------------------------------------------------------------------------

Main program "prz.py":
#------------------------------------------------------------------------
import threading
import os
import signal

def system(s):
p = os.fork()
if p == 0:
os.execvp("/bin/sh", ['sh', '-c', s])
os._exit(99)
else:
p, status = os.waitpid(p, 0);
return os.WEXITSTATUS(status)

class T(threading.Thread):
def run(self):
print system("python alarmed.py")

t = T()
t.run()

t = T()
t.start()
t.join()
#------------------------------------------------------------------------
 

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

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top