Index: base/task.h |
diff --git a/base/task.h b/base/task.h |
index 080c150dd3e51fe61d243892b3be91a5ee773631..e01c955d33da00874d35f4e234e65f339a0420af 100644 |
--- a/base/task.h |
+++ b/base/task.h |
@@ -14,8 +14,11 @@ |
#include "base/tracked.h" |
#include "base/tuple.h" |
+class MessageLoop; |
+ |
namespace base { |
const size_t kDeadTask = 0xDEAD7A53; |
+class MessageLoopProxy; |
} |
// Task ------------------------------------------------------------------------ |
@@ -567,36 +570,49 @@ class BASE_API ScopedTaskRunner { |
namespace internal { |
-class PostTaskAndReplyRelay { |
+// This relay class remembers the MessageLoop that it was created on, and |
+// ensures that both the |task| and |reply| Closures are deleted on this same |
+// thread. |
+// |
+// If this is not possible because the originating MessageLoop is no longer |
+// available, the the |task| and |reply| Closures are leaked. Leaking is |
+// considered preferable to having a thread-safetey violations caused by |
+// invoking the Closure destructor on the wrong thread. |
+class PostTaskAndReplyRelay : |
+ public RefCountedThreadSafe<PostTaskAndReplyRelay, ManualDestruction> { |
public: |
- PostTaskAndReplyRelay(const Closure& task, const Closure& reply); |
+ PostTaskAndReplyRelay(const tracked_objects::Location& from_here, |
+ const Closure& task, const Closure& reply); |
~PostTaskAndReplyRelay(); |
void Run(); |
private: |
+ // An alternate implementation would just call "delete this;" inside |
+ // RunReplyAndSelfDestruct() instead of using refcounts with |
+ // ManualDestruction. While this works mostly, it misses the case where the |
+ // target MessageLoop is in shutdown, but the origin MessageLoop is not. |
willchan no longer on Chromium
2011/07/06 22:10:26
I think this is unnecessarily complicated and this
awong
2011/08/15 22:07:55
Okay, went back to simple delete.
|
+ // |
+ // Using a refcount allows us to still properly delete the relay object even |
+ // if PostTaskAndReplyRelay::Run() is never executed. |
+ friend class base::ManualDestruction; |
+ static void DoManualDestruction(const PostTaskAndReplyRelay* obj); |
+ |
void RunReplyAndSelfDestruct(); |
- base::Closure task_; |
- base::Closure reply_; |
+ tracked_objects::Location from_here_; |
+ scoped_refptr<MessageLoopProxy> origin_loop_; |
+ Closure task_; |
+ Closure reply_; |
}; |
-} // namespace internal |
-template <typename MessageLoopType, typename ResponseType> |
-void PostTaskAndReply(MessageLoopType loop, const Closure& task, |
- const Closure& reply) { |
- PostTaskAndReplyRelay* relay = new PostTaskAndReplyRelay(task, reply); |
- loop.PostTask(&PostTaskAndReplyRelay::Run, base::Unretained(relay)); |
-} |
- |
-template <typename MessageLoopType, typename ResponseType> |
-void PostTaskAndReply<MessageLoopType, ResponseType>( |
- MessageLoopType* loop, const Closure& task, const Closure& reply) { |
- PostTaskAndReplyRelay* relay = new PostTaskAndReplyRelay(task, reply); |
- loop->PostTask(&PostTaskAndReplyRelay::Run, base::Unretained(relay)); |
-} |
+} // namespace internal |
+void PostTaskAndReply(MessageLoop* loop, |
+ const tracked_objects::Location& from_here, |
+ const Closure& task, |
+ const Closure& reply); |
} // namespace base |
#endif // BASE_TASK_H_ |