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