-
Notifications
You must be signed in to change notification settings - Fork 680
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
Add cfmakeraw/cfsetspeed #527
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do this, can we do it right from the start (for these two functions): We should use the libc FFI bindings and if they do not exist create and get the merged first.
Otherwise looks good, thank you.
Sure, that definitely seems like the right play. I've already started here: rust-lang/libc#541 While I've been waiting for that PR I started trying to use those functions and I don't really know how to do this. if I just use For example if I implement it like this: diff --git a/src/sys/termios.rs b/src/sys/termios.rs
index e8df1ed..954ec85 100644
--- a/src/sys/termios.rs
+++ b/src/sys/termios.rs
@@ -1,5 +1,5 @@
use {Errno, Result};
-use libc::c_int;
+use libc::{self, c_int};
use std::mem;
use std::os::unix::io::RawFd;
@@ -599,6 +599,12 @@ pub fn cfgetospeed(termios: &Termios) -> BaudRate {
}
}
+pub fn cfmakeraw(termios: &mut Termios) {
+ unsafe {
+ libc::cfmakeraw(termios);
+ }
+}
+
pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
Errno::result(unsafe {
ffi::cfsetispeed(termios, baud as speed_t)
@@ -611,6 +617,12 @@ pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
}).map(drop)
}
+pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
+ Errno::result(unsafe {
+ libc::cfsetspeed(termios, baud as speed_t)
+ }).map(drop)
+}
+
pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
let mut termios = unsafe { mem::uninitialized() }; then I get these errors: error[E0308]: mismatched types
--> src/sys/termios.rs:604:25
|
604 | libc::cfmakeraw(termios);
| ^^^^^^^ expected struct `libc::libc::termios`, found struct `sys::termios::ffi::consts::Termios`
|
= note: expected type `*mut libc::libc::termios`
= note: found type `&mut sys::termios::ffi::consts::Termios`
error[E0308]: mismatched types
--> src/sys/termios.rs:622:26
|
622 | libc::cfsetspeed(termios, baud as speed_t)
| ^^^^^^^ expected struct `libc::libc::termios`, found struct `sys::termios::ffi::consts::Termios`
|
= note: expected type `*mut libc::libc::termios`
= note: found type `&mut sys::termios::ffi::consts::Termios` Any guidance here as to how to properly wrap libc's datatypes in nix? |
I think we probably want to use nix's type at the interface level (which provide greater safety) and ensure that proper conversion functions into the libc struct format exist. The memory layout of the two is required to be the same at present, so we just need to (unsafely) |
Is there a convention for this elsewhere in nix I can copy? I'm uncertain whether implementing From would be better than doing it manually in each location and figured there should be consensus on this in nic already. |
Yes. Look for example at |
So I've been making some progress on this, but I wanted to understand how high-level you wanted the API. Given the API designed for |
So I have everything all set for refactoring |
Good work. There are at least two problems with flags under OSX left. Regarding your question about making the functions into methods of Termios, like it was done with Signal: I do not think, that we have yet discussed what style we prefer. I prefer plain functions with arguments for nix. My reason for this is, that I see libc as the place for a raw binding, nix as a place for a safe binding, as far as that's possible, and other libraries can build upon that to create idiomatic wrappers, whatever idiomatic means at that point in time. The module structure derives from the C file header paths. So, we have |
This is actually blocking on rust-lang/libc#542 where it looks like they don't have two of the constants we need. Once that's merged that should fix this. |
Rebased and pushed again now that libc has been updated with the proper constants. This should succeed on OS X now whenever Travis gets around to it. |
Passing now on Mac. CI hasn't finished but all the necessary platforms have passed. |
Missed a couple of baud rate constants in my original patch, so I've re-added those for the appropriate OSes. Also I alphabetized the |
@Susurrus I'd prefer rustfmt in a separate change. |
@kamalmarhubi Other projects I've worked on have only allowed style changes for code that's being modified so that |
I should also note that by doing this the
and corresponding functions where The problem with this however is that these setters & getters partially overlap with existing termios functionality, specifically the |
Ah, that's rust-lang/rustfmt#434 which I should really finish some day :/ This makes sense. I guess I'd just ask if you could revert the blatantly obvious unrelated formatting changes. If not I won't argue hard. |
Could you add |
Yeah, I've seen that used and implemented that in a few spots (not in nix) before and it can work quite nicely to succinctly provide access to fields in a field that still provides control. |
Also, this change in general looks very good. Like seeing more of this finally get moved to libc. |
Regarding the accessors. In the cases that I can remember, only the constructor and read only accessors were necessary. So the accessors where named after the fields (e.g. |
So it seems like there's two directions we can take, head towards setters & getters or just expose the underlying |
Okay, so I implemented
For this I can't just put Another use case of mine would, with this change, look like:
So there's a liberal sprinkling of It really seems like we're straddling in between two levels of API. A low-level API roughly similar to that provided by |
☔ The latest upstream changes (presumably #536) made this pull request unmergeable. Please resolve the merge conflicts. |
Alright, I think this is GTM. Wrote up a couple of tests, as much as I think is reasonable to do here. I have a PR against my |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks good. I didn't have time to review the tests; I'll try to do that later.
test/test_pty.rs
Outdated
@@ -149,7 +149,8 @@ fn test_openpty_with_termios() { | |||
close(pty.slave).unwrap(); | |||
termios | |||
}; | |||
termios.c_oflag &= !ONLCR; | |||
// Make sure newlines are not tranformed so the data is preserved when sent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/tranformed/transformed
//! | ||
//! ``` | ||
//! # use self::nix::sys::termios::{CS5, CSIZE, Termios}; | ||
//! # let mut termios = unsafe { Termios::default_uninit() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the example code have lines commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a comment, it just means that these lines are excluded from rendering when generating docs. default_uninit()
shouldn't be used by external code, it's just to give me an object that I can use for this. I also do it for use
statements that just add visual noise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, that makes sense. As you can see, I'm a doccomment nube.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries, there's lots of weird syntax stuff with doccomments. Also note that #
isn't a comment in Rust :-)
src/sys/termios.rs
Outdated
/// Stores settings for the termios API | ||
/// | ||
/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the | ||
/// standard fields. The only way to obtain an instance of this struct is to extract it from an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/The only way/The only safe way/
/// This can be used for interfacing with other FFI functions like: | ||
/// | ||
/// ```rust | ||
/// # extern crate libc; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, why the comments in the example?
src/sys/termios.rs
Outdated
/// consistent. | ||
// FIXME: Switch this over to use pub(crate) | ||
#[doc(hidden)] | ||
pub unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this function and get_libc_termios
are not intended for public consumption, then why not make them private methods?
Fixed your current review comments about spellings and switched around how public some of the helper functions are. For those we're waiting on |
test/sys/test_termios.rs
Outdated
let mut len = 0; | ||
while len < buf.len() { | ||
// get_mut would be better than split_at_mut, but it requires nightly | ||
len += write(f, &buf[0..]).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is right? What advances buf
?
test/sys/test_termios.rs
Outdated
assert!(pty.master > 0); | ||
assert!(pty.slave > 0); | ||
let termios = tcgetattr(pty.master).unwrap(); | ||
close(pty.master).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a double close. See issue #659. There are a few more instances of it below.
src/sys/termios.rs
Outdated
/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the | ||
/// standard fields. The only safe way to obtain an instance of this struct is to extract it from | ||
/// an open port using `tcgetattr()`. | ||
pub struct Termios { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Termios
is not Clone
anymore
4f52ab7
to
c79b27f
Compare
I don't see any solution for the double close bug in test_termios.rs. Did you forget that one? |
This reduces the boilerplate necessary when wrapping libc constants into groups via enums
This also removes the incorrect TCSASOFT definition as an enum type because it's actually a bitfield.
Indeed! I think I got one but not the other. Should be fixed now. |
That fixed the double close. But I just noticed that we don't have a CHANGELOG entry for the new functions. Could you please add one? |
@asomers Indeed I did forget the changelog. I was waiting until I got the iOS builds sorted and then I forgot about it, thanks for the reminder. While I was in there I did a little cleanup of the CHANGELOG (left it as a separate commit), so it should be a little more readable now. |
Looks like we're finally done. Congrats @Susurrus, you've worked hard on this one. bors r+ |
Well thanks to everyone to helped out with this PR, with all the reviews and discussions I think we actually finalized on a pretty decent API here! I will say, this is my longest PR I've ever done, since it took 4.5 months to get this thing merged! But it was well worth the effort. |
Build succeeded |
We'll see how this tests on other platforms, but it's supported on BSDs and Linux supposedly.