1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18 * IN THE SOFTWARE.
19 */
20
21 #include "uv.h"
22 #include "uv-common.h"
23 #include "heap-inl.h"
24
25 #include <assert.h>
26 #include <limits.h>
27
28 #ifdef ASYNC_STACKTRACE
29 #include "dfx/async_stack/libuv_async_stack.h"
30 #endif
31
timer_heap(const uv_loop_t * loop)32 static struct heap *timer_heap(const uv_loop_t* loop) {
33 #ifdef _WIN32
34 return (struct heap*) loop->timer_heap;
35 #else
36 return (struct heap*) &loop->timer_heap;
37 #endif
38 }
39
40
timer_less_than(const struct heap_node * ha,const struct heap_node * hb)41 static int timer_less_than(const struct heap_node* ha,
42 const struct heap_node* hb) {
43 const uv_timer_t* a;
44 const uv_timer_t* b;
45
46 a = container_of(ha, uv_timer_t, heap_node);
47 b = container_of(hb, uv_timer_t, heap_node);
48
49 if (a->timeout < b->timeout)
50 return 1;
51 if (b->timeout < a->timeout)
52 return 0;
53
54 /* Compare start_id when both have the same timeout. start_id is
55 * allocated with loop->timer_counter in uv_timer_start().
56 */
57 return a->start_id < b->start_id;
58 }
59
60
uv_timer_init(uv_loop_t * loop,uv_timer_t * handle)61 int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
62 uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
63 handle->timer_cb = NULL;
64 handle->timeout = 0;
65 handle->repeat = 0;
66 return 0;
67 }
68
69
uv_timer_start(uv_timer_t * handle,uv_timer_cb cb,uint64_t timeout,uint64_t repeat)70 int uv_timer_start(uv_timer_t* handle,
71 uv_timer_cb cb,
72 uint64_t timeout,
73 uint64_t repeat) {
74 uint64_t clamped_timeout;
75
76 if (uv__is_closing(handle) || cb == NULL)
77 return UV_EINVAL;
78
79 if (uv__is_active(handle))
80 uv_timer_stop(handle);
81
82 clamped_timeout = handle->loop->time + timeout;
83 if (clamped_timeout < timeout)
84 clamped_timeout = (uint64_t) -1;
85
86 handle->timer_cb = cb;
87 handle->timeout = clamped_timeout;
88 handle->repeat = repeat;
89 /* start_id is the second index to be compared in timer_less_than() */
90 handle->start_id = handle->loop->timer_counter++;
91
92 #ifdef ASYNC_STACKTRACE
93 handle->u.reserved[3] = (void*)LibuvCollectAsyncStack();
94 #endif
95
96 heap_insert(timer_heap(handle->loop),
97 (struct heap_node*) &handle->heap_node,
98 timer_less_than);
99 uv__handle_start(handle);
100 #ifdef __linux__
101 if (uv_check_data_valid((struct uv_loop_data*)handle->loop->data) == 0) {
102 uv_async_send(&handle->loop->wq_async);
103 }
104 #endif
105 return 0;
106 }
107
108
uv_timer_stop(uv_timer_t * handle)109 int uv_timer_stop(uv_timer_t* handle) {
110 if (!uv__is_active(handle))
111 return 0;
112
113 heap_remove(timer_heap(handle->loop),
114 (struct heap_node*) &handle->heap_node,
115 timer_less_than);
116 uv__handle_stop(handle);
117
118 return 0;
119 }
120
121
uv_timer_again(uv_timer_t * handle)122 int uv_timer_again(uv_timer_t* handle) {
123 if (handle->timer_cb == NULL)
124 return UV_EINVAL;
125
126 if (handle->repeat) {
127 uv_timer_stop(handle);
128 uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
129 }
130
131 return 0;
132 }
133
134
uv_timer_set_repeat(uv_timer_t * handle,uint64_t repeat)135 void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
136 handle->repeat = repeat;
137 }
138
139
uv_timer_get_repeat(const uv_timer_t * handle)140 uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
141 return handle->repeat;
142 }
143
144
uv_timer_get_due_in(const uv_timer_t * handle)145 uint64_t uv_timer_get_due_in(const uv_timer_t* handle) {
146 if (handle->loop->time >= handle->timeout)
147 return 0;
148
149 return handle->timeout - handle->loop->time;
150 }
151
152
uv__next_timeout(const uv_loop_t * loop)153 int uv__next_timeout(const uv_loop_t* loop) {
154 const struct heap_node* heap_node;
155 const uv_timer_t* handle;
156 uint64_t diff;
157
158 heap_node = heap_min(timer_heap(loop));
159 if (heap_node == NULL)
160 return -1; /* block indefinitely */
161
162 handle = container_of(heap_node, uv_timer_t, heap_node);
163 if (handle->timeout <= loop->time)
164 return 0;
165
166 diff = handle->timeout - loop->time;
167 if (diff > INT_MAX)
168 diff = INT_MAX;
169
170 return (int) diff;
171 }
172
173
uv__run_timers(uv_loop_t * loop)174 void uv__run_timers(uv_loop_t* loop) {
175 struct heap_node* heap_node;
176 uv_timer_t* handle;
177
178 for (;;) {
179 heap_node = heap_min(timer_heap(loop));
180 if (heap_node == NULL)
181 break;
182
183 handle = container_of(heap_node, uv_timer_t, heap_node);
184 if (handle->timeout > loop->time)
185 break;
186
187 uv_timer_stop(handle);
188 uv_timer_again(handle);
189 #ifdef ASYNC_STACKTRACE
190 LibuvSetStackId((uint64_t)handle->u.reserved[3]);
191 #endif
192 handle->timer_cb(handle);
193 }
194 }
195
196
uv__timer_close(uv_timer_t * handle)197 void uv__timer_close(uv_timer_t* handle) {
198 uv_timer_stop(handle);
199 }
200