]> git.ipfire.org Git - thirdparty/squid.git/blob - src/base/AsyncJob.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / base / AsyncJob.cc
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 /* DEBUG: section 93 ICAP (RFC 3507) Client */
10
11 #include "squid.h"
12 #include "base/AsyncCall.h"
13 #include "base/AsyncJob.h"
14 #include "base/AsyncJobCalls.h"
15 #include "base/TextException.h"
16 #include "cbdata.h"
17 #include "MemBuf.h"
18
19 #include <ostream>
20
21 InstanceIdDefinitions(AsyncJob, "job");
22
23 AsyncJob::Pointer AsyncJob::Start(AsyncJob *j)
24 {
25 AsyncJob::Pointer job(j);
26 CallJobHere(93, 5, job, AsyncJob, start);
27 return job;
28 }
29
30 AsyncJob::AsyncJob(const char *aTypeName) :
31 stopReason(NULL), typeName(aTypeName), inCall(NULL)
32 {
33 debugs(93,5, "AsyncJob constructed, this=" << this <<
34 " type=" << typeName << " [" << id << ']');
35 }
36
37 AsyncJob::~AsyncJob()
38 {
39 debugs(93,5, "AsyncJob destructed, this=" << this <<
40 " type=" << typeName << " [" << id << ']');
41 }
42
43 void AsyncJob::start()
44 {
45 }
46
47 // XXX: temporary code to replace calls to "delete this" in jobs-in-transition.
48 // Will be replaced with calls to mustStop() when transition is complete.
49 void AsyncJob::deleteThis(const char *aReason)
50 {
51 Must(aReason);
52 stopReason = aReason;
53 if (inCall != NULL) {
54 // if we are in-call, then the call wrapper will delete us
55 debugs(93, 4, typeName << " will NOT delete in-call job, reason: " << stopReason);
56 return;
57 }
58
59 // there is no call wrapper waiting for our return, so we fake it
60 debugs(93, 5, typeName << " will delete this, reason: " << stopReason);
61 CbcPointer<AsyncJob> self(this);
62 AsyncCall::Pointer fakeCall = asyncCall(93,4, "FAKE-deleteThis",
63 JobMemFun(self, &AsyncJob::deleteThis, aReason));
64 inCall = fakeCall;
65 callEnd();
66 // delete fakeCall;
67 }
68
69 void AsyncJob::mustStop(const char *aReason)
70 {
71 // XXX: temporary code to catch cases where mustStop is called outside
72 // of an async call context. Will be removed when that becomes impossible.
73 // Until then, this will cause memory leaks and possibly other problems.
74 if (!inCall) {
75 stopReason = aReason;
76 debugs(93, 5, typeName << " will STALL, reason: " << stopReason);
77 return;
78 }
79
80 Must(inCall != NULL); // otherwise nobody will delete us if we are done()
81 Must(aReason);
82 if (!stopReason) {
83 stopReason = aReason;
84 debugs(93, 5, typeName << " will stop, reason: " << stopReason);
85 } else {
86 debugs(93, 5, typeName << " will stop, another reason: " << aReason);
87 }
88 }
89
90 bool AsyncJob::done() const
91 {
92 // stopReason, set in mustStop(), overwrites all other conditions
93 return stopReason != NULL || doneAll();
94 }
95
96 bool AsyncJob::doneAll() const
97 {
98 return true; // so that it is safe for kids to use
99 }
100
101 bool AsyncJob::canBeCalled(AsyncCall &call) const
102 {
103 if (inCall != NULL) {
104 // This may happen when we have bugs or some module is not calling
105 // us asynchronously (comm used to do that).
106 debugs(93, 5, HERE << inCall << " is in progress; " <<
107 call << " canot reenter the job.");
108 return call.cancel("reentrant job call");
109 }
110
111 return true;
112 }
113
114 void AsyncJob::callStart(AsyncCall &call)
115 {
116 // we must be called asynchronously and hence, the caller must lock us
117 Must(cbdataReferenceValid(toCbdata()));
118
119 Must(!inCall); // see AsyncJob::canBeCalled
120
121 inCall = &call; // XXX: ugly, but safe if callStart/callEnd,Ex are paired
122 debugs(inCall->debugSection, inCall->debugLevel,
123 typeName << " status in:" << status());
124 }
125
126 void
127 AsyncJob::callException(const std::exception &)
128 {
129 // we must be called asynchronously and hence, the caller must lock us
130 Must(cbdataReferenceValid(toCbdata()));
131
132 mustStop("exception");
133 }
134
135 void AsyncJob::callEnd()
136 {
137 if (done()) {
138 debugs(93, 5, *inCall << " ends job" << status());
139
140 AsyncCall::Pointer inCallSaved = inCall;
141 void *thisSaved = this;
142
143 swanSong();
144
145 delete this; // this is the only place where the object is deleted
146
147 // careful: this object does not exist any more
148 debugs(93, 6, HERE << *inCallSaved << " ended " << thisSaved);
149 return;
150 }
151
152 debugs(inCall->debugSection, inCall->debugLevel,
153 typeName << " status out:" << status());
154 inCall = NULL;
155 }
156
157 // returns a temporary string depicting transaction status, for debugging
158 const char *AsyncJob::status() const
159 {
160 static MemBuf buf;
161 buf.reset();
162
163 buf.append(" [", 2);
164 if (stopReason != NULL) {
165 buf.Printf("Stopped, reason:");
166 buf.Printf("%s",stopReason);
167 }
168 buf.Printf(" %s%u]", id.Prefix, id.value);
169 buf.terminate();
170
171 return buf.content();
172 }
173