ã¿ã¤ãã«ã®éããªãã ãã©ãããããã¯Twitterã§æãã¦ããã£ã
ãã®ãããã使ã£ã¦ãChannelã®ãããªã¤ã³ã¿ãã§ã¼ã¹ã§ããã»ã¹ééä¿¡ãè¡ã£ãã»ããè¯ãã®ã ãããã¨æãã¤ã¤ããªãã¹ãçã·ã¹ãã ã³ã¼ã«ã§å®è£ ãã¦ã¿ããã¹ãã
Rustã§ã½ã±ãããã¢
UnixStream::pair()
ãããã
以ä¸ã®ããã«UNIX domain socketã®ãã¢ãä½æã§ããã®ã§ããã¨ã¯forkãã¦ãsock1ã親ã«ãsock2ãåä¾ã«æ®ãã°ããããã
let (sock1, sock2) = UnixStream::pair()?;
ããããã§ã親å´ã®sock2ã®æ¹ã¨ãåä¾å´ã®sock1ã®æ¹ã®fdã¯æ示çã« close(2)
ãã¦ãããªãã¨ãããªããã¨ããã§Rustã§ã¯UnixStreamï¼ã®æã£ã¦ããfdï¼ã«å¯¾ãã¦æ示çãªcloseãå¼ã¶ã®ã«ã¯å·¥å¤«ãå¿
è¦ã§ããã
ã¡ã½ããã¨ã㦠close(2)
ç¸å½ãæã£ã¦ããªãããããªãã¬ã¤ãããªãã®ã§ãä¸æ¦File Descriptorã®è¡¨ç¾ï¼RawFd
åï¼ã«å¤æãã¦ããã«å¯¾ãã¦nixã® nix::unistd::close()
ãå¼ã¶ã
ããã§ãRawFdåã¸ã®å¤æã®éã« UnixStream::into_raw_fd()
ãå¼ã¶ãã¨ã§ææ権ã奪ã£ã¦ããå¿
è¦ããããããããªãã¨ï¼ãã¨ãã° as_raw_fd() ãå¼ãã ãããå ´åï¼ UnixStream
ã®ã¤ã³ã¹ã¿ã³ã¹èªä½ã®dropãå¼ã°ããéã«ããfdãã¯ãã¼ãºããå¦çãèµ°ãã®ã§ãäºéã¯ãã¼ãºã«ãªã£ã¦ãã¾ãããã
ããããæãã§æ¸ããã
fn main() -> Result<(), Box<dyn std::error::Error>> { let (sock1, sock2) = UnixStream::pair()?; let sock = match unsafe { fork()? } { ForkResult::Parent { child } => { println!("Added child. Pid: {}", child); close(sock2.into_raw_fd())?; sock1.into_raw_fd() } ForkResult::Child => { let cmd = CString::new("/proc/self/exe").unwrap(); close(sock1.into_raw_fd())?; // ...ããã§execããã®ã§å®éã¯ãã®ä¸ã«è³ããªã 0 } }; //... }
å¤åãä»ã«ã drop
ãæ示çã«å¼ã°ããã¨ãã§ããæ°ãããã
ããã¦ãããã§åé¡ã¨ãã¦ãsock1ã®ææ権ãä¸åº¦å¥ªããã¦ãã¾ãã®ã§ãå¾ç¶ã®å¦çã§sock1ã«å¯¾ãã¦ãã¼ã¿ãéããã¨ãã§ããªããªã£ã¦ãã¾ã...ã
ãªã®ã§ãä¸åº¦ RawFd
ãsockå¤æ°ã§åãåããå¾ç¶ã®å¦ç㧠UnixStream::from_raw_fd()
ãèªãã§ããä¸åº¦ UnixStream
ã«æ»ãã¦èªã¿æ¸ããã§ããããã«ããããªãã UnixStream::from_raw_fd()
èªä½ã¯ unsafe ã
//... let mut sock1 = unsafe { UnixStream::from_raw_fd(sock) }; for i in 0..5 { for _ in 0..=i { sock1.write(b"byte ")?; } sock1.write(b"\n")?; sleep(Duration::from_secs(1)); } while let Ok(status) = waitpid(None, None) { println!("Reaped child. Status: {:?}", status); } //...
ã¤ãã§ã« FD_CLOEXEC ã奪ã£ã¦execããå¾ã§ä½¿ã
ãã£ãããªã®ã§ããå°ãããããããã¨ããããåããã»ã¹ã® fd ããexecããå¾ã§ãç¶æ¿ãã¦ãããããã¼ã¿ãåå¾ã§ããããã«ããã
Rustã®ã³ã¼ãããä½æããfdã¯æ®é FD_CLOEXEC
ãã©ã°ãã¤ãã¦ãã®ã§ã exec ãããèªåã§ã¯ãã¼ãºãã¦æ¶æ»
ããã close-on-exec ã«ã¤ãã¦ã¯ man open ã¨ããã®è¾ºã§ ã
FD_CLOEXEC
ã¯fdããæ示çã«å¥ªããã¨ãã§ãããå
·ä½çã«ã¯ fcntl(2)
ã nix::fcntl::fcntl()
ããå¼ã¹ããããªã®ã§å¼ãã ãä¸è¨ã®forkå¨ãã®ã³ã¼ãããããªãã
fn main() -> Result<(), Box<dyn std::error::Error>> { let (sock1, sock2) = UnixStream::pair()?; let sock = match unsafe { fork()? } { ForkResult::Parent { child } => { println!("Added child. Pid: {}", child); close(sock2.into_raw_fd())?; sock1.into_raw_fd() } ForkResult::Child => { let cmd = CString::new("/proc/self/exe").unwrap(); close(sock1.into_raw_fd())?; let newsock = sock2.into_raw_fd(); let _r = fcntl(newsock, FcntlArg::F_SETFD(FdFlag::empty()))?; let args = vec![ CString::new("child").unwrap(), CString::new(format!("{}", newsock)).unwrap(), ]; execvp(&cmd, &args.as_ref())?; 0 } }; let mut sock1 = unsafe { UnixStream::from_raw_fd(sock) }; //... }
ã³ã¼ãã®éããèªåèªèº«ã®ãã¤ããªã execvp() ãã¦ãã*1ãããã°ã©ã å´ã§èªåã® $0
ãè¦ã¦å¦çãåå²ãããã¨ã«ãããmainã®åé ã«ä»¥ä¸ã追å ã
fn main() -> Result<(), Box<dyn std::error::Error>> { if &args().nth(0).unwrap() == "child" { println!("I'm a new child process"); let sock2: RawFd = args().nth(1).unwrap().parse()?; let mut sock2 = unsafe { UnixStream::from_raw_fd(sock2) }; loop { let mut buf = [0u8; 1024]; if sock2.read(&mut buf)? == 0 { break; } print!("{}", String::from_utf8((&buf).to_vec())?.trim_matches('\0')); } println!("All drained."); sleep(Duration::from_secs(3)); return Ok(()); } //... }
fdçªå·ãexecve(execvp)çµç±ã§ã³ãã³ãå¼æ°ã«æ¸¡ããæ°ããããã°ã©ã ããåå¾ããããã®çªå·ã UnixStream::from_raw_fd()
ã§å
ã®ã½ã±ããã«å¤æãã¦ããã
ããã§ã親ããã»ã¹ããåããã»ã¹ã«ãã¼ã¿ãéãã¤ãããã¨ãã§ããããã«ãªã£ãã
åä½ã®æ§åã¯ãããªæãã§ãããªãããã®ãµã³ãã«ã®PIDã§ããã...ã
$ ../target/debug/cloexec-example Added child. Pid: 164043 I'm a new child process byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte All drained. Reaped child. Status: Exited(Pid(164043), 0)
ã³ã¼ãã®å ¨ä½ã¯ãã¡ãã
ã¨ããæãã§ãã½ã±ãããã¢ã§2ã¤ã®å¥ã ã®ããã°ã©ã å士ã§éä¿¡ãããµã³ãã«ãæ¸ãã¦ã¿ãããã©ãunsafeæä½ãå¤ãããããèªåã§æ¸ããããªã¨ããã§ã¯ãªããã...ãservo/ipc-channel ã¯ããããservoããã¸ã§ã¯ãã®ä¸é¨ã§ä¿¡é ¼ã§ããã³ã¼ãã®ãããªæ°ãããã®ã§è©¦ãã¦ã¿ããã¨ããã
*1:ããèãããpä¸è¦ãã