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 29 static 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 38 static 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, node.heap); 44 b = container_of(hb, uv_timer_t, node.heap); 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 return a->start_id < b->start_id; 55 } 56 57 58 int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { 59 uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); 60 handle->timer_cb = NULL; 61 handle->timeout = 0; 62 handle->repeat = 0; 63 uv__queue_init(&handle->node.queue); 64 return 0; 65 } 66 67 68 int uv_timer_start(uv_timer_t* handle, 69 uv_timer_cb cb, 70 uint64_t timeout, 71 uint64_t repeat) { 72 uint64_t clamped_timeout; 73 74 if (uv__is_closing(handle) || cb == NULL) 75 return UV_EINVAL; 76 77 uv_timer_stop(handle); 78 79 clamped_timeout = handle->loop->time + timeout; 80 if (clamped_timeout < timeout) 81 clamped_timeout = (uint64_t) -1; 82 83 handle->timer_cb = cb; 84 handle->timeout = clamped_timeout; 85 handle->repeat = repeat; 86 /* start_id is the second index to be compared in timer_less_than() */ 87 handle->start_id = handle->loop->timer_counter++; 88 89 heap_insert(timer_heap(handle->loop), 90 (struct heap_node*) &handle->node.heap, 91 timer_less_than); 92 uv__handle_start(handle); 93 94 return 0; 95 } 96 97 98 int uv_timer_stop(uv_timer_t* handle) { 99 if (uv__is_active(handle)) { 100 heap_remove(timer_heap(handle->loop), 101 (struct heap_node*) &handle->node.heap, 102 timer_less_than); 103 uv__handle_stop(handle); 104 } else { 105 uv__queue_remove(&handle->node.queue); 106 } 107 108 uv__queue_init(&handle->node.queue); 109 return 0; 110 } 111 112 113 int uv_timer_again(uv_timer_t* handle) { 114 if (handle->timer_cb == NULL) 115 return UV_EINVAL; 116 117 if (handle->repeat) { 118 uv_timer_stop(handle); 119 uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); 120 } 121 122 return 0; 123 } 124 125 126 void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { 127 handle->repeat = repeat; 128 } 129 130 131 uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { 132 return handle->repeat; 133 } 134 135 136 uint64_t uv_timer_get_due_in(const uv_timer_t* handle) { 137 if (handle->loop->time >= handle->timeout) 138 return 0; 139 140 return handle->timeout - handle->loop->time; 141 } 142 143 144 int uv__next_timeout(const uv_loop_t* loop) { 145 const struct heap_node* heap_node; 146 const uv_timer_t* handle; 147 uint64_t diff; 148 149 heap_node = heap_min(timer_heap(loop)); 150 if (heap_node == NULL) 151 return -1; /* block indefinitely */ 152 153 handle = container_of(heap_node, uv_timer_t, node.heap); 154 if (handle->timeout <= loop->time) 155 return 0; 156 157 diff = handle->timeout - loop->time; 158 if (diff > INT_MAX) 159 diff = INT_MAX; 160 161 return (int) diff; 162 } 163 164 165 void uv__run_timers(uv_loop_t* loop) { 166 struct heap_node* heap_node; 167 uv_timer_t* handle; 168 struct uv__queue* queue_node; 169 struct uv__queue ready_queue; 170 171 uv__queue_init(&ready_queue); 172 173 for (;;) { 174 heap_node = heap_min(timer_heap(loop)); 175 if (heap_node == NULL) 176 break; 177 178 handle = container_of(heap_node, uv_timer_t, node.heap); 179 if (handle->timeout > loop->time) 180 break; 181 182 uv_timer_stop(handle); 183 uv__queue_insert_tail(&ready_queue, &handle->node.queue); 184 } 185 186 while (!uv__queue_empty(&ready_queue)) { 187 queue_node = uv__queue_head(&ready_queue); 188 uv__queue_remove(queue_node); 189 uv__queue_init(queue_node); 190 handle = container_of(queue_node, uv_timer_t, node.queue); 191 192 uv_timer_again(handle); 193 handle->timer_cb(handle); 194 } 195 } 196 197 198 void uv__timer_close(uv_timer_t* handle) { 199 uv_timer_stop(handle); 200 } 201