summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gyp1
-rw-r--r--base/task.h8
-rw-r--r--base/task_unittest.cc52
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