Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2020-06-17 Thread 'Jonathan Kliem' via sage-devel
As we are doing the IPython update now, I thought of this thing again and I 
totally forgot how complex this is.

One way to solve this, is to cancel any alarm after evaluating input. That 
should solve the problem, but I have no idea if this is acceptable or not.

I didn't find a way to see, if an alarm is scheduled (it would be nicer if 
one could actually raise the correct error "alarm escaped interact").

Am Donnerstag, 7. Februar 2019 17:23:18 UTC+1 schrieb E. Madison Bray:
>
> On Thu, Feb 7, 2019 at 5:05 PM E. Madison Bray  > wrote: 
> > 
> > On Thu, Feb 7, 2019 at 4:53 PM Jeroen Demeyer  > wrote: 
> > > 
> > > On 2019-02-07 16:45, E. Madison Bray wrote: 
> > > > Apparently Jeroen argued about this with the IPython developers some 
> > > > time ago: https://github.com/ipython/ipython/pull/9867 
> > > 
> > > Indeed. Your post did seem familiar to me, but I actually forgot about 
> > > that discussion. 
> > 
> > FWIW we are on a rather old prompt_toolkit (1.0.9), whereas the 
> > current version is 2.0.7.  Newer versions of IPython have also 
> > upgraded to depend on prompt_toolkit >= 2.0.  It's possible then that 
> > this situation has been improved already, but I am not sure.  Sage 
> > still uses IPython 5.x since it is an LTS release. 
>
> Alas, I tried IPython 7 in a virtualenv and the situation is no 
> better.  The logic for handling the KeyboardInterrupt isn't even 
> right: It catches the KeyboardInterrupt, then calls 
> self._eventloop.stop(), but then rather than break out of IPython's 
> mainloop function it just continues the loop and tries to call 
> self.interact() with a no longer functioning prompt, and then crashes. 
> As a bonus, leaving my terminal in an extremely broken state. 
>
> This stuff is hard to get right, but still, no bueno... :( 
>

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sage-devel/d5e5eede-c9a9-4fe1-a858-f7c7b1d0b6f1o%40googlegroups.com.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread E. Madison Bray
On Thu, Feb 7, 2019 at 5:05 PM E. Madison Bray  wrote:
>
> On Thu, Feb 7, 2019 at 4:53 PM Jeroen Demeyer  wrote:
> >
> > On 2019-02-07 16:45, E. Madison Bray wrote:
> > > Apparently Jeroen argued about this with the IPython developers some
> > > time ago: https://github.com/ipython/ipython/pull/9867
> >
> > Indeed. Your post did seem familiar to me, but I actually forgot about
> > that discussion.
>
> FWIW we are on a rather old prompt_toolkit (1.0.9), whereas the
> current version is 2.0.7.  Newer versions of IPython have also
> upgraded to depend on prompt_toolkit >= 2.0.  It's possible then that
> this situation has been improved already, but I am not sure.  Sage
> still uses IPython 5.x since it is an LTS release.

Alas, I tried IPython 7 in a virtualenv and the situation is no
better.  The logic for handling the KeyboardInterrupt isn't even
right: It catches the KeyboardInterrupt, then calls
self._eventloop.stop(), but then rather than break out of IPython's
mainloop function it just continues the loop and tries to call
self.interact() with a no longer functioning prompt, and then crashes.
As a bonus, leaving my terminal in an extremely broken state.

This stuff is hard to get right, but still, no bueno... :(

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread E. Madison Bray
On Thu, Feb 7, 2019 at 4:53 PM Jeroen Demeyer  wrote:
>
> On 2019-02-07 16:45, E. Madison Bray wrote:
> > Apparently Jeroen argued about this with the IPython developers some
> > time ago: https://github.com/ipython/ipython/pull/9867
>
> Indeed. Your post did seem familiar to me, but I actually forgot about
> that discussion.

FWIW we are on a rather old prompt_toolkit (1.0.9), whereas the
current version is 2.0.7.  Newer versions of IPython have also
upgraded to depend on prompt_toolkit >= 2.0.  It's possible then that
this situation has been improved already, but I am not sure.  Sage
still uses IPython 5.x since it is an LTS release.

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread Jeroen Demeyer

On 2019-02-06 20:52, Nils Bruin wrote:

This is the same as in python:

 >>> import signal
 >>> signal.alarm(1)
0
 >>> Alarm clock

It looks like this is just the default signal handler for python (the
one that just prints the signal name and exits)


For the record, that message "Alarm clock" is printed by the shell (bash 
or whatever) whenever a process that it runs (python in this case) is 
killed by a signal. It's analogous to the more familiar message 
"Segmentation Fault".


--
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread Jeroen Demeyer

On 2019-02-07 16:45, E. Madison Bray wrote:

Apparently Jeroen argued about this with the IPython developers some
time ago: https://github.com/ipython/ipython/pull/9867


Indeed. Your post did seem familiar to me, but I actually forgot about 
that discussion.


--
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread E. Madison Bray
On Thu, Feb 7, 2019 at 4:14 PM E. Madison Bray  wrote:
>
> On Thu, Feb 7, 2019 at 4:13 PM E. Madison Bray  wrote:
> >
> > On Wed, Feb 6, 2019 at 8:52 PM Nils Bruin  wrote:
> > >
> > > On Wednesday, February 6, 2019 at 6:35:27 AM UTC-8, E. Madison Bray wrote:
> > >>
> > >>
> > >> Which is being reached because AlarmInterrupt is a subclass of
> > >> KeyboardInterrupt .   I don't know why this doesn't happen then when,
> > >> say, mashing Ctrl-C.  I guess because IPython installs its own SIGINT
> > >> handler or something.
> > >
> > >
> > > In IPython proper the behaviour is different:
> > >
> > >
> > > In [1]: import signal
> > >
> > > In [2]: signal.alarm(1)
> > > Out[2]: 0
> > >
> > > In [3]: Alarm clock
> > > 
> > >
> > > This is the same as in python:
> > >
> > > >>> import signal
> > > >>> signal.alarm(1)
> > > 0
> > > >>> Alarm clock
> > >
> > > It looks like this is just the default signal handler for python (the one 
> > > that just prints the signal name and exits)
> > >
> > > Note that cysignals.signals.AlarmInterrupt is our own invention, so if 
> > > the problem is inheriting from KeyboardInterrupt, we should probably not 
> > > do that.
> >
> > IIRC there is a good rationale for that, though I don't see it
> > explicitly documented anywhere.  I think it's simply that in most code
> > where you would want to catch an AlarmInterrupt (i.e. you set an alarm
> > on some code that should not be allowed to run for more than a certain
> > amount of time), you would also likely want to break out of it
> > manually with a Ctrl-C, and you would want those two cases handled the
> > same. So you kill two birds with one stone this way, rather than
> > having to write `except (AlarmInterrupt, KeyboardInterrupt)`.  In
> > other words, the AlarmInterrupt is treated sort of as an automatic
> > KeyboardInterrupt on a timer.
> >
> > This can be avoided of course by explicitly writing `except
> > (AlarmInterrupt, KeyboardInterrupt)`, but I do like the existing
> > design on principle.  I think in this case its better to address the
> > specific problem.  I find it odd that IPython would allow an interrupt
> > arising from user code to break out of its event loop.  It seems to
> > happen in the case of code being run via signal handlers, because if I
> > just enter `raise KeyboardInterrupt` at the prompt, this happens:
> >
> > sage: raise KeyboardInterrupt
> > ---
> > KeyboardInterrupt Traceback (most recent call last)
> >  in ()
> > > 1 raise KeyboardInterrupt
> >
> > KeyboardInterrupt:
> >
> > So, no problem.  But I can reproduce the problem with Sage's alarm()
> > using pure Python+stdlib like:
> >
> > sage: import signal
> > sage: def raise_keyboard_interrupt(*args):
> > : raise KeyboardInterrupt
> > :
> > sage: signal.signal(signal.SIGALRM, raise_keyboard_interrupt)
> > 0
> > sage: signal.alarm(1)
> > 0
>
> Forgot to paste the rest of this example.  Point being it does the same thing:
>
>
> sage: import signal
> sage: def raise_keyboard_interrupt(*args):
> : raise KeyboardInterrupt
> :
> sage: signal.signal(signal.SIGALRM, raise_keyboard_interrupt)
> 0
> sage: signal.alarm(1)
> 0
> sage:
>
> KeyboardInterrupt escaped interact()
>
> sage:
> sage:
> ^[[41;1R
> **
>
> Oops, Sage crashed. We do our best to make it stable, but...

Apparently Jeroen argued about this with the IPython developers some
time ago: https://github.com/ipython/ipython/pull/9867

Part of the justification on their end seems to have more to do with
prompt_toolkit, and the fact that if it is interrupted in some random
state by an exception raised from a signal handler, it cannot recover
to a sane state. I'm still not sure I totally buy that explanation
though.

Normally when you're sitting at the IPython prompt they prevent you
from breaking out of the prompt because using prompt_toolkit they
completely override the input handling for Ctrl-C so that it no longer
sends the process a SIGINT and instead just clears the prompt.

This is only true when you're sitting at the prompt though.  Once
you're running some Python code it restores normal input handling--you
can Ctrl-C and break out of that code just fine.  It's *just* when
sitting at the prompt waiting for input that it blows up.  I can even
reproduce this simply by externally sending the process a `kill
-SIGINT` while it's sitting at the prompt.

This seems unreasonable to me.  Even the plain readline-based Python
REPL handles this just fine.  It just prints "KeyboardInterrupt" and
displays a new prompt.  Surely it must be possible, rather than making
prompt-toolkit just completely shut down, to reset its state and
display a new prompt?  If its state is so fragile that one
interruption to its event loop is impossible to recover from that
suggests that it wasn't well designed (and I don't think that's the

Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread E. Madison Bray
On Thu, Feb 7, 2019 at 4:13 PM E. Madison Bray  wrote:
>
> On Wed, Feb 6, 2019 at 8:52 PM Nils Bruin  wrote:
> >
> > On Wednesday, February 6, 2019 at 6:35:27 AM UTC-8, E. Madison Bray wrote:
> >>
> >>
> >> Which is being reached because AlarmInterrupt is a subclass of
> >> KeyboardInterrupt .   I don't know why this doesn't happen then when,
> >> say, mashing Ctrl-C.  I guess because IPython installs its own SIGINT
> >> handler or something.
> >
> >
> > In IPython proper the behaviour is different:
> >
> >
> > In [1]: import signal
> >
> > In [2]: signal.alarm(1)
> > Out[2]: 0
> >
> > In [3]: Alarm clock
> > 
> >
> > This is the same as in python:
> >
> > >>> import signal
> > >>> signal.alarm(1)
> > 0
> > >>> Alarm clock
> >
> > It looks like this is just the default signal handler for python (the one 
> > that just prints the signal name and exits)
> >
> > Note that cysignals.signals.AlarmInterrupt is our own invention, so if the 
> > problem is inheriting from KeyboardInterrupt, we should probably not do 
> > that.
>
> IIRC there is a good rationale for that, though I don't see it
> explicitly documented anywhere.  I think it's simply that in most code
> where you would want to catch an AlarmInterrupt (i.e. you set an alarm
> on some code that should not be allowed to run for more than a certain
> amount of time), you would also likely want to break out of it
> manually with a Ctrl-C, and you would want those two cases handled the
> same. So you kill two birds with one stone this way, rather than
> having to write `except (AlarmInterrupt, KeyboardInterrupt)`.  In
> other words, the AlarmInterrupt is treated sort of as an automatic
> KeyboardInterrupt on a timer.
>
> This can be avoided of course by explicitly writing `except
> (AlarmInterrupt, KeyboardInterrupt)`, but I do like the existing
> design on principle.  I think in this case its better to address the
> specific problem.  I find it odd that IPython would allow an interrupt
> arising from user code to break out of its event loop.  It seems to
> happen in the case of code being run via signal handlers, because if I
> just enter `raise KeyboardInterrupt` at the prompt, this happens:
>
> sage: raise KeyboardInterrupt
> ---
> KeyboardInterrupt Traceback (most recent call last)
>  in ()
> > 1 raise KeyboardInterrupt
>
> KeyboardInterrupt:
>
> So, no problem.  But I can reproduce the problem with Sage's alarm()
> using pure Python+stdlib like:
>
> sage: import signal
> sage: def raise_keyboard_interrupt(*args):
> : raise KeyboardInterrupt
> :
> sage: signal.signal(signal.SIGALRM, raise_keyboard_interrupt)
> 0
> sage: signal.alarm(1)
> 0

Forgot to paste the rest of this example.  Point being it does the same thing:


sage: import signal
sage: def raise_keyboard_interrupt(*args):
: raise KeyboardInterrupt
:
sage: signal.signal(signal.SIGALRM, raise_keyboard_interrupt)
0
sage: signal.alarm(1)
0
sage:

KeyboardInterrupt escaped interact()

sage:
sage:
^[[41;1R
**

Oops, Sage crashed. We do our best to make it stable, but...

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-07 Thread E. Madison Bray
On Wed, Feb 6, 2019 at 8:52 PM Nils Bruin  wrote:
>
> On Wednesday, February 6, 2019 at 6:35:27 AM UTC-8, E. Madison Bray wrote:
>>
>>
>> Which is being reached because AlarmInterrupt is a subclass of
>> KeyboardInterrupt .   I don't know why this doesn't happen then when,
>> say, mashing Ctrl-C.  I guess because IPython installs its own SIGINT
>> handler or something.
>
>
> In IPython proper the behaviour is different:
>
>
> In [1]: import signal
>
> In [2]: signal.alarm(1)
> Out[2]: 0
>
> In [3]: Alarm clock
> 
>
> This is the same as in python:
>
> >>> import signal
> >>> signal.alarm(1)
> 0
> >>> Alarm clock
>
> It looks like this is just the default signal handler for python (the one 
> that just prints the signal name and exits)
>
> Note that cysignals.signals.AlarmInterrupt is our own invention, so if the 
> problem is inheriting from KeyboardInterrupt, we should probably not do that.

IIRC there is a good rationale for that, though I don't see it
explicitly documented anywhere.  I think it's simply that in most code
where you would want to catch an AlarmInterrupt (i.e. you set an alarm
on some code that should not be allowed to run for more than a certain
amount of time), you would also likely want to break out of it
manually with a Ctrl-C, and you would want those two cases handled the
same. So you kill two birds with one stone this way, rather than
having to write `except (AlarmInterrupt, KeyboardInterrupt)`.  In
other words, the AlarmInterrupt is treated sort of as an automatic
KeyboardInterrupt on a timer.

This can be avoided of course by explicitly writing `except
(AlarmInterrupt, KeyboardInterrupt)`, but I do like the existing
design on principle.  I think in this case its better to address the
specific problem.  I find it odd that IPython would allow an interrupt
arising from user code to break out of its event loop.  It seems to
happen in the case of code being run via signal handlers, because if I
just enter `raise KeyboardInterrupt` at the prompt, this happens:

sage: raise KeyboardInterrupt
---
KeyboardInterrupt Traceback (most recent call last)
 in ()
> 1 raise KeyboardInterrupt

KeyboardInterrupt:

So, no problem.  But I can reproduce the problem with Sage's alarm()
using pure Python+stdlib like:

sage: import signal
sage: def raise_keyboard_interrupt(*args):
: raise KeyboardInterrupt
:
sage: signal.signal(signal.SIGALRM, raise_keyboard_interrupt)
0
sage: signal.alarm(1)
0

I'm just not entirely user that the KeyboardInterrupt handling in
IPython is entirely well considered here.

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-06 Thread Nils Bruin
On Wednesday, February 6, 2019 at 6:35:27 AM UTC-8, E. Madison Bray wrote:
>
>
> Which is being reached because AlarmInterrupt is a subclass of 
> KeyboardInterrupt .   I don't know why this doesn't happen then when, 
> say, mashing Ctrl-C.  I guess because IPython installs its own SIGINT 
> handler or something. 
>

In IPython proper the behaviour is different:


In [1]: import signal

In [2]: signal.alarm(1)
Out[2]: 0

In [3]: Alarm clock


This is the same as in python:

>>> import signal
>>> signal.alarm(1)
0
>>> Alarm clock

It looks like this is just the default signal handler for python (the one 
that just prints the signal name and exits)

Note that cysignals.signals.AlarmInterrupt is our own invention, so if the 
problem is inheriting from KeyboardInterrupt, we should probably not do 
that.

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.


Re: [sage-devel] AlarmInterrupt causes Sage to crash hard

2019-02-06 Thread E. Madison Bray
On Wed, Feb 6, 2019 at 10:29 AM jonathan.kliem via sage-devel
 wrote:
>
> sage: alarm(1)
> sage:
>
> AlarmInterrupt escaped interact()
>
> sage:
> sage:
> ^[[50;1R
> **
>
> Oops, Sage crashed. We do our best to make it stable, but...
>
> ...
>
> Is this supposed to happen?

I think obviously not :)

I can confirm the same.  It's not clear how long this has been the
case--it looks to me like a bug/oddity in IPython?

The exception is originating from IPython.terminal.interactiveshell
which contains the following:

def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
# An extra layer of protection in case someone mashing Ctrl-C breaks
# out of our internal code.
if display_banner is not DISPLAY_BANNER_DEPRECATED:
warn('mainloop `display_banner` argument is deprecated
since IPython 5.0. Call `show_banner()` if needed.',
DeprecationWarning, stacklevel=2)
while True:
try:
self.interact()
break
except KeyboardInterrupt as e:
print("\n%s escaped interact()\n" % type(e).__name__)
finally:
# An interrupt during the eventloop will mess up the
# internal state of the prompt_toolkit library.
# Stopping the eventloop fixes this, see
# https://github.com/ipython/ipython/pull/9867
if hasattr(self, '_eventloop'):
self._eventloop.stop()

Which is being reached because AlarmInterrupt is a subclass of
KeyboardInterrupt .   I don't know why this doesn't happen then when,
say, mashing Ctrl-C.  I guess because IPython installs its own SIGINT
handler or something.

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.