timers.cpp 5 KB
Newer Older
somdoron's avatar
somdoron committed
1
/*
2
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
somdoron's avatar
somdoron committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

This file is part of libzmq, the ZeroMQ core engine in C++.

libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.

libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30
#include "precompiled.hpp"
somdoron's avatar
somdoron committed
31 32 33
#include "timers.hpp"
#include "err.hpp"

34
#include <algorithm>
somdoron's avatar
somdoron committed
35

36
zmq::timers_t::timers_t () : _tag (0xCAFEDADA), _next_timer_id (0)
37
{
somdoron's avatar
somdoron committed
38 39 40 41 42
}

zmq::timers_t::~timers_t ()
{
    //  Mark the timers as dead
43
    _tag = 0xdeadbeef;
somdoron's avatar
somdoron committed
44 45 46 47
}

bool zmq::timers_t::check_tag ()
{
48
    return _tag == 0xCAFEDADA;
somdoron's avatar
somdoron committed
49 50
}

51
int zmq::timers_t::add (size_t interval_, timers_timer_fn handler_, void *arg_)
somdoron's avatar
somdoron committed
52
{
53
    if (handler_ == NULL) {
54 55 56 57
        errno = EFAULT;
        return -1;
    }

58 59 60
    uint64_t when = _clock.now_ms () + interval_;
    timer_t timer = {++_next_timer_id, interval_, handler_, arg_};
    _timers.insert (timersmap_t::value_type (when, timer));
somdoron's avatar
somdoron committed
61 62 63 64

    return timer.timer_id;
}

65 66
struct zmq::timers_t::match_by_id
{
67
    match_by_id (int timer_id_) : _timer_id (timer_id_) {}
68

69
    bool operator() (timersmap_t::value_type const &entry_) const
70
    {
71
        return entry_.second.timer_id == _timer_id;
72 73 74
    }

  private:
75
    int _timer_id;
76 77
};

somdoron's avatar
somdoron committed
78 79
int zmq::timers_t::cancel (int timer_id_)
{
80
    // check first if timer exists at all
81 82
    if (_timers.end ()
        == std::find_if (_timers.begin (), _timers.end (),
83 84 85 86
                         match_by_id (timer_id_))) {
        errno = EINVAL;
        return -1;
    }
somdoron's avatar
somdoron committed
87

88
    // check if timer was already canceled
89
    if (_cancelled_timers.count (timer_id_)) {
somdoron's avatar
somdoron committed
90 91 92 93
        errno = EINVAL;
        return -1;
    }

94
    _cancelled_timers.insert (timer_id_);
somdoron's avatar
somdoron committed
95 96 97 98 99 100

    return 0;
}

int zmq::timers_t::set_interval (int timer_id_, size_t interval_)
{
101
    const timersmap_t::iterator end = _timers.end ();
102
    const timersmap_t::iterator it =
103
      std::find_if (_timers.begin (), end, match_by_id (timer_id_));
104 105 106
    if (it != end) {
        timer_t timer = it->second;
        timer.interval = interval_;
107 108 109
        uint64_t when = _clock.now_ms () + interval_;
        _timers.erase (it);
        _timers.insert (timersmap_t::value_type (when, timer));
110 111

        return 0;
somdoron's avatar
somdoron committed
112 113 114 115 116 117
    }

    errno = EINVAL;
    return -1;
}

118 119
int zmq::timers_t::reset (int timer_id_)
{
120
    const timersmap_t::iterator end = _timers.end ();
121
    const timersmap_t::iterator it =
122
      std::find_if (_timers.begin (), end, match_by_id (timer_id_));
123 124
    if (it != end) {
        timer_t timer = it->second;
125 126 127
        uint64_t when = _clock.now_ms () + timer.interval;
        _timers.erase (it);
        _timers.insert (timersmap_t::value_type (when, timer));
somdoron's avatar
somdoron committed
128

129
        return 0;
somdoron's avatar
somdoron committed
130 131 132 133 134 135 136 137
    }

    errno = EINVAL;
    return -1;
}

long zmq::timers_t::timeout ()
{
138 139
    const uint64_t now = _clock.now_ms ();
    long res = -1;
140

141 142 143 144 145 146
    const timersmap_t::iterator begin = _timers.begin ();
    const timersmap_t::iterator end = _timers.end ();
    timersmap_t::iterator it = begin;
    for (; it != end; ++it) {
        if (0 == _cancelled_timers.erase (it->second.timer_id)) {
            //  Live timer, lets return the timeout
147
            res = std::max (static_cast<long> (it->first - now), 0l);
148
            break;
somdoron's avatar
somdoron committed
149 150 151
        }
    }

152 153 154 155
    //  Remove timed-out timers
    _timers.erase (begin, it);

    return res;
somdoron's avatar
somdoron committed
156 157 158 159
}

int zmq::timers_t::execute ()
{
160
    const uint64_t now = _clock.now_ms ();
somdoron's avatar
somdoron committed
161

162 163 164 165 166 167
    const timersmap_t::iterator begin = _timers.begin ();
    const timersmap_t::iterator end = _timers.end ();
    timersmap_t::iterator it = _timers.begin ();
    for (; it != end; ++it) {
        if (0 == _cancelled_timers.erase (it->second.timer_id)) {
            //  Timer is not cancelled
somdoron's avatar
somdoron committed
168

169 170 171
            //  Map is ordered, if we have to wait for current timer we can stop.
            if (it->first > now)
                break;
somdoron's avatar
somdoron committed
172

173
            const timer_t &timer = it->second;
somdoron's avatar
somdoron committed
174

175
            timer.handler (timer.timer_id, timer.arg);
somdoron's avatar
somdoron committed
176

177 178 179
            _timers.insert (
              timersmap_t::value_type (now + timer.interval, timer));
        }
somdoron's avatar
somdoron committed
180
    }
181
    _timers.erase (begin, it);
somdoron's avatar
somdoron committed
182 183 184

    return 0;
}