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:
parent
1f21b19e08
commit
daf8a45d44
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user