win: return IOCP HANDLE in uv_backend_fd

Change the return type from int to uv_os_fd_t so we can return an int on
Unix and a HANDLE on Windows.

Applications can use this to poll the libuv event loop from another
thread as is now possible on Unix.

The test implementation is based on what Electron does:
https://github.com/electron/electron/blob/master/atom/common/node_bindings_win.cc

Refs: https://github.com/libuv/libuv/issues/965
PR-URL: https://github.com/libuv/libuv/pull/1007
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Imran Iqbal <imran@imraniqbal.org>
This commit is contained in:
Saúl Ibarra Corretgé 2016-08-19 13:42:43 +01:00
parent 1f21b19e08
commit daf8a45d44
5 changed files with 60 additions and 24 deletions

View File

@ -121,10 +121,10 @@ API
Returns the size of the `uv_loop_t` structure. Useful for FFI binding
writers who don't want to know the structure layout.
.. c:function:: int uv_backend_fd(const uv_loop_t* loop)
.. c:function:: uv_os_fd_t uv_backend_fd(const uv_loop_t* loop)
Get backend file descriptor. Only kqueue, epoll and event ports are
supported.
Get backend file descriptor. Returns the epoll / kqueue / event ports file
descriptor on Unix and the IOCP `HANDLE` on Windows.
This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to
poll in one thread and run the event loop's callbacks in another see
@ -134,6 +134,9 @@ API
Embedding a kqueue fd in another kqueue pollset doesn't work on all platforms. It's not
an error to add the fd but it never generates events.
.. versionchanged:: 2.0.0: added support for Windows and changed return type
to ``uv_os_fd_t``.
.. c:function:: int uv_backend_timeout(const uv_loop_t* loop)
Get the poll timeout. The return value is in milliseconds, or -1 for no

View File

@ -280,7 +280,7 @@ UV_EXTERN int uv_has_ref(const uv_handle_t*);
UV_EXTERN void uv_update_time(uv_loop_t*);
UV_EXTERN uint64_t uv_now(const uv_loop_t*);
UV_EXTERN int uv_backend_fd(const uv_loop_t*);
UV_EXTERN uv_os_fd_t uv_backend_fd(const uv_loop_t*);
UV_EXTERN int uv_backend_timeout(const uv_loop_t*);
typedef void (*uv_alloc_cb)(uv_handle_t* handle,

View File

@ -283,7 +283,7 @@ int uv_is_closing(const uv_handle_t* handle) {
}
int uv_backend_fd(const uv_loop_t* loop) {
uv_os_fd_t uv_backend_fd(const uv_loop_t* loop) {
return loop->backend_fd;
}

View File

@ -264,8 +264,8 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
}
int uv_backend_fd(const uv_loop_t* loop) {
return -1;
uv_os_fd_t uv_backend_fd(const uv_loop_t* loop) {
return loop->iocp;
}

View File

@ -41,7 +41,7 @@
# endif
#endif
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) || defined(_WIN32)
#if defined(HAVE_KQUEUE)
# include <sys/types.h>
@ -62,28 +62,59 @@ static volatile int embed_closed;
static int embed_timer_called;
static void embed_thread_runner(void* arg) {
#if defined(_WIN32)
static void embed_thread_poll_win(HANDLE iocp, int timeout) {
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
GetQueuedCompletionStatus(iocp,
&bytes,
&key,
&overlapped,
timeout);
/* Give the event back so the loop can deal with it. */
if (overlapped != NULL)
PostQueuedCompletionStatus(iocp,
bytes,
key,
overlapped);
}
#else
static void embed_thread_poll_unix(int fd, int timeout) {
int r;
int fd;
do {
#if defined(HAVE_KQUEUE)
struct timespec ts;
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
r = kevent(fd, NULL, 0, NULL, 0, &ts);
#elif defined(HAVE_EPOLL)
{
struct epoll_event ev;
r = epoll_wait(fd, &ev, 1, timeout);
}
#endif
} while (r == -1 && errno == EINTR);
}
#endif /* !_WIN32 */
static void embed_thread_runner(void* arg) {
uv_os_fd_t fd;
int timeout;
while (!embed_closed) {
fd = uv_backend_fd(uv_default_loop());
timeout = uv_backend_timeout(uv_default_loop());
do {
#if defined(HAVE_KQUEUE)
struct timespec ts;
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
r = kevent(fd, NULL, 0, NULL, 0, &ts);
#elif defined(HAVE_EPOLL)
{
struct epoll_event ev;
r = epoll_wait(fd, &ev, 1, timeout);
}
#if defined(_WIN32)
embed_thread_poll_win(fd, timeout);
#else
embed_thread_poll_unix(fd, timeout);
#endif
} while (r == -1 && errno == EINTR);
uv_async_send(&embed_async);
uv_sem_wait(&embed_sem);
}
@ -107,7 +138,7 @@ static void embed_timer_cb(uv_timer_t* timer) {
TEST_IMPL(embed) {
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) || defined(_WIN32)
uv_loop_t external;
ASSERT(0 == uv_loop_init(&external));
@ -132,7 +163,9 @@ TEST_IMPL(embed) {
uv_loop_close(&external);
ASSERT(embed_timer_called == 1);
#endif
return 0;
#else
RETURN_SKIP("Not supported in the current platform.");
#endif
}