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 #if defined(USE_OHOS_DFX) && defined(__aarch64__)
63 uv__multi_thread_check_unify(loop, __func__);
64 #endif
65 uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
66 handle->timer_cb = NULL;
67 handle->timeout = 0;
68 handle->repeat = 0;
69 return 0;
70 }
71
72
uv_timer_start(uv_timer_t * handle,uv_timer_cb cb,uint64_t timeout,uint64_t repeat)73 int uv_timer_start(uv_timer_t* handle,
74 uv_timer_cb cb,
75 uint64_t timeout,
76 uint64_t repeat) {
77 uint64_t clamped_timeout;
78 #if defined(USE_OHOS_DFX) && defined(__aarch64__)
79 uv__multi_thread_check_unify(handle->loop, __func__);
80 #endif
81
82 if (uv__is_closing(handle) || cb == NULL)
83 return UV_EINVAL;
84
85 if (uv__is_active(handle))
86 uv_timer_stop(handle);
87
88 clamped_timeout = handle->loop->time + timeout;
89 if (clamped_timeout < timeout)
90 clamped_timeout = (uint64_t) -1;
91
92 handle->timer_cb = cb;
93 handle->timeout = clamped_timeout;
94 handle->repeat = repeat;
95 /* start_id is the second index to be compared in timer_less_than() */
96 handle->start_id = handle->loop->timer_counter++;
97
98 #ifdef ASYNC_STACKTRACE
99 handle->u.reserved[3] = (void*)LibuvCollectAsyncStack();
100 #endif
101
102 heap_insert(timer_heap(handle->loop),
103 (struct heap_node*) &handle->heap_node,
104 timer_less_than);
105 uv__handle_start(handle);
106 #ifdef __linux__
107 if (uv_check_data_valid((struct uv_loop_data*)handle->loop->data) == 0) {
108 uv_async_send(&handle->loop->wq_async);
109 }
110 #endif
111 return 0;
112 }
113
114
uv_timer_stop(uv_timer_t * handle)115 int uv_timer_stop(uv_timer_t* handle) {
116 #if defined(USE_OHOS_DFX) && defined(__aarch64__)
117 uv__multi_thread_check_unify(handle->loop, __func__);
118 #endif
119 if (!uv__is_active(handle))
120 return 0;
121
122 heap_remove(timer_heap(handle->loop),
123 (struct heap_node*) &handle->heap_node,
124 timer_less_than);
125 uv__handle_stop(handle);
126
127 return 0;
128 }
129
130
uv_timer_again(uv_timer_t * handle)131 int uv_timer_again(uv_timer_t* handle) {
132 if (handle->timer_cb == NULL)
133 return UV_EINVAL;
134
135 if (handle->repeat) {
136 uv_timer_stop(handle);
137 uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
138 }
139
140 return 0;
141 }
142
143
uv_timer_set_repeat(uv_timer_t * handle,uint64_t repeat)144 void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
145 handle->repeat = repeat;
146 }
147
148
uv_timer_get_repeat(const uv_timer_t * handle)149 uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
150 return handle->repeat;
151 }
152
153
uv_timer_get_due_in(const uv_timer_t * handle)154 uint64_t uv_timer_get_due_in(const uv_timer_t* handle) {
155 if (handle->loop->time >= handle->timeout)
156 return 0;
157
158 return handle->timeout - handle->loop->time;
159 }
160
161
uv__next_timeout(const uv_loop_t * loop)162 int uv__next_timeout(const uv_loop_t* loop) {
163 const struct heap_node* heap_node;
164 const uv_timer_t* handle;
165 uint64_t diff;
166
167 heap_node = heap_min(timer_heap(loop));
168 if (heap_node == NULL)
169 return -1; /* block indefinitely */
170
171 handle = container_of(heap_node, uv_timer_t, heap_node);
172 if (handle->timeout <= loop->time)
173 return 0;
174
175 diff = handle->timeout - loop->time;
176 if (diff > INT_MAX)
177 diff = INT_MAX;
178
179 return (int) diff;
180 }
181
182
uv__run_timers(uv_loop_t * loop)183 void uv__run_timers(uv_loop_t* loop) {
184 struct heap_node* heap_node;
185 uv_timer_t* handle;
186
187 for (;;) {
188 heap_node = heap_min(timer_heap(loop));
189 if (heap_node == NULL)
190 break;
191
192 handle = container_of(heap_node, uv_timer_t, heap_node);
193 if (handle->timeout > loop->time)
194 break;
195
196 uv_timer_stop(handle);
197 uv_timer_again(handle);
198 #ifdef ASYNC_STACKTRACE
199 LibuvSetStackId((uint64_t)handle->u.reserved[3]);
200 #endif
201 handle->timer_cb(handle);
202 }
203 }
204
205
uv__timer_close(uv_timer_t * handle)206 void uv__timer_close(uv_timer_t* handle) {
207 uv_timer_stop(handle);
208 }
209