]>
Commit | Line | Data |
---|---|---|
bbc27441 AJ |
1 | /* |
2 | * Copyright (C) 1996-2014 The Squid Software Foundation and contributors | |
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" |
582c2af2 | 14 | #include "Debug.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> | |
49 | bool | |
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); | |
54 | return ScheduleCall(fileName, fileLine, call); | |
55 | } | |
56 | ||
4299f876 AR |
57 | #define CallJobHere(debugSection, debugLevel, job, Class, method) \ |
58 | CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \ | |
59 | (#Class "::" #method), \ | |
60 | JobMemFun<Class>((job), &Class::method)) | |
61 | ||
62 | #define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1) \ | |
63 | CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \ | |
64 | (#Class "::" #method), \ | |
a3855a07 | 65 | JobMemFun((job), &Class::method, (arg1))) |
4299f876 | 66 | |
4299f876 AR |
67 | /// Convenience macro to create a Dialer-based job callback |
68 | #define JobCallback(dbgSection, dbgLevel, Dialer, job, method) \ | |
69 | asyncCall((dbgSection), (dbgLevel), #method, \ | |
70 | Dialer(CbcPointer<Dialer::DestClass>(job), &method)) | |
71 | ||
0edbef7e | 72 | /* |
73 | * *MemFunT are member function (i.e., class method) wrappers. They store | |
74 | * details of a method call in an object so that the call can be delayed | |
75 | * and executed asynchronously. Details may include the object pointer, | |
76 | * the handler method pointer, and parameters. To simplify, we require | |
77 | * all handlers to return void and not be constant. | |
78 | */ | |
79 | ||
80 | /* | |
81 | * We need one wrapper for every supported member function arity (i.e., | |
82 | * number of handler arguments). The first template parameter is the class | |
83 | * type of the handler. That class must be an AsyncJob child. | |
84 | */ | |
85 | ||
86 | // Arity names are from http://en.wikipedia.org/wiki/Arity | |
87 | ||
4299f876 AR |
88 | template <class Job> |
89 | class NullaryMemFunT: public JobDialer<Job> | |
0edbef7e | 90 | { |
91 | public: | |
4299f876 AR |
92 | typedef void (Job::*Method)(); |
93 | explicit NullaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod): | |
f53969cc | 94 | JobDialer<Job>(aJob), method(aMethod) {} |
0edbef7e | 95 | |
96 | virtual void print(std::ostream &os) const { os << "()"; } | |
97 | ||
98 | public: | |
0edbef7e | 99 | Method method; |
100 | ||
101 | protected: | |
4299f876 | 102 | virtual void doDial() { ((&(*this->job))->*method)(); } |
0edbef7e | 103 | }; |
104 | ||
8822ebee | 105 | template <class Job, class Data, class Argument1 = Data> |
4299f876 | 106 | class UnaryMemFunT: public JobDialer<Job> |
0edbef7e | 107 | { |
108 | public: | |
4299f876 AR |
109 | typedef void (Job::*Method)(Argument1); |
110 | explicit UnaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod, | |
8822ebee | 111 | const Data &anArg1): JobDialer<Job>(aJob), |
f53969cc | 112 | method(aMethod), arg1(anArg1) {} |
0edbef7e | 113 | |
114 | virtual void print(std::ostream &os) const { os << '(' << arg1 << ')'; } | |
115 | ||
116 | public: | |
0edbef7e | 117 | Method method; |
8822ebee | 118 | Data arg1; |
0edbef7e | 119 | |
120 | protected: | |
4299f876 | 121 | virtual void doDial() { ((&(*this->job))->*method)(arg1); } |
0edbef7e | 122 | }; |
123 | ||
124 | // ... add more as needed | |
125 | ||
0edbef7e | 126 | // Now we add global templated functions that create the member function |
127 | // wrappers above. These are for convenience: it is often easier to | |
128 | // call a templated function than to create a templated object. | |
129 | ||
130 | template <class C> | |
131 | NullaryMemFunT<C> | |
4299f876 | 132 | JobMemFun(const CbcPointer<C> &job, typename NullaryMemFunT<C>::Method method) |
0edbef7e | 133 | { |
4299f876 | 134 | return NullaryMemFunT<C>(job, method); |
0edbef7e | 135 | } |
136 | ||
137 | template <class C, class Argument1> | |
138 | UnaryMemFunT<C, Argument1> | |
4299f876 | 139 | JobMemFun(const CbcPointer<C> &job, typename UnaryMemFunT<C, Argument1>::Method method, |
4cb2536f | 140 | Argument1 arg1) |
0edbef7e | 141 | { |
4299f876 AR |
142 | return UnaryMemFunT<C, Argument1>(job, method, arg1); |
143 | } | |
144 | ||
4299f876 AR |
145 | // inlined methods |
146 | ||
147 | template<class Job> | |
148 | JobDialer<Job>::JobDialer(const JobPointer &aJob): job(aJob) | |
149 | { | |
150 | } | |
151 | ||
152 | template<class Job> | |
153 | JobDialer<Job>::JobDialer(const JobDialer<Job> &d): CallDialer(d), job(d.job) | |
154 | { | |
155 | } | |
156 | ||
157 | template<class Job> | |
158 | bool | |
159 | JobDialer<Job>::canDial(AsyncCall &call) | |
160 | { | |
161 | if (!job) | |
162 | return call.cancel("job gone"); | |
163 | ||
164 | return job->canBeCalled(call); | |
165 | } | |
166 | ||
167 | template<class Job> | |
168 | void | |
169 | JobDialer<Job>::dial(AsyncCall &call) | |
170 | { | |
171 | job->callStart(call); | |
172 | ||
173 | try { | |
174 | doDial(); | |
175 | } catch (const std::exception &e) { | |
176 | debugs(call.debugSection, 3, | |
177 | HERE << call.name << " threw exception: " << e.what()); | |
178 | job->callException(e); | |
179 | } | |
180 | ||
181 | job->callEnd(); // may delete job | |
0edbef7e | 182 | } |
183 | ||
184 | #endif /* SQUID_ASYNCJOBCALLS_H */ | |
f53969cc | 185 |