1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TASK_H_ 6 #define BASE_TASK_H_ 7 8 #include "base/non_thread_safe.h" 9 #include "base/raw_scoped_refptr_mismatch_checker.h" 10 #include "base/tracked.h" 11 #include "base/tuple.h" 12 #include "base/weak_ptr.h" 13 14 // Task ------------------------------------------------------------------------ 15 // 16 // A task is a generic runnable thingy, usually used for running code on a 17 // different thread or for scheduling future tasks off of the message loop. 18 19 class Task : public tracked_objects::Tracked { 20 public: 21 Task() {} 22 virtual ~Task() {} 23 24 // Tasks are automatically deleted after Run is called. 25 virtual void Run() = 0; 26 }; 27 28 class CancelableTask : public Task { 29 public: 30 // Not all tasks support cancellation. 31 virtual void Cancel() = 0; 32 }; 33 34 // Scoped Factories ------------------------------------------------------------ 35 // 36 // These scoped factory objects can be used by non-refcounted objects to safely 37 // place tasks in a message loop. Each factory guarantees that the tasks it 38 // produces will not run after the factory is destroyed. Commonly, factories 39 // are declared as class members, so the class' tasks will automatically cancel 40 // when the class instance is destroyed. 41 // 42 // Exampe Usage: 43 // 44 // class MyClass { 45 // private: 46 // // This factory will be used to schedule invocations of SomeMethod. 47 // ScopedRunnableMethodFactory<MyClass> some_method_factory_; 48 // 49 // public: 50 // // It is safe to suppress warning 4355 here. 51 // MyClass() : some_method_factory_(this) { } 52 // 53 // void SomeMethod() { 54 // // If this function might be called directly, you might want to revoke 55 // // any outstanding runnable methods scheduled to call it. If it's not 56 // // referenced other than by the factory, this is unnecessary. 57 // some_method_factory_.RevokeAll(); 58 // ... 59 // } 60 // 61 // void ScheduleSomeMethod() { 62 // // If you'd like to only only have one pending task at a time, test for 63 // // |empty| before manufacturing another task. 64 // if (!some_method_factory_.empty()) 65 // return; 66 // 67 // // The factories are not thread safe, so always invoke on 68 // // |MessageLoop::current()|. 69 // MessageLoop::current()->PostDelayedTask(FROM_HERE, 70 // some_method_factory_.NewRunnableMethod(&MyClass::SomeMethod), 71 // kSomeMethodDelayMS); 72 // } 73 // }; 74 75 // A ScopedRunnableMethodFactory creates runnable methods for a specified 76 // object. This is particularly useful for generating callbacks for 77 // non-reference counted objects when the factory is a member of the object. 78 template<class T> 79 class ScopedRunnableMethodFactory { 80 public: 81 explicit ScopedRunnableMethodFactory(T* object) : weak_factory_(object) { 82 } 83 84 template <class Method> 85 inline Task* NewRunnableMethod(Method method) { 86 return new RunnableMethod<Method, Tuple0>( 87 weak_factory_.GetWeakPtr(), method, MakeTuple()); 88 } 89 90 template <class Method, class A> 91 inline Task* NewRunnableMethod(Method method, const A& a) { 92 return new RunnableMethod<Method, Tuple1<A> >( 93 weak_factory_.GetWeakPtr(), method, MakeTuple(a)); 94 } 95 96 template <class Method, class A, class B> 97 inline Task* NewRunnableMethod(Method method, const A& a, const B& b) { 98 return new RunnableMethod<Method, Tuple2<A, B> >( 99 weak_factory_.GetWeakPtr(), method, MakeTuple(a, b)); 100 } 101 102 template <class Method, class A, class B, class C> 103 inline Task* NewRunnableMethod(Method method, 104 const A& a, 105 const B& b, 106 const C& c) { 107 return new RunnableMethod<Method, Tuple3<A, B, C> >( 108 weak_factory_.GetWeakPtr(), method, MakeTuple(a, b, c)); 109 } 110 111 template <class Method, class A, class B, class C, class D> 112 inline Task* NewRunnableMethod(Method method, 113 const A& a, 114 const B& b, 115 const C& c, 116 const D& d) { 117 return new RunnableMethod<Method, Tuple4<A, B, C, D> >( 118 weak_factory_.GetWeakPtr(), method, MakeTuple(a, b, c, d)); 119 } 120 121 template <class Method, class A, class B, class C, class D, class E> 122 inline Task* NewRunnableMethod(Method method, 123 const A& a, 124 const B& b, 125 const C& c, 126 const D& d, 127 const E& e) { 128 return new RunnableMethod<Method, Tuple5<A, B, C, D, E> >( 129 weak_factory_.GetWeakPtr(), method, MakeTuple(a, b, c, d, e)); 130 } 131 132 void RevokeAll() { weak_factory_.InvalidateWeakPtrs(); } 133 134 bool empty() const { return !weak_factory_.HasWeakPtrs(); } 135 136 protected: 137 template <class Method, class Params> 138 class RunnableMethod : public Task { 139 public: 140 RunnableMethod(const base::WeakPtr<T>& obj, Method meth, const Params& params) 141 : obj_(obj), 142 meth_(meth), 143 params_(params) { 144 COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), 145 badscopedrunnablemethodparams); 146 } 147 148 virtual void Run() { 149 if (obj_) 150 DispatchToMethod(obj_.get(), meth_, params_); 151 } 152 153 private: 154 base::WeakPtr<T> obj_; 155 Method meth_; 156 Params params_; 157 158 DISALLOW_COPY_AND_ASSIGN(RunnableMethod); 159 }; 160 161 private: 162 base::WeakPtrFactory<T> weak_factory_; 163 }; 164 165 // General task implementations ------------------------------------------------ 166 167 // Task to delete an object 168 template<class T> 169 class DeleteTask : public CancelableTask { 170 public: 171 explicit DeleteTask(T* obj) : obj_(obj) { 172 } 173 virtual void Run() { 174 delete obj_; 175 } 176 virtual void Cancel() { 177 obj_ = NULL; 178 } 179 private: 180 T* obj_; 181 }; 182 183 // Task to Release() an object 184 template<class T> 185 class ReleaseTask : public CancelableTask { 186 public: 187 explicit ReleaseTask(T* obj) : obj_(obj) { 188 } 189 virtual void Run() { 190 if (obj_) 191 obj_->Release(); 192 } 193 virtual void Cancel() { 194 obj_ = NULL; 195 } 196 private: 197 T* obj_; 198 }; 199 200 // RunnableMethodTraits -------------------------------------------------------- 201 // 202 // This traits-class is used by RunnableMethod to manage the lifetime of the 203 // callee object. By default, it is assumed that the callee supports AddRef 204 // and Release methods. A particular class can specialize this template to 205 // define other lifetime management. For example, if the callee is known to 206 // live longer than the RunnableMethod object, then a RunnableMethodTraits 207 // struct could be defined with empty RetainCallee and ReleaseCallee methods. 208 209 template <class T> 210 struct RunnableMethodTraits { 211 RunnableMethodTraits() { 212 #ifndef NDEBUG 213 origin_thread_id_ = PlatformThread::CurrentId(); 214 #endif 215 } 216 217 ~RunnableMethodTraits() { 218 #ifndef NDEBUG 219 // If destroyed on a separate thread, then we had better have been using 220 // thread-safe reference counting! 221 if (origin_thread_id_ != PlatformThread::CurrentId()) 222 DCHECK(T::ImplementsThreadSafeReferenceCounting()); 223 #endif 224 } 225 226 void RetainCallee(T* obj) { 227 #ifndef NDEBUG 228 // Catch NewRunnableMethod being called in an object's constructor. This 229 // isn't safe since the method can be invoked before the constructor 230 // completes, causing the object to be deleted. 231 obj->AddRef(); 232 obj->Release(); 233 #endif 234 obj->AddRef(); 235 } 236 237 void ReleaseCallee(T* obj) { 238 obj->Release(); 239 } 240 241 private: 242 #ifndef NDEBUG 243 PlatformThreadId origin_thread_id_; 244 #endif 245 }; 246 247 // RunnableMethod and RunnableFunction ----------------------------------------- 248 // 249 // Runnable methods are a type of task that call a function on an object when 250 // they are run. We implement both an object and a set of NewRunnableMethod and 251 // NewRunnableFunction functions for convenience. These functions are 252 // overloaded and will infer the template types, simplifying calling code. 253 // 254 // The template definitions all use the following names: 255 // T - the class type of the object you're supplying 256 // this is not needed for the Static version of the call 257 // Method/Function - the signature of a pointer to the method or function you 258 // want to call 259 // Param - the parameter(s) to the method, possibly packed as a Tuple 260 // A - the first parameter (if any) to the method 261 // B - the second parameter (if any) to the mathod 262 // 263 // Put these all together and you get an object that can call a method whose 264 // signature is: 265 // R T::MyFunction([A[, B]]) 266 // 267 // Usage: 268 // PostTask(FROM_HERE, NewRunnableMethod(object, &Object::method[, a[, b]]) 269 // PostTask(FROM_HERE, NewRunnableFunction(&function[, a[, b]]) 270 271 // RunnableMethod and NewRunnableMethod implementation ------------------------- 272 273 template <class T, class Method, class Params> 274 class RunnableMethod : public CancelableTask { 275 public: 276 RunnableMethod(T* obj, Method meth, const Params& params) 277 : obj_(obj), meth_(meth), params_(params) { 278 traits_.RetainCallee(obj_); 279 COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), 280 badrunnablemethodparams); 281 } 282 283 ~RunnableMethod() { 284 ReleaseCallee(); 285 } 286 287 virtual void Run() { 288 if (obj_) 289 DispatchToMethod(obj_, meth_, params_); 290 } 291 292 virtual void Cancel() { 293 ReleaseCallee(); 294 } 295 296 private: 297 void ReleaseCallee() { 298 if (obj_) { 299 traits_.ReleaseCallee(obj_); 300 obj_ = NULL; 301 } 302 } 303 304 T* obj_; 305 Method meth_; 306 Params params_; 307 RunnableMethodTraits<T> traits_; 308 }; 309 310 template <class T, class Method> 311 inline CancelableTask* NewRunnableMethod(T* object, Method method) { 312 return new RunnableMethod<T, Method, Tuple0>(object, method, MakeTuple()); 313 } 314 315 template <class T, class Method, class A> 316 inline CancelableTask* NewRunnableMethod(T* object, Method method, const A& a) { 317 return new RunnableMethod<T, Method, Tuple1<A> >(object, 318 method, 319 MakeTuple(a)); 320 } 321 322 template <class T, class Method, class A, class B> 323 inline CancelableTask* NewRunnableMethod(T* object, Method method, 324 const A& a, const B& b) { 325 return new RunnableMethod<T, Method, Tuple2<A, B> >(object, method, 326 MakeTuple(a, b)); 327 } 328 329 template <class T, class Method, class A, class B, class C> 330 inline CancelableTask* NewRunnableMethod(T* object, Method method, 331 const A& a, const B& b, const C& c) { 332 return new RunnableMethod<T, Method, Tuple3<A, B, C> >(object, method, 333 MakeTuple(a, b, c)); 334 } 335 336 template <class T, class Method, class A, class B, class C, class D> 337 inline CancelableTask* NewRunnableMethod(T* object, Method method, 338 const A& a, const B& b, 339 const C& c, const D& d) { 340 return new RunnableMethod<T, Method, Tuple4<A, B, C, D> >(object, method, 341 MakeTuple(a, b, 342 c, d)); 343 } 344 345 template <class T, class Method, class A, class B, class C, class D, class E> 346 inline CancelableTask* NewRunnableMethod(T* object, Method method, 347 const A& a, const B& b, 348 const C& c, const D& d, const E& e) { 349 return new RunnableMethod<T, 350 Method, 351 Tuple5<A, B, C, D, E> >(object, 352 method, 353 MakeTuple(a, b, c, d, e)); 354 } 355 356 template <class T, class Method, class A, class B, class C, class D, class E, 357 class F> 358 inline CancelableTask* NewRunnableMethod(T* object, Method method, 359 const A& a, const B& b, 360 const C& c, const D& d, const E& e, 361 const F& f) { 362 return new RunnableMethod<T, 363 Method, 364 Tuple6<A, B, C, D, E, F> >(object, 365 method, 366 MakeTuple(a, b, c, d, e, 367 f)); 368 } 369 370 template <class T, class Method, class A, class B, class C, class D, class E, 371 class F, class G> 372 inline CancelableTask* NewRunnableMethod(T* object, Method method, 373 const A& a, const B& b, 374 const C& c, const D& d, const E& e, 375 const F& f, const G& g) { 376 return new RunnableMethod<T, 377 Method, 378 Tuple7<A, B, C, D, E, F, G> >(object, 379 method, 380 MakeTuple(a, b, c, d, 381 e, f, g)); 382 } 383 384 // RunnableFunction and NewRunnableFunction implementation --------------------- 385 386 template <class Function, class Params> 387 class RunnableFunction : public CancelableTask { 388 public: 389 RunnableFunction(Function function, const Params& params) 390 : function_(function), params_(params) { 391 COMPILE_ASSERT((FunctionUsesScopedRefptrCorrectly<Function, Params>::value), 392 badrunnablefunctionparams); 393 } 394 395 ~RunnableFunction() { 396 } 397 398 virtual void Run() { 399 if (function_) 400 DispatchToFunction(function_, params_); 401 } 402 403 virtual void Cancel() { 404 } 405 406 private: 407 Function function_; 408 Params params_; 409 }; 410 411 template <class Function> 412 inline CancelableTask* NewRunnableFunction(Function function) { 413 return new RunnableFunction<Function, Tuple0>(function, MakeTuple()); 414 } 415 416 template <class Function, class A> 417 inline CancelableTask* NewRunnableFunction(Function function, const A& a) { 418 return new RunnableFunction<Function, Tuple1<A> >(function, MakeTuple(a)); 419 } 420 421 template <class Function, class A, class B> 422 inline CancelableTask* NewRunnableFunction(Function function, 423 const A& a, const B& b) { 424 return new RunnableFunction<Function, Tuple2<A, B> >(function, 425 MakeTuple(a, b)); 426 } 427 428 template <class Function, class A, class B, class C> 429 inline CancelableTask* NewRunnableFunction(Function function, 430 const A& a, const B& b, 431 const C& c) { 432 return new RunnableFunction<Function, Tuple3<A, B, C> >(function, 433 MakeTuple(a, b, c)); 434 } 435 436 template <class Function, class A, class B, class C, class D> 437 inline CancelableTask* NewRunnableFunction(Function function, 438 const A& a, const B& b, 439 const C& c, const D& d) { 440 return new RunnableFunction<Function, Tuple4<A, B, C, D> >(function, 441 MakeTuple(a, b, 442 c, d)); 443 } 444 445 template <class Function, class A, class B, class C, class D, class E> 446 inline CancelableTask* NewRunnableFunction(Function function, 447 const A& a, const B& b, 448 const C& c, const D& d, 449 const E& e) { 450 return new RunnableFunction<Function, Tuple5<A, B, C, D, E> >(function, 451 MakeTuple(a, b, 452 c, d, 453 e)); 454 } 455 456 // Callback -------------------------------------------------------------------- 457 // 458 // A Callback is like a Task but with unbound parameters. It is basically an 459 // object-oriented function pointer. 460 // 461 // Callbacks are designed to work with Tuples. A set of helper functions and 462 // classes is provided to hide the Tuple details from the consumer. Client 463 // code will generally work with the CallbackRunner base class, which merely 464 // provides a Run method and is returned by the New* functions. This allows 465 // users to not care which type of class implements the callback, only that it 466 // has a certain number and type of arguments. 467 // 468 // The implementation of this is done by CallbackImpl, which inherits 469 // CallbackStorage to store the data. This allows the storage of the data 470 // (requiring the class type T) to be hidden from users, who will want to call 471 // this regardless of the implementor's type T. 472 // 473 // Note that callbacks currently have no facility for cancelling or abandoning 474 // them. We currently handle this at a higher level for cases where this is 475 // necessary. The pointer in a callback must remain valid until the callback 476 // is made. 477 // 478 // Like Task, the callback executor is responsible for deleting the callback 479 // pointer once the callback has executed. 480 // 481 // Example client usage: 482 // void Object::DoStuff(int, string); 483 // Callback2<int, string>::Type* callback = 484 // NewCallback(obj, &Object::DoStuff); 485 // callback->Run(5, string("hello")); 486 // delete callback; 487 // or, equivalently, using tuples directly: 488 // CallbackRunner<Tuple2<int, string> >* callback = 489 // NewCallback(obj, &Object::DoStuff); 490 // callback->RunWithParams(MakeTuple(5, string("hello"))); 491 // 492 // There is also a 0-args version that returns a value. Example: 493 // int Object::GetNextInt(); 494 // CallbackWithReturnValue<int>::Type* callback = 495 // NewCallbackWithReturnValue(obj, &Object::GetNextInt); 496 // int next_int = callback->Run(); 497 // delete callback; 498 499 // Base for all Callbacks that handles storage of the pointers. 500 template <class T, typename Method> 501 class CallbackStorage { 502 public: 503 CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) { 504 } 505 506 protected: 507 T* obj_; 508 Method meth_; 509 }; 510 511 // Interface that is exposed to the consumer, that does the actual calling 512 // of the method. 513 template <typename Params> 514 class CallbackRunner { 515 public: 516 typedef Params TupleType; 517 518 virtual ~CallbackRunner() {} 519 virtual void RunWithParams(const Params& params) = 0; 520 521 // Convenience functions so callers don't have to deal with Tuples. 522 inline void Run() { 523 RunWithParams(Tuple0()); 524 } 525 526 template <typename Arg1> 527 inline void Run(const Arg1& a) { 528 RunWithParams(Params(a)); 529 } 530 531 template <typename Arg1, typename Arg2> 532 inline void Run(const Arg1& a, const Arg2& b) { 533 RunWithParams(Params(a, b)); 534 } 535 536 template <typename Arg1, typename Arg2, typename Arg3> 537 inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) { 538 RunWithParams(Params(a, b, c)); 539 } 540 541 template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> 542 inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) { 543 RunWithParams(Params(a, b, c, d)); 544 } 545 546 template <typename Arg1, typename Arg2, typename Arg3, 547 typename Arg4, typename Arg5> 548 inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, 549 const Arg4& d, const Arg5& e) { 550 RunWithParams(Params(a, b, c, d, e)); 551 } 552 }; 553 554 template <class T, typename Method, typename Params> 555 class CallbackImpl : public CallbackStorage<T, Method>, 556 public CallbackRunner<Params> { 557 public: 558 CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) { 559 } 560 virtual void RunWithParams(const Params& params) { 561 // use "this->" to force C++ to look inside our templatized base class; see 562 // Effective C++, 3rd Ed, item 43, p210 for details. 563 DispatchToMethod(this->obj_, this->meth_, params); 564 } 565 }; 566 567 // 0-arg implementation 568 struct Callback0 { 569 typedef CallbackRunner<Tuple0> Type; 570 }; 571 572 template <class T> 573 typename Callback0::Type* NewCallback(T* object, void (T::*method)()) { 574 return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method); 575 } 576 577 // 1-arg implementation 578 template <typename Arg1> 579 struct Callback1 { 580 typedef CallbackRunner<Tuple1<Arg1> > Type; 581 }; 582 583 template <class T, typename Arg1> 584 typename Callback1<Arg1>::Type* NewCallback(T* object, 585 void (T::*method)(Arg1)) { 586 return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method); 587 } 588 589 // 2-arg implementation 590 template <typename Arg1, typename Arg2> 591 struct Callback2 { 592 typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type; 593 }; 594 595 template <class T, typename Arg1, typename Arg2> 596 typename Callback2<Arg1, Arg2>::Type* NewCallback( 597 T* object, 598 void (T::*method)(Arg1, Arg2)) { 599 return new CallbackImpl<T, void (T::*)(Arg1, Arg2), 600 Tuple2<Arg1, Arg2> >(object, method); 601 } 602 603 // 3-arg implementation 604 template <typename Arg1, typename Arg2, typename Arg3> 605 struct Callback3 { 606 typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type; 607 }; 608 609 template <class T, typename Arg1, typename Arg2, typename Arg3> 610 typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback( 611 T* object, 612 void (T::*method)(Arg1, Arg2, Arg3)) { 613 return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3), 614 Tuple3<Arg1, Arg2, Arg3> >(object, method); 615 } 616 617 // 4-arg implementation 618 template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> 619 struct Callback4 { 620 typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type; 621 }; 622 623 template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> 624 typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback( 625 T* object, 626 void (T::*method)(Arg1, Arg2, Arg3, Arg4)) { 627 return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4), 628 Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method); 629 } 630 631 // 5-arg implementation 632 template <typename Arg1, typename Arg2, typename Arg3, 633 typename Arg4, typename Arg5> 634 struct Callback5 { 635 typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type; 636 }; 637 638 template <class T, typename Arg1, typename Arg2, 639 typename Arg3, typename Arg4, typename Arg5> 640 typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback( 641 T* object, 642 void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) { 643 return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5), 644 Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method); 645 } 646 647 // An UnboundMethod is a wrapper for a method where the actual object is 648 // provided at Run dispatch time. 649 template <class T, class Method, class Params> 650 class UnboundMethod { 651 public: 652 UnboundMethod(Method m, Params p) : m_(m), p_(p) { 653 COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), 654 badunboundmethodparams); 655 } 656 void Run(T* obj) const { 657 DispatchToMethod(obj, m_, p_); 658 } 659 private: 660 Method m_; 661 Params p_; 662 }; 663 664 // Return value implementation with no args. 665 template <typename ReturnValue> 666 struct CallbackWithReturnValue { 667 class Type { 668 public: 669 virtual ~Type() {} 670 virtual ReturnValue Run() = 0; 671 }; 672 }; 673 674 template <class T, typename Method, typename ReturnValue> 675 class CallbackWithReturnValueImpl 676 : public CallbackStorage<T, Method>, 677 public CallbackWithReturnValue<ReturnValue>::Type { 678 public: 679 CallbackWithReturnValueImpl(T* obj, Method meth) 680 : CallbackStorage<T, Method>(obj, meth) {} 681 682 virtual ReturnValue Run() { 683 return (this->obj_->*(this->meth_))(); 684 } 685 686 protected: 687 virtual ~CallbackWithReturnValueImpl() {} 688 }; 689 690 template <class T, typename ReturnValue> 691 typename CallbackWithReturnValue<ReturnValue>::Type* 692 NewCallbackWithReturnValue(T* object, ReturnValue (T::*method)()) { 693 return new CallbackWithReturnValueImpl<T, ReturnValue (T::*)(), ReturnValue>( 694 object, method); 695 } 696 697 698 #endif // BASE_TASK_H_ 699