]>
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" | |
9 | #include "event.h" | |
3e5c8cf4 | 10 | //#include "TextException.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 | |
3e5c8cf4 | 60 | void setNext(AsyncCall::Pointer aNext) { |
26ac0430 | 61 | theNext = aNext; |
3e5c8cf4 | 62 | } |
63 | ||
64 | AsyncCall::Pointer &Next() { | |
26ac0430 | 65 | return theNext; |
3e5c8cf4 | 66 | } |
67 | ||
68 | public: | |
69 | const char *const name; | |
70 | const int debugSection; | |
71 | const int debugLevel; | |
72 | const unsigned int id; | |
73 | ||
74 | protected: | |
75 | virtual bool canFire(); | |
76 | ||
77 | virtual void fire() = 0; | |
78 | ||
79 | AsyncCall::Pointer theNext; // used exclusively by AsyncCallQueue | |
80 | ||
81 | private: | |
82 | const char *isCanceled; // set to the cancelation reason by cancel() | |
83 | static unsigned int TheLastId; | |
84 | }; | |
85 | ||
86 | inline | |
87 | std::ostream &operator <<(std::ostream &os, AsyncCall &call) | |
88 | { | |
89 | call.print(os); | |
90 | return os; | |
854d4d81 | 91 | } |
92 | ||
63be0a78 | 93 | /** |
94 | \ingroup AsyncCallAPI | |
95 | * Interface for all async call dialers | |
96 | */ | |
3e5c8cf4 | 97 | class CallDialer |
98 | { | |
99 | public: | |
100 | CallDialer() {} | |
101 | virtual ~CallDialer() {} | |
102 | ||
103 | // TODO: Add these for clarity when CommCbFunPtrCallT is gone | |
104 | //virtual bool canDial(AsyncCall &call) = 0; | |
105 | //virtual void dial(AsyncCall &call) = 0; | |
106 | ||
107 | virtual void print(std::ostream &os) const = 0; | |
108 | }; | |
109 | ||
63be0a78 | 110 | /** |
111 | \ingroup AsyncCallAPI | |
112 | * This template implements an AsyncCall using a specified Dialer class | |
113 | */ | |
3e5c8cf4 | 114 | template <class Dialer> |
115 | class AsyncCallT: public AsyncCall | |
116 | { | |
117 | public: | |
118 | AsyncCallT(int aDebugSection, int aDebugLevel, const char *aName, | |
26ac0430 AJ |
119 | const Dialer &aDialer): AsyncCall(aDebugSection, aDebugLevel, aName), |
120 | dialer(aDialer) {} | |
3e5c8cf4 | 121 | |
122 | CallDialer *getDialer() { return &dialer; } | |
123 | ||
124 | protected: | |
26ac0430 AJ |
125 | virtual bool canFire() { |
126 | return AsyncCall::canFire() && | |
127 | dialer.canDial(*this); | |
128 | } | |
3e5c8cf4 | 129 | virtual void fire() { dialer.dial(*this); } |
130 | ||
131 | Dialer dialer; | |
132 | }; | |
133 | ||
134 | template <class Dialer> | |
135 | inline | |
136 | AsyncCall * | |
137 | asyncCall(int aDebugSection, int aDebugLevel, const char *aName, | |
26ac0430 | 138 | const Dialer &aDialer) |
3e5c8cf4 | 139 | { |
140 | return new AsyncCallT<Dialer>(aDebugSection, aDebugLevel, aName, aDialer); | |
141 | } | |
854d4d81 | 142 | |
63be0a78 | 143 | /** Call scheduling helper. Use ScheduleCallHere if you can. */ |
3e5c8cf4 | 144 | extern bool ScheduleCall(const char *fileName, int fileLine, AsyncCall::Pointer &call); |
63be0a78 | 145 | |
146 | /** Call scheduling helper. */ | |
3e5c8cf4 | 147 | #define ScheduleCallHere(call) ScheduleCall(__FILE__, __LINE__, (call)) |
854d4d81 | 148 | |
149 | ||
150 | #endif /* SQUID_ASYNCCALL_H */ |