Hi,

Thomas, added you to To for the last paragraph.


On 2026-02-19 11:55:20 +0200, Heikki Linnakangas wrote:
> On 19/02/2026 11:25, Heikki Linnakangas wrote:
> > On 19/02/2026 09:21, Kirill Reshke wrote:
> > > On Thu, 19 Feb 2026 at 02:50, Andres Freund <[email protected]> wrote:
> > > > I don't think die() should call ereport() without being in
> > > > single user mode. I
> > > > guess there's a corner case though, which is that the signal handler is
> > > > executed during exit processing, when we already reset
> > > > whereToSendOutput.  I
> > > > think we probably should make sure this stuff is only reached in
> > > > actual single
> > > > user mode.
> >
> > +1
>
> Attached is a quick patch for that.
>
> At first I considered replacing the "if (DoingCommandRead &&
> whereToSendOutput != DestRemote)" check with "if (DoingCommandRead &&
> whereToSendOutput == DestDebug)".

I had been wondering about !IsUnderPostmaster...


> That would be the minimal change to fix the confusion when a regular backend
> is exiting. But I think it's better to make this exception as narrow as
> possible in general. We only need the exit from the signal handler while
> we're in the middle of the uninterruptible getc(), not for any longer.

What if the client is printing out a lot of data and is stuck in something
like this:

#0  __GI__IO_fwrite (buf=0x7ffcc56b3f70, size=1, count=61, fp=0x7fa4765285c0 
<_IO_2_1_stdout_>) at ./libio/iofwrite.c:32
#1  0x0000000000dd31fb in flushbuffer (target=0x7ffcc56b4370) at 
../../../../../home/andres/src/postgresql/src/port/snprintf.c:310
#2  0x0000000000dd2ff3 in pg_vfprintf (stream=0x7fa4765285c0 <_IO_2_1_stdout_>,
    fmt=0x1003f30 "\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval 
= %c)\n", args=0x7ffcc56b43c0)
    at ../../../../../home/andres/src/postgresql/src/port/snprintf.c:259
#3  0x0000000000dd3193 in pg_printf (fmt=0x1003f30 "\t%2d: %s%s%s%s\t(typeid = 
%u, len = %d, typmod = %d, byval = %c)\n")
    at ../../../../../home/andres/src/postgresql/src/port/snprintf.c:288
#4  0x000000000061c5fe in printatt (attributeId=1, attributeP=0xe1554d0, 
value=0x0)
    at 
../../../../../home/andres/src/postgresql/src/backend/access/common/printtup.c:428
#5  0x000000000061c657 in debugStartup (self=0x15eace0 <debugtupDR>, 
operation=1, typeinfo=0xe1554a8)
    at 
../../../../../home/andres/src/postgresql/src/backend/access/common/printtup.c:454
#6  0x00000000008a3182 in standard_ExecutorRun (queryDesc=0xe145c10, 
direction=ForwardScanDirection, count=0)
    at 
../../../../../home/andres/src/postgresql/src/backend/executor/execMain.c:351
#7  0x00000000008a3008 in ExecutorRun (queryDesc=0xe145c10, 
direction=ForwardScanDirection, count=0)
    at 
../../../../../home/andres/src/postgresql/src/backend/executor/execMain.c:303
#8  0x0000000000b82699 in PortalRunSelect (portal=0xdfe68f0, forward=true, 
count=0, dest=0x15eace0 <debugtupDR>)
    at ../../../../../home/andres/src/postgresql/src/backend/tcop/pquery.c:916
#9  0x0000000000b822f0 in PortalRun (portal=0xdfe68f0, 
count=9223372036854775807, isTopLevel=true, dest=0x15eace0 <debugtupDR>,
    altdest=0x15eace0 <debugtupDR>, qc=0x7ffcc56b47a0) at 
../../../../../home/andres/src/postgresql/src/backend/tcop/pquery.c:760
#10 0x0000000000b7a66b in exec_simple_query (query_string=0xe143160 "select 
1;\n")
    at 
../../../../../home/andres/src/postgresql/src/backend/tcop/postgres.c:1277
#11 0x0000000000b80302 in PostgresMain (dbname=0xdf9fb80 "postgres", 
username=0xdf1e520 "andres")
    at 
../../../../../home/andres/src/postgresql/src/backend/tcop/postgres.c:4812
#12 0x0000000000b7f596 in PostgresSingleUserMain (argc=135, argv=0xdf17810, 
username=0xdf1e520 "andres")
    at 
../../../../../home/andres/src/postgresql/src/backend/tcop/postgres.c:4214
#13 0x000000000093edbf in main (argc=135, argv=0xdf17810) at 
../../../../../home/andres/src/postgresql/src/backend/main/main.c:227




> > So that is pretty well-defined, and we could use poll() on stdin too.
>
> That said, WaitLatchOrSocket() et al. currently assume that the fd is a
> socket rather than a pipe or a file. It might work the same on most
> platforms, but I wonder about Windows. So it could be done, but it might
> require changes to waiteventset.c, which  might not be worth the trouble
> just for single-user mode.

It'd be nice to support pipes, but the last time I looked at it, it'd be
rather hard on windows. From what I understand windows only supports
completion based IO for pipes, there's no support at all for readiness based
interfaces.  Which in turn doesn't mesh very well with portable assumptions
that can be make on other systems.

IIUC IPC::Run does some really nasty gymnastics to make pipes work
transparently-ish on windows (something like a proxy subprocess that then
executes the piped command, allowing perl to communicate with the proxy
process via a readiness supporting socket connection).


> Hmm, how do we do this for pipes in COPY? If waiteventset supported pipes,
> would it be useful for COPY too ?

I wonder if the PROGRAM is properly interruptible on windows right now? I
think we just rely on SIGINT on a process group reaching subprocesses, which
then terminates the executed program, stopping being blocked on the
program. But on windows there's no process groups IIRC.

So yes, proper pipe support would be rather useful.

Another place it'd be really useful for is the startup process, what we do
there right now to react immediately to signals is quite nasty.

I think Thomas did some work around this?


Greetings,

Andres Freund


Reply via email to