]>
Commit | Line | Data |
---|---|---|
854d4d81 | 1 | /* |
63be0a78 | 2 | * $Id: AsyncCall.h,v 1.4 2008/02/26 21:49:34 amosjeffries Exp $ |
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 | |
24 | * object is passed to the wrapper. For the method call to be safe, the | |
25 | * class must be cbdata-enabled. | |
26 | \par | |
27 | * You do not have to use the macros below to make or receive asynchronous | |
28 | * method calls, but they give you a uniform interface and handy call | |
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(); | |
48 | ||
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); | |
53 | ||
54 | bool canceled() { return isCanceled != NULL; } | |
55 | ||
56 | virtual CallDialer *getDialer() = 0; | |
57 | ||
58 | void print(std::ostream &os); | |
59 | ||
60 | void setNext(AsyncCall::Pointer aNext) { | |
61 | theNext = aNext; | |
62 | } | |
63 | ||
64 | AsyncCall::Pointer &Next() { | |
65 | return theNext; | |
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, | |
119 | const Dialer &aDialer): AsyncCall(aDebugSection, aDebugLevel, aName), | |
120 | dialer(aDialer) {} | |
121 | ||
122 | CallDialer *getDialer() { return &dialer; } | |
123 | ||
124 | protected: | |
125 | virtual bool canFire() { return AsyncCall::canFire() && | |
126 | dialer.canDial(*this); } | |
127 | virtual void fire() { dialer.dial(*this); } | |
128 | ||
129 | Dialer dialer; | |
130 | }; | |
131 | ||
132 | template <class Dialer> | |
133 | inline | |
134 | AsyncCall * | |
135 | asyncCall(int aDebugSection, int aDebugLevel, const char *aName, | |
136 | const Dialer &aDialer) | |
137 | { | |
138 | return new AsyncCallT<Dialer>(aDebugSection, aDebugLevel, aName, aDialer); | |
139 | } | |
854d4d81 | 140 | |
63be0a78 | 141 | /** Call scheduling helper. Use ScheduleCallHere if you can. */ |
3e5c8cf4 | 142 | extern bool ScheduleCall(const char *fileName, int fileLine, AsyncCall::Pointer &call); |
63be0a78 | 143 | |
144 | /** Call scheduling helper. */ | |
3e5c8cf4 | 145 | #define ScheduleCallHere(call) ScheduleCall(__FILE__, __LINE__, (call)) |
854d4d81 | 146 | |
147 | ||
148 | #endif /* SQUID_ASYNCCALL_H */ |