summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/allocator/allocator.gyp2
-rw-r--r--base/allocator/allocator_unittests.cc16
-rw-r--r--base/at_exit.cc10
-rw-r--r--base/at_exit.h4
-rw-r--r--base/atomicops_internals_x86_macosx.h23
-rw-r--r--base/base.gyp5
-rw-r--r--base/base.gypi18
-rw-r--r--base/base_paths_linux.cc6
-rw-r--r--base/base_switches.cc6
-rw-r--r--base/bind.h99
-rw-r--r--base/bind.h.pump71
-rw-r--r--base/bind_helpers.h287
-rw-r--r--base/bind_internal.h1670
-rw-r--r--base/bind_internal.h.pump237
-rw-r--r--base/bind_unittest.cc597
-rw-r--r--base/callback.h640
-rw-r--r--base/callback.h.pump291
-rw-r--r--base/callback_helpers.h55
-rw-r--r--base/callback_old.h254
-rw-r--r--base/compiler_specific.h2
-rw-r--r--base/crypto/capi_util.cc8
-rw-r--r--base/crypto/crypto_module_blocking_password_delegate.h34
-rw-r--r--base/crypto/cssm_init.cc144
-rw-r--r--base/crypto/cssm_init.h31
-rw-r--r--base/crypto/rsa_private_key.cc299
-rw-r--r--base/crypto/rsa_private_key.h6
-rw-r--r--base/crypto/rsa_private_key_mac.cc51
-rw-r--r--base/crypto/rsa_private_key_nss.cc139
-rw-r--r--base/crypto/secure_hash.h36
-rw-r--r--base/crypto/secure_hash_default.cc49
-rw-r--r--base/crypto/secure_hash_openssl.cc53
-rw-r--r--base/crypto/secure_hash_unittest.cc34
-rw-r--r--base/crypto/signature_creator_mac.cc10
-rw-r--r--base/crypto/signature_creator_nss.cc22
-rw-r--r--base/crypto/symmetric_key_nss.cc8
-rw-r--r--base/debug/debugger_posix.cc3
-rw-r--r--base/debug/debugger_win.cc3
-rw-r--r--base/debug/profiler.cc65
-rw-r--r--base/debug/profiler.h35
-rw-r--r--base/debug/stack_trace_win.cc6
-rw-r--r--base/debug/trace_event.cc132
-rw-r--r--base/debug/trace_event.h4
-rw-r--r--base/event_recorder.h5
-rw-r--r--base/file_path.cc16
-rw-r--r--base/file_path.h9
-rw-r--r--base/file_util.cc20
-rw-r--r--base/file_util_posix.cc40
-rw-r--r--base/file_util_proxy.cc113
-rw-r--r--base/file_util_proxy.h38
-rw-r--r--base/file_util_unittest.cc4
-rw-r--r--base/file_util_win.cc9
-rw-r--r--base/global_descriptors_posix.cc28
-rw-r--r--base/global_descriptors_posix.h4
-rw-r--r--base/hmac_nss.cc6
-rw-r--r--base/i18n/bidi_line_iterator.cc60
-rw-r--r--base/i18n/bidi_line_iterator.h47
-rw-r--r--base/i18n/char_iterator.cc10
-rw-r--r--base/i18n/char_iterator.h8
-rw-r--r--base/i18n/char_iterator_unittest.cc16
-rw-r--r--base/i18n/file_util_icu.cc4
-rw-r--r--base/i18n/icu_util.cc37
-rw-r--r--base/json/json_reader.cc52
-rw-r--r--base/json/json_reader.h10
-rw-r--r--base/json/json_reader_unittest.cc72
-rw-r--r--base/json/json_writer.cc4
-rw-r--r--base/json/json_writer_unittest.cc6
-rw-r--r--base/linux_util.cc8
-rw-r--r--base/lock.h18
-rw-r--r--base/logging.cc118
-rw-r--r--base/logging.h58
-rw-r--r--base/logging_unittest.cc8
-rw-r--r--base/mac/foundation_util.h107
-rw-r--r--base/mac/foundation_util.mm236
-rw-r--r--base/mac/mac_util.h93
-rw-r--r--base/mac/mac_util.mm234
-rw-r--r--base/mac/mac_util_unittest.mm36
-rw-r--r--base/message_loop.cc10
-rw-r--r--base/message_loop.h9
-rw-r--r--base/message_loop_proxy_impl.cc56
-rw-r--r--base/message_loop_proxy_impl.h4
-rw-r--r--base/message_loop_unittest.cc8
-rw-r--r--base/message_pump_glib.cc38
-rw-r--r--base/message_pump_glib_unittest.cc1
-rw-r--r--base/message_pump_glib_x.cc109
-rw-r--r--base/message_pump_glib_x_dispatch.h2
-rw-r--r--base/message_pump_libevent.cc150
-rw-r--r--base/message_pump_win.cc2
-rw-r--r--base/metrics/field_trial.cc149
-rw-r--r--base/metrics/field_trial.h79
-rw-r--r--base/metrics/field_trial_unittest.cc131
-rw-r--r--base/metrics/histogram.cc572
-rw-r--r--base/metrics/stats_table.cc265
-rw-r--r--base/metrics/stats_table.h6
-rw-r--r--base/mime_util_xdg.cc5
-rw-r--r--base/nss_util.cc42
-rw-r--r--base/nss_util.h7
-rw-r--r--base/observer_list_threadsafe.h54
-rw-r--r--base/openssl_util.cc6
-rw-r--r--base/path_service.cc18
-rw-r--r--base/pickle.cc3
-rw-r--r--base/pickle.h4
-rw-r--r--base/pickle_unittest.cc11
-rw-r--r--base/pr_time_unittest.cc60
-rw-r--r--base/process_linux.cc7
-rw-r--r--base/process_posix.cc32
-rw-r--r--base/process_util.cc8
-rw-r--r--base/process_util_linux.cc176
-rw-r--r--base/process_util_unittest.cc7
-rw-r--r--base/ref_counted.cc28
-rw-r--r--base/ref_counted.h17
-rw-r--r--base/scoped_temp_dir.h8
-rw-r--r--base/scoped_temp_dir_unittest.cc6
-rw-r--r--base/sha1_portable.cc7
-rw-r--r--base/shared_memory_posix.cc123
-rw-r--r--base/string_piece.h12
-rw-r--r--base/synchronization/condition_variable.h8
-rw-r--r--base/synchronization/condition_variable_unittest.cc52
-rw-r--r--base/synchronization/waitable_event.h4
-rw-r--r--base/synchronization/waitable_event_posix.cc11
-rw-r--r--base/sys_info_win.cc6
-rw-r--r--base/template_util.h43
-rw-r--r--base/template_util_unittest.cc66
-rw-r--r--base/test/test_suite.cc19
-rw-r--r--base/test/test_timeouts.cc2
-rw-r--r--base/third_party/dmg_fp/dtoa_wrapper.cc4
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.c145
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.h297
-rw-r--r--base/threading/simple_thread.cc32
-rw-r--r--base/threading/simple_thread.h4
-rw-r--r--base/threading/thread.cc46
-rw-r--r--base/threading/thread_checker.h4
-rw-r--r--base/threading/thread_collision_warner_unittest.cc24
-rw-r--r--base/threading/thread_local_storage_posix.cc5
-rw-r--r--base/threading/thread_local_storage_win.cc5
-rw-r--r--base/threading/worker_pool_posix_unittest.cc14
-rw-r--r--base/time.h8
-rw-r--r--base/time_posix.cc74
-rw-r--r--base/time_win.cc8
-rw-r--r--base/tracked_objects.cc37
-rw-r--r--base/tracked_objects.h8
-rw-r--r--base/tuple.h7
-rw-r--r--base/utf_string_conversions.cc18
-rw-r--r--base/utf_string_conversions.h20
-rw-r--r--base/values.cc60
-rw-r--r--base/values.h39
-rw-r--r--base/values_unittest.cc104
-rw-r--r--base/values_util.cc18
-rw-r--r--base/values_util.h26
-rw-r--r--base/vlog.cc30
-rw-r--r--base/vlog.h17
-rw-r--r--base/weak_ptr.cc4
-rw-r--r--base/win/registry.cc497
-rw-r--r--base/win/registry.h41
-rw-r--r--base/win/registry_unittest.cc71
-rw-r--r--base/win/win_util.cc7
155 files changed, 8039 insertions, 3077 deletions
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
index 64b1159..87b4127 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -248,7 +248,7 @@
],
'msvs_settings': {
# TODO(sgk): merge this with build/common.gypi settings
- 'VCLibrarianTool=': {
+ 'VCLibrarianTool': {
'AdditionalOptions': ['/ignore:4006,4221'],
'AdditionalLibraryDirectories':
['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
diff --git a/base/allocator/allocator_unittests.cc b/base/allocator/allocator_unittests.cc
index b1aa9cb..d935cf9 100644
--- a/base/allocator/allocator_unittests.cc
+++ b/base/allocator/allocator_unittests.cc
@@ -313,9 +313,9 @@ static void TestOneNewWithoutExceptions(void* (*func)(size_t),
try {
void* rv = (*func)(kTooBig);
EXPECT_EQ(NULL, rv);
- EXPECT_EQ(false, should_throw) << "allocation should have thrown.";
+ EXPECT_FALSE(should_throw) << "allocation should have thrown.";
} catch(...) {
- EXPECT_EQ(true, should_throw) << "allocation threw unexpected exception.";
+ EXPECT_TRUE(should_throw) << "allocation threw unexpected exception.";
}
}
@@ -359,7 +359,7 @@ TEST(Allocators, Malloc) {
unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
CheckAlignment(ptr, 2); // Should be 2 byte aligned
Fill(ptr, size);
- EXPECT_EQ(true, Valid(ptr, size));
+ EXPECT_TRUE(Valid(ptr, size));
free(ptr);
}
}
@@ -420,9 +420,9 @@ TEST(Allocators, Realloc2) {
Fill(src, src_size);
unsigned char* dst =
reinterpret_cast<unsigned char*>(realloc(src, dst_size));
- EXPECT_EQ(true, Valid(dst, min(src_size, dst_size)));
+ EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
Fill(dst, dst_size);
- EXPECT_EQ(true, Valid(dst, dst_size));
+ EXPECT_TRUE(Valid(dst, dst_size));
if (dst != NULL) free(dst);
}
}
@@ -468,13 +468,13 @@ TEST(Allocators, Recalloc) {
for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
unsigned char* src =
reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
- EXPECT_EQ(true, IsZeroed(src, src_size));
+ EXPECT_TRUE(IsZeroed(src, src_size));
Fill(src, src_size);
unsigned char* dst =
reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
- EXPECT_EQ(true, Valid(dst, min(src_size, dst_size)));
+ EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
Fill(dst, dst_size);
- EXPECT_EQ(true, Valid(dst, dst_size));
+ EXPECT_TRUE(Valid(dst, dst_size));
if (dst != NULL)
free(dst);
}
diff --git a/base/at_exit.cc b/base/at_exit.cc
index 9fdfd77..e6618a0 100644
--- a/base/at_exit.cc
+++ b/base/at_exit.cc
@@ -18,11 +18,6 @@ AtExitManager::AtExitManager() : next_manager_(NULL) {
g_top_manager = this;
}
-AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
- DCHECK(shadow || !g_top_manager);
- g_top_manager = this;
-}
-
AtExitManager::~AtExitManager() {
if (!g_top_manager) {
NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
@@ -64,4 +59,9 @@ void AtExitManager::ProcessCallbacksNow() {
}
}
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
+ DCHECK(shadow || !g_top_manager);
+ g_top_manager = this;
+}
+
} // namespace base
diff --git a/base/at_exit.h b/base/at_exit.h
index 35c96b9..15dcfc8 100644
--- a/base/at_exit.h
+++ b/base/at_exit.h
@@ -9,7 +9,7 @@
#include <stack>
#include "base/basictypes.h"
-#include "base/lock.h"
+#include "base/synchronization/lock.h"
namespace base {
@@ -60,7 +60,7 @@ class AtExitManager {
void* param_;
};
- Lock lock_;
+ base::Lock lock_;
std::stack<CallbackAndParam> stack_;
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
diff --git a/base/atomicops_internals_x86_macosx.h b/base/atomicops_internals_x86_macosx.h
index 5de7df3..29e58e3 100644
--- a/base/atomicops_internals_x86_macosx.h
+++ b/base/atomicops_internals_x86_macosx.h
@@ -110,7 +110,7 @@ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 prev_value;
do {
if (OSAtomicCompareAndSwap64(old_value, new_value,
- const_cast<Atomic64*>(ptr))) {
+ reinterpret_cast<volatile int64_t*>(ptr))) {
return old_value;
}
prev_value = *ptr;
@@ -124,18 +124,19 @@ inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
do {
old_value = *ptr;
} while (!OSAtomicCompareAndSwap64(old_value, new_value,
- const_cast<Atomic64*>(ptr)));
+ reinterpret_cast<volatile int64_t*>(ptr)));
return old_value;
}
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
Atomic64 increment) {
- return OSAtomicAdd64(increment, const_cast<Atomic64*>(ptr));
+ return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
}
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
Atomic64 increment) {
- return OSAtomicAdd64Barrier(increment, const_cast<Atomic64*>(ptr));
+ return OSAtomicAdd64Barrier(increment,
+ reinterpret_cast<volatile int64_t*>(ptr));
}
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
@@ -143,8 +144,8 @@ inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 new_value) {
Atomic64 prev_value;
do {
- if (OSAtomicCompareAndSwap64Barrier(old_value, new_value,
- const_cast<Atomic64*>(ptr))) {
+ if (OSAtomicCompareAndSwap64Barrier(
+ old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
return old_value;
}
prev_value = *ptr;
@@ -193,12 +194,11 @@ inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
// MacOS uses long for intptr_t, AtomicWord and Atomic32 are always different
// on the Mac, even when they are the same size. We need to explicitly cast
-// from AtomicWord to Atomic32/64 to implement the AtomicWord interface.
-#ifdef __LP64__
-#define AtomicWordCastType Atomic64
-#else
+// from AtomicWord to Atomic32 to implement the AtomicWord interface.
+// When in 64-bit mode, AtomicWord is the same as Atomic64, so we need not
+// add duplicate definitions.
+#ifndef __LP64__
#define AtomicWordCastType Atomic32
-#endif
inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
AtomicWord old_value,
@@ -273,6 +273,7 @@ inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
}
#undef AtomicWordCastType
+#endif
} // namespace base::subtle
} // namespace base
diff --git a/base/base.gyp b/base/base.gyp
index 6dc450c..868569e 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -31,6 +31,8 @@
'base',
],
'sources': [
+ 'i18n/bidi_line_iterator.cc',
+ 'i18n/bidi_line_iterator.h',
'i18n/break_iterator.cc',
'i18n/break_iterator.h',
'i18n/char_iterator.cc',
@@ -63,12 +65,14 @@
'at_exit_unittest.cc',
'atomicops_unittest.cc',
'base64_unittest.cc',
+ 'bind_unittest.cc',
'bits_unittest.cc',
'callback_unittest.cc',
'command_line_unittest.cc',
'crypto/encryptor_unittest.cc',
'crypto/rsa_private_key_unittest.cc',
'crypto/rsa_private_key_nss_unittest.cc',
+ 'crypto/secure_hash_unittest.cc',
'crypto/signature_creator_unittest.cc',
'crypto/signature_verifier_unittest.cc',
'crypto/symmetric_key_unittest.cc',
@@ -139,6 +143,7 @@
'sys_string_conversions_unittest.cc',
'task_queue_unittest.cc',
'task_unittest.cc',
+ 'template_util_unittest.cc',
'threading/non_thread_safe_unittest.cc',
'threading/platform_thread_unittest.cc',
'threading/simple_thread_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index f241967..7a5da2e 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -36,9 +36,14 @@
'base_switches.cc',
'base_switches.h',
'basictypes.h',
+ 'bind.h',
+ 'bind_helpers.h',
+ 'bind_internal.h',
'bits.h',
'bzip2_error_handler.cc',
'callback.h',
+ 'callback_helpers.h',
+ 'callback_old.h',
'command_line.cc',
'command_line.h',
'compiler_specific.h',
@@ -52,6 +57,8 @@
'debug/debugger_win.cc',
'debug/leak_annotations.h',
'debug/leak_tracker.h',
+ 'debug/profiler.cc',
+ 'debug/profiler.h',
'debug/stack_trace.cc',
'debug/stack_trace.h',
'debug/stack_trace_posix.cc',
@@ -98,11 +105,12 @@
'lazy_instance.h',
'linked_list.h',
'linked_ptr.h',
- 'lock.h',
'logging.cc',
'logging.h',
'logging_win.cc',
'mac/cocoa_protocols.h',
+ 'mac/foundation_util.h',
+ 'mac/foundation_util.mm',
'mac/mac_util.h',
'mac/mac_util.mm',
'mac/os_crash_dumps.cc',
@@ -287,8 +295,6 @@
'utf_string_conversions.h',
'values.cc',
'values.h',
- 'values_util.cc',
- 'values_util.h',
'version.cc',
'version.h',
'vlog.cc',
@@ -526,6 +532,7 @@
'sources!': [
'crypto/encryptor_nss.cc',
'crypto/rsa_private_key_nss.cc',
+ 'crypto/secure_hash_default.cc',
'crypto/signature_creator_nss.cc',
'crypto/signature_verifier_nss.cc',
'crypto/symmetric_key_nss.cc',
@@ -545,6 +552,7 @@
'sources!': [
'crypto/encryptor_openssl.cc',
'crypto/rsa_private_key_openssl.cc',
+ 'crypto/secure_hash_openssl.cc',
'crypto/signature_creator_openssl.cc',
'crypto/signature_verifier_openssl.cc',
'crypto/symmetric_key_openssl.cc',
@@ -558,6 +566,7 @@
'sources': [
'crypto/capi_util.cc',
'crypto/capi_util.h',
+ 'crypto/crypto_module_blocking_password_delegate.h',
'crypto/cssm_init.cc',
'crypto/cssm_init.h',
'crypto/encryptor.h',
@@ -571,6 +580,9 @@
'crypto/rsa_private_key_nss.cc',
'crypto/rsa_private_key_openssl.cc',
'crypto/rsa_private_key_win.cc',
+ 'crypto/secure_hash.h',
+ 'crypto/secure_hash_default.cc',
+ 'crypto/secure_hash_openssl.cc',
'crypto/signature_creator.h',
'crypto/signature_creator_mac.cc',
'crypto/signature_creator_nss.cc',
diff --git a/base/base_paths_linux.cc b/base/base_paths_linux.cc
index 48db3f8..ca8c757 100644
--- a/base/base_paths_linux.cc
+++ b/base/base_paths_linux.cc
@@ -83,10 +83,10 @@ bool PathProviderPosix(int key, FilePath* result) {
}
}
// In a case of WebKit-only checkout, executable files are put into
- // WebKit/out/{Debug|Release}, and we should return WebKit/WebKit/chromium
- // for DIR_SOURCE_ROOT.
+ // <root of checkout>/out/{Debug|Release}, and we should return
+ // <root of checkout>/Source/WebKit/chromium for DIR_SOURCE_ROOT.
if (PathService::Get(base::DIR_EXE, &path)) {
- path = path.DirName().DirName().Append("WebKit/chromium");
+ path = path.DirName().DirName().Append("Source/WebKit/chromium");
if (file_util::PathExists(path.Append(kThisSourceFile))) {
*result = path;
return true;
diff --git a/base/base_switches.cc b/base/base_switches.cc
index a1d688a..78f55a7 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -24,8 +24,8 @@ const char kFullMemoryCrashReport[] = "full-memory-crash-report";
// Suppresses all error dialogs when present.
const char kNoErrorDialogs[] = "noerrdialogs";
-// Disable app::win::MessageBox. This is useful when running as part of
-// scripts that do not have a user interface.
+// Disable ui::MessageBox. This is useful when running as part of scripts that
+// do not have a user interface.
const char kNoMessageBox[] = "no-message-box";
// When running certain tests that spawn child processes, this switch indicates
diff --git a/base/bind.h b/base/bind.h
new file mode 100644
index 0000000..c23af2e
--- /dev/null
+++ b/base/bind.h
@@ -0,0 +1,99 @@
+// This file was GENERATED by command:
+// pump.py bind.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 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.
+
+#ifndef BASE_BIND_H_
+#define BASE_BIND_H_
+#pragma once
+
+#include "base/bind_internal.h"
+#include "base/callback_helpers.h"
+
+// See base/callback.h for how to use these functions.
+//
+// IMPLEMENTATION NOTE
+// Though Bind()'s result is meant to be stored in a Callback<> type, it
+// cannot actually return the exact type without requiring a large amount
+// of extra template specializations. The problem is that in order to
+// discern the correct specialization of Callback<>, Bind would need to
+// unwrap the function signature to determine the signature's arity, and
+// whether or not it is a method.
+//
+// Each unique combination of (arity, function_type, num_prebound) where
+// function_type is one of {function, method, const_method} would require
+// one specialization. We eventually have to do a similar number of
+// specializations anyways in the implementation (see the FunctionTraitsN,
+// classes). However, it is avoidable in Bind if we return the result
+// via an indirection like we do below.
+
+namespace base {
+
+template <typename Sig>
+internal::InvokerStorageHolder<internal::InvokerStorage0<Sig> >
+Bind(Sig f) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage0<Sig>(f));
+}
+
+template <typename Sig, typename P1>
+internal::InvokerStorageHolder<internal::InvokerStorage1<Sig,P1> >
+Bind(Sig f, const P1& p1) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage1<Sig, P1>(
+ f, p1));
+}
+
+template <typename Sig, typename P1, typename P2>
+internal::InvokerStorageHolder<internal::InvokerStorage2<Sig,P1, P2> >
+Bind(Sig f, const P1& p1, const P2& p2) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage2<Sig, P1, P2>(
+ f, p1, p2));
+}
+
+template <typename Sig, typename P1, typename P2, typename P3>
+internal::InvokerStorageHolder<internal::InvokerStorage3<Sig,P1, P2, P3> >
+Bind(Sig f, const P1& p1, const P2& p2, const P3& p3) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage3<Sig, P1, P2, P3>(
+ f, p1, p2, p3));
+}
+
+template <typename Sig, typename P1, typename P2, typename P3, typename P4>
+internal::InvokerStorageHolder<internal::InvokerStorage4<Sig,P1, P2, P3, P4> >
+Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage4<Sig, P1, P2, P3, P4>(
+ f, p1, p2, p3, p4));
+}
+
+template <typename Sig, typename P1, typename P2, typename P3, typename P4,
+ typename P5>
+internal::InvokerStorageHolder<internal::InvokerStorage5<Sig,P1, P2, P3, P4,
+ P5> >
+Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+ const P5& p5) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage5<Sig, P1, P2, P3, P4, P5>(
+ f, p1, p2, p3, p4, p5));
+}
+
+template <typename Sig, typename P1, typename P2, typename P3, typename P4,
+ typename P5, typename P6>
+internal::InvokerStorageHolder<internal::InvokerStorage6<Sig,P1, P2, P3, P4,
+ P5, P6> >
+Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
+ const P5& p5, const P6& p6) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage6<Sig, P1, P2, P3, P4, P5, P6>(
+ f, p1, p2, p3, p4, p5, p6));
+}
+
+} // namespace base
+
+#endif // BASE_BIND_H_
diff --git a/base/bind.h.pump b/base/bind.h.pump
new file mode 100644
index 0000000..fc7f246
--- /dev/null
+++ b/base/bind.h.pump
@@ -0,0 +1,71 @@
+$$ This is a pump file for generating file templates. Pump is a python
+$$ script that is part of the Google Test suite of utilities. Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$var MAX_ARITY = 6
+
+// Copyright (c) 2011 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.
+
+#ifndef BASE_BIND_H_
+#define BASE_BIND_H_
+#pragma once
+
+#include "base/bind_internal.h"
+#include "base/callback_helpers.h"
+
+// See base/callback.h for how to use these functions.
+//
+// IMPLEMENTATION NOTE
+// Though Bind()'s result is meant to be stored in a Callback<> type, it
+// cannot actually return the exact type without requiring a large amount
+// of extra template specializations. The problem is that in order to
+// discern the correct specialization of Callback<>, Bind would need to
+// unwrap the function signature to determine the signature's arity, and
+// whether or not it is a method.
+//
+// Each unique combination of (arity, function_type, num_prebound) where
+// function_type is one of {function, method, const_method} would require
+// one specialization. We eventually have to do a similar number of
+// specializations anyways in the implementation (see the FunctionTraitsN,
+// classes). However, it is avoidable in Bind if we return the result
+// via an indirection like we do below.
+
+namespace base {
+
+$range BOUND 0..MAX_ARITY
+$for BOUND [[
+$range BOUND_ARG 1..BOUND
+
+$if BOUND == 0 [[
+
+template <typename Sig>
+internal::InvokerStorageHolder<internal::InvokerStorage0<Sig> >
+Bind(Sig f) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage0<Sig>(f));
+}
+
+]] $else [[
+
+template <typename Sig, $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
+internal::InvokerStorageHolder<internal::InvokerStorage$(BOUND)<Sig,
+$for BOUND_ARG , [[P$(BOUND_ARG)]]> >
+Bind(Sig f, $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) {
+ return internal::MakeInvokerStorageHolder(
+ new internal::InvokerStorage$(BOUND)<Sig, [[]]
+$for BOUND_ARG , [[P$(BOUND_ARG)]]>(
+ f, $for BOUND_ARG , [[p$(BOUND_ARG)]]));
+}
+
+]]
+
+]] $$ for BOUND
+
+} // namespace base
+
+#endif // BASE_BIND_H_
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
new file mode 100644
index 0000000..c1ca3d7
--- /dev/null
+++ b/base/bind_helpers.h
@@ -0,0 +1,287 @@
+// Copyright (c) 2011 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.
+
+// This defines a set of argument wrappers and related factory methods that
+// can be used specify the refcounting and reference semantics of arguments
+// that are bound by the Bind() function in base/bind.h.
+//
+// The public functions are base::Unretained() and base::ConstRef().
+// Unretained() allows Bind() to bind a non-refcounted class.
+// ConstRef() allows binding a constant reference to an argument rather
+// than a copy.
+//
+//
+// EXAMPLE OF Unretained():
+//
+// class Foo {
+// public:
+// void func() { cout << "Foo:f" << endl;
+// };
+//
+// // In some function somewhere.
+// Foo foo;
+// Callback<void(void)> foo_callback =
+// Bind(&Foo::func, Unretained(&foo));
+// foo_callback.Run(); // Prints "Foo:f".
+//
+// Without the Unretained() wrapper on |&foo|, the above call would fail
+// to compile because Foo does not support the AddRef() and Release() methods.
+//
+//
+// EXAMPLE OF ConstRef();
+// void foo(int arg) { cout << arg << endl }
+//
+// int n = 1;
+// Callback<void(void)> no_ref = Bind(&foo, n);
+// Callback<void(void)> has_ref = Bind(&foo, ConstRef(n));
+//
+// no_ref.Run(); // Prints "1"
+// has_ref.Run(); // Prints "1"
+//
+// n = 2;
+// no_ref.Run(); // Prints "1"
+// has_ref.Run(); // Prints "2"
+//
+// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
+// its bound callbacks.
+//
+
+#ifndef BASE_BIND_HELPERS_H_
+#define BASE_BIND_HELPERS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
+// for the existence of AddRef() and Release() functions of the correct
+// signature.
+//
+// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
+// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
+// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
+//
+// The last link in particular show the method used below.
+//
+// For SFINAE to work with inherited methods, we need to pull some extra tricks
+// with multiple inheritance. In the more standard formulation, the overloads
+// of Check would be:
+//
+// template <typename C>
+// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
+//
+// template <typename C>
+// No NotTheCheckWeWant(...);
+//
+// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
+//
+// The problem here is that template resolution will not match
+// C::TargetFunc if TargetFunc does not exist directly in C. That is, if
+// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
+// |value| will be false. This formulation only checks for whether or
+// not TargetFunc exist directly in the class being introspected.
+//
+// To get around this, we play a dirty trick with multiple inheritance.
+// First, We create a class BaseMixin that declares each function that we
+// want to probe for. Then we create a class Base that inherits from both T
+// (the class we wish to probe) and BaseMixin. Note that the function
+// signature in BaseMixin does not need to match the signature of the function
+// we are probing for; thus it's easiest to just use void(void).
+//
+// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
+// ambiguous resolution between BaseMixin and T. This lets us write the
+// following:
+//
+// template <typename C>
+// No GoodCheck(Helper<&C::TargetFunc>*);
+//
+// template <typename C>
+// Yes GoodCheck(...);
+//
+// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
+//
+// Notice here that the variadic version of GoodCheck() returns Yes here
+// instead of No like the previous one. Also notice that we calculate |value|
+// by specializing GoodCheck() on Base instead of T.
+//
+// We've reversed the roles of the variadic, and Helper overloads.
+// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
+// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
+// to the variadic version if T has TargetFunc. If T::TargetFunc does not
+// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
+// will prefer GoodCheck(Helper<&C::TargetFunc>*).
+//
+// This method of SFINAE will correctly probe for inherited names, but it cannot
+// typecheck those names. It's still a good enough sanity check though.
+//
+// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
+//
+// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
+// this works well.
+template <typename T>
+class SupportsAddRefAndRelease {
+ typedef char Yes[1];
+ typedef char No[2];
+
+ struct BaseMixin {
+ void AddRef();
+ void Release();
+ };
+
+ struct Base : public T, public BaseMixin {
+ };
+
+ template <void(BaseMixin::*)(void)> struct Helper {};
+
+ template <typename C>
+ static No& Check(Helper<&C::AddRef>*, Helper<&C::Release>*);
+
+ template <typename >
+ static Yes& Check(...);
+
+ public:
+ static const bool value = sizeof(Check<Base>(0,0)) == sizeof(Yes);
+};
+
+
+// Helpers to assert that arguments of a recounted type are bound with a
+// scoped_refptr.
+template <bool IsClasstype, typename T>
+struct UnsafeBindtoRefCountedArgHelper : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArgHelper<true, T>
+ : integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg
+ : UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
+};
+
+
+template <typename T>
+class UnretainedWrapper {
+ public:
+ explicit UnretainedWrapper(T* o) : obj_(o) {}
+ T* get() { return obj_; }
+ private:
+ T* obj_;
+};
+
+template <typename T>
+class ConstRefWrapper {
+ public:
+ explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
+ const T& get() { return *ptr_; }
+ private:
+ const T* ptr_;
+};
+
+
+// Unwrap the stored parameters for the wrappers above.
+template <typename T>
+T Unwrap(T o) { return o; }
+
+template <typename T>
+T* Unwrap(UnretainedWrapper<T> unretained) { return unretained.get(); }
+
+template <typename T>
+const T& Unwrap(ConstRefWrapper<T> const_ref) {
+ return const_ref.get();
+}
+
+
+// Utility for handling different refcounting semantics in the Bind()
+// function.
+template <typename ref, typename T>
+struct MaybeRefcount;
+
+template <typename T>
+struct MaybeRefcount<base::false_type, T> {
+ static void AddRef(const T&) {}
+ static void Release(const T&) {}
+};
+
+template <typename T, size_t n>
+struct MaybeRefcount<base::false_type, T[n]> {
+ static void AddRef(const T*) {}
+ static void Release(const T*) {}
+};
+
+template <typename T>
+struct MaybeRefcount<base::true_type, UnretainedWrapper<T> > {
+ static void AddRef(const UnretainedWrapper<T>&) {}
+ static void Release(const UnretainedWrapper<T>&) {}
+};
+
+template <typename T>
+struct MaybeRefcount<base::true_type, T*> {
+ static void AddRef(T* o) { o->AddRef(); }
+ static void Release(T* o) { o->Release(); }
+};
+
+template <typename T>
+struct MaybeRefcount<base::true_type, const T*> {
+ static void AddRef(const T* o) { o->AddRef(); }
+ static void Release(const T* o) { o->Release(); }
+};
+
+
+// This is a typetraits object that's used to convert an argument type into a
+// type suitable for storage. In particular, it strips off references, and
+// converts arrays to pointers.
+//
+// This array type becomes an issue because we are passing bound parameters by
+// const reference. In this case, we end up passing an actual array type in the
+// initializer list which C++ does not allow. This will break passing of
+// C-string literals.
+template <typename T>
+struct BindType {
+ typedef T StorageType;
+};
+
+// This should almost be impossible to trigger unless someone manually
+// specifies type of the bind parameters. However, in case they do,
+// this will guard against us accidentally storing a reference parameter.
+template <typename T>
+struct BindType<T&> {
+ typedef T StorageType;
+};
+
+// Note that for array types, we implicitly add a const in the conversion. This
+// means that it is not possible to bind array arguments to functions that take
+// a non-const pointer. Trying to specialize the template based on a "const
+// T[n]" does not seem to match correctly, so we are stuck with this
+// restriction.
+template <typename T, size_t n>
+struct BindType<T[n]> {
+ typedef const T* StorageType;
+};
+
+template <typename T>
+struct BindType<T[]> {
+ typedef const T* StorageType;
+};
+
+} // namespace internal
+
+template <typename T>
+inline internal::UnretainedWrapper<T> Unretained(T* o) {
+ return internal::UnretainedWrapper<T>(o);
+}
+
+template <typename T>
+inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
+ return internal::ConstRefWrapper<T>(o);
+}
+
+} // namespace base
+
+#endif // BASE_BIND_HELPERS_H_
diff --git a/base/bind_internal.h b/base/bind_internal.h
new file mode 100644
index 0000000..62f2050
--- /dev/null
+++ b/base/bind_internal.h
@@ -0,0 +1,1670 @@
+// This file was GENERATED by command:
+// pump.py bind_internal.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 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.
+
+#ifndef BASE_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+#pragma once
+
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// The method by which a function is invoked is determined by 3 different
+// dimensions:
+//
+// 1) The type of function (normal, method, const-method)
+// 2) The arity of the function
+// 3) The number of bound parameters.
+//
+// The FunctionTraitsN classes unwrap the function signature type to
+// specialize based on the first two dimensions. The N in FunctionTraitsN
+// specifies the 3rd dimension. We could have specified the unbound parameters
+// via template parameters, but this method looked cleaner.
+//
+// The FunctionTraitsN contains a static DoInvoke() function that is the key to
+// implementing type erasure in the Callback() classes. DoInvoke() is a static
+// function with a fixed signature that is independent of StorageType; its
+// first argument is a pointer to the non-templated common baseclass of
+// StorageType. This lets us store pointer to DoInvoke() in a function pointer
+// that has knowledge of the specific StorageType, and thus no knowledge of the
+// bound function and bound parameter types.
+//
+// As long as we ensure that DoInvoke() is only used with pointers there were
+// upcasted from the correct StorageType, we can be sure that execution is
+// safe.
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits0;
+
+// Function: Arity 0 -> 0.
+template <typename StorageType, typename R>
+struct FunctionTraits0<StorageType, R(*)()> {
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_();
+ }
+};
+
+// Function: Arity 1 -> 1.
+template <typename StorageType, typename R,typename X1>
+struct FunctionTraits0<StorageType, R(*)(X1)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(x1);
+ }
+};
+
+// Function: Arity 2 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2>
+struct FunctionTraits0<StorageType, R(*)(X1, X2)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(x1, x2);
+ }
+};
+
+// Function: Arity 3 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3>
+struct FunctionTraits0<StorageType, R(*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(x1, x2, x3);
+ }
+};
+
+// Function: Arity 4 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4>
+struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(x1, x2, x3, x4);
+ }
+};
+
+// Function: Arity 5 -> 5.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5>
+struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(x1, x2, x3, x4, x5);
+ }
+};
+
+// Function: Arity 6 -> 6.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4, const X5& x5, const X6& x6) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(x1, x2, x3, x4, x5, x6);
+ }
+};
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits1;
+
+// Function: Arity 1 -> 0.
+template <typename StorageType, typename R,typename X1>
+struct FunctionTraits1<StorageType, R(*)(X1)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_));
+ }
+};
+
+// Method: Arity 0 -> 0.
+template <typename StorageType, typename R, typename T>
+struct FunctionTraits1<StorageType, R(T::*)()> {
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)();
+ }
+};
+
+// Const Method: Arity 0 -> 0.
+template <typename StorageType, typename R, typename T>
+struct FunctionTraits1<StorageType, R(T::*)() const> {
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base ) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)();
+ }
+};
+
+// Function: Arity 2 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2>
+struct FunctionTraits1<StorageType, R(*)(X1, X2)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), x2);
+ }
+};
+
+// Method: Arity 1 -> 1.
+template <typename StorageType, typename R, typename T, typename X1>
+struct FunctionTraits1<StorageType, R(T::*)(X1)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1);
+ }
+};
+
+// Const Method: Arity 1 -> 1.
+template <typename StorageType, typename R, typename T, typename X1>
+struct FunctionTraits1<StorageType, R(T::*)(X1) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1);
+ }
+};
+
+// Function: Arity 3 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3>
+struct FunctionTraits1<StorageType, R(*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), x2, x3);
+ }
+};
+
+// Method: Arity 2 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2);
+ }
+};
+
+// Const Method: Arity 2 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2);
+ }
+};
+
+// Function: Arity 4 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4>
+struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), x2, x3, x4);
+ }
+};
+
+// Method: Arity 3 -> 3.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3);
+ }
+};
+
+// Const Method: Arity 3 -> 3.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3);
+ }
+};
+
+// Function: Arity 5 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5>
+struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), x2, x3, x4, x5);
+ }
+};
+
+// Method: Arity 4 -> 4.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4);
+ }
+};
+
+// Const Method: Arity 4 -> 4.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4);
+ }
+};
+
+// Function: Arity 6 -> 5.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4, const X5& x5, const X6& x6) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), x2, x3, x4, x5, x6);
+ }
+};
+
+// Method: Arity 5 -> 5.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4, x5);
+ }
+};
+
+// Const Method: Arity 5 -> 5.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
+ const X3& x3, const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4, x5);
+ }
+};
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits2;
+
+// Function: Arity 2 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2>
+struct FunctionTraits2<StorageType, R(*)(X1, X2)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_));
+ }
+};
+
+// Method: Arity 1 -> 0.
+template <typename StorageType, typename R, typename T, typename X1>
+struct FunctionTraits2<StorageType, R(T::*)(X1)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_));
+ }
+};
+
+// Const Method: Arity 1 -> 0.
+template <typename StorageType, typename R, typename T, typename X1>
+struct FunctionTraits2<StorageType, R(T::*)(X1) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base ) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_));
+ }
+};
+
+// Function: Arity 3 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3>
+struct FunctionTraits2<StorageType, R(*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3);
+ }
+};
+
+// Method: Arity 2 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2);
+ }
+};
+
+// Const Method: Arity 2 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2);
+ }
+};
+
+// Function: Arity 4 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4>
+struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3, x4);
+ }
+};
+
+// Method: Arity 3 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3);
+ }
+};
+
+// Const Method: Arity 3 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3);
+ }
+};
+
+// Function: Arity 5 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5>
+struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
+ const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3, x4, x5);
+ }
+};
+
+// Method: Arity 4 -> 3.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3,
+ x4);
+ }
+};
+
+// Const Method: Arity 4 -> 3.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3,
+ x4);
+ }
+};
+
+// Function: Arity 6 -> 4.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
+ const X5& x5, const X6& x6) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3, x4, x5,
+ x6);
+ }
+};
+
+// Method: Arity 5 -> 4.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3,
+ x4, x5);
+ }
+};
+
+// Const Method: Arity 5 -> 4.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
+ const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3,
+ x4, x5);
+ }
+};
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits3;
+
+// Function: Arity 3 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3>
+struct FunctionTraits3<StorageType, R(*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_));
+ }
+};
+
+// Method: Arity 2 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_));
+ }
+};
+
+// Const Method: Arity 2 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base ) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_));
+ }
+};
+
+// Function: Arity 4 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4>
+struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x4);
+ }
+};
+
+// Method: Arity 3 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x3);
+ }
+};
+
+// Const Method: Arity 3 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x3);
+ }
+};
+
+// Function: Arity 5 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5>
+struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x4, x5);
+ }
+};
+
+// Method: Arity 4 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x3, x4);
+ }
+};
+
+// Const Method: Arity 4 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x3, x4);
+ }
+};
+
+// Function: Arity 6 -> 3.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5,
+ const X6& x6) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x4, x5, x6);
+ }
+};
+
+// Method: Arity 5 -> 3.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
+ const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x3, x4, x5);
+ }
+};
+
+// Const Method: Arity 5 -> 3.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
+ const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), x3, x4, x5);
+ }
+};
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits4;
+
+// Function: Arity 4 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4>
+struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_));
+ }
+};
+
+// Method: Arity 3 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_));
+ }
+};
+
+// Const Method: Arity 3 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3>
+struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base ) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_));
+ }
+};
+
+// Function: Arity 5 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5>
+struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), x5);
+ }
+};
+
+// Method: Arity 4 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4);
+ }
+};
+
+// Const Method: Arity 4 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4);
+ }
+};
+
+// Function: Arity 6 -> 2.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X5& x5, const X6& x6) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), x5, x6);
+ }
+};
+
+// Method: Arity 5 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4, x5);
+ }
+};
+
+// Const Method: Arity 5 -> 2.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4, x5);
+ }
+};
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits5;
+
+// Function: Arity 5 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5>
+struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_));
+ }
+};
+
+// Method: Arity 4 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_));
+ }
+};
+
+// Const Method: Arity 4 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4>
+struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base ) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_));
+ }
+};
+
+// Function: Arity 6 -> 1.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X6& x6) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), x6);
+ }
+};
+
+// Method: Arity 5 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), x5);
+ }
+};
+
+// Const Method: Arity 5 -> 1.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base, const X5& x5) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), x5);
+ }
+};
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits6;
+
+// Function: Arity 6 -> 0.
+template <typename StorageType, typename R,typename X1, typename X2,
+ typename X3, typename X4, typename X5, typename X6>
+struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ||
+ is_non_const_reference<X6>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_),
+ Unwrap(invoker->p6_));
+ }
+};
+
+// Method: Arity 5 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+ COMPILE_ASSERT(
+ !( is_non_const_reference<X1>::value ||
+ is_non_const_reference<X2>::value ||
+ is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_),
+ Unwrap(invoker->p6_));
+ }
+};
+
+// Const Method: Arity 5 -> 0.
+template <typename StorageType, typename R, typename T, typename X1,
+ typename X2, typename X3, typename X4, typename X5>
+struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
+ COMPILE_ASSERT(
+ !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
+ || is_non_const_reference<X3>::value ||
+ is_non_const_reference<X4>::value ||
+ is_non_const_reference<X5>::value ),
+ do_not_bind_functions_with_nonconst_ref);
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base ) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
+ Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_),
+ Unwrap(invoker->p6_));
+ }
+};
+
+
+// These are the actual storage classes for the invokers.
+//
+// Though these types are "classes", they are being used as structs with
+// all member variable public. We cannot make it a struct because it inherits
+// from a class which causes a compiler warning. We cannot add a "Run()" method
+// that forwards the unbound arguments because that would require we unwrap the
+// Sig type like in FunctionTraitsN above to know the return type, and the arity
+// of Run().
+//
+// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN,
+// but the generated code seemed harder to read.
+
+template <typename Sig>
+class InvokerStorage0 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage0 StorageType;
+ typedef FunctionTraits0<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+
+
+ InvokerStorage0(Sig f)
+ : f_(f) {
+ }
+
+ virtual ~InvokerStorage0() { }
+
+ Sig f_;
+};
+
+template <typename Sig, typename P1>
+class InvokerStorage1 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage1 StorageType;
+ typedef FunctionTraits1<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P1>::value,
+ p1_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value,
+ first_bound_argument_to_method_cannot_be_array);
+
+
+ InvokerStorage1(Sig f, const P1& p1)
+ : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)) {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+ }
+
+ virtual ~InvokerStorage1() {
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+ }
+
+ Sig f_;
+ typename BindType<P1>::StorageType p1_;
+};
+
+template <typename Sig, typename P1, typename P2>
+class InvokerStorage2 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage2 StorageType;
+ typedef FunctionTraits2<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P1>::value,
+ p1_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value,
+ first_bound_argument_to_method_cannot_be_array);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value,
+ p2_is_refcounted_type_and_needs_scoped_refptr);
+
+
+ InvokerStorage2(Sig f, const P1& p1, const P2& p2)
+ : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)),
+ p2_(static_cast<typename BindType<P2>::StorageType>(p2)) {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+ }
+
+ virtual ~InvokerStorage2() {
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+ }
+
+ Sig f_;
+ typename BindType<P1>::StorageType p1_;
+ typename BindType<P2>::StorageType p2_;
+};
+
+template <typename Sig, typename P1, typename P2, typename P3>
+class InvokerStorage3 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage3 StorageType;
+ typedef FunctionTraits3<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P1>::value,
+ p1_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value,
+ first_bound_argument_to_method_cannot_be_array);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value,
+ p2_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value,
+ p3_is_refcounted_type_and_needs_scoped_refptr);
+
+
+ InvokerStorage3(Sig f, const P1& p1, const P2& p2, const P3& p3)
+ : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)),
+ p2_(static_cast<typename BindType<P2>::StorageType>(p2)),
+ p3_(static_cast<typename BindType<P3>::StorageType>(p3)) {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+ }
+
+ virtual ~InvokerStorage3() {
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+ }
+
+ Sig f_;
+ typename BindType<P1>::StorageType p1_;
+ typename BindType<P2>::StorageType p2_;
+ typename BindType<P3>::StorageType p3_;
+};
+
+template <typename Sig, typename P1, typename P2, typename P3, typename P4>
+class InvokerStorage4 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage4 StorageType;
+ typedef FunctionTraits4<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P1>::value,
+ p1_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value,
+ first_bound_argument_to_method_cannot_be_array);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value,
+ p2_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value,
+ p3_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P4>::value,
+ p4_is_refcounted_type_and_needs_scoped_refptr);
+
+
+ InvokerStorage4(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4)
+ : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)),
+ p2_(static_cast<typename BindType<P2>::StorageType>(p2)),
+ p3_(static_cast<typename BindType<P3>::StorageType>(p3)),
+ p4_(static_cast<typename BindType<P4>::StorageType>(p4)) {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+ }
+
+ virtual ~InvokerStorage4() {
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+ }
+
+ Sig f_;
+ typename BindType<P1>::StorageType p1_;
+ typename BindType<P2>::StorageType p2_;
+ typename BindType<P3>::StorageType p3_;
+ typename BindType<P4>::StorageType p4_;
+};
+
+template <typename Sig, typename P1, typename P2, typename P3, typename P4,
+ typename P5>
+class InvokerStorage5 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage5 StorageType;
+ typedef FunctionTraits5<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P1>::value,
+ p1_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value,
+ first_bound_argument_to_method_cannot_be_array);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value,
+ p2_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value,
+ p3_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P4>::value,
+ p4_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P5>::value,
+ p5_is_refcounted_type_and_needs_scoped_refptr);
+
+
+ InvokerStorage5(Sig f, const P1& p1, const P2& p2, const P3& p3,
+ const P4& p4, const P5& p5)
+ : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)),
+ p2_(static_cast<typename BindType<P2>::StorageType>(p2)),
+ p3_(static_cast<typename BindType<P3>::StorageType>(p3)),
+ p4_(static_cast<typename BindType<P4>::StorageType>(p4)),
+ p5_(static_cast<typename BindType<P5>::StorageType>(p5)) {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+ }
+
+ virtual ~InvokerStorage5() {
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+ }
+
+ Sig f_;
+ typename BindType<P1>::StorageType p1_;
+ typename BindType<P2>::StorageType p2_;
+ typename BindType<P3>::StorageType p3_;
+ typename BindType<P4>::StorageType p4_;
+ typename BindType<P5>::StorageType p5_;
+};
+
+template <typename Sig, typename P1, typename P2, typename P3, typename P4,
+ typename P5, typename P6>
+class InvokerStorage6 : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage6 StorageType;
+ typedef FunctionTraits6<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P1>::value,
+ p1_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value,
+ first_bound_argument_to_method_cannot_be_array);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value,
+ p2_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value,
+ p3_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P4>::value,
+ p4_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P5>::value,
+ p5_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P6>::value,
+ p6_is_refcounted_type_and_needs_scoped_refptr);
+
+
+ InvokerStorage6(Sig f, const P1& p1, const P2& p2, const P3& p3,
+ const P4& p4, const P5& p5, const P6& p6)
+ : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)),
+ p2_(static_cast<typename BindType<P2>::StorageType>(p2)),
+ p3_(static_cast<typename BindType<P3>::StorageType>(p3)),
+ p4_(static_cast<typename BindType<P4>::StorageType>(p4)),
+ p5_(static_cast<typename BindType<P5>::StorageType>(p5)),
+ p6_(static_cast<typename BindType<P6>::StorageType>(p6)) {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+ }
+
+ virtual ~InvokerStorage6() {
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+ }
+
+ Sig f_;
+ typename BindType<P1>::StorageType p1_;
+ typename BindType<P2>::StorageType p2_;
+ typename BindType<P3>::StorageType p3_;
+ typename BindType<P4>::StorageType p4_;
+ typename BindType<P5>::StorageType p5_;
+ typename BindType<P6>::StorageType p6_;
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_BIND_INTERNAL_H_
diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump
new file mode 100644
index 0000000..132b0db
--- /dev/null
+++ b/base/bind_internal.h.pump
@@ -0,0 +1,237 @@
+$$ This is a pump file for generating file templates. Pump is a python
+$$ script that is part of the Google Test suite of utilities. Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$var MAX_ARITY = 6
+
+// Copyright (c) 2011 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.
+
+#ifndef BASE_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+#pragma once
+
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// The method by which a function is invoked is determined by 3 different
+// dimensions:
+//
+// 1) The type of function (normal, method, const-method)
+// 2) The arity of the function
+// 3) The number of bound parameters.
+//
+// The FunctionTraitsN classes unwrap the function signature type to
+// specialize based on the first two dimensions. The N in FunctionTraitsN
+// specifies the 3rd dimension. We could have specified the unbound parameters
+// via template parameters, but this method looked cleaner.
+//
+// The FunctionTraitsN contains a static DoInvoke() function that is the key to
+// implementing type erasure in the Callback() classes. DoInvoke() is a static
+// function with a fixed signature that is independent of StorageType; its
+// first argument is a pointer to the non-templated common baseclass of
+// StorageType. This lets us store pointer to DoInvoke() in a function pointer
+// that has knowledge of the specific StorageType, and thus no knowledge of the
+// bound function and bound parameter types.
+//
+// As long as we ensure that DoInvoke() is only used with pointers there were
+// upcasted from the correct StorageType, we can be sure that execution is
+// safe.
+
+$range BOUND 0..MAX_ARITY
+$for BOUND [[
+
+template <typename StorageType, typename Sig>
+struct FunctionTraits$(BOUND);
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+
+$var UNBOUND = ARITY - BOUND
+$if UNBOUND >= 0 [[
+
+$$ Variables for function traits generation.
+$range ARG 1..ARITY
+$range BOUND_ARG 1..BOUND
+$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY
+
+$$ Variables for method traits generation. We are always short one arity since
+$$ the first bound parameter is the object.
+$var M_ARITY = ARITY - 1
+$range M_ARG 1..M_ARITY
+$range M_BOUND_ARG 2..BOUND
+$range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY
+
+// Function: Arity $(ARITY) -> $(UNBOUND).
+template <typename StorageType, typename R[[]]
+$if ARITY > 0 [[,]][[]]
+$for ARG , [[typename X$(ARG)]]>
+struct FunctionTraits$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> {
+$if ARITY > 0 [[
+
+ COMPILE_ASSERT(
+ !($for ARG || [[ is_non_const_reference<X$(ARG)>::value ]]),
+ do_not_bind_functions_with_nonconst_ref);
+
+]]
+
+ typedef base::false_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base[[]]
+$if UNBOUND != 0 [[, ]][[]]
+$for UNBOUND_ARG , [[const X$(UNBOUND_ARG)& x$(UNBOUND_ARG)]]) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]]
+$$ Add comma if there are both boudn and unbound args.
+$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]]
+$for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]);
+ }
+};
+
+$if BOUND > 0 [[
+
+// Method: Arity $(M_ARITY) -> $(UNBOUND).
+template <typename StorageType, typename R, typename T[[]]
+$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
+struct FunctionTraits$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> {
+$if M_ARITY > 0 [[
+
+ COMPILE_ASSERT(
+ !($for M_ARG || [[ is_non_const_reference<X$(M_ARG)>::value ]]),
+ do_not_bind_functions_with_nonconst_ref);
+
+]]
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base[[]]
+$if UNBOUND > 0 [[, ]][[]]
+$for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& x$(M_UNBOUND_ARG)]]) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)([[]]
+$for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
+$if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
+$for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
+ }
+};
+
+// Const Method: Arity $(M_ARITY) -> $(UNBOUND).
+template <typename StorageType, typename R, typename T[[]]
+$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
+struct FunctionTraits$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]]) const> {
+$if M_ARITY > 0 [[
+
+ COMPILE_ASSERT(
+ !($for M_ARG || [[is_non_const_reference<X$(M_ARG)>::value ]]),
+ do_not_bind_functions_with_nonconst_ref);
+
+]]
+
+ typedef base::true_type IsMethod;
+
+ static R DoInvoke(InvokerStorageBase* base[[]]
+$if UNBOUND > 0 [[, ]]
+[[]] $for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& x$(M_UNBOUND_ARG)]]) {
+ StorageType* invoker = static_cast<StorageType*>(base);
+ return (Unwrap(invoker->p1_)->*invoker->f_)([[]]
+$for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
+$if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
+$for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
+ }
+};
+
+]] $$ if BOUND
+
+]] $$ if UNBOUND
+]] $$ for ARITY
+]] $$ for BOUND
+
+
+// These are the actual storage classes for the invokers.
+//
+// Though these types are "classes", they are being used as structs with
+// all member variable public. We cannot make it a struct because it inherits
+// from a class which causes a compiler warning. We cannot add a "Run()" method
+// that forwards the unbound arguments because that would require we unwrap the
+// Sig type like in FunctionTraitsN above to know the return type, and the arity
+// of Run().
+//
+// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN,
+// but the generated code seemed harder to read.
+
+$for BOUND [[
+$range BOUND_ARG 1..BOUND
+
+template <typename Sig[[]]
+$if BOUND > 0 [[, ]]
+$for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
+class InvokerStorage$(BOUND) : public InvokerStorageBase {
+ public:
+ typedef InvokerStorage$(BOUND) StorageType;
+ typedef FunctionTraits$(BOUND)<StorageType, Sig> FunctionTraits;
+ typedef typename FunctionTraits::IsMethod IsMethod;
+
+$for BOUND_ARG [[
+$if BOUND_ARG == 1 [[
+
+ // For methods, we need to be careful for parameter 1. We skip the
+ // scoped_refptr check because the binder itself takes care of this. We also
+ // disallow binding of an array as the method's target object.
+ COMPILE_ASSERT(IsMethod::value ||
+ !internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value,
+ p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr);
+ COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value,
+ first_bound_argument_to_method_cannot_be_array);
+]] $else [[
+
+ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value,
+ p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr);
+]] $$ $if BOUND_ARG
+]] $$ $for BOUND_ARG
+
+
+
+ InvokerStorage$(BOUND)(Sig f
+$if BOUND > 0 [[, ]]
+$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]])
+ : f_(f)[[]]
+$if BOUND == 0 [[
+ {
+
+]] $else [[
+, $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename BindType<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] {
+ MaybeRefcount<IsMethod, P1>::AddRef(p1_);
+
+]]
+ }
+
+ virtual ~InvokerStorage$(BOUND)() {
+$if BOUND > 0 [[
+
+ MaybeRefcount<IsMethod, P1>::Release(p1_);
+
+]]
+ }
+
+ Sig f_;
+
+$for BOUND_ARG [[
+ typename BindType<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_;
+
+]]
+};
+
+]] $$ for BOUND
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_BIND_INTERNAL_H_
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
new file mode 100644
index 0000000..47d971a
--- /dev/null
+++ b/base/bind_unittest.cc
@@ -0,0 +1,597 @@
+// Copyright (c) 2011 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/bind.h"
+
+#if defined(BASE_CALLBACK_H_)
+// We explicitly do not want to include callback.h so people are not tempted
+// to use bind.h in a headerfile for getting the Callback types.
+#error "base/bind.h should avoid pulling in callback.h by default."
+#endif
+
+#include "base/callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+namespace base {
+namespace {
+
+class NoRef {
+ public:
+ NoRef() {}
+
+ MOCK_METHOD0(VoidMethod0, void(void));
+ MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
+
+ MOCK_METHOD0(IntMethod0, int(void));
+ MOCK_CONST_METHOD0(IntConstMethod0, int(void));
+
+ private:
+ // Particularly important in this test to ensure no copies are made.
+ DISALLOW_COPY_AND_ASSIGN(NoRef);
+};
+
+class HasRef : public NoRef {
+ public:
+ HasRef() {}
+
+ MOCK_CONST_METHOD0(AddRef, void(void));
+ MOCK_CONST_METHOD0(Release, bool(void));
+
+ private:
+ // Particularly important in this test to ensure no copies are made.
+ DISALLOW_COPY_AND_ASSIGN(HasRef);
+};
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class Parent {
+ public:
+ void AddRef(void) const {}
+ void Release(void) const {}
+ virtual void VirtualSet() { value = kParentValue; }
+ void NonVirtualSet() { value = kParentValue; }
+ int value;
+};
+
+class Child : public Parent {
+ public:
+ virtual void VirtualSet() { value = kChildValue; }
+ void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+ virtual void VirtualSet() { value = kParentValue; }
+ void NonVirtualSet() { value = kParentValue; }
+ int value;
+};
+
+class NoRefChild : public NoRefParent {
+ virtual void VirtualSet() { value = kChildValue; }
+ void NonVirtualSet() { value = kChildValue; }
+};
+
+// Used for probing the number of copies that occur if a type must be coerced
+// during argument forwarding in the Run() methods.
+struct DerivedCopyCounter {
+ DerivedCopyCounter(int* copies, int* assigns)
+ : copies_(copies), assigns_(assigns) {
+ }
+ int* copies_;
+ int* assigns_;
+};
+
+// Used for probing the number of copies in an argument.
+class CopyCounter {
+ public:
+ CopyCounter(int* copies, int* assigns)
+ : copies_(copies), assigns_(assigns) {
+ }
+
+ CopyCounter(const CopyCounter& other)
+ : copies_(other.copies_),
+ assigns_(other.assigns_) {
+ (*copies_)++;
+ }
+
+ // Probing for copies from coerscion.
+ CopyCounter(const DerivedCopyCounter& other)
+ : copies_(other.copies_),
+ assigns_(other.assigns_) {
+ (*copies_)++;
+ }
+
+ const CopyCounter& operator=(const CopyCounter& rhs) {
+ copies_ = rhs.copies_;
+ assigns_ = rhs.assigns_;
+
+ if (assigns_) {
+ (*assigns_)++;
+ }
+
+ return *this;
+ }
+
+ int copies() const {
+ return *copies_;
+ }
+
+ int assigns() const {
+ return *assigns_;
+ }
+
+ private:
+ int* copies_;
+ int* assigns_;
+};
+
+// Some test functions that we can Bind to.
+template <typename T>
+T PolymorphicIdentity(T t) {
+ return t;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+int Identity(int n) {
+ return n;
+}
+
+int ArrayGet(const int array[], int n) {
+ return array[n];
+}
+
+int Sum(int a, int b, int c, int d, int e, int f) {
+ return a + b + c + d + e + f;
+}
+
+const char* CStringIdentity(const char* s) {
+ return s;
+}
+
+int GetCopies(const CopyCounter& counter) {
+ return counter.copies();
+}
+
+int UnwrapNoRefParent(NoRefParent p) {
+ return p.value;
+}
+
+int UnwrapNoRefParentPtr(NoRefParent* p) {
+ return p->value;
+}
+
+int UnwrapNoRefParentConstRef(const NoRefParent& p) {
+ return p.value;
+}
+
+// Only useful in no-compile tests.
+int UnwrapNoRefParentRef(Parent& p) {
+ return p.value;
+}
+
+class BindTest : public ::testing::Test {
+ public:
+ BindTest() {
+ const_has_ref_ptr_ = &has_ref_;
+ const_no_ref_ptr_ = &no_ref_;
+ static_func_mock_ptr = &static_func_mock_;
+ }
+
+ virtual ~BindTest() {
+ }
+
+ static void VoidFunc0(void) {
+ static_func_mock_ptr->VoidMethod0();
+ }
+
+ static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); }
+
+ protected:
+ StrictMock<NoRef> no_ref_;
+ StrictMock<HasRef> has_ref_;
+ const HasRef* const_has_ref_ptr_;
+ const NoRef* const_no_ref_ptr_;
+ StrictMock<NoRef> static_func_mock_;
+
+ // Used by the static functions to perform expectations.
+ static StrictMock<NoRef>* static_func_mock_ptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BindTest);
+};
+
+StrictMock<NoRef>* BindTest::static_func_mock_ptr;
+
+// Ensure we can create unbound callbacks. We need this to be able to store
+// them in class members that can be initialized later.
+TEST_F(BindTest, DefaultConstruction) {
+ Callback<void(void)> c0;
+ Callback<void(int)> c1;
+ Callback<void(int,int)> c2;
+ Callback<void(int,int,int)> c3;
+ Callback<void(int,int,int,int)> c4;
+ Callback<void(int,int,int,int,int)> c5;
+ Callback<void(int,int,int,int,int,int)> c6;
+}
+
+// Sanity check that we can instantiate a callback for each arity.
+TEST_F(BindTest, ArityTest) {
+ Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
+ EXPECT_EQ(63, c0.Run());
+
+ Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2);
+ EXPECT_EQ(75, c1.Run(13));
+
+ Callback<int(int,int)> c2 = Bind(&Sum, 32, 16, 8, 4);
+ EXPECT_EQ(85, c2.Run(13, 12));
+
+ Callback<int(int,int,int)> c3 = Bind(&Sum, 32, 16, 8);
+ EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+ Callback<int(int,int,int,int)> c4 = Bind(&Sum, 32, 16);
+ EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+ Callback<int(int,int,int,int,int)> c5 = Bind(&Sum, 32);
+ EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+ Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+ EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+}
+
+// Function type support.
+// - Normal function.
+// - Method bound to non-const object.
+// - Const method bound to non-const object.
+// - Const method bound to const object.
+// - Derived classes can be used with pointers to non-virtual base functions.
+// - Derived classes can be used with pointers to virtual base functions (and
+// preserve virtual dispatch).
+TEST_F(BindTest, FunctionTypeSupport) {
+ EXPECT_CALL(static_func_mock_, VoidMethod0());
+ EXPECT_CALL(has_ref_, AddRef()).Times(3);
+ EXPECT_CALL(has_ref_, Release()).Times(3);
+ EXPECT_CALL(has_ref_, VoidMethod0());
+ EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
+
+ Closure normal_cb = Bind(&VoidFunc0);
+ Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_);
+ Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0,
+ &has_ref_);
+ Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0,
+ const_has_ref_ptr_);
+ normal_cb.Run();
+ method_cb.Run();
+ const_method_nonconst_obj_cb.Run();
+ const_method_const_obj_cb.Run();
+
+ Child child;
+ child.value = 0;
+ Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child);
+ virtual_set_cb.Run();
+ EXPECT_EQ(kChildValue, child.value);
+
+ child.value = 0;
+ Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child);
+ non_virtual_set_cb.Run();
+ EXPECT_EQ(kParentValue, child.value);
+}
+
+// Return value support.
+// - Function with return value.
+// - Method with return value.
+// - Const method with return value.
+TEST_F(BindTest, ReturnValues) {
+ EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+ EXPECT_CALL(has_ref_, AddRef()).Times(3);
+ EXPECT_CALL(has_ref_, Release()).Times(3);
+ EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337));
+ EXPECT_CALL(has_ref_, IntConstMethod0())
+ .WillOnce(Return(41337))
+ .WillOnce(Return(51337));
+
+ Callback<int(void)> normal_cb = Bind(&IntFunc0);
+ Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+ Callback<int(void)> const_method_nonconst_obj_cb =
+ Bind(&HasRef::IntConstMethod0, &has_ref_);
+ Callback<int(void)> const_method_const_obj_cb =
+ Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
+ EXPECT_EQ(1337, normal_cb.Run());
+ EXPECT_EQ(31337, method_cb.Run());
+ EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run());
+ EXPECT_EQ(51337, const_method_const_obj_cb.Run());
+}
+
+// Argument binding tests.
+// - Argument binding to primitive.
+// - Argument binding to primitive pointer.
+// - Argument binding to a literal integer.
+// - Argument binding to a literal string.
+// - Argument binding with template function.
+// - Argument binding to an object.
+// - Argument gets type converted.
+// - Pointer argument gets converted.
+// - Const Reference forces conversion.
+TEST_F(BindTest, ArgumentBinding) {
+ int n = 2;
+
+ Callback<int(void)> bind_primitive_cb = Bind(&Identity, n);
+ EXPECT_EQ(n, bind_primitive_cb.Run());
+
+ Callback<int*(void)> bind_primitive_pointer_cb =
+ Bind(&PolymorphicIdentity<int*>, &n);
+ EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
+
+ Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3);
+ EXPECT_EQ(3, bind_int_literal_cb.Run());
+
+ Callback<const char*(void)> bind_string_literal_cb =
+ Bind(&CStringIdentity, "hi");
+ EXPECT_STREQ("hi", bind_string_literal_cb.Run());
+
+ Callback<int(void)> bind_template_function_cb =
+ Bind(&PolymorphicIdentity<int>, 4);
+ EXPECT_EQ(4, bind_template_function_cb.Run());
+
+ NoRefParent p;
+ p.value = 5;
+ Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+ EXPECT_EQ(5, bind_object_cb.Run());
+
+ NoRefChild c;
+ c.value = 6;
+ Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+ EXPECT_EQ(6, bind_promotes_cb.Run());
+
+ c.value = 7;
+ Callback<int(void)> bind_pointer_promotes_cb =
+ Bind(&UnwrapNoRefParentPtr, &c);
+ EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
+
+ c.value = 8;
+ Callback<int(void)> bind_const_reference_promotes_cb =
+ Bind(&UnwrapNoRefParentConstRef, c);
+ EXPECT_EQ(8, bind_const_reference_promotes_cb.Run());
+}
+
+// Functions that take reference parameters.
+// - Forced reference parameter type still stores a copy.
+// - Forced const reference parameter type still stores a copy.
+TEST_F(BindTest, ReferenceArgumentBinding) {
+ int n = 1;
+ int& ref_n = n;
+ const int& const_ref_n = n;
+
+ Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n);
+ EXPECT_EQ(n, ref_copies_cb.Run());
+ n++;
+ EXPECT_EQ(n - 1, ref_copies_cb.Run());
+
+ Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n);
+ EXPECT_EQ(n, const_ref_copies_cb.Run());
+ n++;
+ EXPECT_EQ(n - 1, const_ref_copies_cb.Run());
+}
+
+// Check that we can pass in arrays and have them be stored as a pointer.
+// - Array of values stores a pointer.
+// - Array of const values stores a pointer.
+TEST_F(BindTest, ArrayArgumentBinding) {
+ int array[4] = {1, 1, 1, 1};
+ const int (*const_array_ptr)[4] = &array;
+
+ Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1);
+ EXPECT_EQ(1, array_cb.Run());
+
+ Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
+ EXPECT_EQ(1, const_array_cb.Run());
+
+ array[1] = 3;
+ EXPECT_EQ(3, array_cb.Run());
+ EXPECT_EQ(3, const_array_cb.Run());
+}
+
+// Verify SupportsAddRefAndRelease correctly introspects the class type for
+// AddRef() and Release().
+TEST_F(BindTest, SupportsAddRefAndRelease) {
+ EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value);
+ EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value);
+
+ // StrictMock<T> is a derived class of T. So, we use StrictMock<HasRef> and
+ // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over
+ // inheritance.
+ EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value);
+ EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value);
+}
+
+// Unretained() wrapper support.
+// - Method bound to Unretained() non-object.
+// - Const method bound to Unretained() non-const object.
+// - Const method bound to Unretained() const object.
+TEST_F(BindTest, Unretained) {
+ EXPECT_CALL(no_ref_, VoidMethod0());
+ EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+ Callback<void(void)> method_cb =
+ Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
+ method_cb.Run();
+
+ Callback<void(void)> const_method_cb =
+ Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
+ const_method_cb.Run();
+
+ Callback<void(void)> const_method_const_ptr_cb =
+ Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
+ const_method_const_ptr_cb.Run();
+}
+
+// ConstRef() wrapper support.
+// - Binding w/o ConstRef takes a copy.
+// - Binding a ConstRef takes a reference.
+// - Binding ConstRef to a function ConstRef does not copy on invoke.
+TEST_F(BindTest, ConstRef) {
+ int n = 1;
+
+ Callback<int(void)> copy_cb = Bind(&Identity, n);
+ Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n));
+ EXPECT_EQ(n, copy_cb.Run());
+ EXPECT_EQ(n, const_ref_cb.Run());
+ n++;
+ EXPECT_EQ(n - 1, copy_cb.Run());
+ EXPECT_EQ(n, const_ref_cb.Run());
+
+ int copies = 0;
+ int assigns = 0;
+ CopyCounter counter(&copies, &assigns);
+ Callback<int(void)> all_const_ref_cb =
+ Bind(&GetCopies, ConstRef(counter));
+ EXPECT_EQ(0, all_const_ref_cb.Run());
+ EXPECT_EQ(0, copies);
+ EXPECT_EQ(0, assigns);
+}
+
+// Argument Copy-constructor usage for non-reference parameters.
+// - Bound arguments are only copied once.
+// - Forwarded arguments are only copied once.
+// - Forwarded arguments with coerscions are only copied twice (once for the
+// coerscion, and one for the final dispatch).
+TEST_F(BindTest, ArgumentCopies) {
+ int copies = 0;
+ int assigns = 0;
+
+ CopyCounter counter(&copies, &assigns);
+
+ Callback<void(void)> copy_cb =
+ Bind(&VoidPolymorphic1<CopyCounter>, counter);
+ EXPECT_GE(1, copies);
+ EXPECT_EQ(0, assigns);
+
+ copies = 0;
+ assigns = 0;
+ Callback<void(CopyCounter)> forward_cb =
+ Bind(&VoidPolymorphic1<CopyCounter>);
+ forward_cb.Run(counter);
+ EXPECT_GE(1, copies);
+ EXPECT_EQ(0, assigns);
+
+ copies = 0;
+ assigns = 0;
+ DerivedCopyCounter dervied(&copies, &assigns);
+ Callback<void(CopyCounter)> coerce_cb =
+ Bind(&VoidPolymorphic1<CopyCounter>);
+ coerce_cb.Run(dervied);
+ EXPECT_GE(2, copies);
+ EXPECT_EQ(0, assigns);
+}
+
+// Callback construction and assignment tests.
+// - Construction from an InvokerStorageHolder should not cause ref/deref.
+// - Assignment from other callback should only cause one ref
+//
+// TODO(ajwong): Is there actually a way to test this?
+
+// No-compile tests. These should not compile. If they do, we are allowing
+// error-prone, or incorrect behavior in the callback system. Uncomment the
+// tests to check.
+TEST_F(BindTest, NoCompile) {
+ // - Method bound to const-object.
+ //
+ // Only const methods should be allowed to work with const objects.
+ //
+ // Callback<void(void)> method_to_const_cb =
+ // Bind(&HasRef::VoidMethod0, const_has_ref_ptr_);
+ // method_to_const_cb.Run();
+
+ // - Method bound to non-refcounted object.
+ // - Const Method bound to non-refcounted object.
+ //
+ // We require refcounts unless you have Unretained().
+ //
+ // Callback<void(void)> no_ref_cb =
+ // Bind(&NoRef::VoidMethod0, &no_ref_);
+ // no_ref_cb.Run();
+ // Callback<void(void)> no_ref_const_cb =
+ // Bind(&NoRef::VoidConstMethod0, &no_ref_);
+ // no_ref_const_cb.Run();
+
+ // - Unretained() used with a refcounted object.
+ //
+ // If the object supports refcounts, unretaining it in the callback is a
+ // memory management contract break.
+ // Callback<void(void)> unretained_cb =
+ // Bind(&HasRef::VoidConstMethod0, Unretained(&has_ref_));
+ // unretained_cb.Run();
+
+ // - Const argument used with non-const pointer parameter of same type.
+ // - Const argument used with non-const pointer parameter of super type.
+ //
+ // This is just a const-correctness check.
+ //
+ // const Parent* const_parent_ptr;
+ // const Child* const_child_ptr;
+ // Callback<Parent*(void)> pointer_same_cb =
+ // Bind(&PolymorphicIdentity<Parent*>, const_parent_ptr);
+ // pointer_same_cb.Run();
+ // Callback<Parent*(void)> pointer_super_cb =
+ // Bind(&PolymorphicIdentity<Parent*>, const_child_ptr);
+ // pointer_super_cb.Run();
+
+ // - Construction of Callback<A> from Callback<B> if A is supertype of B.
+ // Specific example: Callback<void(void)> a; Callback<int(void)> b; a = b;
+ //
+ // While this is technically safe, most people aren't used to it when coding
+ // C++ so if this is happening, it is almost certainly an error.
+ //
+ // Callback<int(void)> cb_a0 = Bind(&Identity, 1);
+ // Callback<void(void)> cb_b0 = cb_a0;
+
+ // - Assignment of Callback<A> from Callback<B> if A is supertype of B.
+ // See explanation above.
+ //
+ // Callback<int(void)> cb_a1 = Bind(&Identity, 1);
+ // Callback<void(void)> cb_b1;
+ // cb_a1 = cb_b1;
+
+ // - Functions with reference parameters, unsupported.
+ //
+ // First, non-const reference parameters are disallowed by the Google
+ // style guide. Seconds, since we are doing argument forwarding it becomes
+ // very tricky to avoid copies, maintain const correctness, and not
+ // accidentally have the function be modifying a temporary, or a copy.
+ //
+ // NoRefParent p;
+ // Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapNoRefParentRef);
+ // ref_arg_cb.Run(p);
+ // Callback<int(void)> ref_cb = Bind(&UnwrapNoRefParentRef, p);
+ // ref_cb.Run();
+
+ // - A method should not be bindable with an array of objects.
+ //
+ // This is likely not wanted behavior. We specifically check for it though
+ // because it is possible, depending on how you implement prebinding, to
+ // implicitly convert an array type to a pointer type.
+ //
+ // HasRef p[10];
+ // Callback<void(void)> method_bound_to_array_cb =
+ // Bind(&HasRef::VoidConstMethod0, p);
+ // method_bound_to_array_cb.Run();
+
+ // - Refcounted types should not be bound as a raw pointer.
+ // HasRef for_raw_ptr;
+ // Callback<void(void)> ref_count_as_raw_ptr =
+ // Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr);
+ // ASSERT_EQ(&for_raw_ptr, ref_count_as_raw_ptr.Run());
+
+}
+
+} // namespace
+} // namespace base
diff --git a/base/callback.h b/base/callback.h
index e5ea771..05a7182 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -1,4 +1,9 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// This file was GENERATED by command:
+// pump.py callback.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 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.
@@ -6,249 +11,472 @@
#define BASE_CALLBACK_H_
#pragma once
-#include "base/tuple.h"
-#include "base/raw_scoped_refptr_mismatch_checker.h"
-
-// Callback --------------------------------------------------------------------
-//
-// A Callback is like a Task but with unbound parameters. It is basically an
-// object-oriented function pointer.
-//
-// Callbacks are designed to work with Tuples. A set of helper functions and
-// classes is provided to hide the Tuple details from the consumer. Client
-// code will generally work with the CallbackRunner base class, which merely
-// provides a Run method and is returned by the New* functions. This allows
-// users to not care which type of class implements the callback, only that it
-// has a certain number and type of arguments.
-//
-// The implementation of this is done by CallbackImpl, which inherits
-// CallbackStorage to store the data. This allows the storage of the data
-// (requiring the class type T) to be hidden from users, who will want to call
-// this regardless of the implementor's type T.
-//
-// Note that callbacks currently have no facility for cancelling or abandoning
-// them. We currently handle this at a higher level for cases where this is
-// necessary. The pointer in a callback must remain valid until the callback
-// is made.
-//
-// Like Task, the callback executor is responsible for deleting the callback
-// pointer once the callback has executed.
-//
-// Example client usage:
-// void Object::DoStuff(int, string);
-// Callback2<int, string>::Type* callback =
-// NewCallback(obj, &Object::DoStuff);
-// callback->Run(5, string("hello"));
-// delete callback;
-// or, equivalently, using tuples directly:
-// CallbackRunner<Tuple2<int, string> >* callback =
-// NewCallback(obj, &Object::DoStuff);
-// callback->RunWithParams(MakeTuple(5, string("hello")));
-//
-// There is also a 0-args version that returns a value. Example:
-// int Object::GetNextInt();
-// CallbackWithReturnValue<int>::Type* callback =
-// NewCallbackWithReturnValue(obj, &Object::GetNextInt);
-// int next_int = callback->Run();
-// delete callback;
-
-// Base for all Callbacks that handles storage of the pointers.
-template <class T, typename Method>
-class CallbackStorage {
- public:
- CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) {
- }
-
- protected:
- T* obj_;
- Method meth_;
-};
+#include "base/callback_helpers.h"
+#include "base/callback_old.h"
-// Interface that is exposed to the consumer, that does the actual calling
-// of the method.
-template <typename Params>
-class CallbackRunner {
+// New, super-duper, unified Callback system. This will eventually replace
+// NewRunnableMethod, NewRunnableFunction, CreateFunctor, and CreateCallback
+// systems currently in the Chromium code base.
+//
+// WHAT IS THIS:
+//
+// The templated Callback class is a generalized function object. Together
+// with the Bind() function in bind.h, they provide a type-safe method for
+// performing currying of arguments, and creating a "closure."
+//
+// In programing languages, a closure is a first-class function where all its
+// parameters have been bound (usually via currying). Closures are well
+// suited for representing, and passing around a unit of delayed execution.
+// They are used in Chromium code to schedule tasks on different MessageLoops.
+//
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// EXAMPLE USAGE:
+//
+// /* Binding a normal function. */
+// int Return5() { return 5; }
+// base::Callback<int(int)> func_cb = base::Bind(&Return5);
+// LOG(INFO) << func_cb.Run(5); // Prints 5.
+//
+// void PrintHi() { LOG(INFO) << "hi."; }
+// base::Closure void_func_cb = base::Bind(&PrintHi);
+// LOG(INFO) << void_func_cb.Run(); // Prints: hi.
+//
+// /* Binding a class method. */
+// class Ref : public RefCountedThreadSafe<Ref> {
+// public:
+// int Foo() { return 3; }
+// void PrintBye() { LOG(INFO) << "bye."; }
+// };
+// scoped_refptr<Ref> ref = new Ref();
+// base::Callback<int(void)> ref_cb = base::Bind(&Ref::Foo, ref.get());
+// LOG(INFO) << ref_cb.Run(); // Prints out 3.
+//
+// base::Closure void_ref_cb = base::Bind(&Ref::PrintBye, ref.get());
+// void_ref_cb.Run(); // Prints: bye.
+//
+// /* Binding a class method in a non-refcounted class.
+// *
+// * WARNING: You must be sure the referee outlives the callback!
+// * This is particularly important if you post a closure to a
+// * MessageLoop because then it becomes hard to know what the
+// * lifetime of the referee needs to be.
+// */
+// class NoRef {
+// public:
+// int Foo() { return 4; }
+// void PrintWhy() { LOG(INFO) << "why???"; }
+// };
+// NoRef no_ref;
+// base::Callback<int(void)> base::no_ref_cb =
+// base::Bind(&NoRef::Foo, base::Unretained(&no_ref));
+// LOG(INFO) << ref_cb.Run(); // Prints out 4.
+//
+// base::Closure void_no_ref_cb =
+// base::Bind(&NoRef::PrintWhy, base::Unretained(no_ref));
+// void_no_ref_cb.Run(); // Prints: why???
+//
+// /* Binding a reference. */
+// int Identity(int n) { return n; }
+// int value = 1;
+// base::Callback<int(void)> bound_copy_cb = base::Bind(&Identity, value);
+// base::Callback<int(void)> bound_ref_cb =
+// base::Bind(&Identity, base::ConstRef(value));
+// LOG(INFO) << bound_copy_cb.Run(); // Prints 1.
+// LOG(INFO) << bound_ref_cb.Run(); // Prints 1.
+// value = 2;
+// LOG(INFO) << bound_copy_cb.Run(); // Prints 1.
+// LOG(INFO) << bound_ref_cb.Run(); // Prints 2.
+//
+//
+// WHERE IS THIS DESIGN FROM:
+//
+// The design Callback and Bind is heavily influenced by C++'s
+// tr1::function/tr1::bind, and by the "Google Callback" system used inside
+// Google.
+//
+//
+// HOW THE IMPLEMENTATION WORKS:
+//
+// There are three main components to the system:
+// 1) The Callback classes.
+// 2) The Bind() functions.
+// 3) The arguments wrappers (eg., Unretained() and ConstRef()).
+//
+// The Callback classes represent a generic function pointer. Internally,
+// it stores a refcounted piece of state that represents the target function
+// and all its bound parameters. Each Callback specialization has a templated
+// constructor that takes an InvokerStorageHolder<> object. In the context of
+// the constructor, the static type of this InvokerStorageHolder<> object
+// uniquely identifies the function it is representing, all its bound
+// parameters, and a DoInvoke() that is capable of invoking the target.
+//
+// Callback's constructor is takes the InvokerStorageHolder<> that has the
+// full static type and erases the target function type, and the bound
+// parameters. It does this by storing a pointer to the specific DoInvoke()
+// function, and upcasting the state of InvokerStorageHolder<> to a
+// InvokerStorageBase. This is safe as long as this InvokerStorageBase pointer
+// is only used with the stored DoInvoke() pointer.
+//
+// To create InvokerStorageHolder<> objects, we use the Bind() functions.
+// These functions, along with a set of internal templates, are reponsible for
+//
+// - Unwrapping the function signature into return type, and parameters
+// - Determining the number of parameters that are bound
+// - Creating the storage for the bound parameters
+// - Performing compile-time asserts to avoid error-prone behavior
+// - Returning an InvokerStorageHolder<> with an DoInvoke() that has an arity
+// matching the number of unbound parameters, and knows the correct
+// refcounting semantics for the target object if we are binding a class
+// method.
+//
+// The Bind functions do the above using type-inference, and template
+// specializations.
+//
+// By default Bind() will store copies of all bound parameters, and attempt
+// to refcount a target object if the function being bound is a class method.
+//
+// To change this behavior, we introduce a set of argument wrappers
+// (eg. Unretained(), and ConstRef()). These are simple container templates
+// that are passed by value, and wrap a pointer to argument. See the
+// file-level comment in base/bind_helpers.h for more info.
+//
+// These types are passed to the Unwrap() functions, and the MaybeRefcount()
+// functions respectively to modify the behavior of Bind(). The Unwrap()
+// and MaybeRefcount() functions change behavior by doing partial
+// specialization based on whether or not a parameter is a wrapper type.
+//
+// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium.
+//
+//
+// WHY NOT TR1 FUNCTION/BIND?
+//
+// Direct use of tr1::function and tr1::bind was considered, but ultimately
+// rejected because of the number of copy constructors invocations involved
+// in the binding of arguments during construction, and the forwarding of
+// arguments during invocation. These copies will no longer be an issue in
+// C++0x because C++0x will support rvalue reference allowing for the compiler
+// to avoid these copies. However, waiting for C++0x is not an option.
+//
+// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
+// tr1::bind call itself will invoke a non-trivial copy constructor three times
+// for each bound parameter. Also, each when passing a tr1::function, each
+// bound argument will be copied again.
+//
+// In addition to the copies taken at binding and invocation, copying a
+// tr1::function causes a copy to be made of all the bound parameters and
+// state.
+//
+// Furthermore, in Chromium, it is desirable for the Callback to take a
+// reference on a target object when representing a class method call. This
+// is not supported by tr1.
+//
+// Lastly, tr1::function and tr1::bind has a more general and flexible API.
+// This includes things like argument reordering by use of
+// tr1::bind::placeholder, support for non-const reference parameters, and some
+// limited amount of subtyping of the tr1::function object (eg.,
+// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
+//
+// These are not features that are required in Chromium. Some of them, such as
+// allowing for reference parameters, and subtyping of functions, may actually
+// because a source of errors. Removing support for these features actually
+// allows for a simpler implementation, and a terser Currying API.
+//
+//
+// WHY NOT GOOGLE CALLBACKS?
+//
+// The Google callback system also does not support refcounting. Furthermore,
+// its implementation has a number of strange edge cases with respect to type
+// conversion of its arguments. In particular, the argument's constness must
+// at times match exactly the function signature, or the type-inference might
+// break. Given the above, writing a custom solution was easier.
+//
+//
+// MISSING FUNCTIONALITY
+// - Invoking the return of Bind. Bind(&foo).Run() does not work;
+// - Binding arrays to functions that take a non-const pointer.
+// Example:
+// void Foo(const char* ptr);
+// void Bar(char* ptr);
+// Bind(&Foo, "test");
+// Bind(&Bar, "test"); // This fails because ptr is not const.
+
+namespace base {
+
+// First, we forward declare the Callback class template. This informs the
+// compiler that the template only has 1 type parameter which is the function
+// signature that the Callback is representing.
+//
+// After this, create template specializations for 0-6 parameters. Note that
+// even though the template typelist grows, the specialization still
+// only has one type: the function signature.
+template <typename Sig>
+class Callback;
+
+template <typename R>
+class Callback<R(void)> {
public:
- typedef Params TupleType;
-
- virtual ~CallbackRunner() {}
- virtual void RunWithParams(const Params& params) = 0;
-
- // Convenience functions so callers don't have to deal with Tuples.
- inline void Run() {
- RunWithParams(Tuple0());
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
}
- template <typename Arg1>
- inline void Run(const Arg1& a) {
- RunWithParams(Params(a));
+ R Run(void) const {
+ return polymorphic_invoke_(invoker_storage_.get());
}
- template <typename Arg1, typename Arg2>
- inline void Run(const Arg1& a, const Arg2& b) {
- RunWithParams(Params(a, b));
- }
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
+};
- template <typename Arg1, typename Arg2, typename Arg3>
- inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) {
- RunWithParams(Params(a, b, c));
+template <typename R, typename A1>
+class Callback<R(A1)> {
+ public:
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
}
- template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) {
- RunWithParams(Params(a, b, c, d));
+ R Run(const A1& a1) const {
+ return polymorphic_invoke_(invoker_storage_.get(), a1);
}
- template <typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename Arg5>
- inline void Run(const Arg1& a, const Arg2& b, const Arg3& c,
- const Arg4& d, const Arg5& e) {
- RunWithParams(Params(a, b, c, d, e));
- }
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
};
-template <class T, typename Method, typename Params>
-class CallbackImpl : public CallbackStorage<T, Method>,
- public CallbackRunner<Params> {
+template <typename R, typename A1, typename A2>
+class Callback<R(A1, A2)> {
public:
- CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) {
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
+ const A2&);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
}
- virtual void RunWithParams(const Params& params) {
- // use "this->" to force C++ to look inside our templatized base class; see
- // Effective C++, 3rd Ed, item 43, p210 for details.
- DispatchToMethod(this->obj_, this->meth_, params);
+
+ R Run(const A1& a1,
+ const A2& a2) const {
+ return polymorphic_invoke_(invoker_storage_.get(), a1,
+ a2);
}
-};
-// 0-arg implementation
-struct Callback0 {
- typedef CallbackRunner<Tuple0> Type;
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
};
-template <class T>
-typename Callback0::Type* NewCallback(T* object, void (T::*method)()) {
- return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method);
-}
-
-// 1-arg implementation
-template <typename Arg1>
-struct Callback1 {
- typedef CallbackRunner<Tuple1<Arg1> > Type;
-};
+template <typename R, typename A1, typename A2, typename A3>
+class Callback<R(A1, A2, A3)> {
+ public:
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
+ const A2&,
+ const A3&);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
+ }
-template <class T, typename Arg1>
-typename Callback1<Arg1>::Type* NewCallback(T* object,
- void (T::*method)(Arg1)) {
- return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method);
-}
+ R Run(const A1& a1,
+ const A2& a2,
+ const A3& a3) const {
+ return polymorphic_invoke_(invoker_storage_.get(), a1,
+ a2,
+ a3);
+ }
-// 2-arg implementation
-template <typename Arg1, typename Arg2>
-struct Callback2 {
- typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type;
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
};
-template <class T, typename Arg1, typename Arg2>
-typename Callback2<Arg1, Arg2>::Type* NewCallback(
- T* object,
- void (T::*method)(Arg1, Arg2)) {
- return new CallbackImpl<T, void (T::*)(Arg1, Arg2),
- Tuple2<Arg1, Arg2> >(object, method);
-}
-
-// 3-arg implementation
-template <typename Arg1, typename Arg2, typename Arg3>
-struct Callback3 {
- typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type;
-};
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class Callback<R(A1, A2, A3, A4)> {
+ public:
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
+ const A2&,
+ const A3&,
+ const A4&);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
+ }
-template <class T, typename Arg1, typename Arg2, typename Arg3>
-typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback(
- T* object,
- void (T::*method)(Arg1, Arg2, Arg3)) {
- return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3),
- Tuple3<Arg1, Arg2, Arg3> >(object, method);
-}
-
-// 4-arg implementation
-template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
-struct Callback4 {
- typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type;
-};
+ R Run(const A1& a1,
+ const A2& a2,
+ const A3& a3,
+ const A4& a4) const {
+ return polymorphic_invoke_(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4);
+ }
-template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
-typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback(
- T* object,
- void (T::*method)(Arg1, Arg2, Arg3, Arg4)) {
- return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4),
- Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method);
-}
-
-// 5-arg implementation
-template <typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename Arg5>
-struct Callback5 {
- typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type;
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
};
-template <class T, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename Arg5>
-typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback(
- T* object,
- void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) {
- return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5),
- Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method);
-}
-
-// An UnboundMethod is a wrapper for a method where the actual object is
-// provided at Run dispatch time.
-template <class T, class Method, class Params>
-class UnboundMethod {
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+class Callback<R(A1, A2, A3, A4, A5)> {
public:
- UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
- COMPILE_ASSERT(
- (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
- badunboundmethodparams);
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
+ const A2&,
+ const A3&,
+ const A4&,
+ const A5&);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
}
- void Run(T* obj) const {
- DispatchToMethod(obj, m_, p_);
+
+ R Run(const A1& a1,
+ const A2& a2,
+ const A3& a3,
+ const A4& a4,
+ const A5& a5) const {
+ return polymorphic_invoke_(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4,
+ a5);
}
- private:
- Method m_;
- Params p_;
-};
-// Return value implementation with no args.
-template <typename ReturnValue>
-struct CallbackWithReturnValue {
- class Type {
- public:
- virtual ~Type() {}
- virtual ReturnValue Run() = 0;
- };
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
};
-template <class T, typename Method, typename ReturnValue>
-class CallbackWithReturnValueImpl
- : public CallbackStorage<T, Method>,
- public CallbackWithReturnValue<ReturnValue>::Type {
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+class Callback<R(A1, A2, A3, A4, A5, A6)> {
public:
- CallbackWithReturnValueImpl(T* obj, Method meth)
- : CallbackStorage<T, Method>(obj, meth) {}
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
+ const A2&,
+ const A3&,
+ const A4&,
+ const A5&,
+ const A6&);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
+ }
- virtual ReturnValue Run() {
- return (this->obj_->*(this->meth_))();
+ R Run(const A1& a1,
+ const A2& a2,
+ const A3& a3,
+ const A4& a4,
+ const A5& a5,
+ const A6& a6) const {
+ return polymorphic_invoke_(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6);
}
- protected:
- virtual ~CallbackWithReturnValueImpl() {}
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
};
-template <class T, typename ReturnValue>
-typename CallbackWithReturnValue<ReturnValue>::Type*
-NewCallbackWithReturnValue(T* object, ReturnValue (T::*method)()) {
- return new CallbackWithReturnValueImpl<T, ReturnValue (T::*)(), ReturnValue>(
- object, method);
-}
+
+// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+typedef Callback<void(void)> Closure;
+
+} // namespace base
#endif // BASE_CALLBACK_H
diff --git a/base/callback.h.pump b/base/callback.h.pump
new file mode 100644
index 0000000..9fc4b0b
--- /dev/null
+++ b/base/callback.h.pump
@@ -0,0 +1,291 @@
+$$ This is a pump file for generating file templates. Pump is a python
+$$ script that is part of the Google Test suite of utilities. Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$var MAX_ARITY = 6
+
+// Copyright (c) 2011 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.
+
+#ifndef BASE_CALLBACK_H_
+#define BASE_CALLBACK_H_
+#pragma once
+
+#include "base/callback_helpers.h"
+#include "base/callback_old.h"
+
+// New, super-duper, unified Callback system. This will eventually replace
+// NewRunnableMethod, NewRunnableFunction, CreateFunctor, and CreateCallback
+// systems currently in the Chromium code base.
+//
+// WHAT IS THIS:
+//
+// The templated Callback class is a generalized function object. Together
+// with the Bind() function in bind.h, they provide a type-safe method for
+// performing currying of arguments, and creating a "closure."
+//
+// In programing languages, a closure is a first-class function where all its
+// parameters have been bound (usually via currying). Closures are well
+// suited for representing, and passing around a unit of delayed execution.
+// They are used in Chromium code to schedule tasks on different MessageLoops.
+//
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// EXAMPLE USAGE:
+//
+// /* Binding a normal function. */
+// int Return5() { return 5; }
+// base::Callback<int(int)> func_cb = base::Bind(&Return5);
+// LOG(INFO) << func_cb.Run(5); // Prints 5.
+//
+// void PrintHi() { LOG(INFO) << "hi."; }
+// base::Closure void_func_cb = base::Bind(&PrintHi);
+// LOG(INFO) << void_func_cb.Run(); // Prints: hi.
+//
+// /* Binding a class method. */
+// class Ref : public RefCountedThreadSafe<Ref> {
+// public:
+// int Foo() { return 3; }
+// void PrintBye() { LOG(INFO) << "bye."; }
+// };
+// scoped_refptr<Ref> ref = new Ref();
+// base::Callback<int(void)> ref_cb = base::Bind(&Ref::Foo, ref.get());
+// LOG(INFO) << ref_cb.Run(); // Prints out 3.
+//
+// base::Closure void_ref_cb = base::Bind(&Ref::PrintBye, ref.get());
+// void_ref_cb.Run(); // Prints: bye.
+//
+// /* Binding a class method in a non-refcounted class.
+// *
+// * WARNING: You must be sure the referee outlives the callback!
+// * This is particularly important if you post a closure to a
+// * MessageLoop because then it becomes hard to know what the
+// * lifetime of the referee needs to be.
+// */
+// class NoRef {
+// public:
+// int Foo() { return 4; }
+// void PrintWhy() { LOG(INFO) << "why???"; }
+// };
+// NoRef no_ref;
+// base::Callback<int(void)> base::no_ref_cb =
+// base::Bind(&NoRef::Foo, base::Unretained(&no_ref));
+// LOG(INFO) << ref_cb.Run(); // Prints out 4.
+//
+// base::Closure void_no_ref_cb =
+// base::Bind(&NoRef::PrintWhy, base::Unretained(no_ref));
+// void_no_ref_cb.Run(); // Prints: why???
+//
+// /* Binding a reference. */
+// int Identity(int n) { return n; }
+// int value = 1;
+// base::Callback<int(void)> bound_copy_cb = base::Bind(&Identity, value);
+// base::Callback<int(void)> bound_ref_cb =
+// base::Bind(&Identity, base::ConstRef(value));
+// LOG(INFO) << bound_copy_cb.Run(); // Prints 1.
+// LOG(INFO) << bound_ref_cb.Run(); // Prints 1.
+// value = 2;
+// LOG(INFO) << bound_copy_cb.Run(); // Prints 1.
+// LOG(INFO) << bound_ref_cb.Run(); // Prints 2.
+//
+//
+// WHERE IS THIS DESIGN FROM:
+//
+// The design Callback and Bind is heavily influenced by C++'s
+// tr1::function/tr1::bind, and by the "Google Callback" system used inside
+// Google.
+//
+//
+// HOW THE IMPLEMENTATION WORKS:
+//
+// There are three main components to the system:
+// 1) The Callback classes.
+// 2) The Bind() functions.
+// 3) The arguments wrappers (eg., Unretained() and ConstRef()).
+//
+// The Callback classes represent a generic function pointer. Internally,
+// it stores a refcounted piece of state that represents the target function
+// and all its bound parameters. Each Callback specialization has a templated
+// constructor that takes an InvokerStorageHolder<> object. In the context of
+// the constructor, the static type of this InvokerStorageHolder<> object
+// uniquely identifies the function it is representing, all its bound
+// parameters, and a DoInvoke() that is capable of invoking the target.
+//
+// Callback's constructor is takes the InvokerStorageHolder<> that has the
+// full static type and erases the target function type, and the bound
+// parameters. It does this by storing a pointer to the specific DoInvoke()
+// function, and upcasting the state of InvokerStorageHolder<> to a
+// InvokerStorageBase. This is safe as long as this InvokerStorageBase pointer
+// is only used with the stored DoInvoke() pointer.
+//
+// To create InvokerStorageHolder<> objects, we use the Bind() functions.
+// These functions, along with a set of internal templates, are reponsible for
+//
+// - Unwrapping the function signature into return type, and parameters
+// - Determining the number of parameters that are bound
+// - Creating the storage for the bound parameters
+// - Performing compile-time asserts to avoid error-prone behavior
+// - Returning an InvokerStorageHolder<> with an DoInvoke() that has an arity
+// matching the number of unbound parameters, and knows the correct
+// refcounting semantics for the target object if we are binding a class
+// method.
+//
+// The Bind functions do the above using type-inference, and template
+// specializations.
+//
+// By default Bind() will store copies of all bound parameters, and attempt
+// to refcount a target object if the function being bound is a class method.
+//
+// To change this behavior, we introduce a set of argument wrappers
+// (eg. Unretained(), and ConstRef()). These are simple container templates
+// that are passed by value, and wrap a pointer to argument. See the
+// file-level comment in base/bind_helpers.h for more info.
+//
+// These types are passed to the Unwrap() functions, and the MaybeRefcount()
+// functions respectively to modify the behavior of Bind(). The Unwrap()
+// and MaybeRefcount() functions change behavior by doing partial
+// specialization based on whether or not a parameter is a wrapper type.
+//
+// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium.
+//
+//
+// WHY NOT TR1 FUNCTION/BIND?
+//
+// Direct use of tr1::function and tr1::bind was considered, but ultimately
+// rejected because of the number of copy constructors invocations involved
+// in the binding of arguments during construction, and the forwarding of
+// arguments during invocation. These copies will no longer be an issue in
+// C++0x because C++0x will support rvalue reference allowing for the compiler
+// to avoid these copies. However, waiting for C++0x is not an option.
+//
+// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
+// tr1::bind call itself will invoke a non-trivial copy constructor three times
+// for each bound parameter. Also, each when passing a tr1::function, each
+// bound argument will be copied again.
+//
+// In addition to the copies taken at binding and invocation, copying a
+// tr1::function causes a copy to be made of all the bound parameters and
+// state.
+//
+// Furthermore, in Chromium, it is desirable for the Callback to take a
+// reference on a target object when representing a class method call. This
+// is not supported by tr1.
+//
+// Lastly, tr1::function and tr1::bind has a more general and flexible API.
+// This includes things like argument reordering by use of
+// tr1::bind::placeholder, support for non-const reference parameters, and some
+// limited amount of subtyping of the tr1::function object (eg.,
+// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
+//
+// These are not features that are required in Chromium. Some of them, such as
+// allowing for reference parameters, and subtyping of functions, may actually
+// because a source of errors. Removing support for these features actually
+// allows for a simpler implementation, and a terser Currying API.
+//
+//
+// WHY NOT GOOGLE CALLBACKS?
+//
+// The Google callback system also does not support refcounting. Furthermore,
+// its implementation has a number of strange edge cases with respect to type
+// conversion of its arguments. In particular, the argument's constness must
+// at times match exactly the function signature, or the type-inference might
+// break. Given the above, writing a custom solution was easier.
+//
+//
+// MISSING FUNCTIONALITY
+// - Invoking the return of Bind. Bind(&foo).Run() does not work;
+// - Binding arrays to functions that take a non-const pointer.
+// Example:
+// void Foo(const char* ptr);
+// void Bar(char* ptr);
+// Bind(&Foo, "test");
+// Bind(&Bar, "test"); // This fails because ptr is not const.
+
+namespace base {
+
+// First, we forward declare the Callback class template. This informs the
+// compiler that the template only has 1 type parameter which is the function
+// signature that the Callback is representing.
+//
+// After this, create template specializations for 0-$(MAX_ARITY) parameters. Note that
+// even though the template typelist grows, the specialization still
+// only has one type: the function signature.
+template <typename Sig>
+class Callback;
+
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+$if ARITY == 0 [[
+template <typename R>
+class Callback<R(void)> {
+]] $else [[
+template <typename R, $for ARG , [[typename A$(ARG)]]>
+class Callback<R($for ARG , [[A$(ARG)]])> {
+]]
+
+ public:
+ typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*[[]]
+$if ARITY != 0 [[, ]]
+$for ARG ,
+ [[const A$(ARG)&]]);
+
+ Callback() : polymorphic_invoke_(NULL) { }
+
+ // We pass InvokerStorageHolder by const ref to avoid incurring an
+ // unnecessary AddRef/Unref pair even though we will modify the object.
+ // We cannot use a normal reference because the compiler will warn
+ // since this is often used on a return value, which is a temporary.
+ //
+ // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+ // return the exact Callback<> type. See base/bind.h for details.
+ template <typename T>
+ Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
+ : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
+ invoker_storage_.swap(invoker_holder.invoker_storage_);
+ }
+
+
+$if ARITY == 0 [[
+ R Run(void) const {
+]] $else [[
+ R Run($for ARG ,
+ [[const A$(ARG)& a$(ARG)]]) const {
+]]
+
+ return polymorphic_invoke_(invoker_storage_.get()[[]]
+$if ARITY != 0 [[, ]]
+$for ARG ,
+ [[a$(ARG)]]);
+ }
+
+ private:
+ scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
+ PolymorphicInvoke polymorphic_invoke_;
+};
+
+
+]] $$ for ARITY
+
+// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+typedef Callback<void(void)> Closure;
+
+} // namespace base
+
+#endif // BASE_CALLBACK_H
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
new file mode 100644
index 0000000..86b0df1
--- /dev/null
+++ b/base/callback_helpers.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 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.
+
+// This file contains utility functions and classes that help the
+// implementation, and management of the Callback objects.
+
+#ifndef BASE_CALLBACK_HELPERS_H_
+#define BASE_CALLBACK_HELPERS_H_
+#pragma once
+
+#include "base/ref_counted.h"
+
+namespace base {
+namespace internal {
+
+// InvokerStorageBase is used to provide an opaque handle that the Callback
+// class can use to represent a function object with bound arguments. It
+// behaves as an existential type that is used by a corresponding
+// DoInvoke function to perform the function execution. This allows
+// us to shield the Callback class from the types of the bound argument via
+// "type erasure."
+class InvokerStorageBase : public RefCountedThreadSafe<InvokerStorageBase> {
+ protected:
+ friend class RefCountedThreadSafe<InvokerStorageBase>;
+ virtual ~InvokerStorageBase() {}
+};
+
+// This structure exists purely to pass the returned |invoker_storage_| from
+// Bind() to Callback while avoiding an extra AddRef/Release() pair.
+//
+// To do this, the constructor of Callback<> must take a const-ref. The
+// reference must be to a const object otherwise the compiler will emit a
+// warning about taking a reference to a temporary.
+//
+// Unfortunately, this means that the internal |invoker_storage_| field must
+// be made mutable.
+template <typename T>
+struct InvokerStorageHolder {
+ explicit InvokerStorageHolder(T* invoker_storage)
+ : invoker_storage_(invoker_storage) {
+ }
+
+ mutable scoped_refptr<InvokerStorageBase> invoker_storage_;
+};
+
+template <typename T>
+InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o) {
+ return InvokerStorageHolder<T>(o);
+}
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_CALLBACK_HELPERS_H_
diff --git a/base/callback_old.h b/base/callback_old.h
new file mode 100644
index 0000000..ab3927d
--- /dev/null
+++ b/base/callback_old.h
@@ -0,0 +1,254 @@
+// 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.
+
+#ifndef BASE_CALLBACK_OLD_H_
+#define BASE_CALLBACK_OLD_H_
+#pragma once
+
+#include "base/tuple.h"
+#include "base/raw_scoped_refptr_mismatch_checker.h"
+
+// Callback --------------------------------------------------------------------
+//
+// A Callback is like a Task but with unbound parameters. It is basically an
+// object-oriented function pointer.
+//
+// Callbacks are designed to work with Tuples. A set of helper functions and
+// classes is provided to hide the Tuple details from the consumer. Client
+// code will generally work with the CallbackRunner base class, which merely
+// provides a Run method and is returned by the New* functions. This allows
+// users to not care which type of class implements the callback, only that it
+// has a certain number and type of arguments.
+//
+// The implementation of this is done by CallbackImpl, which inherits
+// CallbackStorage to store the data. This allows the storage of the data
+// (requiring the class type T) to be hidden from users, who will want to call
+// this regardless of the implementor's type T.
+//
+// Note that callbacks currently have no facility for cancelling or abandoning
+// them. We currently handle this at a higher level for cases where this is
+// necessary. The pointer in a callback must remain valid until the callback
+// is made.
+//
+// Like Task, the callback executor is responsible for deleting the callback
+// pointer once the callback has executed.
+//
+// Example client usage:
+// void Object::DoStuff(int, string);
+// Callback2<int, string>::Type* callback =
+// NewCallback(obj, &Object::DoStuff);
+// callback->Run(5, string("hello"));
+// delete callback;
+// or, equivalently, using tuples directly:
+// CallbackRunner<Tuple2<int, string> >* callback =
+// NewCallback(obj, &Object::DoStuff);
+// callback->RunWithParams(MakeTuple(5, string("hello")));
+//
+// There is also a 0-args version that returns a value. Example:
+// int Object::GetNextInt();
+// CallbackWithReturnValue<int>::Type* callback =
+// NewCallbackWithReturnValue(obj, &Object::GetNextInt);
+// int next_int = callback->Run();
+// delete callback;
+
+// Base for all Callbacks that handles storage of the pointers.
+template <class T, typename Method>
+class CallbackStorage {
+ public:
+ CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) {
+ }
+
+ protected:
+ T* obj_;
+ Method meth_;
+};
+
+// Interface that is exposed to the consumer, that does the actual calling
+// of the method.
+template <typename Params>
+class CallbackRunner {
+ public:
+ typedef Params TupleType;
+
+ virtual ~CallbackRunner() {}
+ virtual void RunWithParams(const Params& params) = 0;
+
+ // Convenience functions so callers don't have to deal with Tuples.
+ inline void Run() {
+ RunWithParams(Tuple0());
+ }
+
+ template <typename Arg1>
+ inline void Run(const Arg1& a) {
+ RunWithParams(Params(a));
+ }
+
+ template <typename Arg1, typename Arg2>
+ inline void Run(const Arg1& a, const Arg2& b) {
+ RunWithParams(Params(a, b));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) {
+ RunWithParams(Params(a, b, c));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) {
+ RunWithParams(Params(a, b, c, d));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+ inline void Run(const Arg1& a, const Arg2& b, const Arg3& c,
+ const Arg4& d, const Arg5& e) {
+ RunWithParams(Params(a, b, c, d, e));
+ }
+};
+
+template <class T, typename Method, typename Params>
+class CallbackImpl : public CallbackStorage<T, Method>,
+ public CallbackRunner<Params> {
+ public:
+ CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) {
+ }
+ virtual void RunWithParams(const Params& params) {
+ // use "this->" to force C++ to look inside our templatized base class; see
+ // Effective C++, 3rd Ed, item 43, p210 for details.
+ DispatchToMethod(this->obj_, this->meth_, params);
+ }
+};
+
+// 0-arg implementation
+struct Callback0 {
+ typedef CallbackRunner<Tuple0> Type;
+};
+
+template <class T>
+typename Callback0::Type* NewCallback(T* object, void (T::*method)()) {
+ return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method);
+}
+
+// 1-arg implementation
+template <typename Arg1>
+struct Callback1 {
+ typedef CallbackRunner<Tuple1<Arg1> > Type;
+};
+
+template <class T, typename Arg1>
+typename Callback1<Arg1>::Type* NewCallback(T* object,
+ void (T::*method)(Arg1)) {
+ return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method);
+}
+
+// 2-arg implementation
+template <typename Arg1, typename Arg2>
+struct Callback2 {
+ typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type;
+};
+
+template <class T, typename Arg1, typename Arg2>
+typename Callback2<Arg1, Arg2>::Type* NewCallback(
+ T* object,
+ void (T::*method)(Arg1, Arg2)) {
+ return new CallbackImpl<T, void (T::*)(Arg1, Arg2),
+ Tuple2<Arg1, Arg2> >(object, method);
+}
+
+// 3-arg implementation
+template <typename Arg1, typename Arg2, typename Arg3>
+struct Callback3 {
+ typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type;
+};
+
+template <class T, typename Arg1, typename Arg2, typename Arg3>
+typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback(
+ T* object,
+ void (T::*method)(Arg1, Arg2, Arg3)) {
+ return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3),
+ Tuple3<Arg1, Arg2, Arg3> >(object, method);
+}
+
+// 4-arg implementation
+template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+struct Callback4 {
+ typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type;
+};
+
+template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback(
+ T* object,
+ void (T::*method)(Arg1, Arg2, Arg3, Arg4)) {
+ return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4),
+ Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method);
+}
+
+// 5-arg implementation
+template <typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+struct Callback5 {
+ typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type;
+};
+
+template <class T, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback(
+ T* object,
+ void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) {
+ return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5),
+ Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method);
+}
+
+// An UnboundMethod is a wrapper for a method where the actual object is
+// provided at Run dispatch time.
+template <class T, class Method, class Params>
+class UnboundMethod {
+ public:
+ UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
+ COMPILE_ASSERT(
+ (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ badunboundmethodparams);
+ }
+ void Run(T* obj) const {
+ DispatchToMethod(obj, m_, p_);
+ }
+ private:
+ Method m_;
+ Params p_;
+};
+
+// Return value implementation with no args.
+template <typename ReturnValue>
+struct CallbackWithReturnValue {
+ class Type {
+ public:
+ virtual ~Type() {}
+ virtual ReturnValue Run() = 0;
+ };
+};
+
+template <class T, typename Method, typename ReturnValue>
+class CallbackWithReturnValueImpl
+ : public CallbackStorage<T, Method>,
+ public CallbackWithReturnValue<ReturnValue>::Type {
+ public:
+ CallbackWithReturnValueImpl(T* obj, Method meth)
+ : CallbackStorage<T, Method>(obj, meth) {}
+
+ virtual ReturnValue Run() {
+ return (this->obj_->*(this->meth_))();
+ }
+
+ protected:
+ virtual ~CallbackWithReturnValueImpl() {}
+};
+
+template <class T, typename ReturnValue>
+typename CallbackWithReturnValue<ReturnValue>::Type*
+NewCallbackWithReturnValue(T* object, ReturnValue (T::*method)()) {
+ return new CallbackWithReturnValueImpl<T, ReturnValue (T::*)(), ReturnValue>(
+ object, method);
+}
+
+#endif // BASE_CALLBACK_OLD_H_
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 017b869..3060306 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -85,7 +85,7 @@
#if defined(COMPILER_MSVC)
#define OVERRIDE override
#elif defined(__clang__)
-#define OVERRIDE __attribute__((override))
+#define OVERRIDE override
#else
#define OVERRIDE
#endif
diff --git a/base/crypto/capi_util.cc b/base/crypto/capi_util.cc
index cf47a50..ef57a3c 100644
--- a/base/crypto/capi_util.cc
+++ b/base/crypto/capi_util.cc
@@ -5,8 +5,8 @@
#include "base/crypto/capi_util.h"
#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/singleton.h"
+#include "base/synchronization/lock.h"
namespace {
@@ -18,7 +18,7 @@ class CAPIUtilSingleton {
// Returns a lock to guard calls to CryptAcquireContext with
// CRYPT_DELETEKEYSET or CRYPT_NEWKEYSET.
- Lock& acquire_context_lock() {
+ base::Lock& acquire_context_lock() {
return acquire_context_lock_;
}
@@ -28,7 +28,7 @@ class CAPIUtilSingleton {
CAPIUtilSingleton() {}
- Lock acquire_context_lock_;
+ base::Lock acquire_context_lock_;
DISALLOW_COPY_AND_ASSIGN(CAPIUtilSingleton);
};
@@ -43,7 +43,7 @@ BOOL CryptAcquireContextLocked(HCRYPTPROV* prov,
DWORD prov_type,
DWORD flags)
{
- AutoLock lock(CAPIUtilSingleton::GetInstance()->acquire_context_lock());
+ base::AutoLock lock(CAPIUtilSingleton::GetInstance()->acquire_context_lock());
return CryptAcquireContext(prov, container, provider, prov_type, flags);
}
diff --git a/base/crypto/crypto_module_blocking_password_delegate.h b/base/crypto/crypto_module_blocking_password_delegate.h
new file mode 100644
index 0000000..ae962a8
--- /dev/null
+++ b/base/crypto/crypto_module_blocking_password_delegate.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_CRYPTO_CRYPTO_MODULE_BLOCKING_PASSWORD_DELEGATE_H_
+#define BASE_CRYPTO_CRYPTO_MODULE_BLOCKING_PASSWORD_DELEGATE_H_
+#pragma once
+
+#include <string>
+
+namespace base {
+
+// PK11_SetPasswordFunc is a global setting. An implementation of
+// CryptoModuleBlockingPasswordDelegate should be passed as the user data
+// argument (|wincx|) to relevant NSS functions, which the global password
+// handler will call to do the actual work.
+class CryptoModuleBlockingPasswordDelegate {
+ public:
+ virtual ~CryptoModuleBlockingPasswordDelegate() {}
+
+ // Requests a password to unlock |slot_name|. The interface is
+ // synchronous because NSS cannot issue an asynchronous
+ // request. |retry| is true if this is a request for the retry
+ // and we previously returned the wrong password.
+ // The implementation should set |*cancelled| to true if the user cancelled
+ // instead of entering a password, otherwise it should return the password the
+ // user entered.
+ virtual std::string RequestPassword(const std::string& slot_name, bool retry,
+ bool* cancelled) = 0;
+};
+
+}
+
+#endif // BASE_CRYPTO_CRYPTO_MODULE_BLOCKING_PASSWORD_DELEGATE_H_
diff --git a/base/crypto/cssm_init.cc b/base/crypto/cssm_init.cc
index f588f30..570dcc3 100644
--- a/base/crypto/cssm_init.cc
+++ b/base/crypto/cssm_init.cc
@@ -7,6 +7,7 @@
#include <Security/SecBase.h>
#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
#include "base/singleton.h"
#include "base/synchronization/lock.h"
#include "base/sys_string_conversions.h"
@@ -20,16 +21,38 @@
namespace {
+void* CSSMMalloc(CSSM_SIZE size, void* alloc_ref) {
+ return malloc(size);
+}
+
+void CSSMFree(void* mem_ptr, void* alloc_ref) {
+ free(mem_ptr);
+}
+
+void* CSSMRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) {
+ return realloc(ptr, size);
+}
+
+void* CSSMCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) {
+ return calloc(num, size);
+}
+
class CSSMInitSingleton {
public:
static CSSMInitSingleton* GetInstance() {
- return Singleton<CSSMInitSingleton>::get();
+ return Singleton<CSSMInitSingleton,
+ LeakySingletonTraits<CSSMInitSingleton> >::get();
}
- CSSM_CSP_HANDLE csp_handle() const {return csp_handle_;}
+ CSSM_CSP_HANDLE csp_handle() const { return csp_handle_; }
+ CSSM_CL_HANDLE cl_handle() const { return cl_handle_; }
+ CSSM_TP_HANDLE tp_handle() const { return tp_handle_; }
private:
- CSSMInitSingleton() : inited_(false), loaded_(false), csp_handle_(NULL) {
+ CSSMInitSingleton()
+ : inited_(false), csp_loaded_(false), cl_loaded_(false),
+ tp_loaded_(false), csp_handle_(NULL), cl_handle_(NULL),
+ tp_handle_(NULL) {
static CSSM_VERSION version = {2, 0};
// TODO(wtc): what should our caller GUID be?
static const CSSM_GUID test_guid = {
@@ -50,13 +73,42 @@ class CSSMInitSingleton {
NOTREACHED();
return;
}
- loaded_ = true;
+ csp_loaded_ = true;
+ crtn = CSSM_ModuleLoad(
+ &gGuidAppleX509CL, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
+ if (crtn) {
+ NOTREACHED();
+ return;
+ }
+ cl_loaded_ = true;
+ crtn = CSSM_ModuleLoad(
+ &gGuidAppleX509TP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
+ if (crtn) {
+ NOTREACHED();
+ return;
+ }
+ tp_loaded_ = true;
+
+ const CSSM_API_MEMORY_FUNCS cssmMemoryFunctions = {
+ CSSMMalloc,
+ CSSMFree,
+ CSSMRealloc,
+ CSSMCalloc,
+ NULL
+ };
- crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version,
- &base::kCssmMemoryFunctions, 0,
+ crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &cssmMemoryFunctions, 0,
CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &csp_handle_);
DCHECK(crtn == CSSM_OK);
+ crtn = CSSM_ModuleAttach(&gGuidAppleX509CL, &version, &cssmMemoryFunctions,
+ 0, CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE,
+ NULL, 0, NULL, &cl_handle_);
+ DCHECK(crtn == CSSM_OK);
+ crtn = CSSM_ModuleAttach(&gGuidAppleX509TP, &version, &cssmMemoryFunctions,
+ 0, CSSM_SERVICE_TP, 0, CSSM_KEY_HIERARCHY_NONE,
+ NULL, 0, NULL, &tp_handle_);
+ DCHECK(crtn == CSSM_OK);
}
~CSSMInitSingleton() {
@@ -65,10 +117,26 @@ class CSSMInitSingleton {
CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_);
DCHECK(crtn == CSSM_OK);
}
- if (loaded_) {
+ if (cl_handle_) {
+ CSSM_RETURN crtn = CSSM_ModuleDetach(cl_handle_);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (tp_handle_) {
+ CSSM_RETURN crtn = CSSM_ModuleDetach(tp_handle_);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (csp_loaded_) {
crtn = CSSM_ModuleUnload(&gGuidAppleCSP, NULL, NULL);
DCHECK(crtn == CSSM_OK);
}
+ if (cl_loaded_) {
+ crtn = CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (tp_loaded_) {
+ crtn = CSSM_ModuleUnload(&gGuidAppleX509TP, NULL, NULL);
+ DCHECK(crtn == CSSM_OK);
+ }
if (inited_) {
crtn = CSSM_Terminate();
DCHECK(crtn == CSSM_OK);
@@ -76,8 +144,12 @@ class CSSMInitSingleton {
}
bool inited_; // True if CSSM_Init has been called successfully.
- bool loaded_; // True if CSSM_ModuleLoad has been called successfully.
+ bool csp_loaded_; // True if gGuidAppleCSP has been loaded
+ bool cl_loaded_; // True if gGuidAppleX509CL has been loaded.
+ bool tp_loaded_; // True if gGuidAppleX509TP has been loaded.
CSSM_CSP_HANDLE csp_handle_;
+ CSSM_CL_HANDLE cl_handle_;
+ CSSM_TP_HANDLE tp_handle_;
friend struct DefaultSingletonTraits<CSSMInitSingleton>;
};
@@ -87,18 +159,17 @@ class CSSMInitSingleton {
class SecurityServicesSingleton {
public:
static SecurityServicesSingleton* GetInstance() {
- return Singleton<SecurityServicesSingleton>::get();
+ return Singleton<SecurityServicesSingleton,
+ LeakySingletonTraits<SecurityServicesSingleton> >::get();
}
- ~SecurityServicesSingleton() {}
-
base::Lock& lock() { return lock_; }
private:
- friend class Singleton<SecurityServicesSingleton>;
friend struct DefaultSingletonTraits<SecurityServicesSingleton>;
SecurityServicesSingleton() {}
+ ~SecurityServicesSingleton() {}
base::Lock lock_;
@@ -117,45 +188,44 @@ CSSM_CSP_HANDLE GetSharedCSPHandle() {
return CSSMInitSingleton::GetInstance()->csp_handle();
}
-void* CSSMMalloc(CSSM_SIZE size, void *alloc_ref) {
- return malloc(size);
+CSSM_CL_HANDLE GetSharedCLHandle() {
+ return CSSMInitSingleton::GetInstance()->cl_handle();
}
-void CSSMFree(void* mem_ptr, void* alloc_ref) {
- free(mem_ptr);
+CSSM_TP_HANDLE GetSharedTPHandle() {
+ return CSSMInitSingleton::GetInstance()->tp_handle();
}
-void* CSSMRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) {
- return realloc(ptr, size);
+void* CSSMMalloc(CSSM_SIZE size) {
+ return ::CSSMMalloc(size, NULL);
}
-void* CSSMCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) {
- return calloc(num, size);
+void CSSMFree(void* ptr) {
+ ::CSSMFree(ptr, NULL);
}
-const CSSM_API_MEMORY_FUNCS kCssmMemoryFunctions = {
- CSSMMalloc,
- CSSMFree,
- CSSMRealloc,
- CSSMCalloc,
- NULL
-};
-
-void LogCSSMError(const char *fn_name, CSSM_RETURN err) {
+void LogCSSMError(const char* fn_name, CSSM_RETURN err) {
if (!err)
return;
- CFStringRef cfstr = SecCopyErrorMessageString(err, NULL);
- if (cfstr) {
- std::string err_name = SysCFStringRefToUTF8(cfstr);
- CFRelease(cfstr);
- LOG(ERROR) << fn_name << " returned " << err << " (" << err_name << ")";
- } else {
- LOG(ERROR) << fn_name << " returned " << err;
- }
+ base::mac::ScopedCFTypeRef<CFStringRef> cfstr(
+ SecCopyErrorMessageString(err, NULL));
+ LOG(ERROR) << fn_name << " returned " << err
+ << " (" << SysCFStringRefToUTF8(cfstr) << ")";
}
base::Lock& GetMacSecurityServicesLock() {
return SecurityServicesSingleton::GetInstance()->lock();
}
+ScopedCSSMData::ScopedCSSMData() {
+ memset(&data_, 0, sizeof(data_));
+}
+
+ScopedCSSMData::~ScopedCSSMData() {
+ if (data_.Data) {
+ CSSMFree(data_.Data);
+ data_.Data = NULL;
+ }
+}
+
} // namespace base
diff --git a/base/crypto/cssm_init.h b/base/crypto/cssm_init.h
index 5644d7e..b51a3b5 100644
--- a/base/crypto/cssm_init.h
+++ b/base/crypto/cssm_init.h
@@ -8,7 +8,7 @@
#include <Security/cssm.h>
-#include "base/scoped_ptr.h"
+#include "base/basictypes.h"
namespace base {
@@ -22,12 +22,22 @@ void EnsureCSSMInit();
// Returns the shared CSP handle used by CSSM functions.
CSSM_CSP_HANDLE GetSharedCSPHandle();
+// Returns the shared CL handle used by CSSM functions.
+CSSM_CL_HANDLE GetSharedCLHandle();
+
+// Returns the shared TP handle used by CSSM functions.
+CSSM_TP_HANDLE GetSharedTPHandle();
+
// Set of pointers to memory function wrappers that are required for CSSM
extern const CSSM_API_MEMORY_FUNCS kCssmMemoryFunctions;
// Utility function to log an error message including the error name.
void LogCSSMError(const char *function_name, CSSM_RETURN err);
+// Utility functions to allocate and release CSSM memory.
+void* CSSMMalloc(CSSM_SIZE size);
+void CSSMFree(void* ptr);
+
// The OS X certificate and key management wrappers over CSSM are not
// thread-safe. In particular, code that accesses the CSSM database is
// problematic.
@@ -35,6 +45,25 @@ void LogCSSMError(const char *function_name, CSSM_RETURN err);
// http://developer.apple.com/mac/library/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html
Lock& GetMacSecurityServicesLock();
+// Wrapper class for CSSM_DATA type. This should only be used when using the
+// CL/TP/CSP handles from above, since that's the only time we're guaranteed (or
+// supposed to be guaranteed) that our memory management functions will be used.
+// Apple's Sec* APIs manage their own memory so it shouldn't be used for those.
+// The constructor initializes data_ to zero and the destructor releases the
+// data properly.
+class ScopedCSSMData {
+ public:
+ ScopedCSSMData();
+ ~ScopedCSSMData();
+ operator CSSM_DATA*() { return &data_; }
+ CSSM_DATA* operator ->() { return &data_; }
+
+ private:
+ CSSM_DATA data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCSSMData);
+};
+
} // namespace base
#endif // BASE_CRYPTO_CSSM_INIT_H_
diff --git a/base/crypto/rsa_private_key.cc b/base/crypto/rsa_private_key.cc
index 75da7e4..024f741 100644
--- a/base/crypto/rsa_private_key.cc
+++ b/base/crypto/rsa_private_key.cc
@@ -4,6 +4,7 @@
#include "base/crypto/rsa_private_key.h"
+#include <algorithm>
#include <list>
#include "base/logging.h"
@@ -48,118 +49,6 @@ const uint8 PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = {
0x05, 0x00
};
-void PrivateKeyInfoCodec::PrependBytes(uint8* val,
- int start,
- int num_bytes,
- std::list<uint8>* data) {
- while (num_bytes > 0) {
- --num_bytes;
- data->push_front(val[start + num_bytes]);
- }
-}
-
-void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8>* data) {
- // The high bit is used to indicate whether additional octets are needed to
- // represent the length.
- if (size < 0x80) {
- data->push_front(static_cast<uint8>(size));
- } else {
- uint8 num_bytes = 0;
- while (size > 0) {
- data->push_front(static_cast<uint8>(size & 0xFF));
- size >>= 8;
- num_bytes++;
- }
- CHECK_LE(num_bytes, 4);
- data->push_front(0x80 | num_bytes);
- }
-}
-
-void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(uint8 type,
- uint32 length,
- std::list<uint8>* output) {
- PrependLength(length, output);
- output->push_front(type);
-}
-
-void PrivateKeyInfoCodec::PrependBitString(uint8* val,
- int num_bytes,
- std::list<uint8>* output) {
- // Start with the data.
- PrependBytes(val, 0, num_bytes, output);
- // Zero unused bits.
- output->push_front(0);
- // Add the length.
- PrependLength(num_bytes + 1, output);
- // Finally, add the bit string tag.
- output->push_front((uint8) kBitStringTag);
-}
-
-bool PrivateKeyInfoCodec::ReadLength(uint8** pos, uint8* end, uint32* result) {
- READ_ASSERT(*pos < end);
- int length = 0;
-
- // If the MSB is not set, the length is just the byte itself.
- if (!(**pos & 0x80)) {
- length = **pos;
- (*pos)++;
- } else {
- // Otherwise, the lower 7 indicate the length of the length.
- int length_of_length = **pos & 0x7F;
- READ_ASSERT(length_of_length <= 4);
- (*pos)++;
- READ_ASSERT(*pos + length_of_length < end);
-
- length = 0;
- for (int i = 0; i < length_of_length; ++i) {
- length <<= 8;
- length |= **pos;
- (*pos)++;
- }
- }
-
- READ_ASSERT(*pos + length <= end);
- if (result) *result = length;
- return true;
-}
-
-bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8** pos,
- uint8* end,
- uint8 expected_tag,
- uint32* length) {
- READ_ASSERT(*pos < end);
- READ_ASSERT(**pos == expected_tag);
- (*pos)++;
-
- return ReadLength(pos, end, length);
-}
-
-bool PrivateKeyInfoCodec::ReadSequence(uint8** pos, uint8* end) {
- return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
-}
-
-bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8** pos, uint8* end) {
- READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
- READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
- sizeof(kRsaAlgorithmIdentifier)) == 0);
- (*pos) += sizeof(kRsaAlgorithmIdentifier);
- return true;
-}
-
-bool PrivateKeyInfoCodec::ReadVersion(uint8** pos, uint8* end) {
- uint32 length = 0;
- if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
- return false;
-
- // The version should be zero.
- for (uint32 i = 0; i < length; ++i) {
- READ_ASSERT(**pos == 0x00);
- (*pos)++;
- }
-
- return true;
-}
-
PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian)
: big_endian_(big_endian) {}
@@ -200,19 +89,12 @@ bool PrivateKeyInfoCodec::Export(std::vector<uint8>* output) {
bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) {
// Create a sequence with the modulus (n) and public exponent (e).
- std::list<uint8> content;
- PrependInteger(&public_exponent_[0],
- static_cast<int>(public_exponent_.size()),
- &content);
- PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content);
- PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
-
- // Copy the sequence with n and e into a buffer.
std::vector<uint8> bit_string;
- for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
- bit_string.push_back(*i);
- content.clear();
+ if (!ExportPublicKey(&bit_string))
+ return false;
+
// Add the sequence as the contents of a bit string.
+ std::list<uint8> content;
PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()),
&content);
@@ -231,6 +113,23 @@ bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) {
return true;
}
+bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8>* output) {
+ // Create a sequence with the modulus (n) and public exponent (e).
+ std::list<uint8> content;
+ PrependInteger(&public_exponent_[0],
+ static_cast<int>(public_exponent_.size()),
+ &content);
+ PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content);
+ PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
+
+ // Copy everything into the output.
+ output->reserve(content.size());
+ for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
+ output->push_back(*i);
+
+ return true;
+}
+
bool PrivateKeyInfoCodec::Import(const std::vector<uint8>& input) {
if (input.empty()) {
return false;
@@ -321,6 +220,36 @@ bool PrivateKeyInfoCodec::ReadInteger(uint8** pos,
return ReadIntegerImpl(pos, end, out, big_endian_);
}
+bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(uint8** pos,
+ uint8* end,
+ size_t expected_size,
+ std::vector<uint8>* out) {
+ std::vector<uint8> temp;
+ if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian
+ return false;
+
+ int pad = expected_size - temp.size();
+ int index = 0;
+ if (out->size() == expected_size + 1) {
+ READ_ASSERT(out->front() == 0x00);
+ pad++;
+ index++;
+ } else {
+ READ_ASSERT(out->size() <= expected_size);
+ }
+
+ while (pad) {
+ out->push_back(0x00);
+ pad--;
+ }
+ out->insert(out->end(), temp.begin(), temp.end());
+
+ // Reverse output if little-endian.
+ if (!big_endian_)
+ reverse(out->begin(), out->end());
+ return true;
+}
+
bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8** pos,
uint8* end,
std::vector<uint8>* out,
@@ -346,33 +275,115 @@ bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8** pos,
return true;
}
-bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(uint8** pos,
- uint8* end,
- size_t expected_size,
- std::vector<uint8>* out) {
- std::vector<uint8> temp;
- if (!ReadIntegerImpl(pos, end, &temp, true)) // Big-Endian
- return false;
+void PrivateKeyInfoCodec::PrependBytes(uint8* val,
+ int start,
+ int num_bytes,
+ std::list<uint8>* data) {
+ while (num_bytes > 0) {
+ --num_bytes;
+ data->push_front(val[start + num_bytes]);
+ }
+}
- int pad = expected_size - temp.size();
- int index = 0;
- if (out->size() == expected_size + 1) {
- READ_ASSERT(out->front() == 0x00);
- pad++;
- index++;
+void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8>* data) {
+ // The high bit is used to indicate whether additional octets are needed to
+ // represent the length.
+ if (size < 0x80) {
+ data->push_front(static_cast<uint8>(size));
} else {
- READ_ASSERT(out->size() <= expected_size);
+ uint8 num_bytes = 0;
+ while (size > 0) {
+ data->push_front(static_cast<uint8>(size & 0xFF));
+ size >>= 8;
+ num_bytes++;
+ }
+ CHECK_LE(num_bytes, 4);
+ data->push_front(0x80 | num_bytes);
}
+}
- while (pad) {
- out->push_back(0x00);
- pad--;
+void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(uint8 type,
+ uint32 length,
+ std::list<uint8>* output) {
+ PrependLength(length, output);
+ output->push_front(type);
+}
+
+void PrivateKeyInfoCodec::PrependBitString(uint8* val,
+ int num_bytes,
+ std::list<uint8>* output) {
+ // Start with the data.
+ PrependBytes(val, 0, num_bytes, output);
+ // Zero unused bits.
+ output->push_front(0);
+ // Add the length.
+ PrependLength(num_bytes + 1, output);
+ // Finally, add the bit string tag.
+ output->push_front((uint8) kBitStringTag);
+}
+
+bool PrivateKeyInfoCodec::ReadLength(uint8** pos, uint8* end, uint32* result) {
+ READ_ASSERT(*pos < end);
+ int length = 0;
+
+ // If the MSB is not set, the length is just the byte itself.
+ if (!(**pos & 0x80)) {
+ length = **pos;
+ (*pos)++;
+ } else {
+ // Otherwise, the lower 7 indicate the length of the length.
+ int length_of_length = **pos & 0x7F;
+ READ_ASSERT(length_of_length <= 4);
+ (*pos)++;
+ READ_ASSERT(*pos + length_of_length < end);
+
+ length = 0;
+ for (int i = 0; i < length_of_length; ++i) {
+ length <<= 8;
+ length |= **pos;
+ (*pos)++;
+ }
+ }
+
+ READ_ASSERT(*pos + length <= end);
+ if (result) *result = length;
+ return true;
+}
+
+bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8** pos,
+ uint8* end,
+ uint8 expected_tag,
+ uint32* length) {
+ READ_ASSERT(*pos < end);
+ READ_ASSERT(**pos == expected_tag);
+ (*pos)++;
+
+ return ReadLength(pos, end, length);
+}
+
+bool PrivateKeyInfoCodec::ReadSequence(uint8** pos, uint8* end) {
+ return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
+}
+
+bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8** pos, uint8* end) {
+ READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
+ READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
+ sizeof(kRsaAlgorithmIdentifier)) == 0);
+ (*pos) += sizeof(kRsaAlgorithmIdentifier);
+ return true;
+}
+
+bool PrivateKeyInfoCodec::ReadVersion(uint8** pos, uint8* end) {
+ uint32 length = 0;
+ if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
+ return false;
+
+ // The version should be zero.
+ for (uint32 i = 0; i < length; ++i) {
+ READ_ASSERT(**pos == 0x00);
+ (*pos)++;
}
- out->insert(out->end(), temp.begin(), temp.end());
- // Reverse output if little-endian.
- if (!big_endian_)
- reverse(out->begin(), out->end());
return true;
}
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h
index 9b8b4fd..5357adc 100644
--- a/base/crypto/rsa_private_key.h
+++ b/base/crypto/rsa_private_key.h
@@ -64,6 +64,10 @@ class PrivateKeyInfoCodec {
// of the PublicKeyInfo structure to |output|.
bool ExportPublicKeyInfo(std::vector<uint8>* output);
+ // Exports the contents of the integer components to the ASN.1 DER encoding
+ // of the RSAPublicKey structure to |output|.
+ bool ExportPublicKey(std::vector<uint8>* output);
+
// Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input|
// and populates the integer components with |big_endian_| byte-significance.
// IMPORTANT NOTE: This is currently *not* security-approved for importing
@@ -215,6 +219,7 @@ class RSAPrivateKey {
HCRYPTKEY key() { return key_; }
#elif defined(OS_MACOSX)
CSSM_KEY_PTR key() { return &key_; }
+ CSSM_KEY_PTR public_key() { return &public_key_; }
#endif
// Exports the private key to a PKCS #1 PrivateKey block.
@@ -257,6 +262,7 @@ class RSAPrivateKey {
ScopedHCRYPTKEY key_;
#elif defined(OS_MACOSX)
CSSM_KEY key_;
+ CSSM_KEY public_key_;
#endif
DISALLOW_COPY_AND_ASSIGN(RSAPrivateKey);
diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc
index e46e93e..ede8014 100644
--- a/base/crypto/rsa_private_key_mac.cc
+++ b/base/crypto/rsa_private_key_mac.cc
@@ -26,14 +26,12 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
return NULL;
}
- CSSM_KEY public_key;
- memset(&public_key, 0, sizeof(CSSM_KEY));
CSSM_DATA label = { 9,
const_cast<uint8*>(reinterpret_cast<const uint8*>("temp_key")) };
crtn = CSSM_GenerateKeyPair(cc_handle,
CSSM_KEYUSE_VERIFY,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label,
- &public_key, CSSM_KEYUSE_SIGN,
+ result->public_key(), CSSM_KEYUSE_SIGN,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, NULL,
result->key());
CSSM_DeleteContext(cc_handle);
@@ -42,9 +40,6 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
return NULL;
}
- // Public key is not needed.
- CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key, CSSM_FALSE);
-
return result.release();
}
@@ -106,6 +101,46 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
return NULL;
}
+ // Extract a public key from the private key.
+ // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key
+ // format when attempting to generate certs, so use PKCS1 instead.
+ PrivateKeyInfoCodec codec(true);
+ std::vector<uint8> private_key_data;
+ private_key_data.assign(key.KeyData.Data,
+ key.KeyData.Data + key.KeyData.Length);
+ if (!codec.Import(private_key_data)) {
+ return NULL;
+ }
+ std::vector<uint8> public_key_data;
+ if (!codec.ExportPublicKey(&public_key_data)) {
+ return NULL;
+ }
+
+ CSSM_KEY* public_key = result->public_key();
+ size_t size = public_key_data.size();
+ public_key->KeyData.Data = reinterpret_cast<uint8*>(CSSMMalloc(size));
+ if (!public_key->KeyData.Data) {
+ NOTREACHED() << "CSSMMalloc failed";
+ return NULL;
+ }
+ memcpy(public_key->KeyData.Data, &public_key_data.front(), size);
+ public_key->KeyData.Length = size;
+ public_key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+ public_key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
+ public_key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
+ public_key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
+ public_key->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
+ public_key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
+ public_key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
+
+ crtn = CSSM_QueryKeySizeInBits(
+ base::GetSharedCSPHandle(), NULL, public_key, &key_size);
+ if (crtn) {
+ DLOG(ERROR) << "CSSM_QueryKeySizeInBits failed " << crtn;
+ return NULL;
+ }
+ public_key->KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
+
return result.release();
}
@@ -125,6 +160,7 @@ RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
RSAPrivateKey::RSAPrivateKey() {
memset(&key_, 0, sizeof(key_));
+ memset(&public_key_, 0, sizeof(public_key_));
EnsureCSSMInit();
}
@@ -133,6 +169,9 @@ RSAPrivateKey::~RSAPrivateKey() {
if (key_.KeyData.Data) {
CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE);
}
+ if (public_key_.KeyData.Data) {
+ CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key_, CSSM_FALSE);
+ }
}
bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc
index 7786521..202aa1d 100644
--- a/base/crypto/rsa_private_key_nss.cc
+++ b/base/crypto/rsa_private_key_nss.cc
@@ -41,28 +41,11 @@ static bool ReadAttribute(SECKEYPrivateKey* key,
namespace base {
-// static
-RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
- bool permanent,
- bool sensitive) {
- base::EnsureNSSInit();
-
- scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
-
- PK11SlotInfo *slot = GetDefaultNSSKeySlot();
- if (!slot)
- return NULL;
-
- PK11RSAGenParams param;
- param.keySizeInBits = num_bits;
- param.pe = 65537L;
- result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &param,
- &result->public_key_, permanent, sensitive, NULL);
- PK11_FreeSlot(slot);
- if (!result->key_)
- return NULL;
-
- return result.release();
+RSAPrivateKey::~RSAPrivateKey() {
+ if (key_)
+ SECKEY_DestroyPrivateKey(key_);
+ if (public_key_)
+ SECKEY_DestroyPublicKey(public_key_);
}
// static
@@ -80,41 +63,6 @@ RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
}
// static
-RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
- const std::vector<uint8>& input, bool permanent, bool sensitive) {
- // This method currently leaks some memory.
- // See http://crbug.com/34742.
- ANNOTATE_SCOPED_MEMORY_LEAK;
- base::EnsureNSSInit();
-
- scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
-
- PK11SlotInfo *slot = GetDefaultNSSKeySlot();
- if (!slot)
- return NULL;
-
- SECItem der_private_key_info;
- der_private_key_info.data = const_cast<unsigned char*>(&input.front());
- der_private_key_info.len = input.size();
- SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot,
- &der_private_key_info, NULL, NULL, permanent, sensitive,
- KU_DIGITAL_SIGNATURE, &result->key_, NULL);
- PK11_FreeSlot(slot);
- if (rv != SECSuccess) {
- NOTREACHED();
- return NULL;
- }
-
- result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
- if (!result->public_key_) {
- NOTREACHED();
- return NULL;
- }
-
- return result.release();
-}
-
-// static
RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
const std::vector<uint8>& input) {
return CreateFromPrivateKeyInfoWithParams(input,
@@ -193,16 +141,6 @@ RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
return result.release();
}
-RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
- EnsureNSSInit();
-}
-
-RSAPrivateKey::~RSAPrivateKey() {
- if (key_)
- SECKEY_DestroyPrivateKey(key_);
- if (public_key_)
- SECKEY_DestroyPublicKey(public_key_);
-}
bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
PrivateKeyInfoCodec private_key_info(true);
@@ -240,4 +178,71 @@ bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
return true;
}
+RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
+ EnsureNSSInit();
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
+ bool permanent,
+ bool sensitive) {
+ base::EnsureNSSInit();
+
+ scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
+
+ PK11SlotInfo *slot = GetDefaultNSSKeySlot();
+ if (!slot)
+ return NULL;
+
+ PK11RSAGenParams param;
+ param.keySizeInBits = num_bits;
+ param.pe = 65537L;
+ result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &param,
+ &result->public_key_, permanent, sensitive, NULL);
+ PK11_FreeSlot(slot);
+ if (!result->key_)
+ return NULL;
+
+ return result.release();
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
+ const std::vector<uint8>& input, bool permanent, bool sensitive) {
+ // This method currently leaks some memory.
+ // See http://crbug.com/34742.
+ ANNOTATE_SCOPED_MEMORY_LEAK;
+ base::EnsureNSSInit();
+
+ scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
+
+ PK11SlotInfo *slot = GetDefaultNSSKeySlot();
+ if (!slot)
+ return NULL;
+
+ SECItem der_private_key_info;
+ der_private_key_info.data = const_cast<unsigned char*>(&input.front());
+ der_private_key_info.len = input.size();
+ // Allow the private key to be used for key unwrapping, data decryption,
+ // and signature generation.
+ const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
+ KU_DIGITAL_SIGNATURE;
+ SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
+ key_usage, &result->key_, NULL);
+ PK11_FreeSlot(slot);
+ if (rv != SECSuccess) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
+ if (!result->public_key_) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return result.release();
+}
+
} // namespace base
diff --git a/base/crypto/secure_hash.h b/base/crypto/secure_hash.h
new file mode 100644
index 0000000..3759218
--- /dev/null
+++ b/base/crypto/secure_hash.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_CRYPTO_SECURE_HASH_H_
+#define BASE_CRYPTO_SECURE_HASH_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// A wrapper to calculate secure hashes incrementally, allowing to
+// be used when the full input is not known in advance.
+class SecureHash {
+ public:
+ enum Algorithm {
+ SHA256,
+ };
+ virtual ~SecureHash() {}
+
+ static SecureHash* Create(Algorithm type);
+
+ virtual void Update(const void* input, size_t len) = 0;
+ virtual void Finish(void* output, size_t len) = 0;
+
+ protected:
+ SecureHash() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SecureHash);
+};
+
+} // namespace base
+
+#endif // BASE_CRYPTO_SECURE_HASH_H_
diff --git a/base/crypto/secure_hash_default.cc b/base/crypto/secure_hash_default.cc
new file mode 100644
index 0000000..436867e
--- /dev/null
+++ b/base/crypto/secure_hash_default.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 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/crypto/secure_hash.h"
+
+#include "base/logging.h"
+#include "base/third_party/nss/blapi.h"
+#include "base/third_party/nss/sha256.h"
+
+namespace base {
+
+namespace {
+
+class SecureHashSHA256NSS : public SecureHash {
+ public:
+ SecureHashSHA256NSS() {
+ SHA256_Begin(&ctx_);
+ }
+
+ virtual ~SecureHashSHA256NSS() {
+ }
+
+ virtual void Update(const void* input, size_t len) {
+ SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len);
+ }
+
+ virtual void Finish(void* output, size_t len) {
+ SHA256_End(&ctx_, static_cast<unsigned char*>(output), NULL,
+ static_cast<unsigned int>(len));
+ }
+
+ private:
+ SHA256Context ctx_;
+};
+
+} // namespace
+
+SecureHash* SecureHash::Create(Algorithm algorithm) {
+ switch (algorithm) {
+ case SHA256:
+ return new SecureHashSHA256NSS();
+ default:
+ NOTIMPLEMENTED();
+ return NULL;
+ }
+}
+
+} // namespace base
diff --git a/base/crypto/secure_hash_openssl.cc b/base/crypto/secure_hash_openssl.cc
new file mode 100644
index 0000000..8087279
--- /dev/null
+++ b/base/crypto/secure_hash_openssl.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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/crypto/secure_hash.h"
+
+#include <openssl/ssl.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/openssl_util.h"
+
+namespace base {
+
+namespace {
+
+class SecureHashSHA256OpenSSL : public SecureHash {
+ public:
+ SecureHashSHA256OpenSSL() {
+ SHA256_Init(&ctx_);
+ }
+
+ virtual ~SecureHashSHA256OpenSSL() {
+ OPENSSL_cleanse(&ctx_, sizeof(ctx_));
+ }
+
+ virtual void Update(const void* input, size_t len) {
+ SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len);
+ }
+
+ virtual void Finish(void* output, size_t len) {
+ ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result(
+ static_cast<unsigned char*>(output), len);
+ SHA256_Final(result.safe_buffer(), &ctx_);
+ }
+
+ private:
+ SHA256_CTX ctx_;
+};
+
+} // namespace
+
+SecureHash* SecureHash::Create(Algorithm algorithm) {
+ switch (algorithm) {
+ case SHA256:
+ return new SecureHashSHA256OpenSSL();
+ default:
+ NOTIMPLEMENTED();
+ return NULL;
+ }
+}
+
+} // namespace base
diff --git a/base/crypto/secure_hash_unittest.cc b/base/crypto/secure_hash_unittest.cc
new file mode 100644
index 0000000..2dac928
--- /dev/null
+++ b/base/crypto/secure_hash_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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/crypto/secure_hash.h"
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/sha2.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SecureHashTest, TestUpdate) {
+ // Example B.3 from FIPS 180-2: long message.
+ std::string input3(500000, 'a'); // 'a' repeated half a million times
+ int expected3[] = { 0xcd, 0xc7, 0x6e, 0x5c,
+ 0x99, 0x14, 0xfb, 0x92,
+ 0x81, 0xa1, 0xc7, 0xe2,
+ 0x84, 0xd7, 0x3e, 0x67,
+ 0xf1, 0x80, 0x9a, 0x48,
+ 0xa4, 0x97, 0x20, 0x0e,
+ 0x04, 0x6d, 0x39, 0xcc,
+ 0xc7, 0x11, 0x2c, 0xd0 };
+
+ uint8 output3[base::SHA256_LENGTH];
+
+ scoped_ptr<base::SecureHash> ctx(base::SecureHash::Create(
+ base::SecureHash::SHA256));
+ ctx->Update(input3.data(), input3.size());
+ ctx->Update(input3.data(), input3.size());
+
+ ctx->Finish(output3, sizeof(output3));
+ for (size_t i = 0; i < base::SHA256_LENGTH; i++)
+ EXPECT_EQ(expected3[i], static_cast<int>(output3[i]));
+}
diff --git a/base/crypto/signature_creator_mac.cc b/base/crypto/signature_creator_mac.cc
index d10d54c..1001c64 100644
--- a/base/crypto/signature_creator_mac.cc
+++ b/base/crypto/signature_creator_mac.cc
@@ -59,19 +59,15 @@ bool SignatureCreator::Update(const uint8* data_part, int data_part_len) {
}
bool SignatureCreator::Final(std::vector<uint8>* signature) {
- CSSM_DATA sig;
- memset(&sig, 0, sizeof(CSSM_DATA)); // Allow CSSM allocate memory;
- CSSM_RETURN crtn = CSSM_SignDataFinal(sig_handle_, &sig);
+ ScopedCSSMData sig;
+ CSSM_RETURN crtn = CSSM_SignDataFinal(sig_handle_, sig);
if (crtn) {
NOTREACHED();
return false;
}
- signature->assign(sig.Data, sig.Data + sig.Length);
- kCssmMemoryFunctions.free_func(sig.Data, NULL); // Release data alloc'd
- // by CSSM
-
+ signature->assign(sig->Data, sig->Data + sig->Length);
return true;
}
diff --git a/base/crypto/signature_creator_nss.cc b/base/crypto/signature_creator_nss.cc
index ff1d271..4cc2c10 100644
--- a/base/crypto/signature_creator_nss.cc
+++ b/base/crypto/signature_creator_nss.cc
@@ -14,6 +14,13 @@
namespace base {
+SignatureCreator::~SignatureCreator() {
+ if (sign_context_) {
+ SGN_DestroyContext(sign_context_, PR_TRUE);
+ sign_context_ = NULL;
+ }
+}
+
// static
SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) {
scoped_ptr<SignatureCreator> result(new SignatureCreator);
@@ -35,17 +42,6 @@ SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) {
return result.release();
}
-SignatureCreator::SignatureCreator() : sign_context_(NULL) {
- EnsureNSSInit();
-}
-
-SignatureCreator::~SignatureCreator() {
- if (sign_context_) {
- SGN_DestroyContext(sign_context_, PR_TRUE);
- sign_context_ = NULL;
- }
-}
-
bool SignatureCreator::Update(const uint8* data_part, int data_part_len) {
// TODO(wtc): Remove this const_cast when we require NSS 3.12.5.
// See NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=518255
@@ -73,4 +69,8 @@ bool SignatureCreator::Final(std::vector<uint8>* signature) {
return true;
}
+SignatureCreator::SignatureCreator() : sign_context_(NULL) {
+ EnsureNSSInit();
+}
+
} // namespace base
diff --git a/base/crypto/symmetric_key_nss.cc b/base/crypto/symmetric_key_nss.cc
index d291e8d..1e3551d 100644
--- a/base/crypto/symmetric_key_nss.cc
+++ b/base/crypto/symmetric_key_nss.cc
@@ -12,10 +12,6 @@
namespace base {
-SymmetricKey::SymmetricKey(PK11SymKey* key) : key_(key) {
- DCHECK(key);
-}
-
SymmetricKey::~SymmetricKey() {}
// static
@@ -124,4 +120,8 @@ bool SymmetricKey::GetRawKey(std::string* raw_key) {
return true;
}
+SymmetricKey::SymmetricKey(PK11SymKey* key) : key_(key) {
+ DCHECK(key);
+}
+
} // namespace base
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
index b865e65..2eacaf9 100644
--- a/base/debug/debugger_posix.cc
+++ b/base/debug/debugger_posix.cc
@@ -174,6 +174,9 @@ bool BeingDebugged() {
void BreakDebugger() {
DEBUG_BREAK();
+#if defined(NDEBUG)
+ _exit(1);
+#endif
}
} // namespace debug
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
index 3323b61..b13dbfd 100644
--- a/base/debug/debugger_win.cc
+++ b/base/debug/debugger_win.cc
@@ -105,6 +105,9 @@ void BreakDebugger() {
if (IsDebugUISuppressed())
_exit(1);
__debugbreak();
+#if defined(NDEBUG)
+ _exit(1);
+#endif
}
} // namespace debug
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
new file mode 100644
index 0000000..8597dac
--- /dev/null
+++ b/base/debug/profiler.cc
@@ -0,0 +1,65 @@
+// 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/debug/profiler.h"
+
+#include <string>
+
+#include "base/process_util.h"
+#include "base/string_util.h"
+
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
+#include "third_party/tcmalloc/chromium/src/google/profiler.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
+
+static int profile_count = 0;
+
+void StartProfiling(const std::string& name) {
+ ++profile_count;
+ std::string full_name(name);
+ std::string pid = StringPrintf("%d", GetCurrentProcId());
+ std::string count = StringPrintf("%d", profile_count);
+ ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
+ ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
+ ProfilerStart(full_name.c_str());
+}
+
+void StopProfiling() {
+ ProfilerFlush();
+ ProfilerStop();
+}
+
+void FlushProfiling() {
+ ProfilerFlush();
+}
+
+bool BeingProfiled() {
+ return ProfilingIsEnabledForAllThreads();
+}
+
+#else
+
+void StartProfiling(const std::string& name) {
+}
+
+void StopProfiling() {
+}
+
+void FlushProfiling() {
+}
+
+bool BeingProfiled() {
+ return false;
+}
+
+#endif
+
+} // namespace debug
+} // namespace base
+
diff --git a/base/debug/profiler.h b/base/debug/profiler.h
new file mode 100644
index 0000000..e3044d6
--- /dev/null
+++ b/base/debug/profiler.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_DEBUG_PROFILER_H
+#define BASE_DEBUG_PROFILER_H
+#pragma once
+
+#include <string>
+
+// The Profiler functions allow usage of the underlying sampling based
+// profiler. If the application has not been built with the necessary
+// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
+// are noops.
+namespace base {
+namespace debug {
+
+// Start profiling with the supplied name.
+// {pid} will be replaced by the process' pid and {count} will be replaced
+// by the count of the profile run (starts at 1 with each process).
+void StartProfiling(const std::string& name);
+
+// Stop profiling and write out data.
+void StopProfiling();
+
+// Force data to be written to file.
+void FlushProfiling();
+
+// Returns true if process is being profiled.
+bool BeingProfiled();
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_DEBUGGER_H
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
index 6f4ad02..510d35b 100644
--- a/base/debug/stack_trace_win.cc
+++ b/base/debug/stack_trace_win.cc
@@ -10,9 +10,9 @@
#include <iostream>
#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/logging.h"
#include "base/singleton.h"
+#include "base/synchronization/lock.h"
namespace base {
namespace debug {
@@ -59,7 +59,7 @@ class SymbolContext {
void OutputTraceToStream(const void* const* trace,
int count,
std::ostream* os) {
- AutoLock lock(lock_);
+ base::AutoLock lock(lock_);
for (size_t i = 0; (i < count) && os->good(); ++i) {
const int kMaxNameLength = 256;
@@ -129,7 +129,7 @@ class SymbolContext {
}
DWORD init_error_;
- Lock lock_;
+ base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(SymbolContext);
};
diff --git a/base/debug/trace_event.cc b/base/debug/trace_event.cc
index f50422c..36a3944 100644
--- a/base/debug/trace_event.cc
+++ b/base/debug/trace_event.cc
@@ -28,22 +28,6 @@ static const char* kEventTypeNames[] = {
static const FilePath::CharType* kLogFileName =
FILE_PATH_LITERAL("trace_%d.log");
-TraceLog::TraceLog() : enabled_(false), log_file_(NULL) {
- base::ProcessHandle proc = base::GetCurrentProcessHandle();
-#if !defined(OS_MACOSX)
- process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc));
-#else
- // The default port provider is sufficient to get data for the current
- // process.
- process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc,
- NULL));
-#endif
-}
-
-TraceLog::~TraceLog() {
- Stop();
-}
-
// static
TraceLog* TraceLog::GetInstance() {
return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get();
@@ -59,61 +43,11 @@ bool TraceLog::StartTracing() {
return TraceLog::GetInstance()->Start();
}
-bool TraceLog::Start() {
- if (enabled_)
- return true;
- enabled_ = OpenLogFile();
- if (enabled_) {
- Log("var raw_trace_events = [\n");
- trace_start_time_ = TimeTicks::Now();
- timer_.Start(TimeDelta::FromMilliseconds(250), this, &TraceLog::Heartbeat);
- }
- return enabled_;
-}
-
// static
void TraceLog::StopTracing() {
return TraceLog::GetInstance()->Stop();
}
-void TraceLog::Stop() {
- if (enabled_) {
- enabled_ = false;
- Log("];\n");
- CloseLogFile();
- timer_.Stop();
- }
-}
-
-void TraceLog::Heartbeat() {
- std::string cpu = StringPrintf("%.0f", process_metrics_->GetCPUUsage());
- TRACE_EVENT_INSTANT("heartbeat.cpu", 0, cpu);
-}
-
-void TraceLog::CloseLogFile() {
- if (log_file_) {
- file_util::CloseFile(log_file_);
- }
-}
-
-bool TraceLog::OpenLogFile() {
- FilePath::StringType pid_filename =
- StringPrintf(kLogFileName, base::GetCurrentProcId());
- FilePath log_file_path;
- if (!PathService::Get(base::DIR_EXE, &log_file_path))
- return false;
- log_file_path = log_file_path.Append(pid_filename);
- log_file_ = file_util::OpenFile(log_file_path, "a");
- if (!log_file_) {
- // try the current directory
- log_file_ = file_util::OpenFile(FilePath(pid_filename), "a");
- if (!log_file_) {
- return false;
- }
- }
- return true;
-}
-
void TraceLog::Trace(const std::string& name,
EventType type,
const void* id,
@@ -158,6 +92,72 @@ void TraceLog::Trace(const std::string& name,
Log(msg);
}
+TraceLog::TraceLog() : enabled_(false), log_file_(NULL) {
+ base::ProcessHandle proc = base::GetCurrentProcessHandle();
+#if !defined(OS_MACOSX)
+ process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc));
+#else
+ // The default port provider is sufficient to get data for the current
+ // process.
+ process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc,
+ NULL));
+#endif
+}
+
+TraceLog::~TraceLog() {
+ Stop();
+}
+
+bool TraceLog::OpenLogFile() {
+ FilePath::StringType pid_filename =
+ StringPrintf(kLogFileName, base::GetCurrentProcId());
+ FilePath log_file_path;
+ if (!PathService::Get(base::DIR_EXE, &log_file_path))
+ return false;
+ log_file_path = log_file_path.Append(pid_filename);
+ log_file_ = file_util::OpenFile(log_file_path, "a");
+ if (!log_file_) {
+ // try the current directory
+ log_file_ = file_util::OpenFile(FilePath(pid_filename), "a");
+ if (!log_file_) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void TraceLog::CloseLogFile() {
+ if (log_file_) {
+ file_util::CloseFile(log_file_);
+ }
+}
+
+bool TraceLog::Start() {
+ if (enabled_)
+ return true;
+ enabled_ = OpenLogFile();
+ if (enabled_) {
+ Log("var raw_trace_events = [\n");
+ trace_start_time_ = TimeTicks::Now();
+ timer_.Start(TimeDelta::FromMilliseconds(250), this, &TraceLog::Heartbeat);
+ }
+ return enabled_;
+}
+
+void TraceLog::Stop() {
+ if (enabled_) {
+ enabled_ = false;
+ Log("];\n");
+ CloseLogFile();
+ timer_.Stop();
+ }
+}
+
+void TraceLog::Heartbeat() {
+ std::string cpu = StringPrintf("%.0f", process_metrics_->GetCPUUsage());
+ TRACE_EVENT_INSTANT("heartbeat.cpu", 0, cpu);
+}
+
void TraceLog::Log(const std::string& msg) {
AutoLock lock(file_lock_);
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
index 476f065..e5c2cbd 100644
--- a/base/debug/trace_event.h
+++ b/base/debug/trace_event.h
@@ -31,9 +31,9 @@
#include <string>
-#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
+#include "base/synchronization/lock.h"
#include "base/time.h"
#include "base/timer.h"
@@ -135,7 +135,7 @@ class TraceLog {
bool enabled_;
FILE* log_file_;
- Lock file_lock_;
+ base::Lock file_lock_;
TimeTicks trace_start_time_;
#ifndef ANDROID
scoped_ptr<base::ProcessMetrics> process_metrics_;
diff --git a/base/event_recorder.h b/base/event_recorder.h
index 04fbaa1..e4d8907 100644
--- a/base/event_recorder.h
+++ b/base/event_recorder.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -80,6 +80,9 @@ class EventRecorder {
#endif
playback_first_msg_time_(0),
playback_start_time_(0) {
+#if defined(OS_WIN)
+ memset(&playback_msg_, 0, sizeof(playback_msg_));
+#endif
}
~EventRecorder();
diff --git a/base/file_path.cc b/base/file_path.cc
index cddb17e..5f1375a 100644
--- a/base/file_path.cc
+++ b/base/file_path.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+
#include "base/file_path.h"
#if defined(OS_WIN)
@@ -511,10 +513,14 @@ bool FilePath::ReferencesParent() const {
}
#if defined(OS_POSIX)
-
// See file_path.h for a discussion of the encoding of paths on POSIX
-// platforms. These *Hack() functions are not quite correct, but they're
-// only temporary while we fix the remainder of the code.
+// platforms. These encoding conversion functions are not quite correct.
+
+string16 FilePath::LossyDisplayName() const {
+ return WideToUTF16(base::SysNativeMBToWide(path_));
+}
+
+// The *Hack functions are temporary while we fix the remainder of the code.
// Remember to remove the #includes at the top when you remove these.
// static
@@ -525,6 +531,10 @@ std::wstring FilePath::ToWStringHack() const {
return base::SysNativeMBToWide(path_);
}
#elif defined(OS_WIN)
+string16 FilePath::LossyDisplayName() const {
+ return path_;
+}
+
// static
FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
return FilePath(wstring);
diff --git a/base/file_path.h b/base/file_path.h
index 01cd4a5..84bb350 100644
--- a/base/file_path.h
+++ b/base/file_path.h
@@ -277,6 +277,12 @@ class FilePath {
// directory (i.e. has a path component that is ".."
bool ReferencesParent() const;
+ // Return a Unicode human-readable version of this path.
+ // Warning: you can *not*, in general, go from a display name back to a real
+ // path. Only use this when displaying paths to users, not just when you
+ // want to stuff a string16 into some other API.
+ string16 LossyDisplayName() const;
+
// Older Chromium code assumes that paths are always wstrings.
// These functions convert wstrings to/from FilePaths, and are
// useful to smooth porting that old code to the FilePath API.
@@ -290,6 +296,9 @@ class FilePath {
// OS-native string format.
// - Am I using well-known file names, like "config.ini"? Then use the
// ASCII functions (we require paths to always be supersets of ASCII).
+ // - Am I displaying a string to the user in some UI? Then use the
+ // LossyDisplayName() function, but keep in mind that you can't
+ // ever use the result of that again as a path.
static FilePath FromWStringHack(const std::wstring& wstring);
std::wstring ToWStringHack() const;
diff --git a/base/file_util.cc b/base/file_util.cc
index d1a46c9..c9661e7 100644
--- a/base/file_util.cc
+++ b/base/file_util.cc
@@ -315,13 +315,11 @@ MemoryMappedFile::~MemoryMappedFile() {
CloseHandles();
}
-bool MemoryMappedFile::Initialize(base::PlatformFile file) {
+bool MemoryMappedFile::Initialize(const FilePath& file_name) {
if (IsValid())
return false;
- file_ = file;
-
- if (!MapFileToMemoryInternal()) {
+ if (!MapFileToMemory(file_name)) {
CloseHandles();
return false;
}
@@ -329,11 +327,13 @@ bool MemoryMappedFile::Initialize(base::PlatformFile file) {
return true;
}
-bool MemoryMappedFile::Initialize(const FilePath& file_name) {
+bool MemoryMappedFile::Initialize(base::PlatformFile file) {
if (IsValid())
return false;
- if (!MapFileToMemory(file_name)) {
+ file_ = file;
+
+ if (!MapFileToMemoryInternal()) {
CloseHandles();
return false;
}
@@ -341,6 +341,10 @@ bool MemoryMappedFile::Initialize(const FilePath& file_name) {
return true;
}
+bool MemoryMappedFile::IsValid() {
+ return data_ != NULL;
+}
+
bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
file_ = base::CreatePlatformFile(
file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
@@ -354,10 +358,6 @@ bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
return MapFileToMemoryInternal();
}
-bool MemoryMappedFile::IsValid() {
- return data_ != NULL;
-}
-
// Deprecated functions ----------------------------------------------------
#if defined(OS_WIN)
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 475918e..7dd4127 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -641,26 +641,6 @@ FileEnumerator::FileEnumerator(const FilePath& root_path,
FileEnumerator::~FileEnumerator() {
}
-void FileEnumerator::GetFindInfo(FindInfo* info) {
- DCHECK(info);
-
- if (current_directory_entry_ >= directory_entries_.size())
- return;
-
- DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
- memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
- info->filename.assign(cur_entry->filename.value());
-}
-
-bool FileEnumerator::IsDirectory(const FindInfo& info) {
- return S_ISDIR(info.stat.st_mode);
-}
-
-// static
-FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
- return FilePath(find_info.filename);
-}
-
FilePath FileEnumerator::Next() {
++current_directory_entry_;
@@ -702,6 +682,26 @@ FilePath FileEnumerator::Next() {
].filename);
}
+void FileEnumerator::GetFindInfo(FindInfo* info) {
+ DCHECK(info);
+
+ if (current_directory_entry_ >= directory_entries_.size())
+ return;
+
+ DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
+ memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
+ info->filename.assign(cur_entry->filename.value());
+}
+
+bool FileEnumerator::IsDirectory(const FindInfo& info) {
+ return S_ISDIR(info.stat.st_mode);
+}
+
+// static
+FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
+ return FilePath(find_info.filename);
+}
+
bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
const FilePath& source, bool show_links) {
base::ThreadRestrictions::AssertIOAllowed();
diff --git a/base/file_util_proxy.cc b/base/file_util_proxy.cc
index bd08909..d357e98 100644
--- a/base/file_util_proxy.cc
+++ b/base/file_util_proxy.cc
@@ -525,12 +525,11 @@ class RelayRead : public MessageLoopRelay {
public:
RelayRead(base::PlatformFile file,
int64 offset,
- char* buffer,
int bytes_to_read,
- base::FileUtilProxy::ReadWriteCallback* callback)
+ base::FileUtilProxy::ReadCallback* callback)
: file_(file),
offset_(offset),
- buffer_(buffer),
+ buffer_(new char[bytes_to_read]),
bytes_to_read_(bytes_to_read),
callback_(callback),
bytes_read_(0) {
@@ -538,7 +537,7 @@ class RelayRead : public MessageLoopRelay {
protected:
virtual void RunWork() {
- bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_,
+ bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_.get(),
bytes_to_read_);
if (bytes_read_ < 0)
set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
@@ -546,7 +545,7 @@ class RelayRead : public MessageLoopRelay {
virtual void RunCallback() {
if (callback_) {
- callback_->Run(error_code(), bytes_read_);
+ callback_->Run(error_code(), buffer_.get(), bytes_read_);
delete callback_;
}
}
@@ -554,9 +553,9 @@ class RelayRead : public MessageLoopRelay {
private:
base::PlatformFile file_;
int64 offset_;
- char* buffer_;
+ scoped_array<char> buffer_;
int bytes_to_read_;
- base::FileUtilProxy::ReadWriteCallback* callback_;
+ base::FileUtilProxy::ReadCallback* callback_;
int bytes_read_;
};
@@ -566,17 +565,18 @@ class RelayWrite : public MessageLoopRelay {
int64 offset,
const char* buffer,
int bytes_to_write,
- base::FileUtilProxy::ReadWriteCallback* callback)
+ base::FileUtilProxy::WriteCallback* callback)
: file_(file),
offset_(offset),
- buffer_(buffer),
+ buffer_(new char[bytes_to_write]),
bytes_to_write_(bytes_to_write),
callback_(callback) {
+ memcpy(buffer_.get(), buffer, bytes_to_write);
}
protected:
virtual void RunWork() {
- bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_,
+ bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_.get(),
bytes_to_write_);
if (bytes_written_ < 0)
set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
@@ -592,9 +592,9 @@ class RelayWrite : public MessageLoopRelay {
private:
base::PlatformFile file_;
int64 offset_;
- const char* buffer_;
+ scoped_array<char> buffer_;
int bytes_to_write_;
- base::FileUtilProxy::ReadWriteCallback* callback_;
+ base::FileUtilProxy::WriteCallback* callback_;
int bytes_written_;
};
@@ -747,17 +747,6 @@ bool FileUtilProxy::CreateTemporary(
}
// static
-bool FileUtilProxy::CreateDirectory(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- const FilePath& file_path,
- bool exclusive,
- bool recursive,
- StatusCallback* callback) {
- return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
- file_path, exclusive, recursive, callback));
-}
-
-// static
bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
base::PlatformFile file_handle,
StatusCallback* callback) {
@@ -774,13 +763,43 @@ bool FileUtilProxy::EnsureFileExists(
message_loop_proxy, file_path, callback));
}
+// Retrieves the information about a file. It is invalid to pass NULL for the
+// callback.
+bool FileUtilProxy::GetFileInfo(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ GetFileInfoCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
+ file_path, callback));
+}
+
// static
-bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
- const FilePath& file_path,
- bool recursive,
- StatusCallback* callback) {
+bool FileUtilProxy::GetFileInfoFromPlatformFile(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ GetFileInfoCallback* callback) {
return Start(FROM_HERE, message_loop_proxy,
- new RelayDelete(file_path, recursive, callback));
+ new RelayGetFileInfoFromPlatformFile(file, callback));
+}
+
+// static
+bool FileUtilProxy::ReadDirectory(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ ReadDirectoryCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
+ file_path, callback));
+}
+
+// static
+bool FileUtilProxy::CreateDirectory(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
+ file_path, exclusive, recursive, callback));
}
// static
@@ -802,22 +821,12 @@ bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,
}
// static
-bool FileUtilProxy::ReadDirectory(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- const FilePath& file_path,
- ReadDirectoryCallback* callback) {
- return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
- file_path, callback));
-}
-
-// Retrieves the information about a file. It is invalid to pass NULL for the
-// callback.
-bool FileUtilProxy::GetFileInfo(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- const FilePath& file_path,
- GetFileInfoCallback* callback) {
- return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
- file_path, callback));
+bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ bool recursive,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayDelete(file_path, recursive, callback));
}
// static
@@ -830,24 +839,14 @@ bool FileUtilProxy::RecursiveDelete(
}
// static
-bool FileUtilProxy::GetFileInfoFromPlatformFile(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- PlatformFile file,
- GetFileInfoCallback* callback) {
- return Start(FROM_HERE, message_loop_proxy,
- new RelayGetFileInfoFromPlatformFile(file, callback));
-}
-
-// static
bool FileUtilProxy::Read(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
PlatformFile file,
int64 offset,
- char* buffer,
int bytes_to_read,
- ReadWriteCallback* callback) {
+ ReadCallback* callback) {
return Start(FROM_HERE, message_loop_proxy,
- new RelayRead(file, offset, buffer, bytes_to_read, callback));
+ new RelayRead(file, offset, bytes_to_read, callback));
}
// static
@@ -857,7 +856,7 @@ bool FileUtilProxy::Write(
int64 offset,
const char* buffer,
int bytes_to_write,
- ReadWriteCallback* callback) {
+ WriteCallback* callback) {
return Start(FROM_HERE, message_loop_proxy,
new RelayWrite(file, offset, buffer, bytes_to_write, callback));
}
diff --git a/base/file_util_proxy.h b/base/file_util_proxy.h
index 4181a26..f2368cc 100644
--- a/base/file_util_proxy.h
+++ b/base/file_util_proxy.h
@@ -46,8 +46,11 @@ class FileUtilProxy {
>::Type GetFileInfoCallback;
typedef Callback2<PlatformFileError /* error code */,
const std::vector<Entry>&>::Type ReadDirectoryCallback;
+ typedef Callback3<PlatformFileError /* error code */,
+ const char* /* data */,
+ int /* bytes read/written */>::Type ReadCallback;
typedef Callback2<PlatformFileError /* error code */,
- int /* bytes read/written */>::Type ReadWriteCallback;
+ int /* bytes written */>::Type WriteCallback;
// Creates or opens a file with the given flags. It is invalid to pass NULL
// for the callback.
@@ -100,6 +103,15 @@ class FileUtilProxy {
const FilePath& file_path,
ReadDirectoryCallback* callback);
+ // Creates directory at given path. It's an error to create
+ // if |exclusive| is true and dir already exists.
+ static bool CreateDirectory(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive,
+ StatusCallback* callback);
+
// Copies a file or a directory from |src_file_path| to |dest_file_path|
// Error cases:
// If destination file doesn't exist or destination's parent
@@ -113,13 +125,12 @@ class FileUtilProxy {
const FilePath& dest_file_path,
StatusCallback* callback);
- // Creates directory at given path. It's an error to create
- // if |exclusive| is true and dir already exists.
- static bool CreateDirectory(
+ // Moves a file or a directory from src_file_path to dest_file_path.
+ // Error cases are similar to Copy method's error cases.
+ static bool Move(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- const FilePath& file_path,
- bool exclusive,
- bool recursive,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path,
StatusCallback* callback);
// Deletes a file or a directory.
@@ -129,14 +140,6 @@ class FileUtilProxy {
bool recursive,
StatusCallback* callback);
- // Moves a file or a directory from src_file_path to dest_file_path.
- // Error cases are similar to Copy method's error cases.
- static bool Move(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- const FilePath& src_file_path,
- const FilePath& dest_file_path,
- StatusCallback* callback);
-
// Deletes a directory and all of its contents.
static bool RecursiveDelete(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
@@ -149,9 +152,8 @@ class FileUtilProxy {
scoped_refptr<MessageLoopProxy> message_loop_proxy,
PlatformFile file,
int64 offset,
- char* buffer,
int bytes_to_read,
- ReadWriteCallback* callback);
+ ReadCallback* callback);
// Writes to a file. If |offset| is greater than the length of the file,
// |false| is returned. On success, the file pointer is moved to position
@@ -162,7 +164,7 @@ class FileUtilProxy {
int64 offset,
const char* buffer,
int bytes_to_write,
- ReadWriteCallback* callback);
+ WriteCallback* callback);
// Touches a file. The callback can be NULL.
static bool Touch(
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index 6ea94e4..ea29df5 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -163,7 +163,7 @@ class FindResultCollector {
void CreateTextFile(const FilePath& filename,
const std::wstring& contents) {
std::ofstream file;
- file.open(WideToUTF8(filename.ToWStringHack()).c_str());
+ file.open(filename.value().c_str());
ASSERT_TRUE(file.is_open());
file << contents;
file.close();
@@ -173,7 +173,7 @@ void CreateTextFile(const FilePath& filename,
std::wstring ReadTextFile(const FilePath& filename) {
wchar_t contents[64];
std::wifstream file;
- file.open(WideToUTF8(filename.ToWStringHack()).c_str());
+ file.open(filename.value().c_str());
EXPECT_TRUE(file.is_open());
file.getline(contents, 64);
file.close();
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 7476b53..51bcb4e 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -667,9 +667,10 @@ bool CreateDirectory(const FilePath& full_path) {
if (!::CreateDirectory(full_path_str, NULL)) {
DWORD error_code = ::GetLastError();
if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
- // This error code doesn't indicate whether we were racing with someone
- // creating the same directory, or a file with the same path, therefore
- // we check.
+ // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
+ // were racing with someone creating the same directory, or a file
+ // with the same path. If DirectoryExists() returns true, we lost the
+ // race to create the same directory.
return true;
} else {
LOG(WARNING) << "Failed to create directory " << full_path_str
diff --git a/base/global_descriptors_posix.cc b/base/global_descriptors_posix.cc
index 2fe953c..65e7955 100644
--- a/base/global_descriptors_posix.cc
+++ b/base/global_descriptors_posix.cc
@@ -11,10 +11,6 @@
namespace base {
-GlobalDescriptors::GlobalDescriptors() {}
-
-GlobalDescriptors::~GlobalDescriptors() {}
-
// static
GlobalDescriptors* GlobalDescriptors::GetInstance() {
typedef Singleton<base::GlobalDescriptors,
@@ -23,6 +19,14 @@ GlobalDescriptors* GlobalDescriptors::GetInstance() {
return GlobalDescriptorsSingleton::get();
}
+int GlobalDescriptors::Get(Key key) const {
+ const int ret = MaybeGet(key);
+
+ if (ret == -1)
+ LOG(FATAL) << "Unknown global descriptor: " << key;
+ return ret;
+}
+
int GlobalDescriptors::MaybeGet(Key key) const {
for (Mapping::const_iterator
i = descriptors_.begin(); i != descriptors_.end(); ++i) {
@@ -35,14 +39,6 @@ int GlobalDescriptors::MaybeGet(Key key) const {
return kBaseDescriptor + key;
}
-int GlobalDescriptors::Get(Key key) const {
- const int ret = MaybeGet(key);
-
- if (ret == -1)
- LOG(FATAL) << "Unknown global descriptor: " << key;
- return ret;
-}
-
void GlobalDescriptors::Set(Key key, int fd) {
for (Mapping::iterator
i = descriptors_.begin(); i != descriptors_.end(); ++i) {
@@ -55,4 +51,12 @@ void GlobalDescriptors::Set(Key key, int fd) {
descriptors_.push_back(std::make_pair(key, fd));
}
+void GlobalDescriptors::Reset(const Mapping& mapping) {
+ descriptors_ = mapping;
+}
+
+GlobalDescriptors::GlobalDescriptors() {}
+
+GlobalDescriptors::~GlobalDescriptors() {}
+
} // namespace base
diff --git a/base/global_descriptors_posix.h b/base/global_descriptors_posix.h
index 0cb5b4f..060bf0a 100644
--- a/base/global_descriptors_posix.h
+++ b/base/global_descriptors_posix.h
@@ -55,9 +55,7 @@ class GlobalDescriptors {
// Set the descriptor for the given key.
void Set(Key key, int fd);
- void Reset(const Mapping& mapping) {
- descriptors_ = mapping;
- }
+ void Reset(const Mapping& mapping);
private:
friend struct DefaultSingletonTraits<GlobalDescriptors>;
diff --git a/base/hmac_nss.cc b/base/hmac_nss.cc
index 2ca4f67..af0b3eb 100644
--- a/base/hmac_nss.cc
+++ b/base/hmac_nss.cc
@@ -36,6 +36,9 @@ HMAC::HMAC(HashAlgorithm hash_alg)
}
}
+HMAC::~HMAC() {
+}
+
bool HMAC::Init(const unsigned char *key, int key_length) {
base::EnsureNSSInit();
@@ -70,9 +73,6 @@ bool HMAC::Init(const unsigned char *key, int key_length) {
return true;
}
-HMAC::~HMAC() {
-}
-
bool HMAC::Sign(const std::string& data,
unsigned char* digest,
int digest_length) {
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
new file mode 100644
index 0000000..3222a3a
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 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/i18n/bidi_line_iterator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace i18n {
+
+BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
+}
+
+BiDiLineIterator::~BiDiLineIterator() {
+ if (bidi_) {
+ ubidi_close(bidi_);
+ bidi_ = NULL;
+ }
+}
+
+bool BiDiLineIterator::Open(const string16& text,
+ bool right_to_left,
+ bool url) {
+ DCHECK(bidi_ == NULL);
+ UErrorCode error = U_ZERO_ERROR;
+ bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
+ if (U_FAILURE(error))
+ return false;
+ if (right_to_left && url)
+ ubidi_setReorderingMode(bidi_, UBIDI_REORDER_RUNS_ONLY);
+ ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+ right_to_left ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
+ NULL, &error);
+ return U_SUCCESS(error) ? true : false;
+}
+
+int BiDiLineIterator::CountRuns() {
+ DCHECK(bidi_ != NULL);
+ UErrorCode error = U_ZERO_ERROR;
+ const int runs = ubidi_countRuns(bidi_, &error);
+ return U_SUCCESS(error) ? runs : 0;
+}
+
+UBiDiDirection BiDiLineIterator::GetVisualRun(int index,
+ int* start,
+ int* length) {
+ DCHECK(bidi_ != NULL);
+ return ubidi_getVisualRun(bidi_, index, start, length);
+}
+
+void BiDiLineIterator::GetLogicalRun(int start,
+ int* end,
+ UBiDiLevel* level) {
+ DCHECK(bidi_ != NULL);
+ ubidi_getLogicalRun(bidi_, start, end, level);
+}
+
+} // namespace i18n
+} // namespace base
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
new file mode 100644
index 0000000..5fff6a3
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_I18N_BIDI_LINE_ITERATOR_H_
+#define BASE_I18N_BIDI_LINE_ITERATOR_H_
+#pragma once
+
+#include "unicode/ubidi.h"
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+namespace base {
+namespace i18n {
+
+// A simple wrapper class for the bidirectional iterator of ICU.
+// This class uses the bidirectional iterator of ICU to split a line of
+// bidirectional texts into visual runs in its display order.
+class BiDiLineIterator {
+ public:
+ BiDiLineIterator();
+ ~BiDiLineIterator();
+
+ // Initializes the bidirectional iterator with the specified text. Returns
+ // whether initialization succeeded.
+ bool Open(const string16& text, bool right_to_left, bool url);
+
+ // Returns the number of visual runs in the text, or zero on error.
+ int CountRuns();
+
+ // Gets the logical offset, length, and direction of the specified visual run.
+ UBiDiDirection GetVisualRun(int index, int* start, int* length);
+
+ // Given a start position, figure out where the run ends (and the BiDiLevel).
+ void GetLogicalRun(int start, int* end, UBiDiLevel* level);
+
+ private:
+ UBiDi* bidi_;
+
+ DISALLOW_COPY_AND_ASSIGN(BiDiLineIterator);
+};
+
+} // namespace i18n
+} // namespace base
+
+#endif // BASE_I18N_BIDI_LINE_ITERATOR_H_
diff --git a/base/i18n/char_iterator.cc b/base/i18n/char_iterator.cc
index a6cf944..ce4d513 100644
--- a/base/i18n/char_iterator.cc
+++ b/base/i18n/char_iterator.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -8,6 +8,7 @@
#include "unicode/utf16.h"
namespace base {
+namespace i18n {
UTF8CharIterator::UTF8CharIterator(const std::string* str)
: str_(reinterpret_cast<const uint8_t*>(str->data())),
@@ -20,6 +21,9 @@ UTF8CharIterator::UTF8CharIterator(const std::string* str)
U8_NEXT(str_, next_pos_, len_, char_);
}
+UTF8CharIterator::~UTF8CharIterator() {
+}
+
bool UTF8CharIterator::Advance() {
if (array_pos_ >= len_)
return false;
@@ -54,6 +58,9 @@ UTF16CharIterator::UTF16CharIterator(const char16* str, size_t str_len)
ReadChar();
}
+UTF16CharIterator::~UTF16CharIterator() {
+}
+
bool UTF16CharIterator::Advance() {
if (array_pos_ >= len_)
return false;
@@ -71,4 +78,5 @@ void UTF16CharIterator::ReadChar() {
U16_NEXT(str_, next_pos_, len_, char_);
}
+} // namespace i18n
} // namespace base
diff --git a/base/i18n/char_iterator.h b/base/i18n/char_iterator.h
index f45b04b..bd7cc9f 100644
--- a/base/i18n/char_iterator.h
+++ b/base/i18n/char_iterator.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -25,12 +25,13 @@ typedef unsigned char uint8_t;
#endif
namespace base {
+namespace i18n {
class UTF8CharIterator {
public:
// Requires |str| to live as long as the UTF8CharIterator does.
UTF8CharIterator(const std::string* str);
- ~UTF8CharIterator() {}
+ ~UTF8CharIterator();
// Return the starting array index of the current character within the
// string.
@@ -77,7 +78,7 @@ class UTF16CharIterator {
// Requires |str| to live as long as the UTF16CharIterator does.
UTF16CharIterator(const string16* str);
UTF16CharIterator(const char16* str, size_t str_len);
- ~UTF16CharIterator() {}
+ ~UTF16CharIterator();
// Return the starting array index of the current character within the
// string.
@@ -123,6 +124,7 @@ class UTF16CharIterator {
DISALLOW_COPY_AND_ASSIGN(UTF16CharIterator);
};
+} // namespace i18n
} // namespace base
#endif // BASE_I18N_CHAR_ITERATOR_H_
diff --git a/base/i18n/char_iterator_unittest.cc b/base/i18n/char_iterator_unittest.cc
index 4fe7ebb..6d1294e 100644
--- a/base/i18n/char_iterator_unittest.cc
+++ b/base/i18n/char_iterator_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -7,16 +7,19 @@
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace base {
+namespace i18n {
+
TEST(CharIteratorsTest, TestUTF8) {
std::string empty("");
- base::UTF8CharIterator empty_iter(&empty);
+ UTF8CharIterator empty_iter(&empty);
ASSERT_TRUE(empty_iter.end());
ASSERT_EQ(0, empty_iter.array_pos());
ASSERT_EQ(0, empty_iter.char_pos());
ASSERT_FALSE(empty_iter.Advance());
std::string str("s\303\273r"); // [u with circumflex]
- base::UTF8CharIterator iter(&str);
+ UTF8CharIterator iter(&str);
ASSERT_FALSE(iter.end());
ASSERT_EQ(0, iter.array_pos());
ASSERT_EQ(0, iter.char_pos());
@@ -47,7 +50,7 @@ TEST(CharIteratorsTest, TestUTF8) {
TEST(CharIteratorsTest, TestUTF16) {
string16 empty = UTF8ToUTF16("");
- base::UTF16CharIterator empty_iter(&empty);
+ UTF16CharIterator empty_iter(&empty);
ASSERT_TRUE(empty_iter.end());
ASSERT_EQ(0, empty_iter.array_pos());
ASSERT_EQ(0, empty_iter.char_pos());
@@ -59,7 +62,7 @@ TEST(CharIteratorsTest, TestUTF16) {
// math double-struck A - 4 bytes in UTF8, 2 codewords in UTF16
// z
string16 str = UTF8ToUTF16("x\303\273\360\235\224\270z");
- base::UTF16CharIterator iter(&str);
+ UTF16CharIterator iter(&str);
ASSERT_FALSE(iter.end());
ASSERT_EQ(0, iter.array_pos());
ASSERT_EQ(0, iter.char_pos());
@@ -93,3 +96,6 @@ TEST(CharIteratorsTest, TestUTF16) {
ASSERT_FALSE(iter.Advance());
}
+
+} // namespace i18n
+} // namespace base
diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc
index 34eefac..ba69da0 100644
--- a/base/i18n/file_util_icu.cc
+++ b/base/i18n/file_util_icu.cc
@@ -90,7 +90,7 @@ class LocaleAwareComparator {
int Compare(const string16& a, const string16& b) {
// We are not sure if Collator::compare is thread-safe.
// Use an AutoLock just in case.
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
UErrorCode error_code = U_ZERO_ERROR;
UCollationResult result = collator_->compare(
@@ -120,7 +120,7 @@ class LocaleAwareComparator {
}
scoped_ptr<icu::Collator> collator_;
- Lock lock_;
+ base::Lock lock_;
friend struct DefaultSingletonTraits<LocaleAwareComparator>;
DISALLOW_COPY_AND_ASSIGN(LocaleAwareComparator);
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index d378a25..eb7a688 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -21,6 +21,10 @@
#include "unicode/putil.h"
#include "unicode/udata.h"
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif
+
#define ICU_UTIL_DATA_FILE 0
#define ICU_UTIL_DATA_SHARED 1
#define ICU_UTIL_DATA_STATIC 2
@@ -35,10 +39,14 @@
#endif // ICU_UTIL_DATA_IMPL
-#if defined(OS_WIN)
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#define ICU_UTIL_DATA_FILE_NAME "icudt" U_ICU_VERSION_SHORT "l.dat"
+#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
+#if defined(OS_WIN)
#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt" U_ICU_VERSION_SHORT ".dll"
#endif
+#endif
namespace icu_util {
@@ -78,6 +86,7 @@ bool Initialize() {
// Mac/Linux bundle the ICU data in.
return true;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
+#if !defined(OS_MACOSX)
// For now, expect the data file to be alongside the executable.
// This is sufficient while we work on unit tests, but will eventually
// likely live in a data directory.
@@ -90,6 +99,32 @@ bool Initialize() {
UErrorCode err = U_ZERO_ERROR;
udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
return err == U_ZERO_ERROR;
+#else
+ // If the ICU data directory is set, ICU won't actually load the data until
+ // it is needed. This can fail if the process is sandboxed at that time.
+ // Instead, Mac maps the file in and hands off the data so the sandbox won't
+ // cause any problems.
+
+ // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
+ // be released.
+ static file_util::MemoryMappedFile mapped_file;
+ if (!mapped_file.IsValid()) {
+ // Assume it is in the MainBundle's Resources directory.
+ FilePath data_path =
+ base::mac::PathForMainAppBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME));
+ if (data_path.empty()) {
+ LOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle";
+ return false;
+ }
+ if (!mapped_file.Initialize(data_path)) {
+ LOG(ERROR) << "Couldn't mmap " << data_path.value();
+ return false;
+ }
+ }
+ UErrorCode err = U_ZERO_ERROR;
+ udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+ return err == U_ZERO_ERROR;
+#endif // OS check
#endif
}
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index 391f58b..c8fe78d 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -81,6 +81,11 @@ const char* JSONReader::kUnsupportedEncoding =
const char* JSONReader::kUnquotedDictionaryKey =
"Dictionary keys must be quoted.";
+JSONReader::JSONReader()
+ : start_pos_(NULL), json_pos_(NULL), stack_depth_(0),
+ allow_trailing_comma_(false),
+ error_code_(JSON_NO_ERROR), error_line_(0), error_col_(0) {}
+
/* static */
Value* JSONReader::Read(const std::string& json,
bool allow_trailing_comma) {
@@ -106,16 +111,6 @@ Value* JSONReader::ReadAndReturnError(const std::string& json,
}
/* static */
-std::string JSONReader::FormatErrorMessage(int line, int column,
- const std::string& description) {
- if (line || column) {
- return StringPrintf("Line: %i, column: %i, %s",
- line, column, description.c_str());
- }
- return description;
-}
-
-/* static */
std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
switch (error_code) {
case JSON_NO_ERROR:
@@ -147,11 +142,6 @@ std::string JSONReader::GetErrorMessage() const {
ErrorCodeToString(error_code_));
}
-JSONReader::JSONReader()
- : start_pos_(NULL), json_pos_(NULL), stack_depth_(0),
- allow_trailing_comma_(false),
- error_code_(JSON_NO_ERROR), error_line_(0), error_col_(0) {}
-
Value* JSONReader::JsonToValue(const std::string& json, bool check_root,
bool allow_trailing_comma) {
// The input must be in UTF-8.
@@ -195,6 +185,16 @@ Value* JSONReader::JsonToValue(const std::string& json, bool check_root,
return NULL;
}
+/* static */
+std::string JSONReader::FormatErrorMessage(int line, int column,
+ const std::string& description) {
+ if (line || column) {
+ return StringPrintf("Line: %i, column: %i, %s",
+ line, column, description.c_str());
+ }
+ return description;
+}
+
Value* JSONReader::BuildValue(bool is_root) {
++stack_depth_;
if (stack_depth_ > kStackLimit) {
@@ -396,7 +396,7 @@ Value* JSONReader::DecodeNumber(const Token& token) {
double num_double;
if (StringToDouble(WideToUTF8(num_string), &num_double) &&
base::IsFinite(num_double))
- return Value::CreateRealValue(num_double);
+ return Value::CreateDoubleValue(num_double);
return NULL;
}
@@ -580,16 +580,6 @@ JSONReader::Token JSONReader::ParseToken() {
return token;
}
-bool JSONReader::NextStringMatch(const std::wstring& str) {
- for (size_t i = 0; i < str.length(); ++i) {
- if ('\0' == *json_pos_)
- return false;
- if (*(json_pos_ + i) != str[i])
- return false;
- }
- return true;
-}
-
void JSONReader::EatWhitespaceAndComments() {
while ('\0' != *json_pos_) {
switch (*json_pos_) {
@@ -645,6 +635,16 @@ bool JSONReader::EatComment() {
return true;
}
+bool JSONReader::NextStringMatch(const std::wstring& str) {
+ for (size_t i = 0; i < str.length(); ++i) {
+ if ('\0' == *json_pos_)
+ return false;
+ if (*(json_pos_ + i) != str[i])
+ return false;
+ }
+ return true;
+}
+
void JSONReader::SetErrorCode(JsonParseError error,
const wchar_t* error_pos) {
int line_number = 1;
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index 77c4e74..a6f0686 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -146,14 +146,12 @@ class JSONReader {
bool allow_trailing_comma);
private:
- static std::string FormatErrorMessage(int line, int column,
- const std::string& description);
-
- DISALLOW_COPY_AND_ASSIGN(JSONReader);
-
FRIEND_TEST(JSONReaderTest, Reading);
FRIEND_TEST(JSONReaderTest, ErrorMessages);
+ static std::string FormatErrorMessage(int line, int column,
+ const std::string& description);
+
// Recursively build Value. Returns NULL if we don't have a valid JSON
// string. If |is_root| is true, we verify that the root element is either
// an object or an array.
@@ -213,6 +211,8 @@ class JSONReader {
JsonParseError error_code_;
int error_line_;
int error_col_;
+
+ DISALLOW_COPY_AND_ASSIGN(JSONReader);
};
} // namespace base
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index c00c976..db0ab63 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -75,60 +75,60 @@ TEST(JSONReaderTest, Reading) {
// storage as doubles
root.reset(JSONReader().JsonToValue("2147483648", false, false));
ASSERT_TRUE(root.get());
- double real_val;
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(2147483648.0, real_val);
+ double double_val;
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(2147483648.0, double_val);
root.reset(JSONReader().JsonToValue("-2147483649", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(-2147483649.0, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(-2147483649.0, double_val);
// Parse a double
root.reset(JSONReader().JsonToValue("43.1", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(43.1, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(43.1, double_val);
root.reset(JSONReader().JsonToValue("4.3e-1", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(.43, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(.43, double_val);
root.reset(JSONReader().JsonToValue("2.1e0", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(2.1, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(2.1, double_val);
root.reset(JSONReader().JsonToValue("2.1e+0001", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(21.0, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(21.0, double_val);
root.reset(JSONReader().JsonToValue("0.01", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(0.01, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(0.01, double_val);
root.reset(JSONReader().JsonToValue("1.00", false, false));
ASSERT_TRUE(root.get());
- ASSERT_TRUE(root->IsType(Value::TYPE_REAL));
- real_val = 0.0;
- ASSERT_TRUE(root->GetAsReal(&real_val));
- ASSERT_DOUBLE_EQ(1.0, real_val);
+ ASSERT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+ double_val = 0.0;
+ ASSERT_TRUE(root->GetAsDouble(&double_val));
+ ASSERT_DOUBLE_EQ(1.0, double_val);
// Fractional parts must have a digit before and after the decimal point.
root.reset(JSONReader().JsonToValue("1.", false, false));
@@ -303,9 +303,9 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get());
- real_val = 0.0;
- ASSERT_TRUE(dict_val->GetReal("number", &real_val));
- ASSERT_DOUBLE_EQ(9.87654321, real_val);
+ double_val = 0.0;
+ ASSERT_TRUE(dict_val->GetDouble("number", &double_val));
+ ASSERT_DOUBLE_EQ(9.87654321, double_val);
Value* null_val = NULL;
ASSERT_TRUE(dict_val->Get("null", &null_val));
ASSERT_TRUE(null_val->IsType(Value::TYPE_NULL));
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index dbf43ec..fa8f239 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -75,10 +75,10 @@ void JSONWriter::BuildJSONString(const Value* const node,
break;
}
- case Value::TYPE_REAL:
+ case Value::TYPE_DOUBLE:
{
double value;
- bool result = node->GetAsReal(&value);
+ bool result = node->GetAsDouble(&value);
DCHECK(result);
std::string real = DoubleToString(value);
// Ensure that the number has a .0 if there's no decimal or 'e'. This
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index 937d083..6d7714b 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_unittest.cc
@@ -29,19 +29,19 @@ TEST(JSONWriterTest, Writing) {
delete root;
// Test Real values should always have a decimal or an 'e'.
- root = Value::CreateRealValue(1.0);
+ root = Value::CreateDoubleValue(1.0);
JSONWriter::Write(root, false, &output_js);
ASSERT_EQ("1.0", output_js);
delete root;
// Test Real values in the the range (-1, 1) must have leading zeros
- root = Value::CreateRealValue(0.2);
+ root = Value::CreateDoubleValue(0.2);
JSONWriter::Write(root, false, &output_js);
ASSERT_EQ("0.2", output_js);
delete root;
// Test Real values in the the range (-1, 1) must have leading zeros
- root = Value::CreateRealValue(-0.8);
+ root = Value::CreateDoubleValue(-0.8);
JSONWriter::Write(root, false, &output_js);
ASSERT_EQ("-0.8", output_js);
delete root;
diff --git a/base/linux_util.cc b/base/linux_util.cc
index e1f7275..4e7cc5c 100644
--- a/base/linux_util.cc
+++ b/base/linux_util.cc
@@ -17,12 +17,12 @@
#include "base/command_line.h"
#include "base/file_util.h"
-#include "base/lock.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/singleton.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/synchronization/lock.h"
namespace {
@@ -51,7 +51,7 @@ class LinuxDistroHelper {
// we automatically move to STATE_CHECK_STARTED so nobody else will
// do the check.
LinuxDistroState State() {
- AutoLock scoped_lock(lock_);
+ base::AutoLock scoped_lock(lock_);
if (STATE_DID_NOT_CHECK == state_) {
state_ = STATE_CHECK_STARTED;
return STATE_DID_NOT_CHECK;
@@ -61,13 +61,13 @@ class LinuxDistroHelper {
// Indicate the check finished, move to STATE_CHECK_FINISHED.
void CheckFinished() {
- AutoLock scoped_lock(lock_);
+ base::AutoLock scoped_lock(lock_);
DCHECK(state_ == STATE_CHECK_STARTED);
state_ = STATE_CHECK_FINISHED;
}
private:
- Lock lock_;
+ base::Lock lock_;
LinuxDistroState state_;
};
#endif // if defined(OS_LINUX)
diff --git a/base/lock.h b/base/lock.h
deleted file mode 100644
index 7c90d86..0000000
--- a/base/lock.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2011 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.
-
-#ifndef BASE_LOCK_H_
-#define BASE_LOCK_H_
-#pragma once
-
-// This is a temporary forwarding file so not every user of lock needs to
-// be updated at once.
-// TODO(brettw) remove this and fix everybody up to using the new location.
-#include "base/synchronization/lock.h"
-
-using base::AutoLock;
-using base::AutoUnlock;
-using base::Lock;
-
-#endif // BASE_LOCK_H_
diff --git a/base/logging.cc b/base/logging.cc
index a736590..c38a2e0 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -64,7 +64,7 @@ typedef pthread_mutex_t* MutexHandle;
namespace logging {
-bool g_enable_dcheck = false;
+DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
VlogInfo* g_vlog_info = NULL;
const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
@@ -353,15 +353,19 @@ bool InitializeLogFileHandle() {
bool BaseInitLoggingImpl(const PathChar* new_log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
+<<<<<<< HEAD
OldFileDeletionState delete_old) {
#ifdef ANDROID
// ifdef is here because we don't support parsing command line parameters
g_enable_dcheck = false;
g_vlog_info = NULL;
#else
+=======
+ OldFileDeletionState delete_old,
+ DcheckState dcheck_state) {
+>>>>>>> chromium.org at r11.0.672.0
CommandLine* command_line = CommandLine::ForCurrentProcess();
- g_enable_dcheck =
- command_line->HasSwitch(switches::kEnableDCHECK);
+ g_dcheck_state = dcheck_state;
delete g_vlog_info;
g_vlog_info = NULL;
// Don't bother initializing g_vlog_info unless we use one of the
@@ -536,71 +540,29 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
Init(file, line);
}
-LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
- : severity_(LOG_FATAL), file_(file), line_(line) {
+LogMessage::LogMessage(const char* file, int line)
+ : severity_(LOG_INFO), file_(file), line_(line) {
Init(file, line);
- stream_ << "Check failed: " << (*result.str_);
}
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
- const CheckOpString& result)
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
: severity_(severity), file_(file), line_(line) {
Init(file, line);
- stream_ << "Check failed: " << (*result.str_);
}
-LogMessage::LogMessage(const char* file, int line)
- : severity_(LOG_INFO), file_(file), line_(line) {
+LogMessage::LogMessage(const char* file, int line, std::string* result)
+ : severity_(LOG_FATAL), file_(file), line_(line) {
Init(file, line);
+ stream_ << "Check failed: " << *result;
+ delete result;
}
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* result)
: severity_(severity), file_(file), line_(line) {
Init(file, line);
-}
-
-// writes the common header info to the stream
-void LogMessage::Init(const char* file, int line) {
- base::StringPiece filename(file);
- size_t last_slash_pos = filename.find_last_of("\\/");
- if (last_slash_pos != base::StringPiece::npos)
- filename.remove_prefix(last_slash_pos + 1);
-
- // TODO(darin): It might be nice if the columns were fixed width.
-
- stream_ << '[';
- if (log_process_id)
- stream_ << CurrentProcessId() << ':';
- if (log_thread_id)
- stream_ << CurrentThreadId() << ':';
- if (log_timestamp) {
- time_t t = time(NULL);
- struct tm local_time = {0};
-#if _MSC_VER >= 1400
- localtime_s(&local_time, &t);
-#else
- localtime_r(&t, &local_time);
-#endif
- struct tm* tm_time = &local_time;
- stream_ << std::setfill('0')
- << std::setw(2) << 1 + tm_time->tm_mon
- << std::setw(2) << tm_time->tm_mday
- << '/'
- << std::setw(2) << tm_time->tm_hour
- << std::setw(2) << tm_time->tm_min
- << std::setw(2) << tm_time->tm_sec
- << ':';
- }
- if (log_tickcount)
- stream_ << TickCount() << ':';
- if (severity_ >= 0)
- stream_ << log_severity_names[severity_];
- else
- stream_ << "VERBOSE" << -severity_;
-
- stream_ << ":" << filename << "(" << line << ")] ";
-
- message_start_ = stream_.tellp();
+ stream_ << "Check failed: " << *result;
+ delete result;
}
LogMessage::~LogMessage() {
@@ -696,6 +658,50 @@ LogMessage::~LogMessage() {
}
}
+// writes the common header info to the stream
+void LogMessage::Init(const char* file, int line) {
+ base::StringPiece filename(file);
+ size_t last_slash_pos = filename.find_last_of("\\/");
+ if (last_slash_pos != base::StringPiece::npos)
+ filename.remove_prefix(last_slash_pos + 1);
+
+ // TODO(darin): It might be nice if the columns were fixed width.
+
+ stream_ << '[';
+ if (log_process_id)
+ stream_ << CurrentProcessId() << ':';
+ if (log_thread_id)
+ stream_ << CurrentThreadId() << ':';
+ if (log_timestamp) {
+ time_t t = time(NULL);
+ struct tm local_time = {0};
+#if _MSC_VER >= 1400
+ localtime_s(&local_time, &t);
+#else
+ localtime_r(&t, &local_time);
+#endif
+ struct tm* tm_time = &local_time;
+ stream_ << std::setfill('0')
+ << std::setw(2) << 1 + tm_time->tm_mon
+ << std::setw(2) << tm_time->tm_mday
+ << '/'
+ << std::setw(2) << tm_time->tm_hour
+ << std::setw(2) << tm_time->tm_min
+ << std::setw(2) << tm_time->tm_sec
+ << ':';
+ }
+ if (log_tickcount)
+ stream_ << TickCount() << ':';
+ if (severity_ >= 0)
+ stream_ << log_severity_names[severity_];
+ else
+ stream_ << "VERBOSE" << -severity_;
+
+ stream_ << ":" << filename << "(" << line << ")] ";
+
+ message_start_ = stream_.tellp();
+}
+
#if defined(OS_WIN)
// This has already been defined in the header, but defining it again as DWORD
// ensures that the type used in the header is equivalent to DWORD. If not,
diff --git a/base/logging.h b/base/logging.h
index a097568..b1bc0b0 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -165,6 +165,11 @@ enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
// Defaults to APPEND_TO_OLD_LOG_FILE.
enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+enum DcheckState {
+ DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS,
+ ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS
+};
+
// TODO(avi): do we want to do a unification of character types here?
#if defined(OS_WIN)
typedef wchar_t PathChar;
@@ -188,7 +193,8 @@ typedef char PathChar;
bool BaseInitLoggingImpl(const PathChar* log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
- OldFileDeletionState delete_old);
+ OldFileDeletionState delete_old,
+ DcheckState dcheck_state);
// Sets the log file name and other global logging state. Calling this function
// is recommended, and is normally done at the beginning of application init.
@@ -203,8 +209,10 @@ bool BaseInitLoggingImpl(const PathChar* log_file,
inline bool InitLogging(const PathChar* log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
- OldFileDeletionState delete_old) {
- return BaseInitLoggingImpl(log_file, logging_dest, lock_log, delete_old);
+ OldFileDeletionState delete_old,
+ DcheckState dcheck_state) {
+ return BaseInitLoggingImpl(log_file, logging_dest, lock_log,
+ delete_old, dcheck_state);
}
// Sets the log level. Anything at or above this level will be written to the
@@ -428,19 +436,10 @@ const LogSeverity LOG_0 = LOG_ERROR;
LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
<< "Check failed: " #condition ". "
-// A container for a string pointer which can be evaluated to a bool -
-// true iff the pointer is NULL.
-struct CheckOpString {
- CheckOpString(std::string* str) : str_(str) { }
- // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
- // so there's no point in cleaning up str_.
- operator bool() const { return str_ != NULL; }
- std::string* str_;
-};
-
// Build the error message string. This is separate from the "Impl"
// function template because it is not performance critical and so can
-// be out of line, while the "Impl" code should be inline.
+// be out of line, while the "Impl" code should be inline. Caller
+// takes ownership of the returned string.
template<class t1, class t2>
std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
std::ostringstream ss;
@@ -471,7 +470,7 @@ extern template std::string* MakeCheckOpString<std::string, std::string>(
// TODO(akalin): Rewrite this so that constructs like if (...)
// CHECK_EQ(...) else { ... } work properly.
#define CHECK_OP(name, op, val1, val2) \
- if (logging::CheckOpString _result = \
+ if (std::string* _result = \
logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
logging::LogMessage(__FILE__, __LINE__, _result).stream()
@@ -600,10 +599,11 @@ enum { DEBUG_MODE = ENABLE_DLOG };
COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_ERROR_REPORT
const LogSeverity LOG_DCHECK = LOG_ERROR_REPORT;
-// This is set to true in InitLogging when we want to enable the
-// DCHECKs in release.
-extern bool g_enable_dcheck;
-#define DCHECK_IS_ON() (::logging::g_enable_dcheck && LOG_IS_ON(DCHECK))
+extern DcheckState g_dcheck_state;
+#define DCHECK_IS_ON() \
+ ((::logging::g_dcheck_state == \
+ ::logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) && \
+ LOG_IS_ON(DCHECK))
#else // defined(NDEBUG)
@@ -646,7 +646,7 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
if (DCHECK_IS_ON()) \
- if (logging::CheckOpString _result = \
+ if (std::string* _result = \
logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
logging::LogMessage( \
@@ -714,14 +714,15 @@ class LogMessage {
// saves a couple of bytes per call site.
LogMessage(const char* file, int line, LogSeverity severity);
- // A special constructor used for check failures.
+ // A special constructor used for check failures. Takes ownership
+ // of the given string.
// Implied severity = LOG_FATAL
- LogMessage(const char* file, int line, const CheckOpString& result);
+ LogMessage(const char* file, int line, std::string* result);
// A special constructor used for check failures, with the option to
- // specify severity.
+ // specify severity. Takes ownership of the given string.
LogMessage(const char* file, int line, LogSeverity severity,
- const CheckOpString& result);
+ std::string* result);
~LogMessage();
@@ -910,4 +911,13 @@ inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
} while(0)
#endif
+namespace base {
+
+class StringPiece;
+
+// allow StringPiece to be logged (needed for unit testing).
+extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
+
+} // namespace base
+
#endif // BASE_LOGGING_H_
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
index 4b7fdbc..bb6e3d1 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -197,7 +197,7 @@ TEST_F(LoggingTest, DcheckStreamsAreLazy) {
#if !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG)
// Unofficial release build.
- logging::g_enable_dcheck = false;
+ g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
DCHECK(mock_log_source.Log()) << mock_log_source.Log();
DPCHECK(mock_log_source.Log()) << mock_log_source.Log();
DCHECK_EQ(0, 0) << mock_log_source.Log();
@@ -213,13 +213,13 @@ TEST_F(LoggingTest, Dcheck) {
EXPECT_FALSE(DLOG_IS_ON(DCHECK));
#elif defined(NDEBUG)
// Unofficial release build.
- logging::g_enable_dcheck = true;
- logging::SetLogReportHandler(&LogSink);
+ g_dcheck_state = ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
+ SetLogReportHandler(&LogSink);
EXPECT_TRUE(DCHECK_IS_ON());
EXPECT_FALSE(DLOG_IS_ON(DCHECK));
#else
// Unofficial debug build.
- logging::SetLogAssertHandler(&LogSink);
+ SetLogAssertHandler(&LogSink);
EXPECT_TRUE(DCHECK_IS_ON());
EXPECT_TRUE(DLOG_IS_ON(DCHECK));
#endif // defined(LOGGING_IS_OFFICIAL_BUILD)
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
new file mode 100644
index 0000000..a7c525a
--- /dev/null
+++ b/base/mac/foundation_util.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2011 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.
+
+#ifndef BASE_MAC_FOUNDATION_UTIL_H_
+#define BASE_MAC_FOUNDATION_UTIL_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+@class NSBundle;
+#else // __OBJC__
+class NSBundle;
+#endif // __OBJC__
+
+class FilePath;
+
+// Adapted from NSPathUtilities.h and NSObjCRuntime.h.
+#if __LP64__ || NS_BUILD_32_LIKE_64
+typedef unsigned long NSSearchPathDirectory;
+typedef unsigned long NSSearchPathDomainMask;
+#else
+typedef unsigned int NSSearchPathDirectory;
+typedef unsigned int NSSearchPathDomainMask;
+#endif
+
+namespace base {
+namespace mac {
+
+// Returns true if the application is running from a bundle
+bool AmIBundled();
+void SetOverrideAmIBundled(bool value);
+
+// Returns true if this process is marked as a "Background only process".
+bool IsBackgroundOnlyProcess();
+
+// Returns the main bundle or the override, used for code that needs
+// to fetch resources from bundles, but work within a unittest where we
+// aren't a bundle.
+NSBundle* MainAppBundle();
+FilePath MainAppBundlePath();
+
+// Returns the path to a resource within the MainAppBundle.
+FilePath PathForMainAppBundleResource(CFStringRef resourceName);
+
+// Set the bundle that MainAppBundle will return, overriding the default value
+// (Restore the default by calling SetOverrideAppBundle(nil)).
+void SetOverrideAppBundle(NSBundle* bundle);
+void SetOverrideAppBundlePath(const FilePath& file_path);
+
+// Returns the creator code associated with the CFBundleRef at bundle.
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle);
+
+// Returns the creator code associated with this application, by calling
+// CreatorCodeForCFBundleRef for the application's main bundle. If this
+// information cannot be determined, returns kUnknownType ('????'). This
+// does not respect the override app bundle because it's based on CFBundle
+// instead of NSBundle, and because callers probably don't want the override
+// app bundle's creator code anyway.
+OSType CreatorCodeForApplication();
+
+// Searches for directories for the given key in only the given |domain_mask|.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true. Otherwise, returns false.
+bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+ NSSearchPathDomainMask domain_mask,
+ FilePath* result);
+
+// Searches for directories for the given key in only the local domain.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true. Otherwise, returns false.
+bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result);
+
+// Searches for directories for the given key in only the user domain.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true. Otherwise, returns false.
+bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result);
+
+// Returns the ~/Library directory.
+FilePath GetUserLibraryPath();
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+// |exec_name| - path to the binary
+// returns - path to the application bundle, or empty on error
+FilePath GetAppBundlePath(const FilePath& exec_name);
+
+// Utility function to pull out a value from a dictionary, check its type, and
+// return it. Returns NULL if the key is not present or of the wrong type.
+CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
+ CFStringRef key,
+ CFTypeID expected_type);
+
+// Retain/release calls for memory management in C++.
+void NSObjectRetain(void* obj);
+void NSObjectRelease(void* obj);
+
+} // namespace mac
+} // namespace base
+
+#endif // BASE_MAC_FOUNDATION_UTIL_H_
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
new file mode 100644
index 0000000..151d82f
--- /dev/null
+++ b/base/mac/foundation_util.mm
@@ -0,0 +1,236 @@
+// Copyright (c) 2011 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/mac/foundation_util.h"
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+static bool g_override_am_i_bundled = false;
+static bool g_override_am_i_bundled_value = false;
+
+// Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled
+static bool UncachedAmIBundled() {
+ if (g_override_am_i_bundled)
+ return g_override_am_i_bundled_value;
+
+ ProcessSerialNumber psn = {0, kCurrentProcess};
+
+ FSRef fsref;
+ OSStatus pbErr;
+ if ((pbErr = GetProcessBundleLocation(&psn, &fsref)) != noErr) {
+ LOG(ERROR) << "GetProcessBundleLocation failed: error " << pbErr;
+ return false;
+ }
+
+ FSCatalogInfo info;
+ OSErr fsErr;
+ if ((fsErr = FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info,
+ NULL, NULL, NULL)) != noErr) {
+ LOG(ERROR) << "FSGetCatalogInfo failed: error " << fsErr;
+ return false;
+ }
+
+ return info.nodeFlags & kFSNodeIsDirectoryMask;
+}
+
+bool AmIBundled() {
+ // If the return value is not cached, this function will return different
+ // values depending on when it's called. This confuses some client code, see
+ // http://crbug.com/63183 .
+ static bool result = UncachedAmIBundled();
+ DCHECK_EQ(result, UncachedAmIBundled())
+ << "The return value of AmIBundled() changed. This will confuse tests. "
+ << "Call SetAmIBundled() override manually if your test binary "
+ << "delay-loads the framework.";
+ return result;
+}
+
+void SetOverrideAmIBundled(bool value) {
+ g_override_am_i_bundled = true;
+ g_override_am_i_bundled_value = value;
+}
+
+bool IsBackgroundOnlyProcess() {
+ // This function really does want to examine NSBundle's idea of the main
+ // bundle dictionary, and not the overriden MainAppBundle. It needs to look
+ // at the actual running .app's Info.plist to access its LSUIElement
+ // property.
+ NSDictionary* info_dictionary = [[NSBundle mainBundle] infoDictionary];
+ return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
+}
+
+// No threading worries since NSBundle isn't thread safe.
+static NSBundle* g_override_app_bundle = nil;
+
+NSBundle* MainAppBundle() {
+ if (g_override_app_bundle)
+ return g_override_app_bundle;
+ return [NSBundle mainBundle];
+}
+
+FilePath MainAppBundlePath() {
+ NSBundle* bundle = MainAppBundle();
+ return FilePath([[bundle bundlePath] fileSystemRepresentation]);
+}
+
+FilePath PathForMainAppBundleResource(CFStringRef resourceName) {
+ NSBundle* bundle = MainAppBundle();
+ NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName
+ ofType:nil];
+ if (!resourcePath)
+ return FilePath();
+ return FilePath([resourcePath fileSystemRepresentation]);
+}
+
+void SetOverrideAppBundle(NSBundle* bundle) {
+ if (bundle != g_override_app_bundle) {
+ [g_override_app_bundle release];
+ g_override_app_bundle = [bundle retain];
+ }
+}
+
+void SetOverrideAppBundlePath(const FilePath& file_path) {
+ NSString* path = base::SysUTF8ToNSString(file_path.value());
+ NSBundle* bundle = [NSBundle bundleWithPath:path];
+ CHECK(bundle) << "Failed to load the bundle at " << file_path.value();
+
+ SetOverrideAppBundle(bundle);
+}
+
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
+ OSType creator = kUnknownType;
+ CFBundleGetPackageInfo(bundle, NULL, &creator);
+ return creator;
+}
+
+OSType CreatorCodeForApplication() {
+ CFBundleRef bundle = CFBundleGetMainBundle();
+ if (!bundle)
+ return kUnknownType;
+
+ return CreatorCodeForCFBundleRef(bundle);
+}
+
+bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+ NSSearchPathDomainMask domain_mask,
+ FilePath* result) {
+ DCHECK(result);
+ NSArray* dirs =
+ NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
+ if ([dirs count] < 1) {
+ return false;
+ }
+ NSString* path = [dirs objectAtIndex:0];
+ *result = FilePath([path fileSystemRepresentation]);
+ return true;
+}
+
+bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
+ return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
+}
+
+bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
+ return GetSearchPathDirectory(directory, NSUserDomainMask, result);
+}
+
+FilePath GetUserLibraryPath() {
+ FilePath user_library_path;
+ if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
+ LOG(WARNING) << "Could not get user library path";
+ }
+ return user_library_path;
+}
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+// |exec_name| - path to the binary
+// returns - path to the application bundle, or empty on error
+FilePath GetAppBundlePath(const FilePath& exec_name) {
+ const char kExt[] = ".app";
+ const size_t kExtLength = arraysize(kExt) - 1;
+
+ // Split the path into components.
+ std::vector<std::string> components;
+ exec_name.GetComponents(&components);
+
+ // It's an error if we don't get any components.
+ if (!components.size())
+ return FilePath();
+
+ // Don't prepend '/' to the first component.
+ std::vector<std::string>::const_iterator it = components.begin();
+ std::string bundle_name = *it;
+ DCHECK(it->length() > 0);
+ // If the first component ends in ".app", we're already done.
+ if (it->length() > kExtLength &&
+ !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+ return FilePath(bundle_name);
+
+ // The first component may be "/" or "//", etc. Only append '/' if it doesn't
+ // already end in '/'.
+ if (bundle_name[bundle_name.length() - 1] != '/')
+ bundle_name += '/';
+
+ // Go through the remaining components.
+ for (++it; it != components.end(); ++it) {
+ DCHECK(it->length() > 0);
+
+ bundle_name += *it;
+
+ // If the current component ends in ".app", we're done.
+ if (it->length() > kExtLength &&
+ !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+ return FilePath(bundle_name);
+
+ // Separate this component from the next one.
+ bundle_name += '/';
+ }
+
+ return FilePath();
+}
+
+CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
+ CFStringRef key,
+ CFTypeID expected_type) {
+ CFTypeRef value = CFDictionaryGetValue(dict, key);
+ if (!value)
+ return value;
+
+ if (CFGetTypeID(value) != expected_type) {
+ ScopedCFTypeRef<CFStringRef> expected_type_ref(
+ CFCopyTypeIDDescription(expected_type));
+ ScopedCFTypeRef<CFStringRef> actual_type_ref(
+ CFCopyTypeIDDescription(CFGetTypeID(value)));
+ LOG(WARNING) << "Expected value for key "
+ << base::SysCFStringRefToUTF8(key)
+ << " to be "
+ << base::SysCFStringRefToUTF8(expected_type_ref)
+ << " but it was "
+ << base::SysCFStringRefToUTF8(actual_type_ref)
+ << " instead";
+ return NULL;
+ }
+
+ return value;
+}
+
+void NSObjectRetain(void* obj) {
+ id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+ [nsobj retain];
+}
+
+void NSObjectRelease(void* obj) {
+ id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+ [nsobj release];
+}
+
+} // namespace mac
+} // namespace base
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index 7e5dddb..d75fb6e 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -8,32 +8,20 @@
#include <Carbon/Carbon.h>
#include <string>
-#include <vector>
#include "base/logging.h"
+// TODO(rohitrao): Clean up sites that include mac_util.h and remove this line.
+#include "base/mac/foundation_util.h"
+
#if defined(__OBJC__)
#import <Foundation/Foundation.h>
-
-@class NSBundle;
-@class NSWindow;
#else // __OBJC__
-class NSBundle;
class NSImage;
-class NSWindow;
#endif // __OBJC__
class FilePath;
-// Adapted from NSPathUtilities.h and NSObjCRuntime.h.
-#if __LP64__ || NS_BUILD_32_LIKE_64
-typedef unsigned long NSSearchPathDirectory;
-typedef unsigned long NSSearchPathDomainMask;
-#else
-typedef unsigned int NSSearchPathDirectory;
-typedef unsigned int NSSearchPathDomainMask;
-#endif
-
namespace base {
namespace mac {
@@ -53,55 +41,6 @@ enum FullScreenMode {
std::string PathFromFSRef(const FSRef& ref);
bool FSRefFromPath(const std::string& path, FSRef* ref);
-// Returns true if the application is running from a bundle
-bool AmIBundled();
-void SetOverrideAmIBundled(bool value);
-
-// Returns true if this process is marked as a "Background only process".
-bool IsBackgroundOnlyProcess();
-
-// Returns the main bundle or the override, used for code that needs
-// to fetch resources from bundles, but work within a unittest where we
-// aren't a bundle.
-NSBundle* MainAppBundle();
-FilePath MainAppBundlePath();
-
-// Set the bundle that MainAppBundle will return, overriding the default value
-// (Restore the default by calling SetOverrideAppBundle(nil)).
-void SetOverrideAppBundle(NSBundle* bundle);
-void SetOverrideAppBundlePath(const FilePath& file_path);
-
-// Returns the creator code associated with the CFBundleRef at bundle.
-OSType CreatorCodeForCFBundleRef(CFBundleRef bundle);
-
-// Returns the creator code associated with this application, by calling
-// CreatorCodeForCFBundleRef for the application's main bundle. If this
-// information cannot be determined, returns kUnknownType ('????'). This
-// does not respect the override app bundle because it's based on CFBundle
-// instead of NSBundle, and because callers probably don't want the override
-// app bundle's creator code anyway.
-OSType CreatorCodeForApplication();
-
-// Searches for directories for the given key in only the given |domain_mask|.
-// If found, fills result (which must always be non-NULL) with the
-// first found directory and returns true. Otherwise, returns false.
-bool GetSearchPathDirectory(NSSearchPathDirectory directory,
- NSSearchPathDomainMask domain_mask,
- FilePath* result);
-
-// Searches for directories for the given key in only the user domain.
-// If found, fills result (which must always be non-NULL) with the
-// first found directory and returns true. Otherwise, returns false.
-bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result);
-
-// Searches for directories for the given key in only the local domain.
-// If found, fills result (which must always be non-NULL) with the
-// first found directory and returns true. Otherwise, returns false.
-bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result);
-
-// Returns the ~/Library directory.
-FilePath GetUserLibraryPath();
-
// Returns an sRGB color space. The return value is a static value; do not
// release it!
CGColorSpaceRef GetSRGBColorSpace();
@@ -136,29 +75,11 @@ void SetCursorVisibility(bool visible);
bool ShouldWindowsMiniaturizeOnDoubleClick();
// Activates the process with the given PID.
-void ActivateProcess(pid_t);
-
-// Pulls a snapshot of the entire browser into png_representation.
-void GrabWindowSnapshot(NSWindow* window,
- std::vector<unsigned char>* png_representation,
- int* width, int* height);
-
-// Takes a path to an (executable) binary and tries to provide the path to an
-// application bundle containing it. It takes the outermost bundle that it can
-// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
-// |exec_name| - path to the binary
-// returns - path to the application bundle, or empty on error
-FilePath GetAppBundlePath(const FilePath& exec_name);
+void ActivateProcess(pid_t pid);
// Set the Time Machine exclusion property for the given file.
bool SetFileBackupExclusion(const FilePath& file_path, bool exclude);
-// Utility function to pull out a value from a dictionary, check its type, and
-// return it. Returns NULL if the key is not present or of the wrong type.
-CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
- CFStringRef key,
- CFTypeID expected_type);
-
// Sets the process name as displayed in Activity Monitor to process_name.
void SetProcessName(CFStringRef process_name);
@@ -189,10 +110,6 @@ void RemoveFromLoginItems();
// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows.
bool WasLaunchedAsHiddenLoginItem();
-// Retain/release calls for memory management in C++.
-void NSObjectRetain(void* obj);
-void NSObjectRelease(void* obj);
-
#if defined(__OBJC__)
// Convert toll-free bridged CFTypes to NSTypes. This does not autorelease
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index 21213ba..7f3be18 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -9,7 +9,6 @@
#include "base/file_path.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/message_loop.h"
#include "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
@@ -141,133 +140,6 @@ bool FSRefFromPath(const std::string& path, FSRef* ref) {
return status == noErr;
}
-static bool g_override_am_i_bundled = false;
-static bool g_override_am_i_bundled_value = false;
-
-// Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled
-static bool UncachedAmIBundled() {
- if (g_override_am_i_bundled)
- return g_override_am_i_bundled_value;
-
- ProcessSerialNumber psn = {0, kCurrentProcess};
-
- FSRef fsref;
- OSStatus pbErr;
- if ((pbErr = GetProcessBundleLocation(&psn, &fsref)) != noErr) {
- LOG(ERROR) << "GetProcessBundleLocation failed: error " << pbErr;
- return false;
- }
-
- FSCatalogInfo info;
- OSErr fsErr;
- if ((fsErr = FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info,
- NULL, NULL, NULL)) != noErr) {
- LOG(ERROR) << "FSGetCatalogInfo failed: error " << fsErr;
- return false;
- }
-
- return info.nodeFlags & kFSNodeIsDirectoryMask;
-}
-
-bool AmIBundled() {
- // If the return value is not cached, this function will return different
- // values depending on when it's called. This confuses some client code, see
- // http://crbug.com/63183 .
- static bool result = UncachedAmIBundled();
- DCHECK_EQ(result, UncachedAmIBundled())
- << "The return value of AmIBundled() changed. This will confuse tests. "
- << "Call SetAmIBundled() override manually if your test binary "
- << "delay-loads the framework.";
- return result;
-}
-
-void SetOverrideAmIBundled(bool value) {
- g_override_am_i_bundled = true;
- g_override_am_i_bundled_value = value;
-}
-
-bool IsBackgroundOnlyProcess() {
- // This function really does want to examine NSBundle's idea of the main
- // bundle dictionary, and not the overriden MainAppBundle. It needs to look
- // at the actual running .app's Info.plist to access its LSUIElement
- // property.
- NSDictionary* info_dictionary = [[NSBundle mainBundle] infoDictionary];
- return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
-}
-
-// No threading worries since NSBundle isn't thread safe.
-static NSBundle* g_override_app_bundle = nil;
-
-NSBundle* MainAppBundle() {
- if (g_override_app_bundle)
- return g_override_app_bundle;
- return [NSBundle mainBundle];
-}
-
-FilePath MainAppBundlePath() {
- NSBundle* bundle = MainAppBundle();
- return FilePath([[bundle bundlePath] fileSystemRepresentation]);
-}
-
-void SetOverrideAppBundle(NSBundle* bundle) {
- if (bundle != g_override_app_bundle) {
- [g_override_app_bundle release];
- g_override_app_bundle = [bundle retain];
- }
-}
-
-void SetOverrideAppBundlePath(const FilePath& file_path) {
- NSString* path = base::SysUTF8ToNSString(file_path.value());
- NSBundle* bundle = [NSBundle bundleWithPath:path];
- CHECK(bundle) << "Failed to load the bundle at " << file_path.value();
-
- SetOverrideAppBundle(bundle);
-}
-
-OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
- OSType creator = kUnknownType;
- CFBundleGetPackageInfo(bundle, NULL, &creator);
- return creator;
-}
-
-OSType CreatorCodeForApplication() {
- CFBundleRef bundle = CFBundleGetMainBundle();
- if (!bundle)
- return kUnknownType;
-
- return CreatorCodeForCFBundleRef(bundle);
-}
-
-bool GetSearchPathDirectory(NSSearchPathDirectory directory,
- NSSearchPathDomainMask domain_mask,
- FilePath* result) {
- DCHECK(result);
- NSArray* dirs =
- NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
- if ([dirs count] < 1) {
- return false;
- }
- NSString* path = [dirs objectAtIndex:0];
- *result = FilePath([path fileSystemRepresentation]);
- return true;
-}
-
-bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
- return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
-}
-
-bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
- return GetSearchPathDirectory(directory, NSUserDomainMask, result);
-}
-
-FilePath GetUserLibraryPath() {
- FilePath user_library_path;
- if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
- LOG(WARNING) << "Could not get user library path";
- }
- return user_library_path;
-}
-
CGColorSpaceRef GetSRGBColorSpace() {
// Leaked. That's OK, it's scoped to the lifetime of the application.
static CGColorSpaceRef g_color_space_sRGB =
@@ -356,26 +228,6 @@ bool ShouldWindowsMiniaturizeOnDoubleClick() {
[NSWindow performSelector:@selector(_shouldMiniaturizeOnDoubleClick)];
}
-void GrabWindowSnapshot(NSWindow* window,
- std::vector<unsigned char>* png_representation,
- int* width, int* height) {
- // Make sure to grab the "window frame" view so we get current tab +
- // tabstrip.
- NSView* view = [[window contentView] superview];
- NSBitmapImageRep* rep =
- [view bitmapImageRepForCachingDisplayInRect:[view bounds]];
- [view cacheDisplayInRect:[view bounds] toBitmapImageRep:rep];
- NSData* data = [rep representationUsingType:NSPNGFileType properties:nil];
- const unsigned char* buf = static_cast<const unsigned char*>([data bytes]);
- NSUInteger length = [data length];
- if (buf != NULL && length > 0){
- *width = static_cast<int>([rep pixelsWide]);
- *height = static_cast<int>([rep pixelsHigh]);
- png_representation->assign(buf, buf + length);
- DCHECK(png_representation->size() > 0);
- }
-}
-
void ActivateProcess(pid_t pid) {
ProcessSerialNumber process;
OSStatus status = GetProcessForPID(pid, &process);
@@ -386,55 +238,6 @@ void ActivateProcess(pid_t pid) {
}
}
-// Takes a path to an (executable) binary and tries to provide the path to an
-// application bundle containing it. It takes the outermost bundle that it can
-// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
-// |exec_name| - path to the binary
-// returns - path to the application bundle, or empty on error
-FilePath GetAppBundlePath(const FilePath& exec_name) {
- const char kExt[] = ".app";
- const size_t kExtLength = arraysize(kExt) - 1;
-
- // Split the path into components.
- std::vector<std::string> components;
- exec_name.GetComponents(&components);
-
- // It's an error if we don't get any components.
- if (!components.size())
- return FilePath();
-
- // Don't prepend '/' to the first component.
- std::vector<std::string>::const_iterator it = components.begin();
- std::string bundle_name = *it;
- DCHECK(it->length() > 0);
- // If the first component ends in ".app", we're already done.
- if (it->length() > kExtLength &&
- !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
- return FilePath(bundle_name);
-
- // The first component may be "/" or "//", etc. Only append '/' if it doesn't
- // already end in '/'.
- if (bundle_name[bundle_name.length() - 1] != '/')
- bundle_name += '/';
-
- // Go through the remaining components.
- for (++it; it != components.end(); ++it) {
- DCHECK(it->length() > 0);
-
- bundle_name += *it;
-
- // If the current component ends in ".app", we're done.
- if (it->length() > kExtLength &&
- !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
- return FilePath(bundle_name);
-
- // Separate this component from the next one.
- bundle_name += '/';
- }
-
- return FilePath();
-}
-
bool SetFileBackupExclusion(const FilePath& file_path, bool exclude) {
NSString* filePath =
[NSString stringWithUTF8String:file_path.value().c_str()];
@@ -478,31 +281,6 @@ bool SetFileBackupExclusion(const FilePath& file_path, bool exclude) {
return success;
}
-CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
- CFStringRef key,
- CFTypeID expected_type) {
- CFTypeRef value = CFDictionaryGetValue(dict, key);
- if (!value)
- return value;
-
- if (CFGetTypeID(value) != expected_type) {
- ScopedCFTypeRef<CFStringRef> expected_type_ref(
- CFCopyTypeIDDescription(expected_type));
- ScopedCFTypeRef<CFStringRef> actual_type_ref(
- CFCopyTypeIDDescription(CFGetTypeID(value)));
- LOG(WARNING) << "Expected value for key "
- << base::SysCFStringRefToUTF8(key)
- << " to be "
- << base::SysCFStringRefToUTF8(expected_type_ref)
- << " but it was "
- << base::SysCFStringRefToUTF8(actual_type_ref)
- << " instead";
- return NULL;
- }
-
- return value;
-}
-
void SetProcessName(CFStringRef process_name) {
if (!process_name || CFStringGetLength(process_name) == 0) {
NOTREACHED() << "SetProcessName given bad name.";
@@ -702,15 +480,5 @@ bool WasLaunchedAsHiddenLoginItem() {
return IsHiddenLoginItem(item);
}
-void NSObjectRetain(void* obj) {
- id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
- [nsobj retain];
-}
-
-void NSObjectRelease(void* obj) {
- id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
- [nsobj release];
-}
-
} // namespace mac
} // namespace base
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
index 47ecebf..bae0019 100644
--- a/base/mac/mac_util_unittest.mm
+++ b/base/mac/mac_util_unittest.mm
@@ -1,18 +1,15 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#import <Cocoa/Cocoa.h>
-#include <vector>
#include "base/mac/mac_util.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/test/mock_chrome_application_mac.h"
#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -53,37 +50,6 @@ TEST_F(MacUtilTest, TestLibraryPath) {
EXPECT_FALSE(library_dir.value().empty());
}
-TEST_F(MacUtilTest, TestGrabWindowSnapshot) {
- // Launch a test window so we can take a snapshot.
- [MockCrApp sharedApplication];
- NSRect frame = NSMakeRect(0, 0, 400, 400);
- scoped_nsobject<NSWindow> window(
- [[NSWindow alloc] initWithContentRect:frame
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [window setBackgroundColor:[NSColor whiteColor]];
- [window makeKeyAndOrderFront:NSApp];
-
- scoped_ptr<std::vector<unsigned char> > png_representation(
- new std::vector<unsigned char>);
- int width, height;
- GrabWindowSnapshot(window, png_representation.get(),
- &width, &height);
-
- // Copy png back into NSData object so we can make sure we grabbed a png.
- scoped_nsobject<NSData> image_data(
- [[NSData alloc] initWithBytes:&(*png_representation)[0]
- length:png_representation->size()]);
- NSBitmapImageRep* rep = [NSBitmapImageRep imageRepWithData:image_data.get()];
- EXPECT_TRUE([rep isKindOfClass:[NSBitmapImageRep class]]);
- EXPECT_TRUE(CGImageGetWidth([rep CGImage]) == 400);
- NSColor* color = [rep colorAtX:200 y:200];
- CGFloat red = 0, green = 0, blue = 0, alpha = 0;
- [color getRed:&red green:&green blue:&blue alpha:&alpha];
- EXPECT_GE(red + green + blue, 3.0);
-}
-
TEST_F(MacUtilTest, TestGetAppBundlePath) {
FilePath out;
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 7e35d9f..2ec872f 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -289,6 +289,12 @@ void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
task_observers_.RemoveObserver(task_observer);
}
+void MessageLoop::AssertIdle() const {
+ // We only check |incoming_queue_|, since we don't want to lock |work_queue_|.
+ base::AutoLock lock(incoming_queue_lock_);
+ DCHECK(incoming_queue_.empty());
+}
+
//------------------------------------------------------------------------------
// Runs the loop in two different SEH modes:
@@ -399,7 +405,7 @@ void MessageLoop::ReloadWorkQueue() {
// Acquire all we can from the inter-thread queue with one lock acquisition.
{
- AutoLock lock(incoming_queue_lock_);
+ base::AutoLock lock(incoming_queue_lock_);
if (incoming_queue_.empty())
return;
incoming_queue_.Swap(&work_queue_); // Constant time
@@ -500,7 +506,7 @@ void MessageLoop::PostTask_Helper(
scoped_refptr<base::MessagePump> pump;
{
- AutoLock locked(incoming_queue_lock_);
+ base::AutoLock locked(incoming_queue_lock_);
bool was_empty = incoming_queue_.empty();
incoming_queue_.push(pending_task);
diff --git a/base/message_loop.h b/base/message_loop.h
index d5093a9..d238997 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -10,10 +10,10 @@
#include <string>
#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/message_pump.h"
#include "base/observer_list.h"
#include "base/ref_counted.h"
+#include "base/synchronization/lock.h"
#include "base/task.h"
#if defined(OS_WIN)
@@ -315,6 +315,9 @@ class MessageLoop : public base::MessagePump::Delegate {
// for at least 1s.
static const int kHighResolutionTimerModeLeaseTimeMs = 1000;
+ // Asserts that the MessageLoop is "idle".
+ void AssertIdle() const;
+
//----------------------------------------------------------------------------
protected:
struct RunState {
@@ -461,12 +464,12 @@ class MessageLoop : public base::MessagePump::Delegate {
scoped_refptr<base::Histogram> message_histogram_;
// A null terminated list which creates an incoming_queue of tasks that are
- // aquired under a mutex for processing on this instance's thread. These tasks
+ // acquired under a mutex for processing on this instance's thread. These tasks
// have not yet been sorted out into items for our work_queue_ vs items that
// will be handled by the TimerManager.
TaskQueue incoming_queue_;
// Protect access to incoming_queue_.
- Lock incoming_queue_lock_;
+ mutable base::Lock incoming_queue_lock_;
RunState* state_;
diff --git a/base/message_loop_proxy_impl.cc b/base/message_loop_proxy_impl.cc
index 3b01fd6..b47c934 100644
--- a/base/message_loop_proxy_impl.cc
+++ b/base/message_loop_proxy_impl.cc
@@ -7,11 +7,6 @@
namespace base {
-MessageLoopProxyImpl::MessageLoopProxyImpl()
- : target_message_loop_(MessageLoop::current()) {
- target_message_loop_->AddDestructionObserver(this);
-}
-
MessageLoopProxyImpl::~MessageLoopProxyImpl() {
AutoLock lock(message_loop_lock_);
// If the target message loop still exists, the d'tor WILL execute on the
@@ -56,25 +51,10 @@ bool MessageLoopProxyImpl::BelongsToCurrentThread() {
(MessageLoop::current() == target_message_loop_));
}
-bool MessageLoopProxyImpl::PostTaskHelper(
- const tracked_objects::Location& from_here, Task* task, int64 delay_ms,
- bool nestable) {
- bool ret = false;
- {
- AutoLock lock(message_loop_lock_);
- if (target_message_loop_) {
- if (nestable) {
- target_message_loop_->PostDelayedTask(from_here, task, delay_ms);
- } else {
- target_message_loop_->PostNonNestableDelayedTask(from_here, task,
- delay_ms);
- }
- ret = true;
- }
- }
- if (!ret)
- delete task;
- return ret;
+// MessageLoop::DestructionObserver implementation
+void MessageLoopProxyImpl::WillDestroyCurrentMessageLoop() {
+ AutoLock lock(message_loop_lock_);
+ target_message_loop_ = NULL;
}
void MessageLoopProxyImpl::OnDestruct() const {
@@ -96,10 +76,30 @@ void MessageLoopProxyImpl::OnDestruct() const {
delete this;
}
-// MessageLoop::DestructionObserver implementation
-void MessageLoopProxyImpl::WillDestroyCurrentMessageLoop() {
- AutoLock lock(message_loop_lock_);
- target_message_loop_ = NULL;
+MessageLoopProxyImpl::MessageLoopProxyImpl()
+ : target_message_loop_(MessageLoop::current()) {
+ target_message_loop_->AddDestructionObserver(this);
+}
+
+bool MessageLoopProxyImpl::PostTaskHelper(
+ const tracked_objects::Location& from_here, Task* task, int64 delay_ms,
+ bool nestable) {
+ bool ret = false;
+ {
+ AutoLock lock(message_loop_lock_);
+ if (target_message_loop_) {
+ if (nestable) {
+ target_message_loop_->PostDelayedTask(from_here, task, delay_ms);
+ } else {
+ target_message_loop_->PostNonNestableDelayedTask(from_here, task,
+ delay_ms);
+ }
+ ret = true;
+ }
+ }
+ if (!ret)
+ delete task;
+ return ret;
}
scoped_refptr<MessageLoopProxy>
diff --git a/base/message_loop_proxy_impl.h b/base/message_loop_proxy_impl.h
index 44ab2ea..03e0271 100644
--- a/base/message_loop_proxy_impl.h
+++ b/base/message_loop_proxy_impl.h
@@ -6,9 +6,9 @@
#define BASE_MESSAGE_LOOP_PROXY_IMPL_H_
#pragma once
-#include "base/lock.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
+#include "base/synchronization/lock.h"
namespace base {
@@ -50,7 +50,7 @@ class MessageLoopProxyImpl : public MessageLoopProxy,
friend class MessageLoopProxy;
// The lock that protects access to target_message_loop_.
- mutable Lock message_loop_lock_;
+ mutable base::Lock message_loop_lock_;
MessageLoop* target_message_loop_;
DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index c471e38..9576a58 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -1555,18 +1555,18 @@ TEST(MessageLoopTest, HighResolutionTimer) {
const int kFastTimerMs = 5;
const int kSlowTimerMs = 100;
- EXPECT_EQ(false, loop.high_resolution_timers_enabled());
+ EXPECT_FALSE(loop.high_resolution_timers_enabled());
// Post a fast task to enable the high resolution timers.
loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kFastTimerMs);
loop.Run();
- EXPECT_EQ(true, loop.high_resolution_timers_enabled());
+ EXPECT_TRUE(loop.high_resolution_timers_enabled());
// Post a slow task and verify high resolution timers
// are still enabled.
loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs);
loop.Run();
- EXPECT_EQ(true, loop.high_resolution_timers_enabled());
+ EXPECT_TRUE(loop.high_resolution_timers_enabled());
// Wait for a while so that high-resolution mode elapses.
Sleep(MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
@@ -1574,7 +1574,7 @@ TEST(MessageLoopTest, HighResolutionTimer) {
// Post a slow task to disable the high resolution timers.
loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs);
loop.Run();
- EXPECT_EQ(false, loop.high_resolution_timers_enabled());
+ EXPECT_FALSE(loop.high_resolution_timers_enabled());
}
#endif // defined(OS_WIN)
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
index b9dcc46..721fedb 100644
--- a/base/message_pump_glib.cc
+++ b/base/message_pump_glib.cc
@@ -303,16 +303,15 @@ void MessagePumpForUI::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
-MessagePumpForUI::Dispatcher* MessagePumpForUI::GetDispatcher() {
- return state_ ? state_->dispatcher : NULL;
-}
-
-void MessagePumpForUI::WillProcessEvent(GdkEvent* event) {
- FOR_EACH_OBSERVER(Observer, observers_, WillProcessEvent(event));
-}
-
-void MessagePumpForUI::DidProcessEvent(GdkEvent* event) {
- FOR_EACH_OBSERVER(Observer, observers_, DidProcessEvent(event));
+void MessagePumpForUI::DispatchEvents(GdkEvent* event) {
+ WillProcessEvent(event);
+ if (state_ && state_->dispatcher) { // state_ may be null during tests.
+ if (!state_->dispatcher->Dispatch(event))
+ state_->should_quit = true;
+ } else {
+ gtk_main_do_event(event);
+ }
+ DidProcessEvent(event);
}
void MessagePumpForUI::Run(Delegate* delegate) {
@@ -344,15 +343,16 @@ void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
ScheduleWork();
}
-void MessagePumpForUI::DispatchEvents(GdkEvent* event) {
- WillProcessEvent(event);
- if (state_ && state_->dispatcher) { // state_ may be null during tests.
- if (!state_->dispatcher->Dispatch(event))
- state_->should_quit = true;
- } else {
- gtk_main_do_event(event);
- }
- DidProcessEvent(event);
+MessagePumpForUI::Dispatcher* MessagePumpForUI::GetDispatcher() {
+ return state_ ? state_->dispatcher : NULL;
+}
+
+void MessagePumpForUI::WillProcessEvent(GdkEvent* event) {
+ FOR_EACH_OBSERVER(Observer, observers_, WillProcessEvent(event));
+}
+
+void MessagePumpForUI::DidProcessEvent(GdkEvent* event) {
+ FOR_EACH_OBSERVER(Observer, observers_, DidProcessEvent(event));
}
// static
diff --git a/base/message_pump_glib_unittest.cc b/base/message_pump_glib_unittest.cc
index 9c9f288..fc604b9 100644
--- a/base/message_pump_glib_unittest.cc
+++ b/base/message_pump_glib_unittest.cc
@@ -45,7 +45,6 @@ class EventInjector {
bool HandleCheck() {
if (events_.empty())
return false;
- Event event = events_[0];
return events_[0].time <= base::Time::NowFromSystemTime();
}
diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc
index 775e940..e27a07a 100644
--- a/base/message_pump_glib_x.cc
+++ b/base/message_pump_glib_x.cc
@@ -82,6 +82,41 @@ MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
MessagePumpGlibX::~MessagePumpGlibX() {
}
+#if defined(HAVE_XINPUT2)
+void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
+ Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+
+ // Setup mask for mouse events.
+ unsigned char mask[(XI_LASTEVENT + 7)/8];
+ memset(mask, 0, sizeof(mask));
+
+ XISetMask(mask, XI_ButtonPress);
+ XISetMask(mask, XI_ButtonRelease);
+ XISetMask(mask, XI_Motion);
+
+ // It is necessary to select only for the master devices. XInput2 provides
+ // enough information to the event callback to decide which slave device
+ // triggered the event, thus decide whether the 'pointer event' is a 'mouse
+ // event' or a 'touch event'. So it is not necessary to select for the slave
+ // devices here.
+ XIEventMask evmasks[masters_.size()];
+ int count = 0;
+ for (std::set<int>::const_iterator iter = masters_.begin();
+ iter != masters_.end();
+ ++iter, ++count) {
+ evmasks[count].deviceid = *iter;
+ evmasks[count].mask_len = sizeof(mask);
+ evmasks[count].mask = mask;
+ }
+
+ XISelectEvents(xdisplay, xwindow, evmasks, masters_.size());
+
+ // TODO(sad): Setup masks for keyboard events.
+
+ XFlush(xdisplay);
+}
+#endif // HAVE_XINPUT2
+
bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
GdkDisplay* gdisp = gdk_display_get_default();
if (!gdisp)
@@ -110,7 +145,7 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
MessagePumpGlibXDispatcher::DispatchStatus status =
static_cast<MessagePumpGlibXDispatcher*>
- (GetDispatcher())->Dispatch(&xev);
+ (GetDispatcher())->DispatchX(&xev);
if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) {
should_quit = true;
@@ -166,6 +201,25 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
return retvalue;
}
+void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
+ MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);
+
+ if (!pump_x->gdksource_) {
+ pump_x->gdksource_ = g_main_current_source();
+ pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
+ } else if (!pump_x->IsDispatchingEvent()) {
+ if (event->type != GDK_NOTHING &&
+ pump_x->capture_gdk_events_[event->type]) {
+ // TODO(sad): An X event is caught by the GDK handler. Put it back in the
+ // X queue so that we catch it in the next iteration. When done, the
+ // following DLOG statement will be removed.
+ DLOG(WARNING) << "GDK received an event it shouldn't have";
+ }
+ }
+
+ pump_x->DispatchEvents(event);
+}
+
void MessagePumpGlibX::InitializeEventsToCapture(void) {
// TODO(sad): Decide which events we want to capture and update the tables
// accordingly.
@@ -237,59 +291,6 @@ void MessagePumpGlibX::InitializeXInput2(void) {
// put it off for a later time.
// Note: It is not necessary to listen for XI_DeviceChanged events.
}
-
-void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
- Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
-
- // Setup mask for mouse events.
- unsigned char mask[(XI_LASTEVENT + 7)/8];
- memset(mask, 0, sizeof(mask));
-
- XISetMask(mask, XI_ButtonPress);
- XISetMask(mask, XI_ButtonRelease);
- XISetMask(mask, XI_Motion);
-
- // It is necessary to select only for the master devices. XInput2 provides
- // enough information to the event callback to decide which slave device
- // triggered the event, thus decide whether the 'pointer event' is a 'mouse
- // event' or a 'touch event'. So it is not necessary to select for the slave
- // devices here.
- XIEventMask evmasks[masters_.size()];
- int count = 0;
- for (std::set<int>::const_iterator iter = masters_.begin();
- iter != masters_.end();
- ++iter, ++count) {
- evmasks[count].deviceid = *iter;
- evmasks[count].mask_len = sizeof(mask);
- evmasks[count].mask = mask;
- }
-
- XISelectEvents(xdisplay, xwindow, evmasks, masters_.size());
-
- // TODO(sad): Setup masks for keyboard events.
-
- XFlush(xdisplay);
-}
-
#endif // HAVE_XINPUT2
-void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
- MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);
-
- if (!pump_x->gdksource_) {
- pump_x->gdksource_ = g_main_current_source();
- pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
- } else if (!pump_x->IsDispatchingEvent()) {
- if (event->type != GDK_NOTHING &&
- pump_x->capture_gdk_events_[event->type]) {
- // TODO(sad): An X event is caught by the GDK handler. Put it back in the
- // X queue so that we catch it in the next iteration. When done, the
- // following DLOG statement will be removed.
- DLOG(WARNING) << "GDK received an event it shouldn't have";
- }
- }
-
- pump_x->DispatchEvents(event);
-}
-
} // namespace base
diff --git a/base/message_pump_glib_x_dispatch.h b/base/message_pump_glib_x_dispatch.h
index 4a97372..4c44cab 100644
--- a/base/message_pump_glib_x_dispatch.h
+++ b/base/message_pump_glib_x_dispatch.h
@@ -28,7 +28,7 @@ class MessagePumpGlibXDispatcher : public MessagePumpForUI::Dispatcher {
// Dispatches the event. EVENT_IGNORED is returned if the event was ignored
// (i.e. not processed). EVENT_PROCESSED is returned if the event was
// processed. The nested loop exits immediately if EVENT_QUIT is returned.
- virtual DispatchStatus Dispatch(XEvent* xevent) = 0;
+ virtual DispatchStatus DispatchX(XEvent* xevent) = 0;
};
} // namespace base
diff --git a/base/message_pump_libevent.cc b/base/message_pump_libevent.cc
index 1410f79..933d795 100644
--- a/base/message_pump_libevent.cc
+++ b/base/message_pump_libevent.cc
@@ -62,6 +62,19 @@ MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
}
}
+bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+ event* e = ReleaseEvent();
+ if (e == NULL)
+ return true;
+
+ // event_del() is a no-op if the event isn't active.
+ int rv = event_del(e);
+ delete e;
+ pump_ = NULL;
+ watcher_ = NULL;
+ return (rv == 0);
+}
+
void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e,
bool is_persistent) {
DCHECK(e);
@@ -77,19 +90,6 @@ event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
return e;
}
-bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
- event* e = ReleaseEvent();
- if (e == NULL)
- return true;
-
- // event_del() is a no-op if the event isn't active.
- int rv = event_del(e);
- delete e;
- pump_ = NULL;
- watcher_ = NULL;
- return (rv == 0);
-}
-
void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
int fd, MessagePumpLibevent* pump) {
pump->WillProcessIOEvent();
@@ -104,20 +104,6 @@ void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
pump->DidProcessIOEvent();
}
-// Called if a byte is received on the wakeup pipe.
-void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
- base::MessagePumpLibevent* that =
- static_cast<base::MessagePumpLibevent*>(context);
- DCHECK(that->wakeup_pipe_out_ == socket);
-
- // Remove and discard the wakeup byte.
- char buf;
- int nread = HANDLE_EINTR(read(socket, &buf, 1));
- DCHECK_EQ(nread, 1);
- // Tell libevent to break out of inner loop.
- event_base_loopbreak(that->event_base_);
-}
-
MessagePumpLibevent::MessagePumpLibevent()
: keep_running_(true),
in_run_(false),
@@ -128,33 +114,6 @@ MessagePumpLibevent::MessagePumpLibevent()
NOTREACHED();
}
-bool MessagePumpLibevent::Init() {
- int fds[2];
- if (pipe(fds)) {
- DLOG(ERROR) << "pipe() failed, errno: " << errno;
- return false;
- }
- if (SetNonBlocking(fds[0])) {
- DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
- return false;
- }
- if (SetNonBlocking(fds[1])) {
- DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
- return false;
- }
- wakeup_pipe_out_ = fds[0];
- wakeup_pipe_in_ = fds[1];
-
- wakeup_event_ = new event;
- event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
- OnWakeup, this);
- event_base_set(event_base_, wakeup_event_);
-
- if (event_add(wakeup_event_, 0))
- return false;
- return true;
-}
-
MessagePumpLibevent::~MessagePumpLibevent() {
DCHECK(wakeup_event_);
DCHECK(event_base_);
@@ -234,19 +193,12 @@ bool MessagePumpLibevent::WatchFileDescriptor(int fd,
return true;
}
-void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
- void* context) {
- FileDescriptorWatcher* controller =
- static_cast<FileDescriptorWatcher*>(context);
-
- MessagePumpLibevent* pump = controller->pump();
+void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
+ io_observers_.AddObserver(obs);
+}
- if (flags & EV_WRITE) {
- controller->OnFileCanWriteWithoutBlocking(fd, pump);
- }
- if (flags & EV_READ) {
- controller->OnFileCanReadWithoutBlocking(fd, pump);
- }
+void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
+ io_observers_.RemoveObserver(obs);
}
// Tell libevent to break out of inner loop.
@@ -334,14 +286,6 @@ void MessagePumpLibevent::ScheduleDelayedWork(
delayed_work_time_ = delayed_work_time;
}
-void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
- io_observers_.AddObserver(obs);
-}
-
-void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
- io_observers_.RemoveObserver(obs);
-}
-
void MessagePumpLibevent::WillProcessIOEvent() {
FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
}
@@ -350,4 +294,62 @@ void MessagePumpLibevent::DidProcessIOEvent() {
FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
}
+bool MessagePumpLibevent::Init() {
+ int fds[2];
+ if (pipe(fds)) {
+ DLOG(ERROR) << "pipe() failed, errno: " << errno;
+ return false;
+ }
+ if (SetNonBlocking(fds[0])) {
+ DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ return false;
+ }
+ if (SetNonBlocking(fds[1])) {
+ DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
+ return false;
+ }
+ wakeup_pipe_out_ = fds[0];
+ wakeup_pipe_in_ = fds[1];
+
+ wakeup_event_ = new event;
+ event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
+ OnWakeup, this);
+ event_base_set(event_base_, wakeup_event_);
+
+ if (event_add(wakeup_event_, 0))
+ return false;
+ return true;
+}
+
+// static
+void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+ void* context) {
+ FileDescriptorWatcher* controller =
+ static_cast<FileDescriptorWatcher*>(context);
+
+ MessagePumpLibevent* pump = controller->pump();
+
+ if (flags & EV_WRITE) {
+ controller->OnFileCanWriteWithoutBlocking(fd, pump);
+ }
+ if (flags & EV_READ) {
+ controller->OnFileCanReadWithoutBlocking(fd, pump);
+ }
+}
+
+// Called if a byte is received on the wakeup pipe.
+// static
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+ base::MessagePumpLibevent* that =
+ static_cast<base::MessagePumpLibevent*>(context);
+ DCHECK(that->wakeup_pipe_out_ == socket);
+
+ // Remove and discard the wakeup byte.
+ char buf;
+ int nread = HANDLE_EINTR(read(socket, &buf, 1));
+ DCHECK_EQ(nread, 1);
+ // Tell libevent to break out of inner loop.
+ event_base_loopbreak(that->event_base_);
+}
+
} // namespace base
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc
index 0df888a..d3f3621 100644
--- a/base/message_pump_win.cc
+++ b/base/message_pump_win.cc
@@ -421,7 +421,7 @@ void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
IOHandler* handler) {
ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1);
- DCHECK(port == port_.Get());
+ DPCHECK(port);
}
//-----------------------------------------------------------------------------
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index d29ed2d..fceccde 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -7,14 +7,15 @@
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
namespace base {
// static
-const int FieldTrial::kNotParticipating = -1;
+const int FieldTrial::kNotFinalized = -1;
// static
-const int FieldTrial::kAllRemainingProbability = -2;
+const int FieldTrial::kDefaultGroupNumber = 0;
// static
bool FieldTrial::enable_benchmarking_ = false;
@@ -28,30 +29,53 @@ static const char kHistogramFieldTrialSeparator('_');
// FieldTrial methods and members.
FieldTrial::FieldTrial(const std::string& name,
- const Probability total_probability)
+ const Probability total_probability,
+ const std::string& default_group_name,
+ const int year,
+ const int month,
+ const int day_of_month)
: name_(name),
divisor_(total_probability),
+ default_group_name_(default_group_name),
random_(static_cast<Probability>(divisor_ * base::RandDouble())),
accumulated_group_probability_(0),
- next_group_number_(0),
- group_(kNotParticipating) {
+ next_group_number_(kDefaultGroupNumber+1),
+ group_(kNotFinalized) {
+ DCHECK(!default_group_name_.empty());
FieldTrialList::Register(this);
+
+ DCHECK_GT(year, 1970);
+ DCHECK_GT(month, 0);
+ DCHECK_LT(month, 13);
+ DCHECK_GT(day_of_month, 0);
+ DCHECK_LT(day_of_month, 32);
+
+ base::Time::Exploded exploded;
+ exploded.year = year;
+ exploded.month = month;
+ exploded.day_of_week = 0; // Should be unusued.
+ exploded.day_of_month = day_of_month;
+ exploded.hour = 0;
+ exploded.minute = 0;
+ exploded.second = 0;
+ exploded.millisecond = 0;
+
+ base::Time expiration_time = Time::FromLocalExploded(exploded);
+ disable_field_trial_ = (GetBuildTime() > expiration_time) ? true : false;
}
int FieldTrial::AppendGroup(const std::string& name,
Probability group_probability) {
DCHECK(group_probability <= divisor_);
- DCHECK(group_probability >=0 ||
- group_probability == kAllRemainingProbability);
- if (group_probability == kAllRemainingProbability) {
- accumulated_group_probability_ = divisor_;
- } else {
- if (enable_benchmarking_)
- group_probability = 0;
- accumulated_group_probability_ += group_probability;
- }
+ DCHECK_GE(group_probability, 0);
+
+ if (enable_benchmarking_ || disable_field_trial_)
+ group_probability = 0;
+
+ accumulated_group_probability_ += group_probability;
+
DCHECK(accumulated_group_probability_ <= divisor_);
- if (group_ == kNotParticipating && accumulated_group_probability_ > random_) {
+ if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
// This is the group that crossed the random line, so we do the assignment.
group_ = next_group_number_;
if (name.empty())
@@ -62,6 +86,20 @@ int FieldTrial::AppendGroup(const std::string& name,
return next_group_number_++;
}
+int FieldTrial::group() {
+ if (group_ == kNotFinalized) {
+ accumulated_group_probability_ = divisor_;
+ group_ = kDefaultGroupNumber;
+ group_name_ = default_group_name_;
+ }
+ return group_;
+}
+
+std::string FieldTrial::group_name() {
+ group(); // call group() to make group assignment was done.
+ return group_name_;
+}
+
// static
std::string FieldTrial::MakeName(const std::string& name_prefix,
const std::string& trial_name) {
@@ -78,6 +116,16 @@ void FieldTrial::EnableBenchmarking() {
FieldTrial::~FieldTrial() {}
+// static
+Time FieldTrial::GetBuildTime() {
+ Time integral_build_time;
+ const char* kDateTime = __DATE__ " " __TIME__;
+ bool result = Time::FromString(ASCIIToWide(kDateTime).c_str(),
+ &integral_build_time);
+ DCHECK(result);
+ return integral_build_time;
+}
+
//------------------------------------------------------------------------------
// FieldTrialList methods and members.
@@ -117,11 +165,19 @@ void FieldTrialList::Register(FieldTrial* trial) {
}
// static
+FieldTrial* FieldTrialList::Find(const std::string& name) {
+ if (!global_)
+ return NULL;
+ AutoLock auto_lock(global_->lock_);
+ return global_->PreLockedFind(name);
+}
+
+// static
int FieldTrialList::FindValue(const std::string& name) {
FieldTrial* field_trial = Find(name);
if (field_trial)
return field_trial->group();
- return FieldTrial::kNotParticipating;
+ return FieldTrial::kNotFinalized;
}
// static
@@ -133,21 +189,6 @@ std::string FieldTrialList::FindFullName(const std::string& name) {
}
// static
-FieldTrial* FieldTrialList::Find(const std::string& name) {
- if (!global_)
- return NULL;
- AutoLock auto_lock(global_->lock_);
- return global_->PreLockedFind(name);
-}
-
-FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
- RegistrationList::iterator it = registered_.find(name);
- if (registered_.end() == it)
- return NULL;
- return it->second;
-}
-
-// static
void FieldTrialList::StatesToString(std::string* output) {
if (!global_)
return;
@@ -156,9 +197,11 @@ void FieldTrialList::StatesToString(std::string* output) {
for (RegistrationList::iterator it = global_->registered_.begin();
it != global_->registered_.end(); ++it) {
const std::string name = it->first;
- const std::string group_name = it->second->group_name();
+ std::string group_name = it->second->group_name_internal();
if (group_name.empty())
- continue; // No definitive winner in this trial.
+ // No definitive winner in this trial, use default_group_name as the
+ // group_name.
+ group_name = it->second->default_group_name();
DCHECK_EQ(name.find(kPersistentStringSeparator), std::string::npos);
DCHECK_EQ(group_name.find(kPersistentStringSeparator), std::string::npos);
output->append(name);
@@ -169,34 +212,43 @@ void FieldTrialList::StatesToString(std::string* output) {
}
// static
-bool FieldTrialList::StringAugmentsState(const std::string& prior_state) {
+bool FieldTrialList::CreateTrialsInChildProcess(
+ const std::string& parent_trials) {
DCHECK(global_);
- if (prior_state.empty() || !global_)
+ if (parent_trials.empty() || !global_)
return true;
+ Time::Exploded exploded;
+ Time two_years_from_now =
+ Time::NowFromSystemTime() + TimeDelta::FromDays(730);
+ two_years_from_now.LocalExplode(&exploded);
+ const int kTwoYearsFromNow = exploded.year;
+
size_t next_item = 0;
- while (next_item < prior_state.length()) {
- size_t name_end = prior_state.find(kPersistentStringSeparator, next_item);
- if (name_end == prior_state.npos || next_item == name_end)
+ while (next_item < parent_trials.length()) {
+ size_t name_end = parent_trials.find(kPersistentStringSeparator, next_item);
+ if (name_end == parent_trials.npos || next_item == name_end)
return false;
- size_t group_name_end = prior_state.find(kPersistentStringSeparator,
- name_end + 1);
- if (group_name_end == prior_state.npos || name_end + 1 == group_name_end)
+ size_t group_name_end = parent_trials.find(kPersistentStringSeparator,
+ name_end + 1);
+ if (group_name_end == parent_trials.npos || name_end + 1 == group_name_end)
return false;
- std::string name(prior_state, next_item, name_end - next_item);
- std::string group_name(prior_state, name_end + 1,
+ std::string name(parent_trials, next_item, name_end - next_item);
+ std::string group_name(parent_trials, name_end + 1,
group_name_end - name_end - 1);
next_item = group_name_end + 1;
FieldTrial *field_trial(FieldTrialList::Find(name));
if (field_trial) {
// In single process mode, we may have already created the field trial.
- if (field_trial->group_name() != group_name)
+ if ((field_trial->group_name_internal() != group_name) &&
+ (field_trial->default_group_name() != group_name))
return false;
continue;
}
const int kTotalProbability = 100;
- field_trial = new FieldTrial(name, kTotalProbability);
+ field_trial = new FieldTrial(name, kTotalProbability, group_name,
+ kTwoYearsFromNow, 1, 1);
field_trial->AppendGroup(group_name, kTotalProbability);
}
return true;
@@ -210,4 +262,11 @@ size_t FieldTrialList::GetFieldTrialCount() {
return global_->registered_.size();
}
+FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
+ RegistrationList::iterator it = registered_.find(name);
+ if (registered_.end() == it)
+ return NULL;
+ return it->second;
+}
+
} // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 8902077..ec3a483 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -66,36 +66,40 @@
#include <map>
#include <string>
-#include "base/lock.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
+#include "base/synchronization/lock.h"
#include "base/time.h"
namespace base {
+class FieldTrialList;
+
class FieldTrial : public RefCounted<FieldTrial> {
public:
typedef int Probability; // Probability type for being selected in a trial.
// A return value to indicate that a given instance has not yet had a group
// assignment (and hence is not yet participating in the trial).
- static const int kNotParticipating;
+ static const int kNotFinalized;
- // Provide an easy way to assign all remaining probability to a group. Note
- // that this will force an instance to participate, and make it illegal to
- // attempt to probabalistically add any other groups to the trial. When doing
- // A/B tests with timings, it is often best to define all groups, so that
- // histograms will get unique names via the MakeName() methods.
- static const Probability kAllRemainingProbability;
+ // This is the group number of the 'default' group. This provides an easy way
+ // to assign all the remaining probability to a group ('default').
+ static const int kDefaultGroupNumber;
// The name is used to register the instance with the FieldTrialList class,
// and can be used to find the trial (only one trial can be present for each
// name).
// Group probabilities that are later supplied must sum to less than or equal
- // to the total_probability.
- FieldTrial(const std::string& name, Probability total_probability);
+ // to the total_probability. Arguments year, month and day_of_month specify
+ // the expiration time. If the build time is after the expiration time then
+ // the field trial reverts to the 'default' group.
+ FieldTrial(const std::string& name, Probability total_probability,
+ const std::string& default_group_name, const int year,
+ const int month, const int day_of_month);
// Establish the name and probability of the next group in this trial.
- // Sometimes, based on construction randomization, this call may causes the
+ // Sometimes, based on construction randomization, this call may cause the
// provided group to be *THE* group selected for use in this instance.
int AppendGroup(const std::string& name, Probability group_probability);
@@ -103,14 +107,18 @@ class FieldTrial : public RefCounted<FieldTrial> {
std::string name() const { return name_; }
// Return the randomly selected group number that was assigned.
- // Return kNotParticipating if the instance is not participating in the
- // experiment.
- int group() const { return group_; }
+ // Return kDefaultGroupNumber if the instance is in the 'default' group.
+ // Note that this will force an instance to participate, and make it illegal
+ // to attempt to probabalistically add any other groups to the trial.
+ int group();
// If the field trial is not in an experiment, this returns the empty string.
// if the group's name is empty, a name of "_" concatenated with the group
// number is used as the group name.
- std::string group_name() const { return group_name_; }
+ std::string group_name();
+
+ // Return the default group name of the FieldTrial.
+ std::string default_group_name() const { return default_group_name_; }
// Helper function for the most common use: as an argument to specifiy the
// name of a HISTOGRAM. Use the original histogram name as the name_prefix.
@@ -121,17 +129,40 @@ class FieldTrial : public RefCounted<FieldTrial> {
static void EnableBenchmarking();
private:
+ // Allow tests to access our innards for testing purposes.
+ FRIEND_TEST(FieldTrialTest, Registration);
+ FRIEND_TEST(FieldTrialTest, AbsoluteProbabilities);
+ FRIEND_TEST(FieldTrialTest, RemainingProbability);
+ FRIEND_TEST(FieldTrialTest, FiftyFiftyProbability);
+ FRIEND_TEST(FieldTrialTest, MiddleProbabilities);
+ FRIEND_TEST(FieldTrialTest, OneWinner);
+ FRIEND_TEST(FieldTrialTest, DisableProbability);
+ FRIEND_TEST(FieldTrialTest, Save);
+ FRIEND_TEST(FieldTrialTest, DuplicateRestore);
+ FRIEND_TEST(FieldTrialTest, MakeName);
+
+ friend class base::FieldTrialList;
+
friend class RefCounted<FieldTrial>;
virtual ~FieldTrial();
+ // Returns the group_name. A winner need not have been chosen.
+ std::string group_name_internal() const { return group_name_; }
+
+ // Get build time.
+ static Time GetBuildTime();
+
// The name of the field trial, as can be found via the FieldTrialList.
// This is empty of the trial is not in the experiment.
const std::string name_;
// The maximum sum of all probabilities supplied, which corresponds to 100%.
// This is the scaling factor used to adjust supplied probabilities.
- Probability divisor_;
+ const Probability divisor_;
+
+ // The name of the default group.
+ const std::string default_group_name_;
// The randomly selected probability that is used to select a group (or have
// the instance not participate). It is the product of divisor_ and a random
@@ -144,15 +175,19 @@ class FieldTrial : public RefCounted<FieldTrial> {
int next_group_number_;
// The pseudo-randomly assigned group number.
- // This is kNotParticipating if no group has been assigned.
+ // This is kNotFinalized if no group has been assigned.
int group_;
- // A textual name for the randomly selected group, including the Trial name.
- // If this Trial is not a member of an group, this string is empty.
+ // A textual name for the randomly selected group. If this Trial is not a
+ // member of an group, this string is empty.
std::string group_name_;
+ // When disable_field_trial_ is true, field trial reverts to the 'default'
+ // group.
+ bool disable_field_trial_;
+
// When benchmarking is enabled, field trials all revert to the 'default'
- // bucket.
+ // group.
static bool enable_benchmarking_;
DISALLOW_COPY_AND_ASSIGN(FieldTrial);
@@ -199,7 +234,7 @@ class FieldTrialList {
// is commonly used in a sub-process, to carry randomly selected state in a
// parent process into this sub-process.
// Currently only the group_name_ and name_ are restored.
- static bool StringAugmentsState(const std::string& prior_state);
+ static bool CreateTrialsInChildProcess(const std::string& prior_trials);
// The time of construction of the global map is recorded in a static variable
// and is commonly used by experiments to identify the time since the start
@@ -236,7 +271,7 @@ class FieldTrialList {
TimeTicks application_start_time_;
// Lock for access to registered_.
- Lock lock_;
+ base::Lock lock_;
RegistrationList registered_;
DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index a8138bb..0af6d60 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -13,7 +13,23 @@ namespace base {
class FieldTrialTest : public testing::Test {
public:
- FieldTrialTest() : trial_list_() { }
+ FieldTrialTest() : trial_list_() {
+ Time now = Time::NowFromSystemTime();
+ TimeDelta oneYear = TimeDelta::FromDays(365);
+ Time::Exploded exploded;
+
+ Time next_year_time = now + oneYear;
+ next_year_time.LocalExplode(&exploded);
+ next_year_ = exploded.year;
+
+ Time last_year_time = now - oneYear;
+ last_year_time.LocalExplode(&exploded);
+ last_year_ = exploded.year;
+ }
+
+ protected:
+ int next_year_;
+ int last_year_;
private:
FieldTrialList trial_list_;
@@ -27,20 +43,22 @@ TEST_F(FieldTrialTest, Registration) {
EXPECT_FALSE(FieldTrialList::Find(name1));
EXPECT_FALSE(FieldTrialList::Find(name2));
- FieldTrial* trial1 = new FieldTrial(name1, 10);
- EXPECT_EQ(FieldTrial::kNotParticipating, trial1->group());
+ FieldTrial* trial1 =
+ new FieldTrial(name1, 10, "default name 1 test", next_year_, 12, 31);
+ EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
EXPECT_EQ(name1, trial1->name());
- EXPECT_EQ("", trial1->group_name());
+ EXPECT_EQ("", trial1->group_name_internal());
trial1->AppendGroup("", 7);
EXPECT_EQ(trial1, FieldTrialList::Find(name1));
EXPECT_FALSE(FieldTrialList::Find(name2));
- FieldTrial* trial2 = new FieldTrial(name2, 10);
- EXPECT_EQ(FieldTrial::kNotParticipating, trial2->group());
+ FieldTrial* trial2 =
+ new FieldTrial(name2, 10, "default name 2 test", next_year_, 12, 31);
+ EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
EXPECT_EQ(name2, trial2->name());
- EXPECT_EQ("", trial2->group_name());
+ EXPECT_EQ("", trial2->group_name_internal());
trial2->AppendGroup("a first group", 7);
@@ -51,20 +69,28 @@ TEST_F(FieldTrialTest, Registration) {
TEST_F(FieldTrialTest, AbsoluteProbabilities) {
char always_true[] = " always true";
+ char default_always_true[] = " default always true";
char always_false[] = " always false";
+ char default_always_false[] = " default always false";
for (int i = 1; i < 250; ++i) {
// Try lots of names, by changing the first character of the name.
always_true[0] = i;
+ default_always_true[0] = i;
always_false[0] = i;
+ default_always_false[0] = i;
- FieldTrial* trial_true = new FieldTrial(always_true, 10);
+ FieldTrial* trial_true =
+ new FieldTrial(
+ always_true, 10, default_always_true, next_year_, 12, 31);
const std::string winner = "TheWinner";
int winner_group = trial_true->AppendGroup(winner, 10);
EXPECT_EQ(winner_group, trial_true->group());
EXPECT_EQ(winner, trial_true->group_name());
- FieldTrial* trial_false = new FieldTrial(always_false, 10);
+ FieldTrial* trial_false =
+ new FieldTrial(
+ always_false, 10, default_always_false, next_year_, 12, 31);
int loser_group = trial_false->AppendGroup("ALoser", 0);
EXPECT_NE(loser_group, trial_false->group());
@@ -79,12 +105,13 @@ TEST_F(FieldTrialTest, RemainingProbability) {
int counter = 0;
do {
std::string name = StringPrintf("trial%d", ++counter);
- trial = new FieldTrial(name, 10);
+ trial = new FieldTrial(name, 10, winner, next_year_, 12, 31);
trial->AppendGroup(loser, 5); // 50% chance of not being chosen.
- } while (trial->group() != FieldTrial::kNotParticipating);
+ // If a group is not assigned, group_ will be kNotFinalized.
+ } while (trial->group_ != FieldTrial::kNotFinalized);
- // Now add a winner with all remaining probability.
- trial->AppendGroup(winner, FieldTrial::kAllRemainingProbability);
+ // And that 'default' group (winner) should always win.
+ EXPECT_EQ(FieldTrial::kDefaultGroupNumber, trial->group());
// And that winner should ALWAYS win.
EXPECT_EQ(winner, trial->group_name());
@@ -100,14 +127,18 @@ TEST_F(FieldTrialTest, FiftyFiftyProbability) {
int counter = 0;
do {
std::string name = base::StringPrintf("FiftyFifty%d", ++counter);
- scoped_refptr<FieldTrial> trial(new FieldTrial(name, 2));
+ std::string default_group_name = base::StringPrintf("Default FiftyFifty%d",
+ ++counter);
+ scoped_refptr<FieldTrial> trial(
+ new FieldTrial(name, 2, default_group_name, next_year_, 12, 31));
trial->AppendGroup("first", 1); // 50% chance of being chosen.
- if (trial->group() != FieldTrial::kNotParticipating) {
+ // If group_ is kNotFinalized, then a group assignement hasn't been done.
+ if (trial->group_ != FieldTrial::kNotFinalized) {
first_winner = true;
continue;
}
trial->AppendGroup("second", 1); // Always chosen at this point.
- EXPECT_NE(FieldTrial::kNotParticipating, trial->group());
+ EXPECT_NE(FieldTrial::kNotFinalized, trial->group());
second_winner = true;
} while ((!second_winner || !first_winner) && counter < 100);
EXPECT_TRUE(second_winner);
@@ -116,11 +147,14 @@ TEST_F(FieldTrialTest, FiftyFiftyProbability) {
TEST_F(FieldTrialTest, MiddleProbabilities) {
char name[] = " same name";
+ char default_group_name[] = " default same name";
bool false_event_seen = false;
bool true_event_seen = false;
for (int i = 1; i < 250; ++i) {
name[0] = i;
- FieldTrial* trial = new FieldTrial(name, 10);
+ default_group_name[0] = i;
+ FieldTrial* trial =
+ new FieldTrial(name, 10, default_group_name, next_year_, 12, 31);
int might_win = trial->AppendGroup("MightWin", 5);
if (trial->group() == might_win) {
@@ -139,16 +173,21 @@ TEST_F(FieldTrialTest, MiddleProbabilities) {
TEST_F(FieldTrialTest, OneWinner) {
char name[] = "Some name";
+ char default_group_name[] = "Default some name";
int group_count(10);
- FieldTrial* trial = new FieldTrial(name, group_count);
+ FieldTrial* trial =
+ new FieldTrial(
+ name, group_count, default_group_name, next_year_, 12, 31);
int winner_index(-2);
std::string winner_name;
for (int i = 1; i <= group_count; ++i) {
int might_win = trial->AppendGroup("", 1);
- if (trial->group() == might_win) {
+ // Because we keep appending groups, we want to see if the last group that
+ // was added has been assigned or not.
+ if (trial->group_ == might_win) {
EXPECT_EQ(-2, winner_index);
winner_index = might_win;
StringAppendF(&winner_name, "%d", might_win);
@@ -160,14 +199,34 @@ TEST_F(FieldTrialTest, OneWinner) {
EXPECT_EQ(trial->group_name(), winner_name);
}
+TEST_F(FieldTrialTest, DisableProbability) {
+ const std::string default_group_name = "Default group";
+ const std::string loser = "Loser";
+ const std::string name = "Trial";
+
+ // Create a field trail that has expired.
+ scoped_refptr<FieldTrial> trial;
+ trial = new FieldTrial(
+ name, 1000000000, default_group_name, last_year_, 1, 1);
+ trial->AppendGroup(loser, 999999999); // 99.9999999% chance of being chosen.
+
+ // Because trial has expired, we should always be in the default group.
+ EXPECT_EQ(FieldTrial::kDefaultGroupNumber, trial->group());
+
+ // And that default_group_name should ALWAYS win.
+ EXPECT_EQ(default_group_name, trial->group_name());
+}
+
TEST_F(FieldTrialTest, Save) {
std::string save_string;
- FieldTrial* trial = new FieldTrial("Some name", 10);
+ FieldTrial* trial =
+ new FieldTrial(
+ "Some name", 10, "Default some name", next_year_, 12, 31);
// There is no winner yet, so no textual group name is associated with trial.
- EXPECT_EQ("", trial->group_name());
+ EXPECT_EQ("", trial->group_name_internal());
FieldTrialList::StatesToString(&save_string);
- EXPECT_EQ("", save_string);
+ EXPECT_EQ("Some name/Default some name/", save_string);
save_string.clear();
// Create a winning group.
@@ -177,7 +236,8 @@ TEST_F(FieldTrialTest, Save) {
save_string.clear();
// Create a second trial and winning group.
- FieldTrial* trial2 = new FieldTrial("xxx", 10);
+ FieldTrial* trial2 =
+ new FieldTrial("xxx", 10, "Default xxx", next_year_, 12, 31);
trial2->AppendGroup("yyyy", 10);
FieldTrialList::StatesToString(&save_string);
@@ -189,7 +249,7 @@ TEST_F(FieldTrialTest, Restore) {
EXPECT_TRUE(FieldTrialList::Find("Some_name") == NULL);
EXPECT_TRUE(FieldTrialList::Find("xxx") == NULL);
- FieldTrialList::StringAugmentsState("Some_name/Winner/xxx/yyyy/");
+ FieldTrialList::CreateTrialsInChildProcess("Some_name/Winner/xxx/yyyy/");
FieldTrial* trial = FieldTrialList::Find("Some_name");
ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
@@ -203,29 +263,34 @@ TEST_F(FieldTrialTest, Restore) {
}
TEST_F(FieldTrialTest, BogusRestore) {
- EXPECT_FALSE(FieldTrialList::StringAugmentsState("MissingSlash"));
- EXPECT_FALSE(FieldTrialList::StringAugmentsState("MissingGroupName/"));
- EXPECT_FALSE(FieldTrialList::StringAugmentsState("MissingFinalSlash/gname"));
- EXPECT_FALSE(FieldTrialList::StringAugmentsState("/noname, only group/"));
+ EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("MissingSlash"));
+ EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("MissingGroupName/"));
+ EXPECT_FALSE(
+ FieldTrialList::CreateTrialsInChildProcess("MissingFinalSlash/gname"));
+ EXPECT_FALSE(
+ FieldTrialList::CreateTrialsInChildProcess("/noname, only group/"));
}
TEST_F(FieldTrialTest, DuplicateRestore) {
- FieldTrial* trial = new FieldTrial("Some name", 10);
+ FieldTrial* trial =
+ new FieldTrial(
+ "Some name", 10, "Default some name", next_year_, 12, 31);
trial->AppendGroup("Winner", 10);
std::string save_string;
FieldTrialList::StatesToString(&save_string);
EXPECT_EQ("Some name/Winner/", save_string);
// It is OK if we redundantly specify a winner.
- EXPECT_TRUE(FieldTrialList::StringAugmentsState(save_string));
+ EXPECT_TRUE(FieldTrialList::CreateTrialsInChildProcess(save_string));
// But it is an error to try to change to a different winner.
- EXPECT_FALSE(FieldTrialList::StringAugmentsState("Some name/Loser/"));
+ EXPECT_FALSE(FieldTrialList::CreateTrialsInChildProcess("Some name/Loser/"));
}
TEST_F(FieldTrialTest, MakeName) {
- FieldTrial* trial = new FieldTrial("Field Trial", 10);
- trial->AppendGroup("Winner", 10);
+ FieldTrial* trial =
+ new FieldTrial("Field Trial", 10, "Winner", next_year_, 12, 31);
+ trial->group();
EXPECT_EQ("Histogram_Winner",
FieldTrial::MakeName("Histogram", "Field Trial"));
}
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 1526cd8..a308932 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -53,48 +53,6 @@ scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name,
bucket_count, flags);
}
-Histogram::Histogram(const std::string& name, Sample minimum,
- Sample maximum, size_t bucket_count)
- : histogram_name_(name),
- declared_min_(minimum),
- declared_max_(maximum),
- bucket_count_(bucket_count),
- flags_(kNoFlags),
- ranges_(bucket_count + 1, 0),
- range_checksum_(0),
- sample_() {
- Initialize();
-}
-
-Histogram::Histogram(const std::string& name, TimeDelta minimum,
- TimeDelta maximum, size_t bucket_count)
- : histogram_name_(name),
- declared_min_(static_cast<int> (minimum.InMilliseconds())),
- declared_max_(static_cast<int> (maximum.InMilliseconds())),
- bucket_count_(bucket_count),
- flags_(kNoFlags),
- ranges_(bucket_count + 1, 0),
- range_checksum_(0),
- sample_() {
- Initialize();
-}
-
-Histogram::~Histogram() {
- if (StatisticsRecorder::dump_on_exit()) {
- std::string output;
- WriteAscii(true, "\n", &output);
- LOG(INFO) << output;
- }
-
- // Just to make sure most derived class did this properly...
- DCHECK(ValidateBucketRanges());
- DCHECK(HasValidRangeChecksum());
-}
-
-bool Histogram::PrintEmptyBucket(size_t index) const {
- return true;
-}
-
void Histogram::Add(int value) {
if (value > kSampleType_MAX - 1)
value = kSampleType_MAX - 1;
@@ -190,31 +148,223 @@ void Histogram::WriteAscii(bool graph_it, const std::string& newline,
DCHECK_EQ(sample_count, past);
}
-bool Histogram::ValidateBucketRanges() const {
- // Standard assertions that all bucket ranges should satisfy.
- DCHECK_EQ(bucket_count_ + 1, ranges_.size());
- DCHECK_EQ(0, ranges_[0]);
- DCHECK_EQ(declared_min(), ranges_[1]);
- DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
- DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
+// static
+std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
+ const SampleSet& snapshot) {
+ DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
+
+ Pickle pickle;
+ pickle.WriteString(histogram.histogram_name());
+ pickle.WriteInt(histogram.declared_min());
+ pickle.WriteInt(histogram.declared_max());
+ pickle.WriteSize(histogram.bucket_count());
+ pickle.WriteInt(histogram.range_checksum());
+ pickle.WriteInt(histogram.histogram_type());
+ pickle.WriteInt(histogram.flags());
+
+ snapshot.Serialize(&pickle);
+ return std::string(static_cast<const char*>(pickle.data()), pickle.size());
+}
+
+// static
+bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
+ if (histogram_info.empty()) {
+ return false;
+ }
+
+ Pickle pickle(histogram_info.data(),
+ static_cast<int>(histogram_info.size()));
+ std::string histogram_name;
+ int declared_min;
+ int declared_max;
+ size_t bucket_count;
+ int range_checksum;
+ int histogram_type;
+ int pickle_flags;
+ SampleSet sample;
+
+ void* iter = NULL;
+ if (!pickle.ReadString(&iter, &histogram_name) ||
+ !pickle.ReadInt(&iter, &declared_min) ||
+ !pickle.ReadInt(&iter, &declared_max) ||
+ !pickle.ReadSize(&iter, &bucket_count) ||
+ !pickle.ReadInt(&iter, &range_checksum) ||
+ !pickle.ReadInt(&iter, &histogram_type) ||
+ !pickle.ReadInt(&iter, &pickle_flags) ||
+ !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
+ LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
+ return false;
+ }
+ DCHECK(pickle_flags & kIPCSerializationSourceFlag);
+ // Since these fields may have come from an untrusted renderer, do additional
+ // checks above and beyond those in Histogram::Initialize()
+ if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
+ INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
+ LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
+ return false;
+ }
+
+ Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
+
+ DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
+
+ scoped_refptr<Histogram> render_histogram(NULL);
+
+ if (histogram_type == HISTOGRAM) {
+ render_histogram = Histogram::FactoryGet(
+ histogram_name, declared_min, declared_max, bucket_count, flags);
+ } else if (histogram_type == LINEAR_HISTOGRAM) {
+ render_histogram = LinearHistogram::FactoryGet(
+ histogram_name, declared_min, declared_max, bucket_count, flags);
+ } else if (histogram_type == BOOLEAN_HISTOGRAM) {
+ render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
+ } else {
+ LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
+ << histogram_type;
+ return false;
+ }
+
+ DCHECK_EQ(render_histogram->declared_min(), declared_min);
+ DCHECK_EQ(render_histogram->declared_max(), declared_max);
+ DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
+ DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
+ DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
+
+ if (render_histogram->flags() & kIPCSerializationSourceFlag) {
+ DVLOG(1) << "Single process mode, histogram observed and not copied: "
+ << histogram_name;
+ } else {
+ DCHECK_EQ(flags & render_histogram->flags(), flags);
+ render_histogram->AddSampleSet(sample);
+ }
+
return true;
}
-void Histogram::Initialize() {
- sample_.Resize(*this);
- if (declared_min_ < 1)
- declared_min_ = 1;
- if (declared_max_ > kSampleType_MAX - 1)
- declared_max_ = kSampleType_MAX - 1;
- DCHECK_LE(declared_min_, declared_max_);
- DCHECK_GT(bucket_count_, 1u);
- size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
- DCHECK_LE(bucket_count_, maximal_bucket_count);
- DCHECK_EQ(0, ranges_[0]);
- ranges_[bucket_count_] = kSampleType_MAX;
- InitializeBucketRange();
+//------------------------------------------------------------------------------
+// Methods for the validating a sample and a related histogram.
+//------------------------------------------------------------------------------
+
+Histogram::Inconsistencies Histogram::FindCorruption(
+ const SampleSet& snapshot) const {
+ int inconsistencies = NO_INCONSISTENCIES;
+ Sample previous_range = -1; // Bottom range is always 0.
+ Sample checksum = 0;
+ int64 count = 0;
+ for (size_t index = 0; index < bucket_count(); ++index) {
+ count += snapshot.counts(index);
+ int new_range = ranges(index);
+ checksum += new_range;
+ if (previous_range >= new_range)
+ inconsistencies |= BUCKET_ORDER_ERROR;
+ previous_range = new_range;
+ }
+
+ if (checksum != range_checksum_)
+ inconsistencies |= RANGE_CHECKSUM_ERROR;
+
+ int64 delta64 = snapshot.redundant_count() - count;
+ if (delta64 != 0) {
+ int delta = static_cast<int>(delta64);
+ if (delta != delta64)
+ delta = INT_MAX; // Flag all giant errors as INT_MAX.
+ // Since snapshots of histograms are taken asynchronously relative to
+ // sampling (and snapped from different threads), it is pretty likely that
+ // we'll catch a redundant count that doesn't match the sample count. We
+ // allow for a certain amount of slop before flagging this as an
+ // inconsistency. Even with an inconsistency, we'll snapshot it again (for
+ // UMA in about a half hour, so we'll eventually get the data, if it was
+ // not the result of a corruption. If histograms show that 1 is "too tight"
+ // then we may try to use 2 or 3 for this slop value.
+ const int kCommonRaceBasedCountMismatch = 1;
+ if (delta > 0) {
+ UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
+ if (delta > kCommonRaceBasedCountMismatch)
+ inconsistencies |= COUNT_HIGH_ERROR;
+ } else {
+ DCHECK_GT(0, delta);
+ UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
+ if (-delta > kCommonRaceBasedCountMismatch)
+ inconsistencies |= COUNT_LOW_ERROR;
+ }
+ }
+ return static_cast<Inconsistencies>(inconsistencies);
+}
+
+Histogram::ClassType Histogram::histogram_type() const {
+ return HISTOGRAM;
+}
+
+Histogram::Sample Histogram::ranges(size_t i) const {
+ return ranges_[i];
+}
+
+size_t Histogram::bucket_count() const {
+ return bucket_count_;
+}
+
+// Do a safe atomic snapshot of sample data.
+// This implementation assumes we are on a safe single thread.
+void Histogram::SnapshotSample(SampleSet* sample) const {
+ // Note locking not done in this version!!!
+ *sample = sample_;
+}
+
+bool Histogram::HasConstructorArguments(Sample minimum,
+ Sample maximum,
+ size_t bucket_count) {
+ return ((minimum == declared_min_) && (maximum == declared_max_) &&
+ (bucket_count == bucket_count_));
+}
+
+bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count) {
+ return ((minimum.InMilliseconds() == declared_min_) &&
+ (maximum.InMilliseconds() == declared_max_) &&
+ (bucket_count == bucket_count_));
+}
+
+Histogram::Histogram(const std::string& name, Sample minimum,
+ Sample maximum, size_t bucket_count)
+ : histogram_name_(name),
+ declared_min_(minimum),
+ declared_max_(maximum),
+ bucket_count_(bucket_count),
+ flags_(kNoFlags),
+ ranges_(bucket_count + 1, 0),
+ range_checksum_(0),
+ sample_() {
+ Initialize();
+}
+
+Histogram::Histogram(const std::string& name, TimeDelta minimum,
+ TimeDelta maximum, size_t bucket_count)
+ : histogram_name_(name),
+ declared_min_(static_cast<int> (minimum.InMilliseconds())),
+ declared_max_(static_cast<int> (maximum.InMilliseconds())),
+ bucket_count_(bucket_count),
+ flags_(kNoFlags),
+ ranges_(bucket_count + 1, 0),
+ range_checksum_(0),
+ sample_() {
+ Initialize();
+}
+
+Histogram::~Histogram() {
+ if (StatisticsRecorder::dump_on_exit()) {
+ std::string output;
+ WriteAscii(true, "\n", &output);
+ LOG(INFO) << output;
+ }
+
+ // Just to make sure most derived class did this properly...
DCHECK(ValidateBucketRanges());
- StatisticsRecorder::Register(this);
+ DCHECK(HasValidRangeChecksum());
+}
+
+bool Histogram::PrintEmptyBucket(size_t index) const {
+ return true;
}
// Calculate what range of values are held in each bucket.
@@ -295,60 +445,64 @@ void Histogram::ResetRangeChecksum() {
range_checksum_ = CalculateRangeChecksum();
}
-bool Histogram::HasValidRangeChecksum() const {
- return CalculateRangeChecksum() == range_checksum_;
-}
-
-Histogram::Sample Histogram::CalculateRangeChecksum() const {
- DCHECK_EQ(ranges_.size(), bucket_count() + 1);
- Sample checksum = 0;
- for (size_t index = 0; index < bucket_count(); ++index) {
- checksum += ranges(index);
- }
- return checksum;
+const std::string Histogram::GetAsciiBucketRange(size_t i) const {
+ std::string result;
+ if (kHexRangePrintingFlag & flags_)
+ StringAppendF(&result, "%#x", ranges(i));
+ else
+ StringAppendF(&result, "%d", ranges(i));
+ return result;
}
-//------------------------------------------------------------------------------
-// The following two methods can be overridden to provide a thread safe
-// version of this class. The cost of locking is low... but an error in each
-// of these methods has minimal impact. For now, I'll leave this unlocked,
-// and I don't believe I can loose more than a count or two.
-// The vectors are NOT reallocated, so there is no risk of them moving around.
-
// Update histogram data with new sample.
void Histogram::Accumulate(Sample value, Count count, size_t index) {
// Note locking not done in this version!!!
sample_.Accumulate(value, count, index);
}
-// Do a safe atomic snapshot of sample data.
-// This implementation assumes we are on a safe single thread.
-void Histogram::SnapshotSample(SampleSet* sample) const {
- // Note locking not done in this version!!!
- *sample = sample_;
+void Histogram::SetBucketRange(size_t i, Sample value) {
+ DCHECK_GT(bucket_count_, i);
+ ranges_[i] = value;
}
-bool Histogram::HasConstructorArguments(Sample minimum,
- Sample maximum,
- size_t bucket_count) {
- return ((minimum == declared_min_) && (maximum == declared_max_) &&
- (bucket_count == bucket_count_));
+bool Histogram::ValidateBucketRanges() const {
+ // Standard assertions that all bucket ranges should satisfy.
+ DCHECK_EQ(bucket_count_ + 1, ranges_.size());
+ DCHECK_EQ(0, ranges_[0]);
+ DCHECK_EQ(declared_min(), ranges_[1]);
+ DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
+ DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
+ return true;
}
-bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
- TimeDelta maximum,
- size_t bucket_count) {
- return ((minimum.InMilliseconds() == declared_min_) &&
- (maximum.InMilliseconds() == declared_max_) &&
- (bucket_count == bucket_count_));
+void Histogram::Initialize() {
+ sample_.Resize(*this);
+ if (declared_min_ < 1)
+ declared_min_ = 1;
+ if (declared_max_ > kSampleType_MAX - 1)
+ declared_max_ = kSampleType_MAX - 1;
+ DCHECK_LE(declared_min_, declared_max_);
+ DCHECK_GT(bucket_count_, 1u);
+ size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
+ DCHECK_LE(bucket_count_, maximal_bucket_count);
+ DCHECK_EQ(0, ranges_[0]);
+ ranges_[bucket_count_] = kSampleType_MAX;
+ InitializeBucketRange();
+ DCHECK(ValidateBucketRanges());
+ StatisticsRecorder::Register(this);
}
-//------------------------------------------------------------------------------
-// Accessor methods
+bool Histogram::HasValidRangeChecksum() const {
+ return CalculateRangeChecksum() == range_checksum_;
+}
-void Histogram::SetBucketRange(size_t i, Sample value) {
- DCHECK_GT(bucket_count_, i);
- ranges_[i] = value;
+Histogram::Sample Histogram::CalculateRangeChecksum() const {
+ DCHECK_EQ(ranges_.size(), bucket_count() + 1);
+ Sample checksum = 0;
+ for (size_t index = 0; index < bucket_count(); ++index) {
+ checksum += ranges(index);
+ }
+ return checksum;
}
//------------------------------------------------------------------------------
@@ -400,15 +554,6 @@ void Histogram::WriteAsciiBucketContext(const int64 past,
}
}
-const std::string Histogram::GetAsciiBucketRange(size_t i) const {
- std::string result;
- if (kHexRangePrintingFlag & flags_)
- StringAppendF(&result, "%#x", ranges(i));
- else
- StringAppendF(&result, "%d", ranges(i));
- return result;
-}
-
void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum,
std::string* output) const {
StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
@@ -428,161 +573,6 @@ void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
output->append(" ");
}
-// static
-std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
- const SampleSet& snapshot) {
- DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
-
- Pickle pickle;
- pickle.WriteString(histogram.histogram_name());
- pickle.WriteInt(histogram.declared_min());
- pickle.WriteInt(histogram.declared_max());
- pickle.WriteSize(histogram.bucket_count());
- pickle.WriteInt(histogram.range_checksum());
- pickle.WriteInt(histogram.histogram_type());
- pickle.WriteInt(histogram.flags());
-
- snapshot.Serialize(&pickle);
- return std::string(static_cast<const char*>(pickle.data()), pickle.size());
-}
-
-// static
-bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
- if (histogram_info.empty()) {
- return false;
- }
-
- Pickle pickle(histogram_info.data(),
- static_cast<int>(histogram_info.size()));
- std::string histogram_name;
- int declared_min;
- int declared_max;
- size_t bucket_count;
- int range_checksum;
- int histogram_type;
- int pickle_flags;
- SampleSet sample;
-
- void* iter = NULL;
- if (!pickle.ReadString(&iter, &histogram_name) ||
- !pickle.ReadInt(&iter, &declared_min) ||
- !pickle.ReadInt(&iter, &declared_max) ||
- !pickle.ReadSize(&iter, &bucket_count) ||
- !pickle.ReadInt(&iter, &range_checksum) ||
- !pickle.ReadInt(&iter, &histogram_type) ||
- !pickle.ReadInt(&iter, &pickle_flags) ||
- !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
- LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
- return false;
- }
- DCHECK(pickle_flags & kIPCSerializationSourceFlag);
- // Since these fields may have come from an untrusted renderer, do additional
- // checks above and beyond those in Histogram::Initialize()
- if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
- INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
- LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
- return false;
- }
-
- Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
-
- DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
-
- scoped_refptr<Histogram> render_histogram(NULL);
-
- if (histogram_type == HISTOGRAM) {
- render_histogram = Histogram::FactoryGet(
- histogram_name, declared_min, declared_max, bucket_count, flags);
- } else if (histogram_type == LINEAR_HISTOGRAM) {
- render_histogram = LinearHistogram::FactoryGet(
- histogram_name, declared_min, declared_max, bucket_count, flags);
- } else if (histogram_type == BOOLEAN_HISTOGRAM) {
- render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
- } else {
- LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
- << histogram_type;
- return false;
- }
-
- DCHECK_EQ(render_histogram->declared_min(), declared_min);
- DCHECK_EQ(render_histogram->declared_max(), declared_max);
- DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
- DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
- DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
-
- if (render_histogram->flags() & kIPCSerializationSourceFlag) {
- DVLOG(1) << "Single process mode, histogram observed and not copied: "
- << histogram_name;
- } else {
- DCHECK_EQ(flags & render_histogram->flags(), flags);
- render_histogram->AddSampleSet(sample);
- }
-
- return true;
-}
-
-//------------------------------------------------------------------------------
-// Methods for the validating a sample and a related histogram.
-//------------------------------------------------------------------------------
-
-Histogram::Inconsistencies Histogram::FindCorruption(
- const SampleSet& snapshot) const {
- int inconsistencies = NO_INCONSISTENCIES;
- Sample previous_range = -1; // Bottom range is always 0.
- Sample checksum = 0;
- int64 count = 0;
- for (size_t index = 0; index < bucket_count(); ++index) {
- count += snapshot.counts(index);
- int new_range = ranges(index);
- checksum += new_range;
- if (previous_range >= new_range)
- inconsistencies |= BUCKET_ORDER_ERROR;
- previous_range = new_range;
- }
-
- if (checksum != range_checksum_)
- inconsistencies |= RANGE_CHECKSUM_ERROR;
-
- int64 delta64 = snapshot.redundant_count() - count;
- if (delta64 != 0) {
- int delta = static_cast<int>(delta64);
- if (delta != delta64)
- delta = INT_MAX; // Flag all giant errors as INT_MAX.
- // Since snapshots of histograms are taken asynchronously relative to
- // sampling (and snapped from different threads), it is pretty likely that
- // we'll catch a redundant count that doesn't match the sample count. We
- // allow for a certain amount of slop before flagging this as an
- // inconsistency. Even with an inconsistency, we'll snapshot it again (for
- // UMA in about a half hour, so we'll eventually get the data, if it was
- // not the result of a corruption. If histograms show that 1 is "too tight"
- // then we may try to use 2 or 3 for this slop value.
- const int kCommonRaceBasedCountMismatch = 1;
- if (delta > 0) {
- UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
- if (delta > kCommonRaceBasedCountMismatch)
- inconsistencies |= COUNT_HIGH_ERROR;
- } else {
- DCHECK_GT(0, delta);
- UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
- if (-delta > kCommonRaceBasedCountMismatch)
- inconsistencies |= COUNT_LOW_ERROR;
- }
- }
- return static_cast<Inconsistencies>(inconsistencies);
-}
-
-Histogram::ClassType Histogram::histogram_type() const {
- return HISTOGRAM;
-}
-
-Histogram::Sample Histogram::ranges(size_t i) const {
- return ranges_[i];
-}
-
-size_t Histogram::bucket_count() const {
- return bucket_count_;
-}
-
//------------------------------------------------------------------------------
// Methods for the Histogram::SampleSet class
//------------------------------------------------------------------------------
@@ -700,6 +690,9 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
// buckets.
//------------------------------------------------------------------------------
+LinearHistogram::~LinearHistogram() {
+}
+
scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
Sample minimum,
Sample maximum,
@@ -733,7 +726,15 @@ scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet(
bucket_count, flags);
}
-LinearHistogram::~LinearHistogram() {
+Histogram::ClassType LinearHistogram::histogram_type() const {
+ return LINEAR_HISTOGRAM;
+}
+
+void LinearHistogram::SetRangeDescriptions(
+ const DescriptionPair descriptions[]) {
+ for (int i =0; descriptions[i].description; ++i) {
+ bucket_description_[descriptions[i].sample] = descriptions[i].description;
+ }
}
LinearHistogram::LinearHistogram(const std::string& name,
@@ -757,30 +758,6 @@ LinearHistogram::LinearHistogram(const std::string& name,
DCHECK(ValidateBucketRanges());
}
-Histogram::ClassType LinearHistogram::histogram_type() const {
- return LINEAR_HISTOGRAM;
-}
-
-void LinearHistogram::SetRangeDescriptions(
- const DescriptionPair descriptions[]) {
- for (int i =0; descriptions[i].description; ++i) {
- bucket_description_[descriptions[i].sample] = descriptions[i].description;
- }
-}
-
-const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
- int range = ranges(i);
- BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
- if (it == bucket_description_.end())
- return Histogram::GetAsciiBucketRange(i);
- return it->second;
-}
-
-bool LinearHistogram::PrintEmptyBucket(size_t index) const {
- return bucket_description_.find(ranges(index)) == bucket_description_.end();
-}
-
-
void LinearHistogram::InitializeBucketRange() {
DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here.
double min = declared_min();
@@ -802,6 +779,19 @@ double LinearHistogram::GetBucketSize(Count current, size_t i) const {
return current/denominator;
}
+const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
+ int range = ranges(i);
+ BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
+ if (it == bucket_description_.end())
+ return Histogram::GetAsciiBucketRange(i);
+ return it->second;
+}
+
+bool LinearHistogram::PrintEmptyBucket(size_t index) const {
+ return bucket_description_.find(ranges(index)) == bucket_description_.end();
+}
+
+
//------------------------------------------------------------------------------
// This section provides implementation for BooleanHistogram.
//------------------------------------------------------------------------------
diff --git a/base/metrics/stats_table.cc b/base/metrics/stats_table.cc
index 757c08e..0e8d016 100644
--- a/base/metrics/stats_table.cc
+++ b/base/metrics/stats_table.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -136,7 +136,14 @@ class StatsTable::Private {
private:
// Constructor is private because you should use New() instead.
- Private() {}
+ Private()
+ : table_header_(NULL),
+ thread_names_table_(NULL),
+ thread_tid_table_(NULL),
+ thread_pid_table_(NULL),
+ counter_names_table_(NULL),
+ data_table_(NULL) {
+ }
// Initializes the table on first access. Sets header values
// appropriately and zeroes all counters.
@@ -282,6 +289,13 @@ StatsTable::~StatsTable() {
global_table_ = NULL;
}
+int StatsTable::GetSlot() const {
+ TLSData* data = GetTLSData();
+ if (!data)
+ return 0;
+ return data->slot;
+}
+
int StatsTable::RegisterThread(const std::string& name) {
#ifdef ANDROID
return 0;
@@ -319,15 +333,121 @@ int StatsTable::RegisterThread(const std::string& name) {
#endif
}
-StatsTable::TLSData* StatsTable::GetTLSData() const {
- TLSData* data =
- static_cast<TLSData*>(tls_index_.Get());
- if (!data)
+int StatsTable::CountThreadsRegistered() const {
+ if (!impl_)
+ return 0;
+
+ // Loop through the shared memory and count the threads that are active.
+ // We intentionally do not lock the table during the operation.
+ int count = 0;
+ for (int index = 1; index <= impl_->max_threads(); index++) {
+ char* name = impl_->thread_name(index);
+ if (*name != '\0')
+ count++;
+ }
+ return count;
+}
+
+int StatsTable::FindCounter(const std::string& name) {
+ // Note: the API returns counters numbered from 1..N, although
+ // internally, the array is 0..N-1. This is so that we can return
+ // zero as "not found".
+ if (!impl_)
+ return 0;
+
+ // Create a scope for our auto-lock.
+ {
+ AutoLock scoped_lock(counters_lock_);
+
+ // Attempt to find the counter.
+ CountersMap::const_iterator iter;
+ iter = counters_.find(name);
+ if (iter != counters_.end())
+ return iter->second;
+ }
+
+ // Counter does not exist, so add it.
+ return AddCounter(name);
+}
+
+int* StatsTable::GetLocation(int counter_id, int slot_id) const {
+ if (!impl_)
+ return NULL;
+ if (slot_id > impl_->max_threads())
return NULL;
- DCHECK(data->slot);
- DCHECK_EQ(data->table, this);
- return data;
+ int* row = impl_->row(counter_id);
+ return &(row[slot_id-1]);
+}
+
+const char* StatsTable::GetRowName(int index) const {
+ if (!impl_)
+ return NULL;
+
+ return impl_->counter_name(index);
+}
+
+int StatsTable::GetRowValue(int index) const {
+ return GetRowValue(index, 0);
+}
+
+int StatsTable::GetRowValue(int index, int pid) const {
+ if (!impl_)
+ return 0;
+
+ int rv = 0;
+ int* row = impl_->row(index);
+ for (int slot_id = 0; slot_id < impl_->max_threads(); slot_id++) {
+ if (pid == 0 || *impl_->thread_pid(slot_id) == pid)
+ rv += row[slot_id];
+ }
+ return rv;
+}
+
+int StatsTable::GetCounterValue(const std::string& name) {
+ return GetCounterValue(name, 0);
+}
+
+int StatsTable::GetCounterValue(const std::string& name, int pid) {
+ if (!impl_)
+ return 0;
+
+ int row = FindCounter(name);
+ if (!row)
+ return 0;
+ return GetRowValue(row, pid);
+}
+
+int StatsTable::GetMaxCounters() const {
+ if (!impl_)
+ return 0;
+ return impl_->max_counters();
+}
+
+int StatsTable::GetMaxThreads() const {
+ if (!impl_)
+ return 0;
+ return impl_->max_threads();
+}
+
+int* StatsTable::FindLocation(const char* name) {
+ // Get the static StatsTable
+ StatsTable *table = StatsTable::current();
+ if (!table)
+ return NULL;
+
+ // Get the slot for this thread. Try to register
+ // it if none exists.
+ int slot = table->GetSlot();
+ if (!slot && !(slot = table->RegisterThread("")))
+ return NULL;
+
+ // Find the counter id for the counter.
+ std::string str_name(name);
+ int counter = table->FindCounter(str_name);
+
+ // Now we can find the location in the table.
+ return table->GetLocation(counter, slot);
}
void StatsTable::UnregisterThread() {
@@ -359,28 +479,6 @@ void StatsTable::SlotReturnFunction(void* data) {
}
}
-int StatsTable::CountThreadsRegistered() const {
- if (!impl_)
- return 0;
-
- // Loop through the shared memory and count the threads that are active.
- // We intentionally do not lock the table during the operation.
- int count = 0;
- for (int index = 1; index <= impl_->max_threads(); index++) {
- char* name = impl_->thread_name(index);
- if (*name != '\0')
- count++;
- }
- return count;
-}
-
-int StatsTable::GetSlot() const {
- TLSData* data = GetTLSData();
- if (!data)
- return 0;
- return data->slot;
-}
-
int StatsTable::FindEmptyThread() const {
// Note: the API returns slots numbered from 1..N, although
// internally, the array is 0..N-1. This is so that we can return
@@ -426,28 +524,6 @@ int StatsTable::FindCounterOrEmptyRow(const std::string& name) const {
return free_slot;
}
-int StatsTable::FindCounter(const std::string& name) {
- // Note: the API returns counters numbered from 1..N, although
- // internally, the array is 0..N-1. This is so that we can return
- // zero as "not found".
- if (!impl_)
- return 0;
-
- // Create a scope for our auto-lock.
- {
- AutoLock scoped_lock(counters_lock_);
-
- // Attempt to find the counter.
- CountersMap::const_iterator iter;
- iter = counters_.find(name);
- if (iter != counters_.end())
- return iter->second;
- }
-
- // Counter does not exist, so add it.
- return AddCounter(name);
-}
-
int StatsTable::AddCounter(const std::string& name) {
#ifdef ANDROID
return 0;
@@ -483,84 +559,15 @@ int StatsTable::AddCounter(const std::string& name) {
#endif
}
-int* StatsTable::GetLocation(int counter_id, int slot_id) const {
- if (!impl_)
- return NULL;
- if (slot_id > impl_->max_threads())
- return NULL;
-
- int* row = impl_->row(counter_id);
- return &(row[slot_id-1]);
-}
-
-const char* StatsTable::GetRowName(int index) const {
- if (!impl_)
- return NULL;
-
- return impl_->counter_name(index);
-}
-
-int StatsTable::GetRowValue(int index, int pid) const {
- if (!impl_)
- return 0;
-
- int rv = 0;
- int* row = impl_->row(index);
- for (int slot_id = 0; slot_id < impl_->max_threads(); slot_id++) {
- if (pid == 0 || *impl_->thread_pid(slot_id) == pid)
- rv += row[slot_id];
- }
- return rv;
-}
-
-int StatsTable::GetRowValue(int index) const {
- return GetRowValue(index, 0);
-}
-
-int StatsTable::GetCounterValue(const std::string& name, int pid) {
- if (!impl_)
- return 0;
-
- int row = FindCounter(name);
- if (!row)
- return 0;
- return GetRowValue(row, pid);
-}
-
-int StatsTable::GetCounterValue(const std::string& name) {
- return GetCounterValue(name, 0);
-}
-
-int StatsTable::GetMaxCounters() const {
- if (!impl_)
- return 0;
- return impl_->max_counters();
-}
-
-int StatsTable::GetMaxThreads() const {
- if (!impl_)
- return 0;
- return impl_->max_threads();
-}
-
-int* StatsTable::FindLocation(const char* name) {
- // Get the static StatsTable
- StatsTable *table = StatsTable::current();
- if (!table)
+StatsTable::TLSData* StatsTable::GetTLSData() const {
+ TLSData* data =
+ static_cast<TLSData*>(tls_index_.Get());
+ if (!data)
return NULL;
- // Get the slot for this thread. Try to register
- // it if none exists.
- int slot = table->GetSlot();
- if (!slot && !(slot = table->RegisterThread("")))
- return NULL;
-
- // Find the counter id for the counter.
- std::string str_name(name);
- int counter = table->FindCounter(str_name);
-
- // Now we can find the location in the table.
- return table->GetLocation(counter, slot);
+ DCHECK(data->slot);
+ DCHECK_EQ(data->table, this);
+ return data;
}
} // namespace base
diff --git a/base/metrics/stats_table.h b/base/metrics/stats_table.h
index 32b22eb..94f7463 100644
--- a/base/metrics/stats_table.h
+++ b/base/metrics/stats_table.h
@@ -25,7 +25,7 @@
#include "base/basictypes.h"
#include "base/hash_tables.h"
-#include "base/lock.h"
+#include "base/synchronization/lock.h"
#include "base/threading/thread_local_storage.h"
namespace base {
@@ -122,7 +122,7 @@ class StatsTable {
// The maximum length (in characters) of a Counter's name including
// null terminator, as stored in the shared memory.
- static const int kMaxCounterNameLength = 32;
+ static const int kMaxCounterNameLength = 64;
// Convenience function to lookup a counter location for a
// counter by name for the calling thread. Will register
@@ -175,7 +175,7 @@ class StatsTable {
Private* impl_;
// The counters_lock_ protects the counters_ hash table.
- Lock counters_lock_;
+ base::Lock counters_lock_;
// The counters_ hash map is an in-memory hash of the counters.
// It is used for quick lookup of counters, but is cannot be used
diff --git a/base/mime_util_xdg.cc b/base/mime_util_xdg.cc
index 8be1d0d..5215d01 100644
--- a/base/mime_util_xdg.cc
+++ b/base/mime_util_xdg.cc
@@ -21,6 +21,7 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/third_party/xdg_mime/xdgmime.h"
+#include "base/threading/thread_restrictions.h"
namespace {
@@ -155,6 +156,7 @@ class IconTheme {
IconTheme::IconTheme(const std::string& name)
: index_theme_loaded_(false),
info_array_(NULL) {
+ base::ThreadRestrictions::AssertIOAllowed();
// Iterate on all icon directories to find directories of the specified
// theme and load the first encountered index.theme.
std::map<FilePath, int>::iterator iter;
@@ -550,10 +552,12 @@ MimeUtilConstants::~MimeUtilConstants() {
namespace mime_util {
std::string GetFileMimeType(const FilePath& filepath) {
+ base::ThreadRestrictions::AssertIOAllowed();
return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str());
}
std::string GetDataMimeType(const std::string& data) {
+ base::ThreadRestrictions::AssertIOAllowed();
return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL);
}
@@ -576,6 +580,7 @@ void DetectGtkTheme() {
}
FilePath GetMimeIcon(const std::string& mime_type, size_t size) {
+ base::ThreadRestrictions::AssertIOAllowed();
std::vector<std::string> icon_names;
std::string icon_name;
FilePath icon_file;
diff --git a/base/nss_util.cc b/base/nss_util.cc
index b411422..fe78fe0 100644
--- a/base/nss_util.cc
+++ b/base/nss_util.cc
@@ -29,9 +29,10 @@
// use NSS for crypto or certificate verification, and we don't use the NSS
// certificate and key databases.
#if defined(USE_NSS)
+#include "base/crypto/crypto_module_blocking_password_delegate.h"
#include "base/environment.h"
-#include "base/lock.h"
#include "base/scoped_ptr.h"
+#include "base/synchronization/lock.h"
#endif // defined(USE_NSS)
namespace base {
@@ -69,6 +70,26 @@ FilePath GetInitialConfigDirectory() {
#endif // defined(OS_CHROMEOS)
}
+// This callback for NSS forwards all requests to a caller-specified
+// CryptoModuleBlockingPasswordDelegate object.
+char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
+ base::CryptoModuleBlockingPasswordDelegate* delegate =
+ reinterpret_cast<base::CryptoModuleBlockingPasswordDelegate*>(arg);
+ if (delegate) {
+ bool cancelled = false;
+ std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
+ retry != PR_FALSE,
+ &cancelled);
+ if (cancelled)
+ return NULL;
+ char* result = PORT_Strdup(password.c_str());
+ password.replace(0, password.size(), password.size(), 0);
+ return result;
+ }
+ DLOG(ERROR) << "PK11 password requested with NULL arg";
+ return NULL;
+}
+
// NSS creates a local cache of the sqlite database if it detects that the
// filesystem the database is on is much slower than the local disk. The
// detection doesn't work with the latest versions of sqlite, such as 3.6.22
@@ -78,6 +99,9 @@ FilePath GetInitialConfigDirectory() {
//
// TODO(wtc): port this function to other USE_NSS platforms. It is defined
// only for OS_LINUX simply because the statfs structure is OS-specific.
+//
+// Because this function sets an environment variable it must be run before we
+// go multi-threaded.
void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) {
#if defined(OS_LINUX)
struct statfs buf;
@@ -141,6 +165,9 @@ class NSSInitSingleton {
#if defined(OS_CHROMEOS)
void OpenPersistentNSSDB() {
if (!chromeos_user_logged_in_) {
+ // GetDefaultConfigDirectory causes us to do blocking IO on UI thread.
+ // Temporarily allow it until we fix http://crbug.com.70119
+ ThreadRestrictions::ScopedAllowIO allow_io;
chromeos_user_logged_in_ = true;
real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(),
"Real NSS database");
@@ -219,6 +246,9 @@ class NSSInitSingleton {
#else
FilePath database_dir = GetInitialConfigDirectory();
if (!database_dir.empty()) {
+ // This duplicates the work which should have been done in
+ // EarlySetupForNSSInit. However, this function is idempotent so there's
+ // no harm done.
UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
// Initialize with a persistent database (likely, ~/.pki/nssdb).
@@ -247,6 +277,8 @@ class NSSInitSingleton {
}
}
+ PK11_SetPasswordFunc(PKCS11PasswordFunc);
+
// If we haven't initialized the password for the NSS databases,
// initialize an empty-string password so that we don't need to
// log in.
@@ -321,6 +353,14 @@ LazyInstance<NSSInitSingleton, LeakyLazyInstanceTraits<NSSInitSingleton> >
} // namespace
+#if defined(USE_NSS)
+void EarlySetupForNSSInit() {
+ FilePath database_dir = GetInitialConfigDirectory();
+ if (!database_dir.empty())
+ UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
+}
+#endif
+
void EnsureNSPRInit() {
g_nspr_singleton.Get();
}
diff --git a/base/nss_util.h b/base/nss_util.h
index 2b0139e..10bbdfb 100644
--- a/base/nss_util.h
+++ b/base/nss_util.h
@@ -20,6 +20,13 @@ namespace base {
class Lock;
class Time;
+#if defined(USE_NSS)
+// EarlySetupForNSSInit performs lightweight setup which must occur before the
+// process goes multithreaded. This does not initialise NSS. For test, see
+// EnsureNSSInit.
+void EarlySetupForNSSInit();
+#endif
+
// Initialize NRPR if it isn't already initialized. This function is
// thread-safe, and NSPR will only ever be initialized once. NSPR will be
// properly shut down on program exit.
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index d034e6c..47a662e 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -49,9 +49,32 @@
// will notify its regular ObserverList.
//
///////////////////////////////////////////////////////////////////////////////
+
+// Forward declaration for ObserverListThreadSafeTraits.
+template <class ObserverType>
+class ObserverListThreadSafe;
+
+// This class is used to work around VS2005 not accepting:
+//
+// friend class
+// base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
+//
+// Instead of friending the class, we could friend the actual function
+// which calls delete. However, this ends up being
+// RefCountedThreadSafe::DeleteInternal(), which is private. So we
+// define our own templated traits class so we can friend it.
+template <class T>
+struct ObserverListThreadSafeTraits {
+ static void Destruct(const ObserverListThreadSafe<T>* x) {
+ delete x;
+ }
+};
+
template <class ObserverType>
class ObserverListThreadSafe
- : public base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> > {
+ : public base::RefCountedThreadSafe<
+ ObserverListThreadSafe<ObserverType>,
+ ObserverListThreadSafeTraits<ObserverType> > {
public:
typedef typename ObserverList<ObserverType>::NotificationType
NotificationType;
@@ -60,13 +83,6 @@ class ObserverListThreadSafe
: type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
- ~ObserverListThreadSafe() {
- typename ObserversListMap::const_iterator it;
- for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
- delete (*it).second;
- observer_lists_.clear();
- }
-
// Add an observer to the list.
void AddObserver(ObserverType* obs) {
ObserverList<ObserverType>* list = NULL;
@@ -77,7 +93,7 @@ class ObserverListThreadSafe
if (!loop)
return; // Some unittests may access this without a message loop.
{
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
if (observer_lists_.find(loop) == observer_lists_.end())
observer_lists_[loop] = new ObserverList<ObserverType>(type_);
list = observer_lists_[loop];
@@ -96,7 +112,7 @@ class ObserverListThreadSafe
if (!loop)
return; // On shutdown, it is possible that current() is already null.
{
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
list = observer_lists_[loop];
if (!list) {
NOTREACHED() << "RemoveObserver called on for unknown thread";
@@ -137,9 +153,19 @@ class ObserverListThreadSafe
// TODO(mbelshe): Add more wrappers for Notify() with more arguments.
private:
+ // See comment above ObserverListThreadSafeTraits' definition.
+ friend struct ObserverListThreadSafeTraits<ObserverType>;
+
+ ~ObserverListThreadSafe() {
+ typename ObserversListMap::const_iterator it;
+ for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
+ delete (*it).second;
+ observer_lists_.clear();
+ }
+
template <class Method, class Params>
void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
typename ObserversListMap::iterator it;
for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
MessageLoop* loop = (*it).first;
@@ -161,7 +187,7 @@ class ObserverListThreadSafe
// Check that this list still needs notifications.
{
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
typename ObserversListMap::iterator it =
observer_lists_.find(MessageLoop::current());
@@ -183,7 +209,7 @@ class ObserverListThreadSafe
// If there are no more observers on the list, we can now delete it.
if (list->size() == 0) {
{
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
// Remove |list| if it's not already removed.
// This can happen if multiple observers got removed in a notification.
// See http://crbug.com/55725.
@@ -199,7 +225,7 @@ class ObserverListThreadSafe
typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap;
// These are marked mutable to facilitate having NotifyAll be const.
- Lock list_lock_; // Protects the observer_lists_.
+ base::Lock list_lock_; // Protects the observer_lists_.
ObserversListMap observer_lists_;
const NotificationType type_;
diff --git a/base/openssl_util.cc b/base/openssl_util.cc
index bc174fa..931485a 100644
--- a/base/openssl_util.cc
+++ b/base/openssl_util.cc
@@ -7,11 +7,11 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
-#include "base/lock.h"
#include "base/logging.h"
#include "base/scoped_vector.h"
#include "base/singleton.h"
#include "base/string_piece.h"
+#include "base/synchronization/lock.h"
namespace base {
@@ -46,7 +46,7 @@ class OpenSSLInitSingleton {
int num_locks = CRYPTO_num_locks();
locks_.reserve(num_locks);
for (int i = 0; i < num_locks; ++i)
- locks_.push_back(new Lock());
+ locks_.push_back(new base::Lock());
CRYPTO_set_locking_callback(LockingCallback);
CRYPTO_set_id_callback(CurrentThreadId);
}
@@ -70,7 +70,7 @@ class OpenSSLInitSingleton {
}
// These locks are used and managed by OpenSSL via LockingCallback().
- ScopedVector<Lock> locks_;
+ ScopedVector<base::Lock> locks_;
DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton);
};
diff --git a/base/path_service.cc b/base/path_service.cc
index 56ce5fa..117feb5 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -14,8 +14,8 @@
#include "base/file_util.h"
#include "base/hash_tables.h"
#include "base/lazy_instance.h"
-#include "base/lock.h"
#include "base/logging.h"
+#include "base/synchronization/lock.h"
namespace base {
bool PathProvider(int key, FilePath* result);
@@ -92,9 +92,9 @@ static Provider base_provider_posix = {
struct PathData {
- Lock lock;
- PathMap cache; // Cache mappings from path key to path value.
- PathMap overrides; // Track path overrides.
+ base::Lock lock;
+ PathMap cache; // Cache mappings from path key to path value.
+ PathMap overrides; // Track path overrides.
Provider* providers; // Linked list of path service providers.
PathData() {
@@ -130,7 +130,7 @@ static PathData* GetPathData() {
// static
bool PathService::GetFromCache(int key, FilePath* result) {
PathData* path_data = GetPathData();
- AutoLock scoped_lock(path_data->lock);
+ base::AutoLock scoped_lock(path_data->lock);
// check for a cached version
PathMap::const_iterator it = path_data->cache.find(key);
@@ -144,7 +144,7 @@ bool PathService::GetFromCache(int key, FilePath* result) {
// static
bool PathService::GetFromOverrides(int key, FilePath* result) {
PathData* path_data = GetPathData();
- AutoLock scoped_lock(path_data->lock);
+ base::AutoLock scoped_lock(path_data->lock);
// check for an overriden version.
PathMap::const_iterator it = path_data->overrides.find(key);
@@ -158,7 +158,7 @@ bool PathService::GetFromOverrides(int key, FilePath* result) {
// static
void PathService::AddToCache(int key, const FilePath& path) {
PathData* path_data = GetPathData();
- AutoLock scoped_lock(path_data->lock);
+ base::AutoLock scoped_lock(path_data->lock);
// Save the computed path in our cache.
path_data->cache[key] = path;
}
@@ -225,7 +225,7 @@ bool PathService::Override(int key, const FilePath& path) {
if (!file_util::AbsolutePath(&file_path))
return false;
- AutoLock scoped_lock(path_data->lock);
+ base::AutoLock scoped_lock(path_data->lock);
// Clear the cache now. Some of its entries could have depended
// on the value we are overriding, and are now out of sync with reality.
@@ -243,7 +243,7 @@ void PathService::RegisterProvider(ProviderFunc func, int key_start,
DCHECK(path_data);
DCHECK(key_end > key_start);
- AutoLock scoped_lock(path_data->lock);
+ base::AutoLock scoped_lock(path_data->lock);
Provider* p;
diff --git a/base/pickle.cc b/base/pickle.cc
index a05df28..e7d5768 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -406,6 +406,9 @@ const char* Pickle::FindNext(size_t header_size,
DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
DCHECK(header_size <= static_cast<size_t>(kPayloadUnit));
+ if (static_cast<size_t>(end - start) < sizeof(Header))
+ return NULL;
+
const Header* hdr = reinterpret_cast<const Header*>(start);
const char* payload_base = start + header_size;
const char* payload_end = payload_base + hdr->payload_size;
diff --git a/base/pickle.h b/base/pickle.h
index bbe5d34..ad08b7c 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -55,8 +55,7 @@ class Pickle {
Pickle& operator=(const Pickle& other);
// Returns the size of the Pickle's data.
- int size() const { return static_cast<int>(header_size_ +
- header_->payload_size); }
+ size_t size() const { return header_size_ + header_->payload_size; }
// Returns the data for this Pickle.
const void* data() const { return header_; }
@@ -236,6 +235,7 @@ class Pickle {
FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
+ FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
FRIEND_TEST_ALL_PREFIXES(PickleTest, IteratorHasRoom);
};
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index fdc0664..39eaa1b 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -171,6 +171,17 @@ TEST(PickleTest, FindNext) {
EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
}
+TEST(PickleTest, FindNextWithIncompleteHeader) {
+ size_t header_size = sizeof(Pickle::Header);
+ scoped_array<char> buffer(new char[header_size - 1]);
+ memset(buffer.get(), 0x1, header_size - 1);
+
+ const char* start = buffer.get();
+ const char* end = start + header_size - 1;
+
+ EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end));
+}
+
TEST(PickleTest, IteratorHasRoom) {
Pickle pickle;
EXPECT_TRUE(pickle.WriteInt(1));
diff --git a/base/pr_time_unittest.cc b/base/pr_time_unittest.cc
index 6dda299..646eb16 100644
--- a/base/pr_time_unittest.cc
+++ b/base/pr_time_unittest.cc
@@ -136,7 +136,7 @@ TEST_F(PRTimeTest, ParseTimeTest9) {
TEST_F(PRTimeTest, ParseTimeTest10) {
Time parsed_time;
bool result = Time::FromString(L"15/10/07 12:45", &parsed_time);
- EXPECT_EQ(true, result);
+ EXPECT_TRUE(result);
time_t computed_time = parsed_time.ToTimeT();
time_t time_to_compare = comparison_time_local_ /
@@ -149,7 +149,7 @@ TEST_F(PRTimeTest, ParseTimeTest11) {
Time parsed_time;
bool result = Time::FromString(L"Mon, 15 Oct 2007 19:45:00 GMT",
&parsed_time);
- EXPECT_EQ(true, result);
+ EXPECT_TRUE(result);
time_t computed_time = parsed_time.ToTimeT();
time_t time_to_compare = comparison_time_pdt / Time::kMicrosecondsPerSecond;
@@ -161,11 +161,11 @@ TEST_F(PRTimeTest, ParseTimeTestEpoch0) {
Time parsed_time;
// time_t == epoch == 0
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 01:00:00 +0100 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 01:00:00 +0100 1970",
+ &parsed_time));
EXPECT_EQ(0, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 00:00:00 GMT 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 00:00:00 GMT 1970",
+ &parsed_time));
EXPECT_EQ(0, parsed_time.ToTimeT());
}
@@ -173,11 +173,11 @@ TEST_F(PRTimeTest, ParseTimeTestEpoch1) {
Time parsed_time;
// time_t == 1 second after epoch == 1
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 01:00:01 +0100 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 01:00:01 +0100 1970",
+ &parsed_time));
EXPECT_EQ(1, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 00:00:01 GMT 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 00:00:01 GMT 1970",
+ &parsed_time));
EXPECT_EQ(1, parsed_time.ToTimeT());
}
@@ -185,11 +185,11 @@ TEST_F(PRTimeTest, ParseTimeTestEpoch2) {
Time parsed_time;
// time_t == 2 seconds after epoch == 2
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 01:00:02 +0100 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 01:00:02 +0100 1970",
+ &parsed_time));
EXPECT_EQ(2, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 00:00:02 GMT 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 00:00:02 GMT 1970",
+ &parsed_time));
EXPECT_EQ(2, parsed_time.ToTimeT());
}
@@ -197,11 +197,11 @@ TEST_F(PRTimeTest, ParseTimeTestEpochNeg1) {
Time parsed_time;
// time_t == 1 second before epoch == -1
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 00:59:59 +0100 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 00:59:59 +0100 1970",
+ &parsed_time));
EXPECT_EQ(-1, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Wed Dec 31 23:59:59 GMT 1969",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Wed Dec 31 23:59:59 GMT 1969",
+ &parsed_time));
EXPECT_EQ(-1, parsed_time.ToTimeT());
}
@@ -211,8 +211,8 @@ TEST_F(PRTimeTest, ParseTimeTestEpochNeg1) {
TEST_F(PRTimeTest, ParseTimeTestEpochNotNeg1) {
Time parsed_time;
- EXPECT_EQ(true, Time::FromString(L"Wed Dec 31 23:59:59 GMT 2100",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Wed Dec 31 23:59:59 GMT 2100",
+ &parsed_time));
EXPECT_NE(-1, parsed_time.ToTimeT());
}
@@ -220,11 +220,11 @@ TEST_F(PRTimeTest, ParseTimeTestEpochNeg2) {
Time parsed_time;
// time_t == 2 seconds before epoch == -2
- EXPECT_EQ(true, Time::FromString(L"Thu Jan 01 00:59:58 +0100 1970",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Thu Jan 01 00:59:58 +0100 1970",
+ &parsed_time));
EXPECT_EQ(-2, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Wed Dec 31 23:59:58 GMT 1969",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Wed Dec 31 23:59:58 GMT 1969",
+ &parsed_time));
EXPECT_EQ(-2, parsed_time.ToTimeT());
}
@@ -232,14 +232,14 @@ TEST_F(PRTimeTest, ParseTimeTestEpoch1960) {
Time parsed_time;
// time_t before Epoch, in 1960
- EXPECT_EQ(true, Time::FromString(L"Wed Jun 29 19:40:01 +0100 1960",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Wed Jun 29 19:40:01 +0100 1960",
+ &parsed_time));
EXPECT_EQ(-299999999, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Wed Jun 29 18:40:01 GMT 1960",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Wed Jun 29 18:40:01 GMT 1960",
+ &parsed_time));
EXPECT_EQ(-299999999, parsed_time.ToTimeT());
- EXPECT_EQ(true, Time::FromString(L"Wed Jun 29 17:40:01 GMT 1960",
- &parsed_time));
+ EXPECT_TRUE(Time::FromString(L"Wed Jun 29 17:40:01 GMT 1960",
+ &parsed_time));
EXPECT_EQ(-300003599, parsed_time.ToTimeT());
}
diff --git a/base/process_linux.cc b/base/process_linux.cc
index 21ed933..14c2424 100644
--- a/base/process_linux.cc
+++ b/base/process_linux.cc
@@ -11,7 +11,14 @@
namespace base {
+#if defined(OS_CHROMEOS)
+// We are more aggressive in our lowering of background process priority
+// for chromeos as we have much more control over other processes running
+// on the machine.
+const int kPriorityAdjustment = 19;
+#else
const int kPriorityAdjustment = 5;
+#endif
bool Process::IsProcessBackgrounded() const {
DCHECK(process_);
diff --git a/base/process_posix.cc b/base/process_posix.cc
index ee70e5a..6e65ebf 100644
--- a/base/process_posix.cc
+++ b/base/process_posix.cc
@@ -13,6 +13,22 @@
namespace base {
+// static
+Process Process::Current() {
+ return Process(GetCurrentProcessHandle());
+}
+
+ProcessId Process::pid() const {
+ if (process_ == 0)
+ return 0;
+
+ return GetProcId(process_);
+}
+
+bool Process::is_current() const {
+ return process_ == GetCurrentProcessHandle();
+}
+
void Process::Close() {
process_ = 0;
// if the process wasn't terminated (so we waited) or the state
@@ -43,22 +59,6 @@ bool Process::SetProcessBackgrounded(bool value) {
}
#endif
-ProcessId Process::pid() const {
- if (process_ == 0)
- return 0;
-
- return GetProcId(process_);
-}
-
-bool Process::is_current() const {
- return process_ == GetCurrentProcessHandle();
-}
-
-// static
-Process Process::Current() {
- return Process(GetCurrentProcessHandle());
-}
-
int Process::GetPriority() const {
DCHECK(process_);
return getpriority(PRIO_PROCESS, process_);
diff --git a/base/process_util.cc b/base/process_util.cc
index 7b2935d..462dcbf 100644
--- a/base/process_util.cc
+++ b/base/process_util.cc
@@ -44,10 +44,6 @@ const ProcessEntry* ProcessIterator::NextProcessEntry() {
return NULL;
}
-bool ProcessIterator::IncludeEntry() {
- return !filter_ || filter_->Includes(entry_);
-}
-
ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
ProcessEntries found;
while (const ProcessEntry* process_entry = NextProcessEntry()) {
@@ -56,6 +52,10 @@ ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
return found;
}
+bool ProcessIterator::IncludeEntry() {
+ return !filter_ || filter_->Includes(entry_);
+}
+
NamedProcessIterator::NamedProcessIterator(
const FilePath::StringType& executable_name,
const ProcessFilter* filter) : ProcessIterator(filter),
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index dcaeeb4..4cd27f6 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -68,6 +68,39 @@ bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
return true;
}
+// Get the total CPU of a single process. Return value is number of jiffies
+// on success or -1 on error.
+int GetProcessCPU(pid_t pid) {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ // Use /proc/<pid>/task to find all threads and parse their /stat file.
+ FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid));
+
+ DIR* dir = opendir(path.value().c_str());
+ if (!dir) {
+ PLOG(ERROR) << "opendir(" << path.value() << ")";
+ return -1;
+ }
+
+ int total_cpu = 0;
+ while (struct dirent* ent = readdir(dir)) {
+ if (ent->d_name[0] == '.')
+ continue;
+
+ FilePath stat_path = path.AppendASCII(ent->d_name).AppendASCII("stat");
+ std::string stat;
+ if (file_util::ReadFileToString(stat_path, &stat)) {
+ int cpu = base::ParseProcStatCPU(stat);
+ if (cpu > 0)
+ total_cpu += cpu;
+ }
+ }
+ closedir(dir);
+
+ return total_cpu;
+}
+
} // namespace
namespace base {
@@ -167,18 +200,18 @@ bool ProcessIterator::CheckForNextProcess() {
std::string pid_string(slot->d_name);
int pid;
if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args))
- return false;
+ continue;
// Read the process's status.
char buf[NAME_MAX + 12];
sprintf(buf, "/proc/%s/stat", slot->d_name);
FILE *fp = fopen(buf, "r");
if (!fp)
- return false;
+ continue;
const char* result = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (!result)
- return false;
+ continue;
// Parse the status. It is formatted like this:
// %d (%s) %c %d %d ...
@@ -188,7 +221,7 @@ bool ProcessIterator::CheckForNextProcess() {
openparen = strchr(buf, '(');
closeparen = strrchr(buf, ')');
if (!openparen || !closeparen)
- return false;
+ continue;
char runstate = closeparen[2];
// Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
@@ -226,14 +259,6 @@ bool NamedProcessIterator::IncludeEntry() {
}
-ProcessMetrics::ProcessMetrics(ProcessHandle process)
- : process_(process),
- last_time_(0),
- last_system_time_(0),
- last_cpu_(0) {
- processor_count_ = base::SysInfo::NumberOfProcessors();
-}
-
// static
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
return new ProcessMetrics(process);
@@ -399,6 +424,49 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
return true;
}
+double ProcessMetrics::GetCPUUsage() {
+ // This queries the /proc-specific scaling factor which is
+ // conceptually the system hertz. To dump this value on another
+ // system, try
+ // od -t dL /proc/self/auxv
+ // and look for the number after 17 in the output; mine is
+ // 0000040 17 100 3 134512692
+ // which means the answer is 100.
+ // It may be the case that this value is always 100.
+ static const int kHertz = sysconf(_SC_CLK_TCK);
+
+ struct timeval now;
+ int retval = gettimeofday(&now, NULL);
+ if (retval)
+ return 0;
+ int64 time = TimeValToMicroseconds(now);
+
+ if (last_time_ == 0) {
+ // First call, just set the last values.
+ last_time_ = time;
+ last_cpu_ = GetProcessCPU(process_);
+ return 0;
+ }
+
+ int64 time_delta = time - last_time_;
+ DCHECK_NE(time_delta, 0);
+ if (time_delta == 0)
+ return 0;
+
+ int cpu = GetProcessCPU(process_);
+
+ // We have the number of jiffies in the time period. Convert to percentage.
+ // Note this means we will go *over* 100 in the case where multiple threads
+ // are together adding to more than one CPU's worth.
+ int percentage = 100 * (cpu - last_cpu_) /
+ (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF());
+
+ last_time_ = time;
+ last_cpu_ = cpu;
+
+ return percentage;
+}
+
// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
// in your kernel configuration.
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
@@ -446,6 +514,14 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
return true;
}
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+ : process_(process),
+ last_time_(0),
+ last_system_time_(0),
+ last_cpu_(0) {
+ processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
// Exposed for testing.
int ParseProcStatCPU(const std::string& input) {
@@ -469,82 +545,6 @@ int ParseProcStatCPU(const std::string& input) {
return fields11 + fields12;
}
-// Get the total CPU of a single process. Return value is number of jiffies
-// on success or -1 on error.
-static int GetProcessCPU(pid_t pid) {
- // Synchronously reading files in /proc is safe.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- // Use /proc/<pid>/task to find all threads and parse their /stat file.
- FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid));
-
- DIR* dir = opendir(path.value().c_str());
- if (!dir) {
- PLOG(ERROR) << "opendir(" << path.value() << ")";
- return -1;
- }
-
- int total_cpu = 0;
- while (struct dirent* ent = readdir(dir)) {
- if (ent->d_name[0] == '.')
- continue;
-
- FilePath stat_path = path.AppendASCII(ent->d_name).AppendASCII("stat");
- std::string stat;
- if (file_util::ReadFileToString(stat_path, &stat)) {
- int cpu = ParseProcStatCPU(stat);
- if (cpu > 0)
- total_cpu += cpu;
- }
- }
- closedir(dir);
-
- return total_cpu;
-}
-
-double ProcessMetrics::GetCPUUsage() {
- // This queries the /proc-specific scaling factor which is
- // conceptually the system hertz. To dump this value on another
- // system, try
- // od -t dL /proc/self/auxv
- // and look for the number after 17 in the output; mine is
- // 0000040 17 100 3 134512692
- // which means the answer is 100.
- // It may be the case that this value is always 100.
- static const int kHertz = sysconf(_SC_CLK_TCK);
-
- struct timeval now;
- int retval = gettimeofday(&now, NULL);
- if (retval)
- return 0;
- int64 time = TimeValToMicroseconds(now);
-
- if (last_time_ == 0) {
- // First call, just set the last values.
- last_time_ = time;
- last_cpu_ = GetProcessCPU(process_);
- return 0;
- }
-
- int64 time_delta = time - last_time_;
- DCHECK_NE(time_delta, 0);
- if (time_delta == 0)
- return 0;
-
- int cpu = GetProcessCPU(process_);
-
- // We have the number of jiffies in the time period. Convert to percentage.
- // Note this means we will go *over* 100 in the case where multiple threads
- // are together adding to more than one CPU's worth.
- int percentage = 100 * (cpu - last_cpu_) /
- (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF());
-
- last_time_ = time;
- last_cpu_ = cpu;
-
- return percentage;
-}
-
namespace {
// The format of /proc/meminfo is:
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 672e396..1b7368a 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -485,12 +485,15 @@ std::string TestLaunchApp(const base::environment_vector& env_changes) {
fds_to_remap.push_back(std::make_pair(fds[1], 1));
EXPECT_TRUE(base::LaunchApp(args, env_changes, fds_to_remap,
- true /* wait for exit */, &handle));
- PCHECK(close(fds[1]) == 0);
+ true /* wait for exit */, &handle));
+ PCHECK(HANDLE_EINTR(close(fds[1])) == 0);
char buf[512];
const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
PCHECK(n > 0);
+
+ PCHECK(HANDLE_EINTR(close(fds[0])) == 0);
+
return std::string(buf, n);
}
diff --git a/base/ref_counted.cc b/base/ref_counted.cc
index 2f795ea..54c1071 100644
--- a/base/ref_counted.cc
+++ b/base/ref_counted.cc
@@ -12,7 +12,7 @@ namespace base {
namespace subtle {
RefCountedBase::RefCountedBase()
- : ref_count_(0)
+ : counter_holder_(new CounterHolder)
#ifndef NDEBUG
, in_dtor_(false)
#endif
@@ -20,6 +20,7 @@ RefCountedBase::RefCountedBase()
}
RefCountedBase::~RefCountedBase() {
+ delete counter_holder_;
#ifndef NDEBUG
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
#endif
@@ -32,7 +33,7 @@ void RefCountedBase::AddRef() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
- ++ref_count_;
+ ++(counter_holder_->ref_count);
}
bool RefCountedBase::Release() const {
@@ -42,7 +43,7 @@ bool RefCountedBase::Release() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
- if (--ref_count_ == 0) {
+ if (--(counter_holder_->ref_count) == 0) {
#ifndef NDEBUG
in_dtor_ = true;
#endif
@@ -51,13 +52,21 @@ bool RefCountedBase::Release() const {
return false;
}
-RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
+bool RefCountedThreadSafeBase::HasOneRef() const {
+ return AtomicRefCountIsOne(
+ &const_cast<RefCountedThreadSafeBase*>(this)->
+ counter_holder_->ref_count);
+}
+
+RefCountedThreadSafeBase::RefCountedThreadSafeBase()
+ : counter_holder_(new CounterHolder) {
#ifndef NDEBUG
in_dtor_ = false;
#endif
}
RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+ delete counter_holder_;
#ifndef NDEBUG
DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
"calling Release()";
@@ -68,15 +77,15 @@ void RefCountedThreadSafeBase::AddRef() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
- AtomicRefCountInc(&ref_count_);
+ AtomicRefCountInc(&counter_holder_->ref_count);
}
bool RefCountedThreadSafeBase::Release() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
- DCHECK(!AtomicRefCountIsZero(&ref_count_));
+ DCHECK(!AtomicRefCountIsZero(&counter_holder_->ref_count));
#endif
- if (!AtomicRefCountDec(&ref_count_)) {
+ if (!AtomicRefCountDec(&counter_holder_->ref_count)) {
#ifndef NDEBUG
in_dtor_ = true;
#endif
@@ -85,11 +94,6 @@ bool RefCountedThreadSafeBase::Release() const {
return false;
}
-bool RefCountedThreadSafeBase::HasOneRef() const {
- return AtomicRefCountIsOne(
- &const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
-}
-
} // namespace subtle
} // namespace base
diff --git a/base/ref_counted.h b/base/ref_counted.h
index 4c3aeb8..6a2b996 100644
--- a/base/ref_counted.h
+++ b/base/ref_counted.h
@@ -17,19 +17,25 @@ class RefCountedBase {
public:
static bool ImplementsThreadSafeReferenceCounting() { return false; }
- bool HasOneRef() const { return ref_count_ == 1; }
+ bool HasOneRef() const { return counter_holder_->ref_count == 1; }
protected:
RefCountedBase();
~RefCountedBase();
+ struct CounterHolder {
+ CounterHolder() : ref_count(0), weak_count(0) {}
+ int ref_count;
+ int weak_count; // Simulates weak pointer.
+ };
+
void AddRef() const;
// Returns true if the object should self-delete.
bool Release() const;
private:
- mutable int ref_count_;
+ mutable CounterHolder* counter_holder_;
#ifndef NDEBUG
mutable bool in_dtor_;
#endif
@@ -55,7 +61,12 @@ class RefCountedThreadSafeBase {
bool Release() const;
private:
- mutable AtomicRefCount ref_count_;
+ struct CounterHolder {
+ CounterHolder() : ref_count(0), weak_count(0) {}
+ AtomicRefCount ref_count;
+ AtomicRefCount weak_count; // Simulates weak pointer.
+ };
+ mutable CounterHolder* counter_holder_;
#ifndef NDEBUG
mutable bool in_dtor_;
#endif
diff --git a/base/scoped_temp_dir.h b/base/scoped_temp_dir.h
index f44bcca..4286d28 100644
--- a/base/scoped_temp_dir.h
+++ b/base/scoped_temp_dir.h
@@ -28,17 +28,17 @@ class ScopedTempDir {
// Creates a unique directory in TempPath, and takes ownership of it.
// See file_util::CreateNewTemporaryDirectory.
- bool CreateUniqueTempDir();
+ bool CreateUniqueTempDir() WARN_UNUSED_RESULT;
// Creates a unique directory under a given path, and takes ownership of it.
- bool CreateUniqueTempDirUnderPath(const FilePath& path);
+ bool CreateUniqueTempDirUnderPath(const FilePath& path) WARN_UNUSED_RESULT;
// Takes ownership of directory at |path|, creating it if necessary.
// Don't call multiple times unless Take() has been called first.
- bool Set(const FilePath& path);
+ bool Set(const FilePath& path) WARN_UNUSED_RESULT;
// Deletes the temporary directory wrapped by this object.
- bool Delete();
+ bool Delete() WARN_UNUSED_RESULT;
// Caller takes ownership of the temporary directory so it won't be destroyed
// when this object goes out of scope.
diff --git a/base/scoped_temp_dir_unittest.cc b/base/scoped_temp_dir_unittest.cc
index 039a1ed..135c2fd 100644
--- a/base/scoped_temp_dir_unittest.cc
+++ b/base/scoped_temp_dir_unittest.cc
@@ -23,7 +23,7 @@ TEST(ScopedTempDir, FullPath) {
{
ScopedTempDir dir;
- dir.Set(test_path);
+ EXPECT_TRUE(dir.Set(test_path));
// Now the dir doesn't exist, so ensure that it gets created.
EXPECT_TRUE(file_util::DirectoryExists(test_path));
// When we call Release(), it shouldn't get destroyed when leaving scope.
@@ -36,7 +36,7 @@ TEST(ScopedTempDir, FullPath) {
// Clean up.
{
ScopedTempDir dir;
- dir.Set(test_path);
+ EXPECT_TRUE(dir.Set(test_path));
}
EXPECT_FALSE(file_util::DirectoryExists(test_path));
}
@@ -83,7 +83,7 @@ TEST(ScopedTempDir, MultipleInvocations) {
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
ScopedTempDir other_dir;
- other_dir.Set(dir.Take());
+ EXPECT_TRUE(other_dir.Set(dir.Take()));
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
EXPECT_FALSE(other_dir.CreateUniqueTempDir());
diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc
index d0f3c1c..cc05a5c 100644
--- a/base/sha1_portable.cc
+++ b/base/sha1_portable.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -99,6 +99,11 @@ static inline void swapends(uint32* t) {
const int SecureHashAlgorithm::kDigestSizeBytes = 20;
void SecureHashAlgorithm::Init() {
+ A = 0;
+ B = 0;
+ C = 0;
+ D = 0;
+ E = 0;
cursor = 0;
l = 0;
H[0] = 0x67452301;
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc
index e83b982..5ac7597 100644
--- a/base/shared_memory_posix.cc
+++ b/base/shared_memory_posix.cc
@@ -196,24 +196,52 @@ bool SharedMemory::Open(const std::string& name, bool read_only) {
return PrepareMapFile(fp);
}
-// For the given shmem named |mem_name|, return a filename to mmap()
-// (and possibly create). Modifies |filename|. Return false on
-// error, or true of we are happy.
-bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
- FilePath* path) {
- // mem_name will be used for a filename; make sure it doesn't
- // contain anything which will confuse us.
- DCHECK(mem_name.find('/') == std::string::npos);
- DCHECK(mem_name.find('\0') == std::string::npos);
+bool SharedMemory::Map(uint32 bytes) {
+ if (mapped_file_ == -1)
+ return false;
- FilePath temp_dir;
- if (!file_util::GetShmemTempDir(&temp_dir))
+ memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+ MAP_SHARED, mapped_file_, 0);
+
+ if (memory_)
+ mapped_size_ = bytes;
+
+ bool mmap_succeeded = (memory_ != (void*)-1);
+ DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno;
+ return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+ if (memory_ == NULL)
return false;
- *path = temp_dir.AppendASCII("com.google.chrome.shmem." + mem_name);
+ munmap(memory_, mapped_size_);
+ memory_ = NULL;
+ mapped_size_ = 0;
return true;
}
+SharedMemoryHandle SharedMemory::handle() const {
+ return FileDescriptor(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+ Unmap();
+
+ if (mapped_file_ > 0) {
+ close(mapped_file_);
+ mapped_file_ = -1;
+ }
+}
+
+void SharedMemory::Lock() {
+ LockOrUnlockCommon(F_LOCK);
+}
+
+void SharedMemory::Unlock() {
+ LockOrUnlockCommon(F_ULOCK);
+}
+
bool SharedMemory::PrepareMapFile(FILE *fp) {
DCHECK(mapped_file_ == -1);
if (fp == NULL) return false;
@@ -243,55 +271,24 @@ bool SharedMemory::PrepareMapFile(FILE *fp) {
return true;
}
-bool SharedMemory::Map(uint32 bytes) {
- if (mapped_file_ == -1)
- return false;
-
- memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
- MAP_SHARED, mapped_file_, 0);
-
- if (memory_)
- mapped_size_ = bytes;
-
- bool mmap_succeeded = (memory_ != (void*)-1);
- DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno;
- return mmap_succeeded;
-}
+// For the given shmem named |mem_name|, return a filename to mmap()
+// (and possibly create). Modifies |filename|. Return false on
+// error, or true of we are happy.
+bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
+ FilePath* path) {
+ // mem_name will be used for a filename; make sure it doesn't
+ // contain anything which will confuse us.
+ DCHECK(mem_name.find('/') == std::string::npos);
+ DCHECK(mem_name.find('\0') == std::string::npos);
-bool SharedMemory::Unmap() {
- if (memory_ == NULL)
+ FilePath temp_dir;
+ if (!file_util::GetShmemTempDir(&temp_dir))
return false;
- munmap(memory_, mapped_size_);
- memory_ = NULL;
- mapped_size_ = 0;
- return true;
-}
-
-bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
- SharedMemoryHandle *new_handle,
- bool close_self) {
- const int new_fd = dup(mapped_file_);
- DCHECK(new_fd >= 0);
- new_handle->fd = new_fd;
- new_handle->auto_close = true;
-
- if (close_self)
- Close();
-
+ *path = temp_dir.AppendASCII("com.google.chrome.shmem." + mem_name);
return true;
}
-
-void SharedMemory::Close() {
- Unmap();
-
- if (mapped_file_ > 0) {
- close(mapped_file_);
- mapped_file_ = -1;
- }
-}
-
void SharedMemory::LockOrUnlockCommon(int function) {
DCHECK(mapped_file_ >= 0);
#if !defined(ANDROID)
@@ -313,6 +310,7 @@ void SharedMemory::LockOrUnlockCommon(int function) {
#endif
}
+<<<<<<< HEAD
void SharedMemory::Lock() {
#if !defined(ANDROID)
LockOrUnlockCommon(F_LOCK);
@@ -324,9 +322,20 @@ void SharedMemory::Unlock() {
LockOrUnlockCommon(F_ULOCK);
#endif
}
+=======
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+ SharedMemoryHandle *new_handle,
+ bool close_self) {
+ const int new_fd = dup(mapped_file_);
+ DCHECK(new_fd >= 0);
+ new_handle->fd = new_fd;
+ new_handle->auto_close = true;
-SharedMemoryHandle SharedMemory::handle() const {
- return FileDescriptor(mapped_file_, false);
+ if (close_self)
+ Close();
+>>>>>>> chromium.org at r11.0.672.0
+
+ return true;
}
} // namespace base
diff --git a/base/string_piece.h b/base/string_piece.h
index 80c6cab..64326e1 100644
--- a/base/string_piece.h
+++ b/base/string_piece.h
@@ -19,8 +19,6 @@
#define BASE_STRING_PIECE_H_
#pragma once
-#include <algorithm>
-#include <iosfwd>
#include <string>
#include "base/basictypes.h"
@@ -93,7 +91,8 @@ class StringPiece {
}
int compare(const StringPiece& x) const {
- int r = wordmemcmp(ptr_, x.ptr_, std::min(length_, x.length_));
+ int r = wordmemcmp(
+ ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
if (r == 0) {
if (length_ < x.length_) r = -1;
else if (length_ > x.length_) r = +1;
@@ -171,8 +170,8 @@ inline bool operator!=(const StringPiece& x, const StringPiece& y) {
}
inline bool operator<(const StringPiece& x, const StringPiece& y) {
- const int r = StringPiece::wordmemcmp(x.data(), y.data(),
- std::min(x.size(), y.size()));
+ const int r = StringPiece::wordmemcmp(
+ x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
return ((r < 0) || ((r == 0) && (x.size() < y.size())));
}
@@ -188,9 +187,6 @@ inline bool operator>=(const StringPiece& x, const StringPiece& y) {
return !(x < y);
}
-// allow StringPiece to be logged (needed for unit testing).
-extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
-
} // namespace base
#endif // BASE_STRING_PIECE_H_
diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h
index 3acd0ac..db75a49 100644
--- a/base/synchronization/condition_variable.h
+++ b/base/synchronization/condition_variable.h
@@ -75,7 +75,7 @@
#endif
#include "base/basictypes.h"
-#include "base/lock.h"
+#include "base/synchronization/lock.h"
namespace base {
@@ -156,10 +156,10 @@ class ConditionVariable {
RunState run_state_;
// Private critical section for access to member data.
- Lock internal_lock_;
+ base::Lock internal_lock_;
// Lock that is acquired before calling Wait().
- Lock& user_lock_;
+ base::Lock& user_lock_;
// Events that threads are blocked on.
Event waiting_list_;
@@ -176,7 +176,7 @@ class ConditionVariable {
pthread_cond_t condition_;
pthread_mutex_t* user_mutex_;
#if !defined(NDEBUG)
- Lock* user_lock_; // Needed to adjust shadow lock state on wait.
+ base::Lock* user_lock_; // Needed to adjust shadow lock state on wait.
#endif
#endif
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
index 8cfe4fe..cf18320 100644
--- a/base/synchronization/condition_variable_unittest.cc
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -8,11 +8,11 @@
#include <algorithm>
#include <vector>
-#include "base/synchronization/condition_variable.h"
-#include "base/lock.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/spin_wait.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_collision_warner.h"
#include "base/time.h"
@@ -198,7 +198,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
Time start_time; // Used to time task processing.
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
while (!queue.EveryIdWasAllocated())
queue.all_threads_have_ids()->Wait();
}
@@ -209,7 +209,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
{
// Since we have no tasks yet, all threads should be waiting by now.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -232,7 +232,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
{
// Wait until all 10 work tasks have at least been assigned.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
while (queue.task_count())
queue.no_more_tasks()->Wait();
// The last of the tasks *might* still be running, but... all but one should
@@ -252,7 +252,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
{
// Check that all work was done by one thread id.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -278,7 +278,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
{
// Wait until all work tasks have at least been assigned.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
while (queue.task_count())
queue.no_more_tasks()->Wait();
@@ -301,7 +301,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
queue.SpinUntilAllThreadsAreWaiting();
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -322,7 +322,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
queue.SpinUntilAllThreadsAreWaiting();
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -343,7 +343,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms.
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -362,7 +362,7 @@ TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms.
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -381,11 +381,11 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
WorkQueue queue(kThreadCount); // Start the threads.
Lock private_lock; // Used locally for master to wait.
- AutoLock private_held_lock(private_lock);
+ base::AutoLock private_held_lock(private_lock);
ConditionVariable private_cv(&private_lock);
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
while (!queue.EveryIdWasAllocated())
queue.all_threads_have_ids()->Wait();
}
@@ -395,7 +395,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
{
// Since we have no tasks, all threads should be waiting by now.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -412,7 +412,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
queue.work_is_available()->Broadcast(); // Start up all threads.
// Wait until we've handed out all tasks.
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
while (queue.task_count() != 0)
queue.no_more_tasks()->Wait();
}
@@ -423,7 +423,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
{
// With Broadcast(), every thread should have participated.
// but with racing.. they may not all have done equal numbers of tasks.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -440,7 +440,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
// Wait until we've handed out all tasks
{
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
while (queue.task_count() != 0)
queue.no_more_tasks()->Wait();
}
@@ -451,7 +451,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
{
// With Signal(), every thread should have participated.
// but with racing.. they may not all have done four tasks.
- AutoLock auto_lock(*queue.lock());
+ base::AutoLock auto_lock(*queue.lock());
EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
@@ -500,7 +500,7 @@ WorkQueue::WorkQueue(int thread_count)
WorkQueue::~WorkQueue() {
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
SetShutdown();
}
work_is_available_.Broadcast(); // Tell them all to terminate.
@@ -558,7 +558,7 @@ bool WorkQueue::shutdown() const {
// lock already acquired.
bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) {
bool all_shutdown;
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
{
// Declare in scope so DFAKE is guranteed to be destroyed before AutoLock.
DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
@@ -657,7 +657,7 @@ void WorkQueue::SetShutdown() {
void WorkQueue::SpinUntilAllThreadsAreWaiting() {
while (true) {
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
if (waiting_thread_count_ == thread_count_)
break;
}
@@ -668,7 +668,7 @@ void WorkQueue::SpinUntilAllThreadsAreWaiting() {
void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
while (true) {
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
if (task_count_ < task_count)
break;
}
@@ -698,7 +698,7 @@ void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
void WorkQueue::ThreadMain() {
int thread_id;
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
thread_id = GetThreadId();
if (EveryIdWasAllocated())
all_threads_have_ids()->Signal(); // Tell creator we're ready.
@@ -709,7 +709,7 @@ void WorkQueue::ThreadMain() {
TimeDelta work_time;
bool could_use_help;
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
while (0 == task_count() && !shutdown()) {
++waiting_thread_count_;
work_is_available()->Wait();
@@ -732,13 +732,13 @@ void WorkQueue::ThreadMain() {
if (work_time > TimeDelta::FromMilliseconds(0)) {
// We could just sleep(), but we'll instead further exercise the
// condition variable class, and do a timed wait.
- AutoLock auto_lock(private_lock);
+ base::AutoLock auto_lock(private_lock);
ConditionVariable private_cv(&private_lock);
private_cv.TimedWait(work_time); // Unsynchronized waiting.
}
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
// Send notification that we completed our "work."
WorkIsCompleted(thread_id);
}
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
index 01b5987..9f357d1 100644
--- a/base/synchronization/waitable_event.h
+++ b/base/synchronization/waitable_event.h
@@ -15,8 +15,8 @@
#if defined(OS_POSIX)
#include <list>
#include <utility>
-#include "base/lock.h"
#include "base/ref_counted.h"
+#include "base/synchronization/lock.h"
#endif
namespace base {
@@ -149,7 +149,7 @@ class WaitableEvent {
bool Dequeue(Waiter* waiter, void* tag);
- Lock lock_;
+ base::Lock lock_;
const bool manual_reset_;
bool signaled_;
std::list<Waiter*> waiters_;
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc
index 9cbc03a..ae03ead 100644
--- a/base/synchronization/waitable_event_posix.cc
+++ b/base/synchronization/waitable_event_posix.cc
@@ -149,6 +149,10 @@ class SyncWaiter : public WaitableEvent::Waiter {
base::ConditionVariable cv_;
};
+bool WaitableEvent::Wait() {
+ return TimedWait(TimeDelta::FromSeconds(-1));
+}
+
bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
const Time end_time(Time::Now() + max_time);
const bool finite_time = max_time.ToInternalValue() >= 0;
@@ -204,13 +208,6 @@ bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
}
}
-bool WaitableEvent::Wait() {
- return TimedWait(TimeDelta::FromSeconds(-1));
-}
-
-// -----------------------------------------------------------------------------
-
-
// -----------------------------------------------------------------------------
// Synchronous waiting on multiple objects.
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
index fa3ab43..83e099c 100644
--- a/base/sys_info_win.cc
+++ b/base/sys_info_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -63,8 +63,8 @@ std::string SysInfo::OperatingSystemVersion() {
}
// TODO: Implement OperatingSystemVersionComplete, which would include
-// patchlevel/service pack number. See chrome/browser/views/bug_report_view.cc,
-// BugReportView::SetOSVersion.
+// patchlevel/service pack number.
+// See chrome/browser/ui/views/bug_report_view.cc, BugReportView::SetOSVersion.
// static
std::string SysInfo::CPUArchitecture() {
diff --git a/base/template_util.h b/base/template_util.h
index 27bdb73..0408fc6 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -6,6 +6,8 @@
#define BASE_TEMPLATE_UTIL_H_
#pragma once
+#include <cstddef> // For size_t.
+
#include "build/build_config.h"
namespace base {
@@ -27,14 +29,22 @@ typedef integral_constant<bool, false> false_type;
template <class T> struct is_pointer : false_type {};
template <class T> struct is_pointer<T*> : true_type {};
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
namespace internal {
-// Types small_ and big_ are guaranteed such that sizeof(small_) <
-// sizeof(big_)
-typedef char small_;
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
-struct big_ {
- small_ dummy[2];
+struct NoType {
+ YesType dummy[2];
};
#if !defined(OS_WIN)
@@ -50,13 +60,23 @@ struct big_ {
template <typename From, typename To>
struct ConvertHelper {
- static small_ Test(To);
- static big_ Test(...);
+ static YesType Test(To);
+ static NoType Test(...);
static From Create();
};
#endif // !defined(OS_WIN)
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+ template <typename C>
+ static YesType Test(void(C::*)(void));
+
+ template <typename C>
+ static NoType Test(...);
+};
+
} // namespace internal
#if !defined(OS_WIN)
@@ -67,11 +87,18 @@ struct is_convertible
: integral_constant<bool,
sizeof(internal::ConvertHelper<From, To>::Test(
internal::ConvertHelper<From, To>::Create()))
- == sizeof(internal::small_)> {
+ == sizeof(internal::YesType)> {
};
#endif // !defined(OS_WIN)
+template <typename T>
+struct is_class
+ : integral_constant<bool,
+ sizeof(internal::IsClassHelper::Test<T>(0)) ==
+ sizeof(internal::YesType)> {
+};
+
} // namespace base
#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
new file mode 100644
index 0000000..51d4d33
--- /dev/null
+++ b/base/template_util_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 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/template_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct AStruct {};
+class AClass {};
+enum AnEnum {};
+
+class Parent {};
+class Child : public Parent {};
+
+TEST(TemplateUtilTest, IsPointer) {
+ EXPECT_FALSE(is_pointer<int>::value);
+ EXPECT_FALSE(is_pointer<int&>::value);
+ EXPECT_TRUE(is_pointer<int*>::value);
+ EXPECT_TRUE(is_pointer<const int*>::value);
+}
+
+TEST(TemplateUtilTest, IsArray) {
+ EXPECT_FALSE(is_array<int>::value);
+ EXPECT_FALSE(is_array<int*>::value);
+ EXPECT_FALSE(is_array<int(*)[3]>::value);
+ EXPECT_TRUE(is_array<int[]>::value);
+ EXPECT_TRUE(is_array<const int[]>::value);
+ EXPECT_TRUE(is_array<int[3]>::value);
+}
+
+TEST(TemplateUtilTest, IsNonConstReference) {
+ EXPECT_FALSE(is_non_const_reference<int>::value);
+ EXPECT_FALSE(is_non_const_reference<const int&>::value);
+ EXPECT_TRUE(is_non_const_reference<int&>::value);
+}
+
+#if !defined(OS_WIN)
+// TODO(ajwong): Why is is_convertible disabled on windows?
+TEST(TemplateUtilTest, IsConvertible) {
+ // Extra parents needed to make EXPECT_*'s parsing happy. Otherwise,
+ // it sees the equivalent of
+ //
+ // EXPECT_TRUE( (is_convertible < Child), (Parent > ::value));
+ //
+ // Silly C++.
+ EXPECT_TRUE( (is_convertible<Child, Parent>::value) );
+ EXPECT_FALSE( (is_convertible<Parent, Child>::value) );
+}
+#endif // !defined(OS_WIN)
+
+TEST(TemplateUtilTest, IsClass) {
+ EXPECT_TRUE(is_class<AStruct>::value);
+ EXPECT_TRUE(is_class<AClass>::value);
+
+ EXPECT_FALSE(is_class<AnEnum>::value);
+ EXPECT_FALSE(is_class<int>::value);
+ EXPECT_FALSE(is_class<char*>::value);
+ EXPECT_FALSE(is_class<int&>::value);
+ EXPECT_FALSE(is_class<char[3]>::value);
+}
+
+} // namespace
+} // namespace base
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index aa23f04..447a138 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -24,6 +24,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
+#if defined(OS_MACOSX)
+#include "base/test/mock_chrome_application_mac.h"
+#endif
+
#if defined(TOOLKIT_USES_GTK)
#include <gtk/gtk.h>
#endif
@@ -171,14 +175,21 @@ void TestSuite::SuppressErrorDialogs() {
}
void TestSuite::Initialize() {
+#if defined(OS_MACOSX)
+ // Some of the app unit tests spin runloops.
+ mock_cr_app::RegisterMockCrApp();
+#endif
+
// Initialize logging.
FilePath exe;
PathService::Get(base::FILE_EXE, &exe);
FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
- logging::InitLogging(log_filename.value().c_str(),
- logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
- logging::LOCK_LOG_FILE,
- logging::DELETE_OLD_LOG_FILE);
+ logging::InitLogging(
+ log_filename.value().c_str(),
+ logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE,
+ logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
// We want process and thread IDs because we may have multiple processes.
// Note: temporarily enabled timestamps in an effort to catch bug 6361.
logging::SetLogItems(true, true, true, true);
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
index 016456e..20cd8a9 100644
--- a/base/test/test_timeouts.cc
+++ b/base/test/test_timeouts.cc
@@ -44,7 +44,7 @@ bool TestTimeouts::initialized_ = false;
// static
int TestTimeouts::tiny_timeout_ms_ = 100;
int TestTimeouts::action_timeout_ms_ = 2000;
-int TestTimeouts::action_max_timeout_ms_ = 15000;
+int TestTimeouts::action_max_timeout_ms_ = 20000;
int TestTimeouts::large_test_timeout_ms_ = 3 * 60 * 1000;
int TestTimeouts::huge_test_timeout_ms_ = 10 * 60 * 1000;
diff --git a/base/third_party/dmg_fp/dtoa_wrapper.cc b/base/third_party/dmg_fp/dtoa_wrapper.cc
index fbbaf80..e34b8a6 100644
--- a/base/third_party/dmg_fp/dtoa_wrapper.cc
+++ b/base/third_party/dmg_fp/dtoa_wrapper.cc
@@ -4,12 +4,12 @@
//
// The purpose of this file is to supply the macro definintions necessary
// to make third_party/dmg_fp/dtoa.cc threadsafe.
-#include "base/lock.h"
+#include "base/synchronization/lock.h"
#include "base/logging.h"
// We need two locks because they're sometimes grabbed at the same time.
// A single lock would lead to an attempted recursive grab.
-static Lock dtoa_locks[2];
+static base::Lock dtoa_locks[2];
/*
* This define and the code below is to trigger thread-safe behavior
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c
index 4bfc33b..31e9a2b 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.c
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.c
@@ -50,77 +50,86 @@
#if DYNAMIC_ANNOTATIONS_ENABLED == 1
-void AnnotateRWLockCreate(const char *file, int line,
- const volatile void *lock){}
-void AnnotateRWLockDestroy(const char *file, int line,
- const volatile void *lock){}
-void AnnotateRWLockAcquired(const char *file, int line,
- const volatile void *lock, long is_w){}
-void AnnotateRWLockReleased(const char *file, int line,
- const volatile void *lock, long is_w){}
-void AnnotateBarrierInit(const char *file, int line,
- const volatile void *barrier, long count,
- long reinitialization_allowed) {}
-void AnnotateBarrierWaitBefore(const char *file, int line,
- const volatile void *barrier) {}
-void AnnotateBarrierWaitAfter(const char *file, int line,
- const volatile void *barrier) {}
-void AnnotateBarrierDestroy(const char *file, int line,
- const volatile void *barrier) {}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+ const char *file, int line, const volatile void *lock){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+ const char *file, int line, const volatile void *lock){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+ const char *file, int line, const volatile void *lock, long is_w){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+ const char *file, int line, const volatile void *lock, long is_w){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+ const char *file, int line, const volatile void *barrier, long count,
+ long reinitialization_allowed) {}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+ const char *file, int line, const volatile void *barrier) {}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+ const char *file, int line, const volatile void *barrier) {}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+ const char *file, int line, const volatile void *barrier) {}
-void AnnotateCondVarWait(const char *file, int line,
- const volatile void *cv,
- const volatile void *lock){}
-void AnnotateCondVarSignal(const char *file, int line,
- const volatile void *cv){}
-void AnnotateCondVarSignalAll(const char *file, int line,
- const volatile void *cv){}
-void AnnotatePublishMemoryRange(const char *file, int line,
- const volatile void *address,
- long size){}
-void AnnotateUnpublishMemoryRange(const char *file, int line,
- const volatile void *address,
- long size){}
-void AnnotatePCQCreate(const char *file, int line,
- const volatile void *pcq){}
-void AnnotatePCQDestroy(const char *file, int line,
- const volatile void *pcq){}
-void AnnotatePCQPut(const char *file, int line,
- const volatile void *pcq){}
-void AnnotatePCQGet(const char *file, int line,
- const volatile void *pcq){}
-void AnnotateNewMemory(const char *file, int line,
- const volatile void *mem,
- long size){}
-void AnnotateExpectRace(const char *file, int line,
- const volatile void *mem,
- const char *description){}
-void AnnotateBenignRace(const char *file, int line,
- const volatile void *mem,
- const char *description){}
-void AnnotateBenignRaceSized(const char *file, int line,
- const volatile void *mem,
- long size,
- const char *description) {}
-void AnnotateMutexIsUsedAsCondVar(const char *file, int line,
- const volatile void *mu){}
-void AnnotateTraceMemory(const char *file, int line,
- const volatile void *arg){}
-void AnnotateThreadName(const char *file, int line,
- const char *name){}
-void AnnotateIgnoreReadsBegin(const char *file, int line){}
-void AnnotateIgnoreReadsEnd(const char *file, int line){}
-void AnnotateIgnoreWritesBegin(const char *file, int line){}
-void AnnotateIgnoreWritesEnd(const char *file, int line){}
-void AnnotateIgnoreSyncBegin(const char *file, int line){}
-void AnnotateIgnoreSyncEnd(const char *file, int line){}
-void AnnotateEnableRaceDetection(const char *file, int line, int enable){}
-void AnnotateNoOp(const char *file, int line,
- const volatile void *arg){}
-void AnnotateFlushState(const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+ const char *file, int line, const volatile void *cv,
+ const volatile void *lock){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+ const char *file, int line, const volatile void *cv){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+ const char *file, int line, const volatile void *cv){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+ const char *file, int line, const volatile void *address, long size){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+ const char *file, int line, const volatile void *address, long size){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+ const char *file, int line, const volatile void *pcq){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+ const char *file, int line, const volatile void *pcq){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+ const char *file, int line, const volatile void *pcq){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+ const char *file, int line, const volatile void *pcq){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+ const char *file, int line, const volatile void *mem, long size){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+ const char *file, int line, const volatile void *mem, long size,
+ const char *description){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+ const char *file, int line, const volatile void *mu){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+ const char *file, int line, const volatile void *mu){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+ const char *file, int line, const volatile void *arg){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+ const char *file, int line, const char *name){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+ const char *file, int line){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+ const char *file, int line, int enable){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+ const char *file, int line, const volatile void *arg){}
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+ const char *file, int line){}
#endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
static int GetRunningOnValgrind(void) {
#ifdef RUNNING_ON_VALGRIND
if (RUNNING_ON_VALGRIND) return 1;
@@ -157,3 +166,5 @@ int RunningOnValgrind(void) {
running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
return local_running_on_valgrind;
}
+
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.h b/base/third_party/dynamic_annotations/dynamic_annotations.h
index 373f2ac..263b8ef 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.h
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.h
@@ -53,6 +53,33 @@
#ifndef __DYNAMIC_ANNOTATIONS_H__
#define __DYNAMIC_ANNOTATIONS_H__
+#ifndef DYNAMIC_ANNOTATIONS_PREFIX
+# define DYNAMIC_ANNOTATIONS_PREFIX
+#endif
+
+#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND
+# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1
+#endif
+
+#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK
+# ifdef __GNUC__
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak))
+# else
+/* TODO(glider): for Windows support we may want to change this macro in order
+ to prepend __declspec(selectany) to the annotations' declarations. */
+# error weak annotations are not supported for your compiler
+# endif
+#else
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK
+#endif
+
+/* The following preprocessor magic prepends the value of
+ DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */
+#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B
+#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B)
+#define DYNAMIC_ANNOTATIONS_NAME(name) \
+ DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name)
+
#ifndef DYNAMIC_ANNOTATIONS_ENABLED
# define DYNAMIC_ANNOTATIONS_ENABLED 0
#endif
@@ -100,40 +127,36 @@
/* Report that wait on the condition variable at address "cv" has succeeded
and the lock at address "lock" is held. */
#define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
- AnnotateCondVarWait(__FILE__, __LINE__, cv, lock)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock)
/* Report that wait on the condition variable at "cv" has succeeded. Variant
w/o lock. */
#define ANNOTATE_CONDVAR_WAIT(cv) \
- AnnotateCondVarWait(__FILE__, __LINE__, cv, NULL)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL)
/* Report that we are about to signal on the condition variable at address
"cv". */
#define ANNOTATE_CONDVAR_SIGNAL(cv) \
- AnnotateCondVarSignal(__FILE__, __LINE__, cv)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv)
/* Report that we are about to signal_all on the condition variable at address
"cv". */
#define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
- AnnotateCondVarSignalAll(__FILE__, __LINE__, cv)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv)
/* Annotations for user-defined synchronization mechanisms. */
#define ANNOTATE_HAPPENS_BEFORE(obj) ANNOTATE_CONDVAR_SIGNAL(obj)
#define ANNOTATE_HAPPENS_AFTER(obj) ANNOTATE_CONDVAR_WAIT(obj)
- /* Report that the bytes in the range [pointer, pointer+size) are about
- to be published safely. The race checker will create a happens-before
- arc from the call ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to
- subsequent accesses to this memory.
- Note: this annotation may not work properly if the race detector uses
- sampling, i.e. does not observe all memory accesses.
- */
+ /* DEPRECATED. Don't use it. */
#define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
- AnnotatePublishMemoryRange(__FILE__, __LINE__, pointer, size)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \
+ pointer, size)
/* DEPRECATED. Don't use it. */
#define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \
- AnnotateUnpublishMemoryRange(__FILE__, __LINE__, pointer, size)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \
+ pointer, size)
/* DEPRECATED. Don't use it. */
#define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) \
@@ -150,11 +173,19 @@
happens-before detectors this is a no-op. For more details see
http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */
#define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
- AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+ mu)
+
+ /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
+ Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in
+ pure happens-before mode. For a hybrid mode this is a no-op. */
+ #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu)
/* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
#define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
- AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+ mu)
/* -------------------------------------------------------------
Annotations useful when defining memory allocators, or when memory that
@@ -165,7 +196,8 @@
is about to be reused, or when a the locking discipline for a variable
changes. */
#define ANNOTATE_NEW_MEMORY(address, size) \
- AnnotateNewMemory(__FILE__, __LINE__, address, size)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \
+ size)
/* -------------------------------------------------------------
Annotations useful when defining FIFO queues that transfer data between
@@ -176,21 +208,21 @@
should be used only for FIFO queues. For non-FIFO queues use
ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */
#define ANNOTATE_PCQ_CREATE(pcq) \
- AnnotatePCQCreate(__FILE__, __LINE__, pcq)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq)
/* Report that the queue at address "pcq" is about to be destroyed. */
#define ANNOTATE_PCQ_DESTROY(pcq) \
- AnnotatePCQDestroy(__FILE__, __LINE__, pcq)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq)
/* Report that we are about to put an element into a FIFO queue at address
"pcq". */
#define ANNOTATE_PCQ_PUT(pcq) \
- AnnotatePCQPut(__FILE__, __LINE__, pcq)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq)
/* Report that we've just got an element from a FIFO queue at address
"pcq". */
#define ANNOTATE_PCQ_GET(pcq) \
- AnnotatePCQGet(__FILE__, __LINE__, pcq)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq)
/* -------------------------------------------------------------
Annotations that suppress errors. It is usually better to express the
@@ -202,13 +234,14 @@
point where "pointer" has been allocated, preferably close to the point
where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */
#define ANNOTATE_BENIGN_RACE(pointer, description) \
- AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
- sizeof(*(pointer)), description)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+ pointer, sizeof(*(pointer)), description)
/* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
the memory range [address, address+size). */
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
- AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+ address, size, description)
/* Request the analysis tool to ignore all reads in the current thread
until ANNOTATE_IGNORE_READS_END is called.
@@ -216,19 +249,19 @@
other reads and all writes.
See also ANNOTATE_UNPROTECTED_READ. */
#define ANNOTATE_IGNORE_READS_BEGIN() \
- AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
/* Stop ignoring reads. */
#define ANNOTATE_IGNORE_READS_END() \
- AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
/* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
- AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
/* Stop ignoring writes. */
#define ANNOTATE_IGNORE_WRITES_END() \
- AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
/* Start ignoring all memory accesses (reads and writes). */
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
@@ -247,29 +280,30 @@
/* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events:
RWLOCK* and CONDVAR*. */
#define ANNOTATE_IGNORE_SYNC_BEGIN() \
- AnnotateIgnoreSyncBegin(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__)
/* Stop ignoring sync events. */
#define ANNOTATE_IGNORE_SYNC_END() \
- AnnotateIgnoreSyncEnd(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__)
/* Enable (enable!=0) or disable (enable==0) race detection for all threads.
This annotation could be useful if you want to skip expensive race analysis
during some period of program execution, e.g. during initialization. */
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
- AnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \
+ enable)
/* -------------------------------------------------------------
Annotations useful for debugging. */
/* Request to trace every access to "address". */
#define ANNOTATE_TRACE_MEMORY(address) \
- AnnotateTraceMemory(__FILE__, __LINE__, address)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address)
/* Report the current thread name to a race detector. */
#define ANNOTATE_THREAD_NAME(name) \
- AnnotateThreadName(__FILE__, __LINE__, name)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name)
/* -------------------------------------------------------------
Annotations useful when implementing locks. They are not
@@ -278,20 +312,22 @@
/* Report that a lock has been created at address "lock". */
#define ANNOTATE_RWLOCK_CREATE(lock) \
- AnnotateRWLockCreate(__FILE__, __LINE__, lock)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
/* Report that the lock at address "lock" is about to be destroyed. */
#define ANNOTATE_RWLOCK_DESTROY(lock) \
- AnnotateRWLockDestroy(__FILE__, __LINE__, lock)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
/* Report that the lock at address "lock" has been acquired.
is_w=1 for writer lock, is_w=0 for reader lock. */
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
- AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \
+ is_w)
/* Report that the lock at address "lock" is about to be released. */
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
- AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \
+ is_w)
/* -------------------------------------------------------------
Annotations useful when implementing barriers. They are not
@@ -302,20 +338,23 @@
If 'reinitialization_allowed' is true, initialization is allowed to happen
multiple times w/o calling barrier_destroy() */
#define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
- AnnotateBarrierInit(__FILE__, __LINE__, barrier, count, \
- reinitialization_allowed)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \
+ count, reinitialization_allowed)
/* Report that we are about to enter barrier_wait("barrier"). */
#define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
- AnnotateBarrierWaitBefore(__FILE__, __LINE__, barrier)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \
+ barrier)
/* Report that we just exited barrier_wait("barrier"). */
#define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
- AnnotateBarrierWaitAfter(__FILE__, __LINE__, barrier)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \
+ barrier)
/* Report that the "barrier" has been destroyed. */
#define ANNOTATE_BARRIER_DESTROY(barrier) \
- AnnotateBarrierDestroy(__FILE__, __LINE__, barrier)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \
+ barrier)
/* -------------------------------------------------------------
Annotations useful for testing race detectors. */
@@ -323,16 +362,20 @@
/* Report that we expect a race on the variable at "address".
Use only in unit tests for a race detector. */
#define ANNOTATE_EXPECT_RACE(address, description) \
- AnnotateExpectRace(__FILE__, __LINE__, address, description)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \
+ description)
+
+ #define ANNOTATE_FLUSH_EXPECTED_RACES() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__)
/* A no-op. Insert where you like to test the interceptors. */
#define ANNOTATE_NO_OP(arg) \
- AnnotateNoOp(__FILE__, __LINE__, arg)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg)
/* Force the race detector to flush its state. The actual effect depends on
* the implementation of the detector. */
#define ANNOTATE_FLUSH_STATE() \
- AnnotateFlushState(__FILE__, __LINE__)
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__)
#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
@@ -360,6 +403,7 @@
#define ANNOTATE_PCQ_GET(pcq) /* empty */
#define ANNOTATE_NEW_MEMORY(address, size) /* empty */
#define ANNOTATE_EXPECT_RACE(address, description) /* empty */
+ #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */
#define ANNOTATE_BENIGN_RACE(address, description) /* empty */
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
#define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */
@@ -384,72 +428,106 @@
#ifdef __cplusplus
extern "C" {
#endif
-void AnnotateRWLockCreate(const char *file, int line,
- const volatile void *lock);
-void AnnotateRWLockDestroy(const char *file, int line,
- const volatile void *lock);
-void AnnotateRWLockAcquired(const char *file, int line,
- const volatile void *lock, long is_w);
-void AnnotateRWLockReleased(const char *file, int line,
- const volatile void *lock, long is_w);
-void AnnotateBarrierInit(const char *file, int line,
- const volatile void *barrier, long count,
- long reinitialization_allowed);
-void AnnotateBarrierWaitBefore(const char *file, int line,
- const volatile void *barrier);
-void AnnotateBarrierWaitAfter(const char *file, int line,
- const volatile void *barrier);
-void AnnotateBarrierDestroy(const char *file, int line,
- const volatile void *barrier);
-void AnnotateCondVarWait(const char *file, int line,
- const volatile void *cv,
- const volatile void *lock);
-void AnnotateCondVarSignal(const char *file, int line,
- const volatile void *cv);
-void AnnotateCondVarSignalAll(const char *file, int line,
- const volatile void *cv);
-void AnnotatePublishMemoryRange(const char *file, int line,
- const volatile void *address,
- long size);
-void AnnotateUnpublishMemoryRange(const char *file, int line,
- const volatile void *address,
- long size);
-void AnnotatePCQCreate(const char *file, int line,
- const volatile void *pcq);
-void AnnotatePCQDestroy(const char *file, int line,
- const volatile void *pcq);
-void AnnotatePCQPut(const char *file, int line,
- const volatile void *pcq);
-void AnnotatePCQGet(const char *file, int line,
- const volatile void *pcq);
-void AnnotateNewMemory(const char *file, int line,
- const volatile void *address,
- long size);
-void AnnotateExpectRace(const char *file, int line,
- const volatile void *address,
- const char *description);
-void AnnotateBenignRace(const char *file, int line,
- const volatile void *address,
- const char *description);
-void AnnotateBenignRaceSized(const char *file, int line,
- const volatile void *address,
- long size,
- const char *description);
-void AnnotateMutexIsUsedAsCondVar(const char *file, int line,
- const volatile void *mu);
-void AnnotateTraceMemory(const char *file, int line,
- const volatile void *arg);
-void AnnotateThreadName(const char *file, int line,
- const char *name);
-void AnnotateIgnoreReadsBegin(const char *file, int line);
-void AnnotateIgnoreReadsEnd(const char *file, int line);
-void AnnotateIgnoreWritesBegin(const char *file, int line);
-void AnnotateIgnoreWritesEnd(const char *file, int line);
-void AnnotateEnableRaceDetection(const char *file, int line, int enable);
-void AnnotateNoOp(const char *file, int line,
- const volatile void *arg);
-void AnnotateFlushState(const char *file, int line);
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+ const char *file, int line,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+ const char *file, int line,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+ const char *file, int line,
+ const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+ const char *file, int line,
+ const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+ const char *file, int line, const volatile void *barrier, long count,
+ long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+ const char *file, int line, const volatile void *cv,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+ const char *file, int line,
+ const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+ const char *file, int line,
+ const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+ const char *file, int line,
+ const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+ const char *file, int line,
+ const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+ const char *file, int line,
+ const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+ const char *file, int line, const volatile void *mem, long size,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+ const char *file, int line,
+ const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+ const char *file, int line,
+ const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+ const char *file, int line,
+ const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+ const char *file, int line,
+ const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+ const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+ const char *file, int line,
+ const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
/* Return non-zero value if running under valgrind.
If "valgrind.h" is included into dynamic_annotations.c,
@@ -466,6 +544,7 @@ void AnnotateFlushState(const char *file, int line);
change its return value.
*/
int RunningOnValgrind(void);
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
#ifdef __cplusplus
}
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 2b030f6..4441477 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -10,6 +10,22 @@
namespace base {
+SimpleThread::SimpleThread(const std::string& name_prefix)
+ : name_prefix_(name_prefix), name_(name_prefix),
+ thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::SimpleThread(const std::string& name_prefix,
+ const Options& options)
+ : name_prefix_(name_prefix), name_(name_prefix), options_(options),
+ thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::~SimpleThread() {
+ DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
+ DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
+}
+
void SimpleThread::Start() {
DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
@@ -37,22 +53,6 @@ void SimpleThread::ThreadMain() {
Run();
}
-SimpleThread::SimpleThread(const std::string& name_prefix)
- : name_prefix_(name_prefix), name_(name_prefix),
- thread_(), event_(true, false), tid_(0), joined_(false) {
-}
-
-SimpleThread::SimpleThread(const std::string& name_prefix,
- const Options& options)
- : name_prefix_(name_prefix), name_(name_prefix), options_(options),
- thread_(), event_(true, false), tid_(0), joined_(false) {
-}
-
-SimpleThread::~SimpleThread() {
- DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
- DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
-}
-
DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
const std::string& name_prefix)
: SimpleThread(name_prefix),
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index f55bd62..1631336 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -46,8 +46,8 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/threading/platform_thread.h"
+#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
namespace base {
@@ -173,7 +173,7 @@ class DelegateSimpleThreadPool : public DelegateSimpleThread::Delegate {
int num_threads_;
std::vector<DelegateSimpleThread*> threads_;
std::queue<Delegate*> delegates_;
- Lock lock_; // Locks delegates_
+ base::Lock lock_; // Locks delegates_
WaitableEvent dry_; // Not signaled when there is no work to do.
};
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 09f8847..c0fb537 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -11,6 +11,17 @@
namespace base {
+namespace {
+
+// We use this thread-local variable to record whether or not a thread exited
+// because its Stop method was called. This allows us to catch cases where
+// MessageLoop::Quit() is called directly, which is unexpected when using a
+// Thread to setup and run a MessageLoop.
+base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool(
+ base::LINKER_INITIALIZED);
+
+} // namespace
+
// This task is used to trigger the message loop to exit.
class ThreadQuitTask : public Task {
public:
@@ -48,29 +59,6 @@ Thread::~Thread() {
Stop();
}
-namespace {
-
-// We use this thread-local variable to record whether or not a thread exited
-// because its Stop method was called. This allows us to catch cases where
-// MessageLoop::Quit() is called directly, which is unexpected when using a
-// Thread to setup and run a MessageLoop.
-base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool(
- base::LINKER_INITIALIZED);
-
-} // namespace
-
-void Thread::SetThreadWasQuitProperly(bool flag) {
- lazy_tls_bool.Pointer()->Set(flag);
-}
-
-bool Thread::GetThreadWasQuitProperly() {
- bool quit_properly = true;
-#ifndef NDEBUG
- quit_properly = lazy_tls_bool.Pointer()->Get();
-#endif
- return quit_properly;
-}
-
bool Thread::Start() {
return StartWithOptions(Options());
}
@@ -140,6 +128,18 @@ void Thread::Run(MessageLoop* message_loop) {
message_loop->Run();
}
+void Thread::SetThreadWasQuitProperly(bool flag) {
+ lazy_tls_bool.Pointer()->Set(flag);
+}
+
+bool Thread::GetThreadWasQuitProperly() {
+ bool quit_properly = true;
+#ifndef NDEBUG
+ quit_properly = lazy_tls_bool.Pointer()->Get();
+#endif
+ return quit_properly;
+}
+
void Thread::ThreadMain() {
{
// The message loop for this thread.
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index c0010fb..712b5b5 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -7,7 +7,7 @@
#pragma once
#ifndef NDEBUG
-#include "base/lock.h"
+#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
#endif // NDEBUG
@@ -51,7 +51,7 @@ class ThreadChecker {
private:
void EnsureThreadIdAssigned() const;
- mutable Lock lock_;
+ mutable base::Lock lock_;
// This is mutable so that CalledOnValidThread can set it.
// It's guarded by |lock_|.
mutable PlatformThreadId valid_thread_id_;
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc
index 68987c3..a3d3b66 100644
--- a/base/threading/thread_collision_warner_unittest.cc
+++ b/base/threading/thread_collision_warner_unittest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "base/compiler_specific.h"
-#include "base/lock.h"
#include "base/scoped_ptr.h"
+#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_collision_warner.h"
@@ -266,30 +266,30 @@ TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
// a lock.
class QueueUser : public base::DelegateSimpleThread::Delegate {
public:
- QueueUser(NonThreadSafeQueue& queue, Lock& lock)
+ QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
: queue_(queue),
lock_(lock) {}
virtual void Run() {
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
queue_.push(0);
}
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
queue_.pop();
}
}
private:
NonThreadSafeQueue& queue_;
- Lock& lock_;
+ base::Lock& lock_;
};
AssertReporter* local_reporter = new AssertReporter();
NonThreadSafeQueue queue(local_reporter);
- Lock lock;
+ base::Lock lock;
QueueUser queue_user_a(queue, lock);
QueueUser queue_user_b(queue, lock);
@@ -340,34 +340,34 @@ TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
// a lock.
class QueueUser : public base::DelegateSimpleThread::Delegate {
public:
- QueueUser(NonThreadSafeQueue& queue, Lock& lock)
+ QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
: queue_(queue),
lock_(lock) {}
virtual void Run() {
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
queue_.push(0);
}
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
queue_.bar();
}
{
- AutoLock auto_lock(lock_);
+ base::AutoLock auto_lock(lock_);
queue_.pop();
}
}
private:
NonThreadSafeQueue& queue_;
- Lock& lock_;
+ base::Lock& lock_;
};
AssertReporter* local_reporter = new AssertReporter();
NonThreadSafeQueue queue(local_reporter);
- Lock lock;
+ base::Lock lock;
QueueUser queue_user_a(queue, lock);
QueueUser queue_user_b(queue, lock);
diff --git a/base/threading/thread_local_storage_posix.cc b/base/threading/thread_local_storage_posix.cc
index 81b7332..3d0e187 100644
--- a/base/threading/thread_local_storage_posix.cc
+++ b/base/threading/thread_local_storage_posix.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -9,7 +9,8 @@
namespace base {
ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor)
- : initialized_(false) {
+ : initialized_(false),
+ key_(0) {
Initialize(destructor);
}
diff --git a/base/threading/thread_local_storage_win.cc b/base/threading/thread_local_storage_win.cc
index 2967a27..667d1b9 100644
--- a/base/threading/thread_local_storage_win.cc
+++ b/base/threading/thread_local_storage_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -57,7 +57,8 @@ void** ThreadLocalStorage::Initialize() {
}
ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor)
- : initialized_(false) {
+ : initialized_(false),
+ slot_(0) {
Initialize(destructor);
}
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
index 332c55e..c984ee3 100644
--- a/base/threading/worker_pool_posix_unittest.cc
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -6,8 +6,8 @@
#include <set>
-#include "base/lock.h"
#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
#include "base/task.h"
#include "base/threading/platform_thread.h"
#include "base/synchronization/waitable_event.h"
@@ -61,12 +61,12 @@ class IncrementingTask : public Task {
virtual void Run() {
AddSelfToUniqueThreadSet();
- AutoLock locked(*counter_lock_);
+ base::AutoLock locked(*counter_lock_);
(*counter_)++;
}
void AddSelfToUniqueThreadSet() {
- AutoLock locked(*unique_threads_lock_);
+ base::AutoLock locked(*unique_threads_lock_);
unique_threads_->insert(PlatformThread::CurrentId());
}
@@ -100,7 +100,7 @@ class BlockingIncrementingTask : public Task {
virtual void Run() {
{
- AutoLock num_waiting_to_start_locked(*num_waiting_to_start_lock_);
+ base::AutoLock num_waiting_to_start_locked(*num_waiting_to_start_lock_);
(*num_waiting_to_start_)++;
}
num_waiting_to_start_cv_->Signal();
@@ -138,14 +138,14 @@ class PosixDynamicThreadPoolTest : public testing::Test {
}
void WaitForTasksToStart(int num_tasks) {
- AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
+ base::AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
while (num_waiting_to_start_ < num_tasks) {
num_waiting_to_start_cv_.Wait();
}
}
void WaitForIdleThreads(int num_idle_threads) {
- AutoLock pool_locked(*peer_.lock());
+ base::AutoLock pool_locked(*peer_.lock());
while (peer_.num_idle_threads() < num_idle_threads) {
peer_.num_idle_threads_cv()->Wait();
}
@@ -249,7 +249,7 @@ TEST_F(PosixDynamicThreadPoolTest, Complex) {
// Wake up all idle threads so they can exit.
{
- AutoLock locked(*peer_.lock());
+ base::AutoLock locked(*peer_.lock());
while (peer_.num_idle_threads() > 0) {
peer_.tasks_available_cv()->Signal();
peer_.num_idle_threads_cv()->Wait();
diff --git a/base/time.h b/base/time.h
index e1fbf96..ed4e772 100644
--- a/base/time.h
+++ b/base/time.h
@@ -411,10 +411,6 @@ class Time {
int64 us_;
};
-inline Time TimeDelta::operator+(Time t) const {
- return Time(t.us_ + delta_);
-}
-
// Inline the TimeDelta factory methods, for fast TimeDelta construction.
// static
@@ -447,6 +443,10 @@ inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
return TimeDelta(us);
}
+inline Time TimeDelta::operator+(Time t) const {
+ return Time(t.us_ + delta_);
+}
+
// TimeTicks ------------------------------------------------------------------
class TimeTicks {
diff --git a/base/time_posix.cc b/base/time_posix.cc
index 9646c87..62e6e49 100644
--- a/base/time_posix.cc
+++ b/base/time_posix.cc
@@ -14,6 +14,19 @@
namespace base {
+struct timespec TimeDelta::ToTimeSpec() const {
+ int64 microseconds = InMicroseconds();
+ time_t seconds = 0;
+ if (microseconds >= Time::kMicrosecondsPerSecond) {
+ seconds = InSeconds();
+ microseconds -= seconds * Time::kMicrosecondsPerSecond;
+ }
+ struct timespec result =
+ {seconds,
+ microseconds * Time::kNanosecondsPerMicrosecond};
+ return result;
+}
+
#if !defined(OS_MACOSX)
// The Time routines in this file use standard POSIX routines, or almost-
// standard routines in the case of timegm. We need to use a Mach-specific
@@ -60,6 +73,30 @@ Time Time::NowFromSystemTime() {
return Now();
}
+void Time::Explode(bool is_local, Exploded* exploded) const {
+ // Time stores times with microsecond resolution, but Exploded only carries
+ // millisecond resolution, so begin by being lossy. Adjust from Windows
+ // epoch (1601) to Unix epoch (1970);
+ int64 milliseconds = (us_ - kWindowsEpochDeltaMicroseconds) /
+ kMicrosecondsPerMillisecond;
+ time_t seconds = milliseconds / kMillisecondsPerSecond;
+
+ struct tm timestruct;
+ if (is_local)
+ localtime_r(&seconds, &timestruct);
+ else
+ gmtime_r(&seconds, &timestruct);
+
+ exploded->year = timestruct.tm_year + 1900;
+ exploded->month = timestruct.tm_mon + 1;
+ exploded->day_of_week = timestruct.tm_wday;
+ exploded->day_of_month = timestruct.tm_mday;
+ exploded->hour = timestruct.tm_hour;
+ exploded->minute = timestruct.tm_min;
+ exploded->second = timestruct.tm_sec;
+ exploded->millisecond = milliseconds % kMillisecondsPerSecond;
+}
+
// static
Time Time::FromExploded(bool is_local, const Exploded& exploded) {
struct tm timestruct;
@@ -119,30 +156,6 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
kWindowsEpochDeltaMicroseconds);
}
-void Time::Explode(bool is_local, Exploded* exploded) const {
- // Time stores times with microsecond resolution, but Exploded only carries
- // millisecond resolution, so begin by being lossy. Adjust from Windows
- // epoch (1601) to Unix epoch (1970);
- int64 milliseconds = (us_ - kWindowsEpochDeltaMicroseconds) /
- kMicrosecondsPerMillisecond;
- time_t seconds = milliseconds / kMillisecondsPerSecond;
-
- struct tm timestruct;
- if (is_local)
- localtime_r(&seconds, &timestruct);
- else
- gmtime_r(&seconds, &timestruct);
-
- exploded->year = timestruct.tm_year + 1900;
- exploded->month = timestruct.tm_mon + 1;
- exploded->day_of_week = timestruct.tm_wday;
- exploded->day_of_month = timestruct.tm_mday;
- exploded->hour = timestruct.tm_hour;
- exploded->minute = timestruct.tm_min;
- exploded->second = timestruct.tm_sec;
- exploded->millisecond = milliseconds % kMillisecondsPerSecond;
-}
-
// TimeTicks ------------------------------------------------------------------
// FreeBSD 6 has CLOCK_MONOLITHIC but defines _POSIX_MONOTONIC_CLOCK to -1.
#if (defined(OS_POSIX) && \
@@ -177,19 +190,6 @@ TimeTicks TimeTicks::HighResNow() {
#endif // !OS_MACOSX
-struct timespec TimeDelta::ToTimeSpec() const {
- int64 microseconds = InMicroseconds();
- time_t seconds = 0;
- if (microseconds >= Time::kMicrosecondsPerSecond) {
- seconds = InSeconds();
- microseconds -= seconds * Time::kMicrosecondsPerSecond;
- }
- struct timespec result =
- {seconds,
- microseconds * Time::kNanosecondsPerMicrosecond};
- return result;
-}
-
struct timeval Time::ToTimeVal() const {
struct timeval result;
int64 us = us_ - kTimeTToMicrosecondsOffset;
diff --git a/base/time_win.cc b/base/time_win.cc
index ca3aef1..601211c 100644
--- a/base/time_win.cc
+++ b/base/time_win.cc
@@ -41,10 +41,10 @@
#include <mmsystem.h>
#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/logging.h"
#include "base/cpu.h"
#include "base/singleton.h"
+#include "base/synchronization/lock.h"
using base::Time;
using base::TimeDelta;
@@ -262,7 +262,7 @@ DWORD last_seen_now = 0;
// easy to use a Singleton without even knowing it, and that may lead to many
// gotchas). Its impact on startup time should be negligible due to low-level
// nature of time code.
-Lock rollover_lock;
+base::Lock rollover_lock;
// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
// because it returns the number of milliseconds since Windows has started,
@@ -270,7 +270,7 @@ Lock rollover_lock;
// rollover ourselves, which works if TimeTicks::Now() is called at least every
// 49 days.
TimeDelta RolloverProtectedNow() {
- AutoLock locked(rollover_lock);
+ base::AutoLock locked(rollover_lock);
// We should hold the lock while calling tick_function to make sure that
// we keep last_seen_now stay correctly in sync.
DWORD now = tick_function();
@@ -409,4 +409,4 @@ int64 TimeTicks::GetQPCDriftMicroseconds() {
// static
bool TimeTicks::IsHighResClockWorking() {
return HighResNowSingleton::GetInstance()->IsUsingHighResClock();
-} \ No newline at end of file
+}
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 3646000..a9f81b1 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -85,7 +85,7 @@ Births::Births(const Location& location)
// static
ThreadData* ThreadData::first_ = NULL;
// static
-Lock ThreadData::list_lock_;
+base::Lock ThreadData::list_lock_;
// static
ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
@@ -111,7 +111,7 @@ ThreadData* ThreadData::current() {
bool too_late_to_create = false;
{
registry = new ThreadData;
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
// Use lock to insure we have most recent status.
if (!IsActive()) {
too_late_to_create = true;
@@ -285,7 +285,7 @@ Births* ThreadData::TallyABirth(const Location& location) {
Births* tracker = new Births(location);
// Lock since the map may get relocated now, and other threads sometimes
// snapshot it (but they lock before copying it).
- AutoLock lock(lock_);
+ base::AutoLock lock(lock_);
birth_map_[location] = tracker;
return tracker;
}
@@ -305,13 +305,13 @@ void ThreadData::TallyADeath(const Births& lifetimes,
return;
}
- AutoLock lock(lock_); // Lock since the map may get relocated now.
+ base::AutoLock lock(lock_); // Lock since the map may get relocated now.
death_map_[&lifetimes].RecordDeath(duration);
}
// static
ThreadData* ThreadData::first() {
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
return first_;
}
@@ -323,7 +323,7 @@ const std::string ThreadData::ThreadName() const {
// This may be called from another thread.
void ThreadData::SnapshotBirthMap(BirthMap *output) const {
- AutoLock lock(lock_);
+ base::AutoLock lock(lock_);
for (BirthMap::const_iterator it = birth_map_.begin();
it != birth_map_.end(); ++it)
(*output)[it->first] = it->second;
@@ -331,7 +331,7 @@ void ThreadData::SnapshotBirthMap(BirthMap *output) const {
// This may be called from another thread.
void ThreadData::SnapshotDeathMap(DeathMap *output) const {
- AutoLock lock(lock_);
+ base::AutoLock lock(lock_);
for (DeathMap::const_iterator it = death_map_.begin();
it != death_map_.end(); ++it)
(*output)[it->first] = it->second;
@@ -348,7 +348,7 @@ void ThreadData::ResetAllThreadData() {
}
void ThreadData::Reset() {
- AutoLock lock(lock_);
+ base::AutoLock lock(lock_);
for (DeathMap::iterator it = death_map_.begin();
it != death_map_.end(); ++it)
it->second.Clear();
@@ -372,7 +372,7 @@ class ThreadData::ThreadSafeDownCounter {
private:
size_t remaining_count_;
- Lock lock_; // protect access to remaining_count_.
+ base::Lock lock_; // protect access to remaining_count_.
};
ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count)
@@ -382,7 +382,7 @@ ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count)
bool ThreadData::ThreadSafeDownCounter::LastCaller() {
{
- AutoLock lock(lock_);
+ base::AutoLock lock(lock_);
if (--remaining_count_)
return false;
} // Release lock, so we can delete everything in this instance.
@@ -461,12 +461,12 @@ bool ThreadData::StartTracking(bool status) {
#endif
if (!status) {
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
DCHECK(status_ == ACTIVE || status_ == SHUTDOWN);
status_ = SHUTDOWN;
return true;
}
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
DCHECK(status_ == UNINITIALIZED);
CHECK(tls_index_.Initialize(NULL));
status_ = ACTIVE;
@@ -504,7 +504,7 @@ void ThreadData::ShutdownSingleThreadedCleanup() {
return;
ThreadData* thread_data_list;
{
- AutoLock lock(list_lock_);
+ base::AutoLock lock(list_lock_);
thread_data_list = first_;
first_ = NULL;
}
@@ -614,7 +614,7 @@ void DataCollector::Append(const ThreadData& thread_data) {
thread_data.SnapshotDeathMap(&death_map);
// Use our lock to protect our accumulation activity.
- AutoLock lock(accumulation_lock_);
+ base::AutoLock lock(accumulation_lock_);
DCHECK(count_of_contributing_threads_);
@@ -743,11 +743,6 @@ void Comparator::Clear() {
selector_ = NIL;
}
-void Comparator::Sort(DataCollector::Collection* collection) const {
- std::sort(collection->begin(), collection->end(), *this);
-}
-
-
bool Comparator::operator()(const Snapshot& left,
const Snapshot& right) const {
switch (selector_) {
@@ -816,6 +811,10 @@ bool Comparator::operator()(const Snapshot& left,
return false;
}
+void Comparator::Sort(DataCollector::Collection* collection) const {
+ std::sort(collection->begin(), collection->end(), *this);
+}
+
bool Comparator::Equivalent(const Snapshot& left,
const Snapshot& right) const {
switch (selector_) {
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 07731ff..ed629c3 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -10,7 +10,7 @@
#include <string>
#include <vector>
-#include "base/lock.h"
+#include "base/synchronization/lock.h"
#include "base/tracked.h"
#include "base/threading/thread_local_storage.h"
@@ -322,7 +322,7 @@ class DataCollector {
// seen a death count.
BirthCount global_birth_count_;
- Lock accumulation_lock_; // Protects access during accumulation phase.
+ base::Lock accumulation_lock_; // Protects access during accumulation phase.
DISALLOW_COPY_AND_ASSIGN(DataCollector);
};
@@ -577,7 +577,7 @@ class ThreadData {
// Link to the most recently created instance (starts a null terminated list).
static ThreadData* first_;
// Protection for access to first_.
- static Lock list_lock_;
+ static base::Lock list_lock_;
// We set status_ to SHUTDOWN when we shut down the tracking service. This
// setting is redundantly established by all participating threads so that we
@@ -613,7 +613,7 @@ class ThreadData {
// thread, or reading from another thread. For reading from this thread we
// don't need a lock, as there is no potential for a conflict since the
// writing is only done from this thread.
- mutable Lock lock_;
+ mutable base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(ThreadData);
};
diff --git a/base/tuple.h b/base/tuple.h
index 6b0d336..13d8722 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -548,13 +548,6 @@ inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
template <class ObjT, class Method, class A>
inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) {
-
-#if defined(OS_CHROMEOS)
- // To troubleshoot crosbug.com/7327.
- CHECK(obj);
- CHECK(&arg);
- CHECK(method);
-#endif
(obj->*method)(arg.a);
}
diff --git a/base/utf_string_conversions.cc b/base/utf_string_conversions.cc
index 41a70db..7b73696 100644
--- a/base/utf_string_conversions.cc
+++ b/base/utf_string_conversions.cc
@@ -133,7 +133,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
return ConvertUnicode(src, src_len, output);
}
-string16 UTF8ToUTF16(const std::string& utf8) {
+string16 UTF8ToUTF16(const base::StringPiece& utf8) {
string16 ret;
// Ignore the success flag of this call, it will do the best it can for
// invalid input, which is what we want here.
@@ -161,7 +161,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
return UTF8ToWide(src, src_len, output);
}
-string16 UTF8ToUTF16(const std::string& utf8) {
+string16 UTF8ToUTF16(const base::StringPiece& utf8) {
return UTF8ToWide(utf8);
}
@@ -175,22 +175,12 @@ std::string UTF16ToUTF8(const string16& utf16) {
#endif
-std::wstring ASCIIToWide(const char* ascii) {
- DCHECK(IsStringASCII(ascii)) << ascii;
- return std::wstring(ascii, &ascii[strlen(ascii)]);
-}
-
-std::wstring ASCIIToWide(const std::string& ascii) {
+std::wstring ASCIIToWide(const base::StringPiece& ascii) {
DCHECK(IsStringASCII(ascii)) << ascii;
return std::wstring(ascii.begin(), ascii.end());
}
-string16 ASCIIToUTF16(const char* ascii) {
- DCHECK(IsStringASCII(ascii)) << ascii;
- return string16(ascii, &ascii[strlen(ascii)]);
-}
-
-string16 ASCIIToUTF16(const std::string& ascii) {
+string16 ASCIIToUTF16(const base::StringPiece& ascii) {
DCHECK(IsStringASCII(ascii)) << ascii;
return string16(ascii.begin(), ascii.end());
}
diff --git a/base/utf_string_conversions.h b/base/utf_string_conversions.h
index 6c49b41..4aa4d41 100644
--- a/base/utf_string_conversions.h
+++ b/base/utf_string_conversions.h
@@ -9,10 +9,7 @@
#include <string>
#include "base/string16.h"
-
-namespace base {
-class StringPiece;
-}
+#include "base/string_piece.h"
// These convert between UTF-8, -16, and -32 strings. They are potentially slow,
// so avoid unnecessary conversions. The low-level versions return a boolean
@@ -31,7 +28,7 @@ bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output);
std::wstring UTF16ToWide(const string16& utf16);
bool UTF8ToUTF16(const char* src, size_t src_len, string16* output);
-string16 UTF8ToUTF16(const std::string& utf8);
+string16 UTF8ToUTF16(const base::StringPiece& utf8);
bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output);
std::string UTF16ToUTF8(const string16& utf16);
@@ -50,16 +47,7 @@ std::string UTF16ToUTF8(const string16& utf16);
// These convert an ASCII string, typically a hardcoded constant, to a
// UTF16/Wide string.
-//
-// Note that this doesn't use StringPiece because it's very common to need
-// ASCIIToUTF16("foo"), and either we have to include it in this file, or
-// forward declare it and force all callers to include string_piece.h. Given
-// that string_piece brings in complicated stuff like <algorithm>, it's
-// easier to just duplicate these very simple definitions for the two calling
-// cases we actually use.
-std::wstring ASCIIToWide(const char* ascii);
-std::wstring ASCIIToWide(const std::string& ascii);
-string16 ASCIIToUTF16(const char* ascii);
-string16 ASCIIToUTF16(const std::string& ascii);
+std::wstring ASCIIToWide(const base::StringPiece& ascii);
+string16 ASCIIToUTF16(const base::StringPiece& ascii);
#endif // BASE_UTF_STRING_CONVERSIONS_H_
diff --git a/base/values.cc b/base/values.cc
index 3522569..9c96f26 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -70,27 +70,27 @@ Value* Value::CreateNullValue() {
}
// static
-Value* Value::CreateBooleanValue(bool in_value) {
+FundamentalValue* Value::CreateBooleanValue(bool in_value) {
return new FundamentalValue(in_value);
}
// static
-Value* Value::CreateIntegerValue(int in_value) {
+FundamentalValue* Value::CreateIntegerValue(int in_value) {
return new FundamentalValue(in_value);
}
// static
-Value* Value::CreateRealValue(double in_value) {
+FundamentalValue* Value::CreateDoubleValue(double in_value) {
return new FundamentalValue(in_value);
}
// static
-Value* Value::CreateStringValue(const std::string& in_value) {
+StringValue* Value::CreateStringValue(const std::string& in_value) {
return new StringValue(in_value);
}
// static
-Value* Value::CreateStringValue(const string16& in_value) {
+StringValue* Value::CreateStringValue(const string16& in_value) {
return new StringValue(in_value);
}
@@ -107,7 +107,7 @@ bool Value::GetAsInteger(int* out_value) const {
return false;
}
-bool Value::GetAsReal(double* out_value) const {
+bool Value::GetAsDouble(double* out_value) const {
return false;
}
@@ -158,7 +158,7 @@ FundamentalValue::FundamentalValue(int in_value)
}
FundamentalValue::FundamentalValue(double in_value)
- : Value(TYPE_REAL), real_value_(in_value) {
+ : Value(TYPE_DOUBLE), double_value_(in_value) {
}
FundamentalValue::~FundamentalValue() {
@@ -176,13 +176,13 @@ bool FundamentalValue::GetAsInteger(int* out_value) const {
return (IsType(TYPE_INTEGER));
}
-bool FundamentalValue::GetAsReal(double* out_value) const {
- if (out_value && IsType(TYPE_REAL))
- *out_value = real_value_;
- return (IsType(TYPE_REAL));
+bool FundamentalValue::GetAsDouble(double* out_value) const {
+ if (out_value && IsType(TYPE_DOUBLE))
+ *out_value = double_value_;
+ return (IsType(TYPE_DOUBLE));
}
-Value* FundamentalValue::DeepCopy() const {
+FundamentalValue* FundamentalValue::DeepCopy() const {
switch (GetType()) {
case TYPE_BOOLEAN:
return CreateBooleanValue(boolean_value_);
@@ -190,8 +190,8 @@ Value* FundamentalValue::DeepCopy() const {
case TYPE_INTEGER:
return CreateIntegerValue(integer_value_);
- case TYPE_REAL:
- return CreateRealValue(real_value_);
+ case TYPE_DOUBLE:
+ return CreateDoubleValue(double_value_);
default:
NOTREACHED();
@@ -212,9 +212,9 @@ bool FundamentalValue::Equals(const Value* other) const {
int lhs, rhs;
return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
}
- case TYPE_REAL: {
+ case TYPE_DOUBLE: {
double lhs, rhs;
- return GetAsReal(&lhs) && other->GetAsReal(&rhs) && lhs == rhs;
+ return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs;
}
default:
NOTREACHED();
@@ -250,7 +250,7 @@ bool StringValue::GetAsString(string16* out_value) const {
return true;
}
-Value* StringValue::DeepCopy() const {
+StringValue* StringValue::DeepCopy() const {
return CreateStringValue(value_);
}
@@ -288,7 +288,7 @@ BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
return new BinaryValue(buffer_copy, size);
}
-Value* BinaryValue::DeepCopy() const {
+BinaryValue* BinaryValue::DeepCopy() const {
return CreateWithCopiedBuffer(buffer_, size_);
}
@@ -367,8 +367,8 @@ void DictionaryValue::SetInteger(const std::string& path, int in_value) {
Set(path, CreateIntegerValue(in_value));
}
-void DictionaryValue::SetReal(const std::string& path, double in_value) {
- Set(path, CreateRealValue(in_value));
+void DictionaryValue::SetDouble(const std::string& path, double in_value) {
+ Set(path, CreateDoubleValue(in_value));
}
void DictionaryValue::SetString(const std::string& path,
@@ -430,13 +430,13 @@ bool DictionaryValue::GetInteger(const std::string& path,
return value->GetAsInteger(out_value);
}
-bool DictionaryValue::GetReal(const std::string& path,
- double* out_value) const {
+bool DictionaryValue::GetDouble(const std::string& path,
+ double* out_value) const {
Value* value;
if (!Get(path, &value))
return false;
- return value->GetAsReal(out_value);
+ return value->GetAsDouble(out_value);
}
bool DictionaryValue::GetString(const std::string& path,
@@ -533,13 +533,13 @@ bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
return value->GetAsInteger(out_value);
}
-bool DictionaryValue::GetRealWithoutPathExpansion(const std::string& key,
- double* out_value) const {
+bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key,
+ double* out_value) const {
Value* value;
if (!GetWithoutPathExpansion(key, &value))
return false;
- return value->GetAsReal(out_value);
+ return value->GetAsDouble(out_value);
}
bool DictionaryValue::GetStringWithoutPathExpansion(
@@ -646,7 +646,7 @@ void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
}
}
-Value* DictionaryValue::DeepCopy() const {
+DictionaryValue* DictionaryValue::DeepCopy() const {
DictionaryValue* result = new DictionaryValue;
for (ValueMap::const_iterator current_entry(dictionary_.begin());
@@ -742,12 +742,12 @@ bool ListValue::GetInteger(size_t index, int* out_value) const {
return value->GetAsInteger(out_value);
}
-bool ListValue::GetReal(size_t index, double* out_value) const {
+bool ListValue::GetDouble(size_t index, double* out_value) const {
Value* value;
if (!Get(index, &value))
return false;
- return value->GetAsReal(out_value);
+ return value->GetAsDouble(out_value);
}
bool ListValue::GetString(size_t index, std::string* out_value) const {
@@ -862,7 +862,7 @@ bool ListValue::GetAsList(ListValue** out_value) {
return true;
}
-Value* ListValue::DeepCopy() const {
+ListValue* ListValue::DeepCopy() const {
ListValue* result = new ListValue;
for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
diff --git a/base/values.h b/base/values.h
index d69a685..408ca8b 100644
--- a/base/values.h
+++ b/base/values.h
@@ -50,7 +50,7 @@ class Value {
TYPE_NULL = 0,
TYPE_BOOLEAN,
TYPE_INTEGER,
- TYPE_REAL,
+ TYPE_DOUBLE,
TYPE_STRING,
TYPE_BINARY,
TYPE_DICTIONARY,
@@ -63,11 +63,11 @@ class Value {
// kinds of values without thinking about which class implements them.
// These can always be expected to return a valid Value*.
static Value* CreateNullValue();
- static Value* CreateBooleanValue(bool in_value);
- static Value* CreateIntegerValue(int in_value);
- static Value* CreateRealValue(double in_value);
- static Value* CreateStringValue(const std::string& in_value);
- static Value* CreateStringValue(const string16& in_value);
+ static FundamentalValue* CreateBooleanValue(bool in_value);
+ static FundamentalValue* CreateIntegerValue(int in_value);
+ static FundamentalValue* CreateDoubleValue(double in_value);
+ static StringValue* CreateStringValue(const std::string& in_value);
+ static StringValue* CreateStringValue(const string16& in_value);
// This one can return NULL if the input isn't valid. If the return value
// is non-null, the new object has taken ownership of the buffer pointer.
@@ -89,13 +89,16 @@ class Value {
// returned; otherwise, false is returned and |out_value| is unchanged.
virtual bool GetAsBoolean(bool* out_value) const;
virtual bool GetAsInteger(int* out_value) const;
- virtual bool GetAsReal(double* out_value) const;
+ virtual bool GetAsDouble(double* out_value) const;
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
virtual bool GetAsList(ListValue** out_value);
// This creates a deep copy of the entire Value tree, and returns a pointer
// to the copy. The caller gets ownership of the copy, of course.
+ //
+ // Subclasses return their own type directly in their overrides;
+ // this works because C++ supports covariant return types.
virtual Value* DeepCopy() const;
// Compares if two Value objects have equal contents.
@@ -129,15 +132,15 @@ class FundamentalValue : public Value {
// Subclassed methods
virtual bool GetAsBoolean(bool* out_value) const;
virtual bool GetAsInteger(int* out_value) const;
- virtual bool GetAsReal(double* out_value) const;
- virtual Value* DeepCopy() const;
+ virtual bool GetAsDouble(double* out_value) const;
+ virtual FundamentalValue* DeepCopy() const;
virtual bool Equals(const Value* other) const;
private:
union {
bool boolean_value_;
int integer_value_;
- double real_value_;
+ double double_value_;
};
DISALLOW_COPY_AND_ASSIGN(FundamentalValue);
@@ -156,7 +159,7 @@ class StringValue : public Value {
// Subclassed methods
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
- virtual Value* DeepCopy() const;
+ virtual StringValue* DeepCopy() const;
virtual bool Equals(const Value* other) const;
private:
@@ -185,7 +188,7 @@ class BinaryValue: public Value {
const char* GetBuffer() const { return buffer_; }
// Overridden from Value:
- virtual Value* DeepCopy() const;
+ virtual BinaryValue* DeepCopy() const;
virtual bool Equals(const Value* other) const;
private:
@@ -234,7 +237,7 @@ class DictionaryValue : public Value {
// value at that path, even if it has a different type.
void SetBoolean(const std::string& path, bool in_value);
void SetInteger(const std::string& path, int in_value);
- void SetReal(const std::string& path, double in_value);
+ void SetDouble(const std::string& path, double in_value);
void SetString(const std::string& path, const std::string& in_value);
void SetString(const std::string& path, const string16& in_value);
@@ -256,7 +259,7 @@ class DictionaryValue : public Value {
// the end of the path can be returned in the form specified.
bool GetBoolean(const std::string& path, bool* out_value) const;
bool GetInteger(const std::string& path, int* out_value) const;
- bool GetReal(const std::string& path, double* out_value) const;
+ bool GetDouble(const std::string& path, double* out_value) const;
bool GetString(const std::string& path, std::string* out_value) const;
bool GetString(const std::string& path, string16* out_value) const;
bool GetStringASCII(const std::string& path, std::string* out_value) const;
@@ -271,7 +274,7 @@ class DictionaryValue : public Value {
Value** out_value) const;
bool GetIntegerWithoutPathExpansion(const std::string& key,
int* out_value) const;
- bool GetRealWithoutPathExpansion(const std::string& key,
+ bool GetDoubleWithoutPathExpansion(const std::string& key,
double* out_value) const;
bool GetStringWithoutPathExpansion(const std::string& key,
std::string* out_value) const;
@@ -330,7 +333,7 @@ class DictionaryValue : public Value {
key_iterator end_keys() const { return key_iterator(dictionary_.end()); }
// Overridden from Value:
- virtual Value* DeepCopy() const;
+ virtual DictionaryValue* DeepCopy() const;
virtual bool Equals(const Value* other) const;
private:
@@ -374,7 +377,7 @@ class ListValue : public Value {
// in the specified form.
bool GetBoolean(size_t index, bool* out_value) const;
bool GetInteger(size_t index, int* out_value) const;
- bool GetReal(size_t index, double* out_value) const;
+ bool GetDouble(size_t index, double* out_value) const;
bool GetString(size_t index, std::string* out_value) const;
bool GetString(size_t index, string16* out_value) const;
bool GetBinary(size_t index, BinaryValue** out_value) const;
@@ -417,7 +420,7 @@ class ListValue : public Value {
// Overridden from Value:
virtual bool GetAsList(ListValue** out_value);
- virtual Value* DeepCopy() const;
+ virtual ListValue* DeepCopy() const;
virtual bool Equals(const Value* other) const;
private:
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index adcd07e..5f901b5 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -60,7 +60,7 @@ TEST_F(ValuesTest, List) {
scoped_ptr<ListValue> mixed_list(new ListValue());
mixed_list->Set(0, Value::CreateBooleanValue(true));
mixed_list->Set(1, Value::CreateIntegerValue(42));
- mixed_list->Set(2, Value::CreateRealValue(88.8));
+ mixed_list->Set(2, Value::CreateDoubleValue(88.8));
mixed_list->Set(3, Value::CreateStringValue("foo"));
ASSERT_EQ(4u, mixed_list->GetSize());
@@ -74,7 +74,7 @@ TEST_F(ValuesTest, List) {
ASSERT_FALSE(mixed_list->GetInteger(0, &int_value));
ASSERT_EQ(0, int_value);
- ASSERT_FALSE(mixed_list->GetReal(1, &double_value));
+ ASSERT_FALSE(mixed_list->GetDouble(1, &double_value));
ASSERT_EQ(0.0, double_value);
ASSERT_FALSE(mixed_list->GetString(2, &string_value));
ASSERT_EQ("", string_value);
@@ -85,7 +85,7 @@ TEST_F(ValuesTest, List) {
ASSERT_TRUE(bool_value);
ASSERT_TRUE(mixed_list->GetInteger(1, &int_value));
ASSERT_EQ(42, int_value);
- ASSERT_TRUE(mixed_list->GetReal(2, &double_value));
+ ASSERT_TRUE(mixed_list->GetDouble(2, &double_value));
ASSERT_EQ(88.8, double_value);
ASSERT_TRUE(mixed_list->GetString(3, &string_value));
ASSERT_EQ("foo", string_value);
@@ -323,15 +323,16 @@ TEST_F(ValuesTest, DeepCopy) {
DictionaryValue original_dict;
Value* original_null = Value::CreateNullValue();
original_dict.Set("null", original_null);
- Value* original_bool = Value::CreateBooleanValue(true);
+ FundamentalValue* original_bool = Value::CreateBooleanValue(true);
original_dict.Set("bool", original_bool);
- Value* original_int = Value::CreateIntegerValue(42);
+ FundamentalValue* original_int = Value::CreateIntegerValue(42);
original_dict.Set("int", original_int);
- Value* original_real = Value::CreateRealValue(3.14);
- original_dict.Set("real", original_real);
- Value* original_string = Value::CreateStringValue("hello");
+ FundamentalValue* original_double = Value::CreateDoubleValue(3.14);
+ original_dict.Set("double", original_double);
+ StringValue* original_string = Value::CreateStringValue("hello");
original_dict.Set("string", original_string);
- Value* original_string16 = Value::CreateStringValue(ASCIIToUTF16("hello16"));
+ StringValue* original_string16 =
+ Value::CreateStringValue(ASCIIToUTF16("hello16"));
original_dict.Set("string16", original_string16);
char* original_buffer = new char[42];
@@ -340,14 +341,13 @@ TEST_F(ValuesTest, DeepCopy) {
original_dict.Set("binary", original_binary);
ListValue* original_list = new ListValue();
- Value* original_list_element_0 = Value::CreateIntegerValue(0);
+ FundamentalValue* original_list_element_0 = Value::CreateIntegerValue(0);
original_list->Append(original_list_element_0);
- Value* original_list_element_1 = Value::CreateIntegerValue(1);
+ FundamentalValue* original_list_element_1 = Value::CreateIntegerValue(1);
original_list->Append(original_list_element_1);
original_dict.Set("list", original_list);
- scoped_ptr<DictionaryValue> copy_dict(
- static_cast<DictionaryValue*>(original_dict.DeepCopy()));
+ scoped_ptr<DictionaryValue> copy_dict(original_dict.DeepCopy());
ASSERT_TRUE(copy_dict.get());
ASSERT_NE(copy_dict.get(), &original_dict);
@@ -375,14 +375,14 @@ TEST_F(ValuesTest, DeepCopy) {
ASSERT_TRUE(copy_int->GetAsInteger(&copy_int_value));
ASSERT_EQ(42, copy_int_value);
- Value* copy_real = NULL;
- ASSERT_TRUE(copy_dict->Get("real", &copy_real));
- ASSERT_TRUE(copy_real);
- ASSERT_NE(copy_real, original_real);
- ASSERT_TRUE(copy_real->IsType(Value::TYPE_REAL));
- double copy_real_value = 0;
- ASSERT_TRUE(copy_real->GetAsReal(&copy_real_value));
- ASSERT_EQ(3.14, copy_real_value);
+ Value* copy_double = NULL;
+ ASSERT_TRUE(copy_dict->Get("double", &copy_double));
+ ASSERT_TRUE(copy_double);
+ ASSERT_NE(copy_double, original_double);
+ ASSERT_TRUE(copy_double->IsType(Value::TYPE_DOUBLE));
+ double copy_double_value = 0;
+ ASSERT_TRUE(copy_double->GetAsDouble(&copy_double_value));
+ ASSERT_EQ(3.14, copy_double_value);
Value* copy_string = NULL;
ASSERT_TRUE(copy_dict->Get("string", &copy_string));
@@ -459,13 +459,13 @@ TEST_F(ValuesTest, Equals) {
DictionaryValue dv;
dv.SetBoolean("a", false);
dv.SetInteger("b", 2);
- dv.SetReal("c", 2.5);
+ dv.SetDouble("c", 2.5);
dv.SetString("d1", "string");
dv.SetString("d2", ASCIIToUTF16("http://google.com"));
dv.Set("e", Value::CreateNullValue());
scoped_ptr<DictionaryValue> copy;
- copy.reset(static_cast<DictionaryValue*>(dv.DeepCopy()));
+ copy.reset(dv.DeepCopy());
EXPECT_TRUE(dv.Equals(copy.get()));
ListValue* list = new ListValue;
@@ -481,7 +481,7 @@ TEST_F(ValuesTest, Equals) {
EXPECT_FALSE(dv.Equals(copy.get()));
// Check if Equals detects differences in only the keys.
- copy.reset(static_cast<DictionaryValue*>(dv.DeepCopy()));
+ copy.reset(dv.DeepCopy());
EXPECT_TRUE(dv.Equals(copy.get()));
copy->Remove("a", NULL);
copy->SetBoolean("aa", false);
@@ -511,6 +511,62 @@ TEST_F(ValuesTest, StaticEquals) {
EXPECT_FALSE(Value::Equals(NULL, null1.get()));
}
+TEST_F(ValuesTest, DeepCopyCovariantReturnTypes) {
+ DictionaryValue original_dict;
+ Value* original_null = Value::CreateNullValue();
+ original_dict.Set("null", original_null);
+ FundamentalValue* original_bool = Value::CreateBooleanValue(true);
+ original_dict.Set("bool", original_bool);
+ FundamentalValue* original_int = Value::CreateIntegerValue(42);
+ original_dict.Set("int", original_int);
+ FundamentalValue* original_double = Value::CreateDoubleValue(3.14);
+ original_dict.Set("double", original_double);
+ StringValue* original_string = Value::CreateStringValue("hello");
+ original_dict.Set("string", original_string);
+ StringValue* original_string16 =
+ Value::CreateStringValue(ASCIIToUTF16("hello16"));
+ original_dict.Set("string16", original_string16);
+
+ char* original_buffer = new char[42];
+ memset(original_buffer, '!', 42);
+ BinaryValue* original_binary = Value::CreateBinaryValue(original_buffer, 42);
+ original_dict.Set("binary", original_binary);
+
+ ListValue* original_list = new ListValue();
+ FundamentalValue* original_list_element_0 = Value::CreateIntegerValue(0);
+ original_list->Append(original_list_element_0);
+ FundamentalValue* original_list_element_1 = Value::CreateIntegerValue(1);
+ original_list->Append(original_list_element_1);
+ original_dict.Set("list", original_list);
+
+ Value* original_dict_value = &original_dict;
+ Value* original_bool_value = original_bool;
+ Value* original_int_value = original_int;
+ Value* original_double_value = original_double;
+ Value* original_string_value = original_string;
+ Value* original_string16_value = original_string16;
+ Value* original_binary_value = original_binary;
+ Value* original_list_value = original_list;
+
+ scoped_ptr<Value> copy_dict_value(original_dict_value->DeepCopy());
+ scoped_ptr<Value> copy_bool_value(original_bool_value->DeepCopy());
+ scoped_ptr<Value> copy_int_value(original_int_value->DeepCopy());
+ scoped_ptr<Value> copy_double_value(original_double_value->DeepCopy());
+ scoped_ptr<Value> copy_string_value(original_string_value->DeepCopy());
+ scoped_ptr<Value> copy_string16_value(original_string16_value->DeepCopy());
+ scoped_ptr<Value> copy_binary_value(original_binary_value->DeepCopy());
+ scoped_ptr<Value> copy_list_value(original_list_value->DeepCopy());
+
+ EXPECT_TRUE(original_dict_value->Equals(copy_dict_value.get()));
+ EXPECT_TRUE(original_bool_value->Equals(copy_bool_value.get()));
+ EXPECT_TRUE(original_int_value->Equals(copy_int_value.get()));
+ EXPECT_TRUE(original_double_value->Equals(copy_double_value.get()));
+ EXPECT_TRUE(original_string_value->Equals(copy_string_value.get()));
+ EXPECT_TRUE(original_string16_value->Equals(copy_string16_value.get()));
+ EXPECT_TRUE(original_binary_value->Equals(copy_binary_value.get()));
+ EXPECT_TRUE(original_list_value->Equals(copy_list_value.get()));
+}
+
TEST_F(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<DictionaryValue> root(new DictionaryValue);
// Remove empty lists and dictionaries.
diff --git a/base/values_util.cc b/base/values_util.cc
deleted file mode 100644
index fbc616b..0000000
--- a/base/values_util.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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/values_util.h"
-
-RefCountedList::RefCountedList(ListValue* list) {
- list_ = list;
-}
-
-RefCountedList::~RefCountedList() {
- if (list_)
- delete list_;
-}
-
-ListValue* RefCountedList::Get() {
- return list_;
-}
diff --git a/base/values_util.h b/base/values_util.h
deleted file mode 100644
index 1626bb5..0000000
--- a/base/values_util.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-#ifndef BASE_VALUES_UTIL_H_
-#define BASE_VALUES_UTIL_H_
-#pragma once
-
-#include "base/values.h"
-#include "base/ref_counted.h"
-
-class RefCountedList : public base::RefCountedThreadSafe<RefCountedList> {
- public:
- // Takes ownership of |list|.
- explicit RefCountedList(ListValue* list);
- virtual ~RefCountedList();
-
- virtual ListValue* Get();
-
- private:
- ListValue* list_;
-
- DISALLOW_COPY_AND_ASSIGN(RefCountedList);
-};
-
-#endif // BASE_VALUES_UTIL_H_
diff --git a/base/vlog.cc b/base/vlog.cc
index 8903f39..41bf2a5 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -13,6 +13,18 @@ namespace logging {
const int VlogInfo::kDefaultVlogLevel = 0;
+struct VlogInfo::VmodulePattern {
+ enum MatchTarget { MATCH_MODULE, MATCH_FILE };
+
+ explicit VmodulePattern(const std::string& pattern);
+
+ VmodulePattern();
+
+ std::string pattern;
+ int vlog_level;
+ MatchTarget match_target;
+};
+
VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern)
: pattern(pattern),
vlog_level(VlogInfo::kDefaultVlogLevel),
@@ -64,15 +76,6 @@ VlogInfo::VlogInfo(const std::string& v_switch,
VlogInfo::~VlogInfo() {}
-void VlogInfo::SetMaxVlogLevel(int level) {
- // Log severity is the negative verbosity.
- *min_log_level_ = -level;
-}
-
-int VlogInfo::GetMaxVlogLevel() const {
- return -*min_log_level_;
-}
-
namespace {
// Given a path, returns the basename with the extension chopped off
@@ -109,6 +112,15 @@ int VlogInfo::GetVlogLevel(const base::StringPiece& file) const {
return GetMaxVlogLevel();
}
+void VlogInfo::SetMaxVlogLevel(int level) {
+ // Log severity is the negative verbosity.
+ *min_log_level_ = -level;
+}
+
+int VlogInfo::GetMaxVlogLevel() const {
+ return -*min_log_level_;
+}
+
bool MatchVlogPattern(const base::StringPiece& string,
const base::StringPiece& vlog_pattern) {
base::StringPiece p(vlog_pattern);
diff --git a/base/vlog.h b/base/vlog.h
index 529afd5..54e777f 100644
--- a/base/vlog.h
+++ b/base/vlog.h
@@ -18,6 +18,8 @@ namespace logging {
// A helper class containing all the settings for vlogging.
class VlogInfo {
public:
+ static const int kDefaultVlogLevel;
+
// |v_switch| gives the default maximal active V-logging level; 0 is
// the default. Normally positive values are used for V-logging
// levels.
@@ -45,26 +47,13 @@ class VlogInfo {
// __FILE__).
int GetVlogLevel(const base::StringPiece& file) const;
- static const int kDefaultVlogLevel;
-
private:
void SetMaxVlogLevel(int level);
int GetMaxVlogLevel() const;
// VmodulePattern holds all the information for each pattern parsed
// from |vmodule_switch|.
- struct VmodulePattern {
- enum MatchTarget { MATCH_MODULE, MATCH_FILE };
-
- explicit VmodulePattern(const std::string& pattern);
-
- VmodulePattern();
-
- std::string pattern;
- int vlog_level;
- MatchTarget match_target;
- };
-
+ struct VmodulePattern;
std::vector<VmodulePattern> vmodule_levels_;
int* min_log_level_;
diff --git a/base/weak_ptr.cc b/base/weak_ptr.cc
index 6473b4a..86c89c1 100644
--- a/base/weak_ptr.cc
+++ b/base/weak_ptr.cc
@@ -61,10 +61,10 @@ void WeakReferenceOwner::Invalidate() {
WeakPtrBase::WeakPtrBase() {
}
-WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {
+WeakPtrBase::~WeakPtrBase() {
}
-WeakPtrBase::~WeakPtrBase() {
+WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {
}
} // namespace internal
diff --git a/base/win/registry.cc b/base/win/registry.cc
index dbb8d7a..d105a4c 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -14,136 +14,7 @@
namespace base {
namespace win {
-RegistryValueIterator::RegistryValueIterator(HKEY root_key,
- const wchar_t* folder_key) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
- if (result != ERROR_SUCCESS) {
- key_ = NULL;
- } else {
- DWORD count = 0;
- result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
- NULL, NULL, NULL, NULL);
-
- if (result != ERROR_SUCCESS) {
- ::RegCloseKey(key_);
- key_ = NULL;
- } else {
- index_ = count - 1;
- }
- }
-
- Read();
-}
-
-RegistryValueIterator::~RegistryValueIterator() {
- base::ThreadRestrictions::AssertIOAllowed();
- if (key_)
- ::RegCloseKey(key_);
-}
-
-bool RegistryValueIterator::Valid() const {
- return key_ != NULL && index_ >= 0;
-}
-
-void RegistryValueIterator::operator++() {
- --index_;
- Read();
-}
-
-bool RegistryValueIterator::Read() {
- base::ThreadRestrictions::AssertIOAllowed();
- if (Valid()) {
- DWORD ncount = arraysize(name_);
- value_size_ = sizeof(value_);
- LRESULT r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
- reinterpret_cast<BYTE*>(value_), &value_size_);
- if (ERROR_SUCCESS == r)
- return true;
- }
-
- name_[0] = '\0';
- value_[0] = '\0';
- value_size_ = 0;
- return false;
-}
-
-DWORD RegistryValueIterator::ValueCount() const {
- base::ThreadRestrictions::AssertIOAllowed();
- DWORD count = 0;
- HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
- &count, NULL, NULL, NULL, NULL);
-
- if (result != ERROR_SUCCESS)
- return 0;
-
- return count;
-}
-
-RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
- const wchar_t* folder_key) {
- base::ThreadRestrictions::AssertIOAllowed();
- LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
- if (result != ERROR_SUCCESS) {
- key_ = NULL;
- } else {
- DWORD count = 0;
- HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL);
-
- if (result != ERROR_SUCCESS) {
- ::RegCloseKey(key_);
- key_ = NULL;
- } else {
- index_ = count - 1;
- }
- }
-
- Read();
-}
-
-RegistryKeyIterator::~RegistryKeyIterator() {
- base::ThreadRestrictions::AssertIOAllowed();
- if (key_)
- ::RegCloseKey(key_);
-}
-
-bool RegistryKeyIterator::Valid() const {
- return key_ != NULL && index_ >= 0;
-}
-
-void RegistryKeyIterator::operator++() {
- --index_;
- Read();
-}
-
-bool RegistryKeyIterator::Read() {
- base::ThreadRestrictions::AssertIOAllowed();
- if (Valid()) {
- DWORD ncount = arraysize(name_);
- FILETIME written;
- LRESULT r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
- NULL, &written);
- if (ERROR_SUCCESS == r)
- return true;
- }
-
- name_[0] = '\0';
- return false;
-}
-
-DWORD RegistryKeyIterator::SubkeyCount() const {
- base::ThreadRestrictions::AssertIOAllowed();
- DWORD count = 0;
- HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL);
-
- if (result != ERROR_SUCCESS)
- return 0;
-
- return count;
-}
+// RegKey ----------------------------------------------------------------------
RegKey::RegKey()
: key_(NULL),
@@ -168,57 +39,33 @@ RegKey::~RegKey() {
Close();
}
-void RegKey::Close() {
- base::ThreadRestrictions::AssertIOAllowed();
- StopWatching();
- if (key_) {
- ::RegCloseKey(key_);
- key_ = NULL;
- }
-}
-
-bool RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DWORD disposition_value;
return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}
-bool RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(rootkey && subkey && access && disposition);
Close();
- LONG result = RegCreateKeyEx(rootkey,
- subkey,
- 0,
- NULL,
- REG_OPTION_NON_VOLATILE,
- access,
- NULL,
- &key_,
+ LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
+ REG_OPTION_NON_VOLATILE, access, NULL, &key_,
disposition);
- if (result != ERROR_SUCCESS) {
- key_ = NULL;
- return false;
- }
-
- return true;
+ return result;
}
-bool RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(rootkey && subkey && access);
Close();
LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
- if (result != ERROR_SUCCESS) {
- key_ = NULL;
- return false;
- }
- return true;
+ return result;
}
-bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
+LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(name && access);
@@ -228,10 +75,10 @@ bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
Close();
key_ = subkey;
- return (result == ERROR_SUCCESS);
+ return result;
}
-bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
+LONG RegKey::OpenKey(const wchar_t* name, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(name && access);
@@ -241,56 +88,76 @@ bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
Close();
key_ = subkey;
- return (result == ERROR_SUCCESS);
+ return result;
+}
+
+void RegKey::Close() {
+ base::ThreadRestrictions::AssertIOAllowed();
+ StopWatching();
+ if (key_) {
+ ::RegCloseKey(key_);
+ key_ = NULL;
+ }
}
DWORD RegKey::ValueCount() const {
base::ThreadRestrictions::AssertIOAllowed();
DWORD count = 0;
- HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
- NULL, &count, NULL, NULL, NULL, NULL);
+ LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+ NULL, NULL, NULL, NULL);
return (result != ERROR_SUCCESS) ? 0 : count;
}
-bool RegKey::ReadName(int index, std::wstring* name) const {
+LONG RegKey::ReadName(int index, std::wstring* name) const {
base::ThreadRestrictions::AssertIOAllowed();
wchar_t buf[256];
DWORD bufsize = arraysize(buf);
- LRESULT r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL,
- NULL, NULL);
- if (r != ERROR_SUCCESS)
- return false;
- if (name)
+ LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
+ if (r == ERROR_SUCCESS)
*name = buf;
- return true;
+
+ return r;
+}
+
+LONG RegKey::DeleteKey(const wchar_t* name) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DCHECK(key_);
+ DCHECK(name);
+ LONG result = SHDeleteKey(key_, name);
+ return result;
+}
+
+LONG RegKey::DeleteValue(const wchar_t* value_name) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DCHECK(key_);
+ DCHECK(value_name);
+ LONG result = RegDeleteValue(key_, value_name);
+ return result;
}
-bool RegKey::ValueExists(const wchar_t* name) {
+bool RegKey::ValueExists(const wchar_t* name) const {
base::ThreadRestrictions::AssertIOAllowed();
- if (!key_)
- return false;
- HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
- return (result == ERROR_SUCCESS);
+ LONG result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
+ return result == ERROR_SUCCESS;
}
-bool RegKey::ReadValue(const wchar_t* name, void* data,
- DWORD* dsize, DWORD* dtype) const {
+LONG RegKey::ReadValue(const wchar_t* name, void* data, DWORD* dsize,
+ DWORD* dtype) const {
base::ThreadRestrictions::AssertIOAllowed();
- if (!key_)
- return false;
- HRESULT result = RegQueryValueEx(key_, name, 0, dtype,
- reinterpret_cast<LPBYTE>(data), dsize);
- return (result == ERROR_SUCCESS);
+ LONG result = RegQueryValueEx(key_, name, 0, dtype,
+ reinterpret_cast<LPBYTE>(data), dsize);
+ return result;
}
-bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
+LONG RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(value);
const size_t kMaxStringLength = 1024; // This is after expansion.
// Use the one of the other forms of ReadValue if 1024 is too small for you.
wchar_t raw_value[kMaxStringLength];
DWORD type = REG_SZ, size = sizeof(raw_value);
- if (ReadValue(name, raw_value, &size, &type)) {
+ LONG result = ReadValue(name, raw_value, &size, &type);
+ if (result == ERROR_SUCCESS) {
if (type == REG_SZ) {
*value = raw_value;
} else if (type == REG_EXPAND_SZ) {
@@ -299,80 +166,76 @@ bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
// Success: returns the number of wchar_t's copied
// Fail: buffer too small, returns the size required
// Fail: other, returns 0
- if (size == 0 || size > kMaxStringLength)
- return false;
- *value = expanded;
+ if (size == 0 || size > kMaxStringLength) {
+ result = ERROR_MORE_DATA;
+ } else {
+ *value = expanded;
+ }
} else {
// Not a string. Oops.
- return false;
+ result = ERROR_CANTREAD;
}
- return true;
}
- return false;
+ return result;
}
-bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const {
+LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const {
DCHECK(value);
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
- DWORD result = 0;
- if (ReadValue(name, &result, &size, &type) &&
- (type == REG_DWORD || type == REG_BINARY) &&
- size == sizeof(DWORD)) {
- *value = result;
- return true;
+ DWORD local_value = 0;
+ LONG result = ReadValue(name, &local_value, &size, &type);
+ if (result == ERROR_SUCCESS) {
+ if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) {
+ *value = local_value;
+ } else {
+ result = ERROR_CANTREAD;
+ }
}
- return false;
+ return result;
}
-bool RegKey::WriteValue(const wchar_t* name, const void * data,
+LONG RegKey::ReadInt64(const wchar_t* name, int64* value) const {
+ DCHECK(value);
+ DWORD type = REG_QWORD;
+ int64 local_value = 0;
+ DWORD size = sizeof(local_value);
+ LONG result = ReadValue(name, &local_value, &size, &type);
+ if (result == ERROR_SUCCESS) {
+ if ((type == REG_QWORD || type == REG_BINARY) &&
+ size == sizeof(local_value)) {
+ *value = local_value;
+ } else {
+ result = ERROR_CANTREAD;
+ }
+ }
+
+ return result;
+}
+
+LONG RegKey::WriteValue(const wchar_t* name, const void * data,
DWORD dsize, DWORD dtype) {
base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(data);
-
- if (!key_)
- return false;
+ DCHECK(data || !dsize);
- HRESULT result = RegSetValueEx(
- key_,
- name,
- 0,
- dtype,
- reinterpret_cast<LPBYTE>(const_cast<void*>(data)),
- dsize);
- return (result == ERROR_SUCCESS);
+ LONG result = RegSetValueEx(key_, name, 0, dtype,
+ reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
+ return result;
}
-bool RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
+LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
return WriteValue(name, value,
static_cast<DWORD>(sizeof(*value) * (wcslen(value) + 1)), REG_SZ);
}
-bool RegKey::WriteValue(const wchar_t* name, DWORD value) {
- return WriteValue(name, &value,
- static_cast<DWORD>(sizeof(value)), REG_DWORD);
-}
-
-bool RegKey::DeleteKey(const wchar_t* name) {
- base::ThreadRestrictions::AssertIOAllowed();
- if (!key_)
- return false;
- LSTATUS ret = SHDeleteKey(key_, name);
- if (ERROR_SUCCESS != ret)
- SetLastError(ret);
- return ERROR_SUCCESS == ret;
-}
-
-bool RegKey::DeleteValue(const wchar_t* value_name) {
- base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(value_name);
- HRESULT result = RegDeleteValue(key_, value_name);
- return (result == ERROR_SUCCESS);
+LONG RegKey::WriteValue(const wchar_t* name, DWORD value) {
+ return WriteValue(name, &value, static_cast<DWORD>(sizeof(value)), REG_DWORD);
}
-bool RegKey::StartWatching() {
+LONG RegKey::StartWatching() {
+ DCHECK(key_);
if (!watch_event_)
watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -382,33 +245,165 @@ bool RegKey::StartWatching() {
REG_NOTIFY_CHANGE_SECURITY;
// Watch the registry key for a change of value.
- HRESULT result = RegNotifyChangeKeyValue(key_, TRUE, filter,
- watch_event_, TRUE);
- if (SUCCEEDED(result)) {
- return true;
- } else {
+ LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
+ if (result != ERROR_SUCCESS) {
CloseHandle(watch_event_);
watch_event_ = 0;
- return false;
}
+
+ return result;
}
-bool RegKey::StopWatching() {
+bool RegKey::HasChanged() {
if (watch_event_) {
- CloseHandle(watch_event_);
- watch_event_ = 0;
- return true;
+ if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
+ StartWatching();
+ return true;
+ }
}
return false;
}
-bool RegKey::HasChanged() {
+LONG RegKey::StopWatching() {
+ LONG result = ERROR_INVALID_HANDLE;
if (watch_event_) {
- if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
- StartWatching();
+ CloseHandle(watch_event_);
+ watch_event_ = 0;
+ result = ERROR_SUCCESS;
+ }
+ return result;
+}
+
+// RegistryValueIterator ------------------------------------------------------
+
+RegistryValueIterator::RegistryValueIterator(HKEY root_key,
+ const wchar_t* folder_key) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
+ if (result != ERROR_SUCCESS) {
+ key_ = NULL;
+ } else {
+ DWORD count = 0;
+ result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+ NULL, NULL, NULL, NULL);
+
+ if (result != ERROR_SUCCESS) {
+ ::RegCloseKey(key_);
+ key_ = NULL;
+ } else {
+ index_ = count - 1;
+ }
+ }
+
+ Read();
+}
+
+RegistryValueIterator::~RegistryValueIterator() {
+ base::ThreadRestrictions::AssertIOAllowed();
+ if (key_)
+ ::RegCloseKey(key_);
+}
+
+DWORD RegistryValueIterator::ValueCount() const {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DWORD count = 0;
+ LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
+ &count, NULL, NULL, NULL, NULL);
+ if (result != ERROR_SUCCESS)
+ return 0;
+
+ return count;
+}
+
+bool RegistryValueIterator::Valid() const {
+ return key_ != NULL && index_ >= 0;
+}
+
+void RegistryValueIterator::operator++() {
+ --index_;
+ Read();
+}
+
+bool RegistryValueIterator::Read() {
+ base::ThreadRestrictions::AssertIOAllowed();
+ if (Valid()) {
+ DWORD ncount = arraysize(name_);
+ value_size_ = sizeof(value_);
+ LONG r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
+ reinterpret_cast<BYTE*>(value_), &value_size_);
+ if (ERROR_SUCCESS == r)
return true;
+ }
+
+ name_[0] = '\0';
+ value_[0] = '\0';
+ value_size_ = 0;
+ return false;
+}
+
+// RegistryKeyIterator --------------------------------------------------------
+
+RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
+ const wchar_t* folder_key) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
+ if (result != ERROR_SUCCESS) {
+ key_ = NULL;
+ } else {
+ DWORD count = 0;
+ LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+
+ if (result != ERROR_SUCCESS) {
+ ::RegCloseKey(key_);
+ key_ = NULL;
+ } else {
+ index_ = count - 1;
}
}
+
+ Read();
+}
+
+RegistryKeyIterator::~RegistryKeyIterator() {
+ base::ThreadRestrictions::AssertIOAllowed();
+ if (key_)
+ ::RegCloseKey(key_);
+}
+
+DWORD RegistryKeyIterator::SubkeyCount() const {
+ base::ThreadRestrictions::AssertIOAllowed();
+ DWORD count = 0;
+ LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ if (result != ERROR_SUCCESS)
+ return 0;
+
+ return count;
+}
+
+bool RegistryKeyIterator::Valid() const {
+ return key_ != NULL && index_ >= 0;
+}
+
+void RegistryKeyIterator::operator++() {
+ --index_;
+ Read();
+}
+
+bool RegistryKeyIterator::Read() {
+ base::ThreadRestrictions::AssertIOAllowed();
+ if (Valid()) {
+ DWORD ncount = arraysize(name_);
+ FILETIME written;
+ LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
+ NULL, &written);
+ if (ERROR_SUCCESS == r)
+ return true;
+ }
+
+ name_[0] = '\0';
return false;
}
diff --git a/base/win/registry.h b/base/win/registry.h
index 96a2bb3..cd5421d 100644
--- a/base/win/registry.h
+++ b/base/win/registry.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -17,57 +17,62 @@ namespace win {
// Utility class to read, write and manipulate the Windows Registry.
// Registry vocabulary primer: a "key" is like a folder, in which there
// are "values", which are <name, data> pairs, with an associated data type.
+//
+// Note:
+// ReadValue family of functions guarantee that the return arguments
+// are not touched in case of failure.
class RegKey {
public:
RegKey();
RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
~RegKey();
- bool Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+ LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
- bool CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+ LONG CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access);
- bool Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+ LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
// Creates a subkey or open it if it already exists.
- bool CreateKey(const wchar_t* name, REGSAM access);
+ LONG CreateKey(const wchar_t* name, REGSAM access);
// Opens a subkey
- bool OpenKey(const wchar_t* name, REGSAM access);
+ LONG OpenKey(const wchar_t* name, REGSAM access);
void Close();
DWORD ValueCount() const;
// Determine the nth value's name.
- bool ReadName(int index, std::wstring* name) const;
+ LONG ReadName(int index, std::wstring* name) const;
// True while the key is valid.
bool Valid() const { return key_ != NULL; }
// Kill a key and everything that live below it; please be careful when using
// it.
- bool DeleteKey(const wchar_t* name);
+ LONG DeleteKey(const wchar_t* name);
// Deletes a single value within the key.
- bool DeleteValue(const wchar_t* name);
+ LONG DeleteValue(const wchar_t* name);
- bool ValueExists(const wchar_t* name);
+ bool ValueExists(const wchar_t* name) const;
- bool ReadValue(const wchar_t* name, void* data, DWORD* dsize,
+ LONG ReadValue(const wchar_t* name, void* data, DWORD* dsize,
DWORD* dtype) const;
- bool ReadValue(const wchar_t* name, std::wstring* value) const;
- bool ReadValueDW(const wchar_t* name, DWORD* value) const;
+ LONG ReadValue(const wchar_t* name, std::wstring* value) const;
+ LONG ReadValueDW(const wchar_t* name, DWORD* value) const;
+ LONG ReadInt64(const wchar_t* name, int64* value) const;
- bool WriteValue(const wchar_t* name, const void* data, DWORD dsize,
+ LONG WriteValue(const wchar_t* name, const void* data, DWORD dsize,
DWORD dtype);
- bool WriteValue(const wchar_t* name, const wchar_t* value);
- bool WriteValue(const wchar_t* name, DWORD value);
+ LONG WriteValue(const wchar_t* name, const wchar_t* value);
+ LONG WriteValue(const wchar_t* name, DWORD value);
// Starts watching the key to see if any of its values have changed.
// The key must have been opened with the KEY_NOTIFY access privilege.
- bool StartWatching();
+ LONG StartWatching();
// If StartWatching hasn't been called, always returns false.
// Otherwise, returns true if anything under the key has changed.
@@ -76,7 +81,7 @@ class RegKey {
// Will automatically be called by destructor if not manually called
// beforehand. Returns true if it was watching, false otherwise.
- bool StopWatching();
+ LONG StopWatching();
inline bool IsWatching() const { return watch_event_ != 0; }
HANDLE watch_event() const { return watch_event_; }
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
index 524612a..a7961e9 100644
--- a/base/win/registry_unittest.cc
+++ b/base/win/registry_unittest.cc
@@ -21,14 +21,14 @@ class RegistryTest : public testing::Test {
// Create a temporary key.
RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
key.DeleteKey(kRootKey);
- ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
- ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+ ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+ ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
}
virtual void TearDown() {
// Clean up the temporary key.
RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
- ASSERT_TRUE(key.DeleteKey(kRootKey));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
}
private:
@@ -40,22 +40,59 @@ TEST_F(RegistryTest, ValueTest) {
std::wstring foo_key(kRootKey);
foo_key += L"\\Foo";
- ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+ ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+ KEY_READ));
{
- ASSERT_TRUE(key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
- KEY_READ | KEY_SET_VALUE));
-
- const wchar_t* kName = L"Bar";
- const wchar_t* kValue = L"bar";
- EXPECT_TRUE(key.WriteValue(kName, kValue));
- EXPECT_TRUE(key.ValueExists(kName));
- std::wstring out_value;
- EXPECT_TRUE(key.ReadValue(kName, &out_value));
- EXPECT_NE(out_value, L"");
- EXPECT_STREQ(out_value.c_str(), kValue);
- EXPECT_EQ(1U, key.ValueCount());
- EXPECT_TRUE(key.DeleteValue(kName));
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+ KEY_READ | KEY_SET_VALUE));
+ ASSERT_TRUE(key.Valid());
+
+ const wchar_t* kStringValueName = L"StringValue";
+ const wchar_t* kDWORDValueName = L"DWORDValue";
+ const wchar_t* kInt64ValueName = L"Int64Value";
+ const wchar_t* kStringData = L"string data";
+ const DWORD kDWORDData = 0xdeadbabe;
+ const int64 kInt64Data = 0xdeadbabedeadbabeLL;
+
+ // Test value creation
+ ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
+ ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData));
+ ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data,
+ sizeof(kInt64Data), REG_QWORD));
+ EXPECT_EQ(3U, key.ValueCount());
+ EXPECT_TRUE(key.ValueExists(kStringValueName));
+ EXPECT_TRUE(key.ValueExists(kDWORDValueName));
+ EXPECT_TRUE(key.ValueExists(kInt64ValueName));
+
+ // Test Read
+ std::wstring string_value;
+ DWORD dword_value = 0;
+ int64 int64_value = 0;
+ ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
+ ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
+ ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
+ EXPECT_STREQ(kStringData, string_value.c_str());
+ EXPECT_EQ(kDWORDData, dword_value);
+ EXPECT_EQ(kInt64Data, int64_value);
+
+ // Make sure out args are not touched if ReadValue fails
+ const wchar_t* kNonExistent = L"NonExistent";
+ ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value));
+ ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value));
+ ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value));
+ EXPECT_STREQ(kStringData, string_value.c_str());
+ EXPECT_EQ(kDWORDData, dword_value);
+ EXPECT_EQ(kInt64Data, int64_value);
+
+ // Test delete
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName));
+ EXPECT_EQ(0U, key.ValueCount());
+ EXPECT_FALSE(key.ValueExists(kStringValueName));
+ EXPECT_FALSE(key.ValueExists(kDWORDValueName));
+ EXPECT_FALSE(key.ValueExists(kInt64ValueName));
}
}
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 87905ea..d3d74a2 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -93,7 +93,7 @@ bool UserAccountControlIsEnabled() {
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
KEY_READ);
DWORD uac_enabled;
- if (!key.ReadValueDW(L"EnableLUA", &uac_enabled))
+ if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
return true;
// Users can set the EnableLUA value to something arbitrary, like 2, which
// Vista will treat as UAC enabled, so we make sure it is not set to 0.
@@ -128,12 +128,13 @@ static const char16 kAutoRunKeyPath[] =
bool AddCommandToAutoRun(HKEY root_key, const string16& name,
const string16& command) {
base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
- return autorun_key.WriteValue(name.c_str(), command.c_str());
+ return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
+ ERROR_SUCCESS);
}
bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
- return autorun_key.DeleteValue(name.c_str());
+ return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
}
} // namespace win