]>
Commit | Line | Data |
---|---|---|
0edbef7e | 1 | |
2 | /* | |
262a0e14 | 3 | * $Id$ |
0edbef7e | 4 | */ |
5 | ||
6 | #ifndef SQUID_ASYNCJOBCALLS_H | |
7 | #define SQUID_ASYNCJOBCALLS_H | |
8 | ||
d1e045c3 | 9 | #include "base/AsyncJob.h" |
4299f876 AR |
10 | #include "base/CbcPointer.h" |
11 | ||
12 | /** | |
13 | \ingroup AsyncJobAPI | |
14 | * This is a base class for all job call dialers. It does all the job | |
15 | * dialing logic (debugging, handling exceptions, etc.) except for calling | |
16 | * the job method. The latter requires knowing the number and type of method | |
17 | * parameters. Thus, we add a dial() virtual method that the MemFunT templates | |
18 | * below implement for us, calling the job's method with the right params. | |
19 | */ | |
20 | template <class Job> | |
21 | class JobDialer: public CallDialer | |
22 | { | |
23 | public: | |
24 | typedef Job DestClass; | |
25 | typedef CbcPointer<Job> JobPointer; | |
26 | ||
27 | JobDialer(const JobPointer &aJob); | |
28 | JobDialer(const JobDialer &d); | |
29 | ||
30 | virtual bool canDial(AsyncCall &call); | |
31 | void dial(AsyncCall &call); | |
32 | ||
33 | JobPointer job; | |
34 | ||
35 | protected: | |
36 | virtual void doDial() = 0; // actually calls the job method | |
37 | ||
38 | private: | |
39 | // not implemented and should not be needed | |
40 | JobDialer &operator =(const JobDialer &); | |
41 | }; | |
42 | ||
43 | /// schedule an async job call using a dialer; use CallJobHere macros instead | |
44 | template <class Dialer> | |
45 | bool | |
46 | CallJob(int debugSection, int debugLevel, const char *fileName, int fileLine, | |
47 | const char *callName, const Dialer &dialer) | |
48 | { | |
49 | AsyncCall::Pointer call = asyncCall(debugSection, debugLevel, callName, dialer); | |
50 | return ScheduleCall(fileName, fileLine, call); | |
51 | } | |
52 | ||
53 | ||
54 | #define CallJobHere(debugSection, debugLevel, job, Class, method) \ | |
55 | CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \ | |
56 | (#Class "::" #method), \ | |
57 | JobMemFun<Class>((job), &Class::method)) | |
58 | ||
59 | #define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1) \ | |
60 | CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \ | |
61 | (#Class "::" #method), \ | |
a3855a07 | 62 | JobMemFun((job), &Class::method, (arg1))) |
4299f876 AR |
63 | |
64 | ||
65 | /// Convenience macro to create a Dialer-based job callback | |
66 | #define JobCallback(dbgSection, dbgLevel, Dialer, job, method) \ | |
67 | asyncCall((dbgSection), (dbgLevel), #method, \ | |
68 | Dialer(CbcPointer<Dialer::DestClass>(job), &method)) | |
69 | ||
0edbef7e | 70 | |
71 | /* | |
72 | * *MemFunT are member function (i.e., class method) wrappers. They store | |
73 | * details of a method call in an object so that the call can be delayed | |
74 | * and executed asynchronously. Details may include the object pointer, | |
75 | * the handler method pointer, and parameters. To simplify, we require | |
76 | * all handlers to return void and not be constant. | |
77 | */ | |
78 | ||
79 | /* | |
80 | * We need one wrapper for every supported member function arity (i.e., | |
81 | * number of handler arguments). The first template parameter is the class | |
82 | * type of the handler. That class must be an AsyncJob child. | |
83 | */ | |
84 | ||
85 | // Arity names are from http://en.wikipedia.org/wiki/Arity | |
86 | ||
4299f876 AR |
87 | template <class Job> |
88 | class NullaryMemFunT: public JobDialer<Job> | |
0edbef7e | 89 | { |
90 | public: | |
4299f876 AR |
91 | typedef void (Job::*Method)(); |
92 | explicit NullaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod): | |
4cb2536f | 93 | JobDialer<Job>(aJob), method(aMethod) {} |
0edbef7e | 94 | |
95 | virtual void print(std::ostream &os) const { os << "()"; } | |
96 | ||
97 | public: | |
0edbef7e | 98 | Method method; |
99 | ||
100 | protected: | |
4299f876 | 101 | virtual void doDial() { ((&(*this->job))->*method)(); } |
0edbef7e | 102 | }; |
103 | ||
4299f876 AR |
104 | template <class Job, class Argument1> |
105 | class UnaryMemFunT: public JobDialer<Job> | |
0edbef7e | 106 | { |
107 | public: | |
4299f876 AR |
108 | typedef void (Job::*Method)(Argument1); |
109 | explicit UnaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod, | |
4cb2536f | 110 | const Argument1 &anArg1): JobDialer<Job>(aJob), |
4299f876 | 111 | method(aMethod), arg1(anArg1) {} |
0edbef7e | 112 | |
113 | virtual void print(std::ostream &os) const { os << '(' << arg1 << ')'; } | |
114 | ||
115 | public: | |
0edbef7e | 116 | Method method; |
117 | Argument1 arg1; | |
118 | ||
119 | protected: | |
4299f876 | 120 | virtual void doDial() { ((&(*this->job))->*method)(arg1); } |
0edbef7e | 121 | }; |
122 | ||
123 | // ... add more as needed | |
124 | ||
125 | ||
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 | ||
145 | ||
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, | |
178 | HERE << call.name << " threw exception: " << e.what()); | |
179 | job->callException(e); | |
180 | } | |
181 | ||
182 | job->callEnd(); // may delete job | |
0edbef7e | 183 | } |
184 | ||
185 | #endif /* SQUID_ASYNCJOBCALLS_H */ |