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