rakitzis / rc

rc shell -- independent re-implementation for Unix of the Plan 9 shell (from circa 1992)
Other
250 stars 23 forks source link

Allow builtin wait more than one argument #81

Closed oliwer closed 1 year ago

oliwer commented 1 year ago

When waiting on multiple PIDs, $status will be set with the status of each process. Example:

; true&false&true& wait $apids; whatis status
status=(0 1 0)

This is an extra feature not present in Plan 9 rc.

Note that calling wait without argument keeps its standard behavior and only returns the status of the last terminated process.

xyb3rt commented 1 year ago

This looks good, but commit 1f2a523 did change waitforall(), so that it now prints the messages for children as soon as they are terminated. You could not anticipate that change and so now we have to look at how to bring these two commits together.

I think the best way forward would be to overhaul waiting for all or a given list of processes, by calling rc_wait() repeatedly till all matching children have terminated, so that waitforall() and your setwaitstatus() have to iterate over plist to find the terminated child, mark it and maybe pop it from the list, and then check plist again to check if they're done.

xyb3rt commented 1 year ago

I've created the branch multi-wait with your commit and some changes to fix some issues:

  1. Calling wait with invalid arguments did not exit when -e is set
  2. A change of behaviour when waiting on failed children. Before this, waiting on false & did exit when -e is set
  3. Not reporting terminated children as soon as possible, like discussed above

I'm still not decided on wether we actually want to change the behaviour of (2). The bash shell, for instance, does not exit when -e is on and wait is called on a failed child, it only does if the arguments are invalid (1).

borkovic commented 1 year ago

Yeah, it is a little tricky. The wait command itself is not failing, but wait does signify the end of the failing background command false &, and -e says to exit when any command (other than those in conditionals) finishes with errors.

My reading of the bash man page is that bash should exit: exit after a simple command unless in a conditional or in a && or || list. A command terminated by & is a simple command.

Exit immediately if a simple command (see SHELL GRAMMAR above) exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a && or ⎪⎪ list, or if the command's return value is being inverted via !. A trap on ERR, if set, is executed before the shell exits.

Also, should false & alone cause rc to exit upon completion and during processing of SIGCLD signal?

oliwer commented 1 year ago

Hi. Glad to see this project is resurrected!

should false & alone cause rc to exit upon completion and during processing of SIGCLD signal?

I think that would be a bad idea. When running a background command, we have no idea when the SIGCLD will come up. That would make scripts unpredictable.

But I do think that with -e, wait should fail since it returns a false status. That's what I would expect anyway. The user would need to write wait || true to override this.

oliwer commented 1 year ago

@xyb3rt I don't understand why displaying terminated children notifications immediately is a problem. Am I missing something?

xyb3rt commented 1 year ago

I typically run wait in an interactive shell to see which background jobs have stopped and then hit ^C, if some are still running. If the first one is, no message is displayed for the rest, even if they're long gone.