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


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

Re: Avoid race condition with Popen.send_signal

Started byCameron Simpson <cs@zip.com.au>
First post2012-01-03 12:44 +1100
Last post2012-01-03 18:25 +0100
Articles 15 — 4 participants

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

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Avoid race condition with Popen.send_signal Cameron Simpson <cs@zip.com.au> - 2012-01-03 12:44 +1100
    Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-02 19:16 -0800
      Re: Avoid race condition with Popen.send_signal Cameron Simpson <cs@zip.com.au> - 2012-01-03 15:53 +1100
        Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-03 06:52 -0800
      Re: Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 09:44 +0100
        Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-03 06:12 -0800
          Re: Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 16:09 +0100
            Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-03 09:58 -0800
              Re: Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 19:45 +0100
      Re: Avoid race condition with Popen.send_signal Chris Angelico <rosuav@gmail.com> - 2012-01-03 19:58 +1100
        Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-03 06:20 -0800
      Re: Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 10:38 +0100
        Re: Avoid race condition with Popen.send_signal Adam Skutt <askutt@gmail.com> - 2012-01-03 07:03 -0800
          Re: Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 17:24 +0100
          Re: Avoid race condition with Popen.send_signal Jérôme <jerome@jolimont.fr> - 2012-01-03 18:25 +0100

#18361 — Re: Avoid race condition with Popen.send_signal

FromCameron Simpson <cs@zip.com.au>
Date2012-01-03 12:44 +1100
SubjectRe: Avoid race condition with Popen.send_signal
Message-ID<mailman.4327.1325555666.27778.python-list@python.org>
On 02Jan2012 20:31, Devin Jeanpierre <jeanpierreda@gmail.com> wrote:
| > I think that catching the exception is probably the most Pythonic way.
| 
| It's the only correct way.

Indeed, but be precise - chek that it _is_ error 3, or more portably,
errno.ESRCH. POSIX probably mandates that that is a 3, but the symbol
should track the local system if it differs. Example:

  import errno
  ...
  try:
    ...signal...
  except OSError, e:
    if e.errno == errno.ESRCH:
      pass      # or maybe an info log message
    else:
      raise     # something else wrong - raise exception anyway

Cheers,
-- 
Cameron Simpson <cs@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/

WHAT"S A ""K3WL D00D"" AND WH3R3 CAN 1 G3T S0M3!!!!!!!!!!!????????
        - Darren Embry

[toc] | [next] | [standalone]


#18367

FromAdam Skutt <askutt@gmail.com>
Date2012-01-02 19:16 -0800
Message-ID<63817f2b-ccf8-4d7d-92a6-c1d622986d8a@j10g2000vbe.googlegroups.com>
In reply to#18361
On Jan 2, 8:44 pm, Cameron Simpson <c...@zip.com.au> wrote:
> On 02Jan2012 20:31, Devin Jeanpierre <jeanpierr...@gmail.com> wrote:
> | > I think that catching the exception is probably the most Pythonic way.
> |
> | It's the only correct way.
>
> Indeed, but be precise - chek that it _is_ error 3, or more portably,
> errno.ESRCH. POSIX probably mandates that that is a 3, but the symbol
> should track the local system if it differs. Example:
>

No. It is possible (however unlikely) for EPERM to be legitimately
returned in this case.  Anything other than EINVAL should be
interpreted as "The child process is dead".  Hence why you should
avoid sending the signal in the first place: the situations where you
don't run the risk of possibly killing an innocent bystander are
pretty narrow.  While unlikely on modern UNiX and Linux, IMO it's best
to avoid the issue altogether whenever possible.

Adam

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


#18370

FromCameron Simpson <cs@zip.com.au>
Date2012-01-03 15:53 +1100
Message-ID<mailman.4329.1325566392.27778.python-list@python.org>
In reply to#18367
On 02Jan2012 19:16, Adam Skutt <askutt@gmail.com> wrote:
| On Jan 2, 8:44 pm, Cameron Simpson <c...@zip.com.au> wrote:
| > On 02Jan2012 20:31, Devin Jeanpierre <jeanpierr...@gmail.com> wrote:
| > | > I think that catching the exception is probably the most Pythonic way.
| > |
| > | It's the only correct way.
| >
| > Indeed, but be precise - chek that it _is_ error 3, or more portably,
| > errno.ESRCH. POSIX probably mandates that that is a 3, but the symbol
| > should track the local system if it differs. Example:
| 
| No. It is possible (however unlikely) for EPERM to be legitimately
| returned in this case.  Anything other than EINVAL should be
| interpreted as "The child process is dead".

Sure. I was more taking the line: catch and accept only the specific
errors you understand. Of course he can catch EPERM also. But any other
variant should at the least generate a warning to stderr or a log -
it is _unexpected_.

I take your point that reraising the exception may be overkill for
failed signal delivery (if that was your point). But I am arguing for
being very careful about what you silently pass as an ok thing.

| Hence why you should
| avoid sending the signal in the first place: the situations where you
| don't run the risk of possibly killing an innocent bystander are
| pretty narrow.  While unlikely on modern UNiX and Linux, IMO it's best
| to avoid the issue altogether whenever possible.

Fair enough too. But sometimes you need to nail a rogue child.

Cheers,
-- 
Cameron Simpson <cs@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/

Death is life's way of telling you you've been fired.   - R. Geis

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


#18413

FromAdam Skutt <askutt@gmail.com>
Date2012-01-03 06:52 -0800
Message-ID<f5c7af9a-8ee2-4dce-8ca7-a7c93d56628b@m4g2000vbc.googlegroups.com>
In reply to#18370
On Jan 2, 11:53 pm, Cameron Simpson <c...@zip.com.au> wrote:
> On 02Jan2012 19:16, Adam Skutt <ask...@gmail.com> wrote:
> | On Jan 2, 8:44 pm, Cameron Simpson <c...@zip.com.au> wrote:
> | > On 02Jan2012 20:31, Devin Jeanpierre <jeanpierr...@gmail.com> wrote:
> | > | > I think that catching the exception is probably the most Pythonic way.
> | > |
> | > | It's the only correct way.
> | >
> | > Indeed, but be precise - chek that it _is_ error 3, or more portably,
> | > errno.ESRCH. POSIX probably mandates that that is a 3, but the symbol
> | > should track the local system if it differs. Example:
> |
> | No. It is possible (however unlikely) for EPERM to be legitimately
> | returned in this case.  Anything other than EINVAL should be
> | interpreted as "The child process is dead".
>
> Sure. I was more taking the line: catch and accept only the specific
> errors you understand.

That advice really only applies when we have interfaces that don't
fully define their exceptional conditions.  That's not the case here.
Though I should correct myself and note that EPERM can only occur if
SIGCHLD is being handled in a non-default fashion.  That being said,
I'm not sure any error code should be treated differently from another
here.

> Of course he can catch EPERM also. But any other
> variant should at the least generate a warning to stderr or a log
> it is _unexpected_.

Are they really unexpected though?  Even if they are, what is logging
an error going to gain anyone?  Even crashing may not be helpful,
especially given that there have been bugs in the past with the return
codes from kill(2).  Certainly, I'd be far more concerned about
ensuring my code doesn't accidentally kill the wrong process than
worrying about ensuring it handles the return code from kill(2)
correctly.

> I take your point that reraising the exception may be overkill for
> failed signal delivery (if that was your point). But I am arguing for
> being very careful about what you silently pass as an ok thing.
>

Trapping too few conditions is just as erroneous as trapping too
many.  This is especially true when dealing with UNIX system calls.
The right behavior is frequently not as simple as it may appear,
unfortunately.

> | Hence why you should
> | avoid sending the signal in the first place: the situations where you
> | don't run the risk of possibly killing an innocent bystander are
> | pretty narrow.  While unlikely on modern UNiX and Linux, IMO it's best
> | to avoid the issue altogether whenever possible.
>
> Fair enough too. But sometimes you need to nail a rogue child.

Even if I believed that were true, I wouldn't use SIGINT to do it.

Adam

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


#18385

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 09:44 +0100
Message-ID<mailman.4339.1325580095.27778.python-list@python.org>
In reply to#18367
Mon, 2 Jan 2012 19:16:50 -0800 (PST)
Adam Skutt a écrit:

> No. It is possible (however unlikely) for EPERM to be legitimately
> returned in this case.  Anything other than EINVAL should be
> interpreted as "The child process is dead".  Hence why you should
> avoid sending the signal in the first place: the situations where you
> don't run the risk of possibly killing an innocent bystander are
> pretty narrow.  While unlikely on modern UNiX and Linux, IMO it's best
> to avoid the issue altogether whenever possible.

Should I understand that Popen.send_signal blindly sends the signal to the
process of PID Popen.pid, and therefore could kill a new process of the same
PID that would have been launched by the same user in another program ?

In other words, if a user launches my python program, which in its turn
launches a subprocess of PID N, then the subprocess dies, then the same user
launches a terminal that gets the same PID (N), what happens if my python
program calls Popen.send_signal(SIGINT) ? Does it kill the terminal ?

If so, I don't see how I can protect myself from that. Checking the process
is alive and then hoping that the time interval for the race condition is so
small that there are few chances for that to happen (because the OS
quarantines PID numbers for a while, for instance) ?

-- 
Jérôme

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


#18408

FromAdam Skutt <askutt@gmail.com>
Date2012-01-03 06:12 -0800
Message-ID<8614ceb1-f31f-4904-b2b9-6ef0d2bc7cdc@m20g2000vbf.googlegroups.com>
In reply to#18385
On Jan 3, 3:44 am, Jérôme <jer...@jolimont.fr> wrote:
> Mon, 2 Jan 2012 19:16:50 -0800 (PST)
> Adam Skutt a écrit:
>
> > No. It is possible (however unlikely) for EPERM to be legitimately
> > returned in this case.  Anything other than EINVAL should be
> > interpreted as "The child process is dead".  Hence why you should
> > avoid sending the signal in the first place: the situations where you
> > don't run the risk of possibly killing an innocent bystander are
> > pretty narrow.  While unlikely on modern UNiX and Linux, IMO it's best
> > to avoid the issue altogether whenever possible.
>
> Should I understand that Popen.send_signal blindly sends the signal to the
> process of PID Popen.pid, and therefore could kill a new process of the same
> PID that would have been launched by the same user in another program ?
>

Or possibly one launched by another user altogether.  By /default/,
child processes that terminate become zombies and remain in that state
until their parent reaps them via wait(2) or a related syscall.  This
means that until you make such a call, the signal is delivered to the
desired child process.  In this case, kill(2) still returns ESRCH
since the child process is a zombie and cannot possibly respond to the
signal.

However, if SIGCHLD has been explicitly ignored or has no SA_NOCLDWAIT
set, child processes are reaped automatically.  Likewise, it is
possible to install a signal handler for SIGCHLD that calls wait and
reaps the child processes.  Do you know what all of your other Python
modules and extensions do? If so, then you can probably rely on the
default semantics.  If not, I'd strongly suggest a more conservative
approach.

Regardless, of whether you can rely on the presence of your zombie
children or not, you should expect the kill(2) call to fail and be
prepared to trap the failure.

Obviously, all of this is rather UNIX / Linux specific.

> If so, I don't see how I can protect myself from that. Checking the process
> is alive and then hoping that the time interval for the race condition is so
> small that there are few chances for that to happen (because the OS
> quarantines PID numbers for a while, for instance) ?

The conservative approach is to use another IPC mechanism to talk to
the process, such as a pipe or a socket.  Why are you trying to send
the child process SIGINT in the first place?

Adam

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


#18412

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 16:09 +0100
Message-ID<mailman.4355.1325603216.27778.python-list@python.org>
In reply to#18408
Tue, 3 Jan 2012 06:12:59 -0800 (PST)
Adam Skutt a écrit:

> The conservative approach is to use another IPC mechanism to talk to
> the process, such as a pipe or a socket.  Why are you trying to send
> the child process SIGINT in the first place?

Say, you've got an application that plays a sound for a few seconds, using an
external program for that (beep, sox). If you close the application, you want
the sound to stop as well.

I don't know much about subprocess, not much more than what is in the
tutorial : http://docs.python.org/library/subprocess.html

(I don't know much about signalling either, I'm learning...)

I naively thought kill() was the "normal" way. Then realized terminate() or
even send_signal(SIGINT) would be softer.

What would be a good approach, then ?

Should I try something like this ?

	communicate(input="Ctrl+C")

(I'd need to figure out how to write Ctrl+C...)

Would that be cross-platform ?

-- 
Jérôme

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


#18425

FromAdam Skutt <askutt@gmail.com>
Date2012-01-03 09:58 -0800
Message-ID<f6cd8985-1d8d-487d-9f5f-02d4b9a42e8e@t16g2000vba.googlegroups.com>
In reply to#18412
On Jan 3, 10:09 am, Jérôme <jer...@jolimont.fr> wrote:
> Tue, 3 Jan 2012 06:12:59 -0800 (PST)
> Adam Skutt a écrit:
>
> > The conservative approach is to use another IPC mechanism to talk to
> > the process, such as a pipe or a socket.  Why are you trying to send
> > the child process SIGINT in the first place?
>
> Say, you've got an application that plays a sound for a few seconds, using an
> external program for that (beep, sox). If you close the application, you want
> the sound to stop as well.

If your application wants to play audio and terminate playing audio
early, it really should use an audio library and play the sound
directly.  Especially if you're playing so many sounds in such a
fashion you need to terminate them.  If you're playing a single beep
or short sound, then who really cares if it occurs slightly after your
processes ends?  GStreamer is one such library for sound processing
though it may be more complicated than you need.

> Should I try something like this ?
>
>         communicate(input="Ctrl+C")
>
> (I'd need to figure out how to write Ctrl+C...)
>
> Would that be cross-platform ?
>

No, that won't work at all.  'Ctrl-C' is a magic indicator to the
terminal driver to send SIGINT to the appropriate processes: it never
actually appears as an input and output character to a program unless
it's controlling the terminal in raw mode (where it loses its special
meaning).  If you're really insistent on using the sox(1) command-line
tools to play your sounds, then you'll have to send SIGINT or SIGTERM
in order to tell it to terminate (which can be done just by calling
the terminate() method).

Which is fine and will probably work OK subject to three restrictions:
1. Nothing in your application modifies the default handling of
SIGCHLD.  This means that the child process appears as a zombie (e.g.,
via 'ps ax') until the parent calls poll() or wait() methods to reap
it.
2. You only send signals while the process is alive or a zombie: once
the poll() or wait() methods  return something other than None, you
cannot safely send anymore signals.
3. You trap any errors returned by the send signal call.

Adam

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


#18429

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 19:45 +0100
Message-ID<mailman.4365.1325616193.27778.python-list@python.org>
In reply to#18425
Tue, 3 Jan 2012 09:58:35 -0800 (PST)
Adam Skutt a écrit:

> If you're really insistent on using the sox(1) command-line tools to play
> your sounds, then you'll have to send SIGINT or SIGTERM in order to tell it
> to terminate (which can be done just by calling the terminate() method).
> 
> Which is fine and will probably work OK subject to three restrictions:
> 1. Nothing in your application modifies the default handling of
> SIGCHLD.  This means that the child process appears as a zombie (e.g.,
> via 'ps ax') until the parent calls poll() or wait() methods to reap
> it.
> 2. You only send signals while the process is alive or a zombie: once
> the poll() or wait() methods  return something other than None, you
> cannot safely send anymore signals.
> 3. You trap any errors returned by the send signal call.

Thank you very much for your patient explanations.

I sort of figured that out from your precedent messages and I was writing
the following :

-----------------------------------------------------------------------

I use poll() in idle task to follow the process's activity, then set a
variable if still in progress.

If I do the signalling in idle task as well, relying on that variable, there
should not be any race condition collateral damage. (If I did not, however, I
could send SIGINT between poll() and the variable being set.)

It just makes the code even heavier with each "stop sound" callback calling
GObject.idle_add() to ask for the work to be done in idle task, instead of
doing it right away.

-----------------------------------------------------------------------

I agree with the fact that ideally I would use another playback library.

The reason of my choice is "historical". This is my first python application.
I started simple and used beep for simplicity. 

Then, as I wanted to use the sound card, I searched for a library (I posted
here about that) and realized playing a sine wave was not that
straightforward. (I tried alsaaudio and had multithreading issues (posted
here as well).) 

As it was not that important to me (after all, it's just an exercise), I
decided to move on and use sox, as invoking it would be quite similar to
calling beep and I had already enough difficulties to face and other
priorities.

I guess I can always change my mind and use an audio library some day but I
was merely interested in the way signalling and processes work.

Thanks again.

-- 
Jérôme

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


#18388

FromChris Angelico <rosuav@gmail.com>
Date2012-01-03 19:58 +1100
Message-ID<mailman.4341.1325581146.27778.python-list@python.org>
In reply to#18367
On Tue, Jan 3, 2012 at 7:44 PM, Jérôme <jerome@jolimont.fr> wrote:
> If so, I don't see how I can protect myself from that. Checking the process
> is alive and then hoping that the time interval for the race condition is so
> small that there are few chances for that to happen (because the OS
> quarantines PID numbers for a while, for instance) ?

The probability is extremely small. PIDs are generally allocated
sequentially, and obviously one won't be reallocated until the
previous process has terminated. You're looking at a narrow window of
opportunity between a check and an action; you don't really need to
worry about PID reuse within that window, unless there's a particular
reason to fear it (eg your process is very low priority, or there's a
lot of "process spinning" happening). Under normal circumstances, you
won't see a new process start up with the same PID for some time.

(I can't make a statement on Python's module, though.)

ChrisA

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


#18410

FromAdam Skutt <askutt@gmail.com>
Date2012-01-03 06:20 -0800
Message-ID<70871926-8a1e-4506-b867-cde96537dcd9@m4g2000vbc.googlegroups.com>
In reply to#18388
On Jan 3, 3:58 am, Chris Angelico <ros...@gmail.com> wrote:
> On Tue, Jan 3, 2012 at 7:44 PM, Jérôme <jer...@jolimont.fr> wrote:
> > If so, I don't see how I can protect myself from that. Checking the process
> > is alive and then hoping that the time interval for the race condition is so
> > small that there are few chances for that to happen (because the OS
> > quarantines PID numbers for a while, for instance) ?
>
> The probability is extremely small. PIDs are generally allocated
> sequentially, and obviously one won't be reallocated until the
> previous process has terminated. You're looking at a narrow window of
> opportunity between a check and an action; you don't really need to
> worry about PID reuse within that window, unless there's a particular
> reason to fear it (eg your process is very low priority, or there's a
> lot of "process spinning" happening). Under normal circumstances, you
> won't see a new process start up with the same PID for some time.
>

Not all operating systems attempt to generate sequential processes
IDs.  The window can be rather large in certain situations, and if you
cannot rely on your child processes becoming zombies and kill being
called only when the child is alive or a zombie, then you should not
be calling kill(2) at all.  Killing an unrelated process will be
considered as a bug by users.  Hence why I find it easier just to
avoid the problem altogether if I can.

Adam

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


#18389

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 10:38 +0100
Message-ID<mailman.4342.1325583331.27778.python-list@python.org>
In reply to#18367
Tue, 3 Jan 2012 19:58:57 +1100
Chris Angelico a écrit:

> On Tue, Jan 3, 2012 at 7:44 PM, Jérôme <jerome@jolimont.fr> wrote:
> > If so, I don't see how I can protect myself from that. Checking the
> > process is alive and then hoping that the time interval for the race
> > condition is so small that there are few chances for that to happen
> > (because the OS quarantines PID numbers for a while, for instance) ?
> 
> The probability is extremely small. PIDs are generally allocated
> sequentially, and obviously one won't be reallocated until the
> previous process has terminated. You're looking at a narrow window of
> opportunity between a check and an action; you don't really need to
> worry about PID reuse within that window, unless there's a particular
> reason to fear it (eg your process is very low priority, or there's a
> lot of "process spinning" happening). Under normal circumstances, you
> won't see a new process start up with the same PID for some time.
> 
> (I can't make a statement on Python's module, though.)

Thanks for clarifying this.

(Out of curiosity, what would be the way to be sure when not in "normal
circumstances" ?)

So I rely on the OS for not allocating a "recently released" PID. However, if
the PID was released long ago, I still need to cover myself up as Popen won't
do it for me.

E.g.:

I have an application that can spawn a subprocess to play a beep. I want it
to kill the subprocess when exiting.

To do so, my close() method must

  a/ Check if any subprocess has actually been launched (I store the Popen in
  a variable called _beep_process. If Popen has not been called, the variable
  is init to 0 and the call to send_signal will fail.)

  b/ Check if the process is still alive using Popen.poll() and returncode
  (otherwise, I might kill a new process)

  c/ Catch the exception in case the process would be dead since the last
  check (otherwise, I might get an error from send_signal)


It looks like this :

    #####################################################################
    # Close
    #####################################################################
    def _close (self, widget):
        # If self._beep_process != 0, a subprocess was launched at some point
        if (0 != self._beep_process):
            print "process launched"
            self._beep_process.poll()
            # If process still alive
            if (None == self._beep_process.returncode):
                print "process stil alive"
            # Send signal
                try:
                    self._beep_process.send_signal(signal.SIGINT)
                except OSError, e:
                    if e.errno == errno.ESRCH:
                        print "process just died"
                        pass      # process already dead
                    else:
                        raise     # something else wrong - raise exception
                else:
                    print "signal sent"
                    # wait for process to complete
                    self._beep_process.wait()
            else:
                print "process already dead"
        # Close application
        Gtk.main_quit()
    #####################################################################

I would have expected something shorter.

For instance, Popen.send_signal() should not be able to send a signal to a
subprocess that has already returned, should it ? Is there any good reason
for allowing it to do so ? If not, it would spare me check b/ in this example.

-- 
Jérôme

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


#18416

FromAdam Skutt <askutt@gmail.com>
Date2012-01-03 07:03 -0800
Message-ID<f677dfce-e286-4366-ba64-3585dc6428c7@p4g2000vbt.googlegroups.com>
In reply to#18389
On Jan 3, 4:38 am, Jérôme <jer...@jolimont.fr> wrote:
> I have an application that can spawn a subprocess to play a beep. I want it
> to kill the subprocess when exiting.

Why?  You shouldn't need to send a signal to tell the process to
terminate: it should terminate when its stdin is closed or when it's
done playing the beep in the first place.  If it doesn't, I would find
a better way to play a beep in the first place.  What you're
attempting to do sounds superfluous and unnecessary.

The only thing you ought to need to do is ensure that the child
process is properly reaped if it terminates before your process
terminates.

> To do so, my close() method must
>
>   a/ Check if any subprocess has actually been launched (I store the Popen in
>   a variable called _beep_process. If Popen has not been called, the variable
>   is init to 0 and the call to send_signal will fail.)
>
>   b/ Check if the process is still alive using Popen.poll() and returncode
>   (otherwise, I might kill a new process)
>
>   c/ Catch the exception in case the process would be dead since the last
>   check (otherwise, I might get an error from send_signal)
>

Steps a and c are all that are necessary under standard SIGCHLD
handling.  However, all of this should be entirely unnecessary in the
first place.  Plus, I have a hard time imagining why something like
'gtk.gdk.beep()' isn't adequate for your needs anyway.

> For instance, Popen.send_signal() should not be able to send a signal to a
> subprocess that has already returned, should it ? Is there any good reason
> for allowing it to do so ? If not, it would spare me check b/ in this example.
>

The problem is being able to distinguish "process is a zombie" from
"process doesn't exist" which both return ESRCH.  This is certainly
possible with careful coding but I'm not sure I would bother except in
the simplest programs.  Too many libraries do too many questionable
things with signal handlers so I find it much safer and easier just to
avoid the damn things whenever possible.

Adam

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


#18421

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 17:24 +0100
Message-ID<mailman.4357.1325607722.27778.python-list@python.org>
In reply to#18416
Tue, 3 Jan 2012 07:03:08 -0800 (PST)
Adam Skutt a écrit:

> On Jan 3, 4:38 am, Jérôme <jer...@jolimont.fr> wrote:
> > I have an application that can spawn a subprocess to play a beep. I want
> > it to kill the subprocess when exiting.
> 
> Why?  You shouldn't need to send a signal to tell the process to
> terminate: it should terminate when its stdin is closed or when it's
> done playing the beep in the first place.  If it doesn't, I would find
> a better way to play a beep in the first place.  What you're
> attempting to do sounds superfluous and unnecessary.

Probably. And somehow, I'd be glad.

Once the command (say beep) is called, it does terminate when done with the
beep. I just don't know if it can be stopped while playing and how.

(Perhaps the only clean way would be to call it several times by period of
10ms, for instance, to be able to stop at any time. But this makes the whole
thing much more complicated.)

> The only thing you ought to need to do is ensure that the child
> process is properly reaped if it terminates before your process
> terminates.

The application polls the ongoing child process until it has terminated, and
fetches its returncode. I hope this is "proper reaping".

The tutorial (http://docs.python.org/library/subprocess.html) didn't suggest
me to do anything more than that.
 
> Steps a and c are all that are necessary under standard SIGCHLD
> handling.  However, all of this should be entirely unnecessary in the
> first place.  

That's good news, because it seems a little bit ugly.

> Plus, I have a hard time imagining why something like 'gtk.gdk.beep()'
> isn't adequate for your needs anyway.

Short answer : I may well be, I just didn't know it.

I just looked at it quickly and it does not seem as flexible. Besides, beep
is just an example, I also use sox. And anyway, the whole thing is just a
training exercise I'm inflicting on myself, so I'm interested in solving the
subprocess issue for itself.

> The problem is being able to distinguish "process is a zombie" from
> "process doesn't exist" which both return ESRCH.  This is certainly
> possible with careful coding but I'm not sure I would bother except in
> the simplest programs.  Too many libraries do too many questionable
> things with signal handlers so I find it much safer and easier just to
> avoid the damn things whenever possible.

My small program _seems to_ work with the dirty hacks I already exposed. Yet,
I'd rather stay on the safe and easy side, especially in a future bigger
program. Therefore, I'm still interested in a better way to proceed.

Is there another way to tell beep (or sox) to stop before the end of the
beep ?

AFAIK, the only way to stop it on console is to feed it Ctrl+C. Should I use
communicate() for that ? How ? Apparently, the following does not work :

	process.communicate("\C-c")

It may well be that the dirtyness of my program comes from the choice of
external applications that don't allow nice termination through stdin. Or
perhaps is it possible and I haven't figured out how yet...

-- 
Jérôme

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


#18422

FromJérôme <jerome@jolimont.fr>
Date2012-01-03 18:25 +0100
Message-ID<mailman.4358.1325611385.27778.python-list@python.org>
In reply to#18416
Tue, 3 Jan 2012 17:24:44 +0100
Jérôme a écrit:

> > Too many libraries do too many questionable things with signal handlers
> > so I find it much safer and easier just to avoid the damn things whenever
> > possible.
> 
> My small program _seems to_ work with the dirty hacks I already exposed.
> Yet, I'd rather stay on the safe and easy side, especially in a future
> bigger program. Therefore, I'm still interested in a better way to proceed.
> 
> Is there another way to tell beep (or sox) to stop before the end of the
> beep ?
> 
> AFAIK, the only way to stop it on console is to feed it Ctrl+C. Should I use
> communicate() for that ? How ? Apparently, the following does not work :
> 
> 	process.communicate("\C-c")
> 

I've been reading more and what I wrote now appears to me as silly, as
Ctrl+C, as I understand, is just a way to send SIGINT...

I guess I'll have to do with the signal handling, then.

But I think I'm beggining to understand what you (Adam Skutt) meant. This is
just as dirty as using Ctrl+C to stop beep when using the console, as opposed
to using a software that would wait for a specific keypress to stop (in which
case I could use communicate()).

-- 
Jérôme

[toc] | [prev] | [standalone]


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


csiph-web