Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement io::{Read, Write} for &TTYPort #57

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions serial-unix/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@ use std::ffi::CStr;
use std::io;
use std::str;

use libc::{c_int, c_char, size_t};
use libc::{c_char, c_int, size_t};

pub fn last_os_error() -> core::Error {
from_raw_os_error(errno())
}

pub fn from_raw_os_error(errno: i32) -> core::Error {
use libc::{EBUSY, EISDIR, ELOOP, ENOTDIR, ENOENT, ENODEV, ENXIO, EACCES, EINVAL, ENAMETOOLONG, EINTR, EWOULDBLOCK};
use libc::{
EACCES, EBUSY, EINTR, EINVAL, EISDIR, ELOOP, ENAMETOOLONG, ENODEV, ENOENT, ENOTDIR, ENXIO,
EWOULDBLOCK,
};

let kind = match errno {
EBUSY | EISDIR | ELOOP | ENOTDIR | ENOENT | ENODEV | ENXIO | EACCES => core::ErrorKind::NoDevice,
EBUSY | EISDIR | ELOOP | ENOTDIR | ENOENT | ENODEV | ENXIO | EACCES => {
core::ErrorKind::NoDevice
}
EINVAL | ENAMETOOLONG => core::ErrorKind::InvalidInput,

EINTR => core::ErrorKind::Io(io::ErrorKind::Interrupted),
EINTR => core::ErrorKind::Io(io::ErrorKind::Interrupted),
EWOULDBLOCK => core::ErrorKind::Io(io::ErrorKind::WouldBlock),
_ => core::ErrorKind::Io(io::ErrorKind::Other),
_ => core::ErrorKind::Io(io::ErrorKind::Other),
};

core::Error::new(kind, error_string(errno))
Expand All @@ -44,51 +49,55 @@ const TMPBUF_SZ: usize = 128;
pub fn errno() -> i32 {
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
unsafe fn errno_location() -> *const c_int {
extern { fn __error() -> *const c_int; }
extern "C" {
fn __error() -> *const c_int;
}
__error()
}

#[cfg(target_os = "bitrig")]
fn errno_location() -> *const c_int {
extern {
extern "C" {
fn __errno() -> *const c_int;
}
unsafe {
__errno()
}
unsafe { __errno() }
}

#[cfg(target_os = "dragonfly")]
unsafe fn errno_location() -> *const c_int {
extern { fn __dfly_error() -> *const c_int; }
extern "C" {
fn __dfly_error() -> *const c_int;
}
__dfly_error()
}

#[cfg(target_os = "openbsd")]
unsafe fn errno_location() -> *const c_int {
extern { fn __errno() -> *const c_int; }
extern "C" {
fn __errno() -> *const c_int;
}
__errno()
}

#[cfg(any(target_os = "linux", target_os = "android"))]
unsafe fn errno_location() -> *const c_int {
extern { fn __errno_location() -> *const c_int; }
extern "C" {
fn __errno_location() -> *const c_int;
}
__errno_location()
}

unsafe {
(*errno_location()) as i32
}
unsafe { (*errno_location()) as i32 }
}

pub fn error_string(errno: i32) -> String {
#[cfg(target_os = "linux")]
extern {
extern "C" {
#[link_name = "__xpg_strerror_r"]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int;
}
#[cfg(not(target_os = "linux"))]
extern {
extern "C" {
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int;
}

Expand All @@ -101,6 +110,8 @@ pub fn error_string(errno: i32) -> String {
}

let p = p as *const _;
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string()
str::from_utf8(CStr::from_ptr(p).to_bytes())
.unwrap()
.to_string()
}
}
4 changes: 2 additions & 2 deletions serial-unix/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Serial port implementation for Unix operating systems.

extern crate serial_core as core;
extern crate ioctl_rs as ioctl;
extern crate libc;
extern crate serial_core as core;
extern crate termios;
extern crate ioctl_rs as ioctl;

pub use tty::*;

Expand Down
60 changes: 41 additions & 19 deletions serial-unix/src/poll.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(non_camel_case_types,dead_code)]
#![allow(non_camel_case_types, dead_code)]

use libc;

Expand All @@ -21,12 +21,12 @@ struct pollfd {
revents: c_short,
}

const POLLIN: c_short = 0x0001;
const POLLPRI: c_short = 0x0002;
const POLLOUT: c_short = 0x0004;
const POLLIN: c_short = 0x0001;
const POLLPRI: c_short = 0x0002;
const POLLOUT: c_short = 0x0004;

const POLLERR: c_short = 0x0008;
const POLLHUP: c_short = 0x0010;
const POLLERR: c_short = 0x0008;
const POLLHUP: c_short = 0x0010;
const POLLNVAL: c_short = 0x0020;

pub fn wait_read_fd(fd: c_int, timeout: Duration) -> io::Result<()> {
Expand All @@ -38,9 +38,13 @@ pub fn wait_write_fd(fd: c_int, timeout: Duration) -> io::Result<()> {
}

fn wait_fd(fd: c_int, events: c_short, timeout: Duration) -> io::Result<()> {
use libc::{EINTR, EPIPE, EIO};
use libc::{EINTR, EIO, EPIPE};

let mut fds = vec!(pollfd { fd: fd, events: events, revents: 0 });
let mut fds = vec![pollfd {
fd: fd,
events: events,
revents: 0,
}];

let wait = do_poll(&mut fds, timeout);

Expand All @@ -56,18 +60,27 @@ fn wait_fd(fd: c_int, events: c_short, timeout: Duration) -> io::Result<()> {
}

if wait == 0 {
return Err(io::Error::new(io::ErrorKind::TimedOut, "Operation timed out"));
return Err(io::Error::new(
io::ErrorKind::TimedOut,
"Operation timed out",
));
}

if fds[0].revents & events != 0 {
return Ok(());
}

if fds[0].revents & (POLLHUP | POLLNVAL) != 0 {
return Err(io::Error::new(io::ErrorKind::BrokenPipe, super::error::error_string(EPIPE)));
return Err(io::Error::new(
io::ErrorKind::BrokenPipe,
super::error::error_string(EPIPE),
));
}

Err(io::Error::new(io::ErrorKind::Other, super::error::error_string(EIO)))
Err(io::Error::new(
io::ErrorKind::Other,
super::error::error_string(EIO),
))
}

#[cfg(target_os = "linux")]
Expand All @@ -83,7 +96,12 @@ fn do_poll(fds: &mut Vec<pollfd>, timeout: Duration) -> c_int {
}

extern "C" {
fn ppoll(fds: *mut pollfd, nfds: nfds_t, timeout_ts: *mut libc::timespec, sigmask: *const sigset_t) -> c_int;
fn ppoll(
fds: *mut pollfd,
nfds: nfds_t,
timeout_ts: *mut libc::timespec,
sigmask: *const sigset_t,
) -> c_int;
}

let mut timeout_ts = libc::timespec {
Expand All @@ -92,10 +110,12 @@ fn do_poll(fds: &mut Vec<pollfd>, timeout: Duration) -> c_int {
};

unsafe {
ppoll((&mut fds[..]).as_mut_ptr(),
fds.len() as nfds_t,
&mut timeout_ts,
ptr::null())
ppoll(
(&mut fds[..]).as_mut_ptr(),
fds.len() as nfds_t,
&mut timeout_ts,
ptr::null(),
)
}
}

Expand All @@ -109,8 +129,10 @@ fn do_poll(fds: &mut Vec<pollfd>, timeout: Duration) -> c_int {
let milliseconds = timeout.as_secs() * 1000 + timeout.subsec_nanos() as u64 / 1_000_000;

unsafe {
poll((&mut fds[..]).as_mut_ptr(),
fds.len() as nfds_t,
milliseconds as c_int)
poll(
(&mut fds[..]).as_mut_ptr(),
fds.len() as nfds_t,
milliseconds as c_int,
)
}
}
Loading