/src/libzmq/src/timers.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | |
3 | | #include "precompiled.hpp" |
4 | | #include "timers.hpp" |
5 | | #include "err.hpp" |
6 | | |
7 | | #include <algorithm> |
8 | | |
9 | 0 | zmq::timers_t::timers_t () : _tag (0xCAFEDADA), _next_timer_id (0) |
10 | 0 | { |
11 | 0 | } |
12 | | |
13 | | zmq::timers_t::~timers_t () |
14 | 0 | { |
15 | | // Mark the timers as dead |
16 | 0 | _tag = 0xdeadbeef; |
17 | 0 | } |
18 | | |
19 | | bool zmq::timers_t::check_tag () const |
20 | 0 | { |
21 | 0 | return _tag == 0xCAFEDADA; |
22 | 0 | } |
23 | | |
24 | | int zmq::timers_t::add (size_t interval_, timers_timer_fn handler_, void *arg_) |
25 | 0 | { |
26 | 0 | if (handler_ == NULL) { |
27 | 0 | errno = EFAULT; |
28 | 0 | return -1; |
29 | 0 | } |
30 | | |
31 | 0 | uint64_t when = _clock.now_ms () + interval_; |
32 | 0 | timer_t timer = {++_next_timer_id, interval_, handler_, arg_}; |
33 | 0 | _timers.insert (timersmap_t::value_type (when, timer)); |
34 | |
|
35 | 0 | return timer.timer_id; |
36 | 0 | } |
37 | | |
38 | | struct zmq::timers_t::match_by_id |
39 | | { |
40 | 0 | match_by_id (int timer_id_) : _timer_id (timer_id_) {} |
41 | | |
42 | | bool operator() (timersmap_t::value_type const &entry_) const |
43 | 0 | { |
44 | 0 | return entry_.second.timer_id == _timer_id; |
45 | 0 | } |
46 | | |
47 | | private: |
48 | | int _timer_id; |
49 | | }; |
50 | | |
51 | | int zmq::timers_t::cancel (int timer_id_) |
52 | 0 | { |
53 | | // check first if timer exists at all |
54 | 0 | if (_timers.end () |
55 | 0 | == std::find_if (_timers.begin (), _timers.end (), |
56 | 0 | match_by_id (timer_id_))) { |
57 | 0 | errno = EINVAL; |
58 | 0 | return -1; |
59 | 0 | } |
60 | | |
61 | | // check if timer was already canceled |
62 | 0 | if (_cancelled_timers.count (timer_id_)) { |
63 | 0 | errno = EINVAL; |
64 | 0 | return -1; |
65 | 0 | } |
66 | | |
67 | 0 | _cancelled_timers.insert (timer_id_); |
68 | |
|
69 | 0 | return 0; |
70 | 0 | } |
71 | | |
72 | | int zmq::timers_t::set_interval (int timer_id_, size_t interval_) |
73 | 0 | { |
74 | 0 | const timersmap_t::iterator end = _timers.end (); |
75 | 0 | const timersmap_t::iterator it = |
76 | 0 | std::find_if (_timers.begin (), end, match_by_id (timer_id_)); |
77 | 0 | if (it != end) { |
78 | 0 | timer_t timer = it->second; |
79 | 0 | timer.interval = interval_; |
80 | 0 | uint64_t when = _clock.now_ms () + interval_; |
81 | 0 | _timers.erase (it); |
82 | 0 | _timers.insert (timersmap_t::value_type (when, timer)); |
83 | |
|
84 | 0 | return 0; |
85 | 0 | } |
86 | | |
87 | 0 | errno = EINVAL; |
88 | 0 | return -1; |
89 | 0 | } |
90 | | |
91 | | int zmq::timers_t::reset (int timer_id_) |
92 | 0 | { |
93 | 0 | const timersmap_t::iterator end = _timers.end (); |
94 | 0 | const timersmap_t::iterator it = |
95 | 0 | std::find_if (_timers.begin (), end, match_by_id (timer_id_)); |
96 | 0 | if (it != end) { |
97 | 0 | timer_t timer = it->second; |
98 | 0 | uint64_t when = _clock.now_ms () + timer.interval; |
99 | 0 | _timers.erase (it); |
100 | 0 | _timers.insert (timersmap_t::value_type (when, timer)); |
101 | |
|
102 | 0 | return 0; |
103 | 0 | } |
104 | | |
105 | 0 | errno = EINVAL; |
106 | 0 | return -1; |
107 | 0 | } |
108 | | |
109 | | long zmq::timers_t::timeout () |
110 | 0 | { |
111 | 0 | const uint64_t now = _clock.now_ms (); |
112 | 0 | long res = -1; |
113 | |
|
114 | 0 | const timersmap_t::iterator begin = _timers.begin (); |
115 | 0 | const timersmap_t::iterator end = _timers.end (); |
116 | 0 | timersmap_t::iterator it = begin; |
117 | 0 | for (; it != end; ++it) { |
118 | 0 | if (0 == _cancelled_timers.erase (it->second.timer_id)) { |
119 | | // Live timer, lets return the timeout |
120 | 0 | res = std::max (static_cast<long> (it->first - now), 0l); |
121 | 0 | break; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | // Remove timed-out timers |
126 | 0 | _timers.erase (begin, it); |
127 | |
|
128 | 0 | return res; |
129 | 0 | } |
130 | | |
131 | | int zmq::timers_t::execute () |
132 | 0 | { |
133 | 0 | const uint64_t now = _clock.now_ms (); |
134 | |
|
135 | 0 | const timersmap_t::iterator begin = _timers.begin (); |
136 | 0 | const timersmap_t::iterator end = _timers.end (); |
137 | 0 | timersmap_t::iterator it = _timers.begin (); |
138 | 0 | for (; it != end; ++it) { |
139 | 0 | if (0 == _cancelled_timers.erase (it->second.timer_id)) { |
140 | | // Timer is not cancelled |
141 | | |
142 | | // Map is ordered, if we have to wait for current timer we can stop. |
143 | 0 | if (it->first > now) |
144 | 0 | break; |
145 | | |
146 | 0 | const timer_t &timer = it->second; |
147 | |
|
148 | 0 | timer.handler (timer.timer_id, timer.arg); |
149 | |
|
150 | 0 | _timers.insert ( |
151 | 0 | timersmap_t::value_type (now + timer.interval, timer)); |
152 | 0 | } |
153 | 0 | } |
154 | 0 | _timers.erase (begin, it); |
155 | |
|
156 | 0 | return 0; |
157 | 0 | } |