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