Bug 246385 - SIGCHLD dropped if generated while blocked in sigfastblock
Summary: SIGCHLD dropped if generated while blocked in sigfastblock
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-05-11 19:56 UTC by corydoras
Modified: 2020-05-13 06:42 UTC (History)
5 users (show)

See Also:


Attachments
reduced test case, see description for how to compile (1.94 KB, text/plain)
2020-05-11 19:56 UTC, corydoras
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description corydoras 2020-05-11 19:56:54 UTC
Created attachment 214394 [details]
reduced test case, see description for how to compile

fish-shell is observing a hang under FreeBSD CURRENT which I believe to be a regression in FreeBSD signal handling, relative to 12.1.

Originally reported as https://github.com/fish-shell/fish-shell/issues/6919

High level: if a process forks and the child exits before fork is complete in the parent, then SIGCHLD will not be delivered.

Details: fork() will block signals using sigfastblock. If the child dies before signals are unblocked, the SIGCHLD will be marked as pending via the sigfastblock word. In this case fork() will issue a syscall to `sigfastblock(SIGFASTBLOCK_UNBLOCK)`; however SIGCHLD will NOT be delivered.

Reduced test case attached as `demo.c`. This test case uses a loop which creates a child and waits for SIGCHLD to be delivered via the self-pipe trick. It counts every 256 iterations.

To reproduce:

    clang demo.c ; ./a.out # this does not hang
    
    clang -lpthread demo.c ; ./a.out # this hangs on FreeBSD CURRENT only


ktrace output:

Good iteration (SIGCHLD generated while signals NOT blocked):
 27181 a.out    CALL  fork
 27181 a.out    RET   fork 27581/0x6bbd
 27181 a.out    CALL  read(0x3,0x7fffffffe8e0,0x200)
 27181 a.out    RET   read RESTART
 27181 a.out    PSIG  SIGCHLD caught handler=0x800258dd0 mask=0x0 code=CLD_EXITED
 27181 a.out    CALL  sigprocmask(SIG_SETMASK,0x7fffffffe24c,0)
 27181 a.out    RET   sigprocmask 0
 27181 a.out    CALL  write(0x4,0x7fffffffde6b,0x1)
 27181 a.out    GIO   fd 4 wrote 1 byte
 27181 a.out    RET   write 1
 27181 a.out    CALL  sigreturn(0x7fffffffde80)
 27181 a.out    RET   sigreturn JUSTRETURN
 27181 a.out    CALL  read(0x3,0x7fffffffe8e0,0x200)
 27181 a.out    GIO   fd 3 read 1 byte


Hanging iteration (SIGCHLD generated while signals ARE blocked):

 27181 a.out    RET   read 1
 27181 a.out    CALL  wait4(0x6bbd,0x7fffffffe8d4,0x6<WUNTRACED|WCONTINUED>,0)
 27181 a.out    RET   wait4 27581/0x6bbd
 27181 a.out    CALL  fork
 27181 a.out    RET   fork 27582/0x6bbe
 27181 a.out    CALL  sigfastblock(0x2,0)
 27181 a.out    RET   sigfastblock 0
 27181 a.out    CALL  read(0x3,0x7fffffffe8e0,0x200)

Note the call to sigfastblock(0x2) (pending signal) but PSIG  SIGCHLD is not generated.
Comment 1 commit-hook freebsd_committer freebsd_triage 2020-05-11 22:38:50 UTC
A commit references this bug:

Author: kib
Date: Mon May 11 22:38:32 UTC 2020
New revision: 360940
URL: https://svnweb.freebsd.org/changeset/base/360940

Log:
  sigfastblock: fix delivery of the pending signals in single-threaded processes.

  If single-threaded process receives a signal during critical section
  established by sigfastblock(2) word, unblock did not caused signal
  delivery because sigfastblock(SIGFASTBLOCK_UNBLOCK) failed to request
  ast handling of the pending signals.

  Set TDF_ASTPENDING | TDF_NEEDSIGCHK on unblock or when kernel forces
  end of sigfastblock critical section, to cause syscall exit to recheck
  and deliver any signal pending.

  Reported by:	corydoras@ridiculousfish.com
  PR:	246385
  Sponsored by:	The FreeBSD Foundation

Changes:
  head/sys/kern/kern_sig.c
Comment 2 Alan Somers freebsd_committer freebsd_triage 2020-05-11 22:40:28 UTC
Wow, fast work Kib!  Does this change need to be MFCed?
Comment 3 Conrad Meyer freebsd_committer freebsd_triage 2020-05-11 22:41:33 UTC
I don't believe fastblock is in any stable/.
Comment 4 commit-hook freebsd_committer freebsd_triage 2020-05-13 06:42:14 UTC
A commit references this bug:

Author: pho
Date: Wed May 13 06:41:42 UTC 2020
New revision: 361003
URL: https://svnweb.freebsd.org/changeset/base/361003

Log:
  Added a regression test.

  PR:		246385

Changes:
  user/pho/stress2/misc/sigfastblock2.sh