]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Author: Alex Rousskov <rousskov@measurement-factory.com>
authorAmos Jeffries <amosjeffries@squid-cache.org>
Fri, 27 Aug 2010 16:16:29 +0000 (10:16 -0600)
committerAmos Jeffries <amosjeffries@squid-cache.org>
Fri, 27 Aug 2010 16:16:29 +0000 (10:16 -0600)
Bug 2583: pure virtual method called

When a cbdata-protected class holds its own cbdata and has virtual
toCbdata(), there is a catch22 problem: we need cbdata to know whether
the pointer to the class object is valid, and we need to dereference
that pointer to get cbdata.

Added CbcPointer class to hold both a pointer to a potentially freed
class object and the cbdata pointer protecting that object. Keeping the
cbdata pointer allows us to test whether the object is still there
without dereferencing the object pointer.

Use the CbcPointer class to hold safe pointers to AsyncJobs. This
prevents "pure virtual method called" failures because we no longer
dereference freed job pointers.

Removed Initiator parameter from many initiatee constructors. The
Adaptation::Initiator::initiateAdaptation method now sets the initiator
of the job. This makes the constructor profile simpler and removes the
need to propagate Initiator changes through all the [nested]
constructors.

Renamed AsyncJob::AsyncStart() to AsyncJob::Start(). I had to change the
callers code anyway and it was a good opportunity to remove the
redundant "Async".

Special thanks to Stefan Fritsch for updating and testing an earlier
version of this patch.

37 files changed:
src/BodyPipe.cc
src/BodyPipe.h
src/CommCalls.h
src/Server.cc
src/Server.h
src/adaptation/AccessCheck.cc
src/adaptation/Initiate.cc
src/adaptation/Initiate.h
src/adaptation/Initiator.cc
src/adaptation/Initiator.h
src/adaptation/Iterator.cc
src/adaptation/Iterator.h
src/adaptation/Service.h
src/adaptation/ecap/ServiceRep.cc
src/adaptation/ecap/ServiceRep.h
src/adaptation/ecap/XactionRep.cc
src/adaptation/ecap/XactionRep.h
src/adaptation/icap/Launcher.cc
src/adaptation/icap/Launcher.h
src/adaptation/icap/ModXact.cc
src/adaptation/icap/ModXact.h
src/adaptation/icap/OptXact.cc
src/adaptation/icap/OptXact.h
src/adaptation/icap/ServiceRep.cc
src/adaptation/icap/ServiceRep.h
src/adaptation/icap/Xaction.cc
src/adaptation/icap/Xaction.h
src/base/AsyncJob.cc
src/base/AsyncJob.h
src/base/AsyncJobCalls.h
src/base/CbcPointer.h [new file with mode: 0644]
src/base/Makefile.am
src/client_side.cc
src/client_side_request.cc
src/client_side_request.h
src/ftp.cc
src/http.cc

index eb0a7e52d4c8780ef9289f5c77bc6692a42da761..98b979e24c364164d5f199dcf7b46cdffc20f62a 100644 (file)
@@ -1,5 +1,6 @@
 
 #include "squid.h"
+#include "base/AsyncJobCalls.h"
 #include "BodyPipe.h"
 #include "TextException.h"
 
@@ -40,8 +41,9 @@ class BodyProducerDialer: public UnaryMemFunT<BodyProducer, BodyPipe::Pointer>
 public:
     typedef UnaryMemFunT<BodyProducer, BodyPipe::Pointer> Parent;
 
-    BodyProducerDialer(BodyProducer *aProducer, Parent::Method aHandler,
-                       BodyPipe::Pointer bp): Parent(aProducer, aHandler, bp) {}
+    BodyProducerDialer(const BodyProducer::Pointer &aProducer,
+                       Parent::Method aHandler, BodyPipe::Pointer bp):
+            Parent(aProducer, aHandler, bp) {}
 
     virtual bool canDial(AsyncCall &call);
 };
@@ -54,8 +56,9 @@ class BodyConsumerDialer: public UnaryMemFunT<BodyConsumer, BodyPipe::Pointer>
 public:
     typedef UnaryMemFunT<BodyConsumer, BodyPipe::Pointer> Parent;
 
-    BodyConsumerDialer(BodyConsumer *aConsumer, Parent::Method aHandler,
-                       BodyPipe::Pointer bp): Parent(aConsumer, aHandler, bp) {}
+    BodyConsumerDialer(const BodyConsumer::Pointer &aConsumer,
+                       Parent::Method aHandler, BodyPipe::Pointer bp):
+            Parent(aConsumer, aHandler, bp) {}
 
     virtual bool canDial(AsyncCall &call);
 };
@@ -66,7 +69,7 @@ BodyProducerDialer::canDial(AsyncCall &call)
     if (!Parent::canDial(call))
         return false;
 
-    BodyProducer *producer = object;
+    const BodyProducer::Pointer &producer = job;
     BodyPipe::Pointer pipe = arg1;
     if (!pipe->stillProducing(producer)) {
         debugs(call.debugSection, call.debugLevel, HERE << producer <<
@@ -83,7 +86,7 @@ BodyConsumerDialer::canDial(AsyncCall &call)
     if (!Parent::canDial(call))
         return false;
 
-    BodyConsumer *consumer = object;
+    const BodyConsumer::Pointer &consumer = job;
     BodyPipe::Pointer pipe = arg1;
     if (!pipe->stillConsuming(consumer)) {
         debugs(call.debugSection, call.debugLevel, HERE << consumer <<
@@ -183,9 +186,9 @@ uint64_t BodyPipe::unproducedSize() const
 void
 BodyPipe::clearProducer(bool atEof)
 {
-    if (theProducer) {
+    if (theProducer.set()) {
         debugs(91,7, HERE << "clearing BodyPipe producer" << status());
-        theProducer = NULL;
+        theProducer.clear();
         if (atEof) {
             if (!bodySizeKnown())
                 theBodySize = thePutSize;
@@ -215,10 +218,10 @@ BodyPipe::putMoreData(const char *aBuffer, size_t size)
 }
 
 bool
-BodyPipe::setConsumerIfNotLate(Consumer *aConsumer)
+BodyPipe::setConsumerIfNotLate(const Consumer::Pointer &aConsumer)
 {
     assert(!theConsumer);
-    assert(aConsumer);
+    assert(aConsumer.set()); // but might be invalid
 
     // TODO: convert this into an exception and remove IfNotLate suffix
     // If there is something consumed already, we are in an auto-consuming mode
@@ -247,9 +250,9 @@ BodyPipe::setConsumerIfNotLate(Consumer *aConsumer)
 void
 BodyPipe::clearConsumer()
 {
-    if (theConsumer) {
+    if (theConsumer.set()) {
         debugs(91,7, HERE << "clearing consumer" << status());
-        theConsumer = NULL;
+        theConsumer.clear();
         if (consumedSize() && !exhausted()) {
             AsyncCall::Pointer call= asyncCall(91, 7,
                                                "BodyProducer::noteBodyConsumerAborted",
@@ -377,7 +380,7 @@ BodyPipe::postAppend(size_t size)
 void
 BodyPipe::scheduleBodyDataNotification()
 {
-    if (theConsumer) {
+    if (theConsumer.valid()) { // TODO: allow asyncCall() to check this instead
         AsyncCall::Pointer call = asyncCall(91, 7,
                                             "BodyConsumer::noteMoreBodyDataAvailable",
                                             BodyConsumerDialer(theConsumer,
@@ -389,7 +392,7 @@ BodyPipe::scheduleBodyDataNotification()
 void
 BodyPipe::scheduleBodyEndNotification()
 {
-    if (theConsumer) {
+    if (theConsumer.valid()) { // TODO: allow asyncCall() to check this instead
         if (bodySizeKnown() && bodySize() == thePutSize) {
             AsyncCall::Pointer call = asyncCall(91, 7,
                                                 "BodyConsumer::noteBodyProductionEnded",
@@ -423,10 +426,10 @@ const char *BodyPipe::status() const
     outputBuffer.Printf(" %d+%d", (int)theBuf.contentSize(), (int)theBuf.spaceSize());
 
     outputBuffer.Printf(" pipe%p", this);
-    if (theProducer)
-        outputBuffer.Printf(" prod%p", theProducer);
-    if (theConsumer)
-        outputBuffer.Printf(" cons%p", theConsumer);
+    if (theProducer.set())
+        outputBuffer.Printf(" prod%p", theProducer.get());
+    if (theConsumer.set())
+        outputBuffer.Printf(" cons%p", theConsumer.get());
 
     if (mustAutoConsume)
         outputBuffer.append(" A", 2);
index ee5378b59487807386d26d6037dd2717146d3f62..47e30349d4d1400667b38fbdf4ae534a83847074 100644 (file)
@@ -3,8 +3,8 @@
 #define SQUID_BODY_PIPE_H
 
 #include "MemBuf.h"
-#include "base/AsyncCall.h"
 #include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
 
 class BodyPipe;
 
@@ -14,6 +14,8 @@ class BodyPipe;
 class BodyProducer: virtual public AsyncJob
 {
 public:
+    typedef CbcPointer<BodyProducer> Pointer;
+
     BodyProducer():AsyncJob("BodyProducer") {}
     virtual ~BodyProducer() {}
 
@@ -31,6 +33,8 @@ protected:
 class BodyConsumer: virtual public AsyncJob
 {
 public:
+    typedef CbcPointer<BodyConsumer> Pointer;
+
     BodyConsumer():AsyncJob("BodyConsumer") {}
     virtual ~BodyConsumer() {}
 
@@ -100,16 +104,16 @@ public:
     bool mayNeedMoreData() const { return !bodySizeKnown() || needsMoreData(); }
     bool needsMoreData() const { return bodySizeKnown() && unproducedSize() > 0; }
     uint64_t unproducedSize() const; // size of still unproduced data
-    bool stillProducing(const Producer *producer) const { return theProducer == producer; }
+    bool stillProducing(const Producer::Pointer &producer) const { return theProducer == producer; }
 
     // called by consumers
-    bool setConsumerIfNotLate(Consumer *aConsumer);
+    bool setConsumerIfNotLate(const Consumer::Pointer &aConsumer);
     void clearConsumer(); // aborts if still piping
     size_t getMoreData(MemBuf &buf);
     void consume(size_t size);
     bool expectMoreAfter(uint64_t offset) const;
     bool exhausted() const; // saw eof/abort and all data consumed
-    bool stillConsuming(const Consumer *consumer) const { return theConsumer == consumer; }
+    bool stillConsuming(const Consumer::Pointer &consumer) const { return theConsumer == consumer; }
 
     // start or continue consuming when there is no consumer
     void enableAutoConsumption();
@@ -135,8 +139,8 @@ protected:
 
 private:
     int64_t  theBodySize;   // expected total content length, if known
-    Producer *theProducer; // content producer, if any
-    Consumer *theConsumer; // content consumer, if any
+    Producer::Pointer theProducer; // content producer, if any
+    Consumer::Pointer theConsumer; // content consumer, if any
 
     uint64_t thePutSize; // ever-increasing total
     uint64_t theGetSize; // ever-increasing total
index 5012e836b2ce721602adc52c79d7e76b829b417e..84e4a72875a308653fa7c64675a410dd470306ad 100644 (file)
@@ -141,17 +141,18 @@ Params &GetCommParams(AsyncCall::Pointer &call)
 // All job dialers with comm parameters are merged into one since they
 // all have exactly one callback argument and differ in Params type only
 template <class C, class Params_>
-class CommCbMemFunT: public JobDialer, public CommDialerParamsT<Params_>
+class CommCbMemFunT: public JobDialer<C>, public CommDialerParamsT<Params_>
 {
 public:
     typedef Params_ Params;
     typedef void (C::*Method)(const Params &io);
 
-    CommCbMemFunT(C *obj, Method meth): JobDialer(obj),
-            CommDialerParamsT<Params>(obj), object(obj), method(meth) {}
+    CommCbMemFunT(const CbcPointer<C> &job, Method meth): JobDialer<C>(job),
+            CommDialerParamsT<Params_>(job.get()),
+            method(meth) {}
 
     virtual bool canDial(AsyncCall &c) {
-        return JobDialer::canDial(c) &&
+        return JobDialer<C>::canDial(c) &&
                this->params.syncWithComm();
     }
 
@@ -162,11 +163,10 @@ public:
     }
 
 public:
-    C *object;
     Method method;
 
 protected:
-    virtual void doDial() { (object->*method)(this->params); }
+    virtual void doDial() { ((&(*this->job))->*method)(this->params); }
 };
 
 
index 52e0f94203f0b49f4f7f67d101bb4acc80da7105..990cf819d4151399bfbaffe819b2e74fb9c936fa 100644 (file)
@@ -417,8 +417,8 @@ ServerStateData::sendMoreRequestBody()
     if (requestBodySource->getMoreData(buf)) {
         debugs(9,3, HERE << "will write " << buf.contentSize() << " request body bytes");
         typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
-        requestSender = asyncCall(93,3, "ServerStateData::sentRequestBody",
-                                  Dialer(this, &ServerStateData::sentRequestBody));
+        requestSender = JobCallback(93,3,
+                                    Dialer, this, ServerStateData::sentRequestBody);
         comm_write_mbuf(fd, &buf, requestSender);
     } else {
         debugs(9,3, HERE << "will wait for more request body bytes or eof");
@@ -544,8 +544,8 @@ ServerStateData::startAdaptation(const Adaptation::ServiceGroupPointer &group, H
     }
 
     adaptedHeadSource = initiateAdaptation(
-                            new Adaptation::Iterator(this, vrep, cause, group));
-    startedAdaptation = adaptedHeadSource != NULL;
+                            new Adaptation::Iterator(vrep, cause, group));
+    startedAdaptation = initiated(adaptedHeadSource);
     Must(startedAdaptation);
 }
 
index 27e722ab9d73accd47242dfde7e430406ad19b96..d49e770784c836b56fa21db5f8ae0cd9ddcb8bdc 100644 (file)
@@ -186,7 +186,7 @@ protected:
 
 #if USE_ADAPTATION
     BodyPipe::Pointer virginBodyDestination;  /**< to provide virgin response body */
-    Adaptation::Initiate *adaptedHeadSource;  /**< to get adapted response headers */
+    CbcPointer<Adaptation::Initiate> adaptedHeadSource;  /**< to get adapted response headers */
     BodyPipe::Pointer adaptedBodySource;      /**< to consume adated response body */
 
     bool adaptationAccessCheckPending;
index 2f3a12617b43157b8d47a5923726ab52423719c9..abac18d2e04d54fd914b5fbe41b9d1ba9aee7c26 100644 (file)
@@ -23,8 +23,9 @@ Adaptation::AccessCheck::Start(Method method, VectPoint vp,
 
     if (Config::Enabled) {
         // the new check will call the callback and delete self, eventually
-        return AsyncStart(new AccessCheck(
-                              ServiceFilter(method, vp, req, rep), cb, cbdata));
+        AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer
+                            ServiceFilter(method, vp, req, rep), cb, cbdata));
+        return true;
     }
 
     debugs(83, 3, HERE << "adaptation off, skipping");
index 110c4108babfdde84182c2ec24733bbb5d58410f..ffba5bc923b7b64d4f5d5c8eef141c6db373269f 100644 (file)
@@ -6,6 +6,7 @@
 #include "HttpMsg.h"
 #include "adaptation/Initiator.h"
 #include "adaptation/Initiate.h"
+#include "base/AsyncJobCalls.h"
 
 namespace Adaptation
 {
@@ -17,11 +18,13 @@ class AnswerDialer: public UnaryMemFunT<Initiator, HttpMsg*>
 public:
     typedef UnaryMemFunT<Initiator, HttpMsg*> Parent;
 
-    AnswerDialer(Initiator *obj, Parent::Method meth, HttpMsg *msg):
-            Parent(obj, meth, msg) { HTTPMSGLOCK(arg1); }
-    AnswerDialer(const AnswerDialer &d):
-            Parent(d) { HTTPMSGLOCK(arg1); }
+    AnswerDialer(const Parent::JobPointer &job, Parent::Method meth,
+                 HttpMsg *msg): Parent(job, meth, msg) { HTTPMSGLOCK(arg1); }
+    AnswerDialer(const AnswerDialer &d): Parent(d) { HTTPMSGLOCK(arg1); }
     virtual ~AnswerDialer() { HTTPMSGUNLOCK(arg1); }
+
+private:
+    AnswerDialer &operator =(const AnswerDialer &); // not implemented
 };
 
 } // namespace Adaptation
@@ -29,10 +32,8 @@ public:
 
 /* Initiate */
 
-Adaptation::Initiate::Initiate(const char *aTypeName, Initiator *anInitiator):
-        AsyncJob(aTypeName), theInitiator(anInitiator)
+Adaptation::Initiate::Initiate(const char *aTypeName): AsyncJob(aTypeName)
 {
-    assert(theInitiator);
 }
 
 Adaptation::Initiate::~Initiate()
@@ -42,12 +43,21 @@ Adaptation::Initiate::~Initiate()
     // can assert(!(wasStarted && theInitiator)).
 }
 
+void
+Adaptation::Initiate::initiator(const CbcPointer<Initiator> &i)
+{
+    Must(!theInitiator);
+    Must(i.valid());
+    theInitiator = i;
+}
+
+
 // internal cleanup
 void Adaptation::Initiate::swanSong()
 {
     debugs(93, 5, HERE << "swan sings" << status());
 
-    if (theInitiator) {
+    if (theInitiator.set()) {
         debugs(93, 3, HERE << "fatal failure; sending abort notification");
         tellQueryAborted(true); // final by default
     }
@@ -57,27 +67,22 @@ void Adaptation::Initiate::swanSong()
 
 void Adaptation::Initiate::clearInitiator()
 {
-    if (theInitiator)
-        theInitiator.clear();
+    theInitiator.clear();
 }
 
 void Adaptation::Initiate::sendAnswer(HttpMsg *msg)
 {
     assert(msg);
-    if (theInitiator.isThere()) {
-        CallJob(93, 5, __FILE__, __LINE__, "Initiator::noteAdaptAnswer",
-                AnswerDialer(theInitiator.ptr(), &Initiator::noteAdaptationAnswer, msg));
-    }
+    CallJob(93, 5, __FILE__, __LINE__, "Initiator::noteAdaptationAnswer",
+            AnswerDialer(theInitiator, &Initiator::noteAdaptationAnswer, msg));
     clearInitiator();
 }
 
 
 void Adaptation::Initiate::tellQueryAborted(bool final)
 {
-    if (theInitiator.isThere()) {
-        CallJobHere1(93, 5, theInitiator.ptr(),
-                     Initiator::noteAdaptationQueryAbort, final);
-    }
+    CallJobHere1(93, 5, theInitiator,
+                 Initiator, noteAdaptationQueryAbort, final);
     clearInitiator();
 }
 
@@ -85,57 +90,3 @@ const char *Adaptation::Initiate::status() const
 {
     return AsyncJob::status(); // for now
 }
-
-
-/* InitiatorHolder */
-
-Adaptation::InitiatorHolder::InitiatorHolder(Initiator *anInitiator):
-        prime(0), cbdata(0)
-{
-    if (anInitiator) {
-        cbdata = cbdataReference(anInitiator->toCbdata());
-        prime = anInitiator;
-    }
-}
-
-Adaptation::InitiatorHolder::InitiatorHolder(const InitiatorHolder &anInitiator):
-        prime(0), cbdata(0)
-{
-    if (anInitiator != NULL && cbdataReferenceValid(anInitiator.cbdata)) {
-        cbdata = cbdataReference(anInitiator.cbdata);
-        prime = anInitiator.prime;
-    }
-}
-
-Adaptation::InitiatorHolder::~InitiatorHolder()
-{
-    clear();
-}
-
-void Adaptation::InitiatorHolder::clear()
-{
-    if (prime) {
-        prime = NULL;
-        cbdataReferenceDone(cbdata);
-    }
-}
-
-Adaptation::Initiator *Adaptation::InitiatorHolder::ptr()
-{
-    assert(isThere());
-    return prime;
-}
-
-bool
-Adaptation::InitiatorHolder::isThere()
-{
-    return prime && cbdataReferenceValid(cbdata);
-}
-
-// should not be used
-Adaptation::InitiatorHolder &
-Adaptation::InitiatorHolder::operator =(const InitiatorHolder &anInitiator)
-{
-    assert(false);
-    return *this;
-}
index 1cca091995f41b9c52a7bedd7d470873b61a2240..1baa959c274a693c38875606d90096f4e8ac2fea 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef SQUID_ADAPTATION__INITIATE_H
 #define SQUID_ADAPTATION__INITIATE_H
 
-#include "base/AsyncCall.h"
 #include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
 #include "adaptation/forward.h"
 
 class HttpMsg;
@@ -10,37 +10,6 @@ class HttpMsg;
 namespace Adaptation
 {
 
-/* Initiator holder associtates an initiator with its cbdata. It is used as
- * a temporary hack to make cbdata work with multiple inheritance. We need
- * this hack because we cannot know whether the initiator pointer is still
- * valid without dereferencing it to call toCbdata()
- * TODO: JobDialer uses the same trick. Factor out or move this code. */
-class InitiatorHolder
-{
-public:
-    InitiatorHolder(Initiator *anInitiator);
-    InitiatorHolder(const InitiatorHolder &anInitiator);
-    ~InitiatorHolder();
-
-    void clear();
-
-    // to make comparison with NULL possible
-    operator void*() { return prime; }
-    bool operator == (void *) const { return prime == NULL; }
-    bool operator != (void *) const { return prime != NULL; }
-    bool operator !() const { return !prime; }
-
-    bool isThere(); // we have a valid initiator pointer
-    Initiator *ptr(); // asserts isThere()
-    void *theCbdata() { return cbdata;}
-
-private:
-    InitiatorHolder &operator =(const InitiatorHolder &anInitiator);
-
-    Initiator *prime;
-    void *cbdata;
-};
-
 /*
  * The  Initiate is a common base for  queries or transactions
  * initiated by an Initiator. This interface exists to allow an
@@ -56,9 +25,11 @@ class Initiate: virtual public AsyncJob
 {
 
 public:
-    Initiate(const char *aTypeName, Initiator *anInitiator);
+    Initiate(const char *aTypeName);
     virtual ~Initiate();
 
+    void initiator(const CbcPointer<Initiator> &i); ///< sets initiator
+
     // communication with the initiator
     virtual void noteInitiatorAborted() = 0;
 
@@ -71,7 +42,7 @@ protected:
 
     virtual const char *status() const; // for debugging
 
-    InitiatorHolder theInitiator;
+    CbcPointer<Initiator> theInitiator;
 
 private:
     Initiate(const Initiate &); // no definition
index d5ba04223e95a90b442b32bf65f59cc550759c1f..f72e69f8ea6f50cfe14540f46f6bb5042c3c6346 100644 (file)
@@ -5,27 +5,26 @@
 #include "squid.h"
 #include "adaptation/Initiate.h"
 #include "adaptation/Initiator.h"
+#include "base/AsyncJobCalls.h"
 
-Adaptation::Initiate *
-Adaptation::Initiator::initiateAdaptation(Adaptation::Initiate *x)
+CbcPointer<Adaptation::Initiate>
+Adaptation::Initiator::initiateAdaptation(Initiate *x)
 {
-    if ((x = dynamic_cast<Initiate*>(Initiate::AsyncStart(x))))
-        x = cbdataReference(x);
-    return x;
+    CbcPointer<Initiate> i(x);
+    x->initiator(this);
+    Start(x);
+    return i;
 }
 
 void
-Adaptation::Initiator::clearAdaptation(Initiate *&x)
+Adaptation::Initiator::clearAdaptation(CbcPointer<Initiate> &x)
 {
-    assert(x);
-    cbdataReferenceDone(x);
+    x.clear();
 }
 
 void
-Adaptation::Initiator::announceInitiatorAbort(Initiate *&x)
+Adaptation::Initiator::announceInitiatorAbort(CbcPointer<Initiate> &x)
 {
-    if (x) {
-        CallJobHere(93, 5, x, Initiate::noteInitiatorAborted);
-        clearAdaptation(x);
-    }
+    CallJobHere(93, 5, x, Initiate, noteInitiatorAborted);
+    clearAdaptation(x);
 }
index ba2a1254f10957db81ea04346fc915398a8c56d2..32c6a249d742700c914c0240729b62d919fe0c5d 100644 (file)
@@ -2,6 +2,7 @@
 #define SQUID_ADAPTATION__INITIATOR_H
 
 #include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
 #include "adaptation/forward.h"
 
 /*
@@ -32,13 +33,17 @@ public:
     virtual void noteAdaptationQueryAbort(bool final) = 0;
 
 protected:
-    Initiate *initiateAdaptation(Initiate *x); // locks and returns x
+    ///< starts freshly created initiate and returns a safe pointer to it
+    CbcPointer<Initiate> initiateAdaptation(Initiate *x);
 
-    // done with x (and not calling announceInitiatorAbort)
-    void clearAdaptation(Initiate *&x); // unlocks x
+    /// clears the pointer (does not call announceInitiatorAbort)
+    void clearAdaptation(CbcPointer<Initiate> &x);
 
-    // inform the transaction about abnormal termination and clear it
-    void announceInitiatorAbort(Initiate *&x); // unlocks x
+    /// inform the transaction about abnormal termination and clear the pointer
+    void announceInitiatorAbort(CbcPointer<Initiate> &x);
+
+    /// Must(initiated(initiate)) instead of Must(initiate.set()), for clarity
+    bool initiated(const CbcPointer<AsyncJob> &job) const { return job.set(); }
 };
 
 } // namespace Adaptation
index 6ff122c71850b264c20c3ca12d5254893f367be1..89d87c39ae8ae2c7c82a1e6cbe01de868a73886e 100644 (file)
 #include "adaptation/ServiceGroups.h"
 
 
-Adaptation::Iterator::Iterator(Adaptation::Initiator *anInitiator,
-                               HttpMsg *aMsg, HttpRequest *aCause,
-                               const ServiceGroupPointer &aGroup):
+Adaptation::Iterator::Iterator(
+    HttpMsg *aMsg, HttpRequest *aCause,
+    const ServiceGroupPointer &aGroup):
         AsyncJob("Iterator"),
-        Adaptation::Initiate("Iterator", anInitiator),
+        Adaptation::Initiate("Iterator"),
         theGroup(aGroup),
         theMsg(HTTPMSGLOCK(aMsg)),
         theCause(aCause ? HTTPMSGLOCK(aCause) : NULL),
@@ -69,8 +69,8 @@ void Adaptation::Iterator::step()
     debugs(93,5, HERE << "using adaptation service: " << service->cfg().key);
 
     theLauncher = initiateAdaptation(
-                      service->makeXactLauncher(this, theMsg, theCause));
-    Must(theLauncher);
+                      service->makeXactLauncher(theMsg, theCause));
+    Must(initiated(theLauncher));
     Must(!done());
 }
 
@@ -148,10 +148,10 @@ bool Adaptation::Iterator::doneAll() const
 
 void Adaptation::Iterator::swanSong()
 {
-    if (theInitiator)
+    if (theInitiator.set())
         tellQueryAborted(true); // abnormal condition that should not happen
 
-    if (theLauncher)
+    if (initiated(theLauncher))
         clearAdaptation(theLauncher);
 
     Adaptation::Initiate::swanSong();
index 0a0b35483a96fe00e72cf5faffb3c133ce60c204..b1313bf190b7daf2ff9253a5abca0ec93c8730aa 100644 (file)
@@ -21,8 +21,7 @@ namespace Adaptation
 class Iterator: public Initiate, public Initiator
 {
 public:
-    Iterator(Adaptation::Initiator *anInitiator,
-             HttpMsg *virginHeader, HttpRequest *virginCause,
+    Iterator(HttpMsg *virginHeader, HttpRequest *virginCause,
              const Adaptation::ServiceGroupPointer &aGroup);
     virtual ~Iterator();
 
@@ -52,7 +51,7 @@ protected:
     ServicePlan thePlan; ///< which services to use and in what order
     HttpMsg *theMsg; ///< the message being adapted (virgin for each step)
     HttpRequest *theCause; ///< the cause of the original virgin message
-    Adaptation::Initiate *theLauncher; ///< current transaction launcher
+    CbcPointer<Adaptation::Initiate> theLauncher; ///< current transaction launcher
     int iterations; ///< number of steps initiated
     bool adapted; ///< whether the virgin message has been replaced
 
index ab770d9fcd0c9d9b620dc8c7d3f88dd1a7dc1296..d00f4f6184f1d747c1c56c24e27e403a1b890807 100644 (file)
@@ -31,7 +31,7 @@ public:
     virtual bool broken() const;
     virtual bool up() const = 0; // see comments above
 
-    virtual Initiate *makeXactLauncher(Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause) = 0;
+    virtual Initiate *makeXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause) = 0;
 
     typedef void Callback(void *data, Pointer &service);
     void callWhenReady(Callback *cb, void *data);
index 41708bc573e3f4bf5a8941406cb5ad02831a449e..6bac7b18fc528a8982f779964a7f98146a37e72e 100644 (file)
@@ -57,11 +57,11 @@ bool Adaptation::Ecap::ServiceRep::wantsUrl(const String &urlPath) const
 }
 
 Adaptation::Initiate *
-Adaptation::Ecap::ServiceRep::makeXactLauncher(Adaptation::Initiator *initiator,
-        HttpMsg *virgin, HttpRequest *cause)
+Adaptation::Ecap::ServiceRep::makeXactLauncher(HttpMsg *virgin,
+        HttpRequest *cause)
 {
     Must(up());
-    XactionRep *rep = new XactionRep(initiator, virgin, cause, Pointer(this));
+    XactionRep *rep = new XactionRep(virgin, cause, Pointer(this));
     XactionRep::AdapterXaction x(theService->makeXaction(rep));
     rep->master(x);
     return rep;
index 27046b9a98f1af0ff6854480b0c37a17533944f2..9c858ccf268835fce6a28a336f1ab2a410bbb274 100644 (file)
@@ -33,7 +33,7 @@ public:
     virtual bool probed() const;
     virtual bool up() const;
 
-    Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
+    Adaptation::Initiate *makeXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause);
 
     // the methods below can only be called on an up() service
     virtual bool wantsUrl(const String &urlPath) const;
index 6f673422a74dfb42b364a8f2bad38f7031e4d3cf..b0f657e1ad68a68bc45f08d6f6ee8ff19887e381 100644 (file)
 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep);
 
 
-Adaptation::Ecap::XactionRep::XactionRep(Adaptation::Initiator *anInitiator,
-        HttpMsg *virginHeader, HttpRequest *virginCause,
-        const Adaptation::ServicePointer &aService):
+Adaptation::Ecap::XactionRep::XactionRep(
+    HttpMsg *virginHeader, HttpRequest *virginCause,
+    const Adaptation::ServicePointer &aService):
         AsyncJob("Adaptation::Ecap::XactionRep"),
-        Adaptation::Initiate("Adaptation::Ecap::XactionRep", anInitiator),
+        Adaptation::Initiate("Adaptation::Ecap::XactionRep"),
         theService(aService),
         theVirginRep(virginHeader), theCauseRep(NULL),
         proxyingVb(opUndecided), proxyingAb(opUndecided),
index 2930e9e5fdc76873534602f986782f44fc162316..e07cb981bcc3285201d0cef04a02e88b15728c40 100644 (file)
@@ -28,7 +28,7 @@ class XactionRep : public Adaptation::Initiate, public libecap::host::Xaction,
         public BodyConsumer, public BodyProducer
 {
 public:
-    XactionRep(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, const Adaptation::ServicePointer &service);
+    XactionRep(HttpMsg *virginHeader, HttpRequest *virginCause, const Adaptation::ServicePointer &service);
     virtual ~XactionRep();
 
     typedef libecap::shared_ptr<libecap::adapter::Xaction> AdapterXaction;
index 180a114d84e5da7822f4753f560d637032a1b96a..e3c252d92818f26010c812b6527c076f6f5a858f 100644 (file)
@@ -15,9 +15,9 @@
 
 
 Adaptation::Icap::Launcher::Launcher(const char *aTypeName,
-                                     Adaptation::Initiator *anInitiator, Adaptation::ServicePointer &aService):
+                                     Adaptation::ServicePointer &aService):
         AsyncJob(aTypeName),
-        Adaptation::Initiate(aTypeName, anInitiator),
+        Adaptation::Initiate(aTypeName),
         theService(aService), theXaction(0), theLaunches(0)
 {
 }
@@ -31,7 +31,7 @@ void Adaptation::Icap::Launcher::start()
 {
     Adaptation::Initiate::start();
 
-    Must(theInitiator);
+    Must(theInitiator.set());
     launchXaction("first");
 }
 
@@ -47,7 +47,7 @@ void Adaptation::Icap::Launcher::launchXaction(const char *xkind)
     if (theLaunches >= TheConfig.repeat_limit)
         x->disableRepeats("over icap_retry_limit");
     theXaction = initiateAdaptation(x);
-    Must(theXaction);
+    Must(initiated(theXaction));
 }
 
 void Adaptation::Icap::Launcher::noteAdaptationAnswer(HttpMsg *message)
@@ -76,7 +76,7 @@ void Adaptation::Icap::Launcher::noteAdaptationQueryAbort(bool final)
     Must(done()); // swanSong will notify the initiator
 }
 
-void Adaptation::Icap::Launcher::noteXactAbort(XactAbortInfo &info)
+void Adaptation::Icap::Launcher::noteXactAbort(XactAbortInfo info)
 {
     debugs(93,5, HERE << "theXaction:" << theXaction << " launches: " << theLaunches);
 
@@ -102,10 +102,10 @@ bool Adaptation::Icap::Launcher::doneAll() const
 
 void Adaptation::Icap::Launcher::swanSong()
 {
-    if (theInitiator)
+    if (theInitiator.set())
         tellQueryAborted(true); // always final here because abnormal
 
-    if (theXaction)
+    if (theXaction.set())
         clearAdaptation(theXaction);
 
     Adaptation::Initiate::swanSong();
index 23ffffac5209c8a9154013c49a48b180faf74bd8..054b96bf981ce60bee3385db48638127e9cb2a07 100644 (file)
@@ -73,7 +73,7 @@ class XactAbortInfo;
 class Launcher: public Adaptation::Initiate, public Adaptation::Initiator
 {
 public:
-    Launcher(const char *aTypeName, Adaptation::Initiator *anInitiator, Adaptation::ServicePointer &aService);
+    Launcher(const char *aTypeName, Adaptation::ServicePointer &aService);
     virtual ~Launcher();
 
     // Adaptation::Initiate: asynchronous communication with the initiator
@@ -81,7 +81,7 @@ public:
 
     // Adaptation::Initiator: asynchronous communication with the current transaction
     virtual void noteAdaptationAnswer(HttpMsg *message);
-    virtual void noteXactAbort(XactAbortInfo &info);
+    virtual void noteXactAbort(XactAbortInfo info);
 
 private:
     bool canRetry(XactAbortInfo &info) const; //< true if can retry in the case of persistent connection failures
@@ -100,7 +100,7 @@ protected:
     void launchXaction(const char *xkind);
 
     Adaptation::ServicePointer theService; ///< ICAP service for all launches
-    Adaptation::Initiate *theXaction; ///< current ICAP transaction
+    CbcPointer<Initiate> theXaction; ///< current ICAP transaction
     int theLaunches; // the number of transaction launches
 };
 
@@ -114,6 +114,10 @@ public:
     XactAbortInfo(const XactAbortInfo &);
     ~XactAbortInfo();
 
+    std::ostream &print(std::ostream &os) const {
+        return os << isRetriable << ',' << isRepeatable;
+    }
+
     HttpRequest *icapRequest;
     HttpReply *icapReply;
     bool isRetriable;
@@ -123,31 +127,13 @@ private:
     XactAbortInfo &operator =(const XactAbortInfo &); // undefined
 };
 
-/* required by UnaryMemFunT */
-inline std::ostream &operator << (std::ostream &os, Adaptation::Icap::XactAbortInfo info)
+inline
+std::ostream &
+operator <<(std::ostream &os, const XactAbortInfo &xai)
 {
-    // Nothing, it is unused
-    return os;
+    return xai.print(os);
 }
 
-/// A Dialer class used to schedule the Adaptation::Icap::Launcher::noteXactAbort call
-class XactAbortCall: public UnaryMemFunT<Adaptation::Icap::Launcher, Adaptation::Icap::XactAbortInfo>
-{
-public:
-    typedef void (Adaptation::Icap::Launcher::*DialMethod)(Adaptation::Icap::XactAbortInfo &);
-    XactAbortCall(Adaptation::Icap::Launcher *launcer, DialMethod aMethod,
-                  const Adaptation::Icap::XactAbortInfo &info):
-            UnaryMemFunT<Adaptation::Icap::Launcher, Adaptation::Icap::XactAbortInfo>(launcer, NULL, info),
-            dialMethod(aMethod) {}
-    virtual void print(std::ostream &os) const {  os << '(' << "retriable:" << arg1.isRetriable << ", repeatable:" << arg1.isRepeatable << ')'; }
-
-public:
-    DialMethod dialMethod;
-
-protected:
-    virtual void doDial() { (object->*dialMethod)(arg1); }
-};
-
 } // namespace Icap
 } // namespace Adaptation
 
index bddee51219b60c2e667bd3d2d8c539deb8daff8b..e6747b46268a746ce06da29e1fadd59b680385b1 100644 (file)
@@ -37,10 +37,10 @@ Adaptation::Icap::ModXact::State::State()
     memset(this, 0, sizeof(*this));
 }
 
-Adaptation::Icap::ModXact::ModXact(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader,
+Adaptation::Icap::ModXact::ModXact(HttpMsg *virginHeader,
                                    HttpRequest *virginCause, Adaptation::Icap::ServiceRep::Pointer &aService):
         AsyncJob("Adaptation::Icap::ModXact"),
-        Adaptation::Icap::Xaction("Adaptation::Icap::ModXact", anInitiator, aService),
+        Adaptation::Icap::Xaction("Adaptation::Icap::ModXact", aService),
         virginConsumed(0),
         bodyParser(NULL),
         canStartBypass(false), // too early
@@ -94,8 +94,9 @@ void Adaptation::Icap::ModXact::waitForService()
     Must(!state.serviceWaiting);
     debugs(93, 7, HERE << "will wait for the ICAP service" << status());
     state.serviceWaiting = true;
-    AsyncCall::Pointer call = asyncCall(93,5, "Adaptation::Icap::ModXact::noteServiceReady",
-                                        MemFun(this, &Adaptation::Icap::ModXact::noteServiceReady));
+    typedef NullaryMemFunT<ModXact> Dialer;
+    AsyncCall::Pointer call = JobCallback(93,5,
+                                          Dialer, this, Adaptation::Icap::ModXact::noteServiceReady);
     service().callWhenReady(call);
 }
 
@@ -1681,9 +1682,9 @@ bool Adaptation::Icap::ModXact::fillVirginHttpHeader(MemBuf &mb) const
 
 /* Adaptation::Icap::ModXactLauncher */
 
-Adaptation::Icap::ModXactLauncher::ModXactLauncher(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer aService):
+Adaptation::Icap::ModXactLauncher::ModXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer aService):
         AsyncJob("Adaptation::Icap::ModXactLauncher"),
-        Adaptation::Icap::Launcher("Adaptation::Icap::ModXactLauncher", anInitiator, aService)
+        Adaptation::Icap::Launcher("Adaptation::Icap::ModXactLauncher", aService)
 {
     virgin.setHeader(virginHeader);
     virgin.setCause(virginCause);
@@ -1695,7 +1696,7 @@ Adaptation::Icap::Xaction *Adaptation::Icap::ModXactLauncher::createXaction()
     Adaptation::Icap::ServiceRep::Pointer s =
         dynamic_cast<Adaptation::Icap::ServiceRep*>(theService.getRaw());
     Must(s != NULL);
-    return new Adaptation::Icap::ModXact(this, virgin.header, virgin.cause, s);
+    return new Adaptation::Icap::ModXact(virgin.header, virgin.cause, s);
 }
 
 void Adaptation::Icap::ModXactLauncher::swanSong()
index a837fcb242d05713e136fc88e032da411da75f41..fd5bbf08f7f797c3a64bd1dec43d40e9bf82d5cb 100644 (file)
@@ -136,7 +136,7 @@ class ModXact: public Xaction, public BodyProducer, public BodyConsumer
 {
 
 public:
-    ModXact(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, ServiceRep::Pointer &s);
+    ModXact(HttpMsg *virginHeader, HttpRequest *virginCause, ServiceRep::Pointer &s);
 
     // BodyProducer methods
     virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer);
@@ -161,7 +161,6 @@ public:
     InOut virgin;
     InOut adapted;
 
-protected:
     // bypasses exceptions if needed and possible
     virtual void callException(const std::exception &e);
 
@@ -322,7 +321,7 @@ private:
 class ModXactLauncher: public Launcher
 {
 public:
-    ModXactLauncher(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer s);
+    ModXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer s);
 
 protected:
     virtual Xaction *createXaction();
index 0eb53af1debb4dbf2972ba83d29d85855f767020..09d217292283b9a806b4a40ce952e19b9d1058ff 100644 (file)
@@ -16,9 +16,9 @@ CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, OptXact);
 CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, OptXactLauncher);
 
 
-Adaptation::Icap::OptXact::OptXact(Adaptation::Initiator *anInitiator, Adaptation::Icap::ServiceRep::Pointer &aService):
+Adaptation::Icap::OptXact::OptXact(Adaptation::Icap::ServiceRep::Pointer &aService):
         AsyncJob("Adaptation::Icap::OptXact"),
-        Adaptation::Icap::Xaction("Adaptation::Icap::OptXact", anInitiator, aService)
+        Adaptation::Icap::Xaction("Adaptation::Icap::OptXact", aService)
 {
 }
 
@@ -111,9 +111,9 @@ void Adaptation::Icap::OptXact::finalizeLogInfo()
 
 /* Adaptation::Icap::OptXactLauncher */
 
-Adaptation::Icap::OptXactLauncher::OptXactLauncher(Adaptation::Initiator *anInitiator, Adaptation::ServicePointer aService):
+Adaptation::Icap::OptXactLauncher::OptXactLauncher(Adaptation::ServicePointer aService):
         AsyncJob("Adaptation::Icap::OptXactLauncher"),
-        Adaptation::Icap::Launcher("Adaptation::Icap::OptXactLauncher", anInitiator, aService)
+        Adaptation::Icap::Launcher("Adaptation::Icap::OptXactLauncher", aService)
 {
 }
 
@@ -122,5 +122,5 @@ Adaptation::Icap::Xaction *Adaptation::Icap::OptXactLauncher::createXaction()
     Adaptation::Icap::ServiceRep::Pointer s =
         dynamic_cast<Adaptation::Icap::ServiceRep*>(theService.getRaw());
     Must(s != NULL);
-    return new Adaptation::Icap::OptXact(this, s);
+    return new Adaptation::Icap::OptXact(s);
 }
index c2119d5d34870abc70f1a4e22bbf6eb6240f6568..35561996dc5f3f8855741b3f91a6b59bac1206e2 100644 (file)
@@ -51,7 +51,7 @@ class OptXact: public Xaction
 {
 
 public:
-    OptXact(Adaptation::Initiator *anInitiator, ServiceRep::Pointer &aService);
+    OptXact(ServiceRep::Pointer &aService);
 
 protected:
     virtual void start();
@@ -76,7 +76,7 @@ private:
 class OptXactLauncher: public Launcher
 {
 public:
-    OptXactLauncher(Adaptation::Initiator *anInitiator, Adaptation::ServicePointer aService);
+    OptXactLauncher(Adaptation::ServicePointer aService);
 
 protected:
     virtual Xaction *createXaction();
index fe45a6a758aa7f763a126ea7af4283efa259930d..3421168eaa3067ad4f749c6da6359db3c10f6a72 100644 (file)
@@ -135,7 +135,7 @@ void Adaptation::Icap::ServiceRep::noteTimeToUpdate()
     if (!detached())
         updateScheduled = false;
 
-    if (detached() || theOptionsFetcher) {
+    if (detached() || theOptionsFetcher.set()) {
         debugs(93,5, HERE << "ignores options update " << status());
         return;
     }
@@ -188,7 +188,7 @@ void Adaptation::Icap::ServiceRep::callWhenReady(AsyncCall::Pointer &cb)
     i.callback = cb;
     theClients.push_back(i);
 
-    if (theOptionsFetcher || notifying)
+    if (theOptionsFetcher.set() || notifying)
         return; // do nothing, we will be picked up in noteTimeToNotify()
 
     if (needNewOptions())
@@ -200,7 +200,7 @@ void Adaptation::Icap::ServiceRep::callWhenReady(AsyncCall::Pointer &cb)
 void Adaptation::Icap::ServiceRep::scheduleNotification()
 {
     debugs(93,7, HERE << "will notify " << theClients.size() << " clients");
-    CallJobHere(93, 5, this, Adaptation::Icap::ServiceRep::noteTimeToNotify);
+    CallJobHere(93, 5, this, Adaptation::Icap::ServiceRepnoteTimeToNotify);
 }
 
 bool Adaptation::Icap::ServiceRep::needNewOptions() const
@@ -294,7 +294,7 @@ void Adaptation::Icap::ServiceRep::announceStatusChange(const char *downPhrase,
 // we are receiving ICAP OPTIONS response headers here or NULL on failures
 void Adaptation::Icap::ServiceRep::noteAdaptationAnswer(HttpMsg *msg)
 {
-    Must(theOptionsFetcher);
+    Must(initiated(theOptionsFetcher));
     clearAdaptation(theOptionsFetcher);
 
     Must(msg);
@@ -314,13 +314,23 @@ void Adaptation::Icap::ServiceRep::noteAdaptationAnswer(HttpMsg *msg)
 
 void Adaptation::Icap::ServiceRep::noteAdaptationQueryAbort(bool)
 {
-    Must(theOptionsFetcher);
+    Must(initiated(theOptionsFetcher));
     clearAdaptation(theOptionsFetcher);
 
     debugs(93,3, HERE << "failed to fetch options " << status());
     handleNewOptions(0);
 }
 
+// we (a) must keep trying to get OPTIONS and (b) are RefCounted so we
+// must keep our job alive (XXX: until nobody needs us)
+void Adaptation::Icap::ServiceRep::callException(const std::exception &e)
+{
+    clearAdaptation(theOptionsFetcher);
+    debugs(93,2, "ICAP probably failed to fetch options (" << e.what() <<
+           ")" << status());
+    handleNewOptions(0);
+}
+
 void Adaptation::Icap::ServiceRep::handleNewOptions(Adaptation::Icap::Options *newOptions)
 {
     // new options may be NULL
@@ -337,9 +347,9 @@ void Adaptation::Icap::ServiceRep::startGettingOptions()
     Must(!theOptionsFetcher);
     debugs(93,6, HERE << "will get new options " << status());
 
-    // XXX: second "this" is "self"; this works but may stop if API changes
-    theOptionsFetcher = initiateAdaptation(new Adaptation::Icap::OptXactLauncher(this, this));
-    Must(theOptionsFetcher);
+    // XXX: "this" here is "self"; works until refcounting API changes
+    theOptionsFetcher = initiateAdaptation(
+                            new Adaptation::Icap::OptXactLauncher(this));
     // TODO: timeout in case Adaptation::Icap::OptXact never calls us back?
     // Such a timeout should probably be a generic AsyncStart feature.
 }
@@ -406,10 +416,10 @@ Adaptation::Icap::ServiceRep::optionsFetchTime() const
 }
 
 Adaptation::Initiate *
-Adaptation::Icap::ServiceRep::makeXactLauncher(Adaptation::Initiator *initiator,
-        HttpMsg *virgin, HttpRequest *cause)
+Adaptation::Icap::ServiceRep::makeXactLauncher(HttpMsg *virgin,
+        HttpRequest *cause)
 {
-    return new Adaptation::Icap::ModXactLauncher(initiator, virgin, cause, this);
+    return new Adaptation::Icap::ModXactLauncher(virgin, cause, this);
 }
 
 // returns a temporary string depicting service status, for debugging
@@ -438,7 +448,7 @@ const char *Adaptation::Icap::ServiceRep::status() const
     if (detached())
         buf.append(",detached", 9);
 
-    if (theOptionsFetcher)
+    if (theOptionsFetcher.set())
         buf.append(",fetch", 6);
 
     if (notifying)
index 23d76443a61a2e86c4858b16cd5cef689a3f2e79..f47fb557510ff09d30604702857248a05ce13191 100644 (file)
@@ -94,7 +94,7 @@ public:
     virtual bool probed() const; // see comments above
     virtual bool up() const; // see comments above
 
-    virtual Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
+    virtual Initiate *makeXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause);
 
     void callWhenReady(AsyncCall::Pointer &cb);
 
@@ -107,6 +107,7 @@ public:
 
     //AsyncJob virtual methods
     virtual bool doneAll() const { return Adaptation::Initiator::doneAll() && false;}
+    virtual void callException(const std::exception &e);
 
     virtual void detach();
     virtual bool detached() const;
@@ -131,7 +132,7 @@ private:
     Clients theClients; // all clients waiting for a call back
 
     Options *theOptions;
-    Adaptation::Initiate *theOptionsFetcher; // pending ICAP OPTIONS transaction
+    CbcPointer<Adaptation::Initiate> theOptionsFetcher; // pending ICAP OPTIONS transaction
     time_t theLastUpdate; // time the options were last updated
 
     static const int TheSessionFailureLimit;
index 3986593864b719591442255fdff32cd1daf6532f..d063d276ab9845f90dcd364efb233259472e29d7 100644 (file)
@@ -24,9 +24,10 @@ static PconnPool *icapPconnPool = new PconnPool("ICAP Servers");
 
 //CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, Xaction);
 
-Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Initiator *anInitiator, Adaptation::Icap::ServiceRep::Pointer &aService):
+Adaptation::Icap::Xaction::Xaction(const char *aTypeName,
+                                   Adaptation::Icap::ServiceRep::Pointer &aService):
         AsyncJob(aTypeName),
-        Adaptation::Initiate(aTypeName, anInitiator),
+        Adaptation::Initiate(aTypeName),
         icapRequest(NULL),
         icapReply(NULL),
         attempts(0),
@@ -105,7 +106,8 @@ void Adaptation::Icap::Xaction::openConnection()
         // fake the connect callback
         // TODO: can we sync call Adaptation::Icap::Xaction::noteCommConnected here instead?
         typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> Dialer;
-        Dialer dialer(this, &Adaptation::Icap::Xaction::noteCommConnected);
+        CbcPointer<Xaction> self(this);
+        Dialer dialer(self, &Adaptation::Icap::Xaction::noteCommConnected);
         dialer.params.fd = connection;
         dialer.params.flag = COMM_OK;
         // fake other parameters by copying from the existing connection
@@ -136,20 +138,19 @@ void Adaptation::Icap::Xaction::openConnection()
 
     // TODO: service bypass status may differ from that of a transaction
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommTimedout",
-                                      TimeoutDialer(this,&Adaptation::Icap::Xaction::noteCommTimedout));
-
+    AsyncCall::Pointer timeoutCall = JobCallback(93, 5,
+                                     TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
     commSetTimeout(connection, TheConfig.connect_timeout(
                        service().cfg().bypass), timeoutCall);
 
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommCloseCbParams> CloseDialer;
-    closer =  asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommClosed",
-                        CloseDialer(this,&Adaptation::Icap::Xaction::noteCommClosed));
+    closer = JobCallback(93, 5,
+                         CloseDialer, this, Adaptation::Icap::Xaction::noteCommClosed);
     comm_add_close_handler(connection, closer);
 
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> ConnectDialer;
-    connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected",
-                          ConnectDialer(this, &Adaptation::Icap::Xaction::noteCommConnected));
+    connector = JobCallback(93,3,
+                            ConnectDialer, this, Adaptation::Icap::Xaction::noteCommConnected);
     commConnectStart(connection, s.cfg().host.termedBuf(), s.cfg().port, connector);
 }
 
@@ -233,8 +234,8 @@ void Adaptation::Icap::Xaction::scheduleWrite(MemBuf &buf)
 {
     // comm module will free the buffer
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
-    writer = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommWrote",
-                       Dialer(this, &Adaptation::Icap::Xaction::noteCommWrote));
+    writer = JobCallback(93,3,
+                         Dialer, this, Adaptation::Icap::Xaction::noteCommWrote);
 
     comm_write_mbuf(connection, &buf, writer);
     updateTimeout();
@@ -316,8 +317,8 @@ void Adaptation::Icap::Xaction::updateTimeout()
         // XXX: why does Config.Timeout lacks a write timeout?
         // TODO: service bypass status may differ from that of a transaction
         typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommTimeoutCbParams> TimeoutDialer;
-        AsyncCall::Pointer call =  asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommTimedout",
-                                             TimeoutDialer(this,&Adaptation::Icap::Xaction::noteCommTimedout));
+        AsyncCall::Pointer call = JobCallback(93,5,
+                                              TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
 
         commSetTimeout(connection,
                        TheConfig.io_timeout(service().cfg().bypass), call);
@@ -340,8 +341,8 @@ void Adaptation::Icap::Xaction::scheduleRead()
      * here instead of reading directly into readBuf.buf.
      */
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
-    reader = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommRead",
-                       Dialer(this, &Adaptation::Icap::Xaction::noteCommRead));
+    reader = JobCallback(93,3,
+                         Dialer, this, Adaptation::Icap::Xaction::noteCommRead);
 
     comm_read(connection, commBuf, readBuf.spaceSize(), reader);
     updateTimeout();
@@ -431,7 +432,7 @@ bool Adaptation::Icap::Xaction::doneWithIo() const
 void Adaptation::Icap::Xaction::noteInitiatorAborted()
 {
 
-    if (theInitiator) {
+    if (theInitiator.set()) {
         clearInitiator();
         mustStop("initiator aborted");
     }
@@ -464,8 +465,7 @@ void Adaptation::Icap::Xaction::swanSong()
     if (commBuf)
         memFreeBuf(commBufSize, commBuf);
 
-    if (theInitiator)
-        tellQueryAborted();
+    tellQueryAborted();
 
     maybeLog();
 
@@ -474,12 +474,15 @@ void Adaptation::Icap::Xaction::swanSong()
 
 void Adaptation::Icap::Xaction::tellQueryAborted()
 {
-    Adaptation::Icap::Launcher *l = dynamic_cast<Adaptation::Icap::Launcher*>(theInitiator.ptr());
-    Adaptation::Icap::XactAbortInfo abortInfo(icapRequest, icapReply, retriable(), repeatable());
-    CallJob(91, 5, __FILE__, __LINE__,
-            "Adaptation::Icap::Launcher::noteXactAbort",
-            XactAbortCall(l, &Adaptation::Icap::Launcher::noteXactAbort, abortInfo) );
-    clearInitiator();
+    if (theInitiator.set()) {
+        Adaptation::Icap::XactAbortInfo abortInfo(icapRequest, icapReply,
+                retriable(), repeatable());
+        Launcher *launcher = dynamic_cast<Launcher*>(theInitiator.get());
+        // launcher may be nil if initiator is invalid
+        CallJobHere1(91,5, CbcPointer<Launcher>(launcher),
+                     Launcher, noteXactAbort, abortInfo);
+        clearInitiator();
+    }
 }
 
 
index 322991601996960953fca7bb92504dabdb7ecb07..4e81dfca917ac1ee96e0ced391fc76f5fc2b2a45 100644 (file)
@@ -63,7 +63,7 @@ class Xaction: public Adaptation::Initiate
 {
 
 public:
-    Xaction(const char *aTypeName, Adaptation::Initiator *anInitiator, ServiceRep::Pointer &aService);
+    Xaction(const char *aTypeName, ServiceRep::Pointer &aService);
     virtual ~Xaction();
 
     void disableRetries();
@@ -125,10 +125,12 @@ protected:
     // useful for debugging
     virtual bool fillVirginHttpHeader(MemBuf&) const;
 
+public:
     // custom exception handling and end-of-call checks
     virtual void callException(const std::exception  &e);
     virtual void callEnd();
 
+protected:
     // logging
     void setOutcome(const XactOutcome &xo);
     virtual void finalizeLogInfo();
index 7db50ad3402b68d800a9ad8f5ddcb9db89b348e1..85b2a313502ca90e56db1327ac5e804a70f6ffba 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include "squid.h"
+#include "base/AsyncJobCalls.h"
 #include "cbdata.h"
 #include "MemBuf.h"
 #include "TextException.h"
 
 unsigned int AsyncJob::TheLastId = 0;
 
-AsyncJob *AsyncJob::AsyncStart(AsyncJob *job)
+AsyncJob::Pointer AsyncJob::Start(AsyncJob *j)
 {
-    assert(job);
-    CallJobHere(93, 5, job, AsyncJob::noteStart);
+    AsyncJob::Pointer job(j);
+    CallJobHere(93, 5, job, AsyncJob, start);
     return job;
 }
 
@@ -29,11 +30,6 @@ AsyncJob::~AsyncJob()
 {
 }
 
-void AsyncJob::noteStart()
-{
-    start();
-}
-
 void AsyncJob::start()
 {
 }
@@ -52,8 +48,9 @@ void AsyncJob::deleteThis(const char *aReason)
 
     // there is no call wrapper waiting for our return, so we fake it
     debugs(93, 5, typeName << " will delete this, reason: " << stopReason);
+    CbcPointer<AsyncJob> self(this);
     AsyncCall::Pointer fakeCall = asyncCall(93,4, "FAKE-deleteThis",
-                                            MemFun(this, &AsyncJob::deleteThis, aReason));
+                                            JobMemFun(self, &AsyncJob::deleteThis, aReason));
     inCall = fakeCall;
     callEnd();
 //    delete fakeCall;
@@ -164,60 +161,3 @@ const char *AsyncJob::status() const
 }
 
 
-/* JobDialer */
-
-JobDialer::JobDialer(AsyncJob *aJob): job(NULL), lock(NULL)
-{
-    if (aJob) {
-        lock = cbdataReference(aJob->toCbdata());
-        job = aJob;
-    }
-}
-
-JobDialer::JobDialer(const JobDialer &d): CallDialer(d),
-        job(NULL), lock(NULL)
-{
-    if (d.lock && cbdataReferenceValid(d.lock)) {
-        lock = cbdataReference(d.lock);
-        Must(d.job);
-        job = d.job;
-    }
-}
-
-JobDialer::~JobDialer()
-{
-    cbdataReferenceDone(lock); // lock may be NULL
-}
-
-
-bool
-JobDialer::canDial(AsyncCall &call)
-{
-    if (!lock)
-        return call.cancel("job was gone before the call");
-
-    if (!cbdataReferenceValid(lock))
-        return call.cancel("job gone after the call");
-
-    Must(job);
-    return job->canBeCalled(call);
-}
-
-void
-JobDialer::dial(AsyncCall &call)
-{
-    Must(lock && cbdataReferenceValid(lock)); // canDial() checks for this
-    Must(job);
-
-    job->callStart(call);
-
-    try {
-        doDial();
-    } catch (const std::exception &e) {
-        debugs(call.debugSection, 3,
-               HERE << call.name << " threw exception: " << e.what());
-        job->callException(e);
-    }
-
-    job->callEnd(); // may delete job
-}
index dd33044ca08bcc75f93c301235b35d3e03d95899..e6625aadedb0f8799bd415b59417c9a1089447bf 100644 (file)
@@ -8,6 +8,9 @@
 #include "base/AsyncCall.h"
 #include "TextException.h"
 
+template <class Cbc>
+class CbcPointer;
+
 /**
  \defgroup AsyncJobAPI Async-Jobs API
  \par
  */
 
 /// \ingroup AsyncJobAPI
+/// Base class for all asynchronous jobs
 class AsyncJob
 {
-
 public:
-    static AsyncJob *AsyncStart(AsyncJob *job); // use this to start jobs
+    typedef CbcPointer<AsyncJob> Pointer;
 
+public:
     AsyncJob(const char *aTypeName);
     virtual ~AsyncJob();
 
     virtual void *toCbdata() = 0;
-    void noteStart(); // calls virtual start
+
+    /// starts a freshly created job (i.e., makes the job asynchronous)
+    static Pointer Start(AsyncJob *job);
 
 protected:
     // XXX: temporary method to replace "delete this" in jobs-in-transition.
@@ -72,56 +78,4 @@ private:
     static unsigned int TheLastId;
 };
 
-
-/**
- \ingroup AsyncJobAPI
- * This is a base class for all job call dialers. It does all the job
- * dialing logic (debugging, handling exceptions, etc.) except for calling
- * the job method. The latter is not possible without templates and we
- * want to keep this class simple and template-free. Thus, we add a dial()
- * virtual method that the JobCallT template below will implement for us,
- * calling the job.
- */
-class JobDialer: public CallDialer
-{
-public:
-    JobDialer(AsyncJob *aJob);
-    JobDialer(const JobDialer &d);
-    virtual ~JobDialer();
-
-    virtual bool canDial(AsyncCall &call);
-    void dial(AsyncCall &call);
-
-    AsyncJob *job;
-    void *lock; // job's cbdata
-
-protected:
-    virtual void doDial() = 0; // actually calls the job method
-
-private:
-    // not implemented and should not be needed
-    JobDialer &operator =(const JobDialer &);
-};
-
-#include "base/AsyncJobCalls.h"
-
-template <class Dialer>
-bool
-CallJob(int debugSection, int debugLevel, const char *fileName, int fileLine,
-        const char *callName, const Dialer &dialer)
-{
-    AsyncCall::Pointer call = asyncCall(debugSection, debugLevel, callName, dialer);
-    return ScheduleCall(fileName, fileLine, call);
-}
-
-
-#define CallJobHere(debugSection, debugLevel, job, method) \
-    CallJob((debugSection), (debugLevel), __FILE__, __LINE__, #method, \
-        MemFun((job), &method))
-
-#define CallJobHere1(debugSection, debugLevel, job, method, arg1) \
-    CallJob((debugSection), (debugLevel), __FILE__, __LINE__, #method, \
-        MemFun((job), &method, (arg1)))
-
-
 #endif /* SQUID_ASYNC_JOB_H */
index 0657d3672015361f13cbc67e8a31a20635d41482..ef9a285f4ba5edc0a55a0e40a86e3e58ee2af6c5 100644 (file)
@@ -7,6 +7,66 @@
 #define SQUID_ASYNCJOBCALLS_H
 
 #include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
+
+/**
+ \ingroup AsyncJobAPI
+ * This is a base class for all job call dialers. It does all the job
+ * dialing logic (debugging, handling exceptions, etc.) except for calling
+ * the job method. The latter requires knowing the number and type of method
+ * parameters. Thus, we add a dial() virtual method that the MemFunT templates
+ * below implement for us, calling the job's method with the right params.
+ */
+template <class Job>
+class JobDialer: public CallDialer
+{
+public:
+    typedef Job DestClass;
+    typedef CbcPointer<Job> JobPointer;
+
+    JobDialer(const JobPointer &aJob);
+    JobDialer(const JobDialer &d);
+
+    virtual bool canDial(AsyncCall &call);
+    void dial(AsyncCall &call);
+
+    JobPointer job;
+
+protected:
+    virtual void doDial() = 0; // actually calls the job method
+
+private:
+    // not implemented and should not be needed
+    JobDialer &operator =(const JobDialer &);
+};
+
+/// schedule an async job call using a dialer; use CallJobHere macros instead
+template <class Dialer>
+bool
+CallJob(int debugSection, int debugLevel, const char *fileName, int fileLine,
+        const char *callName, const Dialer &dialer)
+{
+    AsyncCall::Pointer call = asyncCall(debugSection, debugLevel, callName, dialer);
+    return ScheduleCall(fileName, fileLine, call);
+}
+
+
+#define CallJobHere(debugSection, debugLevel, job, Class, method) \
+    CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \
+        (#Class "::" #method), \
+        JobMemFun<Class>((job), &Class::method))
+
+#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1) \
+    CallJob((debugSection), (debugLevel), __FILE__, __LINE__, \
+        (#Class "::" #method), \
+        JobMemFun<Class>((job), &Class::method, (arg1)))
+
+
+/// Convenience macro to create a Dialer-based job callback
+#define JobCallback(dbgSection, dbgLevel, Dialer, job, method) \
+    asyncCall((dbgSection), (dbgLevel), #method, \
+        Dialer(CbcPointer<Dialer::DestClass>(job), &method))
+
 
 /*
  * *MemFunT are member function (i.e., class method) wrappers. They store
 
 // Arity names are from http://en.wikipedia.org/wiki/Arity
 
-template <class C>
-class NullaryMemFunT: public JobDialer
+template <class Job>
+class NullaryMemFunT: public JobDialer<Job>
 {
 public:
-    typedef void (C::*Method)();
-    explicit NullaryMemFunT(C *anObject, Method aMethod):
-            JobDialer(anObject), object(anObject), method(aMethod) {}
+    typedef void (Job::*Method)();
+    explicit NullaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod):
+            JobDialer<Job>(aJob), method(aMethod) {}
 
     virtual void print(std::ostream &os) const {  os << "()"; }
 
 public:
-    C *object;
     Method method;
 
 protected:
-    virtual void doDial() { (object->*method)(); }
+    virtual void doDial() { ((&(*this->job))->*method)(); }
 };
 
-template <class C, class Argument1>
-class UnaryMemFunT: public JobDialer
+template <class Job, class Argument1>
+class UnaryMemFunT: public JobDialer<Job>
 {
 public:
-    typedef void (C::*Method)(Argument1);
-    explicit UnaryMemFunT(C *anObject, Method aMethod, const Argument1 &anArg1):
-            JobDialer(anObject),
-            object(anObject), method(aMethod), arg1(anArg1) {}
+    typedef void (Job::*Method)(Argument1);
+    explicit UnaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod,
+                          const Argument1 &anArg1): JobDialer<Job>(aJob),
+            method(aMethod), arg1(anArg1) {}
 
     virtual void print(std::ostream &os) const {  os << '(' << arg1 << ')'; }
 
 public:
-    C *object;
     Method method;
     Argument1 arg1;
 
 protected:
-    virtual void doDial() { (object->*method)(arg1); }
+    virtual void doDial() { ((&(*this->job))->*method)(arg1); }
 };
 
 // ... add more as needed
@@ -71,17 +129,57 @@ protected:
 
 template <class C>
 NullaryMemFunT<C>
-MemFun(C *object, typename NullaryMemFunT<C>::Method method)
+JobMemFun(const CbcPointer<C> &job, typename NullaryMemFunT<C>::Method method)
 {
-    return NullaryMemFunT<C>(object, method);
+    return NullaryMemFunT<C>(job, method);
 }
 
 template <class C, class Argument1>
 UnaryMemFunT<C, Argument1>
-MemFun(C *object, typename UnaryMemFunT<C, Argument1>::Method method,
-       Argument1 arg1)
+JobMemFun(const CbcPointer<C> &job, typename UnaryMemFunT<C, Argument1>::Method method,
+          Argument1 arg1)
+{
+    return UnaryMemFunT<C, Argument1>(job, method, arg1);
+}
+
+
+// inlined methods
+
+template<class Job>
+JobDialer<Job>::JobDialer(const JobPointer &aJob): job(aJob)
+{
+}
+
+template<class Job>
+JobDialer<Job>::JobDialer(const JobDialer<Job> &d): CallDialer(d), job(d.job)
 {
-    return UnaryMemFunT<C, Argument1>(object, method, arg1);
+}
+
+template<class Job>
+bool
+JobDialer<Job>::canDial(AsyncCall &call)
+{
+    if (!job)
+        return call.cancel("job gone");
+
+    return job->canBeCalled(call);
+}
+
+template<class Job>
+void
+JobDialer<Job>::dial(AsyncCall &call)
+{
+    job->callStart(call);
+
+    try {
+        doDial();
+    } catch (const std::exception &e) {
+        debugs(call.debugSection, 3,
+               HERE << call.name << " threw exception: " << e.what());
+        job->callException(e);
+    }
+
+    job->callEnd(); // may delete job
 }
 
 #endif /* SQUID_ASYNCJOBCALLS_H */
diff --git a/src/base/CbcPointer.h b/src/base/CbcPointer.h
new file mode 100644 (file)
index 0000000..97067f8
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_CBC_POINTER_H
+#define SQUID_CBC_POINTER_H
+
+#include "TextException.h"
+#include "cbdata.h"
+
+/**
+ \ingroup CBDATAAPI
+ *
+ * Safely points to a cbdata-protected class (cbc), such as an AsyncJob.
+ * When a cbc we communicate with disappears without
+ * notice or a notice has not reached us yet, this class prevents
+ * dereferencing the pointer to the gone cbc object.
+ */
+template<class Cbc>
+class CbcPointer
+{
+public:
+    CbcPointer(); // a nil pointer
+    CbcPointer(Cbc *aCbc);
+    CbcPointer(const CbcPointer &p);
+    ~CbcPointer();
+
+    Cbc *raw() const; ///< a temporary raw Cbc pointer; may be invalid
+    Cbc *get() const; ///< a temporary valid raw Cbc pointer or NULL
+    Cbc &operator *() const; ///< a valid Cbc reference or exception
+    Cbc *operator ->() const; ///< a valid Cbc pointer or exception
+
+    // no bool operator because set() != valid()
+    bool set() const { return cbc != NULL; } ///< was set but may be invalid
+    Cbc *valid() const { return get(); } ///< was set and is valid
+    bool operator !() const { return !valid(); } ///< invalid or was not set
+    bool operator ==(const CbcPointer<Cbc> &o) const { return lock == o.lock; }
+
+    CbcPointer &operator =(const CbcPointer &p);
+
+    /// support converting a child cbc pointer into a parent cbc pointer
+    template <typename Other>
+    CbcPointer(const CbcPointer<Other> &o): cbc(o.raw()), lock(NULL) {
+        if (o.valid())
+            lock = cbdataReference(o->toCbdata());
+    }
+
+    /// support assigning a child cbc pointer to a parent cbc pointer
+    template <typename Other>
+    CbcPointer &operator =(const CbcPointer<Other> &o) {
+        clear();
+        cbc = o.raw(); // so that set() is accurate
+        if (o.valid())
+            lock = cbdataReference(o->toCbdata());
+        return *this;
+    }
+
+    void clear(); ///< make pointer not set; does not invalidate cbdata
+
+    std::ostream &print(std::ostream &os) const;
+
+private:
+    Cbc *cbc; // a possibly invalid pointer to a cbdata class
+    void *lock; // a valid pointer to cbc's cbdata or nil
+};
+
+template <class Cbc>
+inline
+std::ostream &operator <<(std::ostream &os, const CbcPointer<Cbc> &p)
+{
+    return p.print(os);
+}
+
+// inlined methods
+
+template<class Cbc>
+CbcPointer<Cbc>::CbcPointer(): cbc(NULL), lock(NULL)
+{
+}
+
+template<class Cbc>
+CbcPointer<Cbc>::CbcPointer(Cbc *aCbc): cbc(aCbc), lock(NULL)
+{
+    if (cbc)
+        lock = cbdataReference(cbc->toCbdata());
+}
+
+template<class Cbc>
+CbcPointer<Cbc>::CbcPointer(const CbcPointer &d): cbc(d.cbc), lock(NULL)
+{
+    if (d.lock && cbdataReferenceValid(d.lock))
+        lock = cbdataReference(d.lock);
+}
+
+template<class Cbc>
+CbcPointer<Cbc>::~CbcPointer()
+{
+    clear();
+}
+
+template<class Cbc>
+CbcPointer<Cbc> &CbcPointer<Cbc>::operator =(const CbcPointer &d)
+{
+    clear();
+    cbc = d.cbc;
+    if (d.lock && cbdataReferenceValid(d.lock))
+        lock = cbdataReference(d.lock);
+    return *this;
+}
+
+template<class Cbc>
+void
+CbcPointer<Cbc>::clear()
+{
+    cbdataReferenceDone(lock); // lock may be nil before and will be nil after
+    cbc = NULL;
+}
+
+template<class Cbc>
+Cbc *
+CbcPointer<Cbc>::raw() const
+{
+    return cbc;
+}
+
+template<class Cbc>
+Cbc *
+CbcPointer<Cbc>::get() const
+{
+    return (lock && cbdataReferenceValid(lock)) ? cbc : NULL;
+}
+
+template<class Cbc>
+Cbc &
+CbcPointer<Cbc>::operator *() const
+{
+    Cbc *c = get();
+    Must(c);
+    return *c;
+}
+
+template<class Cbc>
+Cbc *
+CbcPointer<Cbc>::operator ->() const
+{
+    Cbc *c = get();
+    Must(c);
+    return c;
+}
+
+template <class Cbc>
+std::ostream &CbcPointer<Cbc>::print(std::ostream &os) const
+{
+    return os << cbc << '/' << lock;
+}
+
+
+#endif /* SQUID_CBC_POINTER_H */
index 0596e0168f813df601d0a328b32a8f13cad5162a..552de3c634c60ccccc3e92c7cc802582e8dcd6b4 100644 (file)
@@ -11,4 +11,5 @@ libbase_la_SOURCES = \
        AsyncJob.cc \
        AsyncJobCalls.h \
        AsyncCallQueue.cc \
-       AsyncCallQueue.h
+       AsyncCallQueue.h \
+       CbcPointer.h
index a25cbddf8884850b91100816e9380828abf340ed..18dd88fd86a9136cdb7394575943d57d185df39e 100644 (file)
@@ -210,8 +210,8 @@ ConnStateData::readSomeData()
     makeSpaceAvailable();
 
     typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
-    reader = asyncCall(33, 5, "ConnStateData::clientReadRequest",
-                       Dialer(this, &ConnStateData::clientReadRequest));
+    reader = JobCallback(33, 5,
+                         Dialer, this, ConnStateData::clientReadRequest);
     comm_read(fd, in.addressToReadInto(), getAvailableBufferLength(), reader);
 }
 
@@ -1358,8 +1358,8 @@ ConnStateData::readNextRequest()
      * Set the timeout BEFORE calling clientReadRequest().
      */
     typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(33, 5, "ConnStateData::requestTimeout",
-                                      TimeoutDialer(this, &ConnStateData::requestTimeout));
+    AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+                                     TimeoutDialer, this, ConnStateData::requestTimeout);
     commSetTimeout(fd, Config.Timeout.persistent_request, timeoutCall);
 
     readSomeData();
@@ -2928,8 +2928,8 @@ ConnStateData::requestTimeout(const CommTimeoutCbParams &io)
          * if we don't close() here, we still need a timeout handler!
          */
         typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
-        AsyncCall::Pointer timeoutCall =  asyncCall(33, 5, "ConnStateData::requestTimeout",
-                                          TimeoutDialer(this,&ConnStateData::requestTimeout));
+        AsyncCall::Pointer timeoutCall =  JobCallback(33, 5,
+                                          TimeoutDialer, this, ConnStateData::requestTimeout);
         commSetTimeout(io.fd, 30, timeoutCall);
 
         /*
@@ -3055,16 +3055,16 @@ httpAccept(int sock, int newfd, ConnectionDetail *details,
     connState = connStateCreate(&details->peer, &details->me, newfd, s);
 
     typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
-    AsyncCall::Pointer call = asyncCall(33, 5, "ConnStateData::connStateClosed",
-                                        Dialer(connState, &ConnStateData::connStateClosed));
+    AsyncCall::Pointer call = JobCallback(33, 5,
+                                          Dialer, connState, ConnStateData::connStateClosed);
     comm_add_close_handler(newfd, call);
 
     if (Config.onoff.log_fqdn)
         fqdncache_gethostbyaddr(details->peer, FQDN_LOOKUP_IF_MISS);
 
     typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(33, 5, "ConnStateData::requestTimeout",
-                                      TimeoutDialer(connState,&ConnStateData::requestTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(33, 5,
+                                      TimeoutDialer, connState, ConnStateData::requestTimeout);
     commSetTimeout(newfd, Config.Timeout.read, timeoutCall);
 
 #if USE_IDENT
@@ -3266,16 +3266,16 @@ httpsAccept(int sock, int newfd, ConnectionDetail *details,
     ConnStateData *connState = connStateCreate(details->peer, details->me,
                                newfd, &s->http);
     typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
-    AsyncCall::Pointer call = asyncCall(33, 5, "ConnStateData::connStateClosed",
-                                        Dialer(connState, &ConnStateData::connStateClosed));
+    AsyncCall::Pointer call = JobCallback(33, 5,
+                                          Dialer, connState, ConnStateData::connStateClosed);
     comm_add_close_handler(newfd, call);
 
     if (Config.onoff.log_fqdn)
         fqdncache_gethostbyaddr(details->peer, FQDN_LOOKUP_IF_MISS);
 
     typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(33, 5, "ConnStateData::requestTimeout",
-                                      TimeoutDialer(connState,&ConnStateData::requestTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(33, 5,
+                                      TimeoutDialer, connState, ConnStateData::requestTimeout);
     commSetTimeout(newfd, Config.Timeout.request, timeoutCall);
 
 #if USE_IDENT
@@ -3798,8 +3798,8 @@ void ConnStateData::pinConnection(int pinning_fd, HttpRequest *request, struct p
     fd_note(pinning_fd, desc);
 
     typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
-    pinning.closeHandler = asyncCall(33, 5, "ConnStateData::clientPinnedConnectionClosed",
-                                     Dialer(this, &ConnStateData::clientPinnedConnectionClosed));
+    pinning.closeHandler = JobCallback(33, 5,
+                                       Dialer, this, ConnStateData::clientPinnedConnectionClosed);
     comm_add_close_handler(pinning_fd, pinning.closeHandler);
 
 }
index b6ca7b7ce9dbe15dcd7198c7a8a92cc8857dfd23..bff82991ee98520da91a78e9679b8f558be8e82b 100644 (file)
@@ -1368,11 +1368,11 @@ ClientHttpRequest::startAdaptation(const Adaptation::ServiceGroupPointer &g)
     assert(!virginHeadSource);
     assert(!adaptedBodySource);
     virginHeadSource = initiateAdaptation(
-                           new Adaptation::Iterator(this, request, NULL, g));
+                           new Adaptation::Iterator(request, NULL, g));
 
     // we could try to guess whether we can bypass this adaptation
     // initiation failure, but it should not really happen
-    assert(virginHeadSource != NULL); // Must, really
+    Must(initiated(virginHeadSource));
 }
 
 void
index f30335d171311e7651f64257416651f31e322d6b..e4f710a470e68d13a8d454c3ab39e58188606958 100644 (file)
@@ -177,7 +177,7 @@ private:
     void endRequestSatisfaction();
 
 private:
-    Adaptation::Initiate *virginHeadSource;
+    CbcPointer<Adaptation::Initiate> virginHeadSource;
     BodyPipe::Pointer adaptedBodySource;
 
     bool request_satisfaction_mode;
index 5b72df2e9ab4565bcf50088c912b2b52a7f4dc90..60848b2c747d336f5334cc9f57d47c45023161d6 100644 (file)
@@ -461,8 +461,8 @@ FtpStateData::FtpStateData(FwdState *theFwdState) : AsyncJob("FtpStateData"), Se
     flags.rest_supported = 1;
 
     typedef CommCbMemFunT<FtpStateData, CommCloseCbParams> Dialer;
-    AsyncCall::Pointer closer = asyncCall(9, 5, "FtpStateData::ctrlClosed",
-                                          Dialer(this, &FtpStateData::ctrlClosed));
+    AsyncCall::Pointer closer = JobCallback(9, 5,
+                                            Dialer, this, FtpStateData::ctrlClosed);
     ctrl.opened(theFwdState->server_fd, closer);
 
     if (request->method == METHOD_PUT)
@@ -1311,16 +1311,15 @@ FtpStateData::maybeReadVirginBody()
     data.read_pending = true;
 
     typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                      TimeoutDialer(this,&FtpStateData::ftpTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(9, 5,
+                                      TimeoutDialer, this, FtpStateData::ftpTimeout);
     commSetTimeout(data.fd, Config.Timeout.read, timeoutCall);
 
     debugs(9,5,HERE << "queueing read on FD " << data.fd);
 
     typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
     entry->delayAwareRead(data.fd, data.readBuf->space(), read_sz,
-                          asyncCall(9, 5, "FtpStateData::dataRead",
-                                    Dialer(this, &FtpStateData::dataRead)));
+                          JobCallback(9, 5, Dialer, this, FtpStateData::dataRead));
 }
 
 void
@@ -1369,8 +1368,8 @@ FtpStateData::dataRead(const CommIoCbParams &io)
 
         if (ignoreErrno(io.xerrno)) {
             typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-            AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                              TimeoutDialer(this,&FtpStateData::ftpTimeout));
+            AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
+                                             TimeoutDialer, this, FtpStateData::ftpTimeout);
             commSetTimeout(io.fd, Config.Timeout.read, timeoutCall);
 
             maybeReadVirginBody();
@@ -1678,8 +1677,8 @@ FtpStateData::writeCommand(const char *buf)
     }
 
     typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
-    AsyncCall::Pointer call = asyncCall(9, 5, "FtpStateData::ftpWriteCommandCallback",
-                                        Dialer(this, &FtpStateData::ftpWriteCommandCallback));
+    AsyncCall::Pointer call = JobCallback(9, 5,
+                                          Dialer, this, FtpStateData::ftpWriteCommandCallback);
     comm_write(ctrl.fd,
                ctrl.last_command,
                strlen(ctrl.last_command),
@@ -1816,8 +1815,8 @@ FtpStateData::scheduleReadControlReply(int buffered_ok)
     } else {
         /* XXX What about Config.Timeout.read? */
         typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
-        AsyncCall::Pointer reader=asyncCall(9, 5, "FtpStateData::ftpReadControlReply",
-                                            Dialer(this, &FtpStateData::ftpReadControlReply));
+        AsyncCall::Pointer reader = JobCallback(9, 5,
+                                                Dialer, this, FtpStateData::ftpReadControlReply);
         comm_read(ctrl.fd, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
         /*
          * Cancel the timeout on the Data socket (if any) and
@@ -1830,8 +1829,8 @@ FtpStateData::scheduleReadControlReply(int buffered_ok)
         }
 
         typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-        AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                          TimeoutDialer(this,&FtpStateData::ftpTimeout));
+        AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
+                                         TimeoutDialer, this, FtpStateData::ftpTimeout);
 
         commSetTimeout(ctrl.fd, Config.Timeout.read, timeoutCall);
     }
@@ -2709,8 +2708,8 @@ ftpSendPassive(FtpStateData * ftpState)
      * dont acknowledge PASV commands.
      */
     typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                      TimeoutDialer(ftpState,&FtpStateData::ftpTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(9, 5,
+                                      TimeoutDialer, ftpState, FtpStateData::ftpTimeout);
 
     commSetTimeout(ftpState->data.fd, 15, timeoutCall);
 }
@@ -3085,8 +3084,8 @@ void FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
 
             comm_close(io.nfd);
             typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
-            AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
-                                            acceptDialer(this, &FtpStateData::ftpAcceptDataConnection));
+            AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+                                            acceptDialer, this, FtpStateData::ftpAcceptDataConnection);
             comm_accept(data.fd, acceptCall);
             return;
         }
@@ -3116,8 +3115,8 @@ void FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
     commSetTimeout(ctrl.fd, -1, nullCall);
 
     typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                      TimeoutDialer(this,&FtpStateData::ftpTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(9, 5,
+                                      TimeoutDialer, this, FtpStateData::ftpTimeout);
     commSetTimeout(data.fd, Config.Timeout.read, timeoutCall);
 
     /*\todo XXX We should have a flag to track connect state...
@@ -3209,8 +3208,8 @@ void FtpStateData::readStor()
         commSetTimeout(ctrl.fd, -1, nullCall);
 
         typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-        AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                          TimeoutDialer(this,&FtpStateData::ftpTimeout));
+        AsyncCall::Pointer timeoutCall =  JobCallback(9, 5,
+                                          TimeoutDialer, this, FtpStateData::ftpTimeout);
 
         commSetTimeout(data.fd, Config.Timeout.read, timeoutCall);
 
@@ -3221,8 +3220,8 @@ void FtpStateData::readStor()
          * When client code is 150 with a hostname, Accept data channel. */
         debugs(9, 3, "ftpReadStor: accepting data channel");
         typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
-        AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
-                                        acceptDialer(this, &FtpStateData::ftpAcceptDataConnection));
+        AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+                                        acceptDialer, this, FtpStateData::ftpAcceptDataConnection);
 
         comm_accept(data.fd, acceptCall);
     } else {
@@ -3357,8 +3356,8 @@ ftpReadList(FtpStateData * ftpState)
     } else if (code == 150) {
         /* Accept data channel */
         typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
-        AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
-                                        acceptDialer(ftpState, &FtpStateData::ftpAcceptDataConnection));
+        AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+                                        acceptDialer, ftpState, FtpStateData::ftpAcceptDataConnection);
 
         comm_accept(ftpState->data.fd, acceptCall);
         /*
@@ -3369,8 +3368,8 @@ ftpReadList(FtpStateData * ftpState)
         commSetTimeout(ftpState->ctrl.fd, -1, nullCall);
 
         typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-        AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                          TimeoutDialer(ftpState,&FtpStateData::ftpTimeout));
+        AsyncCall::Pointer timeoutCall =  JobCallback(9, 5,
+                                          TimeoutDialer, ftpState,FtpStateData::ftpTimeout);
         commSetTimeout(ftpState->data.fd, Config.Timeout.read, timeoutCall);
         return;
     } else if (!ftpState->flags.tried_nlst && code > 300) {
@@ -3419,8 +3418,8 @@ ftpReadRetr(FtpStateData * ftpState)
     } else if (code == 150) {
         /* Accept data channel */
         typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
-        AsyncCall::Pointer acceptCall = asyncCall(11, 5, "FtpStateData::ftpAcceptDataConnection",
-                                        acceptDialer(ftpState, &FtpStateData::ftpAcceptDataConnection));
+        AsyncCall::Pointer acceptCall = JobCallback(11, 5,
+                                        acceptDialer, ftpState, FtpStateData::ftpAcceptDataConnection);
         comm_accept(ftpState->data.fd, acceptCall);
         /*
          * Cancel the timeout on the Control socket and establish one
@@ -3430,8 +3429,8 @@ ftpReadRetr(FtpStateData * ftpState)
         commSetTimeout(ftpState->ctrl.fd, -1, nullCall);
 
         typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
-        AsyncCall::Pointer timeoutCall =  asyncCall(9, 5, "FtpStateData::ftpTimeout",
-                                          TimeoutDialer(ftpState,&FtpStateData::ftpTimeout));
+        AsyncCall::Pointer timeoutCall =  JobCallback(9, 5,
+                                          TimeoutDialer, ftpState,FtpStateData::ftpTimeout);
         commSetTimeout(ftpState->data.fd, Config.Timeout.read, timeoutCall);
     } else if (code >= 300) {
         if (!ftpState->flags.try_slash_hack) {
@@ -4041,8 +4040,7 @@ AsyncCall::Pointer
 FtpStateData::dataCloser()
 {
     typedef CommCbMemFunT<FtpStateData, CommCloseCbParams> Dialer;
-    return asyncCall(9, 5, "FtpStateData::dataClosed",
-                     Dialer(this, &FtpStateData::dataClosed));
+    return JobCallback(9, 5, Dialer, this, FtpStateData::dataClosed);
 }
 
 /// configures the channel with a descriptor and registers a close handler
index 3c93e53150ca0b7cc0bc83265aebfac296af82b4..f600c3312be35138bdcfab07e0ada248a37defc1 100644 (file)
@@ -139,8 +139,8 @@ HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"),
      * register the handler to free HTTP state data when the FD closes
      */
     typedef CommCbMemFunT<HttpStateData, CommCloseCbParams> Dialer;
-    closeHandler = asyncCall(9, 5, "httpStateData::httpStateConnClosed",
-                             Dialer(this,&HttpStateData::httpStateConnClosed));
+    closeHandler = JobCallback(9, 5,
+                               Dialer, this, HttpStateData::httpStateConnClosed);
     comm_add_close_handler(fd, closeHandler);
 }
 
@@ -1406,8 +1406,7 @@ HttpStateData::maybeReadVirginBody()
         flags.do_next_read = 0;
         typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
         entry->delayAwareRead(fd, readBuf->space(read_size), read_size,
-                              asyncCall(11, 5, "HttpStateData::readReply",
-                                        Dialer(this, &HttpStateData::readReply)));
+                              JobCallback(11, 5, Dialer, this,  HttpStateData::readReply));
     }
 }
 
@@ -1450,8 +1449,8 @@ HttpStateData::sendComplete(const CommIoCbParams &io)
      * request bodies.
      */
     typedef CommCbMemFunT<HttpStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(11, 5, "HttpStateData::httpTimeout",
-                                      TimeoutDialer(this,&HttpStateData::httpTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(11, 5,
+                                      TimeoutDialer, this, HttpStateData::httpTimeout);
 
     commSetTimeout(fd, Config.Timeout.read, timeoutCall);
 
@@ -1976,8 +1975,8 @@ HttpStateData::sendRequest()
     }
 
     typedef CommCbMemFunT<HttpStateData, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(11, 5, "HttpStateData::httpTimeout",
-                                      TimeoutDialer(this,&HttpStateData::httpTimeout));
+    AsyncCall::Pointer timeoutCall =  JobCallback(11, 5,
+                                      TimeoutDialer, this, HttpStateData::httpTimeout);
     commSetTimeout(fd, Config.Timeout.lifetime, timeoutCall);
     flags.do_next_read = 1;
     maybeReadVirginBody();
@@ -1986,13 +1985,13 @@ HttpStateData::sendRequest()
         if (!startRequestBodyFlow()) // register to receive body data
             return false;
         typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
-        Dialer dialer(this, &HttpStateData::sentRequestBody);
-        requestSender = asyncCall(11,5, "HttpStateData::sentRequestBody", dialer);
+        requestSender = JobCallback(11,5,
+                                    Dialer, this, HttpStateData::sentRequestBody);
     } else {
         assert(!requestBodySource);
         typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
-        Dialer dialer(this, &HttpStateData::sendComplete);
-        requestSender = asyncCall(11,5, "HttpStateData::SendComplete", dialer);
+        requestSender = JobCallback(11,5,
+                                    Dialer, this,  HttpStateData::sendComplete);
     }
 
     if (_peer != NULL) {
@@ -2085,8 +2084,8 @@ HttpStateData::doneSendingRequestBody()
             }
 
             typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
-            Dialer dialer(this, &HttpStateData::sendComplete);
-            AsyncCall::Pointer call= asyncCall(11,5, "HttpStateData::SendComplete", dialer);
+            AsyncCall::Pointer call = JobCallback(11,5,
+                                                  Dialer, this, HttpStateData::sendComplete);
             comm_write(fd, "\r\n", 2, call);
         }
         return;