]>
Commit | Line | Data |
---|---|---|
854d4d81 | 1 | /* |
262a0e14 | 2 | * $Id$ |
854d4d81 | 3 | */ |
4 | ||
5 | #ifndef SQUID_ASYNCCALL_H | |
6 | #define SQUID_ASYNCCALL_H | |
7 | ||
52ed047a | 8 | #include "base/InstanceId.h" |
854d4d81 | 9 | #include "event.h" |
314782d4 | 10 | #include "RefCount.h" |
854d4d81 | 11 | |
63be0a78 | 12 | /** |
13 | \defgroup AsynCallsAPI Async-Calls API | |
14 | \par | |
15 | * A call is asynchronous if the caller proceeds after the call is made, | |
16 | * and the callee receives the call during the next main loop iteration. | |
17 | * Asynchronous calls help avoid nasty call-me-when-I-call-you loops | |
18 | * that humans often have trouble understanding or implementing correctly. | |
19 | \par | |
20 | * Asynchronous calls are currently implemented via Squid events. The call | |
21 | * event stores the pointer to the callback function and cbdata-protected | |
22 | * callback data. To call a method of an object, the method is wrapped | |
23 | * in a method-specific, static callback function and the pointer to the | |
26ac0430 | 24 | * object is passed to the wrapper. For the method call to be safe, the |
63be0a78 | 25 | * class must be cbdata-enabled. |
26 | \par | |
27 | * You do not have to use the macros below to make or receive asynchronous | |
26ac0430 | 28 | * method calls, but they give you a uniform interface and handy call |
63be0a78 | 29 | * debugging. |
30 | */ | |
854d4d81 | 31 | |
3e5c8cf4 | 32 | class CallDialer; |
33 | class AsyncCallQueue; | |
34 | ||
63be0a78 | 35 | /** |
36 | \todo add unique call IDs | |
37 | \todo CBDATA_CLASS2 kids | |
38 | \ingroup AsyncCallsAPI | |
39 | */ | |
3e5c8cf4 | 40 | class AsyncCall: public RefCountable |
41 | { | |
42 | public: | |
43 | typedef RefCount <AsyncCall> Pointer; | |
44 | friend class AsyncCallQueue; | |
45 | ||
46 | AsyncCall(int aDebugSection, int aDebugLevel, const char *aName); | |
47 | virtual ~AsyncCall(); | |
26ac0430 | 48 | |
3e5c8cf4 | 49 | void make(); // fire if we can; handles general call debugging |
50 | ||
51 | // can be called from canFire() for debugging; always returns false | |
52 | bool cancel(const char *reason); | |
26ac0430 | 53 | |
3e5c8cf4 | 54 | bool canceled() { return isCanceled != NULL; } |
55 | ||
56 | virtual CallDialer *getDialer() = 0; | |
57 | ||
58 | void print(std::ostream &os); | |
26ac0430 | 59 | |
37cba319 AR |
60 | /// remove us from the queue; we are head unless we are queued after prev |
61 | void dequeue(AsyncCall::Pointer &head, AsyncCall::Pointer &prev); | |
62 | ||
3e5c8cf4 | 63 | void setNext(AsyncCall::Pointer aNext) { |
26ac0430 | 64 | theNext = aNext; |
3e5c8cf4 | 65 | } |
66 | ||
67 | AsyncCall::Pointer &Next() { | |
26ac0430 | 68 | return theNext; |
3e5c8cf4 | 69 | } |
70 | ||
71 | public: | |
72 | const char *const name; | |
73 | const int debugSection; | |
74 | const int debugLevel; | |
52ed047a | 75 | const InstanceId<AsyncCall> id; |
3e5c8cf4 | 76 | |
77 | protected: | |
78 | virtual bool canFire(); | |
79 | ||
80 | virtual void fire() = 0; | |
81 | ||
82 | AsyncCall::Pointer theNext; // used exclusively by AsyncCallQueue | |
83 | ||
84 | private: | |
85 | const char *isCanceled; // set to the cancelation reason by cancel() | |
cbff89ba AJ |
86 | |
87 | // not implemented to prevent nil calls from being passed around and unknowingly scheduled, for now. | |
88 | AsyncCall(); | |
89 | AsyncCall(const AsyncCall &); | |
3e5c8cf4 | 90 | }; |
91 | ||
92 | inline | |
93 | std::ostream &operator <<(std::ostream &os, AsyncCall &call) | |
94 | { | |
95 | call.print(os); | |
96 | return os; | |
854d4d81 | 97 | } |
98 | ||
63be0a78 | 99 | /** |
100 | \ingroup AsyncCallAPI | |
101 | * Interface for all async call dialers | |
102 | */ | |
3e5c8cf4 | 103 | class CallDialer |
104 | { | |
105 | public: | |
106 | CallDialer() {} | |
107 | virtual ~CallDialer() {} | |
108 | ||
109 | // TODO: Add these for clarity when CommCbFunPtrCallT is gone | |
110 | //virtual bool canDial(AsyncCall &call) = 0; | |
111 | //virtual void dial(AsyncCall &call) = 0; | |
112 | ||
113 | virtual void print(std::ostream &os) const = 0; | |
114 | }; | |
115 | ||
63be0a78 | 116 | /** |
117 | \ingroup AsyncCallAPI | |
118 | * This template implements an AsyncCall using a specified Dialer class | |
119 | */ | |
3e5c8cf4 | 120 | template <class Dialer> |
121 | class AsyncCallT: public AsyncCall | |
122 | { | |
123 | public: | |
124 | AsyncCallT(int aDebugSection, int aDebugLevel, const char *aName, | |
26ac0430 AJ |
125 | const Dialer &aDialer): AsyncCall(aDebugSection, aDebugLevel, aName), |
126 | dialer(aDialer) {} | |
3e5c8cf4 | 127 | |
cbff89ba AJ |
128 | AsyncCallT(const AsyncCallT<Dialer> &o): |
129 | AsyncCall(o.debugSection, o.debugLevel, o.name), | |
130 | dialer(o.dialer) {} | |
131 | ||
132 | ~AsyncCallT() {} | |
133 | ||
3e5c8cf4 | 134 | CallDialer *getDialer() { return &dialer; } |
135 | ||
136 | protected: | |
26ac0430 AJ |
137 | virtual bool canFire() { |
138 | return AsyncCall::canFire() && | |
139 | dialer.canDial(*this); | |
140 | } | |
3e5c8cf4 | 141 | virtual void fire() { dialer.dial(*this); } |
142 | ||
143 | Dialer dialer; | |
cbff89ba AJ |
144 | |
145 | private: | |
146 | AsyncCallT & operator=(const AsyncCallT &); // not defined. call assignments not permitted. | |
3e5c8cf4 | 147 | }; |
148 | ||
149 | template <class Dialer> | |
150 | inline | |
151 | AsyncCall * | |
152 | asyncCall(int aDebugSection, int aDebugLevel, const char *aName, | |
26ac0430 | 153 | const Dialer &aDialer) |
3e5c8cf4 | 154 | { |
155 | return new AsyncCallT<Dialer>(aDebugSection, aDebugLevel, aName, aDialer); | |
156 | } | |
854d4d81 | 157 | |
63be0a78 | 158 | /** Call scheduling helper. Use ScheduleCallHere if you can. */ |
3e5c8cf4 | 159 | extern bool ScheduleCall(const char *fileName, int fileLine, AsyncCall::Pointer &call); |
63be0a78 | 160 | |
161 | /** Call scheduling helper. */ | |
3e5c8cf4 | 162 | #define ScheduleCallHere(call) ScheduleCall(__FILE__, __LINE__, (call)) |
854d4d81 | 163 | |
854d4d81 | 164 | #endif /* SQUID_ASYNCCALL_H */ |