1/*
2 This file is part of Mtproto-proxy Library.
3
4 Mtproto-proxy Library is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Mtproto-proxy Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2009-2013 Vkontakte Ltd
18 2008-2013 Nikolai Durov
19 2008-2013 Andrey Lopatin
20
21 Copyright 2015-2016 Telegram Messenger Inc
22 2015-2016 Vitaly Valtman
23
24*/
25#include "net/net-timers.h"
26#include "jobs/jobs.h"
27#include "common/common-stats.h"
28#include "common/kprintf.h"
29#include "common/precise-time.h"
30
31/* {{{ STAT */
32#define MODULE timers
33
34MODULE_STAT_TYPE {
35 long long event_timer_insert_ops;
36 long long event_timer_remove_ops;
37 long long event_timer_alarms;
38 int total_timers;
39};
40
41MODULE_INIT
42
43MODULE_STAT_FUNCTION
44 SB_SUM_ONE_LL (event_timer_insert_ops);
45 SB_SUM_ONE_LL (event_timer_remove_ops);
46 SB_SUM_ONE_LL (event_timer_alarms);
47 SB_SUM_ONE_I (total_timers);
48MODULE_STAT_FUNCTION_END
49/* }}} */
50
51static __thread event_timer_t **et_heap;
52__thread int et_heap_size;
53
54
55static inline int basic_et_adjust (event_timer_t *et, int i) {
56 int j;
57 while (i > 1) {
58 j = (i >> 1);
59 if (et_heap[j]->wakeup_time <= et->wakeup_time) {
60 break;
61 }
62 et_heap[i] = et_heap[j];
63 et_heap[i]->h_idx = i;
64 i = j;
65 }
66 j = 2*i;
67 while (j <= et_heap_size) {
68 if (j < et_heap_size && et_heap[j]->wakeup_time > et_heap[j+1]->wakeup_time) {
69 j++;
70 }
71 if (et->wakeup_time <= et_heap[j]->wakeup_time) {
72 break;
73 }
74 et_heap[i] = et_heap[j];
75 et_heap[i]->h_idx = i;
76 i = j;
77 j <<= 1;
78 }
79 et_heap[i] = et;
80 et->h_idx = i;
81 return i;
82}
83
84int insert_event_timer (event_timer_t *et) {
85 if (!et_heap) {
86 et_heap = calloc (sizeof (void *), MAX_EVENT_TIMERS);
87 }
88 MODULE_STAT->event_timer_insert_ops ++;
89 int i;
90 if (et->h_idx) {
91 i = et->h_idx;
92 assert (i > 0 && i <= et_heap_size && et_heap[i] == et);
93 } else {
94 MODULE_STAT->total_timers ++;
95 assert (et_heap_size < MAX_EVENT_TIMERS);
96 i = ++et_heap_size;
97 }
98 return basic_et_adjust (et, i);
99}
100
101int remove_event_timer (event_timer_t *et) {
102 if (!et_heap) {
103 et_heap = calloc (sizeof (void *), MAX_EVENT_TIMERS);
104 }
105 int i = et->h_idx;
106 if (!i) {
107 return 0;
108 }
109 MODULE_STAT->total_timers --;
110 MODULE_STAT->event_timer_remove_ops ++;
111 assert (i > 0 && i <= et_heap_size && et_heap[i] == et);
112 et->h_idx = 0;
113
114 et = et_heap[et_heap_size--];
115 if (i > et_heap_size) {
116 return 1;
117 }
118 basic_et_adjust (et, i);
119 return 1;
120}
121
122int thread_run_timers (void) {
123 if (!et_heap) {
124 et_heap = calloc (sizeof (void *), MAX_EVENT_TIMERS);
125 }
126 double wait_time;
127 event_timer_t *et;
128 if (!et_heap_size) {
129 return 100000;
130 }
131 wait_time = et_heap[1]->wakeup_time - precise_now;
132 if (wait_time > 0) {
133 //do not remove this useful debug!
134 vkprintf (3, "%d event timers, next in %.3f seconds\n", et_heap_size, wait_time);
135 return (int) (wait_time*1000) + 1;
136 }
137 while (et_heap_size > 0 && et_heap[1]->wakeup_time <= precise_now) {
138 et = et_heap[1];
139 assert (et->h_idx == 1);
140 remove_event_timer (et);
141 et->wakeup (et);
142 MODULE_STAT->event_timer_alarms ++;
143 }
144
145 if (!et_heap_size) {
146 return 100000;
147 }
148 wait_time = et_heap[1]->wakeup_time - precise_now;
149 if (wait_time > 0) {
150 //do not remove this useful debug!
151 vkprintf (3, "%d event timers, next in %.3f seconds\n", et_heap_size, wait_time);
152 return (int) (wait_time*1000) + 1;
153 }
154
155 assert (0);
156 return 0;
157}
158
159double timers_get_first (void) {
160 if (!et_heap_size) { return 0; }
161 return et_heap[1]->wakeup_time;
162}
163