diff options
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/task.h | 8 | ||||
-rw-r--r-- | base/task_unittest.cc | 52 |
3 files changed, 57 insertions, 4 deletions
diff --git a/base/base.gyp b/base/base.gyp index 70cf465..f4ddeb5 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -141,6 +141,7 @@ 'sys_string_conversions_mac_unittest.mm', 'sys_string_conversions_unittest.cc', 'task_queue_unittest.cc', + 'task_unittest.cc', 'thread_checker_unittest.cc', 'thread_collision_warner_unittest.cc', 'thread_local_storage_unittest.cc', diff --git a/base/task.h b/base/task.h index 1949e74..e6e0d2d 100644 --- a/base/task.h +++ b/base/task.h @@ -338,10 +338,10 @@ class RunnableMethod : public CancelableTask { private: void ReleaseCallee() { - if (obj_) { - traits_.ReleaseCallee(obj_); - obj_ = NULL; - } + T* obj = obj_; + obj_ = NULL; + if (obj) + traits_.ReleaseCallee(obj); } T* obj_; diff --git a/base/task_unittest.cc b/base/task_unittest.cc new file mode 100644 index 0000000..cc975e0 --- /dev/null +++ b/base/task_unittest.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2010 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. + +#include "base/ref_counted.h" +#include "base/task.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class CancelInDestructor : public base::RefCounted<CancelInDestructor> { + public: + CancelInDestructor() : cancelable_task_(NULL) {} + + void Start() { + if (cancelable_task_) { + ADD_FAILURE(); + return; + } + AddRef(); + cancelable_task_ = NewRunnableMethod( + this, &CancelInDestructor::NeverIssuedCallback); + Release(); + } + + CancelableTask* cancelable_task() { + return cancelable_task_; + } + + private: + friend class base::RefCounted<CancelInDestructor>; + + ~CancelInDestructor() { + if (cancelable_task_) + cancelable_task_->Cancel(); + } + + void NeverIssuedCallback() { NOTREACHED(); } + + CancelableTask* cancelable_task_; +}; + +TEST(TaskTest, TestCancelInDestructor) { + // Intentionally not using a scoped_refptr for cancel_in_destructor. + CancelInDestructor* cancel_in_destructor = new CancelInDestructor(); + cancel_in_destructor->Start(); + CancelableTask* cancelable_task = cancel_in_destructor->cancelable_task(); + ASSERT_TRUE(cancelable_task); + delete cancelable_task; +} + +} // namespace |