]> git.ipfire.org Git - thirdparty/squid.git/blob - src/base/AsyncCall.h
merge from trunk
[thirdparty/squid.git] / src / base / AsyncCall.h
1 /*
2 * $Id$
3 */
4
5 #ifndef SQUID_ASYNCCALL_H
6 #define SQUID_ASYNCCALL_H
7
8 //#include "cbdata.h"
9 #include "base/InstanceId.h"
10 #include "event.h"
11 //#include "TextException.h"
12
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
25 * object is passed to the wrapper. For the method call to be safe, the
26 * class must be cbdata-enabled.
27 \par
28 * You do not have to use the macros below to make or receive asynchronous
29 * method calls, but they give you a uniform interface and handy call
30 * debugging.
31 */
32
33 class CallDialer;
34 class AsyncCallQueue;
35
36 /**
37 \todo add unique call IDs
38 \todo CBDATA_CLASS2 kids
39 \ingroup AsyncCallsAPI
40 */
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();
49
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);
54
55 bool canceled() { return isCanceled != NULL; }
56
57 virtual CallDialer *getDialer() = 0;
58
59 void print(std::ostream &os);
60
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
64 void setNext(AsyncCall::Pointer aNext) {
65 theNext = aNext;
66 }
67
68 AsyncCall::Pointer &Next() {
69 return theNext;
70 }
71
72 public:
73 const char *const name;
74 const int debugSection;
75 const int debugLevel;
76 const InstanceId<AsyncCall> id;
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()
87
88 // not implemented to prevent nil calls from being passed around and unknowingly scheduled, for now.
89 AsyncCall();
90 AsyncCall(const AsyncCall &);
91 };
92
93 inline
94 std::ostream &operator <<(std::ostream &os, AsyncCall &call)
95 {
96 call.print(os);
97 return os;
98 }
99
100 /**
101 \ingroup AsyncCallAPI
102 * Interface for all async call dialers
103 */
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
117 /**
118 \ingroup AsyncCallAPI
119 * This template implements an AsyncCall using a specified Dialer class
120 */
121 template <class Dialer>
122 class AsyncCallT: public AsyncCall
123 {
124 public:
125 AsyncCallT(int aDebugSection, int aDebugLevel, const char *aName,
126 const Dialer &aDialer): AsyncCall(aDebugSection, aDebugLevel, aName),
127 dialer(aDialer) {}
128
129 AsyncCallT(const AsyncCallT<Dialer> &o):
130 AsyncCall(o.debugSection, o.debugLevel, o.name),
131 dialer(o.dialer) {}
132
133 ~AsyncCallT() {}
134
135 CallDialer *getDialer() { return &dialer; }
136
137 protected:
138 virtual bool canFire() {
139 return AsyncCall::canFire() &&
140 dialer.canDial(*this);
141 }
142 virtual void fire() { dialer.dial(*this); }
143
144 Dialer dialer;
145
146 private:
147 AsyncCallT & operator=(const AsyncCallT &); // not defined. call assignments not permitted.
148 };
149
150 template <class Dialer>
151 inline
152 AsyncCall *
153 asyncCall(int aDebugSection, int aDebugLevel, const char *aName,
154 const Dialer &aDialer)
155 {
156 return new AsyncCallT<Dialer>(aDebugSection, aDebugLevel, aName, aDialer);
157 }
158
159 /** Call scheduling helper. Use ScheduleCallHere if you can. */
160 extern bool ScheduleCall(const char *fileName, int fileLine, AsyncCall::Pointer &call);
161
162 /** Call scheduling helper. */
163 #define ScheduleCallHere(call) ScheduleCall(__FILE__, __LINE__, (call))
164
165
166 #endif /* SQUID_ASYNCCALL_H */