--------------------- PatchSet 6067 Date: 2007/11/01 19:06:21 Author: chtsanti Branch: async-calls Tag: (none) Log: Author: Alex Rousskov The first sketch of the AsyncCall wrappers design. A number of new classes and templates introduced. - *MemFunT template classes are a member function wrappers. It is a way to convert method calls from obj->func() or obj->func(arg) to simpler calls like objfunc(). Currently only methods with one or no arguments supported. If we want to support methods with 2 or 3 arguments the BinaryMemFunT and TernaryMemFunT must implemented. - AsynCallBase and child classes used to encapsulate the details of an async job to an object. Members: src/AsyncCall.cc:1.3->1.3.22.1 src/AsyncCall.h:1.3->1.3.22.1 Index: squid3/src/AsyncCall.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/AsyncCall.cc,v retrieving revision 1.3 retrieving revision 1.3.22.1 diff -u -r1.3 -r1.3.22.1 --- squid3/src/AsyncCall.cc 8 May 2007 16:51:26 -0000 1.3 +++ squid3/src/AsyncCall.cc 1 Nov 2007 19:06:21 -0000 1.3.22.1 @@ -1,5 +1,6 @@ #include "squid.h" #include "AsyncCall.h" +#include "cbdata.h" void scheduleAsyncCall(int debugSection, int debugLevel, const char *fileName, int fileLine, void *objectPtr, const char *callName, @@ -27,6 +28,9 @@ } + + + #if USAGE_SKETCH class TestClass { @@ -44,4 +48,59 @@ AsyncCall(0,0, &c, TestClass::testMethod); // make an async call to c } +// This is a class that mimics some job class. +// Note that it is not inherited from AsyncJob yet. It will be once JobCall +// methods are implemented and start casting AsyncCallBase::theObject +// to AsyncJob to call well-known job API methods such as swanSong. +struct Tester { + virtual ~Tester() {} + + virtual void method0() { debugs(0,0, HERE << "METHOD0()"); } + virtual void method1(int arg1) { debugs(0,0, HERE << "METHOD1(" << arg1 << ")"); } +}; + +// Set to false to test immediate call firing from test cases. No calls +// will be fired without submitting an asynchronous event in real code. +extern const bool scheduleAsyncCalls; +const bool scheduleAsyncCalls = true; + +// test a created call (sychronously or asynchronously) +void do_test_call(AsyncCallBase *call) +{ + if (!scheduleAsyncCalls) { + call->fire(); + debugs(0,0, HERE << "sync-fired"); + delete call; + } else { + ScheduleAsyncCall(0, 0, call, AsyncCallBase::fire); // TODO:be more specific + debugs(0,0, HERE << "scheduled"); + } +} + +// do one test with a argument-less member function. +void do_test_arg0() +{ + Tester *tester = new Tester; // leaking + debugs(0,0, HERE << "creating call for " << tester); + AsyncCallBase *call = jobCall(MemFun(tester, &Tester::method0)); + debugs(0,0, HERE << "created"); + do_test_call(call); +} + +// do one test with a member function having one int argument. +void do_test_arg1() +{ + Tester *tester = new Tester; // leaking + debugs(0,0, HERE << "creating call for " << tester); + AsyncCallBase *call = jobCall(MemFun(tester, &Tester::method1, 5)); + debugs(0,0, HERE << "created"); + do_test_call(call); +} + +void do_testAsyncCalls() +{ + do_test_arg0(); + do_test_arg1(); +} + #endif Index: squid3/src/AsyncCall.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/AsyncCall.h,v retrieving revision 1.3 retrieving revision 1.3.22.1 diff -u -r1.3 -r1.3.22.1 --- squid3/src/AsyncCall.h 8 May 2007 16:51:26 -0000 1.3 +++ squid3/src/AsyncCall.h 1 Nov 2007 19:06:21 -0000 1.3.22.1 @@ -1,6 +1,6 @@ /* - * $Id: AsyncCall.h,v 1.3 2007/05/08 16:51:26 squidadm Exp $ + * $Id: AsyncCall.h,v 1.3.22.1 2007/11/01 19:06:21 chtsanti Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -89,4 +89,144 @@ void *objectPtr, const char *className, const char *methodName); +// Our goal here is to encapsulate details of the call in an object. +// Details may include the object pointer, the handler method pointer, and +// parameters. To simplify, we require all handlers to return void and not +// be constant. + +// *MemFunT is a member function wrapper. We need one for every supported +// member function arity (i.e., number of handler arguments). The first +// template parameter is the class type of the handler. + +// Arity names are from http://en.wikipedia.org/wiki/Arity + +template +class NullaryMemFunT { +public: + typedef void (C::*MemFunPtr)(); + explicit NullaryMemFunT(C *anObject, MemFunPtr aP): + theObject(anObject), theP(aP) {} + + void operator ()() { (theObject->*theP)(); } + +private: + C *theObject; + MemFunPtr theP; +}; + +template +class UnaryMemFunT { +public: + typedef void (C::*MemFunPtr)(Argument1); + explicit UnaryMemFunT(C *anObject, MemFunPtr aP, const Argument1 &anArg1): + theObject(anObject), theP(aP), theArg1(anArg1) {} + + void operator ()() { (theObject->*theP)(theArg1); } + +private: + C *theObject; + MemFunPtr theP; + Argument1 theArg1; +}; + +// 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. +// We need one function for each *MemFunT template. + +template +NullaryMemFunT MemFun(C *object, + typename NullaryMemFunT::MemFunPtr p) +{ + return NullaryMemFunT(object, p); +} + +template +UnaryMemFunT MemFun(C *object, + typename UnaryMemFunT::MemFunPtr p, Argument1 arg1) +{ + return UnaryMemFunT(object, p, arg1); +} + +// TODO: rename to AsyncCall once the AsyncCall() macro is gone +class AsyncCallBase +{ +public: + AsyncCallWrapper(0, 0, AsyncCallBase, fire); // nedded for AsyncCall macro + + static void fireWrapper2(void *data) { + debugs(0,0, HERE << "data=" << data); + AsyncCallBase *call = static_cast(data); + if (enterAsyncCallWrapper(0, 0, data, "AsyncCallBase", "fire")) { + debugs(0,0, HERE << "call=" << call); + call->fire(); + exitAsyncCallWrapper(0, 0, data, "AsyncCallBase", "fire"); + } + } + + + virtual ~AsyncCallBase() {} + + virtual bool fire() = 0; + virtual void handleException() = 0; + virtual void end() = 0; +}; + +// Same as AsyncCall, but does not assume the object is cbdata-protected. +// Note that the object here is the call object, not the handler object. +// Calls to handlers are done by AsyncCallBase::fire and do not use the +// old scheduleAsyncCall(). Once the main loop knows about async calls, +// we will not wrap call scheduling in events. +#define ScheduleAsyncCall(debugSection, debugLevel, objectPtr, callName) \ +{ \ + debugs(0,0, HERE << "objectPtr=" << (objectPtr)); \ + scheduleAsyncCall((debugSection), (debugLevel), __FILE__, __LINE__, \ + (objectPtr), #callName, \ + &(callName ## Wrapper), false); \ +} + +// This is a base class for all job calls. It does (well, will do) +// all the job calling logic (debugging, handling exceptions, etc.) except +// for calling the job itself. The latter is not possible without templates +// and we want to keep this class simple and template-free. Thus, we +// add a callJob() virtual method that the JobCallT template below will +// implement for us, calling the job. + +class JobCall: public AsyncCallBase +{ +public: + virtual bool fire() { debugs(0,0, HERE << "job call fire " << this); callJob(); debugs(0,0, HERE << "fired"); return true; } + virtual void handleException() { debugs(0,0, HERE << "job call exception"); } + virtual void end() { debugs(0,0, HERE << "job call end"); } + +protected: + virtual void callJob() = 0; +}; + +// This template combines member function pointer calling ability of MemFunT +// templates above with the job handling abilities of JobCall. + +template +class JobCallT: public JobCall +{ +public: + JobCallT(const Dialer &aDialer): theDialer(aDialer) { debugs(0,0, HERE << "job call created " << this); } + +protected: + virtual void callJob() { debugs(0,0, HERE << "dialing"); theDialer(); } + +private: + Dialer theDialer; +}; + +// Add a global templated function that create a job call using the +// template above. This is for convenience: it is often easier to call +// a templated function than to create a templated object. +// We need one function for each *MemFunT template. +template +JobCall *jobCall(const Dialer &dialer) +{ + return new JobCallT(dialer); +} + #endif /* SQUID_ASYNCCALL_H */