Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Re-enable job suspension tests in W02jobs.ztst
- X-seq: zsh-workers 54694
- From: Mikel Ward <mikel@xxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: [PATCH] Re-enable job suspension tests in W02jobs.ztst
- Date: Sun, 7 Jun 2026 09:31:53 +0100
- Archived-at: <https://zsh.org/workers/54694>
- Feedback-id: 604030m:604030admHXZI:604030sSFdq5B5FZ
- List-id: <zsh-workers.zsh.org>
The three suspended-job tests were disabled in workers/43426 (2018)
because they used a fixed `sleep 0.1` to wait for the foreground
job to start before sending Ctrl-Z, which raced on slower systems.
This patch re-enables them with two changes:
1. Readiness synchronization
Replace the racy `sleep 0.1` with an output-based causal barrier:
the foreground command prints a sentinel ("ready") before it
blocks, and the test reads the sentinel back via `zpty_line`
before sending Ctrl-Z. This is the same pattern the existing
`kill` tests at the end of the file already use, and it
guarantees the foreground process group is established before
the signal is sent.
2. Fast teardown via a new zpty_stop_suspended helper
The default zpty_stop's final `zpty -r` blocks waiting for pty
EOF. A stopped `sleep` keeps the pty slave open, so without
explicit cleanup the test would hang for the full sleep duration
per suspended-job test. An earlier version of this patch used
`sleep 100` and called the regular zpty_stop, which caused each
test to block for up to 100 seconds. zpty_stop_suspended sends
`kill -KILL %1; wait; exit` (all on one command line, to keep
zsh from flushing a "[1] + killed ..." notification into the
test output) so the stopped child is gone by the time the
inner shell exits and the pty slave closes.
Tests 1 and 2 also send their own `exit` before calling the helper,
to verify the "you have suspended jobs" exit warning. Test 3
inspects the job with `jobs -r`/`jobs -s` first; that marks the
job as "reported", which suppresses the exit warning, so test 3
skips the explicit `exit` and just calls the helper.
Uses `sleep 3` instead of `sleep 100` so that even if the cleanup
regresses, the hang is caught in seconds rather than minutes.
Co-Authored-By: Claude <noreply@xxxxxxxxxxxxx>
---
Test/W02jobs.ztst | 91 ++++++++++++++++++++++++++++-------------------
1 file changed, 55 insertions(+), 36 deletions(-)
diff --git a/Test/W02jobs.ztst b/Test/W02jobs.ztst
index f38e90dcd..97359e4ca 100644
--- a/Test/W02jobs.ztst
+++ b/Test/W02jobs.ztst
@@ -27,6 +27,22 @@
zpty -d
:
}
+ # Drop-in replacement for zpty_stop when the inner shell is left with
+ # a suspended foreground job. Without explicit cleanup, the stopped
+ # child keeps the pty slave open and { zpty -r } blocks waiting for
+ # EOF until the child eventually exits on its own. Tests that want
+ # to verify the "you have suspended jobs" exit warning should send
+ # their own `exit` before calling this helper.
+ zpty_stop_suspended() {
+ # SIGKILL works even on stopped processes; `wait` reaps; `exit`
+ # exits. All on one command line so zsh doesn't return to a
+ # prompt between steps and flush a "[1] + killed ..." job-state
+ # notification into the test output.
+ zpty -w zsh $'kill -KILL %1; wait; exit\n'
+ { zpty -r zsh } | sed $'/[^[:space:]]/!d; s/\r$//;'
+ zpty -d
+ :
+ }
else
ZTST_unimplemented='the zsh/zpty module is not available'
fi
@@ -83,29 +99,31 @@
*>zsh:*running jobs*
*>zsh:*SIGHUPed*
-#### Races presumed to be associated with zpty mean that
-#### tests involving suspending jobs are not safe.
-## zpty_start
-## zpty_input 'setopt check_jobs no_check_running_jobs'
-## zpty_input 'sleep 3'
-## sleep 0.1
-## zpty_input $'\C-z'
-## zpty_stop
-## 0:suspended job with check_jobs + no_check_running_jobs
-## *>zsh:*(stopped|suspended)*sleep*
-## *>zsh:*(stopped|suspended) jobs*
-## # no 'SIGHUPed' message for suspended jobs
-##
-## zpty_start
-## zpty_input 'setopt check_jobs check_running_jobs'
-## zpty_input 'sleep 3'
-## sleep 0.1
-## zpty_input $'\C-z'
-## zpty_stop
-## 0:suspended job with check_jobs + check_running_jobs
-## *>zsh:*(stopped|suspended)*sleep*
-## *>zsh:*(stopped|suspended) jobs*
-## # no 'SIGHUPed' message for suspended jobs
+ zpty_start
+ zpty_input 'setopt check_jobs no_check_running_jobs'
+ zpty_input '(print ready; sleep 3)'
+ zpty_line
+ zpty_input $'\C-z'
+ zpty_input 'exit'
+ zpty_stop_suspended
+0:suspended job with check_jobs + no_check_running_jobs
+*>ready
+*>zsh:*(stopped|suspended)*sleep*
+*>zsh:*(stopped|suspended) jobs*
+# no 'SIGHUPed' message for suspended jobs
+
+ zpty_start
+ zpty_input 'setopt check_jobs check_running_jobs'
+ zpty_input '(print ready; sleep 3)'
+ zpty_line
+ zpty_input $'\C-z'
+ zpty_input 'exit'
+ zpty_stop_suspended
+0:suspended job with check_jobs + check_running_jobs
+*>ready
+*>zsh:*(stopped|suspended)*sleep*
+*>zsh:*(stopped|suspended) jobs*
+# no 'SIGHUPed' message for suspended jobs
zpty_start
zpty_input 'sleep 5 & sleep 4 & sleep 3 &'
@@ -155,19 +173,20 @@
*>-
*>zsh:*SIGHUPed*
-## zpty_start
-## zpty_input 'sleep 5'
-## sleep 0.1
-## zpty_input $'\C-z'
-## zpty_input 'jobs -r'
-## zpty_input 'print -- -'
-## zpty_input 'jobs -s'
-## zpty_stop
-## 0:`jobs -r` and `jobs -s` with suspended job
-## *>zsh:*(stopped|suspended)*sleep*
-## *>-
-## *>\[1] + (stopped|suspended)*sleep*
-## # no 'SIGHUPed' message for suspended jobs
+ zpty_start
+ zpty_input '(print ready; sleep 3)'
+ zpty_line
+ zpty_input $'\C-z'
+ zpty_input 'jobs -r'
+ zpty_input 'print -- -'
+ zpty_input 'jobs -s'
+ zpty_stop_suspended
+0:`jobs -r` and `jobs -s` with suspended job
+*>ready
+*>zsh:*(stopped|suspended)*sleep*
+*>-
+*>\[1] + (stopped|suspended)*sleep*
+# no 'SIGHUPed' message for suspended jobs
zpty_start
zpty_input 'sleep 10 & sleep 9 & sleep 8 & sleep 7 &'
--
2.54.0
Messages sorted by:
Reverse Date,
Date,
Thread,
Author