unix,windows: fix timer order in case of same timeout
Compare start_id of timer handles when they have the same timeout. start_id is allocated with loop->timer_counter in uv_timer_start.
This commit is contained in:
parent
c15d4a7c62
commit
fadfeaf6ec
@ -178,6 +178,7 @@ typedef struct {
|
||||
uv__io_t signal_io_watcher; \
|
||||
uv_signal_t child_watcher; \
|
||||
int emfile_fd; \
|
||||
uint64_t timer_counter; \
|
||||
UV_PLATFORM_LOOP_FIELDS \
|
||||
|
||||
#define UV_REQ_TYPE_PRIVATE /* empty */
|
||||
@ -265,7 +266,8 @@ typedef struct {
|
||||
} tree_entry; \
|
||||
uv_timer_cb timer_cb; \
|
||||
uint64_t timeout; \
|
||||
uint64_t repeat;
|
||||
uint64_t repeat; \
|
||||
uint64_t start_id;
|
||||
|
||||
#define UV_GETADDRINFO_PRIVATE_FIELDS \
|
||||
struct uv__work work_req; \
|
||||
|
||||
@ -302,7 +302,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
/* Counter to keep track of active tcp streams */ \
|
||||
unsigned int active_tcp_streams; \
|
||||
/* Counter to keep track of active udp streams */ \
|
||||
unsigned int active_udp_streams;
|
||||
unsigned int active_udp_streams; \
|
||||
/* Counter to started timer */ \
|
||||
uint64_t timer_counter;
|
||||
|
||||
#define UV_REQ_TYPE_PRIVATE \
|
||||
/* TODO: remove the req suffix */ \
|
||||
@ -487,6 +489,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
RB_ENTRY(uv_timer_s) tree_entry; \
|
||||
int64_t due; \
|
||||
int64_t repeat; \
|
||||
uint64_t start_id; \
|
||||
uv_timer_cb timer_cb;
|
||||
|
||||
#define UV_ASYNC_PRIVATE_FIELDS \
|
||||
|
||||
@ -57,6 +57,8 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
|
||||
loop->backend_fd = -1;
|
||||
loop->emfile_fd = -1;
|
||||
|
||||
loop->timer_counter = 0;
|
||||
|
||||
if (uv__platform_loop_init(loop, default_loop))
|
||||
return -1;
|
||||
|
||||
|
||||
@ -27,9 +27,13 @@ static int uv__timer_cmp(const uv_timer_t* a, const uv_timer_t* b) {
|
||||
return -1;
|
||||
if (a->timeout > b->timeout)
|
||||
return 1;
|
||||
if (a < b)
|
||||
/*
|
||||
* compare start_id when both has the same timeout. start_id is
|
||||
* allocated with loop->timer_counter in uv_timer_start().
|
||||
*/
|
||||
if (a->start_id < b->start_id)
|
||||
return -1;
|
||||
if (a > b)
|
||||
if (a->start_id > b->start_id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -59,6 +63,8 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
handle->timer_cb = cb;
|
||||
handle->timeout = handle->loop->time + timeout;
|
||||
handle->repeat = repeat;
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
RB_INSERT(uv__timers, &handle->loop->timer_handles, handle);
|
||||
uv__handle_start(handle);
|
||||
|
||||
@ -115,6 +115,8 @@ static void uv_loop_init(uv_loop_t* loop) {
|
||||
loop->active_tcp_streams = 0;
|
||||
loop->active_udp_streams = 0;
|
||||
|
||||
loop->timer_counter = 0;
|
||||
|
||||
loop->last_err = uv_ok_;
|
||||
}
|
||||
|
||||
|
||||
@ -55,9 +55,13 @@ static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
|
||||
return -1;
|
||||
if (a->due > b->due)
|
||||
return 1;
|
||||
if ((intptr_t)a < (intptr_t)b)
|
||||
/*
|
||||
* compare start_id when both has the same due. start_id is
|
||||
* allocated with loop->timer_counter in uv_timer_start().
|
||||
*/
|
||||
if (a->start_id < b->start_id)
|
||||
return -1;
|
||||
if ((intptr_t)a > (intptr_t)b)
|
||||
if (a->start_id > b->start_id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -98,6 +102,9 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout,
|
||||
handle->flags |= UV_HANDLE_ACTIVE;
|
||||
uv__handle_start(handle);
|
||||
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
|
||||
assert(old == NULL);
|
||||
|
||||
|
||||
@ -96,6 +96,7 @@ TEST_DECLARE (error_message)
|
||||
TEST_DECLARE (timer)
|
||||
TEST_DECLARE (timer_again)
|
||||
TEST_DECLARE (timer_start_twice)
|
||||
TEST_DECLARE (timer_order)
|
||||
TEST_DECLARE (idle_starvation)
|
||||
TEST_DECLARE (loop_handles)
|
||||
TEST_DECLARE (get_loadavg)
|
||||
@ -334,6 +335,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (timer)
|
||||
TEST_ENTRY (timer_again)
|
||||
TEST_ENTRY (timer_start_twice)
|
||||
TEST_ENTRY (timer_order)
|
||||
|
||||
TEST_ENTRY (idle_starvation)
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ static int once_cb_called = 0;
|
||||
static int once_close_cb_called = 0;
|
||||
static int repeat_cb_called = 0;
|
||||
static int repeat_close_cb_called = 0;
|
||||
static int order_cb_called = 0;
|
||||
|
||||
static int64_t start_time;
|
||||
|
||||
@ -153,3 +154,51 @@ TEST_IMPL(timer_start_twice) {
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void order_cb_a(uv_timer_t *handle, int status) {
|
||||
ASSERT(order_cb_called++ == *(int*)handle->data);
|
||||
}
|
||||
|
||||
|
||||
static void order_cb_b(uv_timer_t *handle, int status) {
|
||||
ASSERT(order_cb_called++ == *(int*)handle->data);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(timer_order) {
|
||||
int first;
|
||||
int second;
|
||||
uv_timer_t handle_a;
|
||||
uv_timer_t handle_b;
|
||||
|
||||
first = 0;
|
||||
second = 1;
|
||||
ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_a));
|
||||
ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_b));
|
||||
|
||||
/* Test for starting handle_a then handle_b */
|
||||
handle_a.data = &first;
|
||||
ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0));
|
||||
handle_b.data = &second;
|
||||
ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(order_cb_called == 2);
|
||||
|
||||
ASSERT(0 == uv_timer_stop(&handle_a));
|
||||
ASSERT(0 == uv_timer_stop(&handle_b));
|
||||
|
||||
/* Test for starting handle_b then handle_a */
|
||||
order_cb_called = 0;
|
||||
handle_b.data = &first;
|
||||
ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0));
|
||||
|
||||
handle_a.data = &second;
|
||||
ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(order_cb_called == 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user