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
29static struct heap *timer_heap(const uv_loop_t* loop) {
30#ifdef _WIN32
31 return (struct heap*) loop->timer_heap;
32#else
33 return (struct heap*) &loop->timer_heap;
34#endif
35}
36
37
38static int timer_less_than(const struct heap_node* ha,
39 const struct heap_node* hb) {
40 const uv_timer_t* a;
41 const uv_timer_t* b;
42
43 a = container_of(ha, uv_timer_t, heap_node);
44 b = container_of(hb, uv_timer_t, heap_node);
45
46 if (a->timeout < b->timeout)
47 return 1;
48 if (b->timeout < a->timeout)
49 return 0;
50
51 /* Compare start_id when both have the same timeout. start_id is
52 * allocated with loop->timer_counter in uv_timer_start().
53 */
54 if (a->start_id < b->start_id)
55 return 1;
56 if (b->start_id < a->start_id)
57 return 0;
58
59 return 0;
60}
61
62
63int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
64 uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
65 handle->timer_cb = NULL;
66 handle->repeat = 0;
67 return 0;
68}
69
70
71int uv_timer_start(uv_timer_t* handle,
72 uv_timer_cb cb,
73 uint64_t timeout,
74 uint64_t repeat) {
75 uint64_t clamped_timeout;
76
77 if (cb == NULL)
78 return UV_EINVAL;
79
80 if (uv__is_active(handle))
81 uv_timer_stop(handle);
82
83 clamped_timeout = handle->loop->time + timeout;
84 if (clamped_timeout < timeout)
85 clamped_timeout = (uint64_t) -1;
86
87 handle->timer_cb = cb;
88 handle->timeout = clamped_timeout;
89 handle->repeat = repeat;
90 /* start_id is the second index to be compared in uv__timer_cmp() */
91 handle->start_id = handle->loop->timer_counter++;
92
93 heap_insert(timer_heap(handle->loop),
94 (struct heap_node*) &handle->heap_node,
95 timer_less_than);
96 uv__handle_start(handle);
97
98 return 0;
99}
100
101
102int uv_timer_stop(uv_timer_t* handle) {
103 if (!uv__is_active(handle))
104 return 0;
105
106 heap_remove(timer_heap(handle->loop),
107 (struct heap_node*) &handle->heap_node,
108 timer_less_than);
109 uv__handle_stop(handle);
110
111 return 0;
112}
113
114
115int uv_timer_again(uv_timer_t* handle) {
116 if (handle->timer_cb == NULL)
117 return UV_EINVAL;
118
119 if (handle->repeat) {
120 uv_timer_stop(handle);
121 uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
122 }
123
124 return 0;
125}
126
127
128void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
129 handle->repeat = repeat;
130}
131
132
133uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
134 return handle->repeat;
135}
136
137
138int uv__next_timeout(const uv_loop_t* loop) {
139 const struct heap_node* heap_node;
140 const uv_timer_t* handle;
141 uint64_t diff;
142
143 heap_node = heap_min(timer_heap(loop));
144 if (heap_node == NULL)
145 return -1; /* block indefinitely */
146
147 handle = container_of(heap_node, uv_timer_t, heap_node);
148 if (handle->timeout <= loop->time)
149 return 0;
150
151 diff = handle->timeout - loop->time;
152 if (diff > INT_MAX)
153 diff = INT_MAX;
154
155 return (int) diff;
156}
157
158
159void uv__run_timers(uv_loop_t* loop) {
160 struct heap_node* heap_node;
161 uv_timer_t* handle;
162
163 for (;;) {
164 heap_node = heap_min(timer_heap(loop));
165 if (heap_node == NULL)
166 break;
167
168 handle = container_of(heap_node, uv_timer_t, heap_node);
169 if (handle->timeout > loop->time)
170 break;
171
172 uv_timer_stop(handle);
173 uv_timer_again(handle);
174 handle->timer_cb(handle);
175 }
176}
177
178
179void uv__timer_close(uv_timer_t* handle) {
180 uv_timer_stop(handle);
181}
182