]> git.ipfire.org Git - thirdparty/squid.git/blame - src/base/AsyncCall.h
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / base / AsyncCall.h
CommitLineData
bbc27441 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
bbc27441
AJ
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
854d4d81 9#ifndef SQUID_ASYNCCALL_H
10#define SQUID_ASYNCCALL_H
11
ccfbe8f4 12#include "base/CodeContext.h"
52ed047a 13#include "base/InstanceId.h"
854d4d81 14#include "event.h"
314782d4 15#include "RefCount.h"
854d4d81 16
63be0a78 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
26ac0430 29 * object is passed to the wrapper. For the method call to be safe, the
63be0a78 30 * class must be cbdata-enabled.
31 \par
32 * You do not have to use the macros below to make or receive asynchronous
26ac0430 33 * method calls, but they give you a uniform interface and handy call
63be0a78 34 * debugging.
35 */
854d4d81 36
3e5c8cf4 37class CallDialer;
3e5c8cf4 38
3e5c8cf4 39class AsyncCall: public RefCountable
40{
41public:
42 typedef RefCount <AsyncCall> Pointer;
3e5c8cf4 43
44 AsyncCall(int aDebugSection, int aDebugLevel, const char *aName);
337b9aa4 45 ~AsyncCall() override;
26ac0430 46
3e5c8cf4 47 void make(); // fire if we can; handles general call debugging
48
49 // can be called from canFire() for debugging; always returns false
50 bool cancel(const char *reason);
26ac0430 51
e5ddd4ce 52 bool canceled() const { return isCanceled != nullptr; }
3e5c8cf4 53
54 virtual CallDialer *getDialer() = 0;
55
56 void print(std::ostream &os);
26ac0430 57
37cba319
AR
58 /// remove us from the queue; we are head unless we are queued after prev
59 void dequeue(AsyncCall::Pointer &head, AsyncCall::Pointer &prev);
60
3e5c8cf4 61 void setNext(AsyncCall::Pointer aNext) {
26ac0430 62 theNext = aNext;
3e5c8cf4 63 }
64
65 AsyncCall::Pointer &Next() {
26ac0430 66 return theNext;
3e5c8cf4 67 }
68
69public:
70 const char *const name;
ccfbe8f4
AR
71
72 /// what the callee is expected to work on
73 CodeContext::Pointer codeContext;
74
3e5c8cf4 75 const int debugSection;
76 const int debugLevel;
52ed047a 77 const InstanceId<AsyncCall> id;
3e5c8cf4 78
79protected:
80 virtual bool canFire();
81
82 virtual void fire() = 0;
83
a928fdfd 84 AsyncCall::Pointer theNext; ///< for AsyncCallList and similar lists
3e5c8cf4 85
86private:
2f8abb64 87 const char *isCanceled; // set to the cancellation reason by cancel()
cbff89ba
AJ
88
89 // not implemented to prevent nil calls from being passed around and unknowingly scheduled, for now.
90 AsyncCall();
91 AsyncCall(const AsyncCall &);
3e5c8cf4 92};
93
94inline
95std::ostream &operator <<(std::ostream &os, AsyncCall &call)
96{
97 call.print(os);
98 return os;
854d4d81 99}
100
63be0a78 101/**
102 \ingroup AsyncCallAPI
103 * Interface for all async call dialers
104 */
3e5c8cf4 105class CallDialer
106{
107public:
108 CallDialer() {}
109 virtual ~CallDialer() {}
110
111 // TODO: Add these for clarity when CommCbFunPtrCallT is gone
112 //virtual bool canDial(AsyncCall &call) = 0;
113 //virtual void dial(AsyncCall &call) = 0;
114
115 virtual void print(std::ostream &os) const = 0;
116};
117
63be0a78 118/**
119 \ingroup AsyncCallAPI
120 * This template implements an AsyncCall using a specified Dialer class
121 */
e5ddd4ce 122template <class DialerClass>
3e5c8cf4 123class AsyncCallT: public AsyncCall
124{
125public:
e5ddd4ce
AR
126 using Dialer = DialerClass;
127
3e5c8cf4 128 AsyncCallT(int aDebugSection, int aDebugLevel, const char *aName,
26ac0430 129 const Dialer &aDialer): AsyncCall(aDebugSection, aDebugLevel, aName),
f53969cc 130 dialer(aDialer) {}
3e5c8cf4 131
cbff89ba 132 AsyncCallT(const AsyncCallT<Dialer> &o):
f53969cc
SM
133 AsyncCall(o.debugSection, o.debugLevel, o.name),
134 dialer(o.dialer) {}
cbff89ba 135
337b9aa4 136 ~AsyncCallT() override {}
cbff89ba 137
337b9aa4 138 CallDialer *getDialer() override { return &dialer; }
3e5c8cf4 139
e5ddd4ce
AR
140 Dialer dialer;
141
3e5c8cf4 142protected:
337b9aa4 143 bool canFire() override {
26ac0430
AJ
144 return AsyncCall::canFire() &&
145 dialer.canDial(*this);
146 }
337b9aa4 147 void fire() override { dialer.dial(*this); }
3e5c8cf4 148
cbff89ba
AJ
149private:
150 AsyncCallT & operator=(const AsyncCallT &); // not defined. call assignments not permitted.
3e5c8cf4 151};
152
153template <class Dialer>
1b1b2805 154RefCount< AsyncCallT<Dialer> >
3e5c8cf4 155asyncCall(int aDebugSection, int aDebugLevel, const char *aName,
26ac0430 156 const Dialer &aDialer)
3e5c8cf4 157{
158 return new AsyncCallT<Dialer>(aDebugSection, aDebugLevel, aName, aDialer);
159}
854d4d81 160
63be0a78 161/** Call scheduling helper. Use ScheduleCallHere if you can. */
e5ddd4ce 162bool ScheduleCall(const char *fileName, int fileLine, const AsyncCall::Pointer &);
63be0a78 163
164/** Call scheduling helper. */
3e5c8cf4 165#define ScheduleCallHere(call) ScheduleCall(__FILE__, __LINE__, (call))
854d4d81 166
854d4d81 167#endif /* SQUID_ASYNCCALL_H */
f53969cc 168