Index: chrome_frame/test/net/test_automation_resource_message_filter.cc |
=================================================================== |
--- chrome_frame/test/net/test_automation_resource_message_filter.cc (revision 116132) |
+++ chrome_frame/test/net/test_automation_resource_message_filter.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Copyright (c) 2012 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. |
@@ -29,11 +29,26 @@ |
bool handled = false; |
int request_id; |
if (URLRequestAutomationJob::MayFilterMessage(message, &request_id)) { |
+ base::AutoLock lock(requests_lock_); |
RequestMap::iterator it = requests_.find(request_id); |
if (it != requests_.end()) { |
handled = true; |
IPC::Message* msg = new IPC::Message(message); |
RequestJob& job = it->second; |
+ |
+ // SUBTLE: Why is this safe? We pass the URLRequestAutomationJob to a |
+ // posted task which then takes a reference. We then release the lock, |
+ // meaning we are no longer protecting access to the request_map_ which |
+ // holds our last owned reference to the URLRequestAutomationJob. Thus |
+ // the posted task could be the one holding the last reference. |
+ // |
+ // If the posted task were to be run on a thread other than the one the |
+ // URLRequestAutomationJob was created on, we could destroy the job on |
+ // the wrong thread (resulting in badness as URLRequestJobs must be |
+ // created and destroyed on the same thread). The destruction will happen |
+ // on the correct thread here since we post to job.loop_ which is set as |
+ // the message loop of the current thread when RegisterRequest is invoked |
+ // by URLRequestJob's constructor. |
job.loop_->PostTask(FROM_HERE, |
base::Bind(OnRequestMessage, job.job_, msg)); |
} |
@@ -49,6 +64,7 @@ |
// Store the request in an internal map like the parent class |
// does, but also store the current loop pointer so we can send |
// request messages to that loop. |
+ base::AutoLock lock(requests_lock_); |
DCHECK(requests_.end() == requests_.find(job->id())); |
RequestJob request_job = { MessageLoop::current(), job }; |
requests_[job->id()] = request_job; |
@@ -58,5 +74,6 @@ |
// Remove request from the list of outstanding requests. |
void TestAutomationResourceMessageFilter::UnRegisterRequest( |
URLRequestAutomationJob* job) { |
+ base::AutoLock lock(requests_lock_); |
requests_.erase(job->id()); |
} |