@@ -49,7 +49,7 @@ use oci_spec::runtime::{LinuxResources, Process};
49
49
use runc:: { Command , Runc , Spawner } ;
50
50
use tokio:: {
51
51
fs:: { remove_file, File , OpenOptions } ,
52
- io:: { AsyncBufReadExt , AsyncRead , AsyncReadExt , AsyncWrite , BufReader } ,
52
+ io:: { AsyncBufReadExt , AsyncRead , AsyncReadExt , AsyncWrite , AsyncWriteExt , BufReader } ,
53
53
} ;
54
54
55
55
use super :: {
@@ -63,6 +63,7 @@ use crate::{
63
63
CreateConfig , Log , ProcessIO , ShimExecutor , INIT_PID_FILE , LOG_JSON_FILE ,
64
64
} ,
65
65
io:: Stdio ,
66
+ service:: add_monitor_io,
66
67
} ;
67
68
68
69
pub type ExecProcess = ProcessTemplate < RuncExecLifecycle > ;
@@ -163,8 +164,10 @@ impl RuncFactory {
163
164
( Some ( s) , None )
164
165
} else {
165
166
let pio = create_io ( & id, opts. io_uid , opts. io_gid , stdio) ?;
166
- create_opts. io = pio. io . as_ref ( ) . cloned ( ) ;
167
- ( None , Some ( pio) )
167
+ let ref_pio = Arc :: new ( pio) ;
168
+ create_opts. io = ref_pio. io . clone ( ) ;
169
+ init. io = Some ( ref_pio. clone ( ) ) ;
170
+ ( None , Some ( ref_pio) )
168
171
} ;
169
172
170
173
let resp = init
@@ -178,6 +181,22 @@ impl RuncFactory {
178
181
}
179
182
return Err ( runtime_error ( bundle, e, "OCI runtime create failed" ) . await ) ;
180
183
}
184
+ if !init. stdio . stdin . is_empty ( ) {
185
+ let stdin_clone = init. stdio . stdin . clone ( ) ;
186
+ let stdin_w = init. stdin . clone ( ) ;
187
+ // Open the write side in advance to make sure read side will not block,
188
+ // open it in another thread otherwise it will block too.
189
+ tokio:: spawn ( async move {
190
+ if let Ok ( stdin_w_file) = OpenOptions :: new ( )
191
+ . write ( true )
192
+ . open ( stdin_clone. as_str ( ) )
193
+ . await
194
+ {
195
+ let mut lock_guard = stdin_w. lock ( ) . unwrap ( ) ;
196
+ * lock_guard = Some ( stdin_w_file) ;
197
+ }
198
+ } ) ;
199
+ }
181
200
copy_io_or_console ( init, socket, pio, init. lifecycle . exit_signal . clone ( ) ) . await ?;
182
201
let pid = read_file_to_str ( pid_path) . await ?. parse :: < i32 > ( ) ?;
183
202
init. pid = pid;
@@ -232,6 +251,7 @@ impl ProcessFactory<ExecProcess> for RuncExecFactory {
232
251
stderr : req. stderr . to_string ( ) ,
233
252
terminal : req. terminal ,
234
253
} ,
254
+ io : None ,
235
255
pid : 0 ,
236
256
exit_code : 0 ,
237
257
exited_at : None ,
@@ -299,6 +319,15 @@ impl ProcessLifecycle<InitProcess> for RuncInitLifecycle {
299
319
) ;
300
320
}
301
321
}
322
+ // close pipe read
323
+ if !p. stdio . is_null ( ) {
324
+ if let Some ( c) = p. io . clone ( ) {
325
+ if let Some ( io) = c. io . clone ( ) {
326
+ io. close_read_side ( ) ;
327
+ }
328
+ }
329
+ }
330
+ debug ! ( "Do close io complete" ) ;
302
331
self . exit_signal . signal ( ) ;
303
332
Ok ( ( ) )
304
333
}
@@ -394,8 +423,10 @@ impl ProcessLifecycle<ExecProcess> for RuncExecLifecycle {
394
423
( Some ( s) , None )
395
424
} else {
396
425
let pio = create_io ( & p. id , self . io_uid , self . io_gid , & p. stdio ) ?;
397
- exec_opts. io = pio. io . as_ref ( ) . cloned ( ) ;
398
- ( None , Some ( pio) )
426
+ let ref_pio = Arc :: new ( pio) ;
427
+ exec_opts. io = ref_pio. io . clone ( ) ;
428
+ p. io = Some ( ref_pio. clone ( ) ) ;
429
+ ( None , Some ( ref_pio) )
399
430
} ;
400
431
//TODO checkpoint support
401
432
let exec_result = self
@@ -457,6 +488,15 @@ impl ProcessLifecycle<ExecProcess> for RuncExecLifecycle {
457
488
458
489
async fn delete ( & self , p : & mut ExecProcess ) -> Result < ( ) > {
459
490
self . exit_signal . signal ( ) ;
491
+ //close pipe read
492
+ if !p. stdio . is_null ( ) {
493
+ if let Some ( c) = p. io . clone ( ) {
494
+ if let Some ( io) = c. io . clone ( ) {
495
+ io. close_read_side ( ) ;
496
+ }
497
+ }
498
+ }
499
+ debug ! ( "Do close io complete" ) ;
460
500
let exec_pid_path = Path :: new ( self . bundle . as_str ( ) ) . join ( format ! ( "{}.pid" , p. id) ) ;
461
501
remove_file ( exec_pid_path) . await . unwrap_or_default ( ) ;
462
502
Ok ( ( ) )
@@ -495,7 +535,7 @@ async fn copy_console(
495
535
. open ( stdio. stdin . as_str ( ) )
496
536
. await
497
537
. map_err ( io_error ! ( e, "failed to open stdin" ) ) ?;
498
- spawn_copy ( stdin, console_stdin, exit_signal. clone ( ) , None :: < fn ( ) > ) ;
538
+ spawn_copy_no_recvs ( stdin, console_stdin, exit_signal. clone ( ) , None :: < fn ( ) > ) ;
499
539
}
500
540
501
541
if !stdio. stdout . is_empty ( ) {
@@ -516,7 +556,7 @@ async fn copy_console(
516
556
. open ( stdio. stdout . as_str ( ) )
517
557
. await
518
558
. map_err ( io_error ! ( e, "open stdout for read" ) ) ?;
519
- spawn_copy (
559
+ spawn_copy_no_recvs (
520
560
console_stdout,
521
561
stdout,
522
562
exit_signal,
@@ -535,6 +575,10 @@ pub async fn copy_io(pio: &ProcessIO, stdio: &Stdio, exit_signal: Arc<ExitSignal
535
575
if !pio. copy {
536
576
return Ok ( ( ) ) ;
537
577
} ;
578
+ let mut rs = add_monitor_io ( pio. io . clone ( ) . unwrap ( ) ) . await ;
579
+ //change owner of rs stdin no need spawn_copy
580
+ let stdout_recv = rs. remove ( 0 ) ;
581
+ let stderr_recv = rs. remove ( 0 ) ;
538
582
if let Some ( io) = & pio. io {
539
583
if let Some ( w) = io. stdin ( ) {
540
584
debug ! ( "copy_io: pipe stdin from {}" , stdio. stdin. as_str( ) ) ;
@@ -544,7 +588,7 @@ pub async fn copy_io(pio: &ProcessIO, stdio: &Stdio, exit_signal: Arc<ExitSignal
544
588
. open ( stdio. stdin . as_str ( ) )
545
589
. await
546
590
. map_err ( io_error ! ( e, "open stdin" ) ) ?;
547
- spawn_copy ( stdin, w, exit_signal. clone ( ) , None :: < fn ( ) > ) ;
591
+ spawn_copy_no_recvs ( stdin, w, exit_signal. clone ( ) , None :: < fn ( ) > ) ;
548
592
}
549
593
}
550
594
@@ -568,8 +612,10 @@ pub async fn copy_io(pio: &ProcessIO, stdio: &Stdio, exit_signal: Arc<ExitSignal
568
612
stdout,
569
613
exit_signal. clone ( ) ,
570
614
Some ( move || {
615
+ debug ! ( "stdout exit....................." ) ;
571
616
drop ( stdout_r) ;
572
617
} ) ,
618
+ stdout_recv,
573
619
) ;
574
620
}
575
621
}
@@ -594,8 +640,10 @@ pub async fn copy_io(pio: &ProcessIO, stdio: &Stdio, exit_signal: Arc<ExitSignal
594
640
stderr,
595
641
exit_signal,
596
642
Some ( move || {
643
+ debug ! ( "stderr exit....................." ) ;
597
644
drop ( stderr_r) ;
598
645
} ) ,
646
+ stderr_recv,
599
647
) ;
600
648
}
601
649
}
@@ -604,7 +652,71 @@ pub async fn copy_io(pio: &ProcessIO, stdio: &Stdio, exit_signal: Arc<ExitSignal
604
652
Ok ( ( ) )
605
653
}
606
654
607
- fn spawn_copy < R , W , F > ( from : R , to : W , exit_signal : Arc < ExitSignal > , on_close : Option < F > )
655
+ fn spawn_copy < R , W , F > (
656
+ from : R ,
657
+ to : W ,
658
+ exit_signal : Arc < ExitSignal > ,
659
+ on_close : Option < F > ,
660
+ mut r : tokio:: sync:: mpsc:: Receiver < i64 > ,
661
+ ) where
662
+ R : AsyncRead + Send + Unpin + ' static ,
663
+ W : AsyncWrite + Send + Unpin + ' static ,
664
+ F : FnOnce ( ) + Send + ' static ,
665
+ {
666
+ let mut src = from;
667
+ let mut dst = to;
668
+
669
+ tokio:: spawn ( async move {
670
+ let mut buffer: Vec < u8 > = vec ! [ 0u8 ; 1024 ] ;
671
+ //Change to loop and use time out, to make sure the read_buf will not hangon forever
672
+ loop {
673
+ let mut if_cn = true ;
674
+ let result = tokio:: time:: timeout ( tokio:: time:: Duration :: from_secs ( 5 ) , async {
675
+ tokio:: select! {
676
+ _ = exit_signal. wait( ) =>{
677
+ debug!( "container exit" ) ;
678
+ if_cn = false ;
679
+ }
680
+ r = src. read_buf( & mut buffer) => {
681
+ match r{
682
+ //Read n=0 but read_buf not close means pipe close
683
+ Ok ( n) => {
684
+ if n == 0 {
685
+ if_cn = false ;
686
+ } else{
687
+ //Need sure the dist write complete?
688
+ let d_w = dst. write_all( & buffer) . await ;
689
+ if d_w. is_err( ) {
690
+ if_cn = false ;
691
+ }
692
+ buffer. clear( ) ;
693
+ }
694
+ } ,
695
+ Err ( _) => {
696
+ debug!( "read exit" ) ;
697
+ if_cn = false ;
698
+ } ,
699
+ }
700
+ }
701
+ c = r. recv( ) =>{
702
+ debug!( "fd error io exit!! recv {:?}" , c) ;
703
+ if_cn = false ;
704
+ }
705
+ }
706
+ } ) ;
707
+ //Timeout will continue unitl recv the io close
708
+ let _ = result. await ;
709
+ if !if_cn {
710
+ break ;
711
+ }
712
+ }
713
+ if let Some ( f) = on_close {
714
+ f ( ) ;
715
+ }
716
+ } ) ;
717
+ }
718
+
719
+ fn spawn_copy_no_recvs < R , W , F > ( from : R , to : W , exit_signal : Arc < ExitSignal > , on_close : Option < F > )
608
720
where
609
721
R : AsyncRead + Send + Unpin + ' static ,
610
722
W : AsyncWrite + Send + Unpin + ' static ,
@@ -632,7 +744,7 @@ where
632
744
async fn copy_io_or_console < P > (
633
745
p : & mut ProcessTemplate < P > ,
634
746
socket : Option < ConsoleSocket > ,
635
- pio : Option < ProcessIO > ,
747
+ pio : Option < Arc < ProcessIO > > ,
636
748
exit_signal : Arc < ExitSignal > ,
637
749
) -> Result < ( ) > {
638
750
if p. stdio . terminal {
@@ -670,6 +782,7 @@ impl Spawner for ShimExecutor {
670
782
}
671
783
} ;
672
784
let pid = child. id ( ) . unwrap ( ) ;
785
+
673
786
let ( stdout, stderr, exit_code) = tokio:: join!(
674
787
read_std( child. stdout) ,
675
788
read_std( child. stderr) ,
0 commit comments