@ -1,4 +1,5 @@
//! `pipe()` related operations
//! The async pipe is kinda broke, but that's fine because we don't really need it anyways.
use super ::* ;
use errno ::Errno ;
@ -103,3 +104,289 @@ pub(super) unsafe fn pipe_read_value<T>(fd: i32) -> Result<T, Errno<Error>>
Err ( Error ::Broken . into ( ) )
}
}
#[ derive(Debug, PartialEq, Eq) ]
pub struct WriteHalf ( i32 ) ;
#[ derive(Debug, PartialEq, Eq) ]
pub struct ReadHalf ( i32 ) ;
#[ derive(Debug, PartialEq, Eq) ]
pub struct Pipe
{
tx : WriteHalf ,
rx : ReadHalf ,
}
impl Pipe
{
/// Create from a split
pub fn from_split ( tx : WriteHalf , rx : ReadHalf ) -> Self
{
Self {
tx ,
rx ,
}
}
/// Create a new pipe
pub fn new ( ) -> Result < Self , Error >
{
let ( tx , rx ) = pipe ( ) ? ;
Ok ( Self ::from_split ( tx , rx ) )
}
/// Split into write and read half
pub fn split ( self ) -> ( WriteHalf , ReadHalf )
{
( self . tx , self . rx )
}
}
const GETFL : i32 = 3 ;
const SETFL : i32 = 4 ;
const NOBLOCK : i32 = 2048 ;
fn set_non_blocking ( fd : i32 )
{
use libc ::fcntl ;
unsafe {
fcntl ( fd , SETFL , fcntl ( fd , GETFL , 0 ) | NOBLOCK ) ;
}
}
impl WriteHalf
{
/// Create from a raw file descriptor
pub unsafe fn from_raw ( fd : i32 ) -> Self
{
set_non_blocking ( fd ) ;
Self ( fd )
}
/// Consume and return the output file descriptor
pub fn into_raw ( self ) -> i32
{
self . 0
}
}
impl ReadHalf
{
/// Create from a raw file descriptor
pub unsafe fn from_raw ( fd : i32 ) -> Self
{
set_non_blocking ( fd ) ;
Self ( fd )
}
/// Consume and return the output file descriptor
pub fn into_raw ( self ) -> i32
{
self . 0
}
}
/// Create a new pipe's `Read` and `Write` halfs
pub fn pipe ( ) -> Result < ( WriteHalf , ReadHalf ) , Error >
{
let ( rx , tx ) = unix_pipe ( ) . map_err ( | x | x . into_inner ( ) ) ? ;
if rx < = 0 | | tx < = 0 {
return Err ( Error ::Create ) ;
}
unsafe {
Ok ( ( WriteHalf ::from_raw ( tx ) , ReadHalf ::from_raw ( rx ) ) )
}
}
/// Create 2 linked together pipes.
///
/// # Usage
/// Useful for `fork()`. 1st is parent, 2nd moved to client
pub fn multi ( ) -> Result < ( Pipe , Pipe ) , Error >
{
let ( tx_c , rx_p ) = pipe ( ) ? ;
let ( tx_p , rx_c ) = pipe ( ) ? ;
Ok ( ( Pipe ::from_split ( tx_p , rx_p ) , Pipe ::from_split ( tx_c , rx_c ) ) )
}
use tokio ::{
io ::{
AsyncWrite ,
AsyncRead ,
} ,
} ;
use tokio ::io ::Error as AsyncError ;
use std ::{
pin ::Pin ,
task ::{
Context ,
Poll ,
} ,
} ;
const POLL_IN : i16 = 1 ;
const POLL_OUT : i16 = 4 ;
impl AsyncWrite for WriteHalf
{
#[ inline ] fn poll_flush ( self : Pin < & mut Self > , _cx : & mut Context ) -> Poll < Result < ( ) , AsyncError > >
{
// as far as i can tell this is a no-op with `write()`?
Poll ::Ready ( Ok ( ( ) ) )
}
fn poll_shutdown ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , AsyncError > >
{
let fd = self . 0 ;
if let Poll ::Ready ( res ) = self . poll_flush ( cx ) {
unsafe { libc ::close ( fd ) } ;
Poll ::Ready ( res )
} else {
Poll ::Pending
}
}
fn poll_write ( self : Pin < & mut Self > , _cx : & mut Context , buf : & [ u8 ] ) -> Poll < Result < usize , AsyncError > >
{
use libc ::{
poll ,
write ,
pollfd ,
} ;
let mut fd = pollfd {
fd : self . 0 ,
revents : 0 ,
events : POLL_OUT ,
} ;
let poll = unsafe {
poll ( & mut fd as * mut pollfd , 1 , 0 )
} ;
Poll ::Ready ( if poll < 0 {
Err ( AsyncError ::from_raw_os_error ( errno ::raw ( ) ) )
} else if poll > 0 {
if fd . revents & POLL_OUT = = POLL_OUT {
let wr = unsafe {
write ( self . 0 , & buf [ 0 ] as * const u8 as * const libc ::c_void , buf . len ( ) )
} ;
if wr < 0 {
Err ( AsyncError ::from_raw_os_error ( errno ::raw ( ) ) )
} else {
Ok ( wr as usize )
}
} else {
Err ( AsyncError ::from_raw_os_error ( errno ::raw ( ) ) )
}
} else {
return Poll ::Pending ;
} )
}
}
impl AsyncRead for ReadHalf
{
fn poll_read ( self : Pin < & mut Self > , _cx : & mut Context , buf : & mut [ u8 ] ) -> Poll < Result < usize , AsyncError > >
{
use libc ::{
poll ,
read ,
pollfd ,
} ;
let mut fd = pollfd {
fd : self . 0 ,
revents : 0 ,
events : POLL_IN ,
} ;
let poll = unsafe {
poll ( & mut fd as * mut pollfd , 1 , 0 )
} ;
Poll ::Ready ( if poll < 0 {
Err ( AsyncError ::from_raw_os_error ( errno ::raw ( ) ) )
} else if poll > 0 {
if fd . revents & POLL_IN = = POLL_IN {
let wr = unsafe {
read ( self . 0 , & mut buf [ 0 ] as * mut u8 as * mut libc ::c_void , buf . len ( ) )
} ;
if wr < 0 {
Err ( AsyncError ::from_raw_os_error ( errno ::raw ( ) ) )
} else {
Ok ( wr as usize )
}
} else {
Err ( AsyncError ::from_raw_os_error ( errno ::raw ( ) ) )
}
} else {
return Poll ::Pending ;
} )
}
}
use std ::ops ::Drop ;
impl Drop for WriteHalf
{
fn drop ( & mut self )
{
unsafe {
libc ::close ( self . 0 ) ;
}
}
}
impl Drop for ReadHalf
{
fn drop ( & mut self )
{
unsafe {
libc ::close ( self . 0 ) ;
}
}
}
use tokio ::prelude ::* ;
use futures ::Future ;
impl AsyncWrite for Pipe
{
#[ inline ] fn poll_flush ( mut self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , AsyncError > >
{
let future = async {
self . tx . flush ( ) . await
} ;
tokio ::pin ! ( future ) ;
future . poll ( cx )
}
fn poll_shutdown ( mut self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , AsyncError > >
{
let future = async {
self . tx . shutdown ( ) . await
} ;
tokio ::pin ! ( future ) ;
future . poll ( cx )
}
fn poll_write ( mut self : Pin < & mut Self > , cx : & mut Context , buf : & [ u8 ] ) -> Poll < Result < usize , AsyncError > >
{
let future = async {
self . tx . write ( buf ) . await
} ;
tokio ::pin ! ( future ) ;
future . poll ( cx )
}
}
impl AsyncRead for Pipe
{
fn poll_read ( mut self : Pin < & mut Self > , cx : & mut Context , buf : & mut [ u8 ] ) -> Poll < Result < usize , AsyncError > >
{
let future = async {
self . rx . read ( buf ) . await
} ;
tokio ::pin ! ( future ) ;
future . poll ( cx )
}
}