-
/*
- * $Id$
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
#ifndef SQUID_ASYNCJOBCALLS_H
#define SQUID_ASYNCJOBCALLS_H
#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
+#include "Debug.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((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 Data, class Argument1 = Data>
+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 Data &anArg1): JobDialer<Job>(aJob),
+ method(aMethod), arg1(anArg1) {}
virtual void print(std::ostream &os) const { os << '(' << arg1 << ')'; }
public:
- C *object;
Method method;
- Argument1 arg1;
+ Data arg1;
protected:
- virtual void doDial() { (object->*method)(arg1); }
+ virtual void doDial() { ((&(*this->job))->*method)(arg1); }
};
// ... add more as needed
-
// Now we add global templated functions that create the member function
// wrappers above. These are for convenience: it is often easier to
// call a templated function than to create a templated object.
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)
+{
+}
+
+template<class Job>
+bool
+JobDialer<Job>::canDial(AsyncCall &call)
{
- return UnaryMemFunT<C, Argument1>(object, method, arg1);
+ 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 */
+