Skip to content

Commit

Permalink
wait: Don't return when the target process is suspended
Browse files Browse the repository at this point in the history
The `wait` built-in no longer returns when the target process is
suspended if job-control is on. The built-in now waits for the target
process to exit or be terminated by a signal regardless of mode.
This behavior is required by POSIX.1-2024.

Maybe we could have a new option to make the built-in work as before,
but I'd like to see if other shells introduce such an option first.
  • Loading branch information
magicant committed Feb 21, 2025
1 parent 5867333 commit 96de906
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 26 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
- The `trap` built-in now also reports signals that are ignored
because the program that invoked the shell has set the signal
to be ignored.
- The `wait` built-in no longer returns when the target process is
suspended if job-control is on. The built-in now waits for the
target process to exit or be terminated by a signal regardless
of mode.
- [line-editing] Updated the completion scripts to support Git
2.48.1.
- [line-editing] Added the completion script for `git-mv`.
Expand Down
3 changes: 3 additions & 0 deletions NEWS.ja
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
も含めて全てのトラップを表示する。
- `trap` 組込みはシェルが起動された時点で最初から無視されていた
シグナルも表示するようになった
- ジョブ制御が有効なとき `wait` 組込みはジョブが停止しても待機し
続けるようになった。これで、`wait` 組込みはモードに関係なく
ジョブが終了するまで待機するようになった
- [行編集] 補完スクリプトを Git 2.48.1 相当に更新
- [行編集] git-mv の補完を追加
- 対話シェルで `read` 組込みが入力を読み込む際にクラッシュすることが
Expand Down
7 changes: 2 additions & 5 deletions doc/_wait.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,12 @@ The dfn:[wait built-in] waits for jobs to terminate.
== Description

The wait built-in waits for background jobs to terminate.
If link:job.html[job] control is enabled, stopped jobs are considered as
terminated.

The built-in can be used to wait for link:syntax.html#async[asynchronous
commands] if job control is disabled.
commands].

If the shell receives a signal while the built-in is waiting and if a
link:_trap.html[trap] has been set for the signal, then the trap is executed
and the built-in immediately finishes (without waiting for the jobs).
and the built-in immediately finishes (without further waiting for the jobs).
If the shell receives a SIGINT signal when job control is enabled, the
built-in aborts waiting.

Expand Down
3 changes: 1 addition & 2 deletions doc/ja/_wait.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ dfn:[Wait 組込みコマンド]はバックグラウンドの{zwsp}link:job.htm
[[description]]
== 説明

Wait コマンドは実行中のバックグラウンドジョブが終了するのを待ちます。{zwsp}link:job.html[ジョブ制御]が有効な時は、ジョブが停止したときも終了したとみなします。

Wait コマンドは実行中のバックグラウンドジョブが終了するのを待ちます。
Wait コマンドはジョブ制御が有効でないときでも{zwsp}link:syntax.html#async[非同期コマンド]の終了を待つのに使えます。

Wait コマンドの実行中にシェルがシグナルを受信した場合、そのシグナルに対し{zwsp}link:_trap.html[トラップ]が設定してあればそのトラップを直ちに実行し wait コマンドはそのまま終了します。またジョブ制御が有効な場合、シェルが SIGINT シグナルを受信すると wait コマンドは中断されます。
Expand Down
42 changes: 28 additions & 14 deletions job.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* job.c: job control */
/* (C) 2007-2024 magicant */
/* (C) 2007-2025 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -1345,20 +1345,29 @@ int wait_for_job_by_jobspec(const wchar_t *jobspec)
|| job->j_legacy)
return Exit_NOTFOUND;

int signal = wait_for_job(jobnumber,
doing_job_control_now, doing_job_control_now, true);
if (signal != 0) {
assert(TERMSIGOFFSET >= 128);
return -(signal + TERMSIGOFFSET);
}
while (job->j_status != JS_DONE) {
bool savenonotify = job->j_nonotify;
job->j_nonotify = true;
int signal = wait_for_sigchld(
/* interruptible */ doing_job_control_now,
/* return_on_stop */ true);
job->j_nonotify = savenonotify;
if (signal != 0) {
assert(TERMSIGOFFSET >= 128);
return -(signal + TERMSIGOFFSET);
}

int status = calc_status_of_job(job);
if (job->j_status != JS_RUNNING) {
if (doing_job_control_now && is_interactive_now && !posixly_correct)
print_job_status(jobnumber, false, false, true, stdout);
else if (job->j_status == JS_DONE)
remove_job(jobnumber);
print_job_status(
jobnumber,
/* changedonly */ true,
/* verbose */ false,
/* remove_done */ false,
stdout);
}

int status = calc_status_of_job(job);
remove_job(jobnumber);
return status;
}

Expand All @@ -1369,15 +1378,20 @@ bool wait_builtin_has_job(bool jobcontrol)
for (size_t i = 1; i < joblist.length; i++) {
job_T *job = joblist.contents[i];
if (jobcontrol && is_interactive_now && !posixly_correct)
print_job_status(i, true, false, false, stdout);
print_job_status(
i,
/* changedonly */ true,
/* verbose */ false,
/* remove_done */ false,
stdout);
if (job != NULL && (job->j_legacy || job->j_status == JS_DONE))
remove_job(i);
}

/* see if we have jobs to wait for. */
for (size_t i = 1; i < joblist.length; i++) {
job_T *job = joblist.contents[i];
if (job != NULL && (!jobcontrol || job->j_status == JS_RUNNING))
if (job != NULL)
return true;
}
return false;
Expand Down
2 changes: 1 addition & 1 deletion tests/builtins-y.tst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ posix="true"
setup 'PATH=; unset PATH'

test_OE -e 0 'intrinsic built-in bg can be invoked without $PATH' -em
"$TESTEE" -c 'kill -STOP $$'&
"$TESTEE" -c 'kill -STOP $$' && true
bg >/dev/null
wait
__IN__
Expand Down
7 changes: 3 additions & 4 deletions tests/jobs-y.tst
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,13 @@ __OUT__
test_oE 'exit status of suspended job' -m
"$TESTEE" -cim --norcfile 'echo 1; suspend; echo 2'
kill -l $?
bg >/dev/null
wait %
kill -l $?
#bg >/dev/null
#wait %
#kill -l $?
fg >/dev/null
__IN__
1
STOP
TTOU
2
__OUT__

Expand Down

0 comments on commit 96de906

Please sign in to comment.