Re: SIGPIPE handling - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: SIGPIPE handling
Date
Msg-id 200311180048.hAI0ms409707@candle.pha.pa.us
Whole thread Raw
In response to Re: SIGPIPE handling  (Manfred Spraul <manfred@colorfullife.com>)
List pgsql-patches
Manfred Spraul wrote:
> Bruce Momjian wrote:
>
> >OK, I know you had a flag for pgbench, and that doesn't use threads.
> >What speedup do you see there?
> >
> >
> Tiny. I added the flag to check that my implementation works, not as a
> benchmark tool.
>
> >I would not expect a library to require me to do something in my code to
> >be thread-safe --- either it is or it isn't.
> >
> The library is thread-safe. Just the SIGPIPE handling differs:
> - single thread: handled by libpq.
> - multi thread: caller must handle SIGPIPE for libpq.
> Rationale: posix is broken. Per-thread signal handling is too ugly to
> think about.

I can accept that we require special code in the app to be thread-safe
_if_ they are installing their own SIGPIPE handler, but I don't think it
is fair to require them to set SIGPIPE ==> SIG_IGN to be thread-safe.

> >Again, let's get it working perfect if they say they are going to use
> >threads with libpq.  Does it work OK if the app doesn't use threading?
> >
> >
> No. pthread_sigmask is part of libpthread - libpq would have to link
> unconditionally against libpthread. Or use __attribute__((weak,
> alias())), but that would only work with gcc.

libpq already links against any thread libraries if you configure
--enable-thread-safety.  If you don't, we don't have to be thread-safe.
My question was whether a non-threaded app handles pthread_sigmask in a
normal way or does it only work when you are running in a thread,
pthread_create()?

> >Does sigpending/sigwait work efficiently for threads?  Another idea is
> >to go with a thread-local storage boolean for each thread, and check
> >that in a signal handler we install.
> >
> I think installing a signal handler is not an option - libpq is a
> library, the signal handler is global.

OK.  My suggestion was to add a libpq C function to register a SIGPIPE
handler.  That way, if they don't call it, we can install our own and
handle it via SIG_IGN (if in send()), or SIG_DFL (if not in send()).

If they install their own, they have to handle ignoring SIGPIPE from
send().  They can use our code as an example.

You say you don't want to install a SIGPIPE signal handler, but we are
requiring code to make SIGPIPE => SIG_IGN to be thread-safe.  That seems
like a pretty strange burden that most threaded apps will not figure out
without a lot of digging.  And if you try to install a custom SIGPIPE
handler in a threaded app, libpq will not even be thread-safe because
their signal handler will be called from send() and they have no way to
determine when to ignore it (coming from send()).  Whatever the
solution, I would like to have something that requires a minimal change
in application code, and works reliably in a threaded app.

On the one hand, you are saying libpq shouldn't install a signal
handler, and in another you are saying you have to set SIGPIPE to
SIG_IGN for the library to be thread-safe.

> >  Seems synchronous signals like
> >SIGPIPE are delivered to the thread that invoked them, and we can check
> >thread-local storage to see if we were in a send() loop at the time of
> >signal delivery.
> >
> >
> IMHO way to fragile.

Why?  We have to do something reasonable?  I don't like requiring
SIGPIPE => SIG_IGN to be thread-safe.

Let's look at our four use cases:

    non-threaded app, no SIGPIPE handler - works fine now
    non-threaded app, custom SIGPIPE handler - works fine now
    threaded app, no SIGPIPE handler - doesn't work
    threaded app, custom SIGPIPE handler - doesn't work

I assume we want to get those last two working without breaking the
earlier ones.  I suppose the main argument to _not_ installing our own
SIGPIPE handler is that it would require special work for non-threaded
apps that want to install their own SIGPIPE handler --- they would have
to install the handler _before_ they open a libpq connection, and they
would have to deal with checking the thread-specific send() boolean in
their signal handler to determine if they should ignore the signal.
That does sound like a mess, and is required in non-threaded apps, which
right now work fine without special checking in the custom SIGPIPE
handler.

I thought someone said that an app shouldn't ignore SIGPIPE everywhere?
What happens if an app does that?  I assume using the app in a unix pipe
case would cause the process not to die when the input pipe is closed or
the output pipe closed.  That seems strange.

I was thinking of using pthread_setspecific() and pthread_getspecific()
around the send() call, and have the SIGPIPE signal handler ignore the
signal if it came from the send() block --- you set/clear the value
before/after send().

Should I try to code up something everyone can look at?

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

pgsql-patches by date:

Previous
From: Andrew Dunstan
Date:
Subject: Re: initdb copyright notice
Next
From: Bruce Momjian
Date:
Subject: Re: initdb copyright notice