diff options
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_frame_automation.cc | 42 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_automation.h | 2 | ||||
-rw-r--r-- | chrome_frame/test/proxy_factory_mock.cc | 40 |
3 files changed, 71 insertions, 13 deletions
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc index dce4b78..f505ffe 100644 --- a/chrome_frame/chrome_frame_automation.cc +++ b/chrome_frame/chrome_frame_automation.cc @@ -14,6 +14,7 @@ #include "base/singleton.h" #include "base/string_util.h" #include "base/sys_info.h" +#include "base/waitable_event.h" #include "chrome/app/client_util.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -329,37 +330,54 @@ bool ProxyFactory::ReleaseAutomationServer(void* server_id) { ProxyCacheEntry* entry = reinterpret_cast<ProxyCacheEntry*>(server_id); +#ifndef NDEBUG lock_.Acquire(); Vector::ContainerType::iterator it = std::find(proxies_.container().begin(), proxies_.container().end(), entry); DCHECK(it != proxies_.container().end()); DCHECK(entry->thread->thread_id() != PlatformThread::CurrentId()); - if (--entry->ref_count == 0) { - proxies_.container().erase(it); - } + DCHECK_GT(entry->ref_count, 0); lock_.Release(); +#endif - // Destroy it. + base::WaitableEvent done(true, false); + entry->thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, + &ProxyFactory::ReleaseProxy, entry, &done)); + done.Wait(); + + // Stop the thread and destroy the entry if there is no more clients. if (entry->ref_count == 0) { - entry->thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, - &ProxyFactory::DestroyProxy, entry)); - // Wait until thread exits - entry->thread.reset(); DCHECK(entry->proxy == NULL); + entry->thread.reset(); delete entry; } return true; } -void ProxyFactory::DestroyProxy(ProxyCacheEntry* entry) { +void ProxyFactory::ReleaseProxy(ProxyCacheEntry* entry, + base::WaitableEvent* done) { DCHECK(entry->thread->thread_id() == PlatformThread::CurrentId()); + + lock_.Acquire(); + if (!--entry->ref_count) { + Vector::ContainerType::iterator it = std::find(proxies_.container().begin(), + proxies_.container().end(), + entry); + proxies_->erase(it); + } + lock_.Release(); + // Send pending UMA data if any. - SendUMAData(entry); - delete entry->proxy; - entry->proxy = NULL; + if (!entry->ref_count) { + SendUMAData(entry); + delete entry->proxy; + entry->proxy = NULL; + } + + done->Signal(); } Singleton<ProxyFactory> g_proxy_factory; diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h index 4cfa187..8b2f801 100644 --- a/chrome_frame/chrome_frame_automation.h +++ b/chrome_frame/chrome_frame_automation.h @@ -122,7 +122,7 @@ class ProxyFactory { void CreateProxy(ProxyCacheEntry* entry, const ChromeFrameLaunchParams& params, LaunchDelegate* delegate); - void DestroyProxy(ProxyCacheEntry* entry); + void ReleaseProxy(ProxyCacheEntry* entry, base::WaitableEvent* done); void SendUMAData(ProxyCacheEntry* proxy_entry); diff --git a/chrome_frame/test/proxy_factory_mock.cc b/chrome_frame/test/proxy_factory_mock.cc index a50dc33..2a587f4 100644 --- a/chrome_frame/test/proxy_factory_mock.cc +++ b/chrome_frame/test/proxy_factory_mock.cc @@ -1,6 +1,7 @@ // Copyright (c) 2006-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/waitable_event.h" #include "chrome_frame/test/proxy_factory_mock.h" #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING @@ -84,3 +85,42 @@ TEST(ProxyFactoryTest, CreateDifferentProfiles) { f.ReleaseAutomationServer(i1); } +TEST(ProxyFactoryTest, FastCreateDestroy) { + ProxyFactory f; + LaunchDelegateMock* d1 = new LaunchDelegateMock(); + LaunchDelegateMock* d2 = new LaunchDelegateMock(); + + ChromeFrameLaunchParams params; + params.automation_server_launch_timeout = 10000; + params.profile_name = L"Dr. Gratiano Forbeson"; + params.extra_chrome_arguments = L""; + params.perform_version_check = false; + params.incognito_mode = false; + + void* i1 = NULL; + base::WaitableEvent launched(true, false); + EXPECT_CALL(*d1, LaunchComplete(testing::NotNull(), AUTOMATION_SUCCESS)) + .Times(1) + .WillOnce(testing::InvokeWithoutArgs(&launched, + &base::WaitableEvent::Signal)); + f.GetAutomationServer(d1, params, &i1); + // Wait for launch + ASSERT_TRUE(launched.TimedWait(base::TimeDelta::FromSeconds(10))); + + // Expect second launch to succeed too + EXPECT_CALL(*d2, LaunchComplete(testing::NotNull(), AUTOMATION_SUCCESS)) + .Times(1); + + // Boost thread priority so we call ReleaseAutomationServer before + // LaunchComplete callback have a chance to be executed. + ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + void* i2 = NULL; + f.GetAutomationServer(d2, params, &i2); + EXPECT_EQ(i1, i2); + f.ReleaseAutomationServer(i2); + delete d2; + + ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_NORMAL); + f.ReleaseAutomationServer(i1); + delete d1; +} |