]>
Commit | Line | Data |
---|---|---|
bbc27441 | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
bbc27441 AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
0edbef7e | 9 | #ifndef SQUID_ASYNCJOBCALLS_H |
10 | #define SQUID_ASYNCJOBCALLS_H | |
11 | ||
d1e045c3 | 12 | #include "base/AsyncJob.h" |
4299f876 | 13 | #include "base/CbcPointer.h" |
675b8408 | 14 | #include "debug/Stream.h" |
4299f876 AR |
15 | |
16 | /** | |
17 | \ingroup AsyncJobAPI | |
18 | * This is a base class for all job call dialers. It does all the job | |
19 | * dialing logic (debugging, handling exceptions, etc.) except for calling | |
20 | * the job method. The latter requires knowing the number and type of method | |
21 | * parameters. Thus, we add a dial() virtual method that the MemFunT templates | |
22 | * below implement for us, calling the job's method with the right params. | |
23 | */ | |
24 | template <class Job> | |
25 | class JobDialer: public CallDialer | |
26 | { | |
27 | public: | |
28 | typedef Job DestClass; | |
29 | typedef CbcPointer<Job> JobPointer; | |
30 | ||
31 | JobDialer(const JobPointer &aJob); | |
32 | JobDialer(const JobDialer &d); | |
33 | ||
34 | virtual bool canDial(AsyncCall &call); | |
35 | void dial(AsyncCall &call); | |
36 | ||
37 | JobPointer job; | |
38 | ||
39 | protected: | |
40 | virtual void doDial() = 0; // actually calls the job method | |
41 | ||
42 | private: | |
43 | // not implemented and should not be needed | |
44 | JobDialer &operator =(const JobDialer &); | |
45 | }; | |
46 | ||
47 | /// schedule an async job call using a dialer; use CallJobHere macros instead | |
48 | template <class Dialer> | |
55622953 | 49 | AsyncCall::Pointer |
4299f876 AR |
50 | CallJob(int debugSection, int debugLevel, const char *fileName, int fileLine, |
51 | const char *callName, const Dialer &dialer) | |
52 | { | |
53 | AsyncCall::Pointer call = asyncCall(debugSection, debugLevel, callName, dialer); | |
55622953 CT |
54 | ScheduleCall(fileName, fileLine, call); |
55 | return call; | |
4299f876 AR |
56 | } |
57 | ||
4299f876 AR |
58 | #define CallJobHere(debugSection, debugLevel, job, Class, method) \ |
59 | CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \ | |
60 | (#Class "::" #method), \ | |
61 | JobMemFun<Class>((job), &Class::method)) | |
62 | ||
63 | #define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1) \ | |
64 | CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \ | |
65 | (#Class "::" #method), \ | |
a3855a07 | 66 | JobMemFun((job), &Class::method, (arg1))) |
4299f876 | 67 | |
4299f876 AR |
68 | /// Convenience macro to create a Dialer-based job callback |
69 | #define JobCallback(dbgSection, dbgLevel, Dialer, job, method) \ | |
70 | asyncCall((dbgSection), (dbgLevel), #method, \ | |
71 | Dialer(CbcPointer<Dialer::DestClass>(job), &method)) | |
72 | ||
0edbef7e | 73 | /* |
74 | * *MemFunT are member function (i.e., class method) wrappers. They store | |
75 | * details of a method call in an object so that the call can be delayed | |
76 | * and executed asynchronously. Details may include the object pointer, | |
77 | * the handler method pointer, and parameters. To simplify, we require | |
78 | * all handlers to return void and not be constant. | |
79 | */ | |
80 | ||
81 | /* | |
82 | * We need one wrapper for every supported member function arity (i.e., | |
83 | * number of handler arguments). The first template parameter is the class | |
84 | * type of the handler. That class must be an AsyncJob child. | |
85 | */ | |
86 | ||
87 | // Arity names are from http://en.wikipedia.org/wiki/Arity | |
88 | ||
4299f876 AR |
89 | template <class Job> |
90 | class NullaryMemFunT: public JobDialer<Job> | |
0edbef7e | 91 | { |
92 | public: | |
4299f876 AR |
93 | typedef void (Job::*Method)(); |
94 | explicit NullaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod): | |
f53969cc | 95 | JobDialer<Job>(aJob), method(aMethod) {} |
0edbef7e | 96 | |
337b9aa4 | 97 | void print(std::ostream &os) const override { os << "()"; } |
0edbef7e | 98 | |
99 | public: | |
0edbef7e | 100 | Method method; |
101 | ||
102 | protected: | |
337b9aa4 | 103 | void doDial() override { ((&(*this->job))->*method)(); } |
0edbef7e | 104 | }; |
105 | ||
8822ebee | 106 | template <class Job, class Data, class Argument1 = Data> |
4299f876 | 107 | class UnaryMemFunT: public JobDialer<Job> |
0edbef7e | 108 | { |
109 | public: | |
4299f876 AR |
110 | typedef void (Job::*Method)(Argument1); |
111 | explicit UnaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod, | |
8822ebee | 112 | const Data &anArg1): JobDialer<Job>(aJob), |
f53969cc | 113 | method(aMethod), arg1(anArg1) {} |
0edbef7e | 114 | |
337b9aa4 | 115 | void print(std::ostream &os) const override { os << '(' << arg1 << ')'; } |
0edbef7e | 116 | |
117 | public: | |
0edbef7e | 118 | Method method; |
8822ebee | 119 | Data arg1; |
0edbef7e | 120 | |
121 | protected: | |
337b9aa4 | 122 | void doDial() override { ((&(*this->job))->*method)(arg1); } |
0edbef7e | 123 | }; |
124 | ||
125 | // ... add more as needed | |
126 | ||
0edbef7e | 127 | // Now we add global templated functions that create the member function |
128 | // wrappers above. These are for convenience: it is often easier to | |
129 | // call a templated function than to create a templated object. | |
130 | ||
131 | template <class C> | |
132 | NullaryMemFunT<C> | |
4299f876 | 133 | JobMemFun(const CbcPointer<C> &job, typename NullaryMemFunT<C>::Method method) |
0edbef7e | 134 | { |
4299f876 | 135 | return NullaryMemFunT<C>(job, method); |
0edbef7e | 136 | } |
137 | ||
138 | template <class C, class Argument1> | |
139 | UnaryMemFunT<C, Argument1> | |
4299f876 | 140 | JobMemFun(const CbcPointer<C> &job, typename UnaryMemFunT<C, Argument1>::Method method, |
4cb2536f | 141 | Argument1 arg1) |
0edbef7e | 142 | { |
4299f876 AR |
143 | return UnaryMemFunT<C, Argument1>(job, method, arg1); |
144 | } | |
145 | ||
4299f876 AR |
146 | // inlined methods |
147 | ||
148 | template<class Job> | |
149 | JobDialer<Job>::JobDialer(const JobPointer &aJob): job(aJob) | |
150 | { | |
151 | } | |
152 | ||
153 | template<class Job> | |
154 | JobDialer<Job>::JobDialer(const JobDialer<Job> &d): CallDialer(d), job(d.job) | |
155 | { | |
156 | } | |
157 | ||
158 | template<class Job> | |
159 | bool | |
160 | JobDialer<Job>::canDial(AsyncCall &call) | |
161 | { | |
162 | if (!job) | |
163 | return call.cancel("job gone"); | |
164 | ||
165 | return job->canBeCalled(call); | |
166 | } | |
167 | ||
168 | template<class Job> | |
169 | void | |
170 | JobDialer<Job>::dial(AsyncCall &call) | |
171 | { | |
172 | job->callStart(call); | |
173 | ||
174 | try { | |
175 | doDial(); | |
176 | } catch (const std::exception &e) { | |
177 | debugs(call.debugSection, 3, | |
bf95c10a | 178 | call.name << " threw exception: " << e.what()); |
4299f876 AR |
179 | job->callException(e); |
180 | } | |
181 | ||
182 | job->callEnd(); // may delete job | |
0edbef7e | 183 | } |
184 | ||
185 | #endif /* SQUID_ASYNCJOBCALLS_H */ | |
f53969cc | 186 |