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