Directory: | cvmfs/ |
---|---|
File: | cvmfs/util/async.h |
Date: | 2025-06-22 02:36:02 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 27 | 27 | 100.0% |
Branches: | 8 | 14 | 57.1% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #ifndef CVMFS_UTIL_ASYNC_H_ | ||
6 | #define CVMFS_UTIL_ASYNC_H_ | ||
7 | |||
8 | #ifdef CVMFS_NAMESPACE_GUARD | ||
9 | namespace CVMFS_NAMESPACE_GUARD { | ||
10 | #endif | ||
11 | |||
12 | /** | ||
13 | * Encapsulates a callback function that handles asynchronous responses. | ||
14 | * | ||
15 | * This is an abstract base class for two different callback function objects. | ||
16 | * There are two specializations: | ||
17 | * --> 1. for static members or global C-like functions | ||
18 | * --> 2. for member functions of arbitrary objects | ||
19 | */ | ||
20 | template<typename ParamT> | ||
21 | class CallbackBase { | ||
22 | public: | ||
23 | 20413032 | virtual ~CallbackBase() { } | |
24 | virtual void operator()(const ParamT &value) const = 0; | ||
25 | }; | ||
26 | |||
27 | template<> | ||
28 | class CallbackBase<void> { | ||
29 | public: | ||
30 | 90 | virtual ~CallbackBase() { } | |
31 | virtual void operator()() const = 0; | ||
32 | }; | ||
33 | |||
34 | /** | ||
35 | * This callback function object can be used to call static members or global | ||
36 | * functions with the following signature: | ||
37 | * void <name>(ParamT <parameter>); | ||
38 | * | ||
39 | * TODO: One might use varidic templates once C++11 will be supported, in order | ||
40 | * to allow for more than one parameter to be passed to the callback. | ||
41 | * | ||
42 | * @param ParamT the type of the parameter to be passed to the callback | ||
43 | */ | ||
44 | template<typename ParamT> | ||
45 | class Callback : public CallbackBase<ParamT> { | ||
46 | public: | ||
47 | typedef void (*CallbackFunction)(const ParamT &value); | ||
48 | |||
49 | 2645 | explicit Callback(CallbackFunction function) : function_(function) { } | |
50 | 18313873 | void operator()(const ParamT &value) const { function_(value); } | |
51 | |||
52 | private: | ||
53 | CallbackFunction function_; | ||
54 | }; | ||
55 | |||
56 | template<> | ||
57 | class Callback<void> : public CallbackBase<void> { | ||
58 | public: | ||
59 | typedef void (*CallbackFunction)(); | ||
60 | |||
61 | 30 | explicit Callback(CallbackFunction function) : function_(function) { } | |
62 | 75 | void operator()() const { function_(); } | |
63 | |||
64 | private: | ||
65 | CallbackFunction function_; | ||
66 | }; | ||
67 | |||
68 | |||
69 | /** | ||
70 | * A BoundCallback can be used to call a member of an arbitrary object as a | ||
71 | * callback. | ||
72 | * The member must have the following interface: | ||
73 | * void <DelegateT>::<member name>(ParamT <parameter>); | ||
74 | * | ||
75 | * Note: it is the responsibility of the user to ensure that the bound object | ||
76 | * for `delegate` remains alive in the whole time this callback might be | ||
77 | * invoked. | ||
78 | * | ||
79 | * @param ParamT the type of the parameter to be passed to the callback | ||
80 | * @param DelegateT the <class name> of the object the member <member name> | ||
81 | * should be invoked in | ||
82 | */ | ||
83 | template<typename ParamT, class DelegateT> | ||
84 | class BoundCallback : public CallbackBase<ParamT> { | ||
85 | public: | ||
86 | typedef void (DelegateT::*CallbackMethod)(const ParamT &value); | ||
87 | |||
88 | 29643 | BoundCallback(CallbackMethod method, DelegateT *delegate) | |
89 | 29643 | : delegate_(delegate), method_(method) { } | |
90 | |||
91 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1067174 times.
|
2134265 | void operator()(const ParamT &value) const { (delegate_->*method_)(value); } |
92 | |||
93 | private: | ||
94 | DelegateT *delegate_; | ||
95 | CallbackMethod method_; | ||
96 | }; | ||
97 | |||
98 | template<class DelegateT> | ||
99 | class BoundCallback<void, DelegateT> : public CallbackBase<void> { | ||
100 | public: | ||
101 | typedef void (DelegateT::*CallbackMethod)(); | ||
102 | |||
103 | 60 | BoundCallback(CallbackMethod method, DelegateT *delegate) | |
104 | 60 | : delegate_(delegate), method_(method) { } | |
105 | |||
106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
180 | void operator()() const { (delegate_->*method_)(); } |
107 | |||
108 | private: | ||
109 | DelegateT *delegate_; | ||
110 | CallbackMethod method_; | ||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
115 | * A BoundClosure works exactly the same as a BoundCallback (see above) but, | ||
116 | * allows for an opaque enclosure of an arbitrary chunk of user data on | ||
117 | * creation. When the closure is invoked the provided user data chunk is | ||
118 | * passed as a second argument to the specified callback method. | ||
119 | * | ||
120 | * Note: delegate must be still around when the closure is invoked! | ||
121 | * | ||
122 | * @param ParamT the type of the parameter to be passed to the callback | ||
123 | * @param DelegateT the <class name> of the object the member <member name> | ||
124 | * should be invoked in | ||
125 | * @param ClosureDataT the type of the user data chunk to be passed on invoke | ||
126 | */ | ||
127 | template<typename ParamT, class DelegateT, typename ClosureDataT> | ||
128 | class BoundClosure : public CallbackBase<ParamT> { | ||
129 | public: | ||
130 | typedef void (DelegateT::*CallbackMethod)(const ParamT &value, | ||
131 | const ClosureDataT closure_data); | ||
132 | |||
133 | public: | ||
134 | 11380271 | BoundClosure(CallbackMethod method, DelegateT *delegate, ClosureDataT data) | |
135 |
1/2✓ Branch 2 taken 81158 times.
✗ Branch 3 not taken.
|
11380271 | : delegate_(delegate), method_(method), closure_data_(data) { } |
136 | |||
137 | 11381046 | void operator()(const ParamT &value) const { | |
138 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 10192438 times.
✓ Branch 4 taken 81158 times.
✗ Branch 5 not taken.
|
11381046 | (delegate_->*method_)(value, closure_data_); |
139 | 11381634 | } | |
140 | |||
141 | private: | ||
142 | DelegateT *delegate_; | ||
143 | CallbackMethod method_; | ||
144 | const ClosureDataT closure_data_; | ||
145 | }; | ||
146 | |||
147 | template<class DelegateT, typename ClosureDataT> | ||
148 | class BoundClosure<void, DelegateT, ClosureDataT> : public CallbackBase<void> { | ||
149 | public: | ||
150 | typedef void (DelegateT::*CallbackMethod)(const ClosureDataT closure_data); | ||
151 | |||
152 | public: | ||
153 | 60 | BoundClosure(CallbackMethod method, DelegateT *delegate, ClosureDataT data) | |
154 | 60 | : delegate_(delegate), method_(method), closure_data_(data) { } | |
155 | |||
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
60 | void operator()() const { (delegate_->*method_)(closure_data_); } |
157 | |||
158 | private: | ||
159 | DelegateT *delegate_; | ||
160 | CallbackMethod method_; | ||
161 | const ClosureDataT closure_data_; | ||
162 | }; | ||
163 | |||
164 | |||
165 | /** | ||
166 | * This template contains convenience functions to be inherited by classes pro- | ||
167 | * viding callback functionality. You can use this as a base class providing the | ||
168 | * callback parameter your class is going to process. | ||
169 | * Users of your class can profit from the static MakeCallback resp. MakeClosure | ||
170 | * methods to generated Callback objects. Later they can easily be passed back | ||
171 | * to your class. | ||
172 | * | ||
173 | * Note: the convenience methods return a pointer to a callback object. The user | ||
174 | * is responsible to clean up those pointers in some way. If it is a one- | ||
175 | * time callback, it makes sense to delete it inside the inheriting class | ||
176 | * once it was invoked. | ||
177 | * | ||
178 | * TODO: C++11 - Replace this functionality by lambdas | ||
179 | * | ||
180 | * @param ParamT the parameter type of the callbacks to be called | ||
181 | */ | ||
182 | template<class ParamT> | ||
183 | class Callbackable { | ||
184 | public: | ||
185 | typedef CallbackBase<ParamT> CallbackTN; | ||
186 | |||
187 | public: | ||
188 | /** | ||
189 | * Produces a BoundClosure object that captures a closure value passed along | ||
190 | * to the invoked method. | ||
191 | * | ||
192 | * @param method Function pointer to the method to be called | ||
193 | * @param delegate The delegate object on which <method> will be called | ||
194 | * @param closure_data The closure data to be passed along to <method> | ||
195 | */ | ||
196 | template<class DelegateT, typename ClosureDataT> | ||
197 | 10193644 | static CallbackTN *MakeClosure( | |
198 | typename BoundClosure<ParamT, DelegateT, ClosureDataT>::CallbackMethod | ||
199 | method, | ||
200 | DelegateT *delegate, | ||
201 | const ClosureDataT &closure_data) { | ||
202 | 10193644 | return new BoundClosure<ParamT, DelegateT, ClosureDataT>( | |
203 |
1/2✓ Branch 1 taken 893 times.
✗ Branch 2 not taken.
|
10276555 | method, delegate, closure_data); |
204 | } | ||
205 | |||
206 | /** | ||
207 | * Produces a BoundCallback object that invokes a method on a delegate object. | ||
208 | * | ||
209 | * @param method Function pointer to the method to be called | ||
210 | * @param delegate The delegate object on which <method> will be called | ||
211 | */ | ||
212 | template<class DelegateT> | ||
213 | 15272 | static CallbackTN *MakeCallback( | |
214 | typename BoundCallback<ParamT, DelegateT>::CallbackMethod method, | ||
215 | DelegateT *delegate) { | ||
216 | 15272 | return new BoundCallback<ParamT, DelegateT>(method, delegate); | |
217 | } | ||
218 | |||
219 | /** | ||
220 | * Produces a Callback object that invokes a static function or a globally de- | ||
221 | * fined C-like function. | ||
222 | * | ||
223 | * @param function Function pointer to the function to be invoked | ||
224 | */ | ||
225 | 2575 | static CallbackTN *MakeCallback( | |
226 | typename Callback<ParamT>::CallbackFunction function) { | ||
227 | 2575 | return new Callback<ParamT>(function); | |
228 | } | ||
229 | }; | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Wrapper function to bind an arbitrary this* to a method call in a C-style | ||
234 | * spawned thread function. | ||
235 | * The method called by the ThreadProxy template is meant to look like this: | ||
236 | * void foo(); | ||
237 | */ | ||
238 | template<class DelegateT> | ||
239 | void ThreadProxy(DelegateT *delegate, void (DelegateT::*method)()) { | ||
240 | (*delegate.*method)(); | ||
241 | } | ||
242 | |||
243 | |||
244 | #ifdef CVMFS_NAMESPACE_GUARD | ||
245 | } // namespace CVMFS_NAMESPACE_GUARD | ||
246 | #endif | ||
247 | |||
248 | #endif // CVMFS_UTIL_ASYNC_H_ | ||
249 |