Home | History | Annotate | Line # | Download | only in src
      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