-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Partial implementation of close
for stdin/out/err (#40032)
#46063
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
Conversation
This is only the low-level code required for Unix.
src/libstd/sys/unix/stdio.rs
Outdated
// by `fd.replace` is dropped and thus closed. | ||
fd.replace(open_null_device(true)?)?; | ||
// Don't close STDIN_FILENO itself, though! | ||
fd.into_raw(); |
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.
Errors in those prior ?
will drop fd
without calling your into_raw
. Perhaps you could wrap it in ManuallyDrop
instead?
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.
Oh, good point. Thanks for the tip!
Hi @zackw, do you intend to proceed completing this PR? |
@kennytm If I can get the advice I asked for in the PR cover letter, yes. |
Ping @rust-lang/libs, can someone help out with this please? |
src/libstd/sys/unix/fd.rs
Outdated
/// _overall_ operation is not atomic; concurrent threads that snoop on | ||
/// the set of valid file descriptors (which they shouldn't) can observe | ||
/// intermediate states. | ||
pub fn replace(&mut self, other: FileDesc) -> io::Result<FileDesc> { |
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 don't think the replacement semantics are actually needed when closing, right? That is, I think it's safe for this to return ()
and avoid the first call to duplicate
for the specific use case of Stdout::close
?
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.
Yes, I realized the next morning that any caller that actually needs to preserve the old file can just call duplicate
itself. And that will dovetail better with the semantics of SetStdHandle
on Windows. I will make this change.
|
||
pub struct Stdin(()); | ||
pub struct Stdout(()); | ||
pub struct Stderr(()); | ||
|
||
// FIXME: This duplicates code from process_common.rs. |
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.
Ah yeah, would it be possible to extract the two to common code?
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.
Yeah, where should it live? File::open_bit_bucket
maybe?
@zackw the organization is typically just the same set of functions on each platform, the "maze" is typically what's in libstd at |
I'm sorry, could you please be more specific? I already read through that file and I was not enlightened. |
@zackw hm I think I may just misunderstand the question or the need for information here. What's the end goal here? |
@alexcrichton It is clear to me that I also can't figure out if there is any other place I should be looking at for other classes that also need to be involved. |
Ah ok, I can try to help out with that! So in general this is touching on the question of methods like In that sense it's not even clear how we would add close-related methods to the standard library (API-wise). Something like I would personally recommend adding something like: impl Stdout {
pub fn close(&mut self) -> io::Result<()> {
// ...
}
} That would then probably delegate to a similar method on the versions in the |
Thanks, that's helpful in terms of the larger picture, but it's almost entirely unrelated to the question I was trying to ask. What I'm stuck on is not the appropriate signature of |
That's sort of also a question that is not easily answered unfortunately. We can review more during stabilization but the most conservative route is to likely just add it to |
* FileDesc::replace() no longer returns the old file; call duplicate() yourself if you need it. * Make sure STD{IN,OUT,ERR}_FILENO don't get closed on errors, using ManuallyDrop. * Correct signatures of close methods.
Close methods are available on both Std{in,out,err} and Std{in,out,err}Lock, because closing these files should be serialized against reads/writes in other threads. They are *not* available on Std{in,out,err}Raw because that layer of indirection seems to be to do with the set_print/set_panic mechanism, which *doesn't* operate by changing what fds 0/1/2 refer to. That maybe ought to get cleaned up, but Not In This Patchset™. The test is known to succeed on Unix.
Very nearly the same as the code for Unix. (What's with the extra buffer argument to dup2, though?) Note: the duplicate code for opening the null device should get refactored, but we need to decide where to put it first, and that probably needs its own feature discussion.
With the update, I believe I have addressed all of the review comments on the low-level Unix code. I have also added a low-level implementation for Redox, high-level wrappers in io/stdio.rs, and a test (in test/run-pass/). Still missing is a low-level implementation for Windows. It turns out that I don't understand Windows stream/console handles and how Rust works with them well enough to write that part, after all. |
So on Windows there is no equivalent to |
We don't actually need that, though, I think? The original iteration of the Unix code had
I'm afraid this makes no sense at all to me, I think because I don't know which handle you mean by "this handle". So let's be very concrete here: What is wrong with this more-or-less direct translation of the Unix operations to Win32? let hNullDev = CreateFileW(L"NUL:", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hNullDev == INVALID_HANDLE_VALUE) return Err(GetLastError());
if (SetStdHandle(STD_OUTPUT_HANDLE, hNullDev)) {
int e = GetLastError();
CloseHandle(hNullDev);
return Err(e);
}
CloseHandle(hNullDev);
return Ok; Specifically, I am guessing at two things that you could have meant, both of which seem extremely unlikely to me, but my intuitions are not tuned for Windows.
Please clarify? |
You claim that this PR is an implementation of #40032 which is specifically about closing stdout so the parent process can be notified that it was closed. However this cannot be done sanely!
|
@zackw functionality like this may need to be a unix-specific extension trait rather than a cross-platform implementation, I agree that the desired semantics here I believe cannot be implemented safely by us on Windows. |
@retep998 I'm sorry, I still don't get it.
So what? (Everything else you said seems to be predicated on the assumption that this is wrong, so let's focus on getting this piece sorted out first.) |
@zackw you can sort of think of it in terms of ownership I think. Something like |
@zackw |
@zackw friendly triage ping! How's this going? |
@carols10cents I don't have a lot of time to work on this right now and I'm not sure when this will change. @retep998 has convinced me that this is not something that can be reasonably implemented on Windows, and that means the methods have to be moved to some kind of unix/redox-specific extension trait (unless having them throw unimplemented! on Windows would be acceptable) and I'm worried that that drags in the unresolved design questions from rust-lang/api-guidelines#61. If someone with more time wants to take over the work I won't stand in the way. |
Ok, so should we close this pr?
…On Dec 12, 2017 9:42 AM, "Zack Weinberg" ***@***.***> wrote:
@carols10cents <https://github.com/carols10cents> I don't have a lot of
time to work on this right now and I'm not sure when this will change.
@retep998 <https://github.com/retep998> has convinced me that this is not
something that can be reasonably implemented on Windows, and that means the
methods have to be moved to some kind of unix/redox-specific extension
trait (unless having them throw unimplemented! on Windows would be
acceptable) and I'm worried that that drags in the unresolved design
questions from rust-lang/api-guidelines#61
<https://github.com/rust-lang-nursery/api-guidelines/issues/61>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#46063 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAL1UmQaZJ_7reNX5hq-JKYmRUOq_z7_ks5s_p7rgaJpZM4QigGo>
.
|
It's been a few weeks now so I'm going to close this for now, but we can always reconsider a resubmission! |
I'm in the middle of a Happy Fun Air Travel Experience™ and needed to kill a couple hours, so here is an incomplete implementation of feature request #40032 (providing a way to close the standard I/O streams).
This is only the low-level code required for Unix. I know how to write the low-level code required for Redox and Windows, but first I need a little guidance through the maze of structs and traits in between the low-level
sys/*/stdio.rs
and application code. Currently this will fail to compile with errors likeI'm pretty sure that's because there are no wrapper functions at higher levels, but I'm really not sure where to put them.