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