diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 21:49:38 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 21:49:38 +0000 |
commit | d7cae12696b96500c05dd2d430f6238922c20c96 (patch) | |
tree | ecff27b367735535b2a66477f8cd89d3c462a6c0 /base/task.h | |
parent | ee2815e28d408216cf94e874825b6bcf76c69083 (diff) | |
download | chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.zip chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.gz chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.bz2 |
Add base to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/task.h')
-rw-r--r-- | base/task.h | 725 |
1 files changed, 725 insertions, 0 deletions
diff --git a/base/task.h b/base/task.h new file mode 100644 index 0000000..a964a17 --- /dev/null +++ b/base/task.h @@ -0,0 +1,725 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef BASE_TASK_H__ +#define BASE_TASK_H__ + +#include <set> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/non_thread_safe.h" +#include "base/revocable_store.h" +#include "base/tracked.h" +#include "base/tuple.h" + +//------------------------------------------------------------------------------ +// Base class of Task, where we store info to help MessageLoop handle PostTask() +// elements of Task processing. + +class Task; + +class MessageLoopOwnable : public tracked_objects::Tracked { + public: + MessageLoopOwnable() { Reset(); } + virtual ~MessageLoopOwnable() {} + + // Use this method to adjust the priority given to a task by MessageLoop. + void set_priority(int priority) { priority_ = priority; } + int priority() const { return priority_; } + + // Change whether this task will run in nested message loops. + void set_nestable(bool nestable) { nestable_ = nestable; } + bool nestable() { return nestable_; } + + + protected: + // If a derived class wishes to re-use this instance, then it should override + // this method. This method is called by MessageLoop after processing a task + // that was submitted to PostTask() or PostDelayedTask(). As seen, by default + // it deletes the task, but the derived class can change this behaviour and + // recycle (re-use) it. Be sure to call Reset() if you recycle it! + virtual void RecycleOrDelete() { delete this; } + + // Call this method if you are trying to recycle a Task. Note that only + // derived classes should attempt this feat, as a replacement for creating a + // new instance. + void Reset() { + posted_task_delay_ = -1; + priority_ = 0; + next_task_ = NULL; + nestable_ = true; + } + + private: + friend class TimerManager; // To check is_owned_by_message_loop(). + friend class MessageLoop; // To maintain posted_task_delay(). + friend class WorkerPool; // To release the task. + + // Access methods used ONLY by friends in MessageLoop and TimerManager + int posted_task_delay() const { return posted_task_delay_; } + bool is_owned_by_message_loop() const { return 0 <= posted_task_delay_; } + void set_posted_task_delay(int delay) { posted_task_delay_ = delay; } + + Task* next_task() const { return next_task_; } + void set_next_task(Task* next) { next_task_ = next; } + + // Priority for execution by MessageLoop. 0 is default. Higher means run + // sooner, and lower (including negative) means run less soon. + int priority_; + + // Slot to hold delay if the task was passed to PostTask(). If it was not + // passed to PostTask, then the delay is negative (the default). + int posted_task_delay_; + + // When tasks are collected into a queue by MessageLoop, this member is used + // to form a null terminated list. + Task* next_task_; + + // A nestable task will run in nested message loops, otherwise it will run + // only in the top level message loop. + bool nestable_; + + DISALLOW_EVIL_CONSTRUCTORS(MessageLoopOwnable); +}; + + +// 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 MessageLoopOwnable { + 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<MyClass> 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 TaskType> +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 T> +class ScopedRunnableMethodFactory : public RevocableStore { + public: + explicit ScopedRunnableMethodFactory(T* object) : object_(object) { } + + template <class Method> + inline Task* NewRunnableMethod(Method method) { + typedef typename ScopedTaskFactory<RunnableMethod< + Method, Tuple0> >::TaskWrapper TaskWrapper; + + TaskWrapper* task = new TaskWrapper(this); + task->Init(object_, method, MakeTuple()); + return task; + } + + template <class Method, class A> + inline Task* NewRunnableMethod(Method method, const A& a) { + typedef typename ScopedTaskFactory<RunnableMethod< + Method, Tuple1<A> > >::TaskWrapper TaskWrapper; + + TaskWrapper* task = new TaskWrapper(this); + task->Init(object_, method, MakeTuple(a)); + return task; + } + + template <class Method, class A, class B> + inline Task* NewRunnableMethod(Method method, const A& a, const B& b) { + typedef typename ScopedTaskFactory<RunnableMethod< + Method, Tuple2<A, B> > >::TaskWrapper TaskWrapper; + + TaskWrapper* task = new TaskWrapper(this); + task->Init(object_, method, MakeTuple(a, b)); + return task; + } + + template <class Method, class A, class B, class C> + inline Task* NewRunnableMethod(Method method, + const A& a, + const B& b, + const C& c) { + typedef typename ScopedTaskFactory<RunnableMethod< + Method, Tuple3<A, B, C> > >::TaskWrapper TaskWrapper; + + TaskWrapper* task = new TaskWrapper(this); + task->Init(object_, method, MakeTuple(a, b, c)); + return task; + } + + template <class Method, class A, class B, class C, class D> + inline Task* NewRunnableMethod(Method method, + const A& a, + const B& b, + const C& c, + const D& d) { + typedef typename ScopedTaskFactory<RunnableMethod< + Method, Tuple4<A, B, C, D> > >::TaskWrapper TaskWrapper; + + TaskWrapper* task = new TaskWrapper(this); + task->Init(object_, method, MakeTuple(a, b, c, d)); + return task; + } + + template <class Method, class A, class B, class C, class D, class E> + inline Task* NewRunnableMethod(Method method, + const A& a, + const B& b, + const C& c, + const D& d, + const E& e) { + typedef typename ScopedTaskFactory<RunnableMethod< + Method, Tuple5<A, B, C, D, E> > >::TaskWrapper TaskWrapper; + + TaskWrapper* task = new TaskWrapper(this); + task->Init(object_, method, MakeTuple(a, b, c, d, e)); + return task; + } + + protected: + template <class Method, class Params> + 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 T> +class DeleteTask : public CancelableTask { + public: + explicit DeleteTask(T* obj) : obj_(obj) { + set_nestable(false); + } + virtual void Run() { + delete obj_; + } + virtual void Cancel() { + obj_ = NULL; + } + private: + T* obj_; +}; + +// Task to Release() an object +template<class T> +class ReleaseTask : public CancelableTask { + public: + explicit ReleaseTask(T* obj) : obj_(obj) { + set_nestable(false); + } + 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 <class T> +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 T, class Method, class Params> +class RunnableMethod : public CancelableTask, + public RunnableMethodTraits<T> { + 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<T>::ReleaseCallee(obj_); + obj_ = NULL; + } + } + + T* obj_; + Method meth_; + Params params_; +}; + +template <class T, class Method> +inline CancelableTask* NewRunnableMethod(T* object, Method method) { + return new RunnableMethod<T, Method, Tuple0>(object, method, MakeTuple()); +} + +template <class T, class Method, class A> +inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a) { + return new RunnableMethod<T, Method, Tuple1<A> >(object, method, MakeTuple(a)); +} + +template <class T, class Method, class A, class B> +inline CancelableTask* NewRunnableMethod(T* object, Method method, +const A& a, const B& b) { + return new RunnableMethod<T, Method, Tuple2<A, B> >(object, method, + MakeTuple(a, b)); +} + +template <class T, class Method, class A, class B, class C> +inline CancelableTask* NewRunnableMethod(T* object, Method method, + const A& a, const B& b, const C& c) { + return new RunnableMethod<T, Method, Tuple3<A, B, C> >(object, method, + MakeTuple(a, b, c)); +} + +template <class T, class Method, class A, class B, class C, class D> +inline CancelableTask* NewRunnableMethod(T* object, Method method, + const A& a, const B& b, + const C& c, const D& d) { + return new RunnableMethod<T, Method, Tuple4<A, B, C, D> >(object, method, + MakeTuple(a, b, + c, d)); +} + +template <class T, class Method, class A, class B, class C, class D, class E> +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<T, + Method, + Tuple5<A, B, C, D, E> >(object, + method, + MakeTuple(a, b, c, d, e)); +} + +// RunnableFunction and NewRunnableFunction implementation --------------------- + +template <class Function, class Params> +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 <class Function> +inline CancelableTask* NewRunnableFunction(Function function) { + return new RunnableFunction<Function, Tuple0>(function, MakeTuple()); +} + +template <class Function, class A> +inline CancelableTask* NewRunnableFunction(Function function, const A& a) { + return new RunnableFunction<Function, Tuple1<A> >(function, MakeTuple(a)); +} + +template <class Function, class A, class B> +inline CancelableTask* NewRunnableFunction(Function function, + const A& a, const B& b) { + return new RunnableFunction<Function, Tuple2<A, B> >(function, MakeTuple(a, b)); +} + +template <class Function, class A, class B, class C> +inline CancelableTask* NewRunnableFunction(Function function, + const A& a, const B& b, + const C& c) { + return new RunnableFunction<Function, Tuple3<A, B, C> >(function, + MakeTuple(a, b, c)); +} + +template <class Function, class A, class B, class C, class D> +inline CancelableTask* NewRunnableFunction(Function function, + const A& a, const B& b, + const C& c, const D& d) { + return new RunnableFunction<Function, Tuple4<A, B, C, D> >(function, + MakeTuple(a, b, + c, d)); +} + +template <class Function, class A, class B, class C, class D, class E> +inline CancelableTask* NewRunnableFunction(Function function, + const A& a, const B& b, + const C& c, const D& d, + const E& e) { + return new RunnableFunction<Function, Tuple5<A, B, C, D, E> >(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<int, string>::Type* callback = +// NewCallback(obj, &Object::DoStuff); +// callback->Run(5, string("hello")); +// delete callback; +// or, equivalently, using tuples directly: +// CallbackRunner<Tuple2<int, string> >* callback = +// NewCallback(obj, &Object::DoStuff); +// callback->RunWithParams(MakeTuple(5, string("hello"))); + +// Base for all Callbacks that handles storage of the pointers. +template <class T, typename Method> +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 <typename Params> +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 <typename Arg1> + inline void Run(const Arg1& a) { + RunWithParams(Params(a)); + } + + template <typename Arg1, typename Arg2> + inline void Run(const Arg1& a, const Arg2& b) { + RunWithParams(Params(a, b)); + } + + template <typename Arg1, typename Arg2, typename Arg3> + inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) { + RunWithParams(Params(a, b, c)); + } + + template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> + inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) { + RunWithParams(Params(a, b, c, d)); + } + + template <typename Arg1, typename Arg2, typename Arg3, + typename Arg4, typename Arg5> + 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 T, typename Method, typename Params> +class CallbackImpl : public CallbackStorage<T, Method>, + public CallbackRunner<Params> { + public: + CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(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<Tuple0> Type; +}; + +template <class T> +typename Callback0::Type* NewCallback(T* object, void (T::*method)()) { + return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method); +} + +// 1-arg implementation +template <typename Arg1> +struct Callback1 { + typedef CallbackRunner<Tuple1<Arg1> > Type; +}; + +template <class T, typename Arg1> +typename Callback1<Arg1>::Type* NewCallback(T* object, void (T::*method)(Arg1)) { + return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method); +} + +// 2-arg implementation +template <typename Arg1, typename Arg2> +struct Callback2 { + typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type; +}; + +template <class T, typename Arg1, typename Arg2> +typename Callback2<Arg1, Arg2>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2), + Tuple2<Arg1, Arg2> >(object, method); +} + +// 3-arg implementation +template <typename Arg1, typename Arg2, typename Arg3> +struct Callback3 { + typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type; +}; + +template <class T, typename Arg1, typename Arg2, typename Arg3> +typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2, Arg3)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3), + Tuple3<Arg1, Arg2, Arg3> >(object, method); +} + +// 4-arg implementation +template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct Callback4 { + typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type; +}; + +template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2, Arg3, Arg4)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4), + Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method); +} + +// 5-arg implementation +template <typename Arg1, typename Arg2, typename Arg3, + typename Arg4, typename Arg5> +struct Callback5 { + typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type; +}; + +template <class T, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5), + Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method); +} + +#endif // BASE_TASK_H__ |