Re: Converting pqsignal to void return - Mailing list pgsql-hackers

From Andres Freund
Subject Re: Converting pqsignal to void return
Date
Msg-id a33wjek7umo5gjzaj7guyi5qucg4i6ho7to6r7wardtvggpyxu@ddrzklqt5f3x
Whole thread Raw
In response to Converting pqsignal to void return  (Paul Ramsey <pramsey@cleverelephant.ca>)
Responses Re: Converting pqsignal to void return
Re: Converting pqsignal to void return
List pgsql-hackers
Hi,

On 2025-01-22 07:57:52 -0800, Paul Ramsey wrote:
> I just ran across this change when a bunch of CI’s I run barfed.
>
> https://github.com/postgres/postgres/commit/d4a43b283751b23d32bbfa1ecc2cad2d16e3dde9
>
> The problem we are having in extension land is that we often run functions
> in external libraries that take a long time to return, and we would like to
> ensure that PgSQL users can cancel their queries, even when control has
> passed into those functions.
>
> The way we have done it, historically, has been to take the return value of
> pqsignal(SIGINT, extension_signint_handler) and remember it, and then,
> inside extension_signint_handler, call the pgsql handler once we have done
> our own business.

I think that's a really bad idea. For one, postgres might use signals in
different process types for different things. We are also working on not using
plain signals in a bunch of places.

It's also really hard to write correct signal handlers. E.g.:

> https://github.com/pramsey/pgsql-http/blob/master/http.c#L345

That signal handler is profoundly unsafe:

http_interrupt_handler(int sig)
{
    /* Handle the signal here */
    elog(DEBUG2, "http_interrupt_handler: sig=%d", sig);
    http_interrupt_requested = sig;
    pgsql_interrupt_handler(sig);
    return;
}

You're definitely not allowed to elog in a signal handler unless you take
*extraordinary* precautions (basically converting the normal execution path to
only perform async-signal-safe work).

This signal handler can e.g. corrupt the memory context used by elog.c,
deadlock in the libc memory allocator, break the FE/BE protocol if any client
ever set client_min_messages=debug2, jump out of a signal handler in case of
an allocation failure and many other things.



> It is possible we have been Doing It Wrong all this time, and would love some pointers on the right way to do this.

All your interrupt handler is doing "for you" is setting
http_interrupt_requested, right?  Why do you need that variable? Seems you
could just check postgres' QueryCancelPending? And perhaps ProcDiePending, if
you want to handle termination too.

Greetings,

Andres Freund



pgsql-hackers by date:

Previous
From: Alvaro Herrera
Date:
Subject: Re: Quadratic planning time for ordered paths over partitioned tables
Next
From: Alexander Kuzmenkov
Date:
Subject: Re: Quadratic planning time for ordered paths over partitioned tables