diff --git a/include/uv-win.h b/include/uv-win.h index 4abb294c05..70a5c8ff8a 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -315,7 +315,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); /* The loop's I/O completion port */ \ HANDLE iocp; \ /* The current time according to the event loop. in msecs. */ \ - uint64_t time; \ + /* Don't access these fields directly. Use uv__loop_time() instead. */ \ + uint64_t cached_time; \ + int cached_time_is_valid; \ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ /* is empty, tail_ is NULL. If there is only one item, */ \ /* tail_->next_req == tail_ */ \ diff --git a/src/unix/timer.c b/src/unix/timer.c index ca3ec3db95..c77b065ae6 100644 --- a/src/unix/timer.c +++ b/src/unix/timer.c @@ -26,6 +26,11 @@ #include +uint64_t uv_now(const uv_loop_t* loop) { + return loop->time; +} + + static int timer_less_than(const struct heap_node* ha, const struct heap_node* hb) { const uv_timer_t* a; diff --git a/src/uv-common.c b/src/uv-common.c index 97727baa54..733c8f0f1e 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -391,12 +391,6 @@ void uv_stop(uv_loop_t* loop) { } -uint64_t uv_now(const uv_loop_t* loop) { - return loop->time; -} - - - size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { unsigned int i; size_t bytes; diff --git a/src/win/core.c b/src/win/core.c index c9e4c88fa7..a3c84ade0f 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -133,11 +133,8 @@ int uv_loop_init(uv_loop_t* loop) { if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); - /* To prevent uninitialized memory access, loop->time must be intialized - * to zero before calling uv_update_time for the first time. - */ - loop->time = 0; - uv_update_time(loop); + loop->cached_time = 0; + loop->cached_time_is_valid = 0; QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->handle_queue); diff --git a/src/win/internal.h b/src/win/internal.h index d87402b73a..36c2293a5d 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -245,6 +245,7 @@ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); DWORD uv__next_timeout(const uv_loop_t* loop); void uv__time_forward(uv_loop_t* loop, uint64_t msecs); void uv_process_timers(uv_loop_t* loop); +uint64_t uv__loop_time(const uv_loop_t* loop); /* diff --git a/src/win/timer.c b/src/win/timer.c index 0da541a2c8..8e93f02f5c 100644 --- a/src/win/timer.c +++ b/src/win/timer.c @@ -33,14 +33,34 @@ void uv_update_time(uv_loop_t* loop) { - uint64_t new_time = uv__hrtime(UV__MILLISEC); - if (new_time > loop->time) { - loop->time = new_time; - } + /* Invalidate the loop time, so that the next invocation of uv__loop_time() + * will actually update it. + */ + loop->cached_time_is_valid = 0; } void uv__time_forward(uv_loop_t* loop, uint64_t msecs) { - loop->time += msecs; + loop->cached_time += msecs; + loop->cached_time_is_valid = 0; +} + +uint64_t uv__loop_time(const uv_loop_t* loop) { + uv_loop_t* mutable_loop; + uint64_t new_time; + if (!loop->cached_time_is_valid) { + new_time = uv__hrtime(UV__MILLISEC); + mutable_loop = (uv_loop_t*) loop; + if (new_time > mutable_loop->cached_time) { + mutable_loop->cached_time = new_time; + } + mutable_loop->cached_time_is_valid = 1; + } + + return loop->cached_time; +} + +uint64_t uv_now(const uv_loop_t* loop) { + return uv__loop_time(loop); } @@ -104,7 +124,7 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, uv_timer_stop(handle); handle->timer_cb = timer_cb; - handle->due = get_clamped_due_time(loop->time, timeout); + handle->due = get_clamped_due_time(uv__loop_time(loop), timeout); handle->repeat = repeat; uv__handle_start(handle); @@ -168,7 +188,7 @@ DWORD uv__next_timeout(const uv_loop_t* loop) { */ timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers); if (timer) { - delta = timer->due - loop->time; + delta = timer->due - uv__loop_time(loop); if (delta >= UINT_MAX - 1) { /* A timeout value of UINT_MAX means infinite, so that's no good. */ return UINT_MAX - 1; @@ -190,7 +210,7 @@ void uv_process_timers(uv_loop_t* loop) { /* Call timer callbacks */ for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); - timer != NULL && timer->due <= loop->time; + timer != NULL && timer->due <= uv__loop_time(loop); timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { uv_timer_stop(timer);