Skip to content

Commit

Permalink
win: evaluate timers when system wakes up
Browse files Browse the repository at this point in the history
When Windows resumes after sleep GetQueuedCompletionStatus timeout is
not updated. This commit adds a method for signaling all loops to
wake up and update their timers.

Fixes: nodejs/node#6763
  • Loading branch information
bzoz committed Aug 1, 2016
1 parent f614b43 commit bb7a368
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
4 changes: 3 additions & 1 deletion include/uv-win.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
/* Threadpool */ \
void* wq[2]; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async;
uv_async_t wq_async; \
/* Queue of all active uv_loops */ \
void* uv_loops[2];

#define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \
Expand Down
50 changes: 47 additions & 3 deletions src/win/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "uv.h"
#include "internal.h"
#include "queue.h"
#include "handle-inl.h"
#include "req-inl.h"

Expand Down Expand Up @@ -80,6 +81,38 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
}
#endif

static QUEUE uv_loops;
static uv_mutex_t uv_loops_lock;

static void uv__loops_init() {
uv_mutex_init(&uv_loops_lock);
QUEUE_INIT(&uv_loops);
}

static void uv__loops_add(uv_loop_t* loop) {
uv_mutex_lock(&uv_loops_lock);
QUEUE_INIT(&loop->uv_loops);
QUEUE_INSERT_TAIL(&uv_loops, &loop->uv_loops);
uv_mutex_unlock(&uv_loops_lock);
}

static void uv__loops_remove(uv_loop_t* loop) {
uv_mutex_lock(&uv_loops_lock);
QUEUE_REMOVE(&loop->uv_loops);
uv_mutex_unlock(&uv_loops_lock);
}

void uv_wake_all_loops() {
QUEUE *q;
uv_loop_t* loop;
uv_mutex_lock(&uv_loops_lock);
QUEUE_FOREACH(q, &uv_loops) {
loop = (uv_loop_t*)QUEUE_DATA(q, uv_loop_t, uv_loops);
if (loop->iocp != INVALID_HANDLE_VALUE)
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
}
uv_mutex_unlock(&uv_loops_lock);
}

static void uv_init(void) {
/* Tell Windows that we will handle critical errors. */
Expand All @@ -101,6 +134,9 @@ static void uv_init(void) {
_CrtSetReportHook(uv__crt_dbg_report_handler);
#endif

/* Initialize tracking of all uv loops */
uv__loops_init();

/* Fetch winapi function pointers. This must be done first because other
* initialization code might need these function pointers to be loaded.
*/
Expand Down Expand Up @@ -178,6 +214,8 @@ int uv_loop_init(uv_loop_t* loop) {
uv__handle_unref(&loop->wq_async);
loop->wq_async.flags |= UV__HANDLE_INTERNAL;

uv__loops_add(loop);

return 0;

fail_async_init:
Expand All @@ -199,6 +237,8 @@ void uv__once_init(void) {
void uv__loop_close(uv_loop_t* loop) {
size_t i;

uv__loops_remove(loop);

/* close the async handle without needing an extra loop iteration */
assert(!loop->wq_async.async_sent);
loop->wq_async.close_cb = NULL;
Expand Down Expand Up @@ -323,9 +363,13 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {

if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
/* Package was dequeued, but see if it is not a empty package
* meant only to wake us up.
*/
if (overlappeds[i].lpOverlapped) {
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
}
}

/* Some time might have passed waiting for I/O,
Expand Down
5 changes: 5 additions & 0 deletions src/win/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,4 +381,9 @@ extern int uv_tcp_non_ifs_lsp_ipv6;
extern struct sockaddr_in uv_addr_ip4_any_;
extern struct sockaddr_in6 uv_addr_ip6_any_;

/*
* Wake all loops with fake message
*/
void uv_wake_all_loops();

#endif /* UV_WIN_INTERNAL_H_ */

0 comments on commit bb7a368

Please sign in to comment.