]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/TaskFinisher.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / librbd / TaskFinisher.h
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#ifndef LIBRBD_TASK_FINISHER_H
4#define LIBRBD_TASK_FINISHER_H
5
6#include "include/Context.h"
11fdf7f2 7#include "common/ceph_context.h"
7c673cae
FG
8#include "common/Finisher.h"
9#include "common/Mutex.h"
10#include "common/Timer.h"
11#include <map>
12#include <utility>
13
14class CephContext;
15
16namespace librbd {
17
18struct TaskFinisherSingleton {
19 Mutex m_lock;
20 SafeTimer *m_safe_timer;
21 Finisher *m_finisher;
22
23 explicit TaskFinisherSingleton(CephContext *cct)
24 : m_lock("librbd::TaskFinisher::m_lock") {
25 m_safe_timer = new SafeTimer(cct, m_lock, false);
26 m_safe_timer->init();
27 m_finisher = new Finisher(cct, "librbd::TaskFinisher::m_finisher", "taskfin_librbd");
28 m_finisher->start();
29 }
30 virtual ~TaskFinisherSingleton() {
31 {
32 Mutex::Locker l(m_lock);
33 m_safe_timer->shutdown();
34 delete m_safe_timer;
35 }
36 m_finisher->wait_for_empty();
37 m_finisher->stop();
38 delete m_finisher;
39 }
40};
41
42
43template <typename Task>
44class TaskFinisher {
45public:
46 TaskFinisher(CephContext &cct) : m_cct(cct) {
11fdf7f2
TL
47 auto& singleton =
48 cct.lookup_or_create_singleton_object<TaskFinisherSingleton>(
49 "librbd::TaskFinisher::m_safe_timer", false, &cct);
50 m_lock = &singleton.m_lock;
51 m_safe_timer = singleton.m_safe_timer;
52 m_finisher = singleton.m_finisher;
7c673cae
FG
53 }
54
55 void cancel(const Task& task) {
56 Mutex::Locker l(*m_lock);
57 typename TaskContexts::iterator it = m_task_contexts.find(task);
58 if (it != m_task_contexts.end()) {
59 delete it->second.first;
60 m_safe_timer->cancel_event(it->second.second);
61 m_task_contexts.erase(it);
62 }
63 }
64
65 void cancel_all(Context *comp) {
66 {
67 Mutex::Locker l(*m_lock);
68 for (typename TaskContexts::iterator it = m_task_contexts.begin();
69 it != m_task_contexts.end(); ++it) {
70 delete it->second.first;
71 m_safe_timer->cancel_event(it->second.second);
72 }
73 m_task_contexts.clear();
74 }
75 m_finisher->queue(comp);
76 }
77
78 bool add_event_after(const Task& task, double seconds, Context *ctx) {
79 Mutex::Locker l(*m_lock);
80 if (m_task_contexts.count(task) != 0) {
81 // task already scheduled on finisher or timer
82 delete ctx;
83 return false;
84 }
85 C_Task *timer_ctx = new C_Task(this, task);
86 m_task_contexts[task] = std::make_pair(ctx, timer_ctx);
87
88 m_safe_timer->add_event_after(seconds, timer_ctx);
89 return true;
90 }
91
92 void queue(Context *ctx) {
93 m_finisher->queue(ctx);
94 }
95
96 bool queue(const Task& task, Context *ctx) {
97 Mutex::Locker l(*m_lock);
98 typename TaskContexts::iterator it = m_task_contexts.find(task);
99 if (it != m_task_contexts.end()) {
100 if (it->second.second != NULL) {
11fdf7f2 101 ceph_assert(m_safe_timer->cancel_event(it->second.second));
7c673cae
FG
102 delete it->second.first;
103 } else {
104 // task already scheduled on the finisher
105 delete ctx;
106 return false;
107 }
108 }
109 m_task_contexts[task] = std::make_pair(ctx, reinterpret_cast<Context *>(0));
110
111 m_finisher->queue(new C_Task(this, task));
112 return true;
113 }
114
115private:
116 class C_Task : public Context {
117 public:
118 C_Task(TaskFinisher *task_finisher, const Task& task)
119 : m_task_finisher(task_finisher), m_task(task)
120 {
121 }
122 protected:
123 void finish(int r) override {
124 m_task_finisher->complete(m_task);
125 }
126 private:
127 TaskFinisher *m_task_finisher;
128 Task m_task;
129 };
130
131 CephContext &m_cct;
132
133 Mutex *m_lock;
134 Finisher *m_finisher;
135 SafeTimer *m_safe_timer;
136
137 typedef std::map<Task, std::pair<Context *, Context *> > TaskContexts;
138 TaskContexts m_task_contexts;
139
140 void complete(const Task& task) {
141 Context *ctx = NULL;
142 {
143 Mutex::Locker l(*m_lock);
144 typename TaskContexts::iterator it = m_task_contexts.find(task);
145 if (it != m_task_contexts.end()) {
146 ctx = it->second.first;
147 m_task_contexts.erase(it);
148 }
149 }
150
151 if (ctx != NULL) {
152 ctx->complete(0);
153 }
154 }
155};
156
157} // namespace librbd
158
159#endif // LIBRBD_TASK_FINISHER