Repository navigation
Add stop/continue job control - #7
theduardomaciel wants to merge 1 commit into
Conversation
Map SIGSTOP, SIGTSTP and SIGCONT to NtSuspendProcess/NtResumeProcess, make bg resume a stopped job and fg resume before waiting, and report stopped jobs from jobs. Only external jobs can be stopped; in-process jobs report an error. Windows has no SIGTSTP, so Ctrl+Z still cannot suspend a foreground child. Co-authored-by: DeepSeek V4.1 Flash <noreply@opencode.ai>
dcf7394 to
316fd4e
Compare
hex2f
left a comment
There was a problem hiding this comment.
Thanks for this, it's a useful feature. There are a few problems, though, and some of them change what scripts do. Line comments below.
I merged it onto current main and ran cargo test: all 65 compat scripts still pass. Nothing tests the new code yet.
Stopped jobs outlive the shell. sleep 1 & kill -STOP $!; exit leaves sleep.exe suspended after gash exits, and it stays that way, since on Windows nothing ever resumes or ends it. I reproduced this. Bash warns about stopped jobs on exit, and sends them SIGHUP and SIGCONT. At minimum, gash should resume or terminate the processes it suspended when it exits.
Missing regression test: please add a tests/scripts case, for example: stop a sleep, check jobs, send CONT, then wait and check the status. Keep in mind that Git Bash's non-interactive jobs prints Running for a stopped job, so the expected output has to come from regen_expected.ps1.
Needs a rebase: #13 has been merged. It edits the same job loop in kill, and Job::kill() now takes the signal, so this branch conflicts with main.
| "10" | "USR1" => "USR1", | ||
| "12" | "USR2" => "USR2", | ||
| "17" | "CHLD" => "CHLD", | ||
| "18" | "CONT" => "CONT", |
There was a problem hiding this comment.
These numbers don't match Git Bash. Git Bash uses Cygwin's numbering: STOP=17, TSTP=18, CONT=19, CHLD=20. kill -l in Git Bash 5.3.15 prints those, and this PR uses Linux's. As a result:
kill -19 $pstops the job in gash but resumes it in Git Bash.kill -18 $presumes it in gash but sends TSTP in Git Bash.kill -l 19printsSTOPhere andCONTin Git Bash.
Scripts written for Git Bash would do the opposite of what they mean. gash's existing CHLD=17 has the same problem, so this may be worth fixing in one place, in norm_sig/sig_num.
| let spec = args.first().cloned().unwrap_or_else(|| "%+".into()); | ||
| match find_job(sh, &spec) { | ||
| Some(i) => { | ||
| let mut j = sh.jobs.list.remove(i); |
There was a problem hiding this comment.
The job is lost when resuming fails. The job is removed from sh.jobs.list here, before the resume() check below. If resuming fails, the function returns Ok(1) and the Job is dropped, so it no longer appears in jobs, wait or kill %n. Check (and resume) before removing it.
| (j.id, j.text.clone(), ok) | ||
| }; | ||
| if !ok { | ||
| sh.eprint(&format!("bg: {}: job is not stopped or cannot be resumed", spec)); |
There was a problem hiding this comment.
bg on a running job (nit). Bash prints bg: job 1 already in background and returns 0 when the job is already running. This returns 1 with an error, so bg in a script that doesn't know the job's state now fails.
| } | ||
| } | ||
|
|
||
| pub fn suspend_pid(pid: u32) -> bool { |
There was a problem hiding this comment.
Only the one process is suspended. NtSuspendProcess suspends a single process, not the processes it started. A job such as a .bat file, cmd /c ..., or an MSYS program that spawns helpers keeps its children running while jobs says Stopped. Putting background jobs in a job object, and suspending every process in it, would come closer to stopping a process group. If that's out of scope, please at least note the limitation in the README.
What
Adds the stop/continue subset of job control that Windows can actually support:
SIGSTOP(19),SIGTSTP(20) andSIGCONT(18) are recognized bykillandkill -l.kill -STOP/-TSTPsuspends an external job or PID viaNtSuspendProcess;-CONTresumes it viaNtResumeProcess.jobsreportsStopped.bgresumes a stopped job;fgresumes before waiting.It also fixes an existing footgun: unknown signal names fell back to
SIGTERM, sokill -STOP %1silently killed the job.Limits
Windows has no SIGTSTP and no console job control. Ctrl+Z cannot suspend a foreground child because the child owns the console. In-process (
JobKind::Thread) jobs cannot be suspended and report an error. The feature is still useful for background external jobs andkill -STOP <pid>.Testing
Built with the release workflow and verified on Windows 11: