Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a few things to make $&waiting more flexible. #149

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

jpco
Copy link
Collaborator

@jpco jpco commented Dec 1, 2024

This PR adds a few things:

First, an -n flag for wait, which corresponds with waitpid(WNOHANG). This can be used to implement a check-wait function during %prompt, something some shells do automatically.

To support that use case, there is a new hook function %echo-status, which is called when any process is ewait()ed for, and performs the work of printing the "interesting" signal terminations. A default implementation is provided which should be the same as the current behavior. A quick-and-dirty way to hack on this function is to simply set fn-%echo-status = echo to see how every process exits:

; fn-%echo-status = echo
; cat /usr/share/dict/words | head -5 | wc -c
18
32920 exited 0
32919 exited 0
32918 signaled sigpipe

To make a backwards-compatible %echo-status possible, this PR also adds a new $&sigmessage primitive which externalizes the sigmessage() function. This seems generally useful for signal exception handlers as well; the %interactive-loop function has been modified to use this primitive.

; echo $pid 
34157
; echo $signals 
.sigint /sigquit /sigterm sigpoll sigurg
; # here we run some kills in another terminal
; caught unexpected signal: sigpoll: pollable event occurred
; caught unexpected signal: sigurg: urgent condition on i/o channel

Putting these all together, the following enables the "check-wait" behavior on prompt like in other, job controlling shells:

fn check-wait {
  local (
    fn %echo-status pid did status {
      if {~ $did signaled} {
        echo >[1=2] $pid terminated on signal: <={$&sigmessage $status}
      } {
        echo >[1=2] $pid exited with status $status
      }
    }
  ) $&wait -n
}

let (p = $fn-%prompt)
fn %prompt {
  check-wait
  $p
}

@jpco
Copy link
Collaborator Author

jpco commented Dec 2, 2024

Some caveats/potential alternatives:

  • Bikeshedding welcome. %echo-status has been renamed twice already!
  • %echo-status could be called directly from %pipe, %background, %run (with Use the %run hook function for running binaries. #90), wait, etc., instead of being built-in to every single ewait(), including things like backquotes and heredocs. (actually, %here doesn't ewait() when it should -- $&here leaks child processes #150 -- and I discovered that using %echo-status. Maybe that justifies the version as-written...)
  • %echo-status, like other hook functions, must be dynamically bound to do anything. Also, it's not currently noexport. Should it be?
  • The $echo-status-pid variable is awkward, but it allows people to override %echo-status without having to account for the fact that only sometimes we want the pid printed. Is there a less-awkward way to do the same thing?

A number of the questions I have are in the general category of when we would want to have %echo-status called and when we don't. For example, how many lines do we expect the following to print?

; local (fn-%echo-status = echo) cat <{es -c 'cat <<< blah\n'}

@jpco
Copy link
Collaborator Author

jpco commented Dec 3, 2024

Here's something potentially interesting that wait -n and %echo-status help make posisble (along with sigchld and a couple other bits): a wait-any function that "cleanly" waits for only one of several child pids) https://gist.github.com/jpco/b746ecb7207e1b26da67a71d9c4f0d10

It's only a sketch (note the awkward use of %read as a stand-in for "block until exception", and the fact it doesn't check its arguments for validity at all), but I've been pondering some kind of wait-any function for a while and it's neat that this PR seems to make it possible. Notice in particular that it avoids quietly "eating" the exit status of the "meddling" child, and it does all this without having to keep track of reaped children after-the-fact, as the shell had to do internally before #128 (with some bugs besides; see #125).

A more process-group-aware es could also account for stopped children in some intelligent way in wait-any.

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