kernel - sigblockall()/sigunblockall() support (per thread shared page)
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 12 Nov 2019 01:06:55 +0000 (17:06 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 12 Nov 2019 01:06:55 +0000 (17:06 -0800)
commit64b5a8a550c3c782ab04d04d63723691ac054ffc
tree9ee4fe2a6eb376a27791c02c56e60e0d1bcb5cdb
parent722c3b8b6376deab9407ff00b5e63018ab3aef0b
kernel - sigblockall()/sigunblockall() support (per thread shared page)

* Implement /dev/lpmap, a per-thread RW shared page between userland
  and the kernel.  Each thread in the process will receive a unique
  shared page for communication with the kernel when memory-mapping
  /dev/lpmap and can access varous variables via this map.

* The current thread's TID is retained for both fork() and vfork().
  Previously it was only retained for vfork().  This avoids userland
  code confusion for any bits and pieces that are indexed based on the
  TID.

* Implement support for a per-thread block-all-signals feature that
  does not require any system calls (see next commit to libc).  The
  functions will be called sigblockall() and sigunblockall().

  The lpmap->blockallsigs variable prevents normal signals from being
  dispatched.  They will still be queued to the LWP as per normal.
  The behavior is not quite that of a signal mask when dealing with
  global signals.

  The low 31 bits represents a recursion counter, allowing recursive
  use of the functions.  The high bit (bit 31) is set by the kernel
  if a signal was prevented from being dispatched.  When userland decrements
  the counter to 0 (the low 31 bits), it can check and clear bit 31 and
  if found to be set userland can then make a dummy 'real' system call
  to cause pending signals to be delivered.

  Synchronous TRAPs (e.g. kernel-generated SIGFPE, SIGSEGV, etc) are not
  affected by this feature and will still be dispatched synchronously.

* PThreads is expected to unmap the mapped page upon thread exit.
  The kernel will force-unmap the page upon thread exit if pthreads
  does not.

  XXX needs work - currently if the page has not been faulted in
  the kernel has no visbility into the mapping and will not unmap it,
  but neither will it get confused if the address is accessed.  To
  be fixed soon.  Because if we don't, programs using LWP primitives
  instead of pthreads might not realize that libc has mapped the page.

* The TID is reset to 1 on a successful exec*()

* On [v]fork(), if lpmap exists for the current thread, the kernel will
  copy the lpmap->blockallsigs value to the lpmap for the new thread
  in the new process.  This way sigblock*() state is retained across
  the [v]fork().

  This feature not only reduces code confusion in userland, it also
  allows [v]fork() to be implemented by the userland program in a way
  that ensures no signal races in either the parent or the new child
  process until it is ready for them.

* The implementation leverages our vm_map_backing extents by having
  the per-thread memory mappings indexed within the lwp.  This allows
  the lwp to remove the mappings when it exits (since not doing so
  would result in a wild pmap entry and kernel memory disclosure).

* The implementation currently delays instantiation of the mapped
  page(s) and some side structures until the first fault.

  XXX this will have to be changed.
22 files changed:
sys/kern/imgact_aout.c
sys/kern/imgact_elf.c
sys/kern/init_main.c
sys/kern/kern_exec.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/kern_memio.c
sys/kern/kern_proc.c
sys/kern/kern_sig.c
sys/kern/kern_slaballoc.c
sys/platform/pc64/x86_64/efirt.c
sys/sys/device.h
sys/sys/proc.h
sys/sys/signal.h
sys/sys/signal2.h
sys/sys/signalvar.h
sys/sys/upmap.h
sys/vm/vm_fault.c
sys/vm/vm_kern.c
sys/vm/vm_map.c
sys/vm/vm_map.h
sys/vm/vm_mmap.c