Coverage Report

Created: 2025-07-01 06:07

/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
}