notmuch vs. SIGPIPE
Thomas Schwinge
thomas at codesourcery.com
Mon Jan 20 14:36:51 PST 2020
Hi!
On 2020-01-20T12:55:28+0100, I wrote:
> While looking a bit into the item raised in
> id:87muamgspy.fsf at euler.schwinge.homeip.net I noticed the following
> (mis?)behavior by notmuch.
>
> To set the stage:
>
> $ yes | head -n 1
> y
> $ echo "${PIPESTATUS[@]}"
> 141 0
>
> As expected, the 'yes' process exits with SIGPIPE right after the 'head'
> process terminated.
See also <https://pmhahn.github.io/SIGPIPE/>, for example.
> However:
>
> $ notmuch search \* | head -n 1 & sleep 22; jobs; ps -f
> [1] 622009
> thread:0000000000032bb2 the future [1/1] Jenna Moss; Steve Burbon, Washington (hurd list spam)
> [1]+ Running notmuch search \* | head -n 1 &
> UID PID PPID C STIME TTY TIME CMD
> thomas 621851 4297 0 12:38 pts/38 00:00:00 /bin/bash
> thomas 622008 621851 99 12:48 pts/38 00:00:22 /home/thomas/command/notmuch.real search \*
> thomas 622013 621851 0 12:48 pts/38 00:00:00 ps -f
>
> Even after its "pipe-consumer" 'head' process has terminated, the
> 'notmuch' process still keeps running, and running, and running... It
> has to be killed manually (unless it before exits because of concurrent
> database modification). This doesn't seem expected behavior to me?
>
> Now, I do have a patch or two (actually dozensa; reverts, WIP etc.) on
> top of months-old notmuch sources, so I'll later try to reproduce that
> with clean sources.
$ gdb -q --args notmuch dump
Reading symbols from notmuch...
(gdb) break sigaction
Breakpoint 1 at 0xe130
(gdb) r
Starting program: [...]/notmuch dump
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, __GI___sigaction (sig=13, act=0x0, oact=0x7fffffffd4e0) at ../nptl/sigaction.c:24
24 ../nptl/sigaction.c: No such file or directory.
(gdb) bt
#0 0x00007ffff77e92f0 in __GI___sigaction (sig=13, act=0x0, oact=0x7fffffffd4e0) at ../nptl/sigaction.c:24
#1 0x00007ffff75bfa8d in () at /usr/lib/x86_64-linux-gnu/libgpgme.so.11
#2 0x00007ffff75c64cd in gpgme_check_version () at /usr/lib/x86_64-linux-gnu/libgpgme.so.11
#3 0x00007ffff75c6667 in gpgme_check_version_internal () at /usr/lib/x86_64-linux-gnu/libgpgme.so.11
#4 0x00007ffff7f456b3 in g_mime_init () at /usr/lib/x86_64-linux-gnu/libgmime-3.0.so.0
#5 0x000055555556539d in main (argc=2, argv=0x7fffffffd828) at notmuch.c:469
So, libgpgme via libgmime initialization is doing something with signals.
Here, 'sig=13' is SIGPIPE, 'act=0x0' means to just query, and store
current handling into 'oact':
(gdb) finish
Run till exit from #0 __GI___sigaction (sig=13, act=0x0, oact=0x7fffffffd4e0) at ../nptl/sigaction.c:24
0x00007ffff75bfa8d in ?? () from /usr/lib/x86_64-linux-gnu/libgpgme.so.11
Value returned is $1 = 0
(gdb) print *(struct sigaction *) 0x7fffffffd4e0
$2 = {__sigaction_handler = {sa_handler = 0x0, sa_sigaction = 0x0}, sa_mask = {__val = {0, 8, 93824992565632, 0, 32, 88, 0, 22, 0, 140733193388034, 93823560581120, 7, 93824992559120, 32, 5, 93824992694848}}, sa_flags = 0, sa_restorer = 0x0}
A '0x0' '__sigaction_handler' means 'SIG_DFL', which for SIGPIPE means to
terminate the process. This is as expected. However, then:
(gdb) continue
Continuing.
Breakpoint 1, __GI___sigaction (sig=13, act=0x7fffffffd4e0, oact=0x0) at ../nptl/sigaction.c:24
24 in ../nptl/sigaction.c
(gdb) bt
#0 0x00007ffff77e92f0 in __GI___sigaction (sig=13, act=0x7fffffffd4e0, oact=0x0) at ../nptl/sigaction.c:24
#1 0x00007ffff75bfadc in () at /usr/lib/x86_64-linux-gnu/libgpgme.so.11
#2 0x00007ffff75c64cd in gpgme_check_version () at /usr/lib/x86_64-linux-gnu/libgpgme.so.11
#3 0x00007ffff75c6667 in gpgme_check_version_internal () at /usr/lib/x86_64-linux-gnu/libgpgme.so.11
#4 0x00007ffff7f456b3 in g_mime_init () at /usr/lib/x86_64-linux-gnu/libgmime-3.0.so.0
#5 0x000055555556539d in main (argc=2, argv=0x7fffffffd828) at notmuch.c:469
(gdb) print *act
$3 = {__sigaction_handler = {sa_handler = 0x1, sa_sigaction = 0x1}, sa_mask = {__val = {0 <repeats 16 times>}}, sa_flags = 0, sa_restorer = 0x0}
A '0x1' '__sigaction_handler' means 'SIG_IGN', ignore any such signals.
This is unexpected (to me, at least), not what I'd expect with notmuch?
According to a (very quick) check/survey, this has apparently been the
case "forever", and is documented on
<https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html>,
together with some rationale. Aha, aha, OK, I see.
So, assuming we want to keep it that way (given the gpgme rationale), is
the problem then that we fail to handle appropriately in notmuch any
EPIPE that we may be getting from 'write' etc.? This remains to be
explored another day.
Grüße
Thomas
More information about the notmuch
mailing list