Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #18355 > unrolled thread

Avoid race condition with Popen.send_signal

Started byJérôme <jerome@jolimont.fr>
First post2012-01-03 00:09 +0100
Last post2012-01-03 14:56 +0100
Articles 5 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 00:09 +0100
    Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-02 17:19 -0800
      Re: Avoid race condition with Popen.send_signal Heiko Wundram <modelnine@modelnine.org> - 2012-01-03 13:31 +0100
        Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-03 05:40 -0800
          Re: Avoid race condition with Popen.send_signal Heiko Wundram <modelnine@modelnine.org> - 2012-01-03 14:56 +0100

#18355 — Avoid race condition with Popen.send_signal

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 00:09 +0100
SubjectAvoid race condition with Popen.send_signal
Message-ID<mailman.4323.1325545598.27778.python-list@python.org>
Hi all.

When a subprocess is running, it can be sent a signal with the send_signal
method :

process = Popen( args)
process.send_signal(signal.SIGINT)

If the SIGINT is sent while the process has already finished, an error is
raised : 

  File "/usr/lib/python2.7/subprocess.py", line 1457, in send_signal
    os.kill(self.pid, sig)
OSError: [Errno 3] Aucun processus de ce type

To avoid this, I can check that the process is still alive :

process = Popen( args)
process.poll()
if (None == process.returncode):
    process.send_signal(signal.SIGINT)

It makes safer, but there is still an issue if the process ends between
poll() and send_signal().

What is the clean way to avoid this race condition ?

Should I use try/except to catch the error or is there a more elegant way to
go ?

Thanks.

-- 
Jérôme

[toc] | [next] | [standalone]


#18358

FromAdam Skutt <askutt@gmail.com>
Date2012-01-02 17:19 -0800
Message-ID<e2f96c71-544b-451e-9797-4d6b04438e6a@z17g2000vbe.googlegroups.com>
In reply to#18355
On Jan 2, 6:09 pm, Jérôme <jer...@jolimont.fr> wrote:
> Hi all.
>
> When a subprocess is running, it can be sent a signal with the send_signal
> method :
>
> process = Popen( args)
> process.send_signal(signal.SIGINT)
>
> If the SIGINT is sent while the process has already finished, an error is
> raised :
>
>   File "/usr/lib/python2.7/subprocess.py", line 1457, in send_signal
>     os.kill(self.pid, sig)
> OSError: [Errno 3] Aucun processus de ce type
>
> To avoid this, I can check that the process is still alive :
>
> process = Popen( args)
> process.poll()
> if (None == process.returncode):
>     process.send_signal(signal.SIGINT)
>
> It makes safer, but there is still an issue if the process ends between
> poll() and send_signal().
>
> What is the clean way to avoid this race condition ?

The fundamental race condition cannot be removed nor avoided. Ideally,
avoid the need to send the subprocess a signal in the first place.  If
it cannot be avoided, then trap the exception.

Adam

[toc] | [prev] | [next] | [standalone]


#18398

FromHeiko Wundram <modelnine@modelnine.org>
Date2012-01-03 13:31 +0100
Message-ID<mailman.4348.1325593922.27778.python-list@python.org>
In reply to#18358
Am 03.01.2012 02:19, schrieb Adam Skutt:
> On Jan 2, 6:09 pm, Jérôme<jer...@jolimont.fr>  wrote:
>> What is the clean way to avoid this race condition ?
>
> The fundamental race condition cannot be removed nor avoided. Ideally,
> avoid the need to send the subprocess a signal in the first place.  If
> it cannot be avoided, then trap the exception.

Yes, it can be avoided, that's what the default SIGCHLD-handling 
(keeping the process as a zombie until it's explicitly collected by a 
wait*()) is for, which forces the PID not to be reused by the operating 
system until the parent has acknowledged (by actively calling wait*()) 
that the child has terminated.

-- 
--- Heiko.

[toc] | [prev] | [next] | [standalone]


#18403

FromAdam Skutt <askutt@gmail.com>
Date2012-01-03 05:40 -0800
Message-ID<abf618bc-83d7-4f4b-b889-63e1ce4c42fa@y7g2000vbe.googlegroups.com>
In reply to#18398
On Jan 3, 7:31 am, Heiko Wundram <modeln...@modelnine.org> wrote:
> Am 03.01.2012 02:19, schrieb Adam Skutt:
>
> > On Jan 2, 6:09 pm, Jérôme<jer...@jolimont.fr>  wrote:
> >> What is the clean way to avoid this race condition ?
>
> > The fundamental race condition cannot be removed nor avoided. Ideally,
> > avoid the need to send the subprocess a signal in the first place.  If
> > it cannot be avoided, then trap the exception.
>
> Yes, it can be avoided, that's what the default SIGCHLD-handling
> (keeping the process as a zombie until it's explicitly collected by a
> wait*()) is for, which forces the PID not to be reused by the operating
> system until the parent has acknowledged (by actively calling wait*())
> that the child has terminated.

No, you still can see ESRCH when sending signals to a zombie process.
Code that sends signals to child processes via kill(2) must be
prepared for the call to fail at anytime since the process can die at
anytime.  It can't handle the signal, so it's treated as if it doesn't
exist by kill(2) in this case.  However, you don't have to worry about
sending the signal to the wrong process.

Adam

[toc] | [prev] | [next] | [standalone]


#18405

FromHeiko Wundram <modelnine@modelnine.org>
Date2012-01-03 14:56 +0100
Message-ID<mailman.4352.1325599015.27778.python-list@python.org>
In reply to#18403
Am 03.01.2012 14:40, schrieb Adam Skutt:
> On Jan 3, 7:31 am, Heiko Wundram<modeln...@modelnine.org>  wrote:
>> Yes, it can be avoided, that's what the default SIGCHLD-handling
>> (keeping the process as a zombie until it's explicitly collected by a
>> wait*()) is for, which forces the PID not to be reused by the operating
>> system until the parent has acknowledged (by actively calling wait*())
>> that the child has terminated.
>
> No, you still can see ESRCH when sending signals to a zombie process.
> Code that sends signals to child processes via kill(2) must be
> prepared for the call to fail at anytime since the process can die at
> anytime.  It can't handle the signal, so it's treated as if it doesn't
> exist by kill(2) in this case.  However, you don't have to worry about
> sending the signal to the wrong process.

Getting an error on kill (which you can catch) is not about the race 
that the posters were speculating about (i.e., sending the signal to the 
wrong process), and that's what I was trying to put straight. The only 
advice that I wanted to give is:

1) before calling wait to collect the child, call kill as much as you 
like, and in case it errors, ignore that,

2) after calling wait, never, ever kill, and you don't need to, because 
you already know the process is gone.

There's no race possibility in this, _except_ if you alter handling of 
SIGCHLD away from the default (i.e., to autocollect children), in which 
case you have the possibility of a race and shooting down unrelated 
processes (which the discussion was about).

-- 
--- Heiko.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web