summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcpu@google.com <cpu@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-01 03:06:25 +0000
committercpu@google.com <cpu@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-01 03:06:25 +0000
commitae645471f62870fbe4d09eaa82e9043ffe7284b8 (patch)
tree7fa75ac4be77464cce7077b145a553d721824119
parentf0118db83aa396c97628c33a030627f72bdf0444 (diff)
downloadchromium_src-ae645471f62870fbe4d09eaa82e9043ffe7284b8.zip
chromium_src-ae645471f62870fbe4d09eaa82e9043ffe7284b8.tar.gz
chromium_src-ae645471f62870fbe4d09eaa82e9043ffe7284b8.tar.bz2
Adds new class AtExitManager which manages the dtors of all singletons.
- Previously this job was done by the CRT's atexit() which runs later than we want and under the loader lock. - Had to modify most main() functions for the testing executables so we don't trigger leak detectors. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/at_exit.cc87
-rw-r--r--base/at_exit.h80
-rw-r--r--base/at_exit_unittest.cc82
-rw-r--r--base/build/base.vcproj14
-rw-r--r--base/build/base_unittests.vcproj4
-rw-r--r--base/run_all_perftests.cc5
-rw-r--r--base/run_all_unittests.cc5
-rw-r--r--base/singleton.h55
-rw-r--r--base/singleton_dll_unittest.cc10
-rw-r--r--chrome/app/chrome_main.cc4
-rw-r--r--chrome/app/main.cc4
-rw-r--r--chrome/common/ipc_tests.cc5
-rw-r--r--chrome/installer/util/run_all_unittests.cc6
-rw-r--r--chrome/test/reliability/run_all_unittests.cc5
-rw-r--r--chrome/test/ui/run_all_unittests.cc5
-rw-r--r--chrome/test/unit/run_all_unittests.cc5
-rw-r--r--webkit/tools/test_shell/run_all_tests.cc5
-rw-r--r--webkit/tools/test_shell/test_shell_main.cc4
18 files changed, 345 insertions, 40 deletions
diff --git a/base/at_exit.cc b/base/at_exit.cc
new file mode 100644
index 0000000..c43e9ac
--- /dev/null
+++ b/base/at_exit.cc
@@ -0,0 +1,87 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+
+namespace {
+
+std::stack<base::AtExitCallbackType>* g_atexit_queue = NULL;
+Lock* g_atexit_lock = NULL;
+
+void ProcessCallbacks() {
+ if (!g_atexit_queue)
+ return;
+ base::AtExitCallbackType func = NULL;
+ while(!g_atexit_queue->empty()) {
+ func = g_atexit_queue->top();
+ g_atexit_queue->pop();
+ if (func)
+ func();
+ }
+}
+
+} // namespace
+
+namespace base {
+
+AtExitManager::AtExitManager() {
+ DCHECK(NULL == g_atexit_queue);
+ DCHECK(NULL == g_atexit_lock);
+ g_atexit_lock = &lock_;
+ g_atexit_queue = &atexit_queue_;
+}
+
+AtExitManager::~AtExitManager() {
+ AutoLock lock(lock_);
+ ProcessCallbacks();
+ g_atexit_queue = NULL;
+}
+
+void AtExitManager::RegisterCallback(AtExitCallbackType func) {
+ DCHECK(NULL != g_atexit_queue);
+ DCHECK(NULL != g_atexit_lock);
+ if (!g_atexit_lock)
+ return;
+ AutoLock lock(*g_atexit_lock);
+ if (g_atexit_queue)
+ g_atexit_queue->push(func);
+}
+
+// Calls the functions registered with AtExit in LIFO order.
+void AtExitManager::ProcessCallbacksNow() {
+ DCHECK(NULL != g_atexit_lock);
+ if (!g_atexit_lock)
+ return;
+ AutoLock lock(*g_atexit_lock);
+ DCHECK(NULL != g_atexit_queue);
+ ProcessCallbacks();
+}
+
+} // namespace base
diff --git a/base/at_exit.h b/base/at_exit.h
new file mode 100644
index 0000000..8b9f946
--- /dev/null
+++ b/base/at_exit.h
@@ -0,0 +1,80 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BASE_AT_EXIT_H__
+#define BASE_AT_EXIT_H__
+
+#include <stack>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+
+namespace base {
+
+typedef void (*AtExitCallbackType)();
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+// base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class AtExitManager {
+ public:
+ AtExitManager();
+
+ // The dtor calls all the registered callbacks. Do not try to register more
+ // callbacks after this point.
+ ~AtExitManager();
+
+ // Registers the specified function to be called at exit. The prototype of
+ // the callback function is void func().
+ static void RegisterCallback(AtExitCallbackType func);
+
+ // Calls the functions registered with RegisterCallback in LIFO order. It
+ // is possible to register new callbacks after calling this function.
+ static void ProcessCallbacksNow();
+
+ private:
+ Lock lock_;
+ std::stack<base::AtExitCallbackType> atexit_queue_;
+ DISALLOW_EVIL_CONSTRUCTORS(AtExitManager);
+};
+
+} // namespace base
+
+#endif // BASE_AT_EXIT_H__
diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc
new file mode 100644
index 0000000..692ce66
--- /dev/null
+++ b/base/at_exit_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/at_exit.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int g_test_counter_1 = 0;
+int g_test_counter_2 = 0;
+
+void IncrementTestCounter1() {
+ ++g_test_counter_1;
+}
+
+void IncrementTestCounter2() {
+ ++g_test_counter_2;
+}
+
+void ZeroTestCounters() {
+ g_test_counter_1 = 0;
+ g_test_counter_2 = 0;
+}
+
+void ExpectCounter1IsZero() {
+ EXPECT_EQ(0, g_test_counter_1);
+}
+
+} // namespace
+
+TEST(AtExitTest, Basic) {
+ ZeroTestCounters();
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter2);
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
+
+ EXPECT_EQ(0, g_test_counter_1);
+ EXPECT_EQ(0, g_test_counter_2);
+ base::AtExitManager::ProcessCallbacksNow();
+ EXPECT_EQ(2, g_test_counter_1);
+ EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST(AtExitTest, LIFOOrder) {
+ ZeroTestCounters();
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
+ base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero);
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter2);
+
+ EXPECT_EQ(0, g_test_counter_1);
+ EXPECT_EQ(0, g_test_counter_2);
+ base::AtExitManager::ProcessCallbacksNow();
+ EXPECT_EQ(1, g_test_counter_1);
+ EXPECT_EQ(1, g_test_counter_2);
+}
diff --git a/base/build/base.vcproj b/base/build/base.vcproj
index dd129a5..e4d47856 100644
--- a/base/build/base.vcproj
+++ b/base/build/base.vcproj
@@ -122,6 +122,14 @@
</References>
<Files>
<File
+ RelativePath="..\at_exit.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\at_exit.h"
+ >
+ </File>
+ <File
RelativePath="..\atomic.h"
>
</File>
@@ -162,15 +170,15 @@
>
</File>
<File
- RelativePath="..\bzip2_error_handler.cc"
+ RelativePath="..\third_party\nss\blapi.h"
>
</File>
<File
- RelativePath="..\third_party\nss\blapi.h"
+ RelativePath="..\third_party\nss\blapit.h"
>
</File>
<File
- RelativePath="..\third_party\nss\blapit.h"
+ RelativePath="..\bzip2_error_handler.cc"
>
</File>
<File
diff --git a/base/build/base_unittests.vcproj b/base/build/base_unittests.vcproj
index f9e6787..69d3948 100644
--- a/base/build/base_unittests.vcproj
+++ b/base/build/base_unittests.vcproj
@@ -168,6 +168,10 @@
Name="base_tests"
>
<File
+ RelativePath="..\at_exit_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\atomic_unittest.cc"
>
</File>
diff --git a/base/run_all_perftests.cc b/base/run_all_perftests.cc
index 4ef7494..78eeb37 100644
--- a/base/run_all_perftests.cc
+++ b/base/run_all_perftests.cc
@@ -29,12 +29,17 @@
#include <windows.h>
+#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/perftimer.h"
#include "base/string_util.h"
#include "base/test_suite.h"
int main(int argc, char** argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
// Initialize the perf timer log
std::string log_file =
WideToUTF8(CommandLine().GetSwitchValue(L"log-file"));
diff --git a/base/run_all_unittests.cc b/base/run_all_unittests.cc
index 69b2d3f..299b1c1 100644
--- a/base/run_all_unittests.cc
+++ b/base/run_all_unittests.cc
@@ -27,8 +27,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "base/at_exit.h"
#include "base/test_suite.h"
int main(int argc, char** argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
return TestSuite(argc, argv).Run();
}
diff --git a/base/singleton.h b/base/singleton.h
index 47c0c1d..7df5335 100644
--- a/base/singleton.h
+++ b/base/singleton.h
@@ -34,6 +34,7 @@
#include <utility>
+#include "base/at_exit.h"
#include "base/lock.h"
#include "base/singleton_internal.h"
@@ -44,7 +45,7 @@
#endif // WIN32
// Default traits for Singleton<Type>. Calls operator new and operator delete on
-// the object. Registers automatic deletion at library unload or process exit.
+// the object. Registers automatic deletion at process exit.
// Overload if you need arguments or another memory allocation function.
template<typename Type>
struct DefaultSingletonTraits {
@@ -60,8 +61,8 @@ struct DefaultSingletonTraits {
delete x;
}
- // Set to true to automatically register deletion of the object on library
- // unload or process exit.
+ // Set to true to automatically register deletion of the object on process
+ // exit. See below for the required call that makes this happen.
static const bool kRegisterAtExit = true;
// Note: Only apply on Windows. Has *no effect* on other platform.
@@ -75,8 +76,8 @@ struct DefaultSingletonTraits {
// The Singleton<Type, Traits, DifferentiatingType> class manages a single
// instance of Type which will be created on first use and will be destroyed at
-// library unload (or on normal process exit). The Trait::Delete function will
-// not be called on abnormal process exit.
+// normal process exit). The Trait::Delete function will not be called on
+// abnormal process exit.
//
// DifferentiatingType is used as a key to differentiate two different
// singletons having the same memory allocation functions but serving a
@@ -101,11 +102,15 @@ struct DefaultSingletonTraits {
// RAE = kRegisterAtExit
//
// On every platform, if Traits::RAE is true, the singleton will be destroyed at
-// library unload or process exit. if Traits::RAE is false, the singleton will
-// not be freed at library unload or process exit, thus the singleton will be
-// leaked if it is ever accessed. Traits::RAE shouldn't be false unless
-// absolutely necessary. Remember that the heap where the object is allocated
-// may be destroyed by the CRT anyway.
+// process exit. More precisely it uses base::AtExitManager which requires an
+// object of this type to be instanciated. AtExitManager mimics the semantics
+// of atexit() such as LIFO order but under Windows is safer to call. For more
+// information see at_exit.h.
+//
+// If Traits::RAE is false, the singleton will not be freed at process exit,
+// thus the singleton will be leaked if it is ever accessed. Traits::RAE
+// shouldn't be false unless absolutely necessary. Remember that the heap where
+// the object is allocated may be destroyed by the CRT anyway.
//
// On Windows, now the fun begins. Traits::New() may be called more than once
// concurrently, but no user will gain access to the object until the winning
@@ -231,16 +236,8 @@ class Singleton
// Race condition, discard the temporary value.
Traits::Delete(value);
} else {
- // Got it, register destruction at unload. atexit() is called on library
- // unload. It is assumed that atexit() is itself thread safe. It is also
- // assumed that registered functions by atexit are called in a thread
- // safe manner. At least on Windows, they are called with the loader
- // lock held. On Windows, the CRT use a structure similar to
- // std::map<dll_handle,std::vector<registered_functions>> so the right
- // functions are called on library unload, independent of having a DLL
- // CRT or a static CRT or even both.
if (Traits::kRegisterAtExit)
- atexit(&OnExit);
+ base::AtExitManager::RegisterCallback(&OnExit);
}
}
#endif // WIN32
@@ -249,27 +246,11 @@ class Singleton
static void SafeConstruct() {
instance_ = Traits::New();
- // Porting note: this code depends on some properties of atexit which are
- // not guaranteed by the standard:
- // - atexit must be thread-safe: its internal manipulation of the list of
- // registered functions must be tolerant of multiple threads attempting
- // to register exit routines simultaneously.
- // - exit routines must run when the executable module that contains them
- // is unloaded. For routines in by dynamically-loaded modules, this
- // may be sooner than process termination.
- // - atexit should support an arbitrary number of registered exit
- // routines, or at least should support more routines than will
- // actually be registered (the standard only requires 32).
- // The atexit implementations in contemporary versions of Mac OS X, glibc,
- // and the Windows C runtime provide these capabilities. To port to other
- // systems with less-advanced (even though still standard-conforming)
- // atexit implmentations, consider alternatives such as __cxa_atexit or
- // custom termination sections.
if (Traits::kRegisterAtExit)
- atexit(OnExit);
+ base::AtExitManager::RegisterCallback(OnExit);
}
- // Adapter function for use with atexit().
+ // Adapter function for use with AtExit().
static void OnExit() {
if (!instance_)
return;
diff --git a/base/singleton_dll_unittest.cc b/base/singleton_dll_unittest.cc
index c663db3..4e0ec3a 100644
--- a/base/singleton_dll_unittest.cc
+++ b/base/singleton_dll_unittest.cc
@@ -28,16 +28,26 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/singleton_dll_unittest.h"
+#include "base/at_exit.h"
#include "base/logging.h"
+namespace {
+
+base::AtExitManager* g_exit_manager = NULL;
+
+} // namespace
+
BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) {
switch (reason_for_call) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(module);
+ g_exit_manager = new base::AtExitManager();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
+ break;
case DLL_PROCESS_DETACH:
+ delete g_exit_manager;
break;
}
return TRUE;
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index 54cb57c..a6f8091 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -32,6 +32,7 @@
#include <malloc.h>
#include <new.h>
+#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/icu_util.h"
#include "base/message_loop.h"
@@ -140,6 +141,9 @@ DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
_CrtSetReportMode(_CRT_ASSERT, 0);
#endif
+ // The exit manager is in charge of calling the dtors of singleton objects.
+ base::AtExitManager exit_manager;
+
// Register the invalid param handler and pure call handler to be able to
// notify breakpad when it happens.
_set_invalid_parameter_handler(InvalidParameter);
diff --git a/chrome/app/main.cc b/chrome/app/main.cc
index cbcfdee..ab2848b 100644
--- a/chrome/app/main.cc
+++ b/chrome/app/main.cc
@@ -30,6 +30,7 @@
#include <windows.h>
#include <tchar.h>
+#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug_on_start.h"
@@ -43,6 +44,9 @@
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
wchar_t* command_line, int show_command) {
+ // The exit manager is in charge of calling the dtors of singletons.
+ base::AtExitManager exit_manager;
+
google_update::GoogleUpdateClient client;
// Note that std::wstring and CommandLine got linked anyway because of
diff --git a/chrome/common/ipc_tests.cc b/chrome/common/ipc_tests.cc
index a9d998c..dbcd33d 100644
--- a/chrome/common/ipc_tests.cc
+++ b/chrome/common/ipc_tests.cc
@@ -34,6 +34,7 @@
#include "chrome/common/ipc_tests.h"
+#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug_on_start.h"
@@ -400,6 +401,10 @@ HANDLE SpawnChild(ChildType child_type) {
}
int main(int argc, char** argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
MessageLoop main_message_loop;
// suppress standard crash dialogs and such unless a debugger is present.
diff --git a/chrome/installer/util/run_all_unittests.cc b/chrome/installer/util/run_all_unittests.cc
index 69b2d3f..f38f05b 100644
--- a/chrome/installer/util/run_all_unittests.cc
+++ b/chrome/installer/util/run_all_unittests.cc
@@ -27,8 +27,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/at_exit.h"
#include "base/test_suite.h"
int main(int argc, char** argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
return TestSuite(argc, argv).Run();
}
diff --git a/chrome/test/reliability/run_all_unittests.cc b/chrome/test/reliability/run_all_unittests.cc
index a5d3da3..cfe0a29 100644
--- a/chrome/test/reliability/run_all_unittests.cc
+++ b/chrome/test/reliability/run_all_unittests.cc
@@ -27,8 +27,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "base/at_exit.h"
#include "chrome/test/reliability/reliability_test_suite.h"
int main(int argc, char **argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
return ReliabilityTestSuite(argc, argv).Run();
}
diff --git a/chrome/test/ui/run_all_unittests.cc b/chrome/test/ui/run_all_unittests.cc
index 737a7be..8d1307772 100644
--- a/chrome/test/ui/run_all_unittests.cc
+++ b/chrome/test/ui/run_all_unittests.cc
@@ -27,9 +27,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "base/at_exit.h"
#include "chrome/test/ui/ui_test_suite.h"
int main(int argc, char **argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
Thread::SetThreadName("Tests_Main", GetCurrentThreadId());
return UITestSuite(argc, argv).Run();
}
diff --git a/chrome/test/unit/run_all_unittests.cc b/chrome/test/unit/run_all_unittests.cc
index f8d6fea..f52bd78 100644
--- a/chrome/test/unit/run_all_unittests.cc
+++ b/chrome/test/unit/run_all_unittests.cc
@@ -27,8 +27,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "base/at_exit.h"
#include "chrome/test/unit/chrome_test_suite.h"
int main(int argc, char **argv) {
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
return ChromeTestSuite(argc, argv).Run();
}
diff --git a/webkit/tools/test_shell/run_all_tests.cc b/webkit/tools/test_shell/run_all_tests.cc
index 05cdc43..3c4148d 100644
--- a/webkit/tools/test_shell/run_all_tests.cc
+++ b/webkit/tools/test_shell/run_all_tests.cc
@@ -33,6 +33,7 @@
#include <windows.h>
#include <commctrl.h>
+#include "base/at_exit.h"
#include "base/icu_util.h"
#include "base/message_loop.h"
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
@@ -50,6 +51,10 @@ const char* TestShellTest::kJavascriptDelayExitScript =
"</script>";
int main(int argc, char* argv[]) {
+ // Some unittests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
+
TestShell::InitLogging(true); // suppress error dialogs
// Initialize test shell in non-interactive mode, which will let us load one
diff --git a/webkit/tools/test_shell/test_shell_main.cc b/webkit/tools/test_shell/test_shell_main.cc
index 468ec36..4b1940e 100644
--- a/webkit/tools/test_shell/test_shell_main.cc
+++ b/webkit/tools/test_shell/test_shell_main.cc
@@ -34,6 +34,7 @@
#include <windows.h>
#include <commctrl.h>
+#include "base/at_exit.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/event_recorder.h"
@@ -136,6 +137,9 @@ int main(int argc, char* argv[])
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
#endif
+ // Some tests may use base::Singleton<>, thus we need to instanciate
+ // the AtExitManager or else we will leak objects.
+ base::AtExitManager at_exit_manager;
CommandLine parsed_command_line;
if (parsed_command_line.HasSwitch(test_shell::kStartupDialog))