Skip to content

Conversation

JohnoKing
Copy link

@JohnoKing JohnoKing commented Jun 16, 2025

Alterations:

  • Bugfix: Don't set the terminal signals to their defaults in the parent prior to calling spawnveg. This is the primary cause of a lockup in the pty tests occurring on Linux distributions using glibc 2.35+. The correct way to go about dealing with SIGT* is to set those to SIG_DFL in the child process; see _sh_fork() for a working example that doesn't lock up or produce segfaults. In this commit I duplicate _sh_fork's behavior in spawnveg for the fork fallback and with POSIX_SPAWN_SETSIGDEF for the posix_spawn version. The lockup can be reproduced as follows:
$ exec ksh
$ bin/shtests pty 2>/dev/null
^C ^C ^C
# (SIGINT doesn't work anymore and may segfault)
  • Added support for tcsetpgrp to the fork fallback in spawnveg. Some form of this appears to have already been attempted in AT&T olden times, but that old version was broken and needed bugfixes desperately.
    • If the child needs tcsetpgrp, block the terminal signals in the parent process via sigcritical(). The posix_spawn version doesn't need this because posix_spawn will usually block signals automatically and therefore doesn't need sigcritical.
  • Now that the fork fallback for spawnveg works correctly in interactive terminals, prefer that to the sh_fork() codepath on operating systems without posix_spawn_file_actions_addtcsetpgrp_np. Even though the underlying system call is still ultimately fork, the sh_ntfork() codepath is faster than the traditional sh_fork() codepath. Benchmark (FreeBSD 14.2):
$ time /tmp/ksh-devbranch -ic "for i in {1..10000}; do $(whence -p true); done"
real       0m03.302s
user       0m00.988s
sys        0m02.320s
$ time /tmp/ksh-newspawnveg -ic "for i in {1..10000}; do $(whence -p true); done"
real       0m03.160s
user       0m01.187s
sys        0m01.977s
  • To that end, split up the spawnveg versions into spawnveg_fast and spawnveg_slow. Choose the appropriate one when spawnveg is called; this removes the need for the xec.c ifdef hackery.
    • Removed the ntfork_tcpgrp ifdefs from xec.c; spawnveg can handle it by itself now.
  • Bugfix: With the spawnveg_fast and spawnveg_slow innovation, spawnveg now always has support for setsid. It'll fallback to fork if POSIX_SPAWN_SETSID isn't available.
  • Bugfix: For the posix_spawn version of spawnveg, the flags should be of the short type pursuant to the POSIX specification.
  • Optimization: Use pipe2 in the fork fallback for spawnveg when it's available to avoid two fcntl syscalls.
  • Updated the spawnveg documentation to reflect the new changes.

Alterations:
- Bugfix: Don't set the terminal signals to their defaults
  in the parent prior to calling spawnveg. This is the primary
  cause of a lockup in the pty tests which can be reproduced
  as follows:
    $ exec ksh
    $ bin/shtests pty 2>/dev/null
    ^C ^C ^C (SIGINT doesn't work anymore and may segfault)
  The correct way to go about dealing with SIGT* is to set
  those to SIG_DFL in the child process; see _sh_fork()
  for a working example that doesn't lock up or produce segfaults.
  In this commit I duplicate _sh_fork()'s behavior in spawnveg
  for the fork fallback and with POSIX_SPAWN_SETSIGDEF for the
  posix_spawn version.
- Added support for tcsetpgrp to the fork fallback in spawnveg.
  Some form of this appears to have already been attempted in
  AT&T olden times, but that old version was broken and needed
  bugfixes desperately.
  - If the child needs tcsetpgrp, block the terminal signals
    in the parent process via sigcritical(). The posix_spawn
    version doesn't need this because posix_spawn will block
    signals automatically and therefore doesn't need sigcritical.
- Now that the fork fallback for spawnveg works correctly in
  interactive terminals, prefer that to the sh_fork() codepath
  on operating systems without posix_spawn tcsetpgrp support.
  Even though the underlying system call is still ultimately fork,
  the sh_ntfork() codepath is faster than the traditional sh_fork
  codepath. Benchmark:
     $ time /tmp/ksh-devbranch -ic "for i in {1..10000}; do $(whence -p true); done"
     real       0m03.302s
     user       0m00.988s
     sys        0m02.320s
     $ time /tmp/ksh-newspawnveg -ic "for i in {1..10000}; do $(whence -p true); done"
     real       0m03.160s
     user       0m01.187s
     sys        0m01.977s
- To that end, split up the spawnveg versions into spawnveg_fast
  and spawnveg_slow. Choose the appropriate one when spawnveg is
  called; this removes the need for the xec.c ifdef hackery.
  - Removed the ntfork_tcpgrp ifdefs from xec.c; spawnveg can
    handle it by itself now.
- Bugfix: With the spawnveg_fast and spawnveg_slow innovation,
  spawnveg now always has support for setsid. It'll fallback to
  fork if POSIX_SPAWN_SETSID isn't available.
- Bugfix: For the posix_spawn version of spawnveg, the flags should
  be of the short type pursuant to the POSIX specification.
- Optimization: Use pipe2 in the fork fallback for spawnveg when
  it's available to avoid two fcntl syscalls.
- Updated the spawnveg documentation to reflect the new changes.
@JohnoKing
Copy link
Author

This pull request has been superseded by #888.

@JohnoKing JohnoKing closed this Jul 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant