// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_TASK_H__ #define BASE_TASK_H__ #include #include "base/basictypes.h" #include "base/logging.h" #include "base/non_thread_safe.h" #include "base/revocable_store.h" #include "base/time.h" #include "base/tracked.h" #include "base/tuple.h" // Task ------------------------------------------------------------------------ // // A task is a generic runnable thingy, usually used for running code on a // different thread or for scheduling future tasks off of the message loop. class Task : public tracked_objects::Tracked { public: Task() {} virtual ~Task() {} // Tasks are automatically deleted after Run is called. virtual void Run() = 0; }; class CancelableTask : public Task { public: // Not all tasks support cancellation. virtual void Cancel() = 0; }; // Scoped Factories ------------------------------------------------------------ // // These scoped factory objects can be used by non-refcounted objects to safely // place tasks in a message loop. Each factory guarantees that the tasks it // produces will not run after the factory is destroyed. Commonly, factories // are declared as class members, so the class' tasks will automatically cancel // when the class instance is destroyed. // // Exampe Usage: // // class MyClass { // private: // // This factory will be used to schedule invocations of SomeMethod. // ScopedRunnableMethodFactory some_method_factory_; // // public: // // It is safe to suppress warning 4355 here. // MyClass() : some_method_factory_(this) { } // // void SomeMethod() { // // If this function might be called directly, you might want to revoke // // any outstanding runnable methods scheduled to call it. If it's not // // referenced other than by the factory, this is unnecessary. // some_method_factory_.RevokeAll(); // ... // } // // void ScheduleSomeMethod() { // // If you'd like to only only have one pending task at a time, test for // // |empty| before manufacturing another task. // if (!some_method_factory_.empty()) // return; // // // The factories are not thread safe, so always invoke on // // |MessageLoop::current()|. // MessageLoop::current()->PostTask(FROM_HERE, // some_method_factory_.NewRunnableMethod(&MyClass::SomeMethod), // kSomeMethodDelayMS); // } // }; // A ScopedTaskFactory produces tasks of type |TaskType| and prevents them from // running after it is destroyed. template class ScopedTaskFactory : public RevocableStore { public: ScopedTaskFactory() { } // Create a new task. inline TaskType* NewTask() { return new TaskWrapper(this); } class TaskWrapper : public TaskType, public NonThreadSafe { public: explicit TaskWrapper(RevocableStore* store) : revocable_(store) { } virtual void Run() { if (!revocable_.revoked()) TaskType::Run(); } private: Revocable revocable_; DISALLOW_EVIL_CONSTRUCTORS(TaskWrapper); }; private: DISALLOW_EVIL_CONSTRUCTORS(ScopedTaskFactory); }; // A ScopedRunnableMethodFactory creates runnable methods for a specified // object. This is particularly useful for generating callbacks for // non-reference counted objects when the factory is a member of the object. template class ScopedRunnableMethodFactory : public RevocableStore { public: explicit ScopedRunnableMethodFactory(T* object) : object_(object) { } template inline Task* NewRunnableMethod(Method method) { typedef typename ScopedTaskFactory >::TaskWrapper TaskWrapper; TaskWrapper* task = new TaskWrapper(this); task->Init(object_, method, MakeTuple()); return task; } template inline Task* NewRunnableMethod(Method method, const A& a) { typedef typename ScopedTaskFactory > >::TaskWrapper TaskWrapper; TaskWrapper* task = new TaskWrapper(this); task->Init(object_, method, MakeTuple(a)); return task; } template inline Task* NewRunnableMethod(Method method, const A& a, const B& b) { typedef typename ScopedTaskFactory > >::TaskWrapper TaskWrapper; TaskWrapper* task = new TaskWrapper(this); task->Init(object_, method, MakeTuple(a, b)); return task; } template inline Task* NewRunnableMethod(Method method, const A& a, const B& b, const C& c) { typedef typename ScopedTaskFactory > >::TaskWrapper TaskWrapper; TaskWrapper* task = new TaskWrapper(this); task->Init(object_, method, MakeTuple(a, b, c)); return task; } template inline Task* NewRunnableMethod(Method method, const A& a, const B& b, const C& c, const D& d) { typedef typename ScopedTaskFactory > >::TaskWrapper TaskWrapper; TaskWrapper* task = new TaskWrapper(this); task->Init(object_, method, MakeTuple(a, b, c, d)); return task; } template inline Task* NewRunnableMethod(Method method, const A& a, const B& b, const C& c, const D& d, const E& e) { typedef typename ScopedTaskFactory > >::TaskWrapper TaskWrapper; TaskWrapper* task = new TaskWrapper(this); task->Init(object_, method, MakeTuple(a, b, c, d, e)); return task; } protected: template class RunnableMethod : public Task { public: RunnableMethod() { } void Init(T* obj, Method meth, const Params& params) { obj_ = obj; meth_ = meth; params_ = params; } virtual void Run() { DispatchToMethod(obj_, meth_, params_); } private: T* obj_; Method meth_; Params params_; DISALLOW_EVIL_CONSTRUCTORS(RunnableMethod); }; private: T* object_; DISALLOW_EVIL_CONSTRUCTORS(ScopedRunnableMethodFactory); }; // General task implementations ------------------------------------------------ // Task to delete an object template class DeleteTask : public CancelableTask { public: explicit DeleteTask(T* obj) : obj_(obj) { } virtual void Run() { delete obj_; } virtual void Cancel() { obj_ = NULL; } private: T* obj_; }; // Task to Release() an object template class ReleaseTask : public CancelableTask { public: explicit ReleaseTask(T* obj) : obj_(obj) { } virtual void Run() { if (obj_) obj_->Release(); } virtual void Cancel() { obj_ = NULL; } private: T* obj_; }; // RunnableMethodTraits -------------------------------------------------------- // // This traits-class is used by RunnableMethod to manage the lifetime of the // callee object. By default, it is assumed that the callee supports AddRef // and Release methods. A particular class can specialize this template to // define other lifetime management. For example, if the callee is known to // live longer than the RunnableMethod object, then a RunnableMethodTraits // struct could be defined with empty RetainCallee and ReleaseCallee methods. template struct RunnableMethodTraits { static void RetainCallee(T* obj) { obj->AddRef(); } static void ReleaseCallee(T* obj) { obj->Release(); } }; // RunnableMethod and RunnableFunction ----------------------------------------- // // Runnable methods are a type of task that call a function on an object when // they are run. We implement both an object and a set of NewRunnableMethod and // NewRunnableFunction functions for convenience. These functions are // overloaded and will infer the template types, simplifying calling code. // // The template definitions all use the following names: // T - the class type of the object you're supplying // this is not needed for the Static version of the call // Method/Function - the signature of a pointer to the method or function you // want to call // Param - the parameter(s) to the method, possibly packed as a Tuple // A - the first parameter (if any) to the method // B - the second parameter (if any) to the mathod // // Put these all together and you get an object that can call a method whose // signature is: // R T::MyFunction([A[, B]]) // // Usage: // PostTask(FROM_HERE, NewRunnableMethod(object, &Object::method[, a[, b]]) // PostTask(FROM_HERE, NewRunnableFunction(&function[, a[, b]]) // RunnableMethod and NewRunnableMethod implementation ------------------------- template class RunnableMethod : public CancelableTask, public RunnableMethodTraits { public: RunnableMethod(T* obj, Method meth, const Params& params) : obj_(obj), meth_(meth), params_(params) { RetainCallee(obj_); } ~RunnableMethod() { ReleaseCallee(); } virtual void Run() { if (obj_) DispatchToMethod(obj_, meth_, params_); } virtual void Cancel() { ReleaseCallee(); } private: void ReleaseCallee() { if (obj_) { RunnableMethodTraits::ReleaseCallee(obj_); obj_ = NULL; } } T* obj_; Method meth_; Params params_; }; template inline CancelableTask* NewRunnableMethod(T* object, Method method) { return new RunnableMethod(object, method, MakeTuple()); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a) { return new RunnableMethod >(object, method, MakeTuple(a)); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a, const B& b) { return new RunnableMethod >(object, method, MakeTuple(a, b)); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a, const B& b, const C& c) { return new RunnableMethod >(object, method, MakeTuple(a, b, c)); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a, const B& b, const C& c, const D& d) { return new RunnableMethod >(object, method, MakeTuple(a, b, c, d)); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a, const B& b, const C& c, const D& d, const E& e) { return new RunnableMethod >(object, method, MakeTuple(a, b, c, d, e)); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a, const B& b, const C& c, const D& d, const E& e, const F& f) { return new RunnableMethod >(object, method, MakeTuple(a, b, c, d, e, f)); } template inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a, const B& b, const C& c, const D& d, const E& e, const F& f, const G& g) { return new RunnableMethod >(object, method, MakeTuple(a, b, c, d, e, f, g)); } // RunnableFunction and NewRunnableFunction implementation --------------------- template class RunnableFunction : public CancelableTask { public: RunnableFunction(Function function, const Params& params) : function_(function), params_(params) { } ~RunnableFunction() { } virtual void Run() { if (function_) DispatchToFunction(function_, params_); } virtual void Cancel() { } private: Function function_; Params params_; }; template inline CancelableTask* NewRunnableFunction(Function function) { return new RunnableFunction(function, MakeTuple()); } template inline CancelableTask* NewRunnableFunction(Function function, const A& a) { return new RunnableFunction >(function, MakeTuple(a)); } template inline CancelableTask* NewRunnableFunction(Function function, const A& a, const B& b) { return new RunnableFunction >(function, MakeTuple(a, b)); } template inline CancelableTask* NewRunnableFunction(Function function, const A& a, const B& b, const C& c) { return new RunnableFunction >(function, MakeTuple(a, b, c)); } template inline CancelableTask* NewRunnableFunction(Function function, const A& a, const B& b, const C& c, const D& d) { return new RunnableFunction >(function, MakeTuple(a, b, c, d)); } template inline CancelableTask* NewRunnableFunction(Function function, const A& a, const B& b, const C& c, const D& d, const E& e) { return new RunnableFunction >(function, MakeTuple(a, b, c, d, e)); } // Callback -------------------------------------------------------------------- // // A Callback is like a Task but with unbound parameters. It is basically an // object-oriented function pointer. // // Callbacks are designed to work with Tuples. A set of helper functions and // classes is provided to hide the Tuple details from the consumer. Client // code will generally work with the CallbackRunner base class, which merely // provides a Run method and is returned by the New* functions. This allows // users to not care which type of class implements the callback, only that it // has a certain number and type of arguments. // // The implementation of this is done by CallbackImpl, which inherits // CallbackStorage to store the data. This allows the storage of the data // (requiring the class type T) to be hidden from users, who will want to call // this regardless of the implementor's type T. // // Note that callbacks currently have no facility for cancelling or abandoning // them. We currently handle this at a higher level for cases where this is // necessary. The pointer in a callback must remain valid until the callback // is made. // // Like Task, the callback executor is responsible for deleting the callback // pointer once the callback has executed. // // Example client usage: // void Object::DoStuff(int, string); // Callback2::Type* callback = // NewCallback(obj, &Object::DoStuff); // callback->Run(5, string("hello")); // delete callback; // or, equivalently, using tuples directly: // CallbackRunner >* callback = // NewCallback(obj, &Object::DoStuff); // callback->RunWithParams(MakeTuple(5, string("hello"))); // Base for all Callbacks that handles storage of the pointers. template class CallbackStorage { public: CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) { } protected: T* obj_; Method meth_; }; // Interface that is exposed to the consumer, that does the actual calling // of the method. template class CallbackRunner { public: typedef Params TupleType; virtual ~CallbackRunner() {} virtual void RunWithParams(const Params& params) = 0; // Convenience functions so callers don't have to deal with Tuples. inline void Run() { RunWithParams(Tuple0()); } template inline void Run(const Arg1& a) { RunWithParams(Params(a)); } template inline void Run(const Arg1& a, const Arg2& b) { RunWithParams(Params(a, b)); } template inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) { RunWithParams(Params(a, b, c)); } template inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) { RunWithParams(Params(a, b, c, d)); } template inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d, const Arg5& e) { RunWithParams(Params(a, b, c, d, e)); } }; template class CallbackImpl : public CallbackStorage, public CallbackRunner { public: CallbackImpl(T* obj, Method meth) : CallbackStorage(obj, meth) { } virtual void RunWithParams(const Params& params) { // use "this->" to force C++ to look inside our templatized base class; see // Effective C++, 3rd Ed, item 43, p210 for details. DispatchToMethod(this->obj_, this->meth_, params); } }; // 0-arg implementation struct Callback0 { typedef CallbackRunner Type; }; template typename Callback0::Type* NewCallback(T* object, void (T::*method)()) { return new CallbackImpl(object, method); } // 1-arg implementation template struct Callback1 { typedef CallbackRunner > Type; }; template typename Callback1::Type* NewCallback(T* object, void (T::*method)(Arg1)) { return new CallbackImpl >(object, method); } // 2-arg implementation template struct Callback2 { typedef CallbackRunner > Type; }; template typename Callback2::Type* NewCallback( T* object, void (T::*method)(Arg1, Arg2)) { return new CallbackImpl >(object, method); } // 3-arg implementation template struct Callback3 { typedef CallbackRunner > Type; }; template typename Callback3::Type* NewCallback( T* object, void (T::*method)(Arg1, Arg2, Arg3)) { return new CallbackImpl >(object, method); } // 4-arg implementation template struct Callback4 { typedef CallbackRunner > Type; }; template typename Callback4::Type* NewCallback( T* object, void (T::*method)(Arg1, Arg2, Arg3, Arg4)) { return new CallbackImpl >(object, method); } // 5-arg implementation template struct Callback5 { typedef CallbackRunner > Type; }; template typename Callback5::Type* NewCallback( T* object, void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) { return new CallbackImpl >(object, method); } // An UnboundMethod is a wrapper for a method where the actual object is // provided at Run dispatch time. template class UnboundMethod { public: UnboundMethod(Method m, Params p) : m_(m), p_(p) {} void Run(T* obj) const { DispatchToMethod(obj, m_, p_); } private: Method m_; Params p_; }; #endif // BASE_TASK_H__