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