Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
- When a foreground job suspends in an interactive shell, the shell
now discards any remaining commands that were typed but not yet
executed, and immediately continues to read the next command.
- The shell now considers a job to be suspended when any child
process suspends in a pipeline, instead of when all child
processes suspend.
- The `read` built-in now returns a more specific exit status
depending on the cause of the error.
- The `read` built-in now supports the `-d` option, which can be
Expand Down
2 changes: 2 additions & 0 deletions NEWS.ja
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- POSIX.1-2024 のサポートを強化:
- 対話シェルでフォアグラウンドのジョブが停止したとき、残りの未実行の
コマンドを破棄して直ちに次のコマンドを読むようになった
- ジョブの全ての子プロセスが停止しなくても、どれかの子プロセスが停止
したときにジョブが停止したとみなすようになった
- `read` 組込みは結果に応じてより細分化された終了ステータスを返す
ようになった
- `read` 組込みに行区切り文字を指定する `-d` オプションを追加
Expand Down
4 changes: 2 additions & 2 deletions doc/ja/job.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dfn:[ジョブ制御]とは、複数のコマンドを同時に実行し、必
ジョブ制御が有効な時……

- シェルが起動する各プロセスは、{zwsp}link:syntax.html#pipelines[パイプライン]ごとに共通の一意なプロセスグループに属します。すなわち、シェルが起動するコマンドはそれぞれパイプラインごとにdfn:[ジョブ]として扱われます。
- シェルがジョブを起動しそのジョブのプロセスが終了するのを待っている間にそのプロセスが停止した場合、シェルは (プロセスが実際に終了したときと同様に) 次のコマンドの処理に移ります。このときシェルはジョブが停止したことを覚えているので、後でジョブを再開させることができます。
- シェルがジョブを起動しそのジョブのプロセスが終了するのを待っている間にそのプロセスのどれかが停止した場合、シェルは (ジョブが終了したときと同様に) 次のコマンドの処理に移ります。このときシェルはジョブが停止したことを覚えているので、後でジョブを再開させることができます。
* このとき、シェルが{zwsp}link:interact.html[対話モード]の場合、シェルが読み込んだがまだ実行していないコマンドは破棄され、次のプロンプトが表示されます。
- ジョブが{zwsp}link:syntax.html#async[同期的]に実行される場合、そのジョブの実行中はそのジョブのプロセスグループが端末のフォアグラウンドプロセスグループになります。ジョブの実行が終了 (または停止) すると、再びシェルがフォアグラウンドになります。
- シェルが{zwsp}link:interact.html[対話モード]の場合、プロンプトを出す前に毎回コマンド +link:_jobs.html[jobs] -n+ を実行するのと同様にしてジョブの状態変化を報告します。
Expand All @@ -27,7 +27,7 @@ link:_jobs.html[jobs]::
link:_fg.html[fg] および link:_bg.html[bg]::
ジョブをフォアグラウンドまたはバックグラウンドで実行します。主に停止したジョブを再開させるのに使います。
link:_wait.html[wait]::
ジョブが終了 (または停止) するまで待ちます
ジョブが終了するまで待ちます
link:_disown.html[disown]::
ジョブの存在を忘れます。
link:_kill.html[kill]::
Expand Down
8 changes: 4 additions & 4 deletions doc/job.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ When job control is active:
dfn:[job].
A job has its unique process group ID that is shared among all processes in
the job.
- If the processes of a job are suspended while the shell is waiting for the
processes to finish, the shell continues to the next command as if the
process have finished.
- If a process in a job is suspended while the shell is waiting for the job to
complete, the shell stops waiting and continues to the next command as if
the job has finished.
The shell remembers the job as suspended so that it can be resumed later.
* If the shell is link:interact.html[interactive] in this case, the shell
discards any remaining commands that have been read but not executed, and
Expand Down Expand Up @@ -51,7 +51,7 @@ prints existing jobs
link:_fg.html[fg] and link:_bg.html[bg]::
run jobs in the foreground or background
link:_wait.html[wait]::
waits for jobs to be finished (or suspended)
waits for jobs to be finished
link:_disown.html[disown]::
forgets jobs
link:_kill.html[kill]::
Expand Down
17 changes: 8 additions & 9 deletions job.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,22 +416,21 @@ void do_wait(void)
#endif

/* decide the job status from the process status:
* - JS_RUNNING if any of the processes is running.
* - JS_STOPPED if no processes are running but some are stopped.
* - JS_RUNNING if no processes are stopped but some are running.
* - JS_STOPPED if any of the processes is stopped.
* - JS_DONE if all the processes are finished. */
jobstatus_T oldstatus = job->j_status;
bool anyrunning = false, anystopped = false;
jobstatus_T oldstatus = job->j_status, newstatus = JS_DONE;
/* check if there are running/stopped processes */
for (size_t i = 0; i < job->j_pcount; i++) {
switch (job->j_procs[i].pr_status) {
case JS_RUNNING: anyrunning = true; goto out_of_loop;
case JS_STOPPED: anystopped = true; break;
default: break;
case JS_RUNNING: newstatus = JS_RUNNING; break;
case JS_STOPPED: newstatus = JS_STOPPED; goto out_of_loop;
case JS_DONE: break;
}
}
out_of_loop:
job->j_status = anyrunning ? JS_RUNNING : anystopped ? JS_STOPPED : JS_DONE;
if (job->j_status != oldstatus)
job->j_status = newstatus;
if (newstatus != oldstatus)
job->j_statuschanged = true;

goto start;
Expand Down
9 changes: 5 additions & 4 deletions tests/POSIX
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,15 @@ Volume 3: Shell & Utilities
* case-y.tst
* redir-y.tst

2.11 Signals and Error Handling
2.11 Job Control
* job-p.tst
* job-y.tst

2.12 Signals and Error Handling
* sig*-p.tst
* trap-p.tst
* wait-p.tst

2.12 Job Control
* job-p.tst

2.13 Shell Execution Environment
* trap-p.tst

Expand Down
13 changes: 13 additions & 0 deletions tests/job-y.tst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ cat sync
wait $pid
__IN__

: TODO This test case is flaky for unknown reasons <<'__IN__'
# This is a POSIX requirement, but this test case depends on the shell's
# behavior that runs all pipeline components in child processes.
test_O -e USR1 'job is considered suspended when any child process suspends' -im
# This pipeline suspends its second component. The shell should consider the
# pipeline as suspended.
: | sh -c 'kill -STOP $$' | sleep 50
# The pipeline processes are still alive. Send a signal to terminate them.
kill -USR1 %
# The exit status should indicate the signal that terminated the pipeline.
fg >/dev/null
__IN__

# This is a POSIX requirement, but this test case depends on the shell's
# behavior that runs all pipeline components in child processes.
test_o -e 0 'discard remaining commands when a command suspends' -im
Expand Down