]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/Timer.cc
import ceph quincy 17.2.4
[ceph.git] / ceph / src / common / Timer.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include "Cond.h"
7c673cae
FG
16#include "Timer.h"
17
7c673cae
FG
18
19#define dout_subsys ceph_subsys_timer
20#undef dout_prefix
21#define dout_prefix *_dout << "timer(" << this << ")."
22
f67539c2 23using std::pair;
7c673cae 24
f67539c2 25using ceph::operator <<;
7c673cae 26
a4b75251
TL
27template <class Mutex>
28class CommonSafeTimerThread : public Thread {
29 CommonSafeTimer<Mutex> *parent;
7c673cae 30public:
a4b75251 31 explicit CommonSafeTimerThread(CommonSafeTimer<Mutex> *s) : parent(s) {}
7c673cae
FG
32 void *entry() override {
33 parent->timer_thread();
34 return NULL;
35 }
36};
37
a4b75251
TL
38template <class Mutex>
39CommonSafeTimer<Mutex>::CommonSafeTimer(CephContext *cct_, Mutex &l, bool safe_callbacks)
7c673cae
FG
40 : cct(cct_), lock(l),
41 safe_callbacks(safe_callbacks),
42 thread(NULL),
43 stopping(false)
44{
45}
46
a4b75251
TL
47template <class Mutex>
48CommonSafeTimer<Mutex>::~CommonSafeTimer()
7c673cae 49{
11fdf7f2 50 ceph_assert(thread == NULL);
7c673cae
FG
51}
52
a4b75251
TL
53template <class Mutex>
54void CommonSafeTimer<Mutex>::init()
7c673cae
FG
55{
56 ldout(cct,10) << "init" << dendl;
a4b75251 57 thread = new CommonSafeTimerThread<Mutex>(this);
7c673cae
FG
58 thread->create("safe_timer");
59}
60
a4b75251
TL
61template <class Mutex>
62void CommonSafeTimer<Mutex>::shutdown()
7c673cae
FG
63{
64 ldout(cct,10) << "shutdown" << dendl;
65 if (thread) {
9f95a23c 66 ceph_assert(ceph_mutex_is_locked(lock));
7c673cae
FG
67 cancel_all_events();
68 stopping = true;
9f95a23c 69 cond.notify_all();
11fdf7f2 70 lock.unlock();
7c673cae 71 thread->join();
11fdf7f2 72 lock.lock();
7c673cae
FG
73 delete thread;
74 thread = NULL;
75 }
76}
77
a4b75251
TL
78template <class Mutex>
79void CommonSafeTimer<Mutex>::timer_thread()
7c673cae 80{
9f95a23c 81 std::unique_lock l{lock};
7c673cae
FG
82 ldout(cct,10) << "timer_thread starting" << dendl;
83 while (!stopping) {
9f95a23c 84 auto now = clock_t::now();
7c673cae
FG
85
86 while (!schedule.empty()) {
9f95a23c 87 auto p = schedule.begin();
7c673cae
FG
88
89 // is the future now?
90 if (p->first > now)
91 break;
92
93 Context *callback = p->second;
94 events.erase(callback);
95 schedule.erase(p);
96 ldout(cct,10) << "timer_thread executing " << callback << dendl;
97
9f95a23c
TL
98 if (!safe_callbacks) {
99 l.unlock();
100 callback->complete(0);
101 l.lock();
102 } else {
103 callback->complete(0);
104 }
7c673cae
FG
105 }
106
107 // recheck stopping if we dropped the lock
108 if (!safe_callbacks && stopping)
109 break;
110
111 ldout(cct,20) << "timer_thread going to sleep" << dendl;
9f95a23c
TL
112 if (schedule.empty()) {
113 cond.wait(l);
114 } else {
f67539c2
TL
115 auto when = schedule.begin()->first;
116 cond.wait_until(l, when);
9f95a23c 117 }
7c673cae
FG
118 ldout(cct,20) << "timer_thread awake" << dendl;
119 }
120 ldout(cct,10) << "timer_thread exiting" << dendl;
7c673cae
FG
121}
122
a4b75251
TL
123template <class Mutex>
124Context* CommonSafeTimer<Mutex>::add_event_after(double seconds, Context *callback)
f67539c2
TL
125{
126 return add_event_after(ceph::make_timespan(seconds), callback);
127}
128
a4b75251
TL
129template <class Mutex>
130Context* CommonSafeTimer<Mutex>::add_event_after(ceph::timespan duration, Context *callback)
7c673cae 131{
9f95a23c 132 ceph_assert(ceph_mutex_is_locked(lock));
7c673cae 133
f67539c2 134 auto when = clock_t::now() + duration;
224ce89b 135 return add_event_at(when, callback);
7c673cae
FG
136}
137
a4b75251
TL
138template <class Mutex>
139Context* CommonSafeTimer<Mutex>::add_event_at(CommonSafeTimer<Mutex>::clock_t::time_point when, Context *callback)
7c673cae 140{
9f95a23c 141 ceph_assert(ceph_mutex_is_locked(lock));
224ce89b
WB
142 ldout(cct,10) << __func__ << " " << when << " -> " << callback << dendl;
143 if (stopping) {
144 ldout(cct,5) << __func__ << " already shutdown, event not added" << dendl;
145 delete callback;
3efd9988 146 return nullptr;
224ce89b 147 }
7c673cae
FG
148 scheduled_map_t::value_type s_val(when, callback);
149 scheduled_map_t::iterator i = schedule.insert(s_val);
150
151 event_lookup_map_t::value_type e_val(callback, i);
152 pair < event_lookup_map_t::iterator, bool > rval(events.insert(e_val));
153
154 /* If you hit this, you tried to insert the same Context* twice. */
11fdf7f2 155 ceph_assert(rval.second);
7c673cae
FG
156
157 /* If the event we have just inserted comes before everything else, we need to
158 * adjust our timeout. */
159 if (i == schedule.begin())
9f95a23c 160 cond.notify_all();
3efd9988 161 return callback;
7c673cae
FG
162}
163
a4b75251 164template <class Mutex>
20effc67 165Context* CommonSafeTimer<Mutex>::add_event_at(ceph::real_clock::time_point when, Context *callback)
7c673cae 166{
9f95a23c 167 ceph_assert(ceph_mutex_is_locked(lock));
20effc67
TL
168 // convert from real_clock to mono_clock
169 auto mono_now = ceph::mono_clock::now();
170 auto real_now = ceph::real_clock::now();
171 const auto delta = when - real_now;
172 const auto mono_atime = (mono_now +
173 std::chrono::ceil<clock_t::duration>(delta));
174 return add_event_at(mono_atime, callback);
175}
a4b75251 176
20effc67
TL
177template <class Mutex>
178bool CommonSafeTimer<Mutex>::cancel_event(Context *callback)
179{
180 ceph_assert(ceph_mutex_is_locked(lock));
181
7c673cae
FG
182 auto p = events.find(callback);
183 if (p == events.end()) {
184 ldout(cct,10) << "cancel_event " << callback << " not found" << dendl;
185 return false;
186 }
187
188 ldout(cct,10) << "cancel_event " << p->second->first << " -> " << callback << dendl;
189 delete p->first;
190
191 schedule.erase(p->second);
192 events.erase(p);
193 return true;
194}
195
a4b75251
TL
196template <class Mutex>
197void CommonSafeTimer<Mutex>::cancel_all_events()
7c673cae
FG
198{
199 ldout(cct,10) << "cancel_all_events" << dendl;
9f95a23c 200 ceph_assert(ceph_mutex_is_locked(lock));
11fdf7f2 201
7c673cae
FG
202 while (!events.empty()) {
203 auto p = events.begin();
204 ldout(cct,10) << " cancelled " << p->second->first << " -> " << p->first << dendl;
205 delete p->first;
206 schedule.erase(p->second);
207 events.erase(p);
208 }
209}
210
a4b75251
TL
211template <class Mutex>
212void CommonSafeTimer<Mutex>::dump(const char *caller) const
7c673cae
FG
213{
214 if (!caller)
215 caller = "";
216 ldout(cct,10) << "dump " << caller << dendl;
217
218 for (scheduled_map_t::const_iterator s = schedule.begin();
219 s != schedule.end();
220 ++s)
221 ldout(cct,10) << " " << s->first << "->" << s->second << dendl;
222}
a4b75251
TL
223
224template class CommonSafeTimer<ceph::mutex>;
225template class CommonSafeTimer<ceph::fair_mutex>;