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

LEP-0005 implementation – remove uv_file #1166

Closed
wants to merge 9 commits into from

Conversation

vtjnash
Copy link
Member

@vtjnash vtjnash commented Dec 10, 2016

Since on Windows, HANDLEs are not the same as file descriptors,
confusing the two meant that almost all APIs in libuv had to go through
a thin compatibility layer, adding needless complication.

This removes that layer of external indirection and instead
works with the native Win32 API directly.

This is the implementation for libuv/leps#8 which closes #856.

APIs added:

  • uv_get_osfhandle
  • uv_convert_fd_to_handle
  • uv_dup
  • UV_STDIN_FD / UV_STDOUT_FD / UV_STDERR_FD

APIs removed:

  • uv_poll_init_socket (now identical to uv_poll_init)

TODO list:

  • documentation updates
  • merge LEP 5

@bnoordhuis
Copy link
Member

It's not clear to me why you removed uv_poll_init(). It's used a lot, removing it is rather disruptive.

@vtjnash
Copy link
Member Author

vtjnash commented Dec 12, 2016

On Windows, it's an alias for uv_poll_init_socket (on non-windows, the aliasing is reversed). In this case, I opted for removing the name uv_poll_init where the API changed on Windows (and keeping the name uv_poll_init_socket, which isn't affected by this change), to help FFI users find places they need to fix their code. But I can make this go either way, and I opened this as WIP to get feedback on that.

@saghul
Copy link
Member

saghul commented Dec 12, 2016

I'd rather keep uv_poll_init for consistency with the rest of the handles.

Copy link
Member

@saghul saghul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a first review round! I'm happy with the code reduction and how fs operations are simpler :-)

I left a bunch of comments but nothing major. Please address them, rebase and I'll kick off a CI run and give it another review round.

include/uv.h Outdated
@@ -431,10 +427,56 @@ UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value);
UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value);

UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
UV_EXTERN int uv_dup(uv_os_fd_t fd, uv_os_fd_t* dup);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you rename the parameter to dupfd

include/uv.h Outdated
#endif

INLINE static uv_os_fd_t uv_get_osfhandle(int fd)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: brace on the previous line

include/uv.h Outdated
{
#ifdef _WIN32
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
/* So if you plan on using invalid fd, you will need to install a _CrtSetReportHook handler */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this a block comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have that handler added automaticaly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, libuv can't add that handler automatically as the _CrtSetReportHook may be non-unique in the process. Since libuv won't use file-descriptors after this change, it'll never see an invalid one.

include/uv.h Outdated


INLINE static uv_os_fd_t uv_convert_fd_to_handle(int fd)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: braces

include/uv.h Outdated
# define INLINE inline
#endif

INLINE static uv_os_fd_t uv_get_osfhandle(int fd)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please define these in uv-common.c, no need to inline them, IMHO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inlining them is the only way to get the linker to point to the right copy of this function.

result = -1;
break;
}
/* hopefully n == n_out here (e.g. that fd_out wasn't opened non-blocking mode) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we account for the case where that doesn't happen? if the answer it's "never", place an assert

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just documenting an existing potential deficiency (_write is just a thin wrapper for WriteFile, although I shudder to think of what this code used to do if someone accidentally opened a fd with _O_TEXT ). I don't think anyone is passing in a pipe opened in non-blocking mode intentionally.

} else {
fs__open(req);
return req->result;
if (req->result < 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the previous version was more readable, please revert this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old version does a silent truncating cast (from HANDLE to int), #1166 (comment)

if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
/* If fdopt.data.file is pointing at one of the pseudo stdio handles,
* but it is not valid ignore the error. */
if ((fdopt.data.file == UV_STDIN_FD || fdopt.data.file == UV_STDOUT_FD || fdopt.data.file == UV_STDERR_FD) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: long line

src/win/tty.c Outdated
*/
handle = GetStdHandle((DWORD)(uintptr_t) handle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this construct seems to repeat a bit, maybe create an internal uv__dup_stdio_handle helper?

@@ -376,7 +376,8 @@ int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) {
r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb);
ASSERT(r == 0);
} else {
r = uv_pipe_open(&ctx2.channel, 0);
uv_os_fd_t stdin_handle = uv_convert_fd_to_handle(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't UV_STDIN_FD work here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would work, since for the purposes of this test harness they happen to get set to the same stream. However, testing with fd = 0 is slightly more accurate – and makes for better example code for the expected nodejs usage.

@vtjnash
Copy link
Member Author

vtjnash commented Feb 20, 2017

I've updated the PR based on your review feedback. Let me know what else needs to be done here.

@saghul
Copy link
Member

saghul commented Mar 23, 2017

Hey @vtjnash I'm ready to land this, once we have a bit of documentation. I seem to have forgotten to point that out earlier, sorry about that.

We need:

@vtjnash vtjnash changed the title WIP: LEP-0005 implementation – remove uv_file LEP-0005 implementation – remove uv_file Mar 24, 2017
@vtjnash
Copy link
Member Author

vtjnash commented Mar 24, 2017

Thanks @sagful. I had documentation update in my TODO list at the top, and was just waiting for the LEP to be merged. I also added the migration guide – thanks for mentioned that too. Let me know if it looks good (or has any typos :P).

Copy link
Member

@saghul saghul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more documentation fixes are required. Also please drop the public uv_dup.

@@ -179,6 +179,12 @@ just for some handle types.
Be very careful when using this function. libuv assumes it's in control of the file
descriptor so any change to it may lead to malfunction.

.. c:function:: int uv_dup(uv_os_fd_t fd, uv_os_fd_t* dupfd)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we only use this internally, please make it private.


Destructively converts a file descriptor in the C runtime
to the OS-dependent handle.
Upon return, the input ``fd`` parameter is invalid and closed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add some more details mentioning this only makes sense on windows, what function uses internally, etc.

@@ -161,7 +161,7 @@ API
Cleanup request. Must be called after a request is finished to deallocate
any memory libuv might have allocated.

.. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
.. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_os_fd_t file, uv_fs_cb cb)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a .. versionchanged:: for each of these

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that be v2.0.0, or something else?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a fixup! commit to address the doc comments, assuming for now that I should go with v2.0.0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's the one, thanks!

Constants ``UV_STDIN_FD``, ``UV_STDOUT_FD``, and ``UV_STDERR_FD`` provide cross-platform
references to the standard constants for stdio access, and can be used in place of any ``uv_os_fd_t``.
Existing clients can transition to the new API by using the conversion function ``uv_convert_fd_to_handle``
defined in the libuv header file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please expand a bit here: show an example on how one would open stdin before and how to do it now.

include/uv.h Outdated
# define INLINE inline
#endif

INLINE static uv_os_fd_t uv_get_osfhandle(int fd) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move these to uv-common. We tend not to have implementations in uv.h.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These need to be statically linked into the caller, which is why they can't go in the libuv library.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recently opened issue #1291 demonstrates why it is required that this code be part of the header and not the library.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see! Can you please add a comment so someone doesn't f*ck this up in the future?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, added.

@saghul
Copy link
Member

saghul commented Apr 24, 2017

Damn, GH doesn't send notifications when you add new commits so I missed this. I'll review today @vtjnash.

Copy link
Member

@saghul saghul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM once uv_dup is removed from the public API. That's the only thing left, fantastic work here!

@vtjnash
Copy link
Member Author

vtjnash commented Apr 26, 2017

Ok, I added a commit to remove uv_dup from the public API (I'm assuming you'll squash when you merge).

@vtjnash
Copy link
Member Author

vtjnash commented May 15, 2017

bump.

@vtjnash
Copy link
Member Author

vtjnash commented May 24, 2017

All comments have been addressed, should be ready to merge.

@saghul
Copy link
Member

saghul commented May 29, 2017

@vtjnash
Copy link
Member Author

vtjnash commented May 29, 2017

Thanks - looks like I need to add the io.h header.

cjihrig pushed a commit that referenced this pull request May 30, 2017
The uv__get_osfhandle() function is a private functio of the
Windows subsystem, and its used to get a Windows HANDLE out
of a file descriptor number.

The motivation behind making this function public is to
allow Node.js programs to pass file descriptors created
using fs.open() to native Node.js C++ add-ons, and be able to
successfully convert them to Windows HANDLEs.

Refs: #1166
Refs: nodejs/node#6369
Fixes: #1291
PR-URL: #1323
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Since on Windows, HANDLEs are not the same as file descriptors,
confusing the two meant that almost all APIs in libuv had to go through
a thin compatibility layer, adding needless complication.

This removes that layer of external indirection and instead
works with the native Win32 API directly.
@vtjnash
Copy link
Member Author

vtjnash commented Jun 23, 2017

Alright, I've tried to cleanup the list of headers affected by this change to help avoid accidentally referencing shared state in msvcrt.dll where not intended. I think this should address the CI test failure, but would be best to re-run that to check that I didn't miss any.

@santigimeno
Copy link
Member

@santigimeno
Copy link
Member

@santigimeno
Copy link
Member

@santigimeno
Copy link
Member

@saghul
Copy link
Member

saghul commented Jul 4, 2017

@saghul
Copy link
Member

saghul commented Jul 4, 2017

💚 landing!

saghul pushed a commit that referenced this pull request Jul 4, 2017
Since on Windows HANDLEs are not the same as file descriptors,
confusing the two meant that almost all APIs in libuv had to go through
a thin compatibility layer, adding needless complication.

This removes that layer of external indirection and instead
works with the native Win32 API directly.

See: https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md

PR-URL: #1166
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
@saghul
Copy link
Member

saghul commented Jul 4, 2017

Landed in 68dafe9, cheers @vtjnash! This was a lot of work and it took a long time to review, I'm sorry about the delay on my side and I'm grateful you stuck with it and took it over the finish line. 🍸

@saghul saghul closed this Jul 4, 2017
@saghul
Copy link
Member

saghul commented Jul 4, 2017

@libuv/collaborators I'll try to merge v1.x into master this weekend. It will be a messy one after this commit, but once done the next ones should be easier.

@vtjnash
Copy link
Member Author

vtjnash commented Jul 4, 2017

😀😀😀💥💥💥Thanks!

fdopen added a commit to fdopen/libuv that referenced this pull request Jul 29, 2017
It was already wrong inside libuv#974 (`UV_EINVAL` and `-EINVAL` are different on Windows), but libuv#1166 made it even worse. It's now wrong on windows and *nix 😆
fdopen added a commit to fdopen/libuv that referenced this pull request Jul 29, 2017
It was already wrong inside libuv#974 (`UV_EINVAL` and `-EINVAL` are different on Windows), but libuv#1166 made it even worse. It's now wrong on windows and *nix 😆
cjihrig pushed a commit that referenced this pull request Jul 31, 2017
Refs: #974
Refs: #1166
PR-URL: #1446
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
@vtjnash vtjnash deleted the jn/kill-msvcrt branch November 15, 2017 15:27
@vtjnash vtjnash mentioned this pull request Aug 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants