diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 1f504cb3..400d8c05 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -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 diff --git a/include/uv.h b/include/uv.h index cc385d01..99ed9771 100644 --- a/include/uv.h +++ b/include/uv.h @@ -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, diff --git a/src/unix/core.c b/src/unix/core.c index 965aae79..5be878dd 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -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; } diff --git a/src/win/core.c b/src/win/core.c index 26ad3929..ca9f2cc5 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -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; } diff --git a/test/test-embed.c b/test/test-embed.c index 06137456..145819a6 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -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 @@ -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 }