@@ -115,7 +115,7 @@ use yash_env::system::SystemEx as _;
115
115
///
116
116
/// This function panics if there is no job at the specified index.
117
117
async fn resume_job_by_index ( env : & mut Env , index : usize ) -> Result < ProcessResult , ResumeError > {
118
- let tty = env. get_tty ( ) ? ;
118
+ let tty = env. get_tty ( ) . ok ( ) ;
119
119
120
120
let job = & env. jobs [ index] ;
121
121
if !job. is_owned {
@@ -141,7 +141,9 @@ async fn resume_job_by_index(env: &mut Env, index: usize) -> Result<ProcessResul
141
141
142
142
// Make sure to put the target job in the foreground before sending the
143
143
// SIGCONT signal, or the job may be immediately re-suspended.
144
- env. system . tcsetpgrp_without_block ( tty, job. pid ) ?;
144
+ if let Some ( tty) = tty {
145
+ env. system . tcsetpgrp_without_block ( tty, job. pid ) ?;
146
+ }
145
147
146
148
let pgid = -job. pid ;
147
149
let sigcont = env. system . signal_number_from_name ( signal:: Name :: Cont ) ;
@@ -152,7 +154,9 @@ async fn resume_job_by_index(env: &mut Env, index: usize) -> Result<ProcessResul
152
154
let result = env. wait_for_subshell_to_halt ( job. pid ) . await ?. 1 ;
153
155
154
156
// Move the shell back to the foreground.
155
- env. system . tcsetpgrp_with_block ( tty, env. main_pgid ) ?;
157
+ if let Some ( tty) = tty {
158
+ env. system . tcsetpgrp_with_block ( tty, env. main_pgid ) ?;
159
+ }
156
160
157
161
result
158
162
}
@@ -265,10 +269,35 @@ mod tests {
265
269
} )
266
270
}
267
271
272
+ #[ test]
273
+ fn resume_job_by_index_resume_job_even_without_tty ( ) {
274
+ in_virtual_system ( async |mut env, _| {
275
+ env. options . set ( Monitor , On ) ;
276
+ let reached = Rc :: new ( Cell :: new ( false ) ) ;
277
+ let reached2 = Rc :: clone ( & reached) ;
278
+ let subshell = Subshell :: new ( |env, _| {
279
+ Box :: pin ( async move {
280
+ suspend ( env) . await ;
281
+ reached2. set ( true ) ;
282
+ } )
283
+ } )
284
+ . job_control ( JobControl :: Foreground ) ;
285
+ let ( pid, subshell_result) = subshell. start_and_wait ( & mut env) . await . unwrap ( ) ;
286
+ assert_eq ! ( subshell_result, ProcessResult :: Stopped ( SIGSTOP ) ) ;
287
+ let mut job = Job :: new ( pid) ;
288
+ job. job_controlled = true ;
289
+ job. state = subshell_result. into ( ) ;
290
+ let index = env. jobs . add ( job) ;
291
+
292
+ resume_job_by_index ( & mut env, index) . await . unwrap ( ) ;
293
+
294
+ assert ! ( reached. get( ) ) ;
295
+ } )
296
+ }
297
+
268
298
#[ test]
269
299
fn resume_job_by_index_prints_job_name ( ) {
270
300
in_virtual_system ( |mut env, state| async move {
271
- stub_tty ( & state) ;
272
301
env. options . set ( Monitor , On ) ;
273
302
let subshell =
274
303
Subshell :: new ( |env, _| Box :: pin ( suspend ( env) ) ) . job_control ( JobControl :: Foreground ) ;
@@ -289,7 +318,6 @@ mod tests {
289
318
#[ test]
290
319
fn resume_job_by_index_returns_after_job_exits ( ) {
291
320
in_virtual_system ( |mut env, state| async move {
292
- stub_tty ( & state) ;
293
321
env. options . set ( Monitor , On ) ;
294
322
let subshell = Subshell :: new ( |env, _| {
295
323
Box :: pin ( async move {
@@ -318,7 +346,6 @@ mod tests {
318
346
#[ test]
319
347
fn resume_job_by_index_returns_after_job_suspends ( ) {
320
348
in_virtual_system ( |mut env, state| async move {
321
- stub_tty ( & state) ;
322
349
env. options . set ( Monitor , On ) ;
323
350
let subshell = Subshell :: new ( |env, _| {
324
351
Box :: pin ( async move {
@@ -369,7 +396,6 @@ mod tests {
369
396
#[ test]
370
397
fn resume_job_by_index_sends_no_sigcont_to_dead_process ( ) {
371
398
let system = VirtualSystem :: new ( ) ;
372
- stub_tty ( & system. state ) ;
373
399
let mut env = Env :: with_system ( Box :: new ( system. clone ( ) ) ) ;
374
400
env. options . set ( Monitor , On ) ;
375
401
let pid = Pid ( 123 ) ;
@@ -402,7 +428,6 @@ mod tests {
402
428
#[ test]
403
429
fn resume_job_by_index_rejects_unowned_job ( ) {
404
430
let system = VirtualSystem :: new ( ) ;
405
- stub_tty ( & system. state ) ;
406
431
let mut env = Env :: with_system ( Box :: new ( system) ) ;
407
432
env. options . set ( Monitor , On ) ;
408
433
let mut job = Job :: new ( Pid ( 123 ) ) ;
@@ -417,7 +442,6 @@ mod tests {
417
442
#[ test]
418
443
fn resume_job_by_index_rejects_unmonitored_job ( ) {
419
444
let system = VirtualSystem :: new ( ) ;
420
- stub_tty ( & system. state ) ;
421
445
let mut env = Env :: with_system ( Box :: new ( system) ) ;
422
446
env. options . set ( Monitor , On ) ;
423
447
let index = env. jobs . add ( Job :: new ( Pid ( 123 ) ) ) ;
@@ -484,7 +508,6 @@ mod tests {
484
508
#[ test]
485
509
fn main_with_operand_resumes_specified_job ( ) {
486
510
in_virtual_system ( |mut env, state| async move {
487
- stub_tty ( & state) ;
488
511
env. options . set ( Monitor , On ) ;
489
512
// previous job
490
513
let subshell =
@@ -545,8 +568,7 @@ mod tests {
545
568
546
569
#[ test]
547
570
fn main_returns_exit_status_if_job_suspends_if_not_interactive ( ) {
548
- in_virtual_system ( |mut env, state| async move {
549
- stub_tty ( & state) ;
571
+ in_virtual_system ( |mut env, _| async move {
550
572
env. options . set ( Monitor , On ) ;
551
573
env. exit_status = ExitStatus ( 42 ) ;
552
574
let subshell = Subshell :: new ( |env, _| {
@@ -572,8 +594,7 @@ mod tests {
572
594
573
595
#[ test]
574
596
fn main_returns_interrupt_if_job_suspends_if_interactive ( ) {
575
- in_virtual_system ( |mut env, state| async move {
576
- stub_tty ( & state) ;
597
+ in_virtual_system ( |mut env, _| async move {
577
598
env. options . set ( Interactive , On ) ;
578
599
env. options . set ( Monitor , On ) ;
579
600
env. exit_status = ExitStatus ( 42 ) ;
0 commit comments