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 | |
34 | MODULE_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 | |
41 | MODULE_INIT |
42 | |
43 | MODULE_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); |
48 | MODULE_STAT_FUNCTION_END |
49 | /* }}} */ |
50 | |
51 | static __thread event_timer_t **et_heap; |
52 | __thread int et_heap_size; |
53 | |
54 | |
55 | static 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 | |
84 | int 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 | |
101 | int 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 | |
122 | int 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 | |
159 | double timers_get_first (void) { |
160 | if (!et_heap_size) { return 0; } |
161 | return et_heap[1]->wakeup_time; |
162 | } |
163 | |