1use std::{
2 io::{self, IoSlice},
3 pin::Pin,
4 process::Stdio,
5 task::{Context, Poll},
6 time::Duration,
7};
8
9use dolang_rpc::handle::DefaultHandle;
10use serde::{Deserialize, Serialize};
11use tokio::{
12 fs::File,
13 io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, ReadBuf},
14 task::JoinHandle,
15};
16
17use crate::{
18 STREAM_CHUNK_SIZE, SessionMode, Vfs, VfsInner, client, direct,
19 error::{Error, ErrorKind, Result},
20 path,
21 target::OperatingSystem,
22};
23
24mod foreign;
25
26pub(crate) use foreign::ProcessFamily;
27pub use foreign::{Process, ProcessExit, ProcessInfo, Processes, StartTime};
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
31pub enum ProcessStatus {
32 Exited(i32),
33 Signaled(i32),
34}
35
36impl ProcessStatus {
37 pub const fn success(self) -> bool {
39 matches!(self, Self::Exited(0))
40 }
41
42 pub const fn code(self) -> Option<i32> {
44 match self {
45 Self::Exited(code) => Some(code),
46 Self::Signaled(_) => None,
47 }
48 }
49
50 pub const fn signal(self) -> Option<i32> {
52 match self {
53 Self::Exited(_) => None,
54 Self::Signaled(signal) => Some(signal),
55 }
56 }
57
58 pub(crate) fn from_native(status: std::process::ExitStatus) -> io::Result<Self> {
59 if let Some(code) = status.code() {
60 return Ok(Self::Exited(code));
61 }
62 #[cfg(unix)]
63 {
64 use std::os::unix::process::ExitStatusExt;
65 if let Some(signal) = status.signal() {
66 return Ok(Self::Signaled(signal));
67 }
68 }
69 Err(io::Error::new(
70 io::ErrorKind::InvalidData,
71 "process returned an unrepresentable terminal status",
72 ))
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub enum ProcessControl {
79 Foreground,
81 Background,
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
87#[non_exhaustive]
88pub enum Signal {
89 Hup,
90 Int,
91 Quit,
92 Ill,
93 Trap,
94 Abrt,
95 Emt,
96 Fpe,
97 Kill,
98 Bus,
99 Segv,
100 Sys,
101 Pipe,
102 Alrm,
103 Term,
104 Urg,
105 Stop,
106 Tstp,
107 Cont,
108 Chld,
109 Ttin,
110 Ttou,
111 Io,
112 Xcpu,
113 Xfsz,
114 Vtalrm,
115 Prof,
116 Winch,
117 Info,
118 Usr1,
119 Usr2,
120 Stkflt,
121 Pwr,
122 Thr,
123 Librt,
124 Number(i32),
125}
126
127impl Signal {
128 pub fn is_supported(self, operating_system: OperatingSystem) -> bool {
130 use OperatingSystem::{FreeBsd, Linux, Macos, Windows};
131 match self {
132 Self::Emt | Self::Info => matches!(operating_system, FreeBsd | Macos),
133 Self::Stkflt | Self::Pwr => operating_system == Linux,
134 Self::Thr | Self::Librt => operating_system == FreeBsd,
135 Self::Number(_) => operating_system != Windows,
136 _ => operating_system != Windows,
137 }
138 }
139}
140enum CommandInner<'a> {
141 Client(client::Command<'a>),
142 Direct(direct::Command<'a>),
143}
144
145pub struct Command<'a> {
148 inner: CommandInner<'a>,
149 vfs: Vfs,
150 stdin: Option<StdioRecv>,
151 stdout: Option<StdioSend>,
152 stderr: Option<StdioSend>,
153}
154
155impl<'a> Command<'a> {
156 pub(crate) fn new(vfs: &'a Vfs, program: path::Path<'_>) -> Self {
157 let inner = match &vfs.inner {
158 VfsInner::Client(client) => CommandInner::Client(client.command(program)),
159 VfsInner::Direct(direct) => CommandInner::Direct(direct.command(program)),
160 };
161 Self {
162 inner,
163 vfs: vfs.clone(),
164 stdin: None,
165 stdout: None,
166 stderr: None,
167 }
168 }
169}
170
171enum ChildInner {
172 Client(client::Child),
173 Direct(Box<direct::Child>),
174}
175
176#[derive(Default)]
184struct PendingRelays {
185 inputs: Vec<(StdioRecv, StdioSend)>,
186 outputs: Vec<(StdioRecv, StdioSend)>,
187}
188
189impl PendingRelays {
190 fn start(self) -> ActiveRelays {
191 let spawn_all = |pairs: Vec<(StdioRecv, StdioSend)>| {
192 pairs
193 .into_iter()
194 .map(|(src, dst)| tokio::spawn(relay(src, dst)))
195 .collect()
196 };
197 ActiveRelays {
198 inputs: spawn_all(self.inputs),
199 outputs: spawn_all(self.outputs),
200 }
201 }
202}
203
204#[derive(Default)]
205struct ActiveRelays {
206 inputs: Vec<JoinHandle<()>>,
207 outputs: Vec<JoinHandle<()>>,
208}
209
210impl ActiveRelays {
211 fn abort_inputs(&mut self) {
212 for handle in self.inputs.drain(..) {
213 handle.abort();
214 }
215 }
216
217 async fn finish(&mut self) {
225 self.abort_inputs();
226 for handle in self.outputs.drain(..) {
227 let _ = handle.await;
228 }
229 }
230
231 fn abandon(&mut self) {
234 self.abort_inputs();
235 for handle in self.outputs.drain(..) {
236 handle.abort();
237 }
238 }
239}
240
241impl Drop for ActiveRelays {
242 fn drop(&mut self) {
243 self.abandon();
244 }
245}
246
247pub struct Child {
249 inner: ChildInner,
250 relays: ActiveRelays,
251}
252
253impl Child {
254 pub async fn wait(&mut self) -> Result<ProcessStatus> {
256 let status = match &mut self.inner {
257 ChildInner::Client(child) => child.wait().await,
258 ChildInner::Direct(child) => child.wait().await,
259 }?;
260 self.relays.finish().await;
261 Ok(status)
262 }
263
264 pub async fn terminate(mut self) -> Result<Option<ProcessStatus>> {
266 self.relays.abort_inputs();
267 let result = match self.inner {
268 ChildInner::Client(child) => child.terminate().await,
269 ChildInner::Direct(child) => child.terminate().await,
270 };
271 if result.as_ref().is_ok_and(Option::is_some) {
272 self.relays.finish().await;
273 } else {
274 self.relays.abandon();
275 }
276 result
277 }
278}
279
280fn is_direct_recv(target: &Vfs, stdio: &StdioRecv) -> bool {
283 match (&target.inner, &stdio.0) {
284 (VfsInner::Direct(_), StdioRecvInner::Native(_)) => true,
285 (VfsInner::Client(client), StdioRecvInner::Remote(remote)) => {
286 client.is_same_vfs(remote.client())
287 }
288 (VfsInner::Client(client), StdioRecvInner::Native(_)) => {
289 client.mode() == SessionMode::Native
290 }
291 _ => false,
292 }
293}
294
295fn is_direct_send(target: &Vfs, stdio: &StdioSend) -> bool {
298 match (&target.inner, &stdio.0) {
299 (VfsInner::Direct(_), StdioSendInner::Native(_)) => true,
300 (VfsInner::Client(client), StdioSendInner::Remote(remote)) => {
301 client.is_same_vfs(remote.client())
302 }
303 (VfsInner::Client(client), StdioSendInner::Native(_)) => {
304 client.mode() == SessionMode::Native
305 }
306 _ => false,
307 }
308}
309
310async fn classify_recv(
314 target: &Vfs,
315 stdio: StdioRecv,
316 relays: &mut PendingRelays,
317) -> Result<StdioRecv> {
318 if is_direct_recv(target, &stdio) {
319 return Ok(stdio);
320 }
321 let (send, recv) = target.pipe(None).await?;
322 relays.inputs.push((stdio, send));
323 Ok(recv)
324}
325
326async fn classify_send(
330 target: &Vfs,
331 stdio: StdioSend,
332 relays: &mut PendingRelays,
333) -> Result<StdioSend> {
334 if is_direct_send(target, &stdio) {
335 return Ok(stdio);
336 }
337 let (send, recv) = target.pipe(None).await?;
338 relays.outputs.push((recv, stdio));
339 Ok(send)
340}
341
342impl<'a> Command<'a> {
343 pub fn arg(&mut self, arg: &str) -> &mut Self {
345 match &mut self.inner {
346 CommandInner::Client(builder) => {
347 builder.arg(arg);
348 }
349 CommandInner::Direct(builder) => {
350 builder.arg(arg);
351 }
352 }
353 self
354 }
355
356 pub fn env(&mut self, key: &str, val: &str) -> &mut Self {
358 match &mut self.inner {
359 CommandInner::Client(builder) => {
360 builder.env(key, val);
361 }
362 CommandInner::Direct(builder) => {
363 builder.env(key, val);
364 }
365 }
366 self
367 }
368
369 pub fn env_remove(&mut self, key: &str) -> &mut Self {
371 match &mut self.inner {
372 CommandInner::Client(builder) => {
373 builder.env_remove(key);
374 }
375 CommandInner::Direct(builder) => {
376 builder.env_remove(key);
377 }
378 }
379 self
380 }
381
382 pub fn current_dir(&mut self, dir: path::Path<'_>) -> &mut Self {
384 match &mut self.inner {
385 CommandInner::Client(builder) => {
386 builder.current_dir(dir);
387 }
388 CommandInner::Direct(builder) => {
389 builder.current_dir(dir);
390 }
391 }
392 self
393 }
394
395 pub fn stdin(&mut self, stdio: StdioRecv) -> Result<&mut Self> {
397 self.stdin = Some(stdio);
398 Ok(self)
399 }
400
401 pub fn stdout(&mut self, stdio: StdioSend) -> Result<&mut Self> {
403 self.stdout = Some(stdio);
404 Ok(self)
405 }
406
407 pub fn stdin_inherit(&mut self) -> Result<&mut Self> {
413 self.stdin = None;
414 match &mut self.inner {
415 CommandInner::Client(builder) => {
416 builder.stdin_inherit()?;
417 }
418 CommandInner::Direct(builder) => {
419 builder.stdin_inherit()?;
420 }
421 }
422 Ok(self)
423 }
424
425 pub fn stdout_inherit(&mut self) -> Result<&mut Self> {
427 self.stdout = None;
428 match &mut self.inner {
429 CommandInner::Client(builder) => {
430 builder.stdout_inherit()?;
431 }
432 CommandInner::Direct(builder) => {
433 builder.stdout_inherit()?;
434 }
435 }
436 Ok(self)
437 }
438
439 pub fn stdout_inherit_stderr(&mut self) -> Result<&mut Self> {
442 self.stdout = None;
443 match &mut self.inner {
444 CommandInner::Client(builder) => {
445 builder.stdout_inherit_stderr()?;
446 }
447 CommandInner::Direct(builder) => {
448 builder.stdout_inherit_stderr()?;
449 }
450 }
451 Ok(self)
452 }
453
454 pub fn stdin_null(&mut self) -> &mut Self {
456 self.stdin = None;
457 match &mut self.inner {
458 CommandInner::Client(builder) => {
459 builder.stdin_null();
460 }
461 CommandInner::Direct(builder) => {
462 builder.stdin_null();
463 }
464 }
465 self
466 }
467
468 pub fn stdout_null(&mut self) -> &mut Self {
470 self.stdout = None;
471 match &mut self.inner {
472 CommandInner::Client(builder) => {
473 builder.stdout_null();
474 }
475 CommandInner::Direct(builder) => {
476 builder.stdout_null();
477 }
478 }
479 self
480 }
481
482 pub fn stderr(&mut self, stdio: StdioSend) -> Result<&mut Self> {
484 self.stderr = Some(stdio);
485 Ok(self)
486 }
487
488 pub fn stderr_inherit(&mut self) -> Result<&mut Self> {
490 self.stderr = None;
491 match &mut self.inner {
492 CommandInner::Client(builder) => {
493 builder.stderr_inherit()?;
494 }
495 CommandInner::Direct(builder) => {
496 builder.stderr_inherit()?;
497 }
498 }
499 Ok(self)
500 }
501
502 pub fn stderr_to_stdout(&mut self) -> Result<&mut Self> {
505 self.stderr = None;
506 match &mut self.inner {
507 CommandInner::Client(builder) => {
508 builder.stderr_to_stdout()?;
509 }
510 CommandInner::Direct(builder) => {
511 builder.stderr_to_stdout()?;
512 }
513 }
514 Ok(self)
515 }
516
517 pub fn stderr_inherit_stdout(&mut self) -> Result<&mut Self> {
520 self.stderr = None;
521 match &mut self.inner {
522 CommandInner::Client(builder) => {
523 builder.stderr_inherit_stdout()?;
524 }
525 CommandInner::Direct(builder) => {
526 builder.stderr_inherit_stdout()?;
527 }
528 }
529 Ok(self)
530 }
531
532 pub fn stderr_null(&mut self) -> &mut Self {
534 self.stderr = None;
535 match &mut self.inner {
536 CommandInner::Client(builder) => {
537 builder.stderr_null();
538 }
539 CommandInner::Direct(builder) => {
540 builder.stderr_null();
541 }
542 }
543 self
544 }
545
546 pub fn process_control(&mut self, control: ProcessControl) -> &mut Self {
548 match &mut self.inner {
549 CommandInner::Client(builder) => {
550 builder.process_control(control);
551 }
552 CommandInner::Direct(builder) => {
553 builder.process_control(control);
554 }
555 }
556 self
557 }
558
559 pub fn termination_policy(&mut self, policy: TerminationPolicy) -> &mut Self {
561 match &mut self.inner {
562 CommandInner::Client(builder) => {
563 builder.termination_policy(policy);
564 }
565 CommandInner::Direct(builder) => {
566 builder.termination_policy(policy);
567 }
568 }
569 self
570 }
571
572 pub async fn spawn(mut self) -> Result<Child> {
574 let mut relays = PendingRelays::default();
575 if let Some(stdio) = self.stdin.take() {
576 let stdio = classify_recv(&self.vfs, stdio, &mut relays).await?;
577 match &mut self.inner {
578 CommandInner::Client(builder) => {
579 builder.stdin(stdio)?;
580 }
581 CommandInner::Direct(builder) => {
582 builder.stdin(stdio)?;
583 }
584 }
585 }
586 if let Some(stdio) = self.stdout.take() {
587 let stdio = classify_send(&self.vfs, stdio, &mut relays).await?;
588 match &mut self.inner {
589 CommandInner::Client(builder) => {
590 builder.stdout(stdio)?;
591 }
592 CommandInner::Direct(builder) => {
593 builder.stdout(stdio)?;
594 }
595 }
596 }
597 if let Some(stdio) = self.stderr.take() {
598 let stdio = classify_send(&self.vfs, stdio, &mut relays).await?;
599 match &mut self.inner {
600 CommandInner::Client(builder) => {
601 builder.stderr(stdio)?;
602 }
603 CommandInner::Direct(builder) => {
604 builder.stderr(stdio)?;
605 }
606 }
607 }
608 let inner = match self.inner {
609 CommandInner::Client(builder) => builder.spawn().await.map(ChildInner::Client),
610 CommandInner::Direct(builder) => builder
611 .spawn()
612 .await
613 .map(|x| ChildInner::Direct(Box::new(x))),
614 }?;
615 Ok(Child {
616 inner,
617 relays: relays.start(),
618 })
619 }
620}
621
622#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
624pub struct TerminationPolicy {
625 pub(crate) signal: Signal,
627 pub(crate) grace: Duration,
629 pub(crate) force: bool,
631}
632
633impl TerminationPolicy {
634 pub const fn new(signal: Signal, grace: Duration, force: bool) -> Self {
636 Self {
637 signal,
638 grace,
639 force,
640 }
641 }
642 pub const fn signal(self) -> Signal {
644 self.signal
645 }
646 pub const fn grace(self) -> Duration {
648 self.grace
649 }
650 pub const fn force(self) -> bool {
652 self.force
653 }
654 pub fn set_signal(&mut self, signal: Signal) -> &mut Self {
656 self.signal = signal;
657 self
658 }
659 pub fn set_grace(&mut self, grace: Duration) -> &mut Self {
661 self.grace = grace;
662 self
663 }
664 pub fn set_force(&mut self, force: bool) -> &mut Self {
666 self.force = force;
667 self
668 }
669}
670
671impl Default for TerminationPolicy {
672 fn default() -> Self {
673 Self {
674 signal: Signal::Term,
675 grace: Duration::from_secs(5),
676 force: true,
677 }
678 }
679}
680
681#[cfg(test)]
682mod policy_tests {
683 use super::{Signal, TerminationPolicy};
684 use std::time::Duration;
685
686 #[test]
687 fn termination_policy_construction_and_mutation() {
688 let mut policy = TerminationPolicy::new(Signal::Int, Duration::from_secs(2), false);
689 assert_eq!(policy.signal(), Signal::Int);
690 assert_eq!(policy.grace(), Duration::from_secs(2));
691 assert!(!policy.force());
692 policy
693 .set_signal(Signal::Term)
694 .set_grace(Duration::from_secs(3))
695 .set_force(true);
696 assert_eq!(
697 policy,
698 TerminationPolicy::new(Signal::Term, Duration::from_secs(3), true)
699 );
700 }
701}
702
703#[cfg(unix)]
704use std::os::fd::{AsFd, OwnedFd};
705#[cfg(windows)]
706use std::{
707 io::{PipeReader, PipeWriter, Read as _, Write as _},
708 os::windows::io::OwnedHandle,
709 sync::Arc,
710};
711#[derive(Debug)]
713pub struct StdioSend(pub(crate) StdioSendInner);
714
715#[derive(Debug)]
716pub(crate) enum StdioSendInner {
717 Native(NativeStdioSend),
719 Remote(crate::client::RemoteStdioSend),
721}
722
723#[derive(Debug)]
725pub struct StdioRecv(pub(crate) StdioRecvInner);
726
727#[derive(Debug)]
728pub(crate) enum StdioRecvInner {
729 Native(NativeStdioRecv),
731 Remote(crate::client::RemoteStdioRecv),
733}
734
735#[cfg(unix)]
736#[derive(Debug)]
738pub(crate) enum NativeStdioSend {
739 Pipe(tokio::net::unix::pipe::Sender),
741 File(File),
743}
744
745#[cfg(unix)]
746#[derive(Debug)]
748pub(crate) enum NativeStdioRecv {
749 Pipe(tokio::net::unix::pipe::Receiver),
751 File(File),
753}
754
755#[cfg(windows)]
756#[derive(Debug)]
757pub(crate) enum NativeStdioSend {
758 Pipe {
759 inner: Arc<PipeWriter>,
760 pending: Option<JoinHandle<io::Result<usize>>>,
761 },
762 File(File),
763}
764
765#[cfg(windows)]
766#[derive(Debug)]
767pub(crate) enum NativeStdioRecv {
768 Pipe {
769 inner: Arc<PipeReader>,
770 pending: Option<JoinHandle<(Vec<u8>, io::Result<usize>)>>,
771 ready: Option<(Vec<u8>, usize)>,
772 },
773 File(File),
774}
775
776pub(crate) async fn relay<R, W>(src: R, mut dst: W)
778where
779 R: AsyncRead + Unpin,
780 W: AsyncWrite + Unpin,
781{
782 let mut src = BufReader::with_capacity(STREAM_CHUNK_SIZE, src);
783 let _ = tokio::io::copy_buf(&mut src, &mut dst).await;
784 let _ = dst.shutdown().await;
785}
786
787pub(crate) fn pipe(buf_size: Option<usize>) -> io::Result<(StdioSend, StdioRecv)> {
793 #[cfg(unix)]
794 {
795 let (send, recv) = tokio::net::unix::pipe::pipe()?;
796 if let Some(size) = buf_size {
797 use std::os::fd::AsRawFd;
798 set_pipe_buffer_size(send.as_raw_fd(), size);
799 }
800 Ok((
801 StdioSend(StdioSendInner::Native(NativeStdioSend::Pipe(send))),
802 StdioRecv(StdioRecvInner::Native(NativeStdioRecv::Pipe(recv))),
803 ))
804 }
805 #[cfg(windows)]
806 {
807 let (recv, send) = match buf_size {
808 Some(size) => create_pipe_sized(size)?,
809 None => std::io::pipe()?,
810 };
811 Ok((
812 StdioSend(StdioSendInner::Native(NativeStdioSend::Pipe {
813 inner: Arc::new(send),
814 pending: None,
815 })),
816 StdioRecv(StdioRecvInner::Native(NativeStdioRecv::Pipe {
817 inner: Arc::new(recv),
818 pending: None,
819 ready: None,
820 })),
821 ))
822 }
823}
824
825#[cfg(target_os = "linux")]
829pub(crate) fn set_pipe_buffer_size(fd: std::os::fd::RawFd, size: usize) {
830 let size = i32::try_from(size).unwrap_or(i32::MAX);
831 unsafe {
834 libc::fcntl(fd, libc::F_SETPIPE_SZ, size);
835 }
836}
837
838#[cfg(all(unix, not(target_os = "linux")))]
839pub(crate) fn set_pipe_buffer_size(_fd: std::os::fd::RawFd, _size: usize) {}
840
841#[cfg(windows)]
847fn create_pipe_sized(size: usize) -> io::Result<(std::io::PipeReader, std::io::PipeWriter)> {
848 use std::os::windows::io::FromRawHandle;
849
850 use windows_sys::Win32::{
851 Foundation::HANDLE, Security::SECURITY_ATTRIBUTES, System::Pipes::CreatePipe,
852 };
853
854 let mut read_handle: HANDLE = std::ptr::null_mut();
855 let mut write_handle: HANDLE = std::ptr::null_mut();
856 let attrs = SECURITY_ATTRIBUTES {
857 nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
858 lpSecurityDescriptor: std::ptr::null_mut(),
859 bInheritHandle: 0,
860 };
861 let size = u32::try_from(size).unwrap_or(u32::MAX);
862 let ok = unsafe { CreatePipe(&mut read_handle, &mut write_handle, &attrs, size) };
865 if ok == 0 {
866 return Err(io::Error::last_os_error());
867 }
868 let reader = unsafe { std::io::PipeReader::from_raw_handle(read_handle as _) };
871 let writer = unsafe { std::io::PipeWriter::from_raw_handle(write_handle as _) };
872 Ok((reader, writer))
873}
874
875impl StdioSend {
876 pub fn from_file(file: File) -> Self {
878 Self(StdioSendInner::Native(NativeStdioSend::File(file)))
879 }
880
881 pub(crate) fn remote(remote: crate::client::RemoteStdioSend) -> Self {
882 Self(StdioSendInner::Remote(remote))
883 }
884
885 pub async fn try_clone(&self) -> Result<Self> {
887 match &self.0 {
888 #[cfg(unix)]
889 StdioSendInner::Native(NativeStdioSend::Pipe(pipe)) => {
890 let fd = pipe.as_fd().try_clone_to_owned()?;
891 Ok(Self(StdioSendInner::Native(NativeStdioSend::Pipe(
892 tokio::net::unix::pipe::Sender::from_owned_fd_unchecked(fd)?,
893 ))))
894 }
895 #[cfg(windows)]
896 StdioSendInner::Native(NativeStdioSend::Pipe { inner, .. }) => {
897 Ok(Self(StdioSendInner::Native(NativeStdioSend::Pipe {
898 inner: Arc::new(inner.try_clone()?),
899 pending: None,
900 })))
901 }
902 StdioSendInner::Native(NativeStdioSend::File(file)) => Ok(Self(
903 StdioSendInner::Native(NativeStdioSend::File(file.try_clone().await?)),
904 )),
905 StdioSendInner::Remote(remote) => Ok(Self::remote(remote.try_clone().await?)),
906 }
907 }
908
909 pub async fn into_stdio(self) -> Result<Stdio> {
913 match self.0 {
914 StdioSendInner::Native(NativeStdioSend::File(file)) => {
915 Ok(Stdio::from(file.into_std().await))
916 }
917 #[cfg(unix)]
918 StdioSendInner::Native(NativeStdioSend::Pipe(pipe)) => {
919 let fd: OwnedFd = pipe.into_blocking_fd()?;
920 Ok(Stdio::from(fd))
921 }
922 #[cfg(windows)]
923 StdioSendInner::Native(NativeStdioSend::Pipe { inner, pending }) => {
924 if pending.is_some() {
925 return Err(Error::new(
926 ErrorKind::ResourceBusy,
927 "cannot convert StdioSend while an async write is in flight",
928 ));
929 }
930 Ok(Arc::try_unwrap(inner)
931 .or_else(|inner| inner.try_clone())
932 .map(Stdio::from)?)
933 }
934 StdioSendInner::Remote(_) => Err(Error::new(
935 ErrorKind::InvalidInput,
936 "remote stdio cannot be converted to a native handle",
937 )),
938 }
939 }
940
941 pub(crate) async fn into_blocking_handle(self) -> io::Result<DefaultHandle> {
942 match self.0 {
943 StdioSendInner::Native(NativeStdioSend::File(file)) => Ok(file.into_std().await.into()),
944 #[cfg(unix)]
945 StdioSendInner::Native(NativeStdioSend::Pipe(pipe)) => pipe.into_blocking_fd(),
946 #[cfg(windows)]
947 StdioSendInner::Native(NativeStdioSend::Pipe { inner, pending }) => {
948 if pending.is_some() {
949 return Err(io::Error::other(
950 "cannot convert StdioSend while an async write is in flight",
951 ));
952 }
953 let pipe = Arc::try_unwrap(inner).or_else(|inner| inner.try_clone())?;
954 Ok(OwnedHandle::from(pipe))
955 }
956 StdioSendInner::Remote(_) => Err(io::Error::new(
957 io::ErrorKind::InvalidInput,
958 "remote stdio has no native handle",
959 )),
960 }
961 }
962}
963
964impl StdioRecv {
965 pub fn from_file(file: File) -> Self {
967 Self(StdioRecvInner::Native(NativeStdioRecv::File(file)))
968 }
969
970 pub(crate) fn remote(remote: crate::client::RemoteStdioRecv) -> Self {
971 Self(StdioRecvInner::Remote(remote))
972 }
973
974 pub async fn try_clone(&self) -> Result<Self> {
976 match &self.0 {
977 #[cfg(unix)]
978 StdioRecvInner::Native(NativeStdioRecv::Pipe(pipe)) => {
979 let fd = pipe.as_fd().try_clone_to_owned()?;
980 Ok(Self(StdioRecvInner::Native(NativeStdioRecv::Pipe(
981 tokio::net::unix::pipe::Receiver::from_owned_fd_unchecked(fd)?,
982 ))))
983 }
984 #[cfg(windows)]
985 StdioRecvInner::Native(NativeStdioRecv::Pipe { inner, .. }) => {
986 Ok(Self(StdioRecvInner::Native(NativeStdioRecv::Pipe {
987 inner: Arc::new(inner.try_clone()?),
988 pending: None,
989 ready: None,
990 })))
991 }
992 StdioRecvInner::Native(NativeStdioRecv::File(file)) => Ok(Self(
993 StdioRecvInner::Native(NativeStdioRecv::File(file.try_clone().await?)),
994 )),
995 StdioRecvInner::Remote(remote) => Ok(Self::remote(remote.try_clone().await?)),
996 }
997 }
998
999 pub async fn into_stdio(self) -> Result<Stdio> {
1003 match self.0 {
1004 StdioRecvInner::Native(NativeStdioRecv::File(file)) => {
1005 Ok(Stdio::from(file.into_std().await))
1006 }
1007 #[cfg(unix)]
1008 StdioRecvInner::Native(NativeStdioRecv::Pipe(pipe)) => {
1009 let fd: OwnedFd = pipe.into_blocking_fd()?;
1010 Ok(Stdio::from(fd))
1011 }
1012 #[cfg(windows)]
1013 StdioRecvInner::Native(NativeStdioRecv::Pipe { inner, pending, .. }) => {
1014 if pending.is_some() {
1015 return Err(Error::new(
1016 ErrorKind::ResourceBusy,
1017 "cannot convert StdioRecv while an async read is in flight",
1018 ));
1019 }
1020 Ok(Arc::try_unwrap(inner)
1021 .or_else(|inner| inner.try_clone())
1022 .map(Stdio::from)?)
1023 }
1024 StdioRecvInner::Remote(_) => Err(Error::new(
1025 ErrorKind::InvalidInput,
1026 "remote stdio cannot be converted to a native handle",
1027 )),
1028 }
1029 }
1030
1031 pub(crate) async fn into_blocking_handle(self) -> io::Result<DefaultHandle> {
1032 match self.0 {
1033 StdioRecvInner::Native(NativeStdioRecv::File(file)) => Ok(file.into_std().await.into()),
1034 #[cfg(unix)]
1035 StdioRecvInner::Native(NativeStdioRecv::Pipe(pipe)) => pipe.into_blocking_fd(),
1036 #[cfg(windows)]
1037 StdioRecvInner::Native(NativeStdioRecv::Pipe { inner, pending, .. }) => {
1038 if pending.is_some() {
1039 return Err(io::Error::other(
1040 "cannot convert StdioRecv while an async read is in flight",
1041 ));
1042 }
1043 let pipe = Arc::try_unwrap(inner).or_else(|inner| inner.try_clone())?;
1044 Ok(OwnedHandle::from(pipe))
1045 }
1046 StdioRecvInner::Remote(_) => Err(io::Error::new(
1047 io::ErrorKind::InvalidInput,
1048 "remote stdio has no native handle",
1049 )),
1050 }
1051 }
1052}
1053
1054impl AsyncWrite for StdioSend {
1055 fn poll_write(
1056 mut self: Pin<&mut Self>,
1057 cx: &mut Context<'_>,
1058 buf: &[u8],
1059 ) -> Poll<io::Result<usize>> {
1060 match &mut self.0 {
1061 StdioSendInner::Native(native) => Pin::new(native).poll_write(cx, buf),
1062 StdioSendInner::Remote(remote) => Pin::new(remote).poll_write(cx, buf),
1063 }
1064 }
1065
1066 fn poll_write_vectored(
1067 mut self: Pin<&mut Self>,
1068 cx: &mut Context<'_>,
1069 bufs: &[IoSlice<'_>],
1070 ) -> Poll<io::Result<usize>> {
1071 match &mut self.0 {
1072 StdioSendInner::Native(native) => Pin::new(native).poll_write_vectored(cx, bufs),
1073 StdioSendInner::Remote(remote) => Pin::new(remote).poll_write_vectored(cx, bufs),
1074 }
1075 }
1076
1077 fn is_write_vectored(&self) -> bool {
1078 match &self.0 {
1079 StdioSendInner::Native(native) => native.is_write_vectored(),
1080 StdioSendInner::Remote(remote) => remote.is_write_vectored(),
1081 }
1082 }
1083
1084 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1085 match &mut self.0 {
1086 StdioSendInner::Native(native) => Pin::new(native).poll_flush(cx),
1087 StdioSendInner::Remote(remote) => Pin::new(remote).poll_flush(cx),
1088 }
1089 }
1090
1091 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1092 match &mut self.0 {
1093 StdioSendInner::Native(native) => Pin::new(native).poll_shutdown(cx),
1094 StdioSendInner::Remote(remote) => Pin::new(remote).poll_shutdown(cx),
1095 }
1096 }
1097}
1098
1099impl AsyncRead for StdioRecv {
1100 fn poll_read(
1101 mut self: Pin<&mut Self>,
1102 cx: &mut Context<'_>,
1103 buf: &mut ReadBuf<'_>,
1104 ) -> Poll<io::Result<()>> {
1105 match &mut self.0 {
1106 StdioRecvInner::Native(native) => Pin::new(native).poll_read(cx, buf),
1107 StdioRecvInner::Remote(remote) => Pin::new(remote).poll_read(cx, buf),
1108 }
1109 }
1110}
1111
1112#[cfg(unix)]
1113impl AsyncWrite for NativeStdioSend {
1114 fn poll_write(
1115 mut self: Pin<&mut Self>,
1116 cx: &mut Context<'_>,
1117 buf: &[u8],
1118 ) -> Poll<io::Result<usize>> {
1119 match &mut *self {
1120 Self::Pipe(pipe) => Pin::new(pipe).poll_write(cx, buf),
1121 Self::File(file) => Pin::new(file).poll_write(cx, buf),
1122 }
1123 }
1124 fn poll_write_vectored(
1125 mut self: Pin<&mut Self>,
1126 cx: &mut Context<'_>,
1127 bufs: &[IoSlice<'_>],
1128 ) -> Poll<io::Result<usize>> {
1129 match &mut *self {
1130 Self::Pipe(pipe) => Pin::new(pipe).poll_write_vectored(cx, bufs),
1131 Self::File(file) => Pin::new(file).poll_write_vectored(cx, bufs),
1132 }
1133 }
1134 fn is_write_vectored(&self) -> bool {
1135 match self {
1136 Self::Pipe(pipe) => pipe.is_write_vectored(),
1137 Self::File(file) => file.is_write_vectored(),
1138 }
1139 }
1140 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1141 match &mut *self {
1142 Self::Pipe(pipe) => Pin::new(pipe).poll_flush(cx),
1143 Self::File(file) => Pin::new(file).poll_flush(cx),
1144 }
1145 }
1146 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1147 match &mut *self {
1148 Self::Pipe(pipe) => Pin::new(pipe).poll_shutdown(cx),
1149 Self::File(file) => Pin::new(file).poll_shutdown(cx),
1150 }
1151 }
1152}
1153
1154#[cfg(unix)]
1155impl AsyncRead for NativeStdioRecv {
1156 fn poll_read(
1157 mut self: Pin<&mut Self>,
1158 cx: &mut Context<'_>,
1159 buf: &mut ReadBuf<'_>,
1160 ) -> Poll<io::Result<()>> {
1161 match &mut *self {
1162 Self::Pipe(pipe) => Pin::new(pipe).poll_read(cx, buf),
1163 Self::File(file) => Pin::new(file).poll_read(cx, buf),
1164 }
1165 }
1166}
1167
1168#[cfg(windows)]
1169impl AsyncWrite for NativeStdioSend {
1170 fn poll_write(
1171 mut self: Pin<&mut Self>,
1172 cx: &mut Context<'_>,
1173 buf: &[u8],
1174 ) -> Poll<io::Result<usize>> {
1175 match &mut *self {
1176 Self::File(file) => Pin::new(file).poll_write(cx, buf),
1177 Self::Pipe { inner, pending } => {
1178 if let Some(task) = pending {
1179 return match Pin::new(task).poll(cx) {
1180 Poll::Pending => Poll::Pending,
1181 Poll::Ready(Ok(result)) => {
1182 *pending = None;
1183 Poll::Ready(result)
1184 }
1185 Poll::Ready(Err(error)) => {
1186 *pending = None;
1187 Poll::Ready(Err(io::Error::other(error)))
1188 }
1189 };
1190 }
1191 let inner = Arc::clone(inner);
1192 let data = buf.to_vec();
1193 *pending = Some(tokio::task::spawn_blocking(move || (&*inner).write(&data)));
1194 self.poll_write(cx, &[])
1195 }
1196 }
1197 }
1198 fn poll_write_vectored(
1199 mut self: Pin<&mut Self>,
1200 cx: &mut Context<'_>,
1201 bufs: &[IoSlice<'_>],
1202 ) -> Poll<io::Result<usize>> {
1203 match &mut *self {
1204 Self::File(file) => Pin::new(file).poll_write_vectored(cx, bufs),
1205 Self::Pipe { inner, pending } => {
1206 if let Some(task) = pending {
1207 return match Pin::new(task).poll(cx) {
1208 Poll::Pending => Poll::Pending,
1209 Poll::Ready(Ok(result)) => {
1210 *pending = None;
1211 Poll::Ready(result)
1212 }
1213 Poll::Ready(Err(error)) => {
1214 *pending = None;
1215 Poll::Ready(Err(io::Error::other(error)))
1216 }
1217 };
1218 }
1219 let mut data = Vec::new();
1220 for buf in bufs {
1221 data.extend_from_slice(buf);
1222 }
1223 if data.is_empty() {
1224 return Poll::Ready(Ok(0));
1225 }
1226 let inner = Arc::clone(inner);
1227 *pending = Some(tokio::task::spawn_blocking(move || (&*inner).write(&data)));
1228 self.poll_write_vectored(cx, &[])
1229 }
1230 }
1231 }
1232 fn is_write_vectored(&self) -> bool {
1233 true
1234 }
1235 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1236 match self.as_mut().poll_write(cx, &[]) {
1237 Poll::Pending => Poll::Pending,
1238 Poll::Ready(Ok(_)) => Poll::Ready(Ok(())),
1239 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
1240 }
1241 }
1242 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1243 self.poll_flush(cx)
1244 }
1245}
1246
1247#[cfg(windows)]
1248impl AsyncRead for NativeStdioRecv {
1249 fn poll_read(
1250 mut self: Pin<&mut Self>,
1251 cx: &mut Context<'_>,
1252 buf: &mut ReadBuf<'_>,
1253 ) -> Poll<io::Result<()>> {
1254 match &mut *self {
1255 Self::File(file) => Pin::new(file).poll_read(cx, buf),
1256 Self::Pipe {
1257 inner,
1258 pending,
1259 ready,
1260 } => {
1261 if let Some((data, len)) = ready {
1262 let n = (*len).min(buf.remaining());
1263 buf.put_slice(&data[..n]);
1264 if n == *len {
1265 *ready = None;
1266 } else {
1267 data.drain(..n);
1268 *len -= n;
1269 }
1270 return Poll::Ready(Ok(()));
1271 }
1272 if pending.is_none() {
1273 if buf.remaining() == 0 {
1274 return Poll::Ready(Ok(()));
1275 }
1276 let inner = Arc::clone(inner);
1277 let cap = buf.remaining();
1278 *pending = Some(tokio::task::spawn_blocking(move || {
1279 let mut data = vec![0; cap];
1280 let result = (&*inner).read(&mut data);
1281 (data, result)
1282 }));
1283 }
1284 match Pin::new(pending.as_mut().unwrap()).poll(cx) {
1285 Poll::Pending => Poll::Pending,
1286 Poll::Ready(Ok((data, Ok(len)))) => {
1287 *pending = None;
1288 let n = len.min(buf.remaining());
1289 buf.put_slice(&data[..n]);
1290 if n < len {
1291 *ready = Some((data[n..len].to_vec(), len - n));
1292 }
1293 Poll::Ready(Ok(()))
1294 }
1295 Poll::Ready(Ok((_, Err(error)))) => {
1296 *pending = None;
1297 Poll::Ready(Err(error))
1298 }
1299 Poll::Ready(Err(error)) => {
1300 *pending = None;
1301 Poll::Ready(Err(io::Error::other(error)))
1302 }
1303 }
1304 }
1305 }
1306 }
1307}