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 return a->start_id < b->start_id; 55} 56 57 58int 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 return 0; 64} 65 66 67int uv_timer_start(uv_timer_t* handle, 68 uv_timer_cb cb, 69 uint64_t timeout, 70 uint64_t repeat) { 71 uint64_t clamped_timeout; 72 73 if (uv__is_closing(handle) || cb == NULL) 74 return UV_EINVAL; 75 76 if (uv__is_active(handle)) 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->heap_node, 91 timer_less_than); 92 uv__handle_start(handle); 93 94 return 0; 95} 96 97 98int uv_timer_stop(uv_timer_t* handle) { 99 if (!uv__is_active(handle)) 100 return 0; 101 102 heap_remove(timer_heap(handle->loop), 103 (struct heap_node*) &handle->heap_node, 104 timer_less_than); 105 uv__handle_stop(handle); 106 107 return 0; 108} 109 110 111int uv_timer_again(uv_timer_t* handle) { 112 if (handle->timer_cb == NULL) 113 return UV_EINVAL; 114 115 if (handle->repeat) { 116 uv_timer_stop(handle); 117 uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); 118 } 119 120 return 0; 121} 122 123 124void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { 125 handle->repeat = repeat; 126} 127 128 129uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { 130 return handle->repeat; 131} 132 133 134uint64_t uv_timer_get_due_in(const uv_timer_t* handle) { 135 if (handle->loop->time >= handle->timeout) 136 return 0; 137 138 return handle->timeout - handle->loop->time; 139} 140 141 142int uv__next_timeout(const uv_loop_t* loop) { 143 const struct heap_node* heap_node; 144 const uv_timer_t* handle; 145 uint64_t diff; 146 147 heap_node = heap_min(timer_heap(loop)); 148 if (heap_node == NULL) 149 return -1; /* block indefinitely */ 150 151 handle = container_of(heap_node, uv_timer_t, heap_node); 152 if (handle->timeout <= loop->time) 153 return 0; 154 155 diff = handle->timeout - loop->time; 156 if (diff > INT_MAX) 157 diff = INT_MAX; 158 159 return (int) diff; 160} 161 162 163void uv__run_timers(uv_loop_t* loop) { 164 struct heap_node* heap_node; 165 uv_timer_t* handle; 166 167 for (;;) { 168 heap_node = heap_min(timer_heap(loop)); 169 if (heap_node == NULL) 170 break; 171 172 handle = container_of(heap_node, uv_timer_t, heap_node); 173 if (handle->timeout > loop->time) 174 break; 175 176 uv_timer_stop(handle); 177 uv_timer_again(handle); 178 handle->timer_cb(handle); 179 } 180} 181 182 183void uv__timer_close(uv_timer_t* handle) { 184 uv_timer_stop(handle); 185} 186