Re: [PATCH v4 4/8] Python QUIT processing updates

Pedro Alves
2023-02-23T12:51:08Z

Hi Kevin,

On 2023-02-20 2:52 a.m., Kevin Buettner wrote:
> On Mon, 30 Jan 2023 19:01:16 +0000
> Pedro Alves <pedro@palves.net> wrote:
>
>> On 2023-01-12 1:56 a.m., Kevin Buettner wrote:
>>> See the previous patches in this series for the motivation behind
>>> these changes.
>>>
>>> This commit contains updates to Python's QUIT handling. Ideally, we'd
>>> like to throw gdb_exception_forced_quit through the extension
>>> language; I made an attempt to do this for gdb_exception_quit in an
>>> earlier version of this patch, but Pedro pointed out that it is
>>> (almost certainly) not safe to do so.
>>>
>>> Still, we definitely don't want to swallow the exception representing
>>> a SIGTERM for GDB, nor do we want to force modules written in the
>>> extension language to have to explicitly handle this case. Since the
>>> idea is for GDB to cleanup and quit for this exception, we'll simply
>>> call quit_force() just as if the gdb_exception_forced_quit propagation
>>> had managed to make it back to the top level.
>>>
>>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=26761
>>
>> I guess this is OK as long as we don't hook up Python at a very low level
>> where running quit_force() would be dangerous.
>>
>> Alternatively, couldn't we force some Python exception/error which
>> is not catch-able from Python code? Set some error flag in the
>> Python interpreter or something, so that it aborts the Python code
>> as soon as we return to the Python interpreter. We'd use the
>> set_quit_flag() trick here where you're calling quit_force (and
>> instead of calling quit_force), so that as soon as we get out of the
>> Python interpreter on the other end, we'd re-raise
>> gdb_exception_forced_quit.
>
> I've looked into doing this, but I haven't found a way to force/throw
> an uncatchable Python error or exception.

Thanks for checking. I was hoping that we could at least do something
like calling something like Py_Finalize() from within a Python callback,
but of course a version of that function that signaled that were bringing
down the interpreter, without causing Python to crash as soon as we're
out of the callback back into Python.

>
> We could define a Python exception, say GDBForcedQuitException, that's
> derived from BaseException, but it can still be caught either via:
>
> try:
> ...
> except GDBForcedQuitException:
> ...
>
> Or:
>
> try:
> ...
> except BaseException:
> ...
>
> Or even:
>
> try:
> ...
> except:
> ...
>
> The latter construct will basically catch everything. This is why
> there are no uncatchable exceptions (or errors) in Python. That said,
> deriving GDBForcedQuitException from BaseException (instead of Exception)
> means that it can't be caught via "except Exception:", which is a catch-all
> for normal exceptions.
>
> I also took a look at calling PyErr_SetInterruptEx (SIGTERM) which
> would simulate the effect of the Python layer receiving a SIGTERM
> signal. For Ctrl-C/SIGINT, We use something similar - a call to
> PyErr_SetInterrupt() which is equivalent to PyErr_SetInterruptEx(SIGINT).
> However, for SIGINT, python defines the default signal handler for
> SIGINT to raise the KeyboardInterrupt exception. However, from my
> reading of the documentation, Python doesn't have a default handler
> for SIGTERM. The documentation says that such signals will be ignored.
>
> Even though it's not uncatchable, it might be worth pursuing your
> idea via an exception derived from BaseException as described above.
> I started looking into this, but doing it looks somewhat involved.
> So, instead of including it in this series, I'd prefer to push this
> commit as-is and work on raising a GDBForcedQuitException in a separate
> series.

Yes, let's do that.

Thanks again for the investigation.