-
Notifications
You must be signed in to change notification settings - Fork 16
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
fix: work in progress macos support #8
base: main
Are you sure you want to change the base?
Conversation
@doy thank you for this crate. We're trying to use it and we need macos support. So we've been trying to figure that out. I will comment on the individual changes. Could you please allow it to run? |
Co-authored-by: alex <source@proof.construction> Co-authored-by: echolinq <echolinq@protonmail.com> Co-authored-by: warren2k <846021+warren2k@users.noreply.github.com>
8d25795
to
7889630
Compare
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.
@@ -15,7 +15,6 @@ impl Pty { | |||
/// unable to put it into non-blocking mode. | |||
pub fn new() -> crate::Result<Self> { | |||
let pty = crate::sys::Pty::open()?; | |||
pty.set_nonblocking()?; |
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.
Apparently, macos won't let ya do this prior to obtaining a pts.
Ok(Pts(self.0.get_ref().pts()?)) | ||
let pts = Pts(self.0.get_ref().pts()?); | ||
self.0.get_ref().set_nonblocking()?; | ||
Ok(pts) |
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.
So we do it here. And we're not certain whether this is idempotent enough to not be an issue with multiple calls.
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.
i think this should be fine to call multiple times
let pts = pty.pts().unwrap(); | ||
pty.resize(pty_process::Size::new(24, 80)).unwrap(); | ||
let mut child = pty_process::blocking::Command::new("cat") | ||
.spawn(&pty.pts().unwrap()) | ||
.spawn(&pts) | ||
.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.
Similar to setting nonblocking, other operations also seem to be disallowed prior to obtaining a pts.
pty.write_all(&[4u8]).unwrap(); | ||
let status = child.wait().unwrap(); | ||
assert_eq!(status.code().unwrap(), 0); | ||
child.kill().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.
On macos, this ^D
doesn't seem to kill the cat. 🤷 ??
If we care, we better figure out why. If we don't, we may as well allow the child to be dropped implicitly, I suppose.
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.
i'd rather figure out what's going on here - ^D
does work to terminate a cat
process when run normally on macos, so this crate (or test) is doing something wrong here, and i don't want to just sidestep that.
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.
i think this one is actually related to your change above - you're keeping the pts alive longer than before, which apparently prevents the wait from succeeding. if you instead do something like
let mut child = {
let pts = pty.pts().unwrap();
pty.resize(pty_process::Size::new(24, 80)).unwrap();
pty_process::blocking::Command::new("cat")
.spawn(&pts)
.unwrap()
};
^D
should work again.
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.
Hrm... perhaps. Assuming this is true, wouldn't a user be prone to making a similar mistake such as we made in this test?
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.
When spawning a new process, the Pts
is borrowed. Is this because it's meant for reuse? If not, can it instead by passed by value so that spawn()
can drop it?
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.
Pts is meant for reuse (probably in UNIX in general) as demonstrated in
Lines 3 to 29 in 74c223d
#[test] | |
fn test_multiple() { | |
let pty = pty_process::blocking::Pty::new().unwrap(); | |
let pts = pty.pts().unwrap(); | |
pty.resize(pty_process::Size::new(24, 80)).unwrap(); | |
let mut child = pty_process::blocking::Command::new("echo") | |
.arg("foo") | |
.spawn(&pts) | |
.unwrap(); | |
let mut output = helpers::output(&pty); | |
assert_eq!(output.next().unwrap(), "foo\r\n"); | |
let status = child.wait().unwrap(); | |
assert_eq!(status.code().unwrap(), 0); | |
let mut child = pty_process::blocking::Command::new("echo") | |
.arg("bar") | |
.spawn(&pts) | |
.unwrap(); | |
assert_eq!(output.next().unwrap(), "bar\r\n"); | |
let status = child.wait().unwrap(); | |
assert_eq!(status.code().unwrap(), 0); | |
} |
So, alternatively, what does dropping the Pts do... or what does not dropping it do to prevent the cat
child process from exiting on a signal?
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.
It seems that blocking::Pts doesn't have a Drop impl and neither does sys::Pts. It would be std::os::fd::OwnedFd that needs to be dropped in order for cat to terminate on a signal. On macos, at least.
Which kind of makes me think that it may be that cat is terminating and something else does not. But that's just a hunch. We'd have to take a closer look. We can start with the wait method.
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 library's spawn method returns a plain std::process::Child. So it is std::process::Child::wait that is blocking forever even though a signal was sent to cat.
One option: cat is not receiving the signal.
Another option: cat is receiving the signal and terminating—what else would it do?—but for another reason the wait method keeps blocking. Something that has to do with that non-dropped Pts.
child.kill().await.unwrap() | ||
#[cfg(not(target_os = "macos"))] | ||
child.kill().await.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.
On macos this seems to hang. Why?
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.
similarly, this isn't doing anything obviously wrong, so i'd like to understand what is broken here before just disabling it.
pty_w.write_all(&[4u8]).await.unwrap(); | ||
let status = child.wait().await.unwrap(); | ||
assert_eq!(status.code().unwrap(), 0); | ||
child.kill().await.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.
Similar to test_cat_blocking
.
FWIW I tested this example resize usage on the changes from this PR, but found that it doesn't seem to make a difference. Not sure if you view that as in scope for this particular PR or not. |
@samuela I'm not sure what the restrictions on macos are. From what we've seen so far, resizing before creating a client is not tolerated. Which makes the abstraction provided by this crate less appealing on macos. |
Thanks @mightyiam! Only calling resize after spawning a child seems to fix the problem for me |
Ok I can now confirm that as long as I wait until after spawning a process, everything seems to be fine with this PR. Without this PR, it doesn't work regardless of order. So it's definitely a step forward IMHO. |
@samuela I'd love the crate author's feedback, as well, but haven't been able to get it yet. |
thanks for looking into this! these tests have been failing on macos for a while, and i don't have a mac so i'm glad you're looking into it. |
1895e6c this commit appears to get the test suite working on the macos github action workers - can you try this out and see if it works for your case? |
We just had a session where we made some experiments and learned a few things. We will move toward a PR tomorrow. Thank you for that wip commit. We will look at it tomorrow, as well. |
Hi @mightyiam , just curious if you created that PR? I'd be curious to try it! |
Next session scheduled 7 hours from now. |
Hi @doy @mightyiam friendly ping on this. I've been running on this PR for a few weeks now and it's worked great so far. |
Co-authored-by: alex source@proof.construction
Co-authored-by: echolinq echolinq@protonmail.com
Co-authored-by: warren2k 846021+warren2k@users.noreply.github.com