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