summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp20
-rw-r--r--base/base.gypi109
-rw-r--r--base/base_switches.cc5
-rw-r--r--base/cocoa_protocols_mac.h1
-rw-r--r--base/crypto/encryptor_openssl.cc32
-rw-r--r--base/crypto/rsa_private_key_nss.cc2
-rw-r--r--base/crypto/rsa_private_key_openssl.cc79
-rw-r--r--base/crypto/signature_creator_openssl.cc32
-rw-r--r--base/crypto/signature_verifier_openssl.cc41
-rw-r--r--base/crypto/symmetric_key.h5
-rw-r--r--base/crypto/symmetric_key_openssl.cc43
-rw-r--r--base/data/valgrind/DIRECTORY_MOVED4
-rw-r--r--base/data/valgrind/base_unittests.gtest-drmemory_win32.txt11
-rw-r--r--base/data/valgrind/base_unittests.gtest-tsan.txt10
-rw-r--r--base/data/valgrind/base_unittests.gtest-tsan_mac.txt2
-rw-r--r--base/data/valgrind/base_unittests.gtest-tsan_win32.txt15
-rw-r--r--base/data/valgrind/base_unittests.gtest.txt22
-rw-r--r--base/data/valgrind/base_unittests.gtest_mac.txt9
-rw-r--r--base/data/valgrind/base_unittests.gtest_win32.txt7
-rw-r--r--base/data/valgrind/base_unittests.gtest_wine.txt96
-rw-r--r--base/debug/debugger.cc25
-rw-r--r--base/debug/debugger.h39
-rw-r--r--base/debug/debugger_posix.cc165
-rw-r--r--base/debug/debugger_win.cc112
-rw-r--r--base/debug/leak_annotations.h (renamed from base/leak_annotations.h)8
-rw-r--r--base/debug/leak_tracker.h (renamed from base/leak_tracker.h)12
-rw-r--r--base/debug/leak_tracker_unittest.cc113
-rw-r--r--base/debug/stack_trace.cc21
-rw-r--r--base/debug/stack_trace.h63
-rw-r--r--base/debug/stack_trace_posix.cc (renamed from base/debug_util_posix.cc)153
-rw-r--r--base/debug/stack_trace_unittest.cc (renamed from base/debug_util_unittest.cc)17
-rw-r--r--base/debug/stack_trace_win.cc (renamed from base/debug_util_win.cc)103
-rw-r--r--base/debug/trace_event.cc (renamed from base/trace_event.cc)6
-rw-r--r--base/debug/trace_event.h (renamed from base/trace_event.h)57
-rw-r--r--base/debug/trace_event_win.cc (renamed from base/trace_event_win.cc)32
-rw-r--r--base/debug/trace_event_win.h (renamed from base/trace_event_win.h)47
-rw-r--r--base/debug/trace_event_win_unittest.cc (renamed from base/trace_event_win_unittest.cc)86
-rw-r--r--base/debug_on_start.cc8
-rw-r--r--base/debug_util.cc21
-rw-r--r--base/debug_util.h70
-rw-r--r--base/debug_util_mac.cc1
-rw-r--r--base/file_util_mac.mm2
-rw-r--r--base/file_util_posix.cc35
-rw-r--r--base/file_util_proxy.cc6
-rw-r--r--base/file_util_proxy.h62
-rw-r--r--base/file_util_win.cc70
-rw-r--r--base/file_version_info_win.cc4
-rw-r--r--base/gtk_util.cc49
-rw-r--r--base/gtk_util.h22
-rw-r--r--base/hmac_openssl.cc57
-rw-r--r--base/i18n/icu_string_conversions.cc26
-rw-r--r--base/i18n/icu_string_conversions.h6
-rw-r--r--base/i18n/icu_string_conversions_unittest.cc30
-rw-r--r--base/i18n/rtl.cc49
-rw-r--r--base/i18n/rtl.h14
-rw-r--r--base/leak_tracker_unittest.cc107
-rw-r--r--base/logging.cc69
-rw-r--r--base/logging.h221
-rw-r--r--base/logging_unittest.cc119
-rw-r--r--base/logging_win.cc105
-rw-r--r--base/logging_win.h18
-rw-r--r--base/mac_util.h14
-rw-r--r--base/mac_util.mm14
-rw-r--r--base/message_loop.cc47
-rw-r--r--base/message_loop.h29
-rw-r--r--base/message_loop_proxy.cc2
-rw-r--r--base/message_loop_proxy.h4
-rw-r--r--base/message_loop_proxy_impl.cc4
-rw-r--r--base/message_loop_proxy_impl.h4
-rw-r--r--base/message_loop_proxy_impl_unittest.cc10
-rw-r--r--base/message_loop_unittest.cc14
-rw-r--r--base/message_pump.h6
-rw-r--r--base/message_pump_default.cc7
-rw-r--r--base/message_pump_default.h4
-rw-r--r--base/message_pump_glib.cc40
-rw-r--r--base/message_pump_glib.h17
-rw-r--r--base/message_pump_glib_x.cc117
-rw-r--r--base/message_pump_glib_x.h63
-rw-r--r--base/message_pump_glib_x_dispatch.h28
-rw-r--r--base/message_pump_libevent.cc7
-rw-r--r--base/message_pump_libevent.h4
-rw-r--r--base/message_pump_mac.h4
-rw-r--r--base/message_pump_mac.mm16
-rw-r--r--base/message_pump_win.cc7
-rw-r--r--base/message_pump_win.h6
-rw-r--r--base/metrics/field_trial_unittest.cc2
-rw-r--r--base/metrics/histogram.cc106
-rw-r--r--base/metrics/histogram.h61
-rw-r--r--base/metrics/histogram_unittest.cc53
-rw-r--r--base/metrics/nacl_histogram.cc23
-rw-r--r--base/metrics/nacl_histogram.h29
-rw-r--r--base/metrics/stats_table.cc2
-rw-r--r--base/move.h55
-rw-r--r--base/nsimage_cache_mac.mm6
-rw-r--r--base/nss_util.cc7
-rw-r--r--base/openssl_util.h53
-rw-r--r--base/path_service_unittest.cc6
-rw-r--r--base/platform_file_posix.cc5
-rw-r--r--base/platform_file_win.cc10
-rw-r--r--base/process_util_linux.cc22
-rw-r--r--base/process_util_mac.mm36
-rw-r--r--base/process_util_posix.cc4
-rw-r--r--base/process_util_win.cc12
-rw-r--r--base/ref_counted.h10
-rw-r--r--base/ref_counted_unittest.cc2
-rw-r--r--base/registry.h39
-rw-r--r--base/scoped_temp_dir.cc20
-rw-r--r--base/scoped_temp_dir.h4
-rw-r--r--base/scoped_temp_dir_unittest.cc14
-rw-r--r--base/sha2_openssl.cc30
-rw-r--r--base/shared_memory.h43
-rw-r--r--base/shared_memory_posix.cc208
-rw-r--r--base/shared_memory_unittest.cc75
-rw-r--r--base/shared_memory_win.cc59
-rw-r--r--base/singleton.h1
-rw-r--r--base/string_number_conversions.cc2
-rw-r--r--base/string_number_conversions_unittest.cc7
-rw-r--r--base/string_util.cc6
-rw-r--r--base/string_util.h49
-rw-r--r--base/stringprintf.h2
-rw-r--r--base/sys_info_chromeos.cc19
-rw-r--r--base/task.h8
-rw-r--r--base/test/perf_test_suite.cc4
-rw-r--r--base/test/test_suite.cc4
-rw-r--r--base/thread_restrictions.cc4
-rw-r--r--base/thread_restrictions.h42
-rw-r--r--base/tracked.cc8
-rw-r--r--base/tracked.h1
-rw-r--r--base/tracked_objects.cc2
-rw-r--r--base/tracked_objects.h27
-rw-r--r--base/vlog.cc151
-rw-r--r--base/vlog.h47
-rw-r--r--base/vlog_unittest.cc152
-rw-r--r--base/waitable_event_watcher_unittest.cc8
-rw-r--r--base/win/event_trace_consumer.h (renamed from base/event_trace_consumer_win.h)12
-rw-r--r--base/win/event_trace_consumer_unittest.cc (renamed from base/event_trace_consumer_win_unittest.cc)12
-rw-r--r--base/win/event_trace_controller.cc (renamed from base/event_trace_controller_win.cc)8
-rw-r--r--base/win/event_trace_controller.h (renamed from base/event_trace_controller_win.h)12
-rw-r--r--base/win/event_trace_controller_unittest.cc (renamed from base/event_trace_controller_win_unittest.cc)8
-rw-r--r--base/win/event_trace_provider.cc (renamed from base/event_trace_provider_win.cc)8
-rw-r--r--base/win/event_trace_provider.h (renamed from base/event_trace_provider_win.h)12
-rw-r--r--base/win/event_trace_provider_unittest.cc (renamed from base/event_trace_provider_win_unittest.cc)5
-rw-r--r--base/win/registry.cc24
-rw-r--r--base/win_util.cc6
-rw-r--r--base/win_util.h32
-rw-r--r--base/worker_pool_linux.cc18
-rw-r--r--base/worker_pool_linux.h14
-rw-r--r--base/worker_pool_mac.h6
-rw-r--r--base/worker_pool_mac.mm19
149 files changed, 3316 insertions, 1663 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 8e0b1e9..6ae1a95 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -75,12 +75,11 @@
'crypto/signature_verifier_unittest.cc',
'crypto/symmetric_key_unittest.cc',
'data_pack_unittest.cc',
- 'debug_util_unittest.cc',
+ 'debug/leak_tracker_unittest.cc',
+ 'debug/stack_trace_unittest.cc',
+ 'debug/trace_event_win_unittest.cc',
'dir_reader_posix_unittest.cc',
'environment_unittest.cc',
- 'event_trace_consumer_win_unittest.cc',
- 'event_trace_controller_win_unittest.cc',
- 'event_trace_provider_win_unittest.cc',
'file_descriptor_shuffle_unittest.cc',
'file_path_unittest.cc',
'file_util_unittest.cc',
@@ -97,7 +96,6 @@
'json/json_writer_unittest.cc',
'json/string_escape_unittest.cc',
'lazy_instance_unittest.cc',
- 'leak_tracker_unittest.cc',
'linked_list_unittest.cc',
'linked_ptr_unittest.cc',
'lock_unittest.cc',
@@ -150,7 +148,6 @@
'time_win_unittest.cc',
'timer_unittest.cc',
'tools_sanity_unittest.cc',
- 'trace_event_win_unittest.cc',
'tracked_objects_unittest.cc',
'tuple_unittest.cc',
'utf_offset_string_conversions_unittest.cc',
@@ -163,6 +160,9 @@
'watchdog_unittest.cc',
'weak_ptr_unittest.cc',
'win_util_unittest.cc',
+ 'win/event_trace_consumer_unittest.cc',
+ 'win/event_trace_controller_unittest.cc',
+ 'win/event_trace_provider_unittest.cc',
'win/pe_image_unittest.cc',
'win/registry_unittest.cc',
'win/scoped_bstr_unittest.cc',
@@ -225,9 +225,6 @@
['exclude', '^win/'],
],
'sources!': [
- 'event_trace_consumer_win_unittest.cc',
- 'event_trace_controller_win_unittest.cc',
- 'event_trace_provider_win_unittest.cc',
'object_watcher_unittest.cc',
'system_monitor_unittest.cc',
'time_win_unittest.cc',
@@ -235,6 +232,11 @@
'win_util_unittest.cc',
],
}],
+ [ 'use_openssl==1', {
+ 'sources!': [
+ 'crypto/rsa_private_key_nss_unittest.cc',
+ ],
+ }],
],
},
{
diff --git a/base/base.gypi b/base/base.gypi
index 7280eb8..78c97aa 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -58,18 +58,24 @@
'debug_util.cc',
'debug_util.h',
'debug_util_mac.cc',
- 'debug_util_posix.cc',
- 'debug_util_win.cc',
+ 'debug/debugger.cc',
+ 'debug/debugger.h',
+ 'debug/debugger_posix.cc',
+ 'debug/debugger_win.cc',
+ 'debug/leak_annotations.h',
+ 'debug/leak_tracker.h',
+ 'debug/stack_trace.cc',
+ 'debug/stack_trace.h',
+ 'debug/stack_trace_posix.cc',
+ 'debug/stack_trace_win.cc',
+ 'debug/trace_event_win.cc',
+ 'debug/trace_event.cc',
+ 'debug/trace_event.h',
'dir_reader_fallback.h',
'dir_reader_linux.h',
'dir_reader_posix.h',
'environment.cc',
'environment.h',
- 'event_trace_consumer_win.h',
- 'event_trace_controller_win.cc',
- 'event_trace_controller_win.h',
- 'event_trace_provider_win.cc',
- 'event_trace_provider_win.h',
'file_path.cc',
'file_path.h',
'file_util.cc',
@@ -92,8 +98,6 @@
'global_descriptors_posix.cc',
'global_descriptors_posix.h',
'gtest_prod_util.h',
- 'gtk_util.cc',
- 'gtk_util.h',
'hash_tables.h',
'id_map.h',
'json/json_reader.cc',
@@ -104,8 +108,6 @@
'json/string_escape.h',
'lazy_instance.cc',
'lazy_instance.h',
- 'leak_annotations.h',
- 'leak_tracker.h',
'linked_list.h',
'linked_ptr.h',
'lock.cc',
@@ -139,13 +141,14 @@
'message_pump_win.h',
'metrics/histogram.cc',
'metrics/histogram.h',
+ 'metrics/nacl_histogram.cc',
+ 'metrics/nacl_histogram.h',
'metrics/stats_counters.cc',
'metrics/stats_counters.h',
'metrics/stats_table.cc',
'metrics/stats_table.h',
'mime_util.h',
'mime_util_xdg.cc',
- 'move.h',
'native_library.h',
'native_library_linux.cc',
'native_library_mac.mm',
@@ -193,7 +196,7 @@
'safe_strerror_posix.cc',
'safe_strerror_posix.h',
'scoped_callback_factory.h',
- 'scoped_cftyperef.h',
+ 'mac/scoped_cftyperef.h',
'scoped_handle.h',
'scoped_nsobject.h',
'scoped_open_process.h',
@@ -254,14 +257,13 @@
'thread_local_storage_posix.cc',
'thread_local_storage_win.cc',
'thread_local_win.cc',
+ 'thread_restrictions.h',
+ 'thread_restrictions.cc',
'time.cc',
'time.h',
'time_win.cc',
'timer.cc',
'timer.h',
- 'trace_event_win.cc',
- 'trace_event.cc',
- 'trace_event.h',
'tracked.cc',
'tracked.h',
'tracked_objects.cc',
@@ -289,6 +291,11 @@
'weak_ptr.cc',
'weak_ptr.h',
'win/pe_image.cc',
+ 'win/event_trace_consumer.h',
+ 'win/event_trace_controller.cc',
+ 'win/event_trace_controller.h',
+ 'win/event_trace_provider.cc',
+ 'win/event_trace_provider.h',
'win/pe_image.h',
'win/registry.cc',
'win/registry.h',
@@ -305,7 +312,6 @@
'win/windows_version.h',
'win_util.cc',
'win_util.h',
- 'windows_message_list.h',
'worker_pool.h',
'worker_pool_linux.cc',
'worker_pool_linux.h',
@@ -333,6 +339,7 @@
'sources!': [
'atomicops_internals_x86_gcc.cc',
'message_pump_glib.cc',
+ 'message_pump_glib_x.cc',
],
}],
[ 'OS != "linux"', {
@@ -346,6 +353,13 @@
],
},
],
+ # Temporarily include linux implementation while debugging a
+ # workerpool issue. See http://crbug.com/20471 and
+ # http://crbug.com/60426
+ [ 'OS == "mac"', {
+ 'sources/': [ ['include', '(^|/)worker_pool_linux\.cc$'] ],
+ },
+ ],
[ 'OS != "mac"', {
'sources!': [
'scoped_aedesc.h'
@@ -377,7 +391,7 @@
# regression to page cycler moz.
'sha1_win.cc',
'string16.cc',
- 'trace_event.cc',
+ 'debug/trace_event.cc',
],
},],
],
@@ -391,23 +405,28 @@
'crypto/encryptor.h',
'crypto/encryptor_mac.cc',
'crypto/encryptor_nss.cc',
+ 'crypto/encryptor_openssl.cc',
'crypto/encryptor_win.cc',
'crypto/rsa_private_key.h',
'crypto/rsa_private_key.cc',
'crypto/rsa_private_key_mac.cc',
'crypto/rsa_private_key_nss.cc',
+ 'crypto/rsa_private_key_openssl.cc',
'crypto/rsa_private_key_win.cc',
'crypto/signature_creator.h',
'crypto/signature_creator_mac.cc',
'crypto/signature_creator_nss.cc',
+ 'crypto/signature_creator_openssl.cc',
'crypto/signature_creator_win.cc',
'crypto/signature_verifier.h',
'crypto/signature_verifier_mac.cc',
'crypto/signature_verifier_nss.cc',
+ 'crypto/signature_verifier_openssl.cc',
'crypto/signature_verifier_win.cc',
'crypto/symmetric_key.h',
'crypto/symmetric_key_mac.cc',
'crypto/symmetric_key_nss.cc',
+ 'crypto/symmetric_key_openssl.cc',
'crypto/symmetric_key_win.cc',
'third_party/nspr/prcpucfg.h',
'third_party/nspr/prcpucfg_win.h',
@@ -432,6 +451,7 @@
'hmac.h',
'hmac_mac.cc',
'hmac_nss.cc',
+ 'hmac_openssl.cc',
'hmac_win.cc',
'image_util.cc',
'image_util.h',
@@ -441,6 +461,9 @@
'md5.h',
'message_pump_glib.cc',
'message_pump_glib.h',
+ 'message_pump_glib_x.cc',
+ 'message_pump_glib_x.h',
+ 'message_pump_glib_x_dispatch.h',
'message_pump_libevent.cc',
'message_pump_libevent.h',
'message_pump_mac.h',
@@ -455,13 +478,12 @@
'setproctitle_linux.h',
'sha2.cc',
'sha2.h',
+ 'sha2_openssl.cc',
'string16.cc',
'string16.h',
'sync_socket.h',
'sync_socket_win.cc',
'sync_socket_posix.cc',
- 'thread_restrictions.h',
- 'thread_restrictions.cc',
'time_mac.cc',
'time_posix.cc',
'version.cc',
@@ -512,6 +534,38 @@
'win_util.cc',
],
},],
+ [ 'use_openssl==1', {
+ # TODO(joth): Use a glob to match exclude patterns once the
+ # OpenSSL file set is complete.
+ 'sources!': [
+ 'crypto/encryptor_nss.cc',
+ 'crypto/rsa_private_key_nss.cc',
+ 'crypto/signature_creator_nss.cc',
+ 'crypto/signature_verifier_nss.cc',
+ 'crypto/symmetric_key_nss.cc',
+ 'hmac_nss.cc',
+ 'nss_util.cc',
+ 'nss_util.h',
+ # Note that sha2.cc depends on the NSS files bundled into
+ # chromium; it does not have the _nss postfix as it is required
+ # on platforms besides linux and *bsd.
+ 'sha2.cc',
+ 'third_party/nss/blapi.h',
+ 'third_party/nss/blapit.h',
+ 'third_party/nss/sha256.h',
+ 'third_party/nss/sha512.cc',
+ ],
+ }, {
+ 'sources!': [
+ 'crypto/encryptor_openssl.cc',
+ 'crypto/rsa_private_key_openssl.cc',
+ 'crypto/signature_creator_openssl.cc',
+ 'crypto/signature_verifier_openssl.cc',
+ 'crypto/symmetric_key_openssl.cc',
+ 'hmac_openssl.cc',
+ 'sha2_openssl.cc',
+ ],
+ },],
],
}],
],
@@ -550,16 +604,27 @@
},
},
],
+ [ 'use_openssl==1', {
+ 'dependencies': [
+ '../build/linux/system.gyp:openssl',
+ ],
+ }, { # use_openssl==0
+ 'dependencies': [
+ '../build/linux/system.gyp:nss',
+ ],
+ }
+ ],
],
'dependencies': [
'symbolize',
'../build/util/build_util.gyp:lastchange',
'../build/linux/system.gyp:gtk',
- '../build/linux/system.gyp:nss',
+ '../build/linux/system.gyp:x11',
'xdg_mime',
],
'export_dependent_settings': [
'../build/linux/system.gyp:gtk',
+ '../build/linux/system.gyp:x11',
],
},],
[ 'OS == "freebsd" or OS == "openbsd"', {
@@ -660,10 +725,12 @@
'../build/util/build_util.gyp:lastchange',
'../build/linux/system.gyp:gtk',
'../build/linux/system.gyp:nss',
+ '../build/linux/system.gyp:x11',
'xdg_mime',
],
'export_dependent_settings': [
'../build/linux/system.gyp:gtk',
+ '../build/linux/system.gyp:x11',
],
},],
['OS == "linux"', {
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 49c6487..d907a3a 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -39,6 +39,11 @@ const char kV[] = "v";
// given by --v. E.g. "my_module=2,foo*=3" would change the logging
// level for all code in source files "my_module.*" and "foo*.*"
// ("-inl" suffixes are also disregarded for this matching).
+//
+// Any pattern containing a forward or backward slash will be tested
+// against the whole pathname and not just the module. E.g.,
+// "*/foo/bar/*=2" would change the logging level for all code in
+// source files under a "foo/bar" directory.
const char kVModule[] = "vmodule";
// Will wait for 60 seconds for a debugger to come to attach to the process.
diff --git a/base/cocoa_protocols_mac.h b/base/cocoa_protocols_mac.h
index c7808de..9482d51 100644
--- a/base/cocoa_protocols_mac.h
+++ b/base/cocoa_protocols_mac.h
@@ -27,6 +27,7 @@
@end
DEFINE_EMPTY_PROTOCOL(NSAlertDelegate)
+DEFINE_EMPTY_PROTOCOL(NSApplicationDelegate)
DEFINE_EMPTY_PROTOCOL(NSControlTextEditingDelegate)
DEFINE_EMPTY_PROTOCOL(NSMatrixDelegate)
DEFINE_EMPTY_PROTOCOL(NSMenuDelegate)
diff --git a/base/crypto/encryptor_openssl.cc b/base/crypto/encryptor_openssl.cc
new file mode 100644
index 0000000..71a84be
--- /dev/null
+++ b/base/crypto/encryptor_openssl.cc
@@ -0,0 +1,32 @@
+// 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/crypto/encryptor.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+Encryptor::Encryptor() {
+}
+
+Encryptor::~Encryptor() {
+}
+
+bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+} // namespace base
diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc
index 13e4f1f..7786521 100644
--- a/base/crypto/rsa_private_key_nss.cc
+++ b/base/crypto/rsa_private_key_nss.cc
@@ -10,7 +10,7 @@
#include <list>
-#include "base/leak_annotations.h"
+#include "base/debug/leak_annotations.h"
#include "base/logging.h"
#include "base/nss_util.h"
#include "base/nss_util_internal.h"
diff --git a/base/crypto/rsa_private_key_openssl.cc b/base/crypto/rsa_private_key_openssl.cc
new file mode 100644
index 0000000..ec1d8b5
--- /dev/null
+++ b/base/crypto/rsa_private_key_openssl.cc
@@ -0,0 +1,79 @@
+// 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/crypto/rsa_private_key.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
+ bool permanent,
+ bool sensitive) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
+ return CreateWithParams(num_bits,
+ false /* not permanent */,
+ false /* not sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
+ return CreateWithParams(num_bits,
+ true /* permanent */,
+ true /* sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
+ const std::vector<uint8>& input, bool permanent, bool sensitive) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
+ const std::vector<uint8>& input) {
+ return CreateFromPrivateKeyInfoWithParams(input,
+ false /* not permanent */,
+ false /* not sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
+ const std::vector<uint8>& input) {
+ return CreateFromPrivateKeyInfoWithParams(input,
+ true /* permanent */,
+ true /* seneitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
+ const std::vector<uint8>& input) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+RSAPrivateKey::RSAPrivateKey() {
+}
+
+RSAPrivateKey::~RSAPrivateKey() {
+}
+
+bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+} // namespace base
diff --git a/base/crypto/signature_creator_openssl.cc b/base/crypto/signature_creator_openssl.cc
new file mode 100644
index 0000000..5d70f01
--- /dev/null
+++ b/base/crypto/signature_creator_openssl.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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/signature_creator.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+// static
+SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) {
+ return NULL;
+}
+
+SignatureCreator::SignatureCreator() {
+}
+
+SignatureCreator::~SignatureCreator() {
+}
+
+bool SignatureCreator::Update(const uint8* data_part, int data_part_len) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool SignatureCreator::Final(std::vector<uint8>* signature) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+} // namespace base
diff --git a/base/crypto/signature_verifier_openssl.cc b/base/crypto/signature_verifier_openssl.cc
new file mode 100644
index 0000000..49b5e07
--- /dev/null
+++ b/base/crypto/signature_verifier_openssl.cc
@@ -0,0 +1,41 @@
+// 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/crypto/signature_verifier.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+SignatureVerifier::SignatureVerifier() {
+}
+
+SignatureVerifier::~SignatureVerifier() {
+}
+
+bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
+ int signature_algorithm_len,
+ const uint8* signature,
+ int signature_len,
+ const uint8* public_key_info,
+ int public_key_info_len) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void SignatureVerifier::VerifyUpdate(const uint8* data_part,
+ int data_part_len) {
+ NOTIMPLEMENTED();
+}
+
+bool SignatureVerifier::VerifyFinal() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void SignatureVerifier::Reset() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace base
diff --git a/base/crypto/symmetric_key.h b/base/crypto/symmetric_key.h
index d7259be..3f2be76 100644
--- a/base/crypto/symmetric_key.h
+++ b/base/crypto/symmetric_key.h
@@ -65,7 +65,10 @@ class SymmetricKey {
bool GetRawKey(std::string* raw_key);
private:
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+ // TODO(joth): Add a constructor that accepts OpenSSL symmetric key data, and
+ // the appropriate data members to store it in.
+#elif defined(USE_NSS)
explicit SymmetricKey(PK11SymKey* key);
ScopedPK11SymKey key_;
#elif defined(OS_MACOSX)
diff --git a/base/crypto/symmetric_key_openssl.cc b/base/crypto/symmetric_key_openssl.cc
new file mode 100644
index 0000000..591252d
--- /dev/null
+++ b/base/crypto/symmetric_key_openssl.cc
@@ -0,0 +1,43 @@
+// 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/crypto/symmetric_key.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+SymmetricKey::~SymmetricKey() {
+}
+
+// static
+SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
+ size_t key_size_in_bits) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
+ const std::string& password,
+ const std::string& salt,
+ size_t iterations,
+ size_t key_size_in_bits) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
+ const std::string& raw_key) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+bool SymmetricKey::GetRawKey(std::string* raw_key) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+} // namespace base
diff --git a/base/data/valgrind/DIRECTORY_MOVED b/base/data/valgrind/DIRECTORY_MOVED
new file mode 100644
index 0000000..96449fe
--- /dev/null
+++ b/base/data/valgrind/DIRECTORY_MOVED
@@ -0,0 +1,4 @@
+For those who got a merge conflict in this directory on update:
+The files from this dir has been moved to tools/valgrind/gtest_exclude
+
+TODO(timurrrr): remove this in a couple of weeks
diff --git a/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt b/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt
deleted file mode 100644
index b73fa61..0000000
--- a/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# Dr. Memory crashes on some COM calls:
-# http://code.google.com/p/drmemory/issues/detail?id=21
-WMI*
-
-# TODO(timurrrr) investigate the failures and enable these tests one-by-one.
-RSA*
-GmockTest.*
-EtwTrace*
-StatsTableTest.*
-ProcessUtilTest.EnableLFH
-ScopedNativeLibrary.Basic
diff --git a/base/data/valgrind/base_unittests.gtest-tsan.txt b/base/data/valgrind/base_unittests.gtest-tsan.txt
deleted file mode 100644
index 1f81bea..0000000
--- a/base/data/valgrind/base_unittests.gtest-tsan.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# Don't run this test under TSan, it takes ~1-2 minutes to pass.
-ProcessUtilTest.GetAppOutputRestrictedNoZombies
-
-# Don't run Memcheck sanity tests under ThreadSanitizer since they can
-# corrupt memory.
-ToolsSanityTest.*Memory*
-ToolsSanityTest.*Delete*
-
-# TSan doesn't understand SharedMemory locks, see http://crbug.com/45083
-StatsTableTest.*MultipleThreads
diff --git a/base/data/valgrind/base_unittests.gtest-tsan_mac.txt b/base/data/valgrind/base_unittests.gtest-tsan_mac.txt
deleted file mode 100644
index 7ee06a1..0000000
--- a/base/data/valgrind/base_unittests.gtest-tsan_mac.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# http://crbug.com/29855.
-StackTrace.OutputToStream
diff --git a/base/data/valgrind/base_unittests.gtest-tsan_win32.txt b/base/data/valgrind/base_unittests.gtest-tsan_win32.txt
deleted file mode 100644
index 0207c09..0000000
--- a/base/data/valgrind/base_unittests.gtest-tsan_win32.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-# Occasionally fails under TSan, see http://crbug.com/54229
-ProcessUtilTest.CalcFreeMemory
-
-# This file is copied from Valgrind-on-Wine filter
-# TODO(timurrrr): include/investigate the listed tests one-by-one
-EtwTraceControllerTest.EnableDisable
-EtwTraceConsumer*Test.*
-EtwTraceProvider*Test.*
-JSONReaderTest.Reading
-TimeTicks.*
-WMIUtilTest.*
-
-# Too slow under TSan
-RSAPrivateKeyUnitTest.*
-ConditionVariableTest.LargeFastTaskTest
diff --git a/base/data/valgrind/base_unittests.gtest.txt b/base/data/valgrind/base_unittests.gtest.txt
deleted file mode 100644
index 173defa..0000000
--- a/base/data/valgrind/base_unittests.gtest.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-# This test currently times out in valgrind, see http://crbug.com/9194
-WatchdogTest.AlarmTest
-
-# These tests occassionally hangs under Valgrind on Mac. valgrind-darwin r9573
-# Revisit with better valgrind.
-# Valgrind bug: https://bugs.kde.org/show_bug.cgi?id=189661
-TimerTest.RepeatingTimer
-TimerTest.RepeatingTimer_Cancel
-
-# Crashes occasionally, see http://crbug.com/7477
-ObserverListThreadSafeTest.CrossThreadObserver
-ObserverListThreadSafeTest.CrossThreadNotifications
-
-# Hangs sometimes on linux, see http://crbug.com/22138
-ClipboardTest.*
-
-# These tests trigger a CHECK so they will leak memory. They don't test
-# anything else, so just disable them on valgrind. Bug 28179.
-OutOfMemoryDeathTest.*
-
-# Flaky under Valgrind, see http://crbug.com/55517
-PlatformFile.TouchGetInfoPlatformFile
diff --git a/base/data/valgrind/base_unittests.gtest_mac.txt b/base/data/valgrind/base_unittests.gtest_mac.txt
deleted file mode 100644
index 46fbf47..0000000
--- a/base/data/valgrind/base_unittests.gtest_mac.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Fails on Valgrind/Mac, see http://crbug.com/43972
-ConditionVariableTest.LargeFastTaskTest
-
-# Fails on Valgrind/Mac due to missing syscall wrapper
-# for the symlink() syscall. See http://crbug.com/44001
-FileUtilTest.NormalizeFilePathSymlinks
-
-# Fails on Valgrind/Mac, see http://crbug.com/53196
-CancellationFlagTest.SetOnDifferentThreadDeathTest
diff --git a/base/data/valgrind/base_unittests.gtest_win32.txt b/base/data/valgrind/base_unittests.gtest_win32.txt
deleted file mode 100644
index 525648c..0000000
--- a/base/data/valgrind/base_unittests.gtest_win32.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# Too slow under Valgrind/Wine and TSan/Windows
-TimeTicks.WinRollover
-
-# Very sensitive to slowdown
-TimeTicks.Deltas
-TimeTicks.HighResNow
-TimerTest.RepeatingTimer*
diff --git a/base/data/valgrind/base_unittests.gtest_wine.txt b/base/data/valgrind/base_unittests.gtest_wine.txt
deleted file mode 100644
index 17d3085..0000000
--- a/base/data/valgrind/base_unittests.gtest_wine.txt
+++ /dev/null
@@ -1,96 +0,0 @@
-# crash Crashes in Wine
-# crash-valgrind Crashes in Wine + Valgrind
-# dontcare Safe to ignore
-# dontcare-hangwin Ignore, hangs on Windows too
-# dontcare-winfail Ignore, fails on Windows too
-# dontcare-flaky Ignore, flaky test
-# dontcare-hang Ignore, hangs we don't care about
-# fail Fails, needs triaging or needs to be fixed
-# fail-valgrind Fails only under Valgrind
-# fail_wine_vmware Fails in Wine under VMware? TODO(dank) clarify
-# flaky-valgrind Flaky under Valgrind, needs investigation
-# hang Test that hangs for some reason
-# hang-valgrind Test that hangs under valgrind, or just takes too long
-
-# dontcare
-BaseWinUtilTest.FormatMessageW
-
-# fail-valgrind
-# fails under wine + valgrind TODO(thestig): investigate
-ConditionVariableTest.LargeFastTaskTest
-
-# hang
-# http://bugs.winehq.org/show_bug.cgi?id=20946, advapi32.ControlTrace() not yet implemented
-EtwTraceControllerTest.EnableDisable
-
-# crash
-# http://bugs.winehq.org/show_bug.cgi?id=20946, advapi32.OpenTrace() unimplemented
-EtwTraceConsumer*Test.*
-
-# crash
-# http://bugs.winehq.org/show_bug.cgi?id=20946, advapi32.RegisterTraceGuids() unimplemented
-EtwTraceProvider*Test.*
-
-# dontcare
-FileUtilTest.CountFilesCreatedAfter
-
-# dontcare
-FileUtilTest.GetFileCreationLocalTime
-
-# fail
-# http://bugs.winehq.org/show_bug.cgi?id=20340
-HMACTest.HMACObjectReuse
-
-# fail
-# http://bugs.winehq.org/show_bug.cgi?id=20340
-HMACTest.HmacSafeBrowsingResponseTest
-
-# fail
-# http://bugs.winehq.org/show_bug.cgi?id=20340
-HMACTest.RFC2202TestCases
-
-# hang-valgrind
-# not really a hang, takes 400 seconds
-JSONReaderTest.Reading
-
-# dontcare
-# Alexandre Julliard triaged
-PEImageTest.EnumeratesPE
-
-# fail-valgrind
-# fails under wine + valgrind TODO(thestig): investigate
-ProcessUtilTest.CalcFreeMemory
-
-# fail-valgrind
-# fails under wine + valgrind TODO(thestig): investigate
-ProcessUtilTest.KillSlowChild
-
-# fail-valgrind
-# fails under wine + valgrind TODO(thestig): investigate
-ProcessUtilTest.SpawnChild
-
-# hang-valgrind
-# not really a hang, takes 300 seconds
-RSAPrivateKeyUnitTest.InitRandomTest
-
-# fail_wine_vmware
-RSAPrivateKeyUnitTest.ShortIntegers
-
-# dontcare-flaky
-# http://bugs.winehq.org/show_bug.cgi?id=20606
-StatsTableTest.MultipleProcesses
-
-# flaky-valgrind
-# flaky, timing issues? TODO(thestig): investigate
-StatsTableTest.StatsCounterTimer
-
-# fail-valgrind
-# fails under wine + valgrind TODO(thestig): investigate
-StatsTableTest.StatsRate
-
-# fail-valgrind
-# fails under wine + valgrind TODO(thestig): investigate
-StatsTableTest.StatsScope
-
-# dontcare
-WMIUtilTest.*
diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc
new file mode 100644
index 0000000..9ca7e8d
--- /dev/null
+++ b/base/debug/debugger.cc
@@ -0,0 +1,25 @@
+// 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/debugger.h"
+
+#include "base/platform_thread.h"
+
+namespace base {
+namespace debug {
+
+bool WaitForDebugger(int wait_seconds, bool silent) {
+ for (int i = 0; i < wait_seconds * 10; ++i) {
+ if (BeingDebugged()) {
+ if (!silent)
+ BreakDebugger();
+ return true;
+ }
+ PlatformThread::Sleep(100);
+ }
+ return false;
+}
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug/debugger.h b/base/debug/debugger.h
new file mode 100644
index 0000000..008d77d
--- /dev/null
+++ b/base/debug/debugger.h
@@ -0,0 +1,39 @@
+// 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.
+
+// This is a cross platform interface for helper functions related to
+// debuggers. You should use this to test if you're running under a debugger,
+// and if you would like to yield (breakpoint) into the debugger.
+
+#ifndef BASE_DEBUG_DEBUGGER_H
+#define BASE_DEBUG_DEBUGGER_H
+#pragma once
+
+namespace base {
+namespace debug {
+
+// Starts the registered system-wide JIT debugger to attach it to specified
+// process.
+bool SpawnDebuggerOnProcess(unsigned process_id);
+
+// Waits wait_seconds seconds for a debugger to attach to the current process.
+// When silent is false, an exception is thrown when a debugger is detected.
+bool WaitForDebugger(int wait_seconds, bool silent);
+
+// Returns true if the given process is being run under a debugger.
+//
+// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
+// To get around this, this function caches its value.
+//
+// WARNING: Because of this, on OS X, a call MUST be made to this function
+// BEFORE the sandbox is enabled.
+bool BeingDebugged();
+
+// Break into the debugger, assumes a debugger is present.
+void BreakDebugger();
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_DEBUGGER_H
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
new file mode 100644
index 0000000..a5ab066
--- /dev/null
+++ b/base/debug/debugger_posix.cc
@@ -0,0 +1,165 @@
+// 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/debugger.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#include <iostream>
+
+#include "base/basictypes.h"
+#include "base/compat_execinfo.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/safe_strerror_posix.h"
+#include "base/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/stringprintf.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+namespace base {
+namespace debug {
+
+bool SpawnDebuggerOnProcess(unsigned /* process_id */) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+#if defined(OS_MACOSX)
+
+// Based on Apple's recommended method as described in
+// http://developer.apple.com/qa/qa2004/qa1361.html
+bool BeingDebugged() {
+ // If the process is sandboxed then we can't use the sysctl, so cache the
+ // value.
+ static bool is_set = false;
+ static bool being_debugged = false;
+
+ if (is_set) {
+ return being_debugged;
+ }
+
+ // Initialize mib, which tells sysctl what info we want. In this case,
+ // we're looking for information about a specific process ID.
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID,
+ getpid()
+ };
+
+ // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and
+ // binary interfaces may change.
+ struct kinfo_proc info;
+ size_t info_size = sizeof(info);
+
+ int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
+ DCHECK_EQ(sysctl_result, 0);
+ if (sysctl_result != 0) {
+ is_set = true;
+ being_debugged = false;
+ return being_debugged;
+ }
+
+ // This process is being debugged if the P_TRACED flag is set.
+ is_set = true;
+ being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
+ return being_debugged;
+}
+
+#elif defined(OS_LINUX)
+
+// We can look in /proc/self/status for TracerPid. We are likely used in crash
+// handling, so we are careful not to use the heap or have side effects.
+// Another option that is common is to try to ptrace yourself, but then we
+// can't detach without forking(), and that's not so great.
+// static
+bool BeingDebugged() {
+ int status_fd = open("/proc/self/status", O_RDONLY);
+ if (status_fd == -1)
+ return false;
+
+ // We assume our line will be in the first 1024 characters and that we can
+ // read this much all at once. In practice this will generally be true.
+ // This simplifies and speeds up things considerably.
+ char buf[1024];
+
+ ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
+ if (HANDLE_EINTR(close(status_fd)) < 0)
+ return false;
+
+ if (num_read <= 0)
+ return false;
+
+ StringPiece status(buf, num_read);
+ StringPiece tracer("TracerPid:\t");
+
+ StringPiece::size_type pid_index = status.find(tracer);
+ if (pid_index == StringPiece::npos)
+ return false;
+
+ // Our pid is 0 without a debugger, assume this for any pid starting with 0.
+ pid_index += tracer.size();
+ return pid_index < status.size() && status[pid_index] != '0';
+}
+
+#elif defined(OS_FREEBSD)
+
+bool DebugUtil::BeingDebugged() {
+ // TODO(benl): can we determine this under FreeBSD?
+ NOTIMPLEMENTED();
+ return false;
+}
+
+#endif // defined(OS_FREEBSD)
+
+// We want to break into the debugger in Debug mode, and cause a crash dump in
+// Release mode. Breakpad behaves as follows:
+//
+// +-------+-----------------+-----------------+
+// | OS | Dump on SIGTRAP | Dump on SIGABRT |
+// +-------+-----------------+-----------------+
+// | Linux | N | Y |
+// | Mac | Y | N |
+// +-------+-----------------+-----------------+
+//
+// Thus we do the following:
+// Linux: Debug mode, send SIGTRAP; Release mode, send SIGABRT.
+// Mac: Always send SIGTRAP.
+
+#if defined(NDEBUG) && !defined(OS_MACOSX)
+#define DEBUG_BREAK() abort()
+#elif defined(ARCH_CPU_ARM_FAMILY)
+#define DEBUG_BREAK() asm("bkpt 0")
+#else
+#define DEBUG_BREAK() asm("int3")
+#endif
+
+void BreakDebugger() {
+ DEBUG_BREAK();
+}
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
new file mode 100644
index 0000000..d1d47cd
--- /dev/null
+++ b/base/debug/debugger_win.cc
@@ -0,0 +1,112 @@
+// 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/debugger.h"
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#include "base/basictypes.h"
+#include "base/debug_util.h"
+#include "base/logging.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Minimalist key reader.
+// Note: Does not use the CRT.
+bool RegReadString(HKEY root, const wchar_t* subkey,
+ const wchar_t* value_name, wchar_t* buffer, int* len) {
+ HKEY key = NULL;
+ DWORD res = RegOpenKeyEx(root, subkey, 0, KEY_READ, &key);
+ if (ERROR_SUCCESS != res || key == NULL)
+ return false;
+
+ DWORD type = 0;
+ DWORD buffer_size = *len * sizeof(wchar_t);
+ // We don't support REG_EXPAND_SZ.
+ res = RegQueryValueEx(key, value_name, NULL, &type,
+ reinterpret_cast<BYTE*>(buffer), &buffer_size);
+ if (ERROR_SUCCESS == res && buffer_size != 0 && type == REG_SZ) {
+ // Make sure the buffer is NULL terminated.
+ buffer[*len - 1] = 0;
+ *len = lstrlen(buffer);
+ RegCloseKey(key);
+ return true;
+ }
+ RegCloseKey(key);
+ return false;
+}
+
+// Replaces each "%ld" in input per a value. Not efficient but it works.
+// Note: Does not use the CRT.
+bool StringReplace(const wchar_t* input, int value, wchar_t* output,
+ int output_len) {
+ memset(output, 0, output_len*sizeof(wchar_t));
+ int input_len = lstrlen(input);
+
+ for (int i = 0; i < input_len; ++i) {
+ int current_output_len = lstrlen(output);
+
+ if (input[i] == L'%' && input[i + 1] == L'l' && input[i + 2] == L'd') {
+ // Make sure we have enough place left.
+ if ((current_output_len + 12) >= output_len)
+ return false;
+
+ // Cheap _itow().
+ wsprintf(output+current_output_len, L"%d", value);
+ i += 2;
+ } else {
+ if (current_output_len >= output_len)
+ return false;
+ output[current_output_len] = input[i];
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// Note: Does not use the CRT.
+bool SpawnDebuggerOnProcess(unsigned process_id) {
+ wchar_t reg_value[1026];
+ int len = arraysize(reg_value);
+ if (RegReadString(HKEY_LOCAL_MACHINE,
+ L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug",
+ L"Debugger", reg_value, &len)) {
+ wchar_t command_line[1026];
+ if (StringReplace(reg_value, process_id, command_line,
+ arraysize(command_line))) {
+ // We don't mind if the debugger is present because it will simply fail
+ // to attach to this process.
+ STARTUPINFO startup_info = {0};
+ startup_info.cb = sizeof(startup_info);
+ PROCESS_INFORMATION process_info = {0};
+
+ if (CreateProcess(NULL, command_line, NULL, NULL, FALSE, 0, NULL, NULL,
+ &startup_info, &process_info)) {
+ CloseHandle(process_info.hThread);
+ WaitForInputIdle(process_info.hProcess, 10000);
+ CloseHandle(process_info.hProcess);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BeingDebugged() {
+ return ::IsDebuggerPresent() != 0;
+}
+
+void BreakDebugger() {
+ if (DebugUtil::AreDialogsSuppressed())
+ _exit(1);
+ __debugbreak();
+}
+
+} // namespace debug
+} // namespace base
diff --git a/base/leak_annotations.h b/base/debug/leak_annotations.h
index dd8280b..e1086fe 100644
--- a/base/leak_annotations.h
+++ b/base/debug/leak_annotations.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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_LEAK_ANNOTATIONS_H_
-#define BASE_LEAK_ANNOTATIONS_H_
+#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
+#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
#pragma once
#include "build/build_config.h"
@@ -25,4 +25,4 @@
#endif
-#endif // BASE_LEAK_ANNOTATIONS_H_
+#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_
diff --git a/base/leak_tracker.h b/base/debug/leak_tracker.h
index 96d8773..8af82a9 100644
--- a/base/leak_tracker.h
+++ b/base/debug/leak_tracker.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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_LEAK_TRACKER_H_
-#define BASE_LEAK_TRACKER_H_
+#ifndef BASE_DEBUG_LEAK_TRACKER_H_
+#define BASE_DEBUG_LEAK_TRACKER_H_
#pragma once
// Only enable leak tracking in debug builds.
@@ -12,7 +12,7 @@
#endif
#ifdef ENABLE_LEAK_TRACKER
-#include "base/debug_util.h"
+#include "base/debug/stack_trace.h"
#include "base/linked_list.h"
#include "base/logging.h"
#endif // ENABLE_LEAK_TRACKER
@@ -45,6 +45,7 @@
// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
namespace base {
+namespace debug {
#ifndef ENABLE_LEAK_TRACKER
@@ -127,6 +128,7 @@ class LeakTracker : public LinkNode<LeakTracker<T> > {
#endif // ENABLE_LEAK_TRACKER
+} // namespace debug
} // namespace base
-#endif // BASE_LEAK_TRACKER_H_
+#endif // BASE_DEBUG_LEAK_TRACKER_H_
diff --git a/base/debug/leak_tracker_unittest.cc b/base/debug/leak_tracker_unittest.cc
new file mode 100644
index 0000000..2e6a9a5
--- /dev/null
+++ b/base/debug/leak_tracker_unittest.cc
@@ -0,0 +1,113 @@
+// 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/leak_tracker.h"
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+class ClassA {
+ private:
+ LeakTracker<ClassA> leak_tracker_;
+};
+
+class ClassB {
+ private:
+ LeakTracker<ClassB> leak_tracker_;
+};
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, we should do nothing.
+TEST(LeakTrackerTest, NotEnabled) {
+ EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+
+ // Use scoped_ptr so compiler doesn't complain about unused variables.
+ scoped_ptr<ClassA> a1(new ClassA);
+ scoped_ptr<ClassB> b1(new ClassB);
+ scoped_ptr<ClassB> b2(new ClassB);
+
+ EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+#else
+
+TEST(LeakTrackerTest, Basic) {
+ {
+ ClassA a1;
+
+ EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+ ClassB b1;
+ ClassB b2;
+
+ EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+ scoped_ptr<ClassA> a2(new ClassA);
+
+ EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+ a2.reset();
+
+ EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+ }
+
+ EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+// Try some orderings of create/remove to hit different cases in the linked-list
+// assembly.
+TEST(LeakTrackerTest, LinkedList) {
+ EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+ scoped_ptr<ClassA> a1(new ClassA);
+ scoped_ptr<ClassA> a2(new ClassA);
+ scoped_ptr<ClassA> a3(new ClassA);
+ scoped_ptr<ClassA> a4(new ClassA);
+
+ EXPECT_EQ(4, LeakTracker<ClassA>::NumLiveInstances());
+
+ // Remove the head of the list (a1).
+ a1.reset();
+ EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+ // Remove the tail of the list (a4).
+ a4.reset();
+ EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+
+ // Append to the new tail of the list (a3).
+ scoped_ptr<ClassA> a5(new ClassA);
+ EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+ a2.reset();
+ a3.reset();
+
+ EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+
+ a5.reset();
+ EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+}
+
+TEST(LeakTrackerTest, NoOpCheckForLeaks) {
+ // There are no live instances of ClassA, so this should do nothing.
+ LeakTracker<ClassA>::CheckForLeaks();
+}
+
+#endif // ENABLE_LEAK_TRACKER
+
+} // namespace
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
new file mode 100644
index 0000000..5be4c5c
--- /dev/null
+++ b/base/debug/stack_trace.cc
@@ -0,0 +1,21 @@
+// 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/stack_trace.h"
+
+namespace base {
+namespace debug {
+
+StackTrace::~StackTrace() {
+}
+
+const void *const *StackTrace::Addresses(size_t* count) {
+ *count = count_;
+ if (count_)
+ return trace_;
+ return NULL;
+}
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
new file mode 100644
index 0000000..8afc32c
--- /dev/null
+++ b/base/debug/stack_trace.h
@@ -0,0 +1,63 @@
+// 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_DEBUG_STACK_TRACE_H_
+#define BASE_DEBUG_STACK_TRACE_H_
+#pragma once
+
+#include <iosfwd>
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+struct _EXCEPTION_POINTERS;
+#endif
+
+namespace base {
+namespace debug {
+
+// A stacktrace can be helpful in debugging. For example, you can include a
+// stacktrace member in a object (probably around #ifndef NDEBUG) so that you
+// can later see where the given object was created from.
+class StackTrace {
+ public:
+ // Creates a stacktrace from the current location.
+ StackTrace();
+
+#if defined(OS_WIN)
+ // Creates a stacktrace for an exception.
+ // Note: this function will throw an import not found (StackWalk64) exception
+ // on system without dbghelp 5.1.
+ StackTrace(_EXCEPTION_POINTERS* exception_pointers);
+#endif
+
+ // Copying and assignment are allowed with the default functions.
+
+ ~StackTrace();
+
+ // Gets an array of instruction pointer values. |*count| will be set to the
+ // number of elements in the returned array.
+ const void* const* Addresses(size_t* count);
+
+ // Prints a backtrace to stderr
+ void PrintBacktrace();
+
+ // Resolves backtrace to symbols and write to stream.
+ void OutputToStream(std::ostream* os);
+
+ private:
+ // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
+ // the sum of FramesToSkip and FramesToCapture must be less than 63,
+ // so set it to 62. Even if on POSIX it could be a larger value, it usually
+ // doesn't give much more information.
+ static const int kMaxTraces = 62;
+
+ void* trace_[kMaxTraces];
+ int count_;
+};
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_STACK_TRACE_H_
diff --git a/base/debug_util_posix.cc b/base/debug/stack_trace_posix.cc
index 4c5ec80..e4b0ef2 100644
--- a/base/debug_util_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug_util.h"
+#include "base/debug/stack_trace.h"
#include <errno.h>
#include <fcntl.h>
@@ -39,7 +39,11 @@
#include "base/third_party/symbolize/symbolize.h"
#endif
+namespace base {
+namespace debug {
+
namespace {
+
// The prefix used for mangled symbols, per the Itanium C++ ABI:
// http://www.codesourcery.com/cxx-abi/abi.html#mangling
const char kMangledSymbolPrefix[] = "_Z";
@@ -104,9 +108,6 @@ void DemangleSymbols(std::string* text) {
bool GetBacktraceStrings(void **trace, int size,
std::vector<std::string>* trace_strings,
std::string* error_message) {
-#ifdef ANDROID
- return false;
-#else
bool symbolized = false;
#if defined(USE_SYMBOLIZE)
@@ -144,143 +145,16 @@ bool GetBacktraceStrings(void **trace, int size,
#endif // defined(USE_SYMBOLIZE)
return symbolized;
-#endif // ANDROID
}
} // namespace
-// static
-bool DebugUtil::SpawnDebuggerOnProcess(unsigned /* process_id */) {
- NOTIMPLEMENTED();
- return false;
-}
-
-#if defined(OS_MACOSX)
-
-// Based on Apple's recommended method as described in
-// http://developer.apple.com/qa/qa2004/qa1361.html
-// static
-bool DebugUtil::BeingDebugged() {
- // If the process is sandboxed then we can't use the sysctl, so cache the
- // value.
- static bool is_set = false;
- static bool being_debugged = false;
-
- if (is_set) {
- return being_debugged;
- }
-
- // Initialize mib, which tells sysctl what info we want. In this case,
- // we're looking for information about a specific process ID.
- int mib[] = {
- CTL_KERN,
- KERN_PROC,
- KERN_PROC_PID,
- getpid()
- };
-
- // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and
- // binary interfaces may change.
- struct kinfo_proc info;
- size_t info_size = sizeof(info);
-
- int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
- DCHECK_EQ(sysctl_result, 0);
- if (sysctl_result != 0) {
- is_set = true;
- being_debugged = false;
- return being_debugged;
- }
-
- // This process is being debugged if the P_TRACED flag is set.
- is_set = true;
- being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
- return being_debugged;
-}
-
-#elif defined(OS_LINUX)
-
-// We can look in /proc/self/status for TracerPid. We are likely used in crash
-// handling, so we are careful not to use the heap or have side effects.
-// Another option that is common is to try to ptrace yourself, but then we
-// can't detach without forking(), and that's not so great.
-// static
-bool DebugUtil::BeingDebugged() {
- int status_fd = open("/proc/self/status", O_RDONLY);
- if (status_fd == -1)
- return false;
-
- // We assume our line will be in the first 1024 characters and that we can
- // read this much all at once. In practice this will generally be true.
- // This simplifies and speeds up things considerably.
- char buf[1024];
-
- ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
- if (HANDLE_EINTR(close(status_fd)) < 0)
- return false;
-
- if (num_read <= 0)
- return false;
-
- base::StringPiece status(buf, num_read);
- base::StringPiece tracer("TracerPid:\t");
-
- base::StringPiece::size_type pid_index = status.find(tracer);
- if (pid_index == base::StringPiece::npos)
- return false;
-
- // Our pid is 0 without a debugger, assume this for any pid starting with 0.
- pid_index += tracer.size();
- return pid_index < status.size() && status[pid_index] != '0';
-}
-
-#elif defined(OS_FREEBSD)
-
-bool DebugUtil::BeingDebugged() {
- // TODO(benl): can we determine this under FreeBSD?
- NOTIMPLEMENTED();
- return false;
-}
-
-#endif // defined(OS_FREEBSD)
-
-// We want to break into the debugger in Debug mode, and cause a crash dump in
-// Release mode. Breakpad behaves as follows:
-//
-// +-------+-----------------+-----------------+
-// | OS | Dump on SIGTRAP | Dump on SIGABRT |
-// +-------+-----------------+-----------------+
-// | Linux | N | Y |
-// | Mac | Y | N |
-// +-------+-----------------+-----------------+
-//
-// Thus we do the following:
-// Linux: Debug mode, send SIGTRAP; Release mode, send SIGABRT.
-// Mac: Always send SIGTRAP.
-
-#if defined(NDEBUG) && !defined(OS_MACOSX)
-#define DEBUG_BREAK() abort()
-#elif defined(ARCH_CPU_ARM_FAMILY)
-#define DEBUG_BREAK() asm("bkpt 0")
-#else
-#define DEBUG_BREAK() asm("int3")
-#endif
-
-// static
-void DebugUtil::BreakDebugger() {
- DEBUG_BREAK();
-}
-
StackTrace::StackTrace() {
-#if (defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) || defined(ANDROID)
-#if defined(ANDROID)
- return;
-#else
+#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
if (backtrace == NULL) {
count_ = 0;
return;
}
-#endif // ANDROID
#endif
// Though the backtrace API man page does not list any possible negative
// return values, we take no chance.
@@ -288,13 +162,9 @@ StackTrace::StackTrace() {
}
void StackTrace::PrintBacktrace() {
-#if (defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) || defined(ANDROID)
-#if defined(ANDROID)
- return;
-#else
+#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
if (backtrace_symbols_fd == NULL)
return;
-#endif // ANDROID
#endif
fflush(stderr);
std::vector<std::string> trace_strings;
@@ -305,13 +175,9 @@ void StackTrace::PrintBacktrace() {
}
void StackTrace::OutputToStream(std::ostream* os) {
-#if (defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) || defined(ANDROID)
-#if defined(ANDROID)
- return;
-#else
+#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
if (backtrace_symbols == NULL)
return;
-#endif // ANDROID
#endif
std::vector<std::string> trace_strings;
std::string error_message;
@@ -328,3 +194,6 @@ void StackTrace::OutputToStream(std::ostream* os) {
(*os) << "\t" << trace_strings[i] << "\n";
}
}
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug_util_unittest.cc b/base/debug/stack_trace_unittest.cc
index 8d0deab..ce5f313 100644
--- a/base/debug_util_unittest.cc
+++ b/base/debug/stack_trace_unittest.cc
@@ -5,14 +5,22 @@
#include <sstream>
#include <string>
-#include "base/debug_util.h"
+#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace base {
+namespace debug {
+
// Note: On Linux, this test currently only fully works on Debug builds.
// See comments in the #ifdef soup if you intend to change this.
-// Flaky, crbug.com/32070.
-TEST(StackTrace, FLAKY_OutputToStream) {
+#if defined(OS_WIN)
+// Always fails on Windows: crbug.com/32070
+#define MAYBE_OutputToStream FAILS_OutputToStream
+#else
+#define MAYBE_OutputToStream OutputToStream
+#endif
+TEST(StackTrace, MAYBE_OutputToStream) {
StackTrace trace;
// Dump the trace into a string.
@@ -104,3 +112,6 @@ TEST(StackTrace, DebugOutputToStream) {
TEST(StackTrace, DebugPrintBacktrace) {
StackTrace().PrintBacktrace();
}
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug_util_win.cc b/base/debug/stack_trace_win.cc
index b60ba31..653d234 100644
--- a/base/debug_util_win.cc
+++ b/base/debug/stack_trace_win.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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_util.h"
+#include "base/debug/stack_trace.h"
#include <windows.h>
#include <dbghelp.h>
@@ -14,59 +14,10 @@
#include "base/logging.h"
#include "base/singleton.h"
-namespace {
-
-// Minimalist key reader.
-// Note: Does not use the CRT.
-bool RegReadString(HKEY root, const wchar_t* subkey,
- const wchar_t* value_name, wchar_t* buffer, int* len) {
- HKEY key = NULL;
- DWORD res = RegOpenKeyEx(root, subkey, 0, KEY_READ, &key);
- if (ERROR_SUCCESS != res || key == NULL)
- return false;
-
- DWORD type = 0;
- DWORD buffer_size = *len * sizeof(wchar_t);
- // We don't support REG_EXPAND_SZ.
- res = RegQueryValueEx(key, value_name, NULL, &type,
- reinterpret_cast<BYTE*>(buffer), &buffer_size);
- if (ERROR_SUCCESS == res && buffer_size != 0 && type == REG_SZ) {
- // Make sure the buffer is NULL terminated.
- buffer[*len - 1] = 0;
- *len = lstrlen(buffer);
- RegCloseKey(key);
- return true;
- }
- RegCloseKey(key);
- return false;
-}
-
-// Replaces each "%ld" in input per a value. Not efficient but it works.
-// Note: Does not use the CRT.
-bool StringReplace(const wchar_t* input, int value, wchar_t* output,
- int output_len) {
- memset(output, 0, output_len*sizeof(wchar_t));
- int input_len = lstrlen(input);
-
- for (int i = 0; i < input_len; ++i) {
- int current_output_len = lstrlen(output);
+namespace base {
+namespace debug {
- if (input[i] == L'%' && input[i + 1] == L'l' && input[i + 2] == L'd') {
- // Make sure we have enough place left.
- if ((current_output_len + 12) >= output_len)
- return false;
-
- // Cheap _itow().
- wsprintf(output+current_output_len, L"%d", value);
- i += 2;
- } else {
- if (current_output_len >= output_len)
- return false;
- output[current_output_len] = input[i];
- }
- }
- return true;
-}
+namespace {
// SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family
// of functions. The Sym* family of functions may only be invoked by one
@@ -184,47 +135,6 @@ class SymbolContext {
} // namespace
-// Note: Does not use the CRT.
-bool DebugUtil::SpawnDebuggerOnProcess(unsigned process_id) {
- wchar_t reg_value[1026];
- int len = arraysize(reg_value);
- if (RegReadString(HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug",
- L"Debugger", reg_value, &len)) {
- wchar_t command_line[1026];
- if (StringReplace(reg_value, process_id, command_line,
- arraysize(command_line))) {
- // We don't mind if the debugger is present because it will simply fail
- // to attach to this process.
- STARTUPINFO startup_info = {0};
- startup_info.cb = sizeof(startup_info);
- PROCESS_INFORMATION process_info = {0};
-
- if (CreateProcess(NULL, command_line, NULL, NULL, FALSE, 0, NULL, NULL,
- &startup_info, &process_info)) {
- CloseHandle(process_info.hThread);
- WaitForInputIdle(process_info.hProcess, 10000);
- CloseHandle(process_info.hProcess);
- return true;
- }
- }
- }
- return false;
-}
-
-// static
-bool DebugUtil::BeingDebugged() {
- return ::IsDebuggerPresent() != 0;
-}
-
-// static
-void DebugUtil::BreakDebugger() {
- if (suppress_dialogs_)
- _exit(1);
-
- __debugbreak();
-}
-
StackTrace::StackTrace() {
// When walking our own stack, use CaptureStackBackTrace().
count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_, NULL);
@@ -282,3 +192,6 @@ void StackTrace::OutputToStream(std::ostream* os) {
context->OutputTraceToStream(trace_, count_, os);
}
}
+
+} // namespace debug
+} // namespace base
diff --git a/base/trace_event.cc b/base/debug/trace_event.cc
index fbb35f8..616d7ca 100644
--- a/base/trace_event.cc
+++ b/base/debug/trace_event.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/trace_event.h"
+#include "base/debug/trace_event.h"
#include "base/format_macros.h"
#include "base/file_path.h"
@@ -17,6 +17,7 @@
#define USE_UNRELIABLE_NOW
namespace base {
+namespace debug {
static const char* kEventTypeNames[] = {
"BEGIN",
@@ -181,4 +182,5 @@ void TraceLog::Log(const std::string& msg) {
#endif
}
-} // namespace base
+} // namespace debug
+} // namespace base
diff --git a/base/trace_event.h b/base/debug/trace_event.h
index e46e225..38b4d05 100644
--- a/base/trace_event.h
+++ b/base/debug/trace_event.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -12,8 +12,8 @@
// trace report. In the future, it may use another mechansim to facilitate
// real-time analysis.
-#ifndef BASE_TRACE_EVENT_H_
-#define BASE_TRACE_EVENT_H_
+#ifndef BASE_DEBUG_TRACE_EVENT_H_
+#define BASE_DEBUG_TRACE_EVENT_H_
#pragma once
#include "build/build_config.h"
@@ -26,7 +26,7 @@
// value of the CHROMIUM_ENABLE_TRACE_EVENT define. The Windows implementation
// is controlled by Event Tracing for Windows, which will turn tracing on only
// if there is someone listening for the events it generates.
-#include "base/trace_event_win.h"
+#include "base/debug/trace_event_win.h"
#else // defined(OS_WIN)
#include <string>
@@ -52,38 +52,41 @@
// Record that an event (of name, id) has begun. All BEGIN events should have
// corresponding END events with a matching (name, id).
#define TRACE_EVENT_BEGIN(name, id, extra) \
- Singleton<base::TraceLog>::get()->Trace(name, \
- base::TraceLog::EVENT_BEGIN, \
- reinterpret_cast<const void*>(id), \
- extra, \
- __FILE__, \
- __LINE__)
+ Singleton<base::debug::TraceLog>::get()->Trace( \
+ name, \
+ base::debug::TraceLog::EVENT_BEGIN, \
+ reinterpret_cast<const void*>(id), \
+ extra, \
+ __FILE__, \
+ __LINE__)
// Record that an event (of name, id) has ended. All END events should have
// corresponding BEGIN events with a matching (name, id).
#define TRACE_EVENT_END(name, id, extra) \
- Singleton<base::TraceLog>::get()->Trace(name, \
- base::TraceLog::EVENT_END, \
- reinterpret_cast<const void*>(id), \
- extra, \
- __FILE__, \
- __LINE__)
+ Singleton<base::debug::TraceLog>::get()->Trace( \
+ name, \
+ base::debug::TraceLog::EVENT_END, \
+ reinterpret_cast<const void*>(id), \
+ extra, \
+ __FILE__, \
+ __LINE__)
// Record that an event (of name, id) with no duration has happened.
#define TRACE_EVENT_INSTANT(name, id, extra) \
- Singleton<base::TraceLog>::get()->Trace(name, \
- base::TraceLog::EVENT_INSTANT, \
- reinterpret_cast<const void*>(id), \
- extra, \
- __FILE__, \
- __LINE__)
+ Singleton<base::debug::TraceLog>::get()->Trace( \
+ name, \
+ base::debug::TraceLog::EVENT_INSTANT, \
+ reinterpret_cast<const void*>(id), \
+ extra, \
+ __FILE__, \
+ __LINE__)
#endif // CHROMIUM_ENABLE_TRACE_EVENT
namespace base {
+
class ProcessMetrics;
-}
-namespace base {
+namespace debug {
class TraceLog {
public:
@@ -138,7 +141,9 @@ class TraceLog {
RepeatingTimer<TraceLog> timer_;
};
-} // namespace base
+} // namespace debug
+} // namespace base
+
#endif // defined(OS_WIN)
-#endif // BASE_TRACE_EVENT_H_
+#endif // BASE_DEBUG_TRACE_EVENT_H_
diff --git a/base/trace_event_win.cc b/base/debug/trace_event_win.cc
index 7217283..8405699 100644
--- a/base/trace_event_win.cc
+++ b/base/debug/trace_event_win.cc
@@ -1,13 +1,18 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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/trace_event_win.h"
+
+#include "base/debug/trace_event_win.h"
#include "base/logging.h"
#include "base/singleton.h"
#include <initguid.h> // NOLINT
namespace base {
+namespace debug {
+
+using base::win::EtwEventType;
+using base::win::EtwMofEvent;
// {3DADA31D-19EF-4dc1-B345-037927193422}
const GUID kChromeTraceProviderName = {
@@ -22,7 +27,7 @@ const GUID kTraceEventClass64 = {
0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe};
-TraceLog::TraceLog() : EtwTraceProvider(base::kChromeTraceProviderName) {
+TraceLog::TraceLog() : EtwTraceProvider(kChromeTraceProviderName) {
Register();
}
@@ -36,7 +41,7 @@ bool TraceLog::StartTracing() {
void TraceLog::TraceEvent(const char* name,
size_t name_len,
- base::TraceLog::EventType type,
+ EventType type,
const void* id,
const char* extra,
size_t extra_len) {
@@ -48,24 +53,24 @@ void TraceLog::TraceEvent(const char* name,
EtwEventType etw_type = 0;
switch (type) {
- case base::TraceLog::EVENT_BEGIN:
- etw_type = base::kTraceEventTypeBegin;
+ case TraceLog::EVENT_BEGIN:
+ etw_type = kTraceEventTypeBegin;
break;
- case base::TraceLog::EVENT_END:
- etw_type = base::kTraceEventTypeEnd;
+ case TraceLog::EVENT_END:
+ etw_type = kTraceEventTypeEnd;
break;
- case base::TraceLog::EVENT_INSTANT:
- etw_type = base::kTraceEventTypeInstant;
+ case TraceLog::EVENT_INSTANT:
+ etw_type = kTraceEventTypeInstant;
break;
default:
NOTREACHED() << "Unknown event type";
- etw_type = base::kTraceEventTypeInstant;
+ etw_type = kTraceEventTypeInstant;
break;
}
- EtwMofEvent<5> event(base::kTraceEventClass32,
+ EtwMofEvent<5> event(kTraceEventClass32,
etw_type,
TRACE_LEVEL_INFORMATION);
event.SetField(0, name_len + 1, name);
@@ -74,7 +79,7 @@ void TraceLog::TraceEvent(const char* name,
// See whether we're to capture a backtrace.
void* backtrace[32];
- if (enable_flags() & base::CAPTURE_STACK_TRACE) {
+ if (enable_flags() & CAPTURE_STACK_TRACE) {
DWORD hash = 0;
DWORD depth = CaptureStackBackTrace(0,
arraysize(backtrace),
@@ -110,4 +115,5 @@ void TraceLog::Resurrect() {
StaticMemorySingletonTraits<TraceLog>::Resurrect();
}
+} // namespace debug
} // namespace base
diff --git a/base/trace_event_win.h b/base/debug/trace_event_win.h
index 77ab3fb..dd3f512 100644
--- a/base/trace_event_win.h
+++ b/base/debug/trace_event_win.h
@@ -3,40 +3,44 @@
// found in the LICENSE file.
// This file contains the Windows-specific declarations for trace_event.h.
-#ifndef BASE_TRACE_EVENT_WIN_H_
-#define BASE_TRACE_EVENT_WIN_H_
+#ifndef BASE_DEBUG_TRACE_EVENT_WIN_H_
+#define BASE_DEBUG_TRACE_EVENT_WIN_H_
#pragma once
#include <string>
-#include "base/event_trace_provider_win.h"
+#include "base/win/event_trace_provider.h"
#define TRACE_EVENT_BEGIN(name, id, extra) \
- base::TraceLog::Trace(name, \
- base::TraceLog::EVENT_BEGIN, \
- reinterpret_cast<const void*>(id), \
- extra);
+ base::debug::TraceLog::Trace( \
+ name, \
+ base::debug::TraceLog::EVENT_BEGIN, \
+ reinterpret_cast<const void*>(id), \
+ extra);
#define TRACE_EVENT_END(name, id, extra) \
- base::TraceLog::Trace(name, \
- base::TraceLog::EVENT_END, \
- reinterpret_cast<const void*>(id), \
- extra);
+ base::debug::TraceLog::Trace( \
+ name, \
+ base::debug::TraceLog::EVENT_END, \
+ reinterpret_cast<const void*>(id), \
+ extra);
#define TRACE_EVENT_INSTANT(name, id, extra) \
- base::TraceLog::Trace(name, \
- base::TraceLog::EVENT_INSTANT, \
- reinterpret_cast<const void*>(id), \
- extra);
+ base::debug::TraceLog::Trace( \
+ name, \
+ base::debug::TraceLog::EVENT_INSTANT, \
+ reinterpret_cast<const void*>(id), \
+ extra);
// Fwd.
template <typename Type>
struct StaticMemorySingletonTraits;
namespace base {
+namespace debug {
// This EtwTraceProvider subclass implements ETW logging
// for the macros above on Windows.
-class TraceLog : public EtwTraceProvider {
+class TraceLog : public base::win::EtwTraceProvider {
public:
enum EventType {
EVENT_BEGIN,
@@ -95,7 +99,7 @@ class TraceLog : public EtwTraceProvider {
// string will be used.
void TraceEvent(const char* name,
size_t name_len,
- base::TraceLog::EventType type,
+ EventType type,
const void* id,
const char* extra,
size_t extra_len);
@@ -122,9 +126,9 @@ extern const GUID kTraceEventClass32;
extern const GUID kTraceEventClass64;
// The ETW event types, IDs 0x00-0x09 are reserved, so start at 0x10.
-const EtwEventType kTraceEventTypeBegin = 0x10;
-const EtwEventType kTraceEventTypeEnd = 0x11;
-const EtwEventType kTraceEventTypeInstant = 0x12;
+const base::win::EtwEventType kTraceEventTypeBegin = 0x10;
+const base::win::EtwEventType kTraceEventTypeEnd = 0x11;
+const base::win::EtwEventType kTraceEventTypeInstant = 0x12;
// If this flag is set in enable flags
enum TraceEventFlags {
@@ -141,6 +145,7 @@ enum TraceEventFlags {
// Forward decl.
struct TraceLogSingletonTraits;
+} // nemspace debug
} // namespace base
-#endif // BASE_TRACE_EVENT_WIN_H_
+#endif // BASE_DEBUG_TRACE_EVENT_WIN_H_
diff --git a/base/trace_event_win_unittest.cc b/base/debug/trace_event_win_unittest.cc
index 79a48e3..8544bc7 100644
--- a/base/trace_event_win_unittest.cc
+++ b/base/debug/trace_event_win_unittest.cc
@@ -2,21 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/trace_event.h"
+#include "base/debug/trace_event.h"
#include <strstream>
#include "base/at_exit.h"
#include "base/basictypes.h"
#include "base/file_util.h"
-#include "base/event_trace_consumer_win.h"
-#include "base/event_trace_controller_win.h"
+#include "base/win/event_trace_consumer.h"
+#include "base/win/event_trace_controller.h"
#include "base/win/windows_version.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <initguid.h> // NOLINT - must be last include.
+namespace base {
+namespace debug {
+
namespace {
+
using testing::_;
using testing::AnyNumber;
using testing::InSequence;
@@ -24,6 +28,11 @@ using testing::Ge;
using testing::Le;
using testing::NotNull;
+using base::win::EtwEventType;
+using base::win::EtwTraceConsumerBase;
+using base::win::EtwTraceController;
+using base::win::EtwTraceProperties;
+
// Data for unittests traces.
const char kEmpty[] = "";
const char kName[] = "unittest.trace_name";
@@ -81,7 +90,7 @@ class TraceEventTest: public testing::Test {
}
void SetUp() {
- bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
+ bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
if (is_xp) {
// Tear down any dangling session from an earlier failing test.
@@ -94,10 +103,10 @@ class TraceEventTest: public testing::Test {
// start the private, in-proc session, but on XP we need the global
// session created and the provider enabled before we register our
// provider.
- base::TraceLog* tracelog = NULL;
+ TraceLog* tracelog = NULL;
if (!is_xp) {
- base::TraceLog::Resurrect();
- tracelog = base::TraceLog::Get();
+ TraceLog::Resurrect();
+ tracelog = TraceLog::Get();
ASSERT_TRUE(tracelog != NULL);
ASSERT_FALSE(tracelog->IsTracing());
}
@@ -127,13 +136,13 @@ class TraceEventTest: public testing::Test {
// Enable the TraceLog provider GUID.
ASSERT_HRESULT_SUCCEEDED(
- controller_.EnableProvider(base::kChromeTraceProviderName,
+ controller_.EnableProvider(kChromeTraceProviderName,
TRACE_LEVEL_INFORMATION,
0));
if (is_xp) {
- base::TraceLog::Resurrect();
- tracelog = base::TraceLog::Get();
+ TraceLog::Resurrect();
+ tracelog = TraceLog::Get();
}
ASSERT_TRUE(tracelog != NULL);
EXPECT_TRUE(tracelog->IsTracing());
@@ -186,7 +195,7 @@ class TraceEventTest: public testing::Test {
private:
// We want our singleton torn down after each test.
- base::ShadowingAtExitManager at_exit_manager_;
+ ShadowingAtExitManager at_exit_manager_;
EtwTraceController controller_;
FilePath log_file_;
TestEventConsumer consumer_;
@@ -202,67 +211,67 @@ TEST_F(TraceEventTest, TraceLog) {
InSequence in_sequence;
// Full argument version, passing lengths explicitly.
- base::TraceLog::Trace(kName,
+ TraceLog::Trace(kName,
strlen(kName),
- base::TraceLog::EVENT_BEGIN,
+ TraceLog::EVENT_BEGIN,
kId,
kExtra,
strlen(kExtra));
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeBegin,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeBegin,
kName, strlen(kName),
kId,
kExtra, strlen(kExtra));
// Const char* version.
- base::TraceLog::Trace(static_cast<const char*>(kName),
- base::TraceLog::EVENT_END,
+ TraceLog::Trace(static_cast<const char*>(kName),
+ TraceLog::EVENT_END,
kId,
static_cast<const char*>(kExtra));
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeEnd,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeEnd,
kName, strlen(kName),
kId,
kExtra, strlen(kExtra));
// std::string extra version.
- base::TraceLog::Trace(static_cast<const char*>(kName),
- base::TraceLog::EVENT_INSTANT,
+ TraceLog::Trace(static_cast<const char*>(kName),
+ TraceLog::EVENT_INSTANT,
kId,
std::string(kExtra));
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeInstant,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeInstant,
kName, strlen(kName),
kId,
kExtra, strlen(kExtra));
// Test for sanity on NULL inputs.
- base::TraceLog::Trace(NULL,
+ TraceLog::Trace(NULL,
0,
- base::TraceLog::EVENT_BEGIN,
+ TraceLog::EVENT_BEGIN,
kId,
NULL,
0);
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeBegin,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeBegin,
kEmpty, 0,
kId,
kEmpty, 0);
- base::TraceLog::Trace(NULL,
+ TraceLog::Trace(NULL,
-1,
- base::TraceLog::EVENT_END,
+ TraceLog::EVENT_END,
kId,
NULL,
-1);
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeEnd,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeEnd,
kEmpty, 0,
kId,
kEmpty, 0);
@@ -277,25 +286,28 @@ TEST_F(TraceEventTest, Macros) {
InSequence in_sequence;
TRACE_EVENT_BEGIN(kName, kId, kExtra);
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeBegin,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeBegin,
kName, strlen(kName),
kId,
kExtra, strlen(kExtra));
TRACE_EVENT_END(kName, kId, kExtra);
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeEnd,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeEnd,
kName, strlen(kName),
kId,
kExtra, strlen(kExtra));
TRACE_EVENT_INSTANT(kName, kId, kExtra);
- ExpectEvent(base::kTraceEventClass32,
- base::kTraceEventTypeInstant,
+ ExpectEvent(kTraceEventClass32,
+ kTraceEventTypeInstant,
kName, strlen(kName),
kId,
kExtra, strlen(kExtra));
PlayLog();
}
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug_on_start.cc b/base/debug_on_start.cc
index 9cabde5..15dab05 100644
--- a/base/debug_on_start.cc
+++ b/base/debug_on_start.cc
@@ -8,7 +8,7 @@
#include "base/base_switches.h"
#include "base/basictypes.h"
-#include "base/debug_util.h"
+#include "base/debug/debugger.h"
// Minimalist implementation to try to find a command line argument. We can use
// kernel32 exported functions but not the CRT functions because we're too early
@@ -56,13 +56,13 @@ int __cdecl DebugOnStart::Init() {
// - Do a int3.
// It will fails if we run in a sandbox. That is expected.
- DebugUtil::SpawnDebuggerOnProcess(GetCurrentProcessId());
+ base::debug::SpawnDebuggerOnProcess(GetCurrentProcessId());
// Wait for a debugger to come take us.
- DebugUtil::WaitForDebugger(60, false);
+ base::debug::WaitForDebugger(60, false);
} else if (FindArgument(GetCommandLine(), switches::kWaitForDebugger)) {
// Wait for a debugger to come take us.
- DebugUtil::WaitForDebugger(60, true);
+ base::debug::WaitForDebugger(60, true);
}
return 0;
}
diff --git a/base/debug_util.cc b/base/debug_util.cc
index 21f5b70..4773de3 100644
--- a/base/debug_util.cc
+++ b/base/debug_util.cc
@@ -4,25 +4,4 @@
#include "base/debug_util.h"
-#include "base/platform_thread.h"
-
bool DebugUtil::suppress_dialogs_ = false;
-
-bool DebugUtil::WaitForDebugger(int wait_seconds, bool silent) {
- for (int i = 0; i < wait_seconds * 10; ++i) {
- if (BeingDebugged()) {
- if (!silent)
- BreakDebugger();
- return true;
- }
- PlatformThread::Sleep(100);
- }
- return false;
-}
-
-const void *const *StackTrace::Addresses(size_t* count) {
- *count = count_;
- if (count_)
- return trace_;
- return NULL;
-}
diff --git a/base/debug_util.h b/base/debug_util.h
index a7dba3a..a643ccf 100644
--- a/base/debug_util.h
+++ b/base/debug_util.h
@@ -2,78 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This is a cross platform interface for helper functions related to debuggers.
-// You should use this to test if you're running under a debugger, and if you
-// would like to yield (breakpoint) into the debugger.
-
#ifndef BASE_DEBUG_UTIL_H_
#define BASE_DEBUG_UTIL_H_
#pragma once
-#include <iosfwd>
-
-#include "base/basictypes.h"
-
-#if defined(OS_WIN)
-struct _EXCEPTION_POINTERS;
-#endif
-
-// A stacktrace can be helpful in debugging. For example, you can include a
-// stacktrace member in a object (probably around #ifndef NDEBUG) so that you
-// can later see where the given object was created from.
-class StackTrace {
- public:
- // Creates a stacktrace from the current location
- StackTrace();
-
- // Note that the default copy constructor and assignment constructors
- // are OK.
-
-#if defined(OS_WIN)
- // Creates a stacktrace for an exception.
- // Note: this function will throw an import not found (StackWalk64) exception
- // on system without dbghelp 5.1.
- StackTrace(_EXCEPTION_POINTERS* exception_pointers);
-#endif
- // Gets an array of instruction pointer values.
- // count: (output) the number of elements in the returned array
- const void *const *Addresses(size_t* count);
- // Prints a backtrace to stderr
- void PrintBacktrace();
-
- // Resolves backtrace to symbols and write to stream.
- void OutputToStream(std::ostream* os);
-
- private:
- // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
- // the sum of FramesToSkip and FramesToCapture must be less than 63,
- // so set it to 62. Even if on POSIX it could be a larger value, it usually
- // doesn't give much more information.
- static const int MAX_TRACES = 62;
- void* trace_[MAX_TRACES];
- int count_;
-};
+#include "build/build_config.h"
class DebugUtil {
public:
- // Starts the registered system-wide JIT debugger to attach it to specified
- // process.
- static bool SpawnDebuggerOnProcess(unsigned process_id);
-
- // Waits wait_seconds seconds for a debugger to attach to the current process.
- // When silent is false, an exception is thrown when a debugger is detected.
- static bool WaitForDebugger(int wait_seconds, bool silent);
-
- // Are we running under a debugger?
- // On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
- // To get around this, this function caches its value.
- // WARNING: Because of this, on OS X, a call MUST be made to this function
- // BEFORE the sandbox is enabled.
- static bool BeingDebugged();
-
- // Break into the debugger, assumes a debugger is present.
- static void BreakDebugger();
-
#if defined(OS_MACOSX)
// On Mac OS X, it can take a really long time for the OS crash handler to
// process a Chrome crash when debugging symbols are available. This
@@ -87,6 +23,10 @@ class DebugUtil {
suppress_dialogs_ = true;
}
+ static bool AreDialogsSuppressed() {
+ return suppress_dialogs_;
+ }
+
private:
// If true, avoid displaying any dialogs that could cause problems
// in non-interactive environments.
diff --git a/base/debug_util_mac.cc b/base/debug_util_mac.cc
index 78679f2..a4eed66 100644
--- a/base/debug_util_mac.cc
+++ b/base/debug_util_mac.cc
@@ -5,6 +5,7 @@
#include "base/debug_util.h"
#include <signal.h>
+#include <unistd.h>
#include "base/basictypes.h"
diff --git a/base/file_util_mac.mm b/base/file_util_mac.mm
index 811799c..43bf6e9 100644
--- a/base/file_util_mac.mm
+++ b/base/file_util_mac.mm
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/string_util.h"
+#include "base/thread_restrictions.h"
namespace file_util {
@@ -26,6 +27,7 @@ bool GetShmemTempDir(FilePath* path) {
}
bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
return (copyfile(from_path.value().c_str(),
to_path.value().c_str(), NULL, COPYFILE_ALL) == 0);
}
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 18a17d1..85123e9 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -39,6 +39,7 @@
#include "base/singleton.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#include "base/thread_restrictions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -48,6 +49,7 @@ namespace {
// Helper for NormalizeFilePath(), defined below.
bool RealPath(const FilePath& path, FilePath* real_path) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For realpath().
FilePath::CharType buf[PATH_MAX];
if (!realpath(path.value().c_str(), buf))
return false;
@@ -63,11 +65,13 @@ bool RealPath(const FilePath& path, FilePath* real_path) {
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
typedef struct stat stat_wrapper_t;
static int CallStat(const char *path, stat_wrapper_t *sb) {
+ base::ThreadRestrictions::AssertIOAllowed();
return stat(path, sb);
}
#else
typedef struct stat64 stat_wrapper_t;
static int CallStat(const char *path, stat_wrapper_t *sb) {
+ base::ThreadRestrictions::AssertIOAllowed();
return stat64(path, sb);
}
#endif
@@ -80,6 +84,7 @@ static const char* kTempFileName = ".org.chromium.XXXXXX";
#endif
bool AbsolutePath(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For realpath().
char full_path[PATH_MAX];
if (realpath(path->value().c_str(), full_path) == NULL)
return false;
@@ -89,6 +94,7 @@ bool AbsolutePath(FilePath* path) {
int CountFilesCreatedAfter(const FilePath& path,
const base::Time& comparison_time) {
+ base::ThreadRestrictions::AssertIOAllowed();
int file_count = 0;
DIR* dir = opendir(path.value().c_str());
@@ -139,6 +145,7 @@ int CountFilesCreatedAfter(const FilePath& path,
// that functionality. If not, remove from file_util_win.cc, otherwise add it
// here.
bool Delete(const FilePath& path, bool recursive) {
+ base::ThreadRestrictions::AssertIOAllowed();
const char* path_str = path.value().c_str();
stat_wrapper_t file_info;
int test = CallStat(path_str, &file_info);
@@ -178,6 +185,7 @@ bool Delete(const FilePath& path, bool recursive) {
}
bool Move(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
// Windows compatibility: if to_path exists, from_path and to_path
// must be the same type, either both files, or both directories.
stat_wrapper_t to_file_info;
@@ -202,12 +210,14 @@ bool Move(const FilePath& from_path, const FilePath& to_path) {
}
bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
return (rename(from_path.value().c_str(), to_path.value().c_str()) == 0);
}
bool CopyDirectory(const FilePath& from_path,
const FilePath& to_path,
bool recursive) {
+ base::ThreadRestrictions::AssertIOAllowed();
// Some old callers of CopyDirectory want it to support wildcards.
// After some discussion, we decided to fix those callers.
// Break loudly here if anyone tries to do this.
@@ -307,14 +317,17 @@ bool CopyDirectory(const FilePath& from_path,
}
bool PathExists(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
return access(path.value().c_str(), F_OK) == 0;
}
bool PathIsWritable(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
return access(path.value().c_str(), W_OK) == 0;
}
bool DirectoryExists(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
stat_wrapper_t file_info;
if (CallStat(path.value().c_str(), &file_info) == 0)
return S_ISDIR(file_info.st_mode);
@@ -365,6 +378,7 @@ bool ReadFromFD(int fd, char* buffer, size_t bytes) {
// file descriptor. |path| is set to the temporary file path.
// This function does NOT unlink() the file.
int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp().
*path = directory.Append(kTempFileName);
const std::string& tmpdir_string = path->value();
// this should be OK since mkstemp just replaces characters in place
@@ -374,6 +388,7 @@ int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
}
bool CreateTemporaryFile(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For call to close().
FilePath directory;
if (!GetTempDir(&directory))
return false;
@@ -401,6 +416,7 @@ FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
}
bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For call to close().
int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
return ((fd >= 0) && !close(fd));
}
@@ -408,6 +424,7 @@ bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
const FilePath::StringType& name_tmpl,
FilePath* new_dir) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdtemp().
CHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
<< "Directory name template must contain \"XXXXXX\".";
@@ -443,6 +460,7 @@ bool CreateNewTempDirectory(const FilePath::StringType& prefix,
}
bool CreateDirectory(const FilePath& full_path) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdir().
std::vector<FilePath> subpaths;
// Collect a list of all parent directories.
@@ -484,6 +502,7 @@ bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
}
bool GetInode(const FilePath& path, ino_t* inode) {
+ base::ThreadRestrictions::AssertIOAllowed(); // For call to stat().
struct stat buffer;
int result = stat(path.value().c_str(), &buffer);
if (result < 0)
@@ -498,10 +517,12 @@ FILE* OpenFile(const std::string& filename, const char* mode) {
}
FILE* OpenFile(const FilePath& filename, const char* mode) {
+ base::ThreadRestrictions::AssertIOAllowed();
return fopen(filename.value().c_str(), mode);
}
int ReadFile(const FilePath& filename, char* data, int size) {
+ base::ThreadRestrictions::AssertIOAllowed();
int fd = open(filename.value().c_str(), O_RDONLY);
if (fd < 0)
return -1;
@@ -513,6 +534,7 @@ int ReadFile(const FilePath& filename, char* data, int size) {
}
int WriteFile(const FilePath& filename, const char* data, int size) {
+ base::ThreadRestrictions::AssertIOAllowed();
int fd = creat(filename.value().c_str(), 0666);
if (fd < 0)
return -1;
@@ -540,6 +562,9 @@ int WriteFileDescriptor(const int fd, const char* data, int size) {
// Gets the current working directory for the process.
bool GetCurrentDirectory(FilePath* dir) {
+ // getcwd can return ENOENT, which implies it checks against the disk.
+ base::ThreadRestrictions::AssertIOAllowed();
+
char system_buffer[PATH_MAX] = "";
if (!getcwd(system_buffer, sizeof(system_buffer))) {
NOTREACHED();
@@ -551,6 +576,7 @@ bool GetCurrentDirectory(FilePath* dir) {
// Sets the current working directory for the process.
bool SetCurrentDirectory(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
int ret = chdir(path.value().c_str());
return !ret;
}
@@ -655,6 +681,7 @@ FilePath FileEnumerator::Next() {
bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
const FilePath& source, bool show_links) {
+ base::ThreadRestrictions::AssertIOAllowed();
DIR* dir = opendir(source.value().c_str());
if (!dir)
return false;
@@ -703,6 +730,8 @@ MemoryMappedFile::MemoryMappedFile()
}
bool MemoryMappedFile::MapFileToMemoryInternal() {
+ base::ThreadRestrictions::AssertIOAllowed();
+
struct stat file_stat;
if (fstat(file_, &file_stat) == base::kInvalidPlatformFileValue) {
LOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno;
@@ -719,6 +748,8 @@ bool MemoryMappedFile::MapFileToMemoryInternal() {
}
void MemoryMappedFile::CloseHandles() {
+ base::ThreadRestrictions::AssertIOAllowed();
+
if (data_ != NULL)
munmap(data_, length_);
if (file_ != base::kInvalidPlatformFileValue)
@@ -771,6 +802,9 @@ FilePath GetHomeDir() {
if (home_dir && home_dir[0])
return FilePath(home_dir);
+ // g_get_home_dir calls getpwent, which can fall through to LDAP calls.
+ base::ThreadRestrictions::AssertIOAllowed();
+
home_dir = g_get_home_dir();
if (home_dir && home_dir[0])
return FilePath(home_dir);
@@ -784,6 +818,7 @@ FilePath GetHomeDir() {
}
bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
int infile = open(from_path.value().c_str(), O_RDONLY);
if (infile < 0)
return false;
diff --git a/base/file_util_proxy.cc b/base/file_util_proxy.cc
index fc96e8f..bd08909 100644
--- a/base/file_util_proxy.cc
+++ b/base/file_util_proxy.cc
@@ -66,7 +66,7 @@ static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy(
return base::PLATFORM_FILE_OK;
}
-} // anonymous namespace
+} // anonymous namespace
class MessageLoopRelay
: public base::RefCountedThreadSafe<MessageLoopRelay> {
@@ -442,7 +442,7 @@ class RelayReadDirectory : public MessageLoopRelay {
file_util::FileEnumerator::DIRECTORIES));
FilePath current;
while (!(current = file_enum.Next()).empty()) {
- base::file_util_proxy::Entry entry;
+ base::FileUtilProxy::Entry entry;
file_util::FileEnumerator::FindInfo info;
file_enum.GetFindInfo(&info);
entry.is_directory = file_enum.IsDirectory(info);
@@ -461,7 +461,7 @@ class RelayReadDirectory : public MessageLoopRelay {
private:
base::FileUtilProxy::ReadDirectoryCallback* callback_;
FilePath file_path_;
- std::vector<base::file_util_proxy::Entry> entries_;
+ std::vector<base::FileUtilProxy::Entry> entries_;
};
class RelayGetFileInfo : public MessageLoopRelay {
diff --git a/base/file_util_proxy.h b/base/file_util_proxy.h
index 09c2377..f266562 100644
--- a/base/file_util_proxy.h
+++ b/base/file_util_proxy.h
@@ -16,35 +16,30 @@
namespace base {
-namespace file_util_proxy {
-
-// Holds metadata for file or directory entry.
-struct Entry {
- FilePath::StringType name;
- bool is_directory;
-};
-
-} // namespace file_util_proxy
-
class MessageLoopProxy;
class Time;
// This class provides asynchronous access to common file routines.
class FileUtilProxy {
public:
+ // Holds metadata for file or directory entry. Used by ReadDirectoryCallback.
+ struct Entry {
+ FilePath::StringType name;
+ bool is_directory;
+ };
+
// This callback is used by methods that report only an error code. It is
// valid to pass NULL as the callback parameter to any function that takes a
// StatusCallback, in which case the operation will complete silently.
- typedef Callback1<base::PlatformFileError /* error code */
- >::Type StatusCallback;
+ typedef Callback1<PlatformFileError /* error code */>::Type StatusCallback;
// Creates or opens a file with the given flags. It is invalid to pass NULL
// for the callback.
// If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to create
// a new file at the given |file_path| and calls back with
// PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists.
- typedef Callback3<base::PlatformFileError /* error code */,
- base::PassPlatformFile,
+ typedef Callback3<PlatformFileError /* error code */,
+ PassPlatformFile,
bool /* created */>::Type CreateOrOpenCallback;
static bool CreateOrOpen(scoped_refptr<MessageLoopProxy> message_loop_proxy,
const FilePath& file_path,
@@ -53,8 +48,8 @@ class FileUtilProxy {
// Creates a temporary file for writing. The path and an open file handle
// are returned. It is invalid to pass NULL for the callback.
- typedef Callback3<base::PlatformFileError /* error code */,
- base::PassPlatformFile,
+ typedef Callback3<PlatformFileError /* error code */,
+ PassPlatformFile,
FilePath>::Type CreateTemporaryCallback;
static bool CreateTemporary(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
@@ -62,7 +57,7 @@ class FileUtilProxy {
// Close the given file handle.
static bool Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile,
+ PlatformFile,
StatusCallback* callback);
// Ensures that the given |file_path| exist. This creates a empty new file
@@ -74,7 +69,7 @@ class FileUtilProxy {
// is set PLATFORM_FILE_OK.
// If the file hasn't existed but it couldn't be created for some other
// reasons, |created| is set false and |error code| indicates the error.
- typedef Callback2<base::PlatformFileError /* error code */,
+ typedef Callback2<PlatformFileError /* error code */,
bool /* created */>::Type EnsureFileExistsCallback;
static bool EnsureFileExists(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
@@ -83,8 +78,8 @@ class FileUtilProxy {
// Retrieves the information about a file. It is invalid to pass NULL for the
// callback.
- typedef Callback2<base::PlatformFileError /* error code */,
- const base::PlatformFileInfo& /* file_info */
+ typedef Callback2<PlatformFileError /* error code */,
+ const PlatformFileInfo& /* file_info */
>::Type GetFileInfoCallback;
static bool GetFileInfo(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
@@ -93,12 +88,11 @@ class FileUtilProxy {
static bool GetFileInfoFromPlatformFile(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile file,
+ PlatformFile file,
GetFileInfoCallback* callback);
- typedef Callback2<base::PlatformFileError /* error code */,
- const std::vector<base::file_util_proxy::Entry>&
- >::Type ReadDirectoryCallback;
+ typedef Callback2<PlatformFileError /* error code */,
+ const std::vector<Entry>&>::Type ReadDirectoryCallback;
static bool ReadDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy,
const FilePath& file_path,
ReadDirectoryCallback* callback);
@@ -148,11 +142,11 @@ class FileUtilProxy {
// Reads from a file. On success, the file pointer is moved to position
// |offset + bytes_to_read| in the file. The callback can be NULL.
- typedef Callback2<base::PlatformFileError /* error code */,
+ typedef Callback2<PlatformFileError /* error code */,
int /* bytes read/written */>::Type ReadWriteCallback;
static bool Read(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile file,
+ PlatformFile file,
int64 offset,
char* buffer,
int bytes_to_read,
@@ -163,7 +157,7 @@ class FileUtilProxy {
// |offset + bytes_to_write| in the file. The callback can be NULL.
static bool Write(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile file,
+ PlatformFile file,
int64 offset,
const char* buffer,
int bytes_to_write,
@@ -172,17 +166,17 @@ class FileUtilProxy {
// Touches a file. The callback can be NULL.
static bool Touch(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile file,
- const base::Time& last_access_time,
- const base::Time& last_modified_time,
+ PlatformFile file,
+ const Time& last_access_time,
+ const Time& last_modified_time,
StatusCallback* callback);
// Touches a file. The callback can be NULL.
static bool Touch(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
const FilePath& file_path,
- const base::Time& last_access_time,
- const base::Time& last_modified_time,
+ const Time& last_access_time,
+ const Time& last_modified_time,
StatusCallback* callback);
// Truncates a file to the given length. If |length| is greater than the
@@ -190,7 +184,7 @@ class FileUtilProxy {
// The callback can be NULL.
static bool Truncate(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile file,
+ PlatformFile file,
int64 length,
StatusCallback* callback);
@@ -206,7 +200,7 @@ class FileUtilProxy {
// Flushes a file. The callback can be NULL.
static bool Flush(
scoped_refptr<MessageLoopProxy> message_loop_proxy,
- base::PlatformFile file,
+ PlatformFile file,
StatusCallback* callback);
private:
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 30d314f..4645acc 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -19,6 +19,7 @@
#include "base/win/scoped_handle.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/thread_restrictions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/win_util.h"
@@ -35,6 +36,8 @@ const DWORD kFileShareAll =
// Helper for NormalizeFilePath(), defined below.
bool DevicePathToDriveLetterPath(const FilePath& device_path,
FilePath* drive_letter_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// Get the mapping of drive letters to device paths.
const int kDriveMappingSize = 1024;
wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
@@ -75,6 +78,7 @@ bool DevicePathToDriveLetterPath(const FilePath& device_path,
} // namespace
std::wstring GetDirectoryFromPath(const std::wstring& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
wchar_t path_buffer[MAX_PATH];
wchar_t* file_ptr = NULL;
if (GetFullPathName(path.c_str(), MAX_PATH, path_buffer, &file_ptr) == 0)
@@ -87,6 +91,7 @@ std::wstring GetDirectoryFromPath(const std::wstring& path) {
}
bool AbsolutePath(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed();
wchar_t file_path_buf[MAX_PATH];
if (!_wfullpath(file_path_buf, path->value().c_str(), MAX_PATH))
return false;
@@ -96,6 +101,8 @@ bool AbsolutePath(FilePath* path) {
int CountFilesCreatedAfter(const FilePath& path,
const base::Time& comparison_time) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
int file_count = 0;
FILETIME comparison_filetime(comparison_time.ToFileTime());
@@ -123,6 +130,8 @@ int CountFilesCreatedAfter(const FilePath& path,
}
bool Delete(const FilePath& path, bool recursive) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
if (path.value().length() >= MAX_PATH)
return false;
@@ -161,6 +170,8 @@ bool Delete(const FilePath& path, bool recursive) {
}
bool DeleteAfterReboot(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
if (path.value().length() >= MAX_PATH)
return false;
@@ -170,6 +181,8 @@ bool DeleteAfterReboot(const FilePath& path) {
}
bool Move(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// NOTE: I suspect we could support longer paths, but that would involve
// analyzing all our usage of files.
if (from_path.value().length() >= MAX_PATH ||
@@ -189,6 +202,8 @@ bool Move(const FilePath& from_path, const FilePath& to_path) {
}
bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// Make sure that the target file exists.
HANDLE target_file = ::CreateFile(
to_path.value().c_str(),
@@ -208,6 +223,8 @@ bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
}
bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// NOTE: I suspect we could support longer paths, but that would involve
// analyzing all our usage of files.
if (from_path.value().length() >= MAX_PATH ||
@@ -220,6 +237,8 @@ bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
bool recursive) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// NOTE: I suspect we could support longer paths, but that would involve
// analyzing all our usage of files.
if (from_path.value().length() >= MAX_PATH ||
@@ -251,6 +270,8 @@ bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
bool recursive) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
if (recursive)
return ShellCopy(from_path, to_path, true);
@@ -274,6 +295,7 @@ bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
bool CopyAndDeleteDirectory(const FilePath& from_path,
const FilePath& to_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (CopyDirectory(from_path, to_path, true)) {
if (Delete(from_path, true)) {
return true;
@@ -288,10 +310,12 @@ bool CopyAndDeleteDirectory(const FilePath& from_path,
bool PathExists(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
}
bool PathIsWritable(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
HANDLE dir =
CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
@@ -304,6 +328,7 @@ bool PathIsWritable(const FilePath& path) {
}
bool DirectoryExists(const FilePath& path) {
+ base::ThreadRestrictions::AssertIOAllowed();
DWORD fileattr = GetFileAttributes(path.value().c_str());
if (fileattr != INVALID_FILE_ATTRIBUTES)
return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
@@ -312,6 +337,7 @@ bool DirectoryExists(const FilePath& path) {
bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
LPSYSTEMTIME creation_time) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (!file_handle)
return false;
@@ -328,6 +354,7 @@ bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
bool GetFileCreationLocalTime(const std::wstring& filename,
LPSYSTEMTIME creation_time) {
+ base::ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file_handle(
CreateFile(filename.c_str(), GENERIC_READ, kFileShareAll, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
@@ -335,6 +362,8 @@ bool GetFileCreationLocalTime(const std::wstring& filename,
}
bool ResolveShortcut(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
HRESULT result;
base::win::ScopedComPtr<IShellLink> i_shell_link;
bool is_resolved = false;
@@ -370,6 +399,8 @@ bool CreateShortcutLink(const wchar_t *source, const wchar_t *destination,
const wchar_t *working_dir, const wchar_t *arguments,
const wchar_t *description, const wchar_t *icon,
int icon_index, const wchar_t* app_id) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// Length of arguments and description must be less than MAX_PATH.
DCHECK(lstrlen(arguments) < MAX_PATH);
DCHECK(lstrlen(description) < MAX_PATH);
@@ -421,6 +452,8 @@ bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination,
const wchar_t *working_dir, const wchar_t *arguments,
const wchar_t *description, const wchar_t *icon,
int icon_index, const wchar_t* app_id) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// Length of arguments and description must be less than MAX_PATH.
DCHECK(lstrlen(arguments) < MAX_PATH);
DCHECK(lstrlen(description) < MAX_PATH);
@@ -467,6 +500,8 @@ bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination,
}
bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// "Pin to taskbar" is only supported after Win7.
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return false;
@@ -477,6 +512,8 @@ bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
}
bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// "Unpin from taskbar" is only supported after Win7.
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return false;
@@ -487,6 +524,8 @@ bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
}
bool GetTempDir(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
wchar_t temp_path[MAX_PATH + 1];
DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
if (path_len >= MAX_PATH || path_len <= 0)
@@ -503,6 +542,8 @@ bool GetShmemTempDir(FilePath* path) {
}
bool CreateTemporaryFile(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
FilePath temp_file;
if (!GetTempDir(path))
@@ -517,6 +558,7 @@ bool CreateTemporaryFile(FilePath* path) {
}
FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed();
return CreateAndOpenTemporaryFile(path);
}
@@ -525,6 +567,7 @@ FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
// TODO(jrg): is there equivalent call to use on Windows instead of
// going 2-step?
FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (!CreateTemporaryFileInDir(dir, path)) {
return NULL;
}
@@ -536,6 +579,8 @@ FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
bool CreateTemporaryFileInDir(const FilePath& dir,
FilePath* temp_file) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
wchar_t temp_name[MAX_PATH + 1];
if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
@@ -558,6 +603,8 @@ bool CreateTemporaryFileInDir(const FilePath& dir,
bool CreateTemporaryDirInDir(const FilePath& base_dir,
const FilePath::StringType& prefix,
FilePath* new_dir) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
FilePath path_to_create;
srand(static_cast<uint32>(time(NULL)));
@@ -582,6 +629,8 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
bool CreateNewTempDirectory(const FilePath::StringType& prefix,
FilePath* new_temp_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
FilePath system_temp_dir;
if (!GetTempDir(&system_temp_dir))
return false;
@@ -590,6 +639,8 @@ bool CreateNewTempDirectory(const FilePath::StringType& prefix,
}
bool CreateDirectory(const FilePath& full_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// If the path exists, we've succeeded if it's a directory, failed otherwise.
const wchar_t* full_path_str = full_path.value().c_str();
DWORD fileattr = ::GetFileAttributes(full_path_str);
@@ -636,6 +687,8 @@ bool CreateDirectory(const FilePath& full_path) {
}
bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
WIN32_FILE_ATTRIBUTE_DATA attr;
if (!GetFileAttributesEx(file_path.value().c_str(),
GetFileExInfoStandard, &attr)) {
@@ -657,15 +710,18 @@ bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
}
FILE* OpenFile(const FilePath& filename, const char* mode) {
+ base::ThreadRestrictions::AssertIOAllowed();
std::wstring w_mode = ASCIIToWide(std::string(mode));
return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
}
FILE* OpenFile(const std::string& filename, const char* mode) {
+ base::ThreadRestrictions::AssertIOAllowed();
return _fsopen(filename.c_str(), mode, _SH_DENYNO);
}
int ReadFile(const FilePath& filename, char* data, int size) {
+ base::ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -684,6 +740,7 @@ int ReadFile(const FilePath& filename, char* data, int size) {
}
int WriteFile(const FilePath& filename, const char* data, int size) {
+ base::ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
GENERIC_WRITE,
0,
@@ -718,6 +775,8 @@ int WriteFile(const FilePath& filename, const char* data, int size) {
bool RenameFileAndResetSecurityDescriptor(const FilePath& source_file_path,
const FilePath& target_file_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
// The parameters to SHFileOperation must be terminated with 2 NULL chars.
std::wstring source = source_file_path.value();
std::wstring target = target_file_path.value();
@@ -740,6 +799,8 @@ bool RenameFileAndResetSecurityDescriptor(const FilePath& source_file_path,
// Gets the current working directory for the process.
bool GetCurrentDirectory(FilePath* dir) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
wchar_t system_buffer[MAX_PATH];
system_buffer[0] = 0;
DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
@@ -755,6 +816,7 @@ bool GetCurrentDirectory(FilePath* dir) {
// Sets the current working directory for the process.
bool SetCurrentDirectory(const FilePath& directory) {
+ base::ThreadRestrictions::AssertIOAllowed();
BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
return ret != 0;
}
@@ -812,6 +874,8 @@ FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
}
FilePath FileEnumerator::Next() {
+ base::ThreadRestrictions::AssertIOAllowed();
+
while (has_find_data_ || !pending_paths_.empty()) {
if (!has_find_data_) {
// The last find FindFirstFile operation is done, prepare a new one.
@@ -883,6 +947,8 @@ MemoryMappedFile::MemoryMappedFile()
}
bool MemoryMappedFile::MapFileToMemoryInternal() {
+ base::ThreadRestrictions::AssertIOAllowed();
+
if (file_ == INVALID_HANDLE_VALUE)
return false;
@@ -926,12 +992,14 @@ void MemoryMappedFile::CloseHandles() {
bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
const base::Time& cutoff_time) {
+ base::ThreadRestrictions::AssertIOAllowed();
long result = CompareFileTime(&find_info.ftLastWriteTime,
&cutoff_time.ToFileTime());
return result == 1 || result == 0;
}
bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
FilePath mapped_file;
if (!NormalizeToNativeFilePath(path, &mapped_file))
return false;
@@ -943,6 +1011,7 @@ bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
}
bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
// In Vista, GetFinalPathNameByHandle() would give us the real path
// from a file handle. If we ever deprecate XP, consider changing the
// code below to a call to GetFinalPathNameByHandle(). The method this
@@ -998,6 +1067,7 @@ bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
bool PreReadImage(const wchar_t* file_path, size_t size_to_read,
size_t step_size) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (base::win::GetVersion() > base::win::VERSION_XP) {
// Vista+ branch. On these OSes, the forced reads through the DLL actually
// slows warm starts. The solution is to sequentially read file contents
diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc
index d1049b8..6c69708 100644
--- a/base/file_version_info_win.cc
+++ b/base/file_version_info_win.cc
@@ -10,12 +10,14 @@
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "base/thread_restrictions.h"
// This has to be last.
#include <strsafe.h>
FileVersionInfoWin::FileVersionInfoWin(void* data, int language, int code_page)
: language_(language), code_page_(code_page) {
+ base::ThreadRestrictions::AssertIOAllowed();
data_.reset((char*) data);
fixed_file_info_ = NULL;
UINT size;
@@ -43,6 +45,8 @@ FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() {
// static
FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
const FilePath& file_path) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
DWORD dummy;
const wchar_t* path = file_path.value().c_str();
DWORD length = ::GetFileVersionInfoSize(path, &dummy);
diff --git a/base/gtk_util.cc b/base/gtk_util.cc
deleted file mode 100644
index 79fc485..0000000
--- a/base/gtk_util.cc
+++ /dev/null
@@ -1,49 +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/gtk_util.h"
-
-namespace gtk_util {
-
-namespace {
-
-// Common implementation of ConvertAcceleratorsFromWindowsStyle() and
-// RemoveWindowsStyleAccelerators().
-// Replaces all ampersands (as used in our grd files to indicate mnemonics)
-// to |target|. Similarly any underscores get replaced with two underscores as
-// is needed by pango.
-std::string ConvertAmperstandsTo(const std::string& label,
- const std::string& target) {
- std::string ret;
- ret.reserve(label.length() * 2);
- for (size_t i = 0; i < label.length(); ++i) {
- if ('_' == label[i]) {
- ret.push_back('_');
- ret.push_back('_');
- } else if ('&' == label[i]) {
- if (i + 1 < label.length() && '&' == label[i + 1]) {
- ret.push_back('&');
- ++i;
- } else {
- ret.append(target);
- }
- } else {
- ret.push_back(label[i]);
- }
- }
-
- return ret;
-}
-
-} // namespace
-
-std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) {
- return ConvertAmperstandsTo(label, "_");
-}
-
-std::string RemoveWindowsStyleAccelerators(const std::string& label) {
- return ConvertAmperstandsTo(label, "");
-}
-
-} // namespace gtk_util
diff --git a/base/gtk_util.h b/base/gtk_util.h
deleted file mode 100644
index 435780d..0000000
--- a/base/gtk_util.h
+++ /dev/null
@@ -1,22 +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_GTK_UTIL_H_
-#define BASE_GTK_UTIL_H_
-#pragma once
-
-#include <string>
-
-namespace gtk_util {
-
-// Change windows accelerator style to GTK style. (GTK uses _ for
-// accelerators. Windows uses & with && as an escape for &.)
-std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label);
-
-// Removes the "&" accelerators from a Windows label.
-std::string RemoveWindowsStyleAccelerators(const std::string& label);
-
-} // namespace gtk_util
-
-#endif // BASE_GTK_UTIL_H_
diff --git a/base/hmac_openssl.cc b/base/hmac_openssl.cc
new file mode 100644
index 0000000..f45d3a7
--- /dev/null
+++ b/base/hmac_openssl.cc
@@ -0,0 +1,57 @@
+// 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/hmac.h"
+
+#include <openssl/hmac.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/openssl_util.h"
+#include "base/scoped_ptr.h"
+#include "base/stl_util-inl.h"
+
+namespace base {
+
+struct HMACPlatformData {
+ std::vector<unsigned char> key;
+};
+
+HMAC::HMAC(HashAlgorithm hash_alg)
+ : hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
+ // Only SHA-1 and SHA-256 hash algorithms are supported now.
+ DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256);
+}
+
+bool HMAC::Init(const unsigned char* key, int key_length) {
+ // Init must not be called more than once on the same HMAC object.
+ DCHECK(plat_->key.empty());
+
+ plat_->key.assign(key, key + key_length);
+ return true;
+}
+
+HMAC::~HMAC() {
+ // Zero out key copy.
+ plat_->key.assign(plat_->key.size(), 0);
+ STLClearObject(&plat_->key);
+}
+
+bool HMAC::Sign(const std::string& data,
+ unsigned char* digest,
+ int digest_length) {
+ DCHECK_GE(digest_length, 0);
+ DCHECK(!plat_->key.empty()); // Init must be called before Sign.
+
+ ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest, digest_length);
+ return ::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(),
+ &plat_->key[0], plat_->key.size(),
+ reinterpret_cast<const unsigned char*>(data.data()),
+ data.size(),
+ result.safe_buffer(), NULL);
+}
+
+} // namespace base
diff --git a/base/i18n/icu_string_conversions.cc b/base/i18n/icu_string_conversions.cc
index 9014a7b..c353feb 100644
--- a/base/i18n/icu_string_conversions.cc
+++ b/base/i18n/icu_string_conversions.cc
@@ -9,9 +9,11 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "unicode/ucnv.h"
#include "unicode/ucnv_cb.h"
#include "unicode/ucnv_err.h"
+#include "unicode/unorm.h"
#include "unicode/ustring.h"
namespace base {
@@ -264,4 +266,28 @@ bool CodepageToWide(const std::string& encoded,
#endif // defined(WCHAR_T_IS_UTF32)
}
+bool ConvertToUtf8AndNormalize(const std::string& text,
+ const std::string& charset,
+ std::string* result) {
+ result->clear();
+ string16 utf16;
+ if (!CodepageToUTF16(
+ text, charset.c_str(), OnStringConversionError::FAIL, &utf16))
+ return false;
+
+ UErrorCode status = U_ZERO_ERROR;
+ size_t max_length = utf16.length() + 1;
+ string16 normalized_utf16;
+ int actual_length = unorm_normalize(
+ utf16.c_str(), utf16.length(), UNORM_NFC, 0,
+ WriteInto(&normalized_utf16, max_length),
+ static_cast<int>(max_length), &status);
+ if (!U_SUCCESS(status))
+ return false;
+ normalized_utf16.resize(actual_length);
+
+ return UTF16ToUTF8(normalized_utf16.data(),
+ normalized_utf16.length(), result);
+}
+
} // namespace base
diff --git a/base/i18n/icu_string_conversions.h b/base/i18n/icu_string_conversions.h
index 1495cae..901771b 100644
--- a/base/i18n/icu_string_conversions.h
+++ b/base/i18n/icu_string_conversions.h
@@ -64,6 +64,12 @@ bool CodepageToWide(const std::string& encoded,
OnStringConversionError::Type on_error,
std::wstring* wide);
+// Converts from any codepage to UTF-8 and ensures the resulting UTF-8 is
+// normalized.
+bool ConvertToUtf8AndNormalize(const std::string& text,
+ const std::string& charset,
+ std::string* result);
+
} // namespace base
#endif // BASE_I18N_ICU_STRING_CONVERSIONS_H_
diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc
index 2083fa9..40b0fed 100644
--- a/base/i18n/icu_string_conversions_unittest.cc
+++ b/base/i18n/icu_string_conversions_unittest.cc
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -325,4 +326,33 @@ TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) {
}
}
+static const struct {
+ const char* encoded;
+ const char* codepage_name;
+ bool expected_success;
+ const char* expected_value;
+} kConvertAndNormalizeCases[] = {
+ {"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"},
+ {"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"},
+ {"foo-\xe4.html", "foo-bar", false, ""},
+ {"foo-\xff.html", "ascii", false, ""},
+ {"foo.html", "ascii", true, "foo.html"},
+ {"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"},
+ {"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"},
+ {"\xA7\x41\xA6\x6E", "big5", true, "\xE4\xBD\xA0\xE5\xA5\xBD"},
+ // Windows-1258 does have a combining character at xD2 (which is U+0309).
+ // The sequence of (U+00E2, U+0309) is also encoded as U+1EA9.
+ {"foo\xE2\xD2", "windows-1258", true, "foo\xE1\xBA\xA9"},
+};
+TEST(ICUStringConversionsTest, ConvertToUtf8AndNormalize) {
+ std::string result;
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertAndNormalizeCases); ++i) {
+ bool success = ConvertToUtf8AndNormalize(
+ kConvertAndNormalizeCases[i].encoded,
+ kConvertAndNormalizeCases[i].codepage_name, &result);
+ EXPECT_EQ(kConvertAndNormalizeCases[i].expected_success, success);
+ EXPECT_EQ(kConvertAndNormalizeCases[i].expected_value, result);
+ }
+}
+
} // namespace base
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index f5381a2..9ff12d8 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -18,25 +18,57 @@
#include <gtk/gtk.h>
#endif
+namespace {
+
+// Extract language and country, ignore keywords, concatenate using dash.
+std::string GetLocaleString(const icu::Locale& locale) {
+ const char* language = locale.getLanguage();
+ const char* country = locale.getCountry();
+
+ std::string result =
+ (language != NULL && *language != '\0') ? language : "und";
+
+ if (country != NULL && *country != '\0') {
+ result += '-';
+ result += country;
+ }
+
+ return result;
+}
+
+} // namespace
+
namespace base {
namespace i18n {
// Represents the locale-specific ICU text direction.
static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
+#if defined(OS_WIN)
void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) {
// Later we may have to change this to be OS-dependent so that
// it's not affected by ICU's default locale. It's all right
// to do this way because SetICUDefaultLocale is internal
// to this file and we know that it's not yet called when this function
// is called.
- icu::Locale locale = icu::Locale::getDefault();
+ const icu::Locale& locale = icu::Locale::getDefault();
const char* language = locale.getLanguage();
const char* country = locale.getCountry();
DCHECK(language);
*lang = language;
*region = country;
}
+#endif
+
+// Convert the ICU default locale to a string.
+std::string GetConfiguredLocale() {
+ return GetLocaleString(icu::Locale::getDefault());
+}
+
+// Convert the ICU canonicalized locale to a string.
+std::string GetCanonicalLocale(const char* locale) {
+ return GetLocaleString(icu::Locale::createCanonical(locale));
+}
// Convert Chrome locale name to ICU locale name
std::string ICULocaleName(const std::string& locale_string) {
@@ -50,13 +82,14 @@ std::string ICULocaleName(const std::string& locale_string) {
// locale. If it's es-RR other than es-ES, map to es-RR. Otherwise, map
// to es-MX (the most populous in Spanish-speaking Latin America).
if (LowerCaseEqualsASCII(locale_string, "es-419")) {
- std::string lang, region;
- GetLanguageAndRegionFromOS(&lang, &region);
- if (LowerCaseEqualsASCII(lang, "es") &&
- !LowerCaseEqualsASCII(region, "es")) {
- lang.append("-");
- lang.append(region);
- return lang;
+ const icu::Locale& locale = icu::Locale::getDefault();
+ std::string language = locale.getLanguage();
+ const char* country = locale.getCountry();
+ if (LowerCaseEqualsASCII(language, "es") &&
+ !LowerCaseEqualsASCII(country, "es")) {
+ language += '-';
+ language += country;
+ return language;
}
return "es-MX";
}
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
index 2fe932c..52b1a2b 100644
--- a/base/i18n/rtl.h
+++ b/base/i18n/rtl.h
@@ -29,8 +29,18 @@ enum TextDirection {
LEFT_TO_RIGHT,
};
-// Get language and region from the OS.
+#if defined(OS_WIN)
+// Get language and region from the OS. Used by Chrome Frame.
void GetLanguageAndRegionFromOS(std::string* lang, std::string* region);
+#endif
+
+// Get the locale that the currently running process has been configured to use.
+// The return value is of the form language[-country] (e.g., en-US) where the
+// language is the 2 or 3 letter code from ISO-639.
+std::string GetConfiguredLocale();
+
+// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name.
+std::string GetCanonicalLocale(const char* locale);
// Sets the default locale of ICU.
// Once the application locale of Chrome in GetApplicationLocale is determined,
@@ -136,7 +146,7 @@ void WrapPathWithLTRFormatting(const FilePath& path,
// string is wrapped with LRE (Left-To-Right Embedding) and PDF (Pop
// Directional Formatting) marks and returned. In LTR locale, the string itself
// is returned.
-string16 GetDisplayStringInLTRDirectionality(const string16& text)
+string16 GetDisplayStringInLTRDirectionality(const string16& text)
WARN_UNUSED_RESULT;
// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C)
diff --git a/base/leak_tracker_unittest.cc b/base/leak_tracker_unittest.cc
deleted file mode 100644
index 0217b17..0000000
--- a/base/leak_tracker_unittest.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2009 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/leak_tracker.h"
-#include "base/scoped_ptr.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class ClassA {
- private:
- base::LeakTracker<ClassA> leak_tracker_;
-};
-
-class ClassB {
- private:
- base::LeakTracker<ClassB> leak_tracker_;
-};
-
-#ifndef ENABLE_LEAK_TRACKER
-
-// If leak tracking is disabled, we should do nothing.
-TEST(LeakTrackerTest, NotEnabled) {
- EXPECT_EQ(-1, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(-1, base::LeakTracker<ClassB>::NumLiveInstances());
-
- // Use scoped_ptr so compiler doesn't complain about unused variables.
- scoped_ptr<ClassA> a1(new ClassA);
- scoped_ptr<ClassB> b1(new ClassB);
- scoped_ptr<ClassB> b2(new ClassB);
-
- EXPECT_EQ(-1, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(-1, base::LeakTracker<ClassB>::NumLiveInstances());
-}
-
-#else
-
-TEST(LeakTrackerTest, Basic) {
- {
- ClassA a1;
-
- EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(0, base::LeakTracker<ClassB>::NumLiveInstances());
-
- ClassB b1;
- ClassB b2;
-
- EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(2, base::LeakTracker<ClassB>::NumLiveInstances());
-
- scoped_ptr<ClassA> a2(new ClassA);
-
- EXPECT_EQ(2, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(2, base::LeakTracker<ClassB>::NumLiveInstances());
-
- a2.reset();
-
- EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(2, base::LeakTracker<ClassB>::NumLiveInstances());
- }
-
- EXPECT_EQ(0, base::LeakTracker<ClassA>::NumLiveInstances());
- EXPECT_EQ(0, base::LeakTracker<ClassB>::NumLiveInstances());
-}
-
-// Try some orderings of create/remove to hit different cases in the linked-list
-// assembly.
-TEST(LeakTrackerTest, LinkedList) {
- EXPECT_EQ(0, base::LeakTracker<ClassB>::NumLiveInstances());
-
- scoped_ptr<ClassA> a1(new ClassA);
- scoped_ptr<ClassA> a2(new ClassA);
- scoped_ptr<ClassA> a3(new ClassA);
- scoped_ptr<ClassA> a4(new ClassA);
-
- EXPECT_EQ(4, base::LeakTracker<ClassA>::NumLiveInstances());
-
- // Remove the head of the list (a1).
- a1.reset();
- EXPECT_EQ(3, base::LeakTracker<ClassA>::NumLiveInstances());
-
- // Remove the tail of the list (a4).
- a4.reset();
- EXPECT_EQ(2, base::LeakTracker<ClassA>::NumLiveInstances());
-
- // Append to the new tail of the list (a3).
- scoped_ptr<ClassA> a5(new ClassA);
- EXPECT_EQ(3, base::LeakTracker<ClassA>::NumLiveInstances());
-
- a2.reset();
- a3.reset();
-
- EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
-
- a5.reset();
- EXPECT_EQ(0, base::LeakTracker<ClassA>::NumLiveInstances());
-}
-
-TEST(LeakTrackerTest, NoOpCheckForLeaks) {
- // There are no live instances of ClassA, so this should do nothing.
- base::LeakTracker<ClassA>::CheckForLeaks();
-}
-
-#endif // ENABLE_LEAK_TRACKER
-
-} // namespace
diff --git a/base/logging.cc b/base/logging.cc
index 46f22c5..92dd33d 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -42,7 +42,8 @@ typedef pthread_mutex_t* MutexHandle;
#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/debug_util.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
#include "base/eintr_wrapper.h"
#include "base/lock_impl.h"
#if defined(OS_POSIX)
@@ -224,7 +225,7 @@ class LoggingLock {
#if DEBUG
// Keep the error code for debugging
int error = GetLastError(); // NOLINT
- DebugUtil::BreakDebugger();
+ base::debug::BreakDebugger();
#endif
// Return nicely without putting initialized to true.
return;
@@ -339,7 +340,7 @@ bool InitializeLogFileHandle() {
return true;
}
-void BaseInitLoggingImpl(const PathChar* new_log_file,
+bool BaseInitLoggingImpl(const PathChar* new_log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
OldFileDeletionState delete_old) {
@@ -357,7 +358,8 @@ void BaseInitLoggingImpl(const PathChar* new_log_file,
command_line->HasSwitch(switches::kVModule)) {
g_vlog_info =
new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
- command_line->GetSwitchValueASCII(switches::kVModule));
+ command_line->GetSwitchValueASCII(switches::kVModule),
+ &min_log_level);
}
#endif
@@ -377,7 +379,7 @@ void BaseInitLoggingImpl(const PathChar* new_log_file,
// ignore file options if logging is disabled or only to system
if (logging_destination == LOG_NONE ||
logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
- return;
+ return true;
if (!log_file_name)
log_file_name = new PathString();
@@ -385,17 +387,21 @@ void BaseInitLoggingImpl(const PathChar* new_log_file,
if (delete_old == DELETE_OLD_LOG_FILE)
DeleteFilePath(*log_file_name);
- InitializeLogFileHandle();
+ return InitializeLogFileHandle();
}
void SetMinLogLevel(int level) {
- min_log_level = level;
+ min_log_level = std::min(LOG_ERROR_REPORT, level);
}
int GetMinLogLevel() {
return min_log_level;
}
+int GetVlogVerbosity() {
+ return std::max(-1, LOG_INFO - GetMinLogLevel());
+}
+
int GetVlogLevelHelper(const char* file, size_t N) {
#ifdef ANDROID
return 0;
@@ -403,8 +409,12 @@ int GetVlogLevelHelper(const char* file, size_t N) {
DCHECK_GT(N, 0U);
return g_vlog_info ?
g_vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
+<<<<<<< HEAD
VlogInfo::kDefaultVlogLevel;
#endif
+=======
+ GetVlogVerbosity();
+>>>>>>> chromium.org at r65505
}
void SetLogItems(bool enable_process_id, bool enable_thread_id,
@@ -431,6 +441,10 @@ void SetLogMessageHandler(LogMessageHandlerFunction handler) {
log_message_handler = handler;
}
+LogMessageHandlerFunction GetLogMessageHandler() {
+ return log_message_handler;
+}
+
// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// Explicit instantiations for commonly used comparisons.
@@ -515,39 +529,39 @@ LogMessage::SaveLastError::~SaveLastError() {
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
int ctr)
- : severity_(severity) {
+ : severity_(severity), file_(file), line_(line) {
Init(file, line);
}
LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
- : severity_(LOG_FATAL) {
+ : severity_(LOG_FATAL), file_(file), line_(line) {
Init(file, line);
stream_ << "Check failed: " << (*result.str_);
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
const CheckOpString& result)
- : severity_(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) {
+ : severity_(LOG_INFO), file_(file), line_(line) {
Init(file, line);
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
- : severity_(severity) {
+ : 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) {
- // log only the filename
- const char* last_slash = strrchr(file, '\\');
- if (last_slash)
- file = last_slash + 1;
+ 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.
@@ -576,8 +590,12 @@ void LogMessage::Init(const char* file, int line) {
}
if (log_tickcount)
stream_ << TickCount() << ':';
- stream_ << log_severity_names[severity_] << ":" << file <<
- "(" << line << ")] ";
+ if (severity_ >= 0)
+ stream_ << log_severity_names[severity_];
+ else
+ stream_ << "VERBOSE" << -severity_;
+
+ stream_ << ":" << file << "(" << line << ")] ";
message_start_ = stream_.tellp();
}
@@ -592,7 +610,7 @@ LogMessage::~LogMessage() {
#ifndef NDEBUG
if (severity_ == LOG_FATAL) {
// Include a stack trace on a fatal.
- StackTrace trace;
+ base::debug::StackTrace trace;
stream_ << std::endl; // Newline to separate from log message.
trace.OutputToStream(&stream_);
}
@@ -601,8 +619,11 @@ LogMessage::~LogMessage() {
std::string str_newline(stream_.str());
// Give any log message handler first dibs on the message.
- if (log_message_handler && log_message_handler(severity_, str_newline))
+ if (log_message_handler && log_message_handler(severity_, file_, line_,
+ message_start_, str_newline)) {
+ // The handler took care of it, no further processing.
return;
+ }
if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
@@ -649,8 +670,8 @@ LogMessage::~LogMessage() {
if (severity_ == LOG_FATAL) {
// display a message or break into the debugger on a fatal error
- if (DebugUtil::BeingDebugged()) {
- DebugUtil::BreakDebugger();
+ if (base::debug::BeingDebugged()) {
+ base::debug::BreakDebugger();
} else {
if (log_assert_handler) {
// make a copy of the string for the handler out of paranoia
@@ -665,7 +686,7 @@ LogMessage::~LogMessage() {
DisplayDebugMessageInDialog(stream_.str());
#endif
// Crash the process to generate a dump.
- DebugUtil::BreakDebugger();
+ base::debug::BreakDebugger();
}
}
} else if (severity_ == LOG_ERROR_REPORT) {
@@ -804,7 +825,7 @@ void RawLog(int level, const char* message) {
}
if (level == LOG_FATAL)
- DebugUtil::BreakDebugger();
+ base::debug::BreakDebugger();
}
} // namespace logging
diff --git a/base/logging.h b/base/logging.h
index 981669a..6689eec 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -81,16 +81,22 @@
//
// These always log at the INFO log level (when they log at all).
// The verbose logging can also be turned on module-by-module. For instance,
-// --vmodule=profile=2,icon_loader=1,browser_*=3 --v=0
+// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
// will cause:
// a. VLOG(2) and lower messages to be printed from profile.{h,cc}
// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
// c. VLOG(3) and lower messages to be printed from files prefixed with
// "browser"
-// d. VLOG(0) and lower messages to be printed from elsewhere
+// d. VLOG(4) and lower messages to be printed from files under a
+// "chromeos" directory.
+// e. VLOG(0) and lower messages to be printed from elsewhere
//
// The wildcarding functionality shown by (c) supports both '*' (match
-// 0 or more characters) and '?' (match any single character) wildcards.
+// 0 or more characters) and '?' (match any single character)
+// wildcards. Any pattern containing a forward or backward slash will
+// be tested against the whole pathname and not just the module.
+// E.g., "*/foo/bar/*=2" would change the logging level for all code
+// in source files under a "foo/bar" directory.
//
// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
//
@@ -179,7 +185,7 @@ typedef char PathChar;
// Implementation of the InitLogging() method declared below. We use a
// more-specific name so we can #define it above without affecting other code
// that has named stuff "InitLogging".
-void BaseInitLoggingImpl(const PathChar* log_file,
+bool BaseInitLoggingImpl(const PathChar* log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
OldFileDeletionState delete_old);
@@ -194,22 +200,27 @@ void BaseInitLoggingImpl(const PathChar* log_file,
// The default log file is initialized to "debug.log" in the application
// directory. You probably don't want this, especially since the program
// directory may not be writable on an enduser's system.
-inline void InitLogging(const PathChar* log_file,
+inline bool InitLogging(const PathChar* log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
OldFileDeletionState delete_old) {
- BaseInitLoggingImpl(log_file, logging_dest, lock_log, delete_old);
+ return BaseInitLoggingImpl(log_file, logging_dest, lock_log, delete_old);
}
// Sets the log level. Anything at or above this level will be written to the
// log file/displayed to the user (if applicable). Anything below this level
-// will be silently ignored. The log level defaults to 0 (everything is logged)
-// if this function is not called.
+// will be silently ignored. The log level defaults to 0 (everything is logged
+// up to level INFO) if this function is not called.
+// Note that log messages for VLOG(x) are logged at level -x, so setting
+// the min log level to negative values enables verbose logging.
void SetMinLogLevel(int level);
// Gets the current log level.
int GetMinLogLevel();
+// Gets the VLOG default verbosity level.
+int GetVlogVerbosity();
+
// Gets the current vlog level for the given file (usually taken from
// __FILE__).
@@ -239,6 +250,7 @@ void SetShowErrorDialogs(bool enable_dialogs);
// (e.g. a silent one for Unit Tests)
typedef void (*LogAssertHandlerFunction)(const std::string& str);
void SetLogAssertHandler(LogAssertHandlerFunction handler);
+
// Sets the Log Report Handler that will be used to notify of check failures
// in non-debug mode. The default handler shows a dialog box and continues
// the execution, however clients can use this function to override with their
@@ -250,10 +262,15 @@ void SetLogReportHandler(LogReportHandlerFunction handler);
// it's sent to other log destinations (if any).
// Returns true to signal that it handled the message and the message
// should not be sent to other log destinations.
-typedef bool (*LogMessageHandlerFunction)(int severity, const std::string& str);
+typedef bool (*LogMessageHandlerFunction)(int severity,
+ const char* file, int line, size_t message_start, const std::string& str);
void SetLogMessageHandler(LogMessageHandlerFunction handler);
+LogMessageHandlerFunction GetLogMessageHandler();
typedef int LogSeverity;
+const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity
+// Note: the log severities are used to index into the array of names,
+// see log_severity_names.
const LogSeverity LOG_INFO = 0;
const LogSeverity LOG_WARNING = 1;
const LogSeverity LOG_ERROR = 2;
@@ -310,6 +327,10 @@ const LogSeverity LOG_DFATAL = LOG_FATAL;
// Needed for LOG_IS_ON(ERROR).
const LogSeverity LOG_0 = LOG_ERROR;
+// As special cases, we can assume that LOG_IS_ON(ERROR_REPORT) and
+// LOG_IS_ON(FATAL) always hold. Also, LOG_IS_ON(DFATAL) always holds
+// in debug mode. In particular, CHECK()s will always fire if they
+// fail.
#define LOG_IS_ON(severity) \
((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
@@ -342,9 +363,16 @@ const LogSeverity LOG_0 = LOG_ERROR;
#define SYSLOG(severity) LOG(severity)
#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
-#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
-#define VLOG_IF(verboselevel, condition) \
- LOG_IF(INFO, VLOG_IS_ON(verboselevel) && (condition))
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+ logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
@@ -392,9 +420,6 @@ const LogSeverity LOG_0 = LOG_ERROR;
//
// We make sure CHECK et al. always evaluates their arguments, as
// doing CHECK(FunctionWithSideEffect()) is a common idiom.
-//
-// TODO(akalin): Fix the problem where if the min log level is >
-// FATAL, CHECK() et al. won't terminate the program.
#define CHECK(condition) \
LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
<< "Check failed: " #condition ". "
@@ -451,43 +476,28 @@ extern template std::string* MakeCheckOpString<std::string, std::string>(
#val1 " " #op " " #val2)) \
logging::LogMessage(__FILE__, __LINE__, _result).stream()
-// Helper functions for string comparisons.
-// To avoid bloat, the definitions are in logging.cc.
-//
-// TODO(akalin): Actually have the implementations in logging.cc, or
-// remove these.
-#define DECLARE_CHECK_STROP_IMPL(func, expected) \
- std::string* Check##func##expected##Impl(const char* s1, \
- const char* s2, \
- const char* names);
-DECLARE_CHECK_STROP_IMPL(strcmp, true)
-DECLARE_CHECK_STROP_IMPL(strcmp, false)
-DECLARE_CHECK_STROP_IMPL(_stricmp, true)
-DECLARE_CHECK_STROP_IMPL(_stricmp, false)
-#undef DECLARE_CHECK_STROP_IMPL
-
-// Helper macro for string comparisons.
-// Don't use this macro directly in your code, use CHECK_STREQ et al below.
-#define CHECK_STROP(func, op, expected, s1, s2) \
- while (CheckOpString _result = \
- logging::Check##func##expected##Impl((s1), (s2), \
- #s1 " " #op " " #s2)) \
- LOG(FATAL) << *_result.str_
-
-// String (char*) equality/inequality checks.
-// CASE versions are case-insensitive.
-//
-// Note that "s1" and "s2" may be temporary strings which are destroyed
-// by the compiler at the end of the current "full expression"
-// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
-
-#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
-#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
-#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(_stricmp, ==, true, s1, s2)
-#define CHECK_STRCASENE(s1, s2) CHECK_STROP(_stricmp, !=, false, s1, s2)
-
-#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
-#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (v1 op v2) return NULL; \
+ else return MakeCheckOpString(v1, v2, names); \
+ } \
+ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+ if (v1 op v2) return NULL; \
+ else return MakeCheckOpString(v1, v2, names); \
+ }
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, < )
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, > )
+#undef DEFINE_CHECK_OP_IMPL
#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
@@ -525,6 +535,7 @@ DECLARE_CHECK_STROP_IMPL(_stricmp, false)
#if ENABLE_DLOG
+#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
@@ -540,6 +551,7 @@ DECLARE_CHECK_STROP_IMPL(_stricmp, false)
#define DLOG_EAT_STREAM_PARAMETERS \
true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+#define DLOG_IS_ON(severity) false
#define DLOG_IF(severity, condition) DLOG_EAT_STREAM_PARAMETERS
#define DLOG_ASSERT(condition) DLOG_EAT_STREAM_PARAMETERS
#define DPLOG_IF(severity, condition) DLOG_EAT_STREAM_PARAMETERS
@@ -559,8 +571,6 @@ enum { DEBUG_MODE = ENABLE_DLOG };
#undef ENABLE_DLOG
-#define DLOG_IS_ON(severity) (::logging::DEBUG_MODE && LOG_IS_ON(severity))
-
#define DLOG(severity) \
LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
@@ -586,51 +596,56 @@ enum { DEBUG_MODE = ENABLE_DLOG };
#if defined(NDEBUG)
-// 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)
-#define DCHECK_SEVERITY ERROR_REPORT
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ 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))
#else // defined(NDEBUG)
-// On a regular debug build, we want to have DCHECKS enabled.
-#define DCHECK_IS_ON() (true)
-#define DCHECK_SEVERITY FATAL
+// On a regular debug build, we want to have DCHECKs enabled.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
const LogSeverity LOG_DCHECK = LOG_FATAL;
+#define DCHECK_IS_ON() true
#endif // defined(NDEBUG)
#else // ENABLE_DCHECK
-#define DCHECK_IS_ON() (false)
-#define DCHECK_SEVERITY FATAL
-const LogSeverity LOG_DCHECK = LOG_FATAL;
+// These are just dummy values since DCHECK_IS_ON() is always false in
+// this case.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
+const LogSeverity LOG_DCHECK = LOG_INFO;
+#define DCHECK_IS_ON() false
#endif // ENABLE_DCHECK
+#undef ENABLE_DCHECK
-// Unlike CHECK et al., DCHECK et al. *does* evaluate their arguments
-// lazily.
-
-// DCHECK et al. also make sure to reference |condition| regardless of
+// DCHECK et al. make sure to reference |condition| regardless of
// whether DCHECKs are enabled; this is so that we don't get unused
// variable warnings if the only use of a variable is in a DCHECK.
// This behavior is different from DLOG_IF et al.
-#define DCHECK(condition) \
- !DCHECK_IS_ON() ? (void) 0 : \
- LOG_IF(DCHECK_SEVERITY, !(condition)) \
+#define DCHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
<< "Check failed: " #condition ". "
-#define DPCHECK(condition) \
- !DCHECK_IS_ON() ? (void) 0 : \
- PLOG_IF(DCHECK_SEVERITY, !(condition)) \
+#define DPCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
<< "Check failed: " #condition ". "
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
- if (DLOG_IS_ON(DCHECK_SEVERITY)) \
+ if (DCHECK_IS_ON()) \
if (logging::CheckOpString _result = \
logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
@@ -638,9 +653,10 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
__FILE__, __LINE__, ::logging::LOG_DCHECK, \
_result).stream()
-// Equality/Inequality checks - compare two values, and log a LOG_FATAL message
-// including the two values when the result is not as expected. The values
-// must have operator<<(ostream, ...) defined.
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected. The values must have operator<<(ostream, ...)
+// defined.
//
// You may append to the error message like so:
// DCHECK_NE(1, 2) << ": The world must be ending!";
@@ -663,49 +679,6 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
-// Helper macro for string comparisons.
-// Don't use this macro directly in your code, use DCHECK_STREQ et al below.
-#define DCHECK_STROP(func, op, expected, s1, s2) \
- if (DCHECK_IS_ON()) CHECK_STROP(func, op, expected, s1, s2)
-
-// String (char*) equality/inequality checks.
-// CASE versions are case-insensitive.
-//
-// Note that "s1" and "s2" may be temporary strings which are destroyed
-// by the compiler at the end of the current "full expression"
-// (e.g. DCHECK_STREQ(Foo().c_str(), Bar().c_str())).
-
-#define DCHECK_STREQ(s1, s2) DCHECK_STROP(strcmp, ==, true, s1, s2)
-#define DCHECK_STRNE(s1, s2) DCHECK_STROP(strcmp, !=, false, s1, s2)
-#define DCHECK_STRCASEEQ(s1, s2) DCHECK_STROP(_stricmp, ==, true, s1, s2)
-#define DCHECK_STRCASENE(s1, s2) DCHECK_STROP(_stricmp, !=, false, s1, s2)
-
-#define DCHECK_INDEX(I,A) DCHECK(I < (sizeof(A)/sizeof(A[0])))
-#define DCHECK_BOUND(B,A) DCHECK(B <= (sizeof(A)/sizeof(A[0])))
-
-// Helper functions for CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-#define DEFINE_CHECK_OP_IMPL(name, op) \
- template <class t1, class t2> \
- inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
- const char* names) { \
- if (v1 op v2) return NULL; \
- else return MakeCheckOpString(v1, v2, names); \
- } \
- inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
- if (v1 op v2) return NULL; \
- else return MakeCheckOpString(v1, v2, names); \
- }
-DEFINE_CHECK_OP_IMPL(EQ, ==)
-DEFINE_CHECK_OP_IMPL(NE, !=)
-DEFINE_CHECK_OP_IMPL(LE, <=)
-DEFINE_CHECK_OP_IMPL(LT, < )
-DEFINE_CHECK_OP_IMPL(GE, >=)
-DEFINE_CHECK_OP_IMPL(GT, > )
-#undef DEFINE_CHECK_OP_IMPL
-
#define NOTREACHED() DCHECK(false)
// Redefine the standard assert to use our nice log files
@@ -761,6 +734,10 @@ class LogMessage {
std::ostringstream stream_;
size_t message_start_; // Offset of the start of the message (past prefix
// info).
+ // The file and line information passed in to the constructor.
+ const char* file_;
+ const int line_;
+
#if defined(OS_WIN)
// Stores the current value of GetLastError in the constructor and restores
// it in the destructor by calling SetLastError.
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
index fa28ec6..4b7fdbc 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -14,23 +14,35 @@ namespace {
using ::testing::Return;
+// Needs to be global since log assert handlers can't maintain state.
+int log_sink_call_count = 0;
+
+void LogSink(const std::string& str) {
+ ++log_sink_call_count;
+}
+
// Class to make sure any manipulations we do to the min log level are
// contained (i.e., do not affect other unit tests).
-class MinLogLevelSaver {
+class LogStateSaver {
public:
- MinLogLevelSaver() : old_min_log_level_(GetMinLogLevel()) {}
+ LogStateSaver() : old_min_log_level_(GetMinLogLevel()) {}
- ~MinLogLevelSaver() { SetMinLogLevel(old_min_log_level_); }
+ ~LogStateSaver() {
+ SetMinLogLevel(old_min_log_level_);
+ SetLogAssertHandler(NULL);
+ SetLogReportHandler(NULL);
+ log_sink_call_count = 0;
+ }
private:
int old_min_log_level_;
- DISALLOW_COPY_AND_ASSIGN(MinLogLevelSaver);
+ DISALLOW_COPY_AND_ASSIGN(LogStateSaver);
};
class LoggingTest : public testing::Test {
private:
- MinLogLevelSaver min_log_level_saver_;
+ LogStateSaver log_state_saver_;
};
class MockLogSource {
@@ -68,6 +80,64 @@ TEST_F(LoggingTest, BasicLogging) {
DVLOG_IF(0, true) << mock_log_source.Log();
}
+TEST_F(LoggingTest, LogIsOn) {
+#if defined(NDEBUG)
+ const bool kDfatalIsFatal = false;
+#else // defined(NDEBUG)
+ const bool kDfatalIsFatal = true;
+#endif // defined(NDEBUG)
+
+ SetMinLogLevel(LOG_INFO);
+ EXPECT_TRUE(LOG_IS_ON(INFO));
+ EXPECT_TRUE(LOG_IS_ON(WARNING));
+ EXPECT_TRUE(LOG_IS_ON(ERROR));
+ EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+ EXPECT_TRUE(LOG_IS_ON(FATAL));
+ EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+ SetMinLogLevel(LOG_WARNING);
+ EXPECT_FALSE(LOG_IS_ON(INFO));
+ EXPECT_TRUE(LOG_IS_ON(WARNING));
+ EXPECT_TRUE(LOG_IS_ON(ERROR));
+ EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+ EXPECT_TRUE(LOG_IS_ON(FATAL));
+ EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+ SetMinLogLevel(LOG_ERROR);
+ EXPECT_FALSE(LOG_IS_ON(INFO));
+ EXPECT_FALSE(LOG_IS_ON(WARNING));
+ EXPECT_TRUE(LOG_IS_ON(ERROR));
+ EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+ EXPECT_TRUE(LOG_IS_ON(FATAL));
+ EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+ SetMinLogLevel(LOG_ERROR_REPORT);
+ EXPECT_FALSE(LOG_IS_ON(INFO));
+ EXPECT_FALSE(LOG_IS_ON(WARNING));
+ EXPECT_FALSE(LOG_IS_ON(ERROR));
+ EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+ EXPECT_TRUE(LOG_IS_ON(FATAL));
+ EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL));
+
+ // LOG_IS_ON(ERROR_REPORT) should always be true.
+ SetMinLogLevel(LOG_FATAL);
+ EXPECT_FALSE(LOG_IS_ON(INFO));
+ EXPECT_FALSE(LOG_IS_ON(WARNING));
+ EXPECT_FALSE(LOG_IS_ON(ERROR));
+ EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+ EXPECT_TRUE(LOG_IS_ON(FATAL));
+ EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL));
+
+ // So should LOG_IS_ON(FATAL).
+ SetMinLogLevel(LOG_FATAL + 1);
+ EXPECT_FALSE(LOG_IS_ON(INFO));
+ EXPECT_FALSE(LOG_IS_ON(WARNING));
+ EXPECT_FALSE(LOG_IS_ON(ERROR));
+ EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT));
+ EXPECT_TRUE(LOG_IS_ON(FATAL));
+ EXPECT_EQ(kDfatalIsFatal, LOG_IS_ON(DFATAL));
+}
+
TEST_F(LoggingTest, LoggingIsLazy) {
MockLogSource mock_log_source;
EXPECT_CALL(mock_log_source, Log()).Times(0);
@@ -93,14 +163,13 @@ TEST_F(LoggingTest, LoggingIsLazy) {
DVLOG_IF(1, true) << mock_log_source.Log();
}
-TEST_F(LoggingTest, ChecksAreNotLazy) {
+TEST_F(LoggingTest, CheckStreamsAreLazy) {
MockLogSource mock_log_source, uncalled_mock_log_source;
EXPECT_CALL(mock_log_source, Log()).Times(8).
WillRepeatedly(Return("check message"));
EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0);
- SetMinLogLevel(LOG_FATAL + 1);
- EXPECT_FALSE(LOG_IS_ON(FATAL));
+ SetLogAssertHandler(&LogSink);
CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log();
PCHECK(!mock_log_source.Log()) << mock_log_source.Log();
@@ -122,22 +191,46 @@ TEST_F(LoggingTest, DebugLoggingReleaseBehavior) {
DVLOG_IF(1, debug_only_variable) << "test";
}
-TEST_F(LoggingTest, DchecksAreLazy) {
+TEST_F(LoggingTest, DcheckStreamsAreLazy) {
MockLogSource mock_log_source;
EXPECT_CALL(mock_log_source, Log()).Times(0);
#if !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG)
// Unofficial release build.
logging::g_enable_dcheck = false;
-#else // !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG)
- SetMinLogLevel(LOG_FATAL + 1);
- EXPECT_FALSE(LOG_IS_ON(FATAL));
-#endif // !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG)
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();
DCHECK_EQ(mock_log_source.Log(), static_cast<const char*>(NULL))
<< mock_log_source.Log();
+#endif // !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG)
+}
+
+TEST_F(LoggingTest, Dcheck) {
+#if defined(LOGGING_IS_OFFICIAL_BUILD)
+ // Official build.
+ EXPECT_FALSE(DCHECK_IS_ON());
+ EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#elif defined(NDEBUG)
+ // Unofficial release build.
+ logging::g_enable_dcheck = true;
+ logging::SetLogReportHandler(&LogSink);
+ EXPECT_TRUE(DCHECK_IS_ON());
+ EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#else
+ // Unofficial debug build.
+ logging::SetLogAssertHandler(&LogSink);
+ EXPECT_TRUE(DCHECK_IS_ON());
+ EXPECT_TRUE(DLOG_IS_ON(DCHECK));
+#endif // defined(LOGGING_IS_OFFICIAL_BUILD)
+
+ EXPECT_EQ(0, log_sink_call_count);
+ DCHECK(false);
+ EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count);
+ DPCHECK(false);
+ EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count);
+ DCHECK_EQ(0, 1);
+ EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count);
}
TEST_F(LoggingTest, DcheckReleaseBehavior) {
diff --git a/base/logging_win.cc b/base/logging_win.cc
index f17cf34..42610b5 100644
--- a/base/logging_win.cc
+++ b/base/logging_win.cc
@@ -16,31 +16,40 @@ Singleton<logging::LogEventProvider, LogEventSingletonTraits> log_provider;
namespace logging {
+using base::win::EtwEventLevel;
+using base::win::EtwMofEvent;
+
DEFINE_GUID(kLogEventId,
0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
}
-bool LogEventProvider::LogMessage(int severity, const std::string& message) {
+bool LogEventProvider::LogMessage(logging::LogSeverity severity,
+ const char* file, int line, size_t message_start,
+ const std::string& message) {
EtwEventLevel level = TRACE_LEVEL_NONE;
// Convert the log severity to the most appropriate ETW trace level.
- switch (severity) {
- case LOG_INFO:
- level = TRACE_LEVEL_INFORMATION;
- break;
- case LOG_WARNING:
- level = TRACE_LEVEL_WARNING;
- break;
- case LOG_ERROR:
- case LOG_ERROR_REPORT:
- level = TRACE_LEVEL_ERROR;
- break;
- case LOG_FATAL:
- level = TRACE_LEVEL_FATAL;
- break;
- };
+ if (severity >= 0) {
+ switch (severity) {
+ case LOG_INFO:
+ level = TRACE_LEVEL_INFORMATION;
+ break;
+ case LOG_WARNING:
+ level = TRACE_LEVEL_WARNING;
+ break;
+ case LOG_ERROR:
+ case LOG_ERROR_REPORT:
+ level = TRACE_LEVEL_ERROR;
+ break;
+ case LOG_FATAL:
+ level = TRACE_LEVEL_FATAL;
+ break;
+ }
+ } else { // severity < 0 is VLOG verbosity levels.
+ level = TRACE_LEVEL_INFORMATION - severity;
+ }
// Bail if we're not logging, not at that level,
// or if we're post-atexit handling.
@@ -48,27 +57,43 @@ bool LogEventProvider::LogMessage(int severity, const std::string& message) {
if (provider == NULL || level > provider->enable_level())
return false;
- // And now log the event, with stack trace if one is
- // requested per our enable flags.
- if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE) {
+ // And now log the event.
+ if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
+ EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
+ event.SetField(0, message.length() + 1 - message_start,
+ message.c_str() + message_start);
+
+ provider->Log(event.get());
+ } else {
const size_t kMaxBacktraceDepth = 32;
void* backtrace[kMaxBacktraceDepth];
- DWORD depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
- EtwMofEvent<3> event(kLogEventId, LOG_MESSAGE_WITH_STACKTRACE, level);
+ DWORD depth = 0;
+ // Capture a stack trace if one is requested.
+ // requested per our enable flags.
+ if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
+ depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
+
+ EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
+ if (file == NULL)
+ file = "";
+
+ // Add the stack trace.
event.SetField(0, sizeof(depth), &depth);
event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
- event.SetField(2, message.length() + 1, message.c_str());
+ // The line.
+ event.SetField(2, sizeof(line), &line);
+ // The file.
+ event.SetField(3, strlen(file) + 1, file);
+ // And finally the message.
+ event.SetField(4, message.length() + 1 - message_start,
+ message.c_str() + message_start);
provider->Log(event.get());
- } else {
- EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
- event.SetField(0, message.length() + 1, message.c_str());
- provider->Log(event.get());
}
// Don't increase verbosity in other log destinations.
- if (severity >= provider->old_log_level_)
+ if (severity < provider->old_log_level_)
return true;
return false;
@@ -95,21 +120,17 @@ void LogEventProvider::OnEventsEnabled() {
// Convert the new trace level to a logging severity
// and enable logging at that level.
EtwEventLevel level = enable_level();
- switch (level) {
- case TRACE_LEVEL_NONE:
- case TRACE_LEVEL_FATAL:
- SetMinLogLevel(LOG_FATAL);
- break;
- case TRACE_LEVEL_ERROR:
- SetMinLogLevel(LOG_ERROR);
- break;
- case TRACE_LEVEL_WARNING:
- SetMinLogLevel(LOG_WARNING);
- break;
- case TRACE_LEVEL_INFORMATION:
- case TRACE_LEVEL_VERBOSE:
- SetMinLogLevel(LOG_INFO);
- break;
+ if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
+ SetMinLogLevel(LOG_FATAL);
+ } else if (level == TRACE_LEVEL_ERROR) {
+ SetMinLogLevel(LOG_ERROR);
+ } else if (level == TRACE_LEVEL_WARNING) {
+ SetMinLogLevel(LOG_WARNING);
+ } else if (level == TRACE_LEVEL_INFORMATION) {
+ SetMinLogLevel(LOG_INFO);
+ } else if (level >= TRACE_LEVEL_VERBOSE) {
+ // Above INFO, we enable verbose levels with negative severities.
+ SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
}
}
diff --git a/base/logging_win.h b/base/logging_win.h
index f2e6e5a..695c7f2 100644
--- a/base/logging_win.h
+++ b/base/logging_win.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/basictypes.h"
-#include "base/event_trace_provider_win.h"
+#include "base/win/event_trace_provider.h"
#include "base/logging.h"
namespace logging {
@@ -21,6 +21,10 @@ enum LogEnableMask {
// If this bit is set in our provider enable mask, we will include
// a stack trace with every log message.
ENABLE_STACK_TRACE_CAPTURE = 0x0001,
+ // If this bit is set in our provider enable mask, the provider will log
+ // a LOG message with only the textual content of the message, and no
+ // stack trace.
+ ENABLE_LOG_MESSAGE_ONLY = 0x0002,
};
// The message types our log event provider generates.
@@ -31,15 +35,23 @@ enum LogMessageTypes {
// A message with a stack trace, followed by the zero-terminated
// message text.
LOG_MESSAGE_WITH_STACKTRACE = 11,
+ // A message with:
+ // a stack trace,
+ // the line number as a four byte integer,
+ // the file as a zero terminated UTF8 string,
+ // the zero-terminated UTF8 message text.
+ LOG_MESSAGE_FULL = 12,
};
// Trace provider class to drive log control and transport
// with Event Tracing for Windows.
-class LogEventProvider : public EtwTraceProvider {
+class LogEventProvider : public base::win::EtwTraceProvider {
public:
LogEventProvider();
- static bool LogMessage(int severity, const std::string& message);
+ static bool LogMessage(logging::LogSeverity severity, const char* file,
+ int line, size_t message_start, const std::string& str);
+
static void Initialize(const GUID& provider_name);
static void Uninitialize();
diff --git a/base/mac_util.h b/base/mac_util.h
index e590d30..182fcc8 100644
--- a/base/mac_util.h
+++ b/base/mac_util.h
@@ -24,8 +24,10 @@ class NSWindow;
// 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 mac_util {
@@ -74,11 +76,23 @@ OSType CreatorCodeForCFBundleRef(CFBundleRef bundle);
// 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();
diff --git a/base/mac_util.mm b/base/mac_util.mm
index f4e988a..4e6b105 100644
--- a/base/mac_util.mm
+++ b/base/mac_util.mm
@@ -219,10 +219,12 @@ OSType CreatorCodeForApplication() {
return CreatorCodeForCFBundleRef(bundle);
}
-bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
+bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+ NSSearchPathDomainMask domain_mask,
+ FilePath* result) {
DCHECK(result);
NSArray* dirs =
- NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
+ NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
if ([dirs count] < 1) {
return false;
}
@@ -231,6 +233,14 @@ bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
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)) {
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 2a92f4f..c4ff167 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -23,9 +23,13 @@
#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include "base/message_pump_glib.h"
#endif
+#if defined(TOUCH_UI)
+#include "base/message_pump_glib_x.h"
+#endif
using base::Time;
using base::TimeDelta;
+using base::TimeTicks;
namespace {
@@ -134,8 +138,14 @@ MessageLoop::MessageLoop(Type type)
#elif defined(OS_MACOSX)
#define MESSAGE_PUMP_UI base::MessagePumpMac::Create()
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
+<<<<<<< HEAD
#elif defined(ANDROID)
#define MESSAGE_PUMP_UI new base::MessagePumpDefault()
+=======
+#elif defined(TOUCH_UI)
+// TODO(sadrul): enable the new message pump when ready
+#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
+>>>>>>> chromium.org at r65505
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
#elif defined(OS_POSIX) // POSIX but not MACOSX.
#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
@@ -330,7 +340,7 @@ void MessageLoop::PostTask_Helper(
if (delay_ms > 0) {
pending_task.delayed_run_time =
- Time::Now() + TimeDelta::FromMilliseconds(delay_ms);
+ TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms);
#if defined(OS_WIN)
if (high_resolution_timer_expiration_.is_null()) {
@@ -343,7 +353,7 @@ void MessageLoop::PostTask_Helper(
delay_ms < (2 * Time::kMinLowResolutionThresholdMs);
if (needs_high_res_timers) {
Time::ActivateHighResolutionTimer(true);
- high_resolution_timer_expiration_ = base::TimeTicks::Now() +
+ high_resolution_timer_expiration_ = TimeTicks::Now() +
TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs);
}
}
@@ -354,9 +364,9 @@ void MessageLoop::PostTask_Helper(
#if defined(OS_WIN)
if (!high_resolution_timer_expiration_.is_null()) {
- if (base::TimeTicks::Now() > high_resolution_timer_expiration_) {
+ if (TimeTicks::Now() > high_resolution_timer_expiration_) {
Time::ActivateHighResolutionTimer(false);
- high_resolution_timer_expiration_ = base::TimeTicks();
+ high_resolution_timer_expiration_ = TimeTicks();
}
}
#endif
@@ -411,9 +421,9 @@ void MessageLoop::RunTask(Task* task) {
HistogramEvent(kTaskRunEvent);
FOR_EACH_OBSERVER(TaskObserver, task_observers_,
- WillProcessTask(task->tracked_birth_time()));
+ WillProcessTask(task));
task->Run();
- FOR_EACH_OBSERVER(TaskObserver, task_observers_, DidProcessTask());
+ FOR_EACH_OBSERVER(TaskObserver, task_observers_, DidProcessTask(task));
delete task;
nestable_tasks_allowed_ = true;
@@ -475,7 +485,7 @@ bool MessageLoop::DeletePendingTasks() {
// TODO(darin): Delete all tasks once it is safe to do so.
// Until it is totally safe, just do it when running Purify or
// Valgrind.
-#if defined(PURIFY)
+#if defined(PURIFY) || defined(USE_HEAPCHECKER)
delete pending_task.task;
#elif defined(OS_POSIX)
if (RUNNING_ON_VALGRIND)
@@ -488,7 +498,7 @@ bool MessageLoop::DeletePendingTasks() {
// TODO(darin): Delete all tasks once it is safe to do so.
// Until it is totaly safe, only delete them under Purify and Valgrind.
Task* task = NULL;
-#if defined(PURIFY)
+#if defined(PURIFY) || defined(USE_HEAPCHECKER)
task = deferred_non_nestable_work_queue_.front().task;
#elif defined(OS_POSIX)
if (RUNNING_ON_VALGRIND)
@@ -538,15 +548,26 @@ bool MessageLoop::DoWork() {
return false;
}
-bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
+bool MessageLoop::DoDelayedWork(base::TimeTicks* next_delayed_work_time) {
if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
- *next_delayed_work_time = Time();
+ recent_time_ = *next_delayed_work_time = TimeTicks();
return false;
}
- if (delayed_work_queue_.top().delayed_run_time > Time::Now()) {
- *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
- return false;
+ // When we "fall behind," there will be a lot of tasks in the delayed work
+ // queue that are ready to run. To increase efficiency when we fall behind,
+ // we will only call Time::Now() intermittently, and then process all tasks
+ // that are ready to run before calling it again. As a result, the more we
+ // fall behind (and have a lot of ready-to-run delayed tasks), the more
+ // efficient we'll be at handling the tasks.
+
+ TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
+ if (next_run_time > recent_time_) {
+ recent_time_ = TimeTicks::Now(); // Get a better view of Now();
+ if (next_run_time > recent_time_) {
+ *next_delayed_work_time = next_run_time;
+ return false;
+ }
}
PendingTask pending_task = delayed_work_queue_.top();
diff --git a/base/message_loop.h b/base/message_loop.h
index 94e0096..a5a94bc 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -26,6 +26,9 @@
#include "base/message_pump_glib.h"
#endif
#endif
+#if defined(TOUCH_UI)
+#include "base/message_pump_glib_x_dispatch.h"
+#endif
namespace base {
class Histogram;
@@ -72,10 +75,10 @@ class MessageLoop : public base::MessagePump::Delegate {
TaskObserver();
// This method is called before processing a task.
- virtual void WillProcessTask(base::TimeTicks birth_time) = 0;
+ virtual void WillProcessTask(const Task* task) = 0;
// This method is called after processing a task.
- virtual void DidProcessTask() = 0;
+ virtual void DidProcessTask(const Task* task) = 0;
protected:
virtual ~TaskObserver();
@@ -146,7 +149,7 @@ class MessageLoop : public base::MessagePump::Delegate {
// as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit
// from RefCountedThreadSafe<T>!
template <class T>
- void DeleteSoon(const tracked_objects::Location& from_here, T* object) {
+ void DeleteSoon(const tracked_objects::Location& from_here, const T* object) {
PostNonNestableTask(from_here, new DeleteTask<T>(object));
}
@@ -161,7 +164,8 @@ class MessageLoop : public base::MessagePump::Delegate {
// PostDelayedTask(FROM_HERE, ), then T MUST inherit from
// RefCountedThreadSafe<T>!
template <class T>
- void ReleaseSoon(const tracked_objects::Location& from_here, T* object) {
+ void ReleaseSoon(const tracked_objects::Location& from_here,
+ const T* object) {
PostNonNestableTask(from_here, new ReleaseTask<T>(object));
}
@@ -289,7 +293,11 @@ class MessageLoop : public base::MessagePump::Delegate {
typedef base::MessagePumpWin::Dispatcher Dispatcher;
typedef base::MessagePumpForUI::Observer Observer;
#elif !defined(OS_MACOSX)
+#if defined(TOUCH_UI)
+ typedef base::MessagePumpGlibXDispatcher Dispatcher;
+#else
typedef base::MessagePumpForUI::Dispatcher Dispatcher;
+#endif
typedef base::MessagePumpForUI::Observer Observer;
#endif
@@ -333,10 +341,10 @@ class MessageLoop : public base::MessagePump::Delegate {
// This structure is copied around by value.
struct PendingTask {
- Task* task; // The task to run.
- base::Time delayed_run_time; // The time when the task should be run.
- int sequence_num; // Used to facilitate sorting by run time.
- bool nestable; // True if OK to dispatch from a nested loop.
+ Task* task; // The task to run.
+ base::TimeTicks delayed_run_time; // The time when the task should be run.
+ int sequence_num; // Secondary sort key for run time.
+ bool nestable; // OK to dispatch from a nested loop.
PendingTask(Task* task, bool nestable)
: task(task), sequence_num(0), nestable(nestable) {
@@ -421,7 +429,7 @@ class MessageLoop : public base::MessagePump::Delegate {
// base::MessagePump::Delegate methods:
virtual bool DoWork();
- virtual bool DoDelayedWork(base::Time* next_delayed_work_time);
+ virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time);
virtual bool DoIdleWork();
// Start recording histogram info about events and action IF it was enabled
@@ -442,6 +450,9 @@ class MessageLoop : public base::MessagePump::Delegate {
// Contains delayed tasks, sorted by their 'delayed_run_time' property.
DelayedTaskQueue delayed_work_queue_;
+ // A recent snapshot of Time::Now(), used to check delayed_work_queue_.
+ base::TimeTicks recent_time_;
+
// A queue of non-nestable tasks that we had to defer because when it came
// time to execute them we were in a nested message loop. They will execute
// once we're out of nested message loops.
diff --git a/base/message_loop_proxy.cc b/base/message_loop_proxy.cc
index bc7088d..a38db39 100644
--- a/base/message_loop_proxy.cc
+++ b/base/message_loop_proxy.cc
@@ -12,7 +12,7 @@ MessageLoopProxy::MessageLoopProxy() {
MessageLoopProxy::~MessageLoopProxy() {
}
-void MessageLoopProxy::OnDestruct() {
+void MessageLoopProxy::OnDestruct() const {
delete this;
}
diff --git a/base/message_loop_proxy.h b/base/message_loop_proxy.h
index 5d6708e..4d38155 100644
--- a/base/message_loop_proxy.h
+++ b/base/message_loop_proxy.h
@@ -64,11 +64,11 @@ class MessageLoopProxy
// Called when the proxy is about to be deleted. Subclasses can override this
// to provide deletion on specific threads.
- virtual void OnDestruct();
+ virtual void OnDestruct() const;
};
struct MessageLoopProxyTraits {
- static void Destruct(MessageLoopProxy* proxy) {
+ static void Destruct(const MessageLoopProxy* proxy) {
proxy->OnDestruct();
}
};
diff --git a/base/message_loop_proxy_impl.cc b/base/message_loop_proxy_impl.cc
index 983a406..2e0f809 100644
--- a/base/message_loop_proxy_impl.cc
+++ b/base/message_loop_proxy_impl.cc
@@ -71,7 +71,7 @@ bool MessageLoopProxyImpl::PostTaskHelper(
return ret;
}
-void MessageLoopProxyImpl::OnDestruct() {
+void MessageLoopProxyImpl::OnDestruct() const {
bool delete_later = false;
{
AutoLock lock(message_loop_lock_);
@@ -93,7 +93,7 @@ void MessageLoopProxyImpl::WillDestroyCurrentMessageLoop() {
scoped_refptr<MessageLoopProxy>
MessageLoopProxy::CreateForCurrentThread() {
- scoped_refptr<MessageLoopProxy> ret = new MessageLoopProxyImpl();
+ scoped_refptr<MessageLoopProxy> ret(new MessageLoopProxyImpl());
return ret;
}
diff --git a/base/message_loop_proxy_impl.h b/base/message_loop_proxy_impl.h
index b93bb64..87ae70a 100644
--- a/base/message_loop_proxy_impl.h
+++ b/base/message_loop_proxy_impl.h
@@ -39,7 +39,7 @@ class MessageLoopProxyImpl : public MessageLoopProxy,
protected:
// Override OnDestruct so that we can delete the object on the target message
// loop if it still exists.
- virtual void OnDestruct();
+ virtual void OnDestruct() const;
private:
MessageLoopProxyImpl();
@@ -50,7 +50,7 @@ class MessageLoopProxyImpl : public MessageLoopProxy,
friend class MessageLoopProxy;
// The lock that protects access to target_message_loop_.
- Lock message_loop_lock_;
+ mutable Lock message_loop_lock_;
MessageLoop* target_message_loop_;
DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
diff --git a/base/message_loop_proxy_impl_unittest.cc b/base/message_loop_proxy_impl_unittest.cc
index a3cb800..8d8ef4e 100644
--- a/base/message_loop_proxy_impl_unittest.cc
+++ b/base/message_loop_proxy_impl_unittest.cc
@@ -12,20 +12,20 @@
class MessageLoopProxyImplTest : public testing::Test {
public:
- void Release() {
+ void Release() const {
AssertOnIOThread();
Quit();
}
- void Quit() {
+ void Quit() const {
loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask);
}
- void AssertOnIOThread() {
+ void AssertOnIOThread() const {
ASSERT_TRUE(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
}
- void AssertOnFileThread() {
+ void AssertOnFileThread() const {
ASSERT_TRUE(file_thread_->message_loop_proxy()->BelongsToCurrentThread());
}
@@ -79,7 +79,7 @@ class MessageLoopProxyImplTest : public testing::Test {
scoped_ptr<base::Thread> file_thread_;
private:
- MessageLoop loop_;
+ mutable MessageLoop loop_;
};
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index 741eb71..a3c3307 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -95,7 +95,7 @@ void RunTest_PostTask(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
// Add tests to message loop
- scoped_refptr<Foo> foo = new Foo();
+ scoped_refptr<Foo> foo(new Foo());
std::string a("a"), b("b"), c("c"), d("d");
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
foo.get(), &Foo::Test0));
@@ -111,7 +111,7 @@ void RunTest_PostTask(MessageLoop::Type message_loop_type) {
foo.get(), &Foo::Test2Mixed, a, &d));
// After all tests, post a message that will shut down the message loop
- scoped_refptr<QuitMsgLoop> quit = new QuitMsgLoop();
+ scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop());
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
quit.get(), &QuitMsgLoop::QuitNow));
@@ -126,7 +126,7 @@ void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
// Add tests to message loop
- scoped_refptr<Foo> foo = new Foo();
+ scoped_refptr<Foo> foo(new Foo());
std::string a("a"), b("b"), c("c"), d("d");
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
foo.get(), &Foo::Test0));
@@ -142,7 +142,7 @@ void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
foo.get(), &Foo::Test2Mixed, a, &d));
// After all tests, post a message that will shut down the message loop
- scoped_refptr<QuitMsgLoop> quit = new QuitMsgLoop();
+ scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop());
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
quit.get(), &QuitMsgLoop::QuitNow));
@@ -1488,14 +1488,16 @@ class DummyTaskObserver : public MessageLoop::TaskObserver {
virtual ~DummyTaskObserver() {}
- virtual void WillProcessTask(base::TimeTicks /* birth_time */) {
+ virtual void WillProcessTask(const Task* task) {
num_tasks_started_++;
+ EXPECT_TRUE(task != NULL);
EXPECT_LE(num_tasks_started_, num_tasks_);
EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
}
- virtual void DidProcessTask() {
+ virtual void DidProcessTask(const Task* task) {
num_tasks_processed_++;
+ EXPECT_TRUE(task != NULL);
EXPECT_LE(num_tasks_started_, num_tasks_);
EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
}
diff --git a/base/message_pump.h b/base/message_pump.h
index f8a097d..a354724 100644
--- a/base/message_pump.h
+++ b/base/message_pump.h
@@ -10,7 +10,7 @@
namespace base {
-class Time;
+class TimeTicks;
class MessagePump : public RefCountedThreadSafe<MessagePump> {
public:
@@ -33,7 +33,7 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// |next_delayed_work_time| is null (per Time::is_null), then the queue of
// future delayed work (timer events) is currently empty, and no additional
// calls to this function need to be scheduled.
- virtual bool DoDelayedWork(Time* next_delayed_work_time) = 0;
+ virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
// Called from within Run just before the message pump goes to sleep.
// Returns true to indicate that idle work was done.
@@ -116,7 +116,7 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// Schedule a DoDelayedWork callback to happen at the specified time,
// cancelling any pending DoDelayedWork callback. This method may only be
// used on the thread that called Run.
- virtual void ScheduleDelayedWork(const Time& delayed_work_time) = 0;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
};
} // namespace base
diff --git a/base/message_pump_default.cc b/base/message_pump_default.cc
index 518684a..d9eddc4 100644
--- a/base/message_pump_default.cc
+++ b/base/message_pump_default.cc
@@ -41,13 +41,13 @@ void MessagePumpDefault::Run(Delegate* delegate) {
if (delayed_work_time_.is_null()) {
event_.Wait();
} else {
- TimeDelta delay = delayed_work_time_ - Time::Now();
+ TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
if (delay > TimeDelta()) {
event_.TimedWait(delay);
} else {
// It looks like delayed_work_time_ indicates a time in the past, so we
// need to call DoDelayedWork now.
- delayed_work_time_ = Time();
+ delayed_work_time_ = TimeTicks();
}
}
// Since event_ is auto-reset, we don't need to do anything special here
@@ -67,7 +67,8 @@ void MessagePumpDefault::ScheduleWork() {
event_.Signal();
}
-void MessagePumpDefault::ScheduleDelayedWork(const Time& delayed_work_time) {
+void MessagePumpDefault::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
// We know that we can't be blocked on Wait right now since this method can
// only be called on the same thread as Run, so we only need to update our
// record of how long to sleep when we do sleep.
diff --git a/base/message_pump_default.h b/base/message_pump_default.h
index 0ac6cd4..3dfbf1c 100644
--- a/base/message_pump_default.h
+++ b/base/message_pump_default.h
@@ -21,7 +21,7 @@ class MessagePumpDefault : public MessagePump {
virtual void Run(Delegate* delegate);
virtual void Quit();
virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
private:
// This flag is set to false when Run should return.
@@ -31,7 +31,7 @@ class MessagePumpDefault : public MessagePump {
WaitableEvent event_;
// The time at which we should call DoDelayedWork.
- Time delayed_work_time_;
+ TimeTicks delayed_work_time_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
};
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
index e85a712..fa5b726 100644
--- a/base/message_pump_glib.cc
+++ b/base/message_pump_glib.cc
@@ -21,7 +21,7 @@ const char kWorkScheduled = '\0';
// Return a timeout suitable for the glib loop, -1 to block forever,
// 0 to return right away, or a timeout in milliseconds from now.
-int GetTimeIntervalMilliseconds(base::Time from) {
+int GetTimeIntervalMilliseconds(const base::TimeTicks& from) {
if (from.is_null())
return -1;
@@ -29,7 +29,7 @@ int GetTimeIntervalMilliseconds(base::Time from) {
// value in milliseconds. If there are 5.5ms left, should the delay be 5 or
// 6? It should be 6 to avoid executing delayed work too early.
int delay = static_cast<int>(
- ceil((from - base::Time::Now()).InMillisecondsF()));
+ ceil((from - base::TimeTicks::Now()).InMillisecondsF()));
// If this value is negative, then we need to run delayed work soon.
return delay < 0 ? 0 : delay;
@@ -207,8 +207,7 @@ void MessagePumpForUI::RunWithDispatcher(Delegate* delegate,
// Don't block if we think we have more work to do.
bool block = !more_work_is_plausible;
- // g_main_context_iteration returns true if events have been dispatched.
- more_work_is_plausible = g_main_context_iteration(context_, block);
+ more_work_is_plausible = RunOnce(context_, block);
if (state_->should_quit)
break;
@@ -232,6 +231,11 @@ void MessagePumpForUI::RunWithDispatcher(Delegate* delegate,
state_ = previous_state;
}
+bool MessagePumpForUI::RunOnce(GMainContext* context, bool block) {
+ // g_main_context_iteration returns true if events have been dispatched.
+ return g_main_context_iteration(context, block);
+}
+
// Return the timeout we want passed to poll.
int MessagePumpForUI::HandlePrepare() {
// We know we have work, but we haven't called HandleDispatch yet. Don't let
@@ -299,6 +303,10 @@ 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));
}
@@ -325,26 +333,28 @@ void MessagePumpForUI::ScheduleWork() {
}
}
-void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) {
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
// We need to wake up the loop in case the poll timeout needs to be
// adjusted. This will cause us to try to do work, but that's ok.
delayed_work_time_ = delayed_work_time;
ScheduleWork();
}
-// static
-void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) {
- MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data);
-
- message_pump->WillProcessEvent(event);
- if (message_pump->state_ && // state_ may be null during tests.
- message_pump->state_->dispatcher) {
- if (!message_pump->state_->dispatcher->Dispatch(event))
- message_pump->state_->should_quit = true;
+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);
}
- message_pump->DidProcessEvent(event);
+ DidProcessEvent(event);
+}
+
+// static
+void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) {
+ MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data);
+ message_pump->DispatchEvents(event);
}
} // namespace base
diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h
index f6d022a..06635de 100644
--- a/base/message_pump_glib.h
+++ b/base/message_pump_glib.h
@@ -57,10 +57,15 @@ class MessagePumpForUI : public MessagePump {
// Like MessagePump::Run, but GdkEvent objects are routed through dispatcher.
virtual void RunWithDispatcher(Delegate* delegate, Dispatcher* dispatcher);
+ // Run a single iteration of the mainloop. A return value of true indicates
+ // that an event was handled. |block| indicates if it should wait if no event
+ // is ready for processing.
+ virtual bool RunOnce(GMainContext* context, bool block);
+
virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
virtual void Quit();
virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
// Internal methods used for processing the pump callbacks. They are
// public for simplicity but should not be used directly. HandlePrepare
@@ -79,6 +84,14 @@ class MessagePumpForUI : public MessagePump {
// receiving a notification callback.
void RemoveObserver(Observer* observer);
+ // Dispatch an available GdkEvent. Essentially this allows a subclass to do
+ // some task before/after calling the default handler (EventDispatcher).
+ virtual void DispatchEvents(GdkEvent* event);
+
+ protected:
+ // Returns the dispatcher for the current run state (|state_->dispatcher|).
+ Dispatcher* GetDispatcher();
+
private:
// We may make recursive calls to Run, so we save state that needs to be
// separate between them in this structure type.
@@ -103,7 +116,7 @@ class MessagePumpForUI : public MessagePump {
GMainContext* context_;
// This is the time when we need to do delayed work.
- Time delayed_work_time_;
+ TimeTicks delayed_work_time_;
// The work source. It is shared by all calls to Run and destroyed when
// the message pump is destroyed.
diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc
new file mode 100644
index 0000000..675774e
--- /dev/null
+++ b/base/message_pump_glib_x.cc
@@ -0,0 +1,117 @@
+// 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/message_pump_glib_x.h"
+
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+
+#include "base/message_pump_glib_x_dispatch.h"
+
+namespace {
+
+gboolean PlaceholderDispatch(GSource* source,
+ GSourceFunc cb,
+ gpointer data) {
+ return TRUE;
+}
+
+} // namespace
+
+namespace base {
+
+MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
+ gdksource_(NULL),
+ dispatching_event_(false),
+ capture_x_events_(0),
+ capture_gdk_events_(0) {
+ gdk_event_handler_set(&EventDispatcherX, this, NULL);
+
+ InitializeEventsToCapture();
+}
+
+MessagePumpGlibX::~MessagePumpGlibX() {
+}
+
+bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
+ GdkDisplay* gdisp = gdk_display_get_default();
+ Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
+ if (XPending(display)) {
+ XEvent xev;
+ XPeekEvent(display, &xev);
+ if (capture_x_events_[xev.type]) {
+ XNextEvent(display, &xev);
+
+ bool processed = static_cast<MessagePumpGlibXDispatcher*>
+ (GetDispatcher())->Dispatch(&xev);
+
+ if (!processed) {
+ DLOG(WARNING) << "Event (" << xev.type << ") not handled.";
+ }
+ } else {
+ // TODO(sad): A couple of extra events can still sneak in during this.
+ // Those should be sent back to the X queue from the dispatcher
+ // EventDispatcherX.
+ g_main_context_iteration(context, FALSE);
+ }
+ }
+
+ bool retvalue;
+ if (gdksource_) {
+ // Replace the dispatch callback of the GDK event source temporarily so that
+ // it doesn't read events from X.
+ gboolean (*cb)(GSource*, GSourceFunc, void*) =
+ gdksource_->source_funcs->dispatch;
+ gdksource_->source_funcs->dispatch = PlaceholderDispatch;
+
+ dispatching_event_ = true;
+ retvalue = g_main_context_iteration(context, block);
+ dispatching_event_ = false;
+
+ gdksource_->source_funcs->dispatch = cb;
+ } else {
+ retvalue = g_main_context_iteration(context, block);
+ }
+
+ return retvalue;
+}
+
+void MessagePumpGlibX::InitializeEventsToCapture(void) {
+ // TODO(sad): Decide which events we want to capture and update the tables
+ // accordingly.
+ capture_x_events_[KeyPress] = true;
+ capture_gdk_events_[GDK_KEY_PRESS] = true;
+
+ capture_x_events_[KeyRelease] = true;
+ capture_gdk_events_[GDK_KEY_RELEASE] = true;
+
+ capture_x_events_[ButtonPress] = true;
+ capture_gdk_events_[GDK_BUTTON_PRESS] = true;
+
+ capture_x_events_[ButtonRelease] = true;
+ capture_gdk_events_[GDK_BUTTON_RELEASE] = true;
+
+ capture_x_events_[MotionNotify] = true;
+ capture_gdk_events_[GDK_MOTION_NOTIFY] = true;
+}
+
+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();
+ } 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.h b/base/message_pump_glib_x.h
new file mode 100644
index 0000000..2f50731
--- /dev/null
+++ b/base/message_pump_glib_x.h
@@ -0,0 +1,63 @@
+// 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_MESSAGE_PUMP_GLIB_X_H
+#define BASE_MESSAGE_PUMP_GLIB_X_H
+
+#include "base/message_pump.h"
+#include "base/message_pump_glib.h"
+
+#include <bitset>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <X11/X.h>
+
+namespace base {
+
+class MessagePumpGlibX : public MessagePumpForUI {
+ public:
+ MessagePumpGlibX();
+ virtual ~MessagePumpGlibX();
+
+ // MessagePumpForUI implementation.
+ virtual bool RunOnce(GMainContext* context, bool block);
+
+ // Indicates whether a GDK event was injected by chrome (when |true|) or if it
+ // was captured and being processed by GDK (when |false|).
+ bool IsDispatchingEvent(void) { return dispatching_event_; }
+
+ private:
+ static void EventDispatcherX(GdkEvent* event, gpointer data);
+
+ // Update the lookup table and flag the events that should be captured and
+ // processed so that GDK doesn't get to them.
+ void InitializeEventsToCapture(void);
+
+ // The event source for GDK events.
+ GSource* gdksource_;
+
+ // Indicates whether a GDK event was injected by chrome (when |true|) or if it
+ // was captured and being processed by GDK (when |false|).
+ bool dispatching_event_;
+
+#if ! GTK_CHECK_VERSION(2,18,0)
+// GDK_EVENT_LAST was introduced in GTK+ 2.18.0. For earlier versions, we pick a
+// large enough value (the value of GDK_EVENT_LAST in 2.18.0) so that it works
+// for all versions.
+#define GDK_EVENT_LAST 37
+#endif
+
+ // We do not want to process all the events ourselves. So we use a lookup
+ // table to quickly check if a particular event should be handled by us or if
+ // it should be passed on to the default GDK handler.
+ std::bitset<LASTEvent> capture_x_events_;
+ std::bitset<GDK_EVENT_LAST> capture_gdk_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpGlibX);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_GLIB_X_H
diff --git a/base/message_pump_glib_x_dispatch.h b/base/message_pump_glib_x_dispatch.h
new file mode 100644
index 0000000..95364a2
--- /dev/null
+++ b/base/message_pump_glib_x_dispatch.h
@@ -0,0 +1,28 @@
+// 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_MESSAGE_PUMP_GLIB_X_DISPATCH_H
+#define BASE_MESSAGE_PUMP_GLIB_X_DISPATCH_H
+
+#include "base/message_pump.h"
+#include "base/message_pump_glib.h"
+
+typedef union _XEvent XEvent;
+
+namespace base {
+
+// The message pump used for TOUCH_UI on linux is MessagePumpGlibX, which can
+// dispatch both GdkEvents* and XEvents* captured directly from X.
+// MessagePumpForUI::Dispatcher provides the mechanism for dispatching
+// GdkEvents. This class provides additional mechanism for dispatching XEvents.
+class MessagePumpGlibXDispatcher : public MessagePumpForUI::Dispatcher {
+ public:
+ // Dispatches the event. If true is returned processing continues as
+ // normal. If false is returned, the nested loop exits immediately.
+ virtual bool Dispatch(XEvent* xevent) = 0;
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_GLIB_X_DISPATCH_H
diff --git a/base/message_pump_libevent.cc b/base/message_pump_libevent.cc
index d325957..1410f79 100644
--- a/base/message_pump_libevent.cc
+++ b/base/message_pump_libevent.cc
@@ -290,7 +290,7 @@ void MessagePumpLibevent::Run(Delegate* delegate) {
if (delayed_work_time_.is_null()) {
event_base_loop(event_base_, EVLOOP_ONCE);
} else {
- TimeDelta delay = delayed_work_time_ - Time::Now();
+ TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
if (delay > TimeDelta()) {
struct timeval poll_tv;
poll_tv.tv_sec = delay.InSeconds();
@@ -303,7 +303,7 @@ void MessagePumpLibevent::Run(Delegate* delegate) {
} else {
// It looks like delayed_work_time_ indicates a time in the past, so we
// need to call DoDelayedWork now.
- delayed_work_time_ = Time();
+ delayed_work_time_ = TimeTicks();
}
}
}
@@ -326,7 +326,8 @@ void MessagePumpLibevent::ScheduleWork() {
<< "[nwrite:" << nwrite << "] [errno:" << errno << "]";
}
-void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) {
+void MessagePumpLibevent::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
// We know that we can't be blocked on Wait right now since this method can
// only be called on the same thread as Run, so we only need to update our
// record of how long to sleep when we do sleep.
diff --git a/base/message_pump_libevent.h b/base/message_pump_libevent.h
index f271612..d8d000d 100644
--- a/base/message_pump_libevent.h
+++ b/base/message_pump_libevent.h
@@ -119,7 +119,7 @@ class MessagePumpLibevent : public MessagePump {
virtual void Run(Delegate* delegate);
virtual void Quit();
virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
private:
void WillProcessIOEvent();
@@ -135,7 +135,7 @@ class MessagePumpLibevent : public MessagePump {
bool in_run_;
// The time at which we should call DoDelayedWork.
- Time delayed_work_time_;
+ TimeTicks delayed_work_time_;
// Libevent dispatcher. Watches all sockets registered with it, and sends
// readiness callbacks when a socket is ready for I/O.
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h
index 59a7329..e016d54 100644
--- a/base/message_pump_mac.h
+++ b/base/message_pump_mac.h
@@ -44,7 +44,7 @@ class NSAutoreleasePool;
namespace base {
-class Time;
+class TimeTicks;
class MessagePumpCFRunLoopBase : public MessagePump {
// Needs access to CreateAutoreleasePool.
@@ -61,7 +61,7 @@ class MessagePumpCFRunLoopBase : public MessagePump {
virtual void DoRun(Delegate* delegate) = 0;
virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
protected:
// Accessors for private data members to be used by subclasses.
diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm
index 16a9a59..9091006 100644
--- a/base/message_pump_mac.mm
+++ b/base/message_pump_mac.mm
@@ -225,11 +225,17 @@ void MessagePumpCFRunLoopBase::ScheduleWork() {
// Must be called on the run loop thread.
void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
- const Time& delayed_work_time) {
+ const TimeTicks& delayed_work_time) {
+ // TODO(jar): We may need a more efficient way to go between these times, but
+ // the difference will change not only when we sleep/wake, it will also change
+ // when the user changes the wall clock time :-/.
+ Time absolute_work_time =
+ (delayed_work_time - TimeTicks::Now()) + Time::Now();
+
Time::Exploded exploded;
- delayed_work_time.UTCExplode(&exploded);
+ absolute_work_time.UTCExplode(&exploded);
double seconds = exploded.second +
- (static_cast<double>((delayed_work_time.ToInternalValue()) %
+ (static_cast<double>((absolute_work_time.ToInternalValue()) %
Time::kMicrosecondsPerSecond) /
Time::kMicrosecondsPerSecond);
CFGregorianDate gregorian = {
@@ -320,12 +326,12 @@ bool MessagePumpCFRunLoopBase::RunDelayedWork() {
// released promptly even in the absence of UI events.
MessagePumpScopedAutoreleasePool autorelease_pool(this);
- Time next_time;
+ TimeTicks next_time;
delegate_->DoDelayedWork(&next_time);
bool more_work = !next_time.is_null();
if (more_work) {
- TimeDelta delay = next_time - Time::Now();
+ TimeDelta delay = next_time - TimeTicks::Now();
if (delay > TimeDelta()) {
// There's more delayed work to be done in the future.
ScheduleDelayedWork(next_time);
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc
index d0afd51..0df888a 100644
--- a/base/message_pump_win.cc
+++ b/base/message_pump_win.cc
@@ -66,7 +66,8 @@ int MessagePumpWin::GetCurrentDelay() const {
// Be careful here. TimeDelta has a precision of microseconds, but we want a
// value in milliseconds. If there are 5.5ms left, should the delay be 5 or
// 6? It should be 6 to avoid executing delayed work too early.
- double timeout = ceil((delayed_work_time_ - Time::Now()).InMillisecondsF());
+ double timeout =
+ ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
// If this value is negative, then we need to run delayed work soon.
int delay = static_cast<int>(timeout);
@@ -96,7 +97,7 @@ void MessagePumpForUI::ScheduleWork() {
PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0);
}
-void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) {
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
//
// We would *like* to provide high resolution timers. Windows timers using
// SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
@@ -409,7 +410,7 @@ void MessagePumpForIO::ScheduleWork() {
DCHECK(ret);
}
-void MessagePumpForIO::ScheduleDelayedWork(const Time& delayed_work_time) {
+void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
// We know that we can't be blocked right now since this method can only be
// called on the same thread as Run, so we only need to update our record of
// how long to sleep when we do sleep.
diff --git a/base/message_pump_win.h b/base/message_pump_win.h
index d7d53cb..d57fe1d 100644
--- a/base/message_pump_win.h
+++ b/base/message_pump_win.h
@@ -98,7 +98,7 @@ class MessagePumpWin : public MessagePump {
ObserverList<Observer> observers_;
// The time at which delayed work should run.
- Time delayed_work_time_;
+ TimeTicks delayed_work_time_;
// A boolean value used to indicate if there is a kMsgDoWork message pending
// in the Windows Message queue. There is at most one such message, and it
@@ -167,7 +167,7 @@ class MessagePumpForUI : public MessagePumpWin {
// MessagePump methods:
virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
// Applications can call this to encourage us to process all pending WM_PAINT
// messages. This method will process all paint messages the Windows Message
@@ -319,7 +319,7 @@ class MessagePumpForIO : public MessagePumpWin {
// MessagePump methods:
virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
// Register the handler to be used when asynchronous IO for the given file
// completes. The registration persists as long as |file_handle| is valid, so
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index aea8e85..a8138bb 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -100,7 +100,7 @@ TEST_F(FieldTrialTest, FiftyFiftyProbability) {
int counter = 0;
do {
std::string name = base::StringPrintf("FiftyFifty%d", ++counter);
- scoped_refptr<FieldTrial> trial = new FieldTrial(name, 2);
+ scoped_refptr<FieldTrial> trial(new FieldTrial(name, 2));
trial->AppendGroup("first", 1); // 50% chance of being chosen.
if (trial->group() != FieldTrial::kNotParticipating) {
first_winner = true;
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index e07b3a8..2003f25 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -61,6 +61,7 @@ Histogram::Histogram(const std::string& name, Sample minimum,
bucket_count_(bucket_count),
flags_(kNoFlags),
ranges_(bucket_count + 1, 0),
+ range_checksum_(0),
sample_() {
Initialize();
}
@@ -73,6 +74,7 @@ Histogram::Histogram(const std::string& name, TimeDelta minimum,
bucket_count_(bucket_count),
flags_(kNoFlags),
ranges_(bucket_count + 1, 0),
+ range_checksum_(0),
sample_() {
Initialize();
}
@@ -86,6 +88,7 @@ Histogram::~Histogram() {
// Just to make sure most derived class did this properly...
DCHECK(ValidateBucketRanges());
+ DCHECK(HasValidRangeChecksum());
}
bool Histogram::PrintEmptyBucket(size_t index) const {
@@ -218,7 +221,7 @@ void Histogram::Initialize() {
// We have to be careful that we don't pick a ratio between starting points in
// consecutive buckets that is sooo small, that the integer bounds are the same
// (effectively making one bucket get no values). We need to avoid:
-// (ranges_[i] == ranges_[i + 1]
+// ranges_[i] == ranges_[i + 1]
// To avoid that, we just do a fine-grained bucket width as far as we need to
// until we get a ratio that moves us along at least 2 units at a time. From
// that bucket onward we do use the exponential growth of buckets.
@@ -244,6 +247,7 @@ void Histogram::InitializeBucketRange() {
++current; // Just do a narrow bucket, and keep trying.
SetBucketRange(bucket_index, current);
}
+ ResetRangeChecksum();
DCHECK_EQ(bucket_count(), bucket_index);
}
@@ -287,6 +291,23 @@ double Histogram::GetBucketSize(Count current, size_t i) const {
return current/denominator;
}
+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;
+}
+
//------------------------------------------------------------------------------
// 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
@@ -417,6 +438,7 @@ std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
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());
@@ -432,19 +454,21 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
Pickle pickle(histogram_info.data(),
static_cast<int>(histogram_info.size()));
- void* iter = NULL;
- size_t bucket_count;
+ std::string histogram_name;
int declared_min;
int declared_max;
+ size_t bucket_count;
+ int range_checksum;
int histogram_type;
int pickle_flags;
- std::string histogram_name;
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)) {
@@ -483,6 +507,7 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
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) {
@@ -497,13 +522,64 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
}
//------------------------------------------------------------------------------
+// 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);
+}
+
+//------------------------------------------------------------------------------
// Methods for the Histogram::SampleSet class
//------------------------------------------------------------------------------
Histogram::SampleSet::SampleSet()
: counts_(),
sum_(0),
- square_sum_(0) {
+ square_sum_(0),
+ redundant_count_(0) {
}
Histogram::SampleSet::~SampleSet() {
@@ -524,9 +600,11 @@ void Histogram::SampleSet::Accumulate(Sample value, Count count,
counts_[index] += count;
sum_ += count * value;
square_sum_ += (count * value) * static_cast<int64>(value);
+ redundant_count_ += count;
DCHECK_GE(counts_[index], 0);
DCHECK_GE(sum_, 0);
DCHECK_GE(square_sum_, 0);
+ DCHECK_GE(redundant_count_, 0);
}
Count Histogram::SampleSet::TotalCount() const {
@@ -536,6 +614,7 @@ Count Histogram::SampleSet::TotalCount() const {
++it) {
total += *it;
}
+ DCHECK_EQ(total, redundant_count_);
return total;
}
@@ -543,6 +622,7 @@ void Histogram::SampleSet::Add(const SampleSet& other) {
DCHECK_EQ(counts_.size(), other.counts_.size());
sum_ += other.sum_;
square_sum_ += other.square_sum_;
+ redundant_count_ += other.redundant_count_;
for (size_t index = 0; index < counts_.size(); ++index)
counts_[index] += other.counts_[index];
}
@@ -554,6 +634,7 @@ void Histogram::SampleSet::Subtract(const SampleSet& other) {
// calculated). As a result, we don't currently CHCEK() for positive values.
sum_ -= other.sum_;
square_sum_ -= other.square_sum_;
+ redundant_count_ -= other.redundant_count_;
for (size_t index = 0; index < counts_.size(); ++index) {
counts_[index] -= other.counts_[index];
DCHECK_GE(counts_[index], 0);
@@ -563,6 +644,7 @@ void Histogram::SampleSet::Subtract(const SampleSet& other) {
bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
pickle->WriteInt64(sum_);
pickle->WriteInt64(square_sum_);
+ pickle->WriteInt64(redundant_count_);
pickle->WriteSize(counts_.size());
for (size_t index = 0; index < counts_.size(); ++index) {
@@ -576,11 +658,13 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
DCHECK_EQ(counts_.size(), 0u);
DCHECK_EQ(sum_, 0);
DCHECK_EQ(square_sum_, 0);
+ DCHECK_EQ(redundant_count_, 0);
size_t counts_size;
if (!pickle.ReadInt64(iter, &sum_) ||
!pickle.ReadInt64(iter, &square_sum_) ||
+ !pickle.ReadInt64(iter, &redundant_count_) ||
!pickle.ReadSize(iter, &counts_size)) {
return false;
}
@@ -588,14 +672,16 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
if (counts_size == 0)
return false;
+ int count = 0;
for (size_t index = 0; index < counts_size; ++index) {
int i;
if (!pickle.ReadInt(iter, &i))
return false;
counts_.push_back(i);
+ count += i;
}
-
- return true;
+ DCHECK_EQ(count, redundant_count_);
+ return count == redundant_count_;
}
//------------------------------------------------------------------------------
@@ -694,6 +780,7 @@ void LinearHistogram::InitializeBucketRange() {
(bucket_count() - 2);
SetBucketRange(i, static_cast<int> (linear_range + 0.5));
}
+ ResetRangeChecksum();
}
double LinearHistogram::GetBucketSize(Count current, size_t i) const {
@@ -740,7 +827,7 @@ BooleanHistogram::BooleanHistogram(const std::string& name)
scoped_refptr<Histogram> CustomHistogram::FactoryGet(
const std::string& name,
- const std::vector<int>& custom_ranges,
+ const std::vector<Sample>& custom_ranges,
Flags flags) {
scoped_refptr<Histogram> histogram(NULL);
@@ -774,7 +861,7 @@ Histogram::ClassType CustomHistogram::histogram_type() const {
}
CustomHistogram::CustomHistogram(const std::string& name,
- const std::vector<int>& custom_ranges)
+ const std::vector<Sample>& custom_ranges)
: Histogram(name, custom_ranges[1], custom_ranges.back(),
custom_ranges.size()) {
DCHECK_GT(custom_ranges.size(), 1u);
@@ -789,6 +876,7 @@ void CustomHistogram::InitializeBucketRange() {
DCHECK_LE(ranges_vector_->size(), bucket_count());
for (size_t index = 0; index < ranges_vector_->size(); ++index)
SetBucketRange(index, (*ranges_vector_)[index]);
+ ResetRangeChecksum();
}
double CustomHistogram::GetBucketSize(Count current, size_t i) const {
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 20f67c2..b87c891 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -36,6 +36,7 @@
#include <string>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/logging.h"
#include "base/time.h"
@@ -243,8 +244,8 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
typedef std::vector<Count> Counts;
typedef std::vector<Sample> Ranges;
- /* These enums are meant to facilitate deserialization of renderer histograms
- into the browser. */
+ // These enums are used to facilitate deserialization of renderer histograms
+ // into the browser.
enum ClassType {
HISTOGRAM,
LINEAR_HISTOGRAM,
@@ -273,6 +274,16 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
kHexRangePrintingFlag = 0x8000, // Fancy bucket-naming supported.
};
+ enum Inconsistencies {
+ NO_INCONSISTENCIES = 0x0,
+ RANGE_CHECKSUM_ERROR = 0x1,
+ BUCKET_ORDER_ERROR = 0x2,
+ COUNT_HIGH_ERROR = 0x4,
+ COUNT_LOW_ERROR = 0x8,
+
+ NEVER_EXCEEDED_VALUE = 0x10
+ };
+
struct DescriptionPair {
Sample sample;
const char* description; // Null means end of a list of pairs.
@@ -298,6 +309,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
Count TotalCount() const;
int64 sum() const { return sum_; }
int64 square_sum() const { return square_sum_; }
+ int64 redundant_count() const { return redundant_count_; }
// Arithmetic manipulation of corresponding elements of the set.
void Add(const SampleSet& other);
@@ -315,7 +327,21 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// without shared memory at some point.
int64 sum_; // sum of samples.
int64 square_sum_; // sum of squares of samples.
+
+ private:
+ // Allow tests to corrupt our innards for testing purposes.
+ FRIEND_TEST(HistogramTest, CorruptSampleCounts);
+
+ // To help identify memory corruption, we reduntantly save the number of
+ // samples we've accumulated into all of our buckets. We can compare this
+ // count to the sum of the counts in all buckets, and detect problems. Note
+ // that due to races in histogram accumulation (if a histogram is indeed
+ // updated on several threads simultaneously), the tallies might mismatch,
+ // and also the snapshotting code may asynchronously get a mismatch (though
+ // generally either race based mismatch cause is VERY rare).
+ int64 redundant_count_;
};
+
//----------------------------------------------------------------------------
// minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
// default underflow bucket.
@@ -367,6 +393,13 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// browser process.
static bool DeserializeHistogramInfo(const std::string& histogram_info);
+ // Check to see if bucket ranges, counts and tallies in the snapshot are
+ // consistent with the bucket ranges and checksums in our histogram. This can
+ // produce a false-alarm if a race occurred in the reading of the data during
+ // a SnapShot process, but should otherwise be false at all times (unless we
+ // have memory over-writes, or DRAM failures).
+ virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const;
+
//----------------------------------------------------------------------------
// Accessors for factory constuction, serialization and testing.
//----------------------------------------------------------------------------
@@ -375,6 +408,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
Sample declared_min() const { return declared_min_; }
Sample declared_max() const { return declared_max_; }
virtual Sample ranges(size_t i) const { return ranges_[i];}
+ Sample range_checksum() const { return range_checksum_; }
virtual size_t bucket_count() const { return bucket_count_; }
// Snapshot the current complete set of sample data.
// Override with atomic/locked snapshot if needed.
@@ -409,6 +443,9 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// Get normalized size, relative to the ranges_[i].
virtual double GetBucketSize(Count current, size_t i) const;
+ // Recalculate range_checksum_.
+ void ResetRangeChecksum();
+
// Return a string description of what goes in a given bucket.
// Most commonly this is the numeric value, but in derived classes it may
// be a name (or string description) given to the bucket.
@@ -430,9 +467,18 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
bool ValidateBucketRanges() const;
private:
+ // Allow tests to corrupt our innards for testing purposes.
+ FRIEND_TEST(HistogramTest, CorruptBucketBounds);
+ FRIEND_TEST(HistogramTest, CorruptSampleCounts);
+
// Post constructor initialization.
void Initialize();
+ // Return true iff the range_checksum_ matches current ranges_ vector.
+ bool HasValidRangeChecksum() const;
+
+ Sample CalculateRangeChecksum() const;
+
//----------------------------------------------------------------------------
// Helpers for emitting Ascii graphic. Each method appends data to output.
@@ -477,6 +523,11 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// The dimension of ranges_ is bucket_count + 1.
Ranges ranges_;
+ // For redundancy, we store the sum of all the sample ranges when ranges are
+ // generated. If ever there is ever a difference, then the histogram must
+ // have been corrupted.
+ Sample range_checksum_;
+
// Finally, provide the state that changes with the addition of each new
// sample.
SampleSet sample_;
@@ -561,11 +612,11 @@ class CustomHistogram : public Histogram {
virtual ClassType histogram_type() const;
static scoped_refptr<Histogram> FactoryGet(const std::string& name,
- const std::vector<int>& custom_ranges, Flags flags);
+ const std::vector<Sample>& custom_ranges, Flags flags);
protected:
CustomHistogram(const std::string& name,
- const std::vector<int>& custom_ranges);
+ const std::vector<Sample>& custom_ranges);
// Initialize ranges_ mapping.
virtual void InitializeBucketRange();
@@ -573,7 +624,7 @@ class CustomHistogram : public Histogram {
private:
// Temporary pointer used during construction/initialization, and then NULLed.
- const std::vector<int>* ranges_vector_;
+ const std::vector<Sample>* ranges_vector_;
DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
};
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index e7e3983..b9c51ad 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -308,4 +308,57 @@ TEST(HistogramTest, BucketPlacementTest) {
}
} // namespace
+
+//------------------------------------------------------------------------------
+// We can't be an an anonymous namespace while being friends, so we pop back
+// out to the base namespace here. We need to be friends to corrupt the
+// internals of the histogram and/or sampleset.
+TEST(HistogramTest, CorruptSampleCounts) {
+ scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, Histogram::kNoFlags); // As per header file.
+
+ EXPECT_EQ(0, histogram->sample_.redundant_count());
+ histogram->Add(20); // Add some samples.
+ histogram->Add(40);
+ EXPECT_EQ(2, histogram->sample_.redundant_count());
+
+ Histogram::SampleSet snapshot;
+ histogram->SnapshotSample(&snapshot);
+ EXPECT_EQ(Histogram::NO_INCONSISTENCIES, 0);
+ EXPECT_EQ(0, histogram->FindCorruption(snapshot)); // No default corruption.
+ EXPECT_EQ(2, snapshot.redundant_count());
+
+ snapshot.counts_[3] += 100; // Sample count won't match redundant count.
+ EXPECT_EQ(Histogram::COUNT_LOW_ERROR, histogram->FindCorruption(snapshot));
+ snapshot.counts_[2] -= 200;
+ EXPECT_EQ(Histogram::COUNT_HIGH_ERROR, histogram->FindCorruption(snapshot));
+
+ // But we can't spot a corruption if it is compensated for.
+ snapshot.counts_[1] += 100;
+ EXPECT_EQ(0, histogram->FindCorruption(snapshot));
+}
+
+TEST(HistogramTest, CorruptBucketBounds) {
+ scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, Histogram::kNoFlags); // As per header file.
+
+ Histogram::SampleSet snapshot;
+ histogram->SnapshotSample(&snapshot);
+ EXPECT_EQ(Histogram::NO_INCONSISTENCIES, 0);
+ EXPECT_EQ(0, histogram->FindCorruption(snapshot)); // No default corruption.
+
+ std::swap(histogram->ranges_[1], histogram->ranges_[2]);
+ EXPECT_EQ(Histogram::BUCKET_ORDER_ERROR, histogram->FindCorruption(snapshot));
+
+ std::swap(histogram->ranges_[1], histogram->ranges_[2]);
+ EXPECT_EQ(0, histogram->FindCorruption(snapshot));
+
+ ++histogram->ranges_[3];
+ EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
+ histogram->FindCorruption(snapshot));
+
+ // Repair histogram so that destructor won't DCHECK().
+ --histogram->ranges_[3];
+}
+
} // namespace base
diff --git a/base/metrics/nacl_histogram.cc b/base/metrics/nacl_histogram.cc
new file mode 100644
index 0000000..c89e646
--- /dev/null
+++ b/base/metrics/nacl_histogram.cc
@@ -0,0 +1,23 @@
+// 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.
+
+// nacl_histogram provides an enum and defines a macro that uses definitions
+// from histogram.h. Note that a histogram is an object that aggregates
+// statistics, and can summarize them in various forms, including ASCII
+// graphical, HTML, and numerically.
+// nacl_histogram information is used to compare how many times a native
+// client module has been loaded, compared to the number of chrome starts
+// and number of new tabs created.
+
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/nacl_histogram.h"
+
+// To log histogram data about NaCl.Startups, call this function with
+// a NaClHistogramValue passed in as |hvalue|
+void UmaNaclHistogramEnumeration(NaClHistogramValue histogram_value) {
+ UMA_HISTOGRAM_ENUMERATION("NaCl.Startups", histogram_value,
+ NACL_MAX_HISTOGRAM);
+}
+
diff --git a/base/metrics/nacl_histogram.h b/base/metrics/nacl_histogram.h
new file mode 100644
index 0000000..479b571
--- /dev/null
+++ b/base/metrics/nacl_histogram.h
@@ -0,0 +1,29 @@
+// 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.
+
+// nacl_histogram provides an enum and defines a macro that uses definitions
+// from histogram.h. Note that a histogram is an object that aggregates
+// statistics, and can summarize them in various forms, including ASCII
+// graphical, HTML, and numerically.
+// nacl_histogram information is used to compare how many times a native
+// client module has been loaded, compared to the number of chrome starts
+// and number of new tabs created.
+
+#ifndef BASE_METRICS_NACL_HISTOGRAM_H_
+#define BASE_METRICS_NACL_HISTOGRAM_H_
+#pragma once
+
+enum NaClHistogramValue {
+ FIRST_TAB_NACL_BASELINE, // First tab created - a baseline for NaCl starts.
+ NEW_TAB_NACL_BASELINE, // New tab created -- a baseline for NaCl starts.
+ NACL_STARTED, // NaCl process started
+ NACL_MAX_HISTOGRAM // DO NOT USE -- used by histogram for max bound.
+};
+
+// To log histogram data about NaCl.Startups, call this macro with
+// a NaClHistogramValue passed in as |histogram_value|
+void UmaNaclHistogramEnumeration(NaClHistogramValue histogram_value);
+
+#endif // BASE_METRICS_NACL_HISTOGRAM_H_
+
diff --git a/base/metrics/stats_table.cc b/base/metrics/stats_table.cc
index 261f533..bf93395 100644
--- a/base/metrics/stats_table.cc
+++ b/base/metrics/stats_table.cc
@@ -164,7 +164,7 @@ StatsTable::Private* StatsTable::Private::New(const std::string& name,
return NULL;
#else
scoped_ptr<Private> priv(new Private());
- if (!priv->shared_memory_.Create(name, false, true, size))
+ if (!priv->shared_memory_.CreateNamed(name, true, size))
return NULL;
if (!priv->shared_memory_.Map(size))
return NULL;
diff --git a/base/move.h b/base/move.h
deleted file mode 100644
index 118eb0a..0000000
--- a/base/move.h
+++ /dev/null
@@ -1,55 +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_MOVE_H_
-#define BASE_MOVE_H_
-#pragma once
-
-#include <algorithm>
-
-namespace base {
-
-// The move function provides a functional form of swap to move a swappable
-// value leverage the compiler return value optimization and avoiding copy.
-//
-// The type being moved must have an efficient swap() and be default
-// contructable and copyable.
-//
-// C++0x will contain an std::move() function that makes use of rvalue
-// references to achieve the same result. When std::move() is available, it
-// can replace base::move().
-//
-// For example, the following code will not produce any copies of the string.
-//
-// std::string f() {
-// std::string result("Hello World");
-// return result;
-// }
-//
-// class Class {
-// public:
-// Class(std::string x) // Pass sink argument by value
-// : m_(move(x)); // Move x into m_
-// private:
-// std::string m_;
-// };
-//
-// int main() {
-// Class x(f()); // the result string of f() is allocated as the temp argument
-// // to x() and then swapped into the member m_. No Strings
-// // are copied by this call.
-// ...
-
-template <typename T> // T models Regular
-T move(T& x) { // NOLINT : Non-const ref for standard library conformance
- using std::swap;
- T result;
- swap(x, result);
- return result;
-}
-
-} // namespace base
-
-#endif // BASE_MOVE_H_
-
diff --git a/base/nsimage_cache_mac.mm b/base/nsimage_cache_mac.mm
index 566a7f9..e693ed4 100644
--- a/base/nsimage_cache_mac.mm
+++ b/base/nsimage_cache_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -35,8 +35,8 @@ NSImage* ImageNamed(NSString* name) {
NSImage* result = [image_cache objectForKey:name];
if (!result) {
- DLOG_IF(INFO, [[name pathExtension] length] == 0)
- << "Suggest including the extension in the image name";
+ DVLOG_IF(1, [[name pathExtension] length] == 0) << "Suggest including the "
+ "extension in the image name";
NSString* path = [mac_util::MainAppBundle() pathForImageResource:name];
if (path) {
diff --git a/base/nss_util.cc b/base/nss_util.cc
index 5c7cafd..fd91142 100644
--- a/base/nss_util.cc
+++ b/base/nss_util.cc
@@ -14,7 +14,7 @@
#include <secmod.h>
#if defined(OS_LINUX)
-#include <linux/magic.h>
+#include <linux/nfs_fs.h>
#include <sys/vfs.h>
#endif
@@ -22,6 +22,7 @@
#include "base/logging.h"
#include "base/singleton.h"
#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
// USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not
// defined, such as on Mac and Windows, we use NSS for SSL only -- we don't
@@ -310,6 +311,10 @@ void EnsureNSPRInit() {
}
void EnsureNSSInit() {
+ // Initializing SSL causes us to do blocking IO.
+ // Temporarily allow it until we fix
+ // http://code.google.com/p/chromium/issues/detail?id=59847
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
Singleton<NSSInitSingleton>::get();
}
diff --git a/base/openssl_util.h b/base/openssl_util.h
new file mode 100644
index 0000000..4f564cf
--- /dev/null
+++ b/base/openssl_util.h
@@ -0,0 +1,53 @@
+// 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_OPENNSSL_UTIL_H_
+#define BASE_OPENNSSL_UTIL_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's
+// SHA256, HMAC, etc functions, adapting the buffer sizing rules to meet those
+// of the our base wrapper APIs.
+// This allows the library to write directly to the caller's buffer if it is of
+// sufficient size, but if not it will write to temporary |min_sized_buffer_|
+// of required size and then its content is automatically copied out on
+// destruction, with truncation as appropriate.
+template<int MIN_SIZE>
+class ScopedOpenSSLSafeSizeBuffer {
+ public:
+ ScopedOpenSSLSafeSizeBuffer(unsigned char* output, size_t output_len)
+ : output_(output),
+ output_len_(output_len) {
+ }
+
+ ~ScopedOpenSSLSafeSizeBuffer() {
+ if (output_len_ < MIN_SIZE) {
+ // Copy the temporary buffer out, truncating as needed.
+ memcpy(output_, min_sized_buffer_, output_len_);
+ }
+ // else... any writing already happened directly into |output_|.
+ }
+
+ unsigned char* safe_buffer() {
+ return output_len_ < MIN_SIZE ? min_sized_buffer_ : output_;
+ }
+
+ private:
+ // Pointer to the caller's data area and it's associated size, where data
+ // written via safe_buffer() will [eventually] end up.
+ unsigned char* output_;
+ size_t output_len_;
+
+ // Temporary buffer writen into in the case where the caller's
+ // buffer is not of sufficient size.
+ unsigned char min_sized_buffer_[MIN_SIZE];
+};
+
+} // namespace base
+
+#endif // BASE_NSS_UTIL_H_
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
index 4c41aed..c65f7a5 100644
--- a/base/path_service_unittest.cc
+++ b/base/path_service_unittest.cc
@@ -21,6 +21,12 @@ namespace {
bool ReturnsValidPath(int dir_type) {
FilePath path;
bool result = PathService::Get(dir_type, &path);
+#if defined(OS_POSIX)
+ // If chromium has never been started on this account, the cache path will not
+ // exist.
+ if (dir_type == base::DIR_USER_CACHE)
+ return result && !path.value().empty();
+#endif
return result && !path.value().empty() && file_util::PathExists(path);
}
diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc
index b691f00..8af078b 100644
--- a/base/platform_file_posix.cc
+++ b/base/platform_file_posix.cc
@@ -54,8 +54,9 @@ PlatformFile CreatePlatformFile(const FilePath& name, int flags,
open_flags |= O_RDWR;
} else if (flags & PLATFORM_FILE_WRITE) {
open_flags |= O_WRONLY;
- } else if (!(flags & PLATFORM_FILE_READ ||
- flags & PLATFORM_FILE_WRITE_ATTRIBUTES)) {
+ } else if (!(flags & PLATFORM_FILE_READ) &&
+ !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
+ !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
NOTREACHED();
}
diff --git a/base/platform_file_win.cc b/base/platform_file_win.cc
index 3aa02e8..34d8e45 100644
--- a/base/platform_file_win.cc
+++ b/base/platform_file_win.cc
@@ -6,6 +6,7 @@
#include "base/file_path.h"
#include "base/logging.h"
+#include "base/thread_restrictions.h"
namespace base {
@@ -13,6 +14,8 @@ PlatformFile CreatePlatformFile(const FilePath& name,
int flags,
bool* created,
PlatformFileError* error_code) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
DWORD disposition = 0;
if (flags & PLATFORM_FILE_OPEN)
@@ -108,10 +111,12 @@ PlatformFile CreatePlatformFile(const std::wstring& name, int flags,
}
bool ClosePlatformFile(PlatformFile file) {
+ base::ThreadRestrictions::AssertIOAllowed();
return (CloseHandle(file) != 0);
}
int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (file == kInvalidPlatformFileValue)
return -1;
@@ -133,6 +138,7 @@ int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
int WritePlatformFile(PlatformFile file, int64 offset,
const char* data, int size) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (file == kInvalidPlatformFileValue)
return -1;
@@ -151,6 +157,7 @@ int WritePlatformFile(PlatformFile file, int64 offset,
}
bool TruncatePlatformFile(PlatformFile file, int64 length) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (file == kInvalidPlatformFileValue)
return false;
@@ -176,11 +183,13 @@ bool TruncatePlatformFile(PlatformFile file, int64 length) {
}
bool FlushPlatformFile(PlatformFile file) {
+ base::ThreadRestrictions::AssertIOAllowed();
return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file));
}
bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
const base::Time& last_modified_time) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (file == kInvalidPlatformFileValue)
return false;
@@ -191,6 +200,7 @@ bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
}
bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (!info)
return false;
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index 231db59..6138c07 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -22,6 +22,7 @@
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/sys_info.h"
+#include "base/thread_restrictions.h"
namespace {
@@ -33,6 +34,9 @@ enum ParsingState {
// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
// spaces. Returns true if successful.
bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
FilePath stat_file("/proc");
stat_file = stat_file.Append(base::IntToString(pid));
stat_file = stat_file.Append("stat");
@@ -49,6 +53,9 @@ bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
// null characters. We tokenize it into a vector of strings using '\0' as a
// delimiter.
bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
FilePath cmd_line_file("/proc");
cmd_line_file = cmd_line_file.Append(base::IntToString(pid));
cmd_line_file = cmd_line_file.Append("cmdline");
@@ -66,6 +73,9 @@ bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
namespace base {
ProcessId GetParentProcessId(ProcessHandle process) {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
FilePath stat_file("/proc");
stat_file = stat_file.Append(base::IntToString(process));
stat_file = stat_file.Append("status");
@@ -307,6 +317,9 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
// close approximation.
// See http://www.pixelbeat.org/scripts/ps_mem.py
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
FilePath stat_file =
FilePath("/proc").Append(base::IntToString(process_)).Append("smaps");
std::string smaps;
@@ -380,6 +393,9 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
// in your kernel configuration.
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
std::string proc_io_contents;
FilePath io_file("/proc");
io_file = io_file.Append(base::IntToString(process_));
@@ -447,6 +463,9 @@ int ParseProcStatCPU(const std::string& input) {
// 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));
@@ -534,6 +553,9 @@ const size_t kMemCacheIndex = 10;
} // namespace
size_t GetSystemCommitCharge() {
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
// Used memory is: total - free - buffers - caches
FilePath meminfo_file("/proc/meminfo");
std::string meminfo_data;
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index cae47bf..b167aa2 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -23,7 +23,7 @@
#include <new>
#include <string>
-#include "base/debug_util.h"
+#include "base/debug/debugger.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/string_util.h"
@@ -166,7 +166,7 @@ bool ProcessIterator::CheckForNextProcess() {
}
bool NamedProcessIterator::IncludeEntry() {
- return (base::SysWideToUTF8(executable_name_) == entry().exe_file() &&
+ return (SysWideToUTF8(executable_name_) == entry().exe_file() &&
ProcessIterator::IncludeEntry());
}
@@ -187,7 +187,7 @@ ProcessMetrics::ProcessMetrics(ProcessHandle process,
last_time_(0),
last_system_time_(0),
port_provider_(port_provider) {
- processor_count_ = base::SysInfo::NumberOfProcessors();
+ processor_count_ = SysInfo::NumberOfProcessors();
}
// static
@@ -402,7 +402,7 @@ void* oom_killer_malloc(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_malloc(zone, size);
if (!result && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -411,7 +411,7 @@ void* oom_killer_calloc(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_calloc(zone, num_items, size);
if (!result && num_items && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -419,7 +419,7 @@ void* oom_killer_valloc(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_valloc(zone, size);
if (!result && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -428,7 +428,7 @@ void* oom_killer_realloc(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_realloc(zone, ptr, size);
if (!result && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -441,7 +441,7 @@ void* oom_killer_memalign(struct _malloc_zone_t* zone,
// http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
if (!result && size && alignment >= sizeof(void*)
&& (alignment & (alignment - 1)) == 0) {
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
}
return result;
}
@@ -450,7 +450,7 @@ void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_malloc_purgeable(zone, size);
if (!result && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -459,7 +459,7 @@ void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_calloc_purgeable(zone, num_items, size);
if (!result && num_items && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -467,7 +467,7 @@ void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_valloc_purgeable(zone, size);
if (!result && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -476,7 +476,7 @@ void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_realloc_purgeable(zone, ptr, size);
if (!result && size)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -489,7 +489,7 @@ void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
// http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
if (!result && size && alignment >= sizeof(void*)
&& (alignment & (alignment - 1)) == 0) {
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
}
return result;
}
@@ -497,7 +497,7 @@ void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
// === C++ operator new ===
void oom_killer_new() {
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
}
// === Core Foundation CFAllocators ===
@@ -513,7 +513,7 @@ void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
void* info) {
void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
if (!result)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -522,7 +522,7 @@ void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
void* info) {
void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
if (!result)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -531,7 +531,7 @@ void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
void* info) {
void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
if (!result)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
@@ -544,7 +544,7 @@ id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone)
{
id result = g_old_allocWithZone(self, _cmd, zone);
if (!result)
- DebugUtil::BreakDebugger();
+ debug::BreakDebugger();
return result;
}
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index b1dbabd..07e3125 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -18,7 +18,7 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
-#include "base/debug_util.h"
+#include "base/debug/stack_trace.h"
#include "base/dir_reader_posix.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
@@ -103,7 +103,7 @@ int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
void StackDumpSignalHandler(int signal) {
LOG(ERROR) << "Received signal " << signal;
- StackTrace().PrintBacktrace();
+ debug::StackTrace().PrintBacktrace();
_exit(1);
}
diff --git a/base/process_util_win.cc b/base/process_util_win.cc
index 92077b1..097888e 100644
--- a/base/process_util_win.cc
+++ b/base/process_util_win.cc
@@ -13,7 +13,7 @@
#include <ios>
#include "base/command_line.h"
-#include "base/debug_util.h"
+#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/scoped_ptr.h"
@@ -40,7 +40,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
// Prints the exception call stack.
// This is the unit tests exception filter.
long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
- StackTrace(info).PrintBacktrace();
+ debug::StackTrace(info).PrintBacktrace();
if (g_previous_filter)
return g_previous_filter(info);
return EXCEPTION_CONTINUE_SEARCH;
@@ -155,7 +155,7 @@ bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
if (!level)
return false;
- if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ if (win::GetVersion() < base::win::VERSION_VISTA)
return false;
HANDLE process_token;
@@ -163,7 +163,7 @@ bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
&process_token))
return false;
- base::win::ScopedHandle scoped_process_token(process_token);
+ win::ScopedHandle scoped_process_token(process_token);
DWORD token_info_length = 0;
if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
@@ -326,8 +326,8 @@ bool GetAppOutput(const CommandLine& cl, std::string* output) {
}
// Ensure we don't leak the handles.
- base::win::ScopedHandle scoped_out_read(out_read);
- base::win::ScopedHandle scoped_out_write(out_write);
+ win::ScopedHandle scoped_out_read(out_read);
+ win::ScopedHandle scoped_out_write(out_write);
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
diff --git a/base/ref_counted.h b/base/ref_counted.h
index 2cc4029..9c84efa 100644
--- a/base/ref_counted.h
+++ b/base/ref_counted.h
@@ -106,7 +106,7 @@ template <class T, typename Traits> class RefCountedThreadSafe;
// count reaches 0. Overload to delete it on a different thread etc.
template<typename T>
struct DefaultRefCountedThreadSafeTraits {
- static void Destruct(T* x) {
+ static void Destruct(const T* x) {
// Delete through RefCountedThreadSafe to make child classes only need to be
// friend with RefCountedThreadSafe instead of this struct, which is an
// implementation detail.
@@ -133,19 +133,19 @@ class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
RefCountedThreadSafe() { }
~RefCountedThreadSafe() { }
- void AddRef() {
+ void AddRef() const {
subtle::RefCountedThreadSafeBase::AddRef();
}
- void Release() {
+ void Release() const {
if (subtle::RefCountedThreadSafeBase::Release()) {
- Traits::Destruct(static_cast<T*>(this));
+ Traits::Destruct(static_cast<const T*>(this));
}
}
private:
friend struct DefaultRefCountedThreadSafeTraits<T>;
- static void DeleteInternal(T* x) { delete x; }
+ static void DeleteInternal(const T* x) { delete x; }
DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
};
diff --git a/base/ref_counted_unittest.cc b/base/ref_counted_unittest.cc
index f2739fc..cd6f922 100644
--- a/base/ref_counted_unittest.cc
+++ b/base/ref_counted_unittest.cc
@@ -26,7 +26,7 @@ class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
TEST(RefCountedUnitTest, TestSelfAssignment) {
SelfAssign* p = new SelfAssign;
- scoped_refptr<SelfAssign> var = p;
+ scoped_refptr<SelfAssign> var(p);
var = var;
EXPECT_EQ(var.get(), p);
}
diff --git a/base/registry.h b/base/registry.h
deleted file mode 100644
index 5ef45f2..0000000
--- a/base/registry.h
+++ /dev/null
@@ -1,39 +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_REGISTRY_H_
-#define BASE_REGISTRY_H_
-#pragma once
-
-// TODO(brettw) remove this file when all callers are converted to using the
-// new location & namespace.
-#include "base/win/registry.h"
-
-class RegKey : public base::win::RegKey {
- public:
- RegKey() {}
- RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
- : base::win::RegKey(rootkey, subkey, access) {}
- ~RegKey() { base::win::RegKey::~RegKey(); }
-};
-
-class RegistryValueIterator : public base::win::RegistryValueIterator {
- public:
- RegistryValueIterator(HKEY root_key, const wchar_t* folder_key)
- : base::win::RegistryValueIterator(root_key, folder_key) {}
- ~RegistryValueIterator() {
- base::win::RegistryValueIterator::~RegistryValueIterator();
- }
-};
-
-class RegistryKeyIterator : public base::win::RegistryKeyIterator {
- public:
- RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key)
- : base::win::RegistryKeyIterator(root_key, folder_key) {}
- ~RegistryKeyIterator() {
- base::win::RegistryKeyIterator::~RegistryKeyIterator();
- }
-};
-
-#endif // BASE_REGISTRY_H_
diff --git a/base/scoped_temp_dir.cc b/base/scoped_temp_dir.cc
index a510ddf..5cd13b4 100644
--- a/base/scoped_temp_dir.cc
+++ b/base/scoped_temp_dir.cc
@@ -15,6 +15,9 @@ ScopedTempDir::~ScopedTempDir() {
}
bool ScopedTempDir::CreateUniqueTempDir() {
+ if (!path_.empty())
+ return false;
+
// This "scoped_dir" prefix is only used on Windows and serves as a template
// for the unique name.
if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_dir"),
@@ -25,7 +28,10 @@ bool ScopedTempDir::CreateUniqueTempDir() {
}
bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) {
- // If |path| does not exist, create it.
+ if (!path_.empty())
+ return false;
+
+ // If |base_path| does not exist, create it.
if (!file_util::CreateDirectory(base_path))
return false;
@@ -33,18 +39,20 @@ bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) {
if (!file_util::CreateTemporaryDirInDir(
base_path,
FILE_PATH_LITERAL("scoped_dir_"),
- &path_)) {
+ &path_))
return false;
- }
+
return true;
}
bool ScopedTempDir::Set(const FilePath& path) {
- DCHECK(path_.empty());
+ if (!path_.empty())
+ return false;
+
if (!file_util::DirectoryExists(path) &&
- !file_util::CreateDirectory(path)) {
+ !file_util::CreateDirectory(path))
return false;
- }
+
path_ = path;
return true;
}
diff --git a/base/scoped_temp_dir.h b/base/scoped_temp_dir.h
index 66d52f6..6845562 100644
--- a/base/scoped_temp_dir.h
+++ b/base/scoped_temp_dir.h
@@ -11,6 +11,10 @@
// deletion occurs during the destructor, no further error handling is possible
// if the directory fails to be deleted. As a result, deletion is not
// guaranteed by this class.
+//
+// Multiple calls to the methods which establish a temporary directory
+// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have
+// intervening calls to Delete or Take, or the calls will fail.
#include "base/file_path.h"
diff --git a/base/scoped_temp_dir_unittest.cc b/base/scoped_temp_dir_unittest.cc
index 4be0d07..cf5fed3 100644
--- a/base/scoped_temp_dir_unittest.cc
+++ b/base/scoped_temp_dir_unittest.cc
@@ -73,3 +73,17 @@ TEST(ScopedTempDir, UniqueTempDirUnderPath) {
}
EXPECT_FALSE(file_util::DirectoryExists(test_path));
}
+
+TEST(ScopedTempDir, MultipleInvocations) {
+ ScopedTempDir dir;
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(dir.CreateUniqueTempDir());
+ dir.Delete();
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(dir.CreateUniqueTempDir());
+ ScopedTempDir other_dir;
+ other_dir.Set(dir.Take());
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(other_dir.CreateUniqueTempDir());
+}
diff --git a/base/sha2_openssl.cc b/base/sha2_openssl.cc
new file mode 100644
index 0000000..afbce2f
--- /dev/null
+++ b/base/sha2_openssl.cc
@@ -0,0 +1,30 @@
+// 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/sha2.h"
+
+#include <openssl/ssl.h>
+
+#include "base/basictypes.h"
+#include "base/openssl_util.h"
+#include "base/stl_util-inl.h"
+
+namespace base {
+
+void SHA256HashString(const std::string& str, void* output, size_t len) {
+ COMPILE_ASSERT(SHA256_LENGTH == SHA256_DIGEST_LENGTH,
+ API_and_OpenSSL_SHA256_lengths_must_match);
+ ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result(
+ reinterpret_cast<unsigned char*>(output), len);
+ ::SHA256(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
+ result.safe_buffer());
+}
+
+std::string SHA256HashString(const std::string& str) {
+ std::string output(SHA256_LENGTH, 0);
+ SHA256HashString(str, string_as_array(&output), output.size());
+ return output;
+}
+
+} // namespace base
diff --git a/base/shared_memory.h b/base/shared_memory.h
index 053026e..719eb69 100644
--- a/base/shared_memory.h
+++ b/base/shared_memory.h
@@ -43,6 +43,13 @@ class SharedMemory {
public:
SharedMemory();
+#if defined(OS_WIN)
+ // Similar to the default constructor, except that this allows for
+ // calling Lock() to acquire the named mutex before either Create or Open
+ // are called on Windows.
+ explicit SharedMemory(const std::wstring& name);
+#endif
+
// Create a new SharedMemory object from an existing, open
// shared memory file.
SharedMemory(SharedMemoryHandle handle, bool read_only);
@@ -66,14 +73,21 @@ class SharedMemory {
// Closes a shared memory handle.
static void CloseHandle(const SharedMemoryHandle& handle);
+ // Creates and maps an anonymous shared memory segment of size size.
+ // Returns true on success and false on failure.
+ bool CreateAndMapAnonymous(uint32 size);
+
+ // Creates an anonymous shared memory segment of size size.
+ // Returns true on success and false on failure.
+ bool CreateAnonymous(uint32 size);
+
// Creates or opens a shared memory segment based on a name.
- // If read_only is true, opens the memory as read-only.
// If open_existing is true, and the shared memory already exists,
// opens the existing shared memory and ignores the size parameter.
- // If name is the empty string, use a unique name.
+ // If open_existing is false, shared memory must not exist.
+ // size is the size of the block to be created.
// Returns true on success, false on failure.
- bool Create(const std::string& name, bool read_only, bool open_existing,
- uint32 size);
+ bool CreateNamed(const std::string& name, bool open_existing, uint32 size);
// Deletes resources associated with a shared memory segment based on name.
// Not all platforms require this call.
@@ -81,7 +95,6 @@ class SharedMemory {
// Opens a shared memory segment based on a name.
// If read_only is true, opens for read-only access.
- // If name is the empty string, use a unique name.
// Returns true on success, false on failure.
bool Open(const std::string& name, bool read_only);
@@ -95,12 +108,15 @@ class SharedMemory {
// memory is not mapped.
bool Unmap();
- // Get the size of the opened shared memory backing file.
+ // Get the size of the shared memory backing file.
// Note: This size is only available to the creator of the
// shared memory, and not to those that opened shared memory
// created externally.
- // Returns 0 if not opened or unknown.
- uint32 max_size() const { return max_size_; }
+ // Returns 0 if not created or unknown.
+ // Deprecated method, please keep track of the size yourself if you created
+ // it.
+ // http://crbug.com/60821
+ uint32 created_size() const { return created_size_; }
// Gets a pointer to the opened memory space if it has been
// Mapped via Map(). Returns NULL if it is not mapped.
@@ -156,12 +172,18 @@ class SharedMemory {
// across Mac and Linux.
void Lock();
+#if defined(OS_WIN)
+ // A Lock() implementation with a timeout. Returns true if the Lock() has
+ // been acquired, false if the timeout was reached.
+ bool Lock(uint32 timeout_ms);
+#endif
+
// Releases the shared memory lock.
void Unlock();
private:
#if defined(OS_POSIX)
- bool CreateOrOpen(const std::string& name, int posix_flags, uint32 size);
+ bool PrepareMapFile(FILE *fp);
bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
void LockOrUnlockCommon(int function);
#endif
@@ -174,11 +196,12 @@ class SharedMemory {
HANDLE mapped_file_;
#elif defined(OS_POSIX)
int mapped_file_;
+ uint32 mapped_size_;
ino_t inode_;
#endif
void* memory_;
bool read_only_;
- uint32 max_size_;
+ uint32 created_size_;
#if !defined(OS_POSIX)
SharedMemoryLock lock_;
#endif
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc
index dfd86aa..88203dd 100644
--- a/base/shared_memory_posix.cc
+++ b/base/shared_memory_posix.cc
@@ -14,6 +14,7 @@
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/safe_strerror_posix.h"
+#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
namespace base {
@@ -26,18 +27,20 @@ const char kSemaphoreSuffix[] = "-sem";
SharedMemory::SharedMemory()
: mapped_file_(-1),
+ mapped_size_(0),
inode_(0),
memory_(NULL),
read_only_(false),
- max_size_(0) {
+ created_size_(0) {
}
SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
: mapped_file_(handle.fd),
+ mapped_size_(0),
inode_(0),
memory_(NULL),
read_only_(read_only),
- max_size_(0) {
+ created_size_(0) {
struct stat st;
if (fstat(handle.fd, &st) == 0) {
// If fstat fails, then the file descriptor is invalid and we'll learn this
@@ -49,9 +52,11 @@ SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
ProcessHandle process)
: mapped_file_(handle.fd),
+ mapped_size_(0),
+ inode_(0),
memory_(NULL),
read_only_(read_only),
- max_size_(0) {
+ created_size_(0) {
// We don't handle this case yet (note the ignored parameter); let's die if
// someone comes calling.
NOTREACHED();
@@ -77,20 +82,90 @@ void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
close(handle.fd);
}
-bool SharedMemory::Create(const std::string& name, bool read_only,
- bool open_existing, uint32 size) {
- read_only_ = read_only;
+bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
+ return CreateAnonymous(size) && Map(size);
+}
+
+bool SharedMemory::CreateAnonymous(uint32 size) {
+ return CreateNamed("", false, size);
+}
+
+// Chromium mostly only uses the unique/private shmem as specified by
+// "name == L"". The exception is in the StatsTable.
+// TODO(jrg): there is no way to "clean up" all unused named shmem if
+// we restart from a crash. (That isn't a new problem, but it is a problem.)
+// In case we want to delete it later, it may be useful to save the value
+// of mem_filename after FilePathForMemoryName().
+bool SharedMemory::CreateNamed(const std::string& name,
+ bool open_existing, uint32 size) {
+ DCHECK(mapped_file_ == -1);
+ if (size == 0) return false;
+
+ // This function theoretically can block on the disk, but realistically
+ // the temporary files we create will just go into the buffer cache
+ // and be deleted before they ever make it out to disk.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
- int posix_flags = 0;
- posix_flags |= read_only ? O_RDONLY : O_RDWR;
- if (!open_existing || mapped_file_ <= 0)
- posix_flags |= O_CREAT;
+ FILE *fp;
+ bool fix_size = true;
- if (!CreateOrOpen(name, posix_flags, size))
+ FilePath path;
+ if (name.empty()) {
+ // It doesn't make sense to have a open-existing private piece of shmem
+ DCHECK(!open_existing);
+ // Q: Why not use the shm_open() etc. APIs?
+ // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
+ fp = file_util::CreateAndOpenTemporaryShmemFile(&path);
+
+ // Deleting the file prevents anyone else from mapping it in
+ // (making it private), and prevents the need for cleanup (once
+ // the last fd is closed, it is truly freed).
+ if (fp)
+ file_util::Delete(path, false);
+
+ } else {
+ if (!FilePathForMemoryName(name, &path))
+ return false;
+
+ fp = file_util::OpenFile(path, "w+x");
+ if (fp == NULL && open_existing) {
+ // "w+" will truncate if it already exists.
+ fp = file_util::OpenFile(path, "a+");
+ fix_size = false;
+ }
+ }
+ if (fp && fix_size) {
+ // Get current size.
+ struct stat stat;
+ if (fstat(fileno(fp), &stat) != 0)
+ return false;
+ const uint32 current_size = stat.st_size;
+ if (current_size != size) {
+ if (ftruncate(fileno(fp), size) != 0)
+ return false;
+ if (fseeko(fp, size, SEEK_SET) != 0)
+ return false;
+ }
+ created_size_ = size;
+ }
+ if (fp == NULL) {
+#if !defined(OS_MACOSX)
+ PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+ FilePath dir = path.DirName();
+ if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
+ PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
+ if (dir.value() == "/dev/shm") {
+ LOG(FATAL) << "This is frequently caused by incorrect permissions on "
+ << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.";
+ }
+ }
+#else
+ PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+#endif
return false;
+ }
- max_size_ = size;
- return true;
+ return PrepareMapFile(fp);
}
// Our current implementation of shmem is with mmap()ing of files.
@@ -110,12 +185,15 @@ bool SharedMemory::Delete(const std::string& name) {
}
bool SharedMemory::Open(const std::string& name, bool read_only) {
- read_only_ = read_only;
+ FilePath path;
+ if (!FilePathForMemoryName(name, &path))
+ return false;
- int posix_flags = 0;
- posix_flags |= read_only ? O_RDONLY : O_RDWR;
+ read_only_ = read_only;
- return CreateOrOpen(name, posix_flags, 0);
+ const char *mode = read_only ? "r" : "r+";
+ FILE *fp = file_util::OpenFile(path, mode);
+ return PrepareMapFile(fp);
}
// For the given shmem named |mem_name|, return a filename to mmap()
@@ -136,92 +214,16 @@ bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
return true;
}
-// Chromium mostly only use the unique/private shmem as specified by
-// "name == L"". The exception is in the StatsTable.
-// TODO(jrg): there is no way to "clean up" all unused named shmem if
-// we restart from a crash. (That isn't a new problem, but it is a problem.)
-// In case we want to delete it later, it may be useful to save the value
-// of mem_filename after FilePathForMemoryName().
-bool SharedMemory::CreateOrOpen(const std::string& name,
- int posix_flags, uint32 size) {
+bool SharedMemory::PrepareMapFile(FILE *fp) {
DCHECK(mapped_file_ == -1);
+ if (fp == NULL) return false;
- file_util::ScopedFILE file_closer;
- FILE *fp;
-
- FilePath path;
- if (name.empty()) {
- // It doesn't make sense to have a read-only private piece of shmem
- DCHECK(posix_flags & (O_RDWR | O_WRONLY));
-
- // Q: Why not use the shm_open() etc. APIs?
- // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
- fp = file_util::CreateAndOpenTemporaryShmemFile(&path);
-
- // Deleting the file prevents anyone else from mapping it in
- // (making it private), and prevents the need for cleanup (once
- // the last fd is closed, it is truly freed).
- if (fp)
- file_util::Delete(path, false);
- } else {
- if (!FilePathForMemoryName(name, &path))
- return false;
-
- std::string mode;
- switch (posix_flags) {
- case (O_RDWR | O_CREAT):
- // Careful: "w+" will truncate if it already exists.
- mode = "a+";
- break;
- case O_RDWR:
- mode = "r+";
- break;
- case O_RDONLY:
- mode = "r";
- break;
- default:
- NOTIMPLEMENTED();
- break;
- }
-
- fp = file_util::OpenFile(path, mode.c_str());
- }
-
- if (fp == NULL) {
- if (posix_flags & O_CREAT) {
-#if !defined(OS_MACOSX)
- PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
- FilePath dir = path.DirName();
- if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
- PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
- if (dir.value() == "/dev/shm") {
- LOG(FATAL) << "This is frequently caused by incorrect permissions on "
- << "/dev/shm. Try 'sudo chmod 777 /dev/shm' to fix.";
- }
- }
-#else
- PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
-#endif
- }
- return false;
- }
-
- file_closer.reset(fp); // close when we go out of scope
+ // This function theoretically can block on the disk, but realistically
+ // the temporary files we create will just go into the buffer cache
+ // and be deleted before they ever make it out to disk.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
- // Make sure the (new) file is the right size.
- if (size && (posix_flags & (O_RDWR | O_CREAT))) {
- // Get current size.
- struct stat stat;
- if (fstat(fileno(fp), &stat) != 0)
- return false;
- const uint32 current_size = stat.st_size;
- if (current_size != size) {
- if (ftruncate(fileno(fp), size) != 0)
- return false;
- if (fseeko(fp, size, SEEK_SET) != 0)
- return false;
- }
- }
+ file_util::ScopedFILE file_closer(fp);
mapped_file_ = dup(fileno(fp));
if (mapped_file_ == -1) {
@@ -249,7 +251,7 @@ bool SharedMemory::Map(uint32 bytes) {
MAP_SHARED, mapped_file_, 0);
if (memory_)
- max_size_ = bytes;
+ mapped_size_ = bytes;
bool mmap_succeeded = (memory_ != (void*)-1);
DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno;
@@ -260,9 +262,9 @@ bool SharedMemory::Unmap() {
if (memory_ == NULL)
return false;
- munmap(memory_, max_size_);
+ munmap(memory_, mapped_size_);
memory_ = NULL;
- max_size_ = 0;
+ mapped_size_ = 0;
return true;
}
diff --git a/base/shared_memory_unittest.cc b/base/shared_memory_unittest.cc
index 53bffb4..f646158 100644
--- a/base/shared_memory_unittest.cc
+++ b/base/shared_memory_unittest.cc
@@ -8,6 +8,7 @@
#include "base/shared_memory.h"
#include "base/scoped_ptr.h"
#include "base/test/multiprocess_test.h"
+#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -36,7 +37,7 @@ class MultipleThreadMain : public PlatformThread::Delegate {
mac::ScopedNSAutoreleasePool pool; // noop if not OSX
const uint32 kDataSize = 1024;
SharedMemory memory;
- bool rv = memory.Create(s_test_name_, false, true, kDataSize);
+ bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
EXPECT_TRUE(rv);
rv = memory.Map(kDataSize);
EXPECT_TRUE(rv);
@@ -82,8 +83,8 @@ class MultipleLockThread : public PlatformThread::Delegate {
SharedMemoryHandle handle = NULL;
{
SharedMemory memory1;
- EXPECT_TRUE(memory1.Create("SharedMemoryMultipleLockThreadTest",
- false, true, kDataSize));
+ EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest",
+ true, kDataSize));
EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
// TODO(paulg): Implement this once we have a posix version of
// SharedMemory::ShareToProcess.
@@ -128,7 +129,7 @@ TEST(SharedMemoryTest, OpenClose) {
EXPECT_TRUE(rv);
rv = memory1.Open(test_name, false);
EXPECT_FALSE(rv);
- rv = memory1.Create(test_name, false, false, kDataSize);
+ rv = memory1.CreateNamed(test_name, false, kDataSize);
EXPECT_TRUE(rv);
rv = memory1.Map(kDataSize);
EXPECT_TRUE(rv);
@@ -163,6 +164,58 @@ TEST(SharedMemoryTest, OpenClose) {
EXPECT_TRUE(rv);
}
+TEST(SharedMemoryTest, OpenExclusive) {
+ const uint32 kDataSize = 1024;
+ const uint32 kDataSize2 = 2048;
+ std::ostringstream test_name_stream;
+ test_name_stream << "SharedMemoryOpenExclusiveTest."
+ << Time::Now().ToDoubleT();
+ std::string test_name = test_name_stream.str();
+
+ // Open two handles to a memory segment and check that open_existing works
+ // as expected.
+ SharedMemory memory1;
+ bool rv = memory1.CreateNamed(test_name, false, kDataSize);
+ EXPECT_TRUE(rv);
+
+ // Memory1 knows it's size because it created it.
+ EXPECT_EQ(memory1.created_size(), kDataSize);
+
+ rv = memory1.Map(kDataSize);
+ EXPECT_TRUE(rv);
+
+ memset(memory1.memory(), 'G', kDataSize);
+
+ SharedMemory memory2;
+ // Should not be able to create if openExisting is false.
+ rv = memory2.CreateNamed(test_name, false, kDataSize2);
+ EXPECT_FALSE(rv);
+
+ // Should be able to create with openExisting true.
+ rv = memory2.CreateNamed(test_name, true, kDataSize2);
+ EXPECT_TRUE(rv);
+
+ // Memory2 shouldn't know the size because we didn't create it.
+ EXPECT_EQ(memory2.created_size(), 0U);
+
+ // We should be able to map the original size.
+ rv = memory2.Map(kDataSize);
+ EXPECT_TRUE(rv);
+
+ // Verify that opening memory2 didn't truncate or delete memory 1.
+ char *start_ptr = static_cast<char *>(memory2.memory());
+ char *end_ptr = start_ptr + kDataSize;
+ for (char* ptr = start_ptr; ptr < end_ptr; ptr++) {
+ EXPECT_EQ(*ptr, 'G');
+ }
+
+ memory1.Close();
+ memory2.Close();
+
+ rv = memory1.Delete(test_name);
+ EXPECT_TRUE(rv);
+}
+
// Create a set of N threads to each open a shared memory segment and write to
// it. Verify that they are always reading/writing consistent data.
TEST(SharedMemoryTest, MultipleThreads) {
@@ -243,9 +296,7 @@ TEST(SharedMemoryTest, AnonymousPrivate) {
ASSERT_TRUE(pointers.get());
for (i = 0; i < count; i++) {
- rv = memories[i].Create("", false, true, kDataSize);
- EXPECT_TRUE(rv);
- rv = memories[i].Map(kDataSize);
+ rv = memories[i].CreateAndMapAnonymous(kDataSize);
EXPECT_TRUE(rv);
int *ptr = static_cast<int*>(memories[i].memory());
EXPECT_TRUE(ptr);
@@ -289,7 +340,7 @@ class SharedMemoryProcessTest : public base::MultiProcessTest {
mac::ScopedNSAutoreleasePool pool; // noop if not OSX
const uint32 kDataSize = 1024;
SharedMemory memory;
- bool rv = memory.Create(s_test_name_, false, true, kDataSize);
+ bool rv = memory.CreateNamed(s_test_name_, true, kDataSize);
EXPECT_TRUE(rv);
if (rv != true)
errors++;
@@ -320,7 +371,13 @@ class SharedMemoryProcessTest : public base::MultiProcessTest {
const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
-TEST_F(SharedMemoryProcessTest, Tasks) {
+#if defined(OS_MACOSX)
+#define MAYBE_Tasks FLAKY_Tasks
+#else
+#define MAYBE_Tasks Tasks
+#endif
+
+TEST_F(SharedMemoryProcessTest, MAYBE_Tasks) {
SharedMemoryProcessTest::CleanUp();
base::ProcessHandle handles[kNumTasks];
diff --git a/base/shared_memory_win.cc b/base/shared_memory_win.cc
index f35ada1..5f293fc 100644
--- a/base/shared_memory_win.cc
+++ b/base/shared_memory_win.cc
@@ -13,15 +13,24 @@ SharedMemory::SharedMemory()
: mapped_file_(NULL),
memory_(NULL),
read_only_(false),
- max_size_(0),
+ created_size_(0),
lock_(NULL) {
}
+SharedMemory::SharedMemory(const std::wstring& name)
+ : mapped_file_(NULL),
+ memory_(NULL),
+ read_only_(false),
+ created_size_(0),
+ lock_(NULL),
+ name_(name) {
+}
+
SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
: mapped_file_(handle),
memory_(NULL),
read_only_(read_only),
- max_size_(0),
+ created_size_(0),
lock_(NULL) {
}
@@ -30,7 +39,7 @@ SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
: mapped_file_(NULL),
memory_(NULL),
read_only_(read_only),
- max_size_(0),
+ created_size_(0),
lock_(NULL) {
::DuplicateHandle(process, handle,
GetCurrentProcess(), &mapped_file_,
@@ -61,9 +70,19 @@ void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
::CloseHandle(handle);
}
-bool SharedMemory::Create(const std::string& name, bool read_only,
- bool open_existing, uint32 size) {
+bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
+ return CreateAnonymous(size) && Map(size);
+}
+
+bool SharedMemory::CreateAnonymous(uint32 size) {
+ return CreateNamed("", false, size);
+}
+
+bool SharedMemory::CreateNamed(const std::string& name,
+ bool open_existing, uint32 size) {
DCHECK(mapped_file_ == NULL);
+ if (size == 0)
+ return false;
// NaCl's memory allocator requires 0mod64K alignment and size for
// shared memory objects. To allow passing shared memory to NaCl,
@@ -72,20 +91,25 @@ bool SharedMemory::Create(const std::string& name, bool read_only,
// actual requested size.
uint32 rounded_size = (size + 0xffff) & ~0xffff;
name_ = ASCIIToWide(name);
- read_only_ = read_only;
mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
- read_only_ ? PAGE_READONLY : PAGE_READWRITE, 0,
- static_cast<DWORD>(rounded_size),
+ PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
name_.empty() ? NULL : name_.c_str());
if (!mapped_file_)
return false;
+ created_size_ = size;
+
// Check if the shared memory pre-exists.
- if (GetLastError() == ERROR_ALREADY_EXISTS && !open_existing) {
- Close();
- return false;
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ // If the file already existed, set created_size_ to 0 to show that
+ // we don't know the size.
+ created_size_ = 0;
+ if (!open_existing) {
+ Close();
+ return false;
+ }
}
- max_size_ = size;
+
return true;
}
@@ -173,6 +197,10 @@ void SharedMemory::Close() {
}
void SharedMemory::Lock() {
+ Lock(INFINITE);
+}
+
+bool SharedMemory::Lock(uint32 timeout_ms) {
if (lock_ == NULL) {
std::wstring name = name_;
name.append(L"lock");
@@ -180,10 +208,13 @@ void SharedMemory::Lock() {
DCHECK(lock_ != NULL);
if (lock_ == NULL) {
DLOG(ERROR) << "Could not create mutex" << GetLastError();
- return; // there is nothing good we can do here.
+ return false; // there is nothing good we can do here.
}
}
- WaitForSingleObject(lock_, INFINITE);
+ DWORD result = WaitForSingleObject(lock_, timeout_ms);
+
+ // Return false for WAIT_ABANDONED, WAIT_TIMEOUT or WAIT_FAILED.
+ return (result == WAIT_OBJECT_0);
}
void SharedMemory::Unlock() {
diff --git a/base/singleton.h b/base/singleton.h
index ccb2c7d..3fe16ce 100644
--- a/base/singleton.h
+++ b/base/singleton.h
@@ -8,7 +8,6 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
-#include "base/platform_thread.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
// Default traits for Singleton<Type>. Calls operator new and operator delete on
diff --git a/base/string_number_conversions.cc b/base/string_number_conversions.cc
index 9cce9cc..7677a86 100644
--- a/base/string_number_conversions.cc
+++ b/base/string_number_conversions.cc
@@ -143,7 +143,7 @@ template<typename CHAR> class WhitespaceHelper {
template<> class WhitespaceHelper<char> {
public:
static bool Invoke(char c) {
- return 0 != isspace(c);
+ return 0 != isspace(static_cast<unsigned char>(c));
}
};
diff --git a/base/string_number_conversions_unittest.cc b/base/string_number_conversions_unittest.cc
index 55487df..8cdd77d 100644
--- a/base/string_number_conversions_unittest.cc
+++ b/base/string_number_conversions_unittest.cc
@@ -80,6 +80,8 @@ TEST(StringNumberConversionsTest, StringToInt) {
} cases[] = {
{"0", 0, true},
{"42", 42, true},
+ {"42\x99", 42, false},
+ {"\x99" "42\x99", 0, false},
{"-2147483648", INT_MIN, true},
{"2147483647", INT_MAX, true},
{"", 0, false},
@@ -161,6 +163,11 @@ TEST(StringNumberConversionsTest, StringToInt) {
utf16_chars + utf16_input.length(),
&output));
EXPECT_EQ(6, output);
+
+ output = 0;
+ const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0};
+ EXPECT_FALSE(StringToInt(string16(negative_wide_input), &output));
+ EXPECT_EQ(0, output);
}
TEST(StringNumberConversionsTest, StringToInt64) {
diff --git a/base/string_util.cc b/base/string_util.cc
index ece5ddb..6717ca5 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -484,7 +484,7 @@ static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
Iter a_end,
const char* b) {
for (Iter it = a_begin; it != a_end; ++it, ++b) {
- if (!*b || ToLowerASCII(*it) != *b)
+ if (!*b || base::ToLowerASCII(*it) != *b)
return false;
}
return *b == 0;
@@ -572,7 +572,7 @@ bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
if (search.size() > str.size())
return false;
return std::equal(search.begin(), search.end(), str.begin(),
- CaseInsensitiveCompare<typename STR::value_type>());
+ base::CaseInsensitiveCompare<typename STR::value_type>());
}
}
@@ -599,7 +599,7 @@ bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
} else {
return std::equal(search.begin(), search.end(),
str.begin() + (str_length - search_length),
- CaseInsensitiveCompare<typename STR::value_type>());
+ base::CaseInsensitiveCompare<typename STR::value_type>());
}
}
diff --git a/base/string_util.h b/base/string_util.h
index 27de472..c238e4a 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -116,6 +116,30 @@ size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
// This function is intended to be called from base::vswprintf.
bool IsWprintfFormatPortable(const wchar_t* format);
+// ASCII-specific tolower. The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToLowerASCII(Char c) {
+ return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+
+// Function objects to aid in comparing/searching strings.
+
+template<typename Char> struct CaseInsensitiveCompare {
+ public:
+ bool operator()(Char x, Char y) const {
+ // TODO(darin): Do we really want to do locale sensitive comparisons here?
+ // See http://crbug.com/24917
+ return tolower(x) == tolower(y);
+ }
+};
+
+template<typename Char> struct CaseInsensitiveCompareASCII {
+ public:
+ bool operator()(Char x, Char y) const {
+ return ToLowerASCII(x) == ToLowerASCII(y);
+ }
+};
+
} // namespace base
#if defined(OS_WIN)
@@ -257,17 +281,11 @@ bool IsStringASCII(const std::wstring& str);
bool IsStringASCII(const base::StringPiece& str);
bool IsStringASCII(const string16& str);
-// ASCII-specific tolower. The standard library's tolower is locale sensitive,
-// so we don't want to use it here.
-template <class Char> inline Char ToLowerASCII(Char c) {
- return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
-}
-
// Converts the elements of the given string. This version uses a pointer to
// clearly differentiate it from the non-pointer variant.
template <class str> inline void StringToLowerASCII(str* s) {
for (typename str::iterator i = s->begin(); i != s->end(); ++i)
- *i = ToLowerASCII(*i);
+ *i = base::ToLowerASCII(*i);
}
template <class str> inline str StringToLowerASCII(const str& s) {
@@ -468,23 +486,6 @@ inline typename string_type::value_type* WriteInto(string_type* str,
//-----------------------------------------------------------------------------
-// Function objects to aid in comparing/searching strings.
-
-template<typename Char> struct CaseInsensitiveCompare {
- public:
- bool operator()(Char x, Char y) const {
- // TODO(darin): Do we really want to do locale sensitive comparisons here?
- // See http://crbug.com/24917
- return tolower(x) == tolower(y);
- }
-};
-
-template<typename Char> struct CaseInsensitiveCompareASCII {
- public:
- bool operator()(Char x, Char y) const {
- return ToLowerASCII(x) == ToLowerASCII(y);
- }
-};
// Splits a string into its fields delimited by any of the characters in
// |delimiters|. Each field is added to the |tokens| vector. Returns the
diff --git a/base/stringprintf.h b/base/stringprintf.h
index a502a2f..3608f9d 100644
--- a/base/stringprintf.h
+++ b/base/stringprintf.h
@@ -49,8 +49,6 @@ void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap)
//
// TODO(brettw) remove these when calling code is converted.
using base::StringPrintf;
-using base::StringPrintV;
-using base::SStringPrintf;
using base::StringAppendV;
using base::StringAppendF;
using base::StringAppendV;
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index 1cd9fb6..e554d73 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -9,6 +9,7 @@
#include "base/file_util.h"
#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
+#include "base/thread_restrictions.h"
namespace base {
@@ -24,6 +25,12 @@ const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
void SysInfo::OperatingSystemVersionNumbers(int32 *major_version,
int32 *minor_version,
int32 *bugfix_version) {
+ // The other implementations of SysInfo don't block on the disk.
+ // See http://code.google.com/p/chromium/issues/detail?id=60394
+ // Perhaps the caller ought to cache this?
+ // Temporary allowing while we work the bug out.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
// TODO(cmasone): If this gets called a lot, it may kill performance.
// consider using static variables to cache these values?
FilePath path(kLinuxStandardBaseReleaseFile);
@@ -54,12 +61,18 @@ void SysInfo::ParseLsbRelease(const std::string& lsb_release,
StringTokenizer tokenizer(version, ".");
for (int i = 0; i < 3 && tokenizer.GetNext(); i++) {
if (0 == i) {
- StringToInt(tokenizer.token(), major_version);
+ StringToInt(tokenizer.token_begin(),
+ tokenizer.token_end(),
+ major_version);
*minor_version = *bugfix_version = 0;
} else if (1 == i) {
- StringToInt(tokenizer.token(), minor_version);
+ StringToInt(tokenizer.token_begin(),
+ tokenizer.token_end(),
+ minor_version);
} else { // 2 == i
- StringToInt(tokenizer.token(), bugfix_version);
+ StringToInt(tokenizer.token_begin(),
+ tokenizer.token_end(),
+ bugfix_version);
}
}
}
diff --git a/base/task.h b/base/task.h
index e6ac33c..28d15fc 100644
--- a/base/task.h
+++ b/base/task.h
@@ -180,7 +180,7 @@ class ScopedRunnableMethodFactory {
template<class T>
class DeleteTask : public CancelableTask {
public:
- explicit DeleteTask(T* obj) : obj_(obj) {
+ explicit DeleteTask(const T* obj) : obj_(obj) {
}
virtual void Run() {
delete obj_;
@@ -190,14 +190,14 @@ class DeleteTask : public CancelableTask {
}
private:
- T* obj_;
+ const T* obj_;
};
// Task to Release() an object
template<class T>
class ReleaseTask : public CancelableTask {
public:
- explicit ReleaseTask(T* obj) : obj_(obj) {
+ explicit ReleaseTask(const T* obj) : obj_(obj) {
}
virtual void Run() {
if (obj_)
@@ -208,7 +208,7 @@ class ReleaseTask : public CancelableTask {
}
private:
- T* obj_;
+ const T* obj_;
};
// RunnableMethodTraits --------------------------------------------------------
diff --git a/base/test/perf_test_suite.cc b/base/test/perf_test_suite.cc
index b787add..232766a 100644
--- a/base/test/perf_test_suite.cc
+++ b/base/test/perf_test_suite.cc
@@ -5,7 +5,7 @@
#include "base/test/perf_test_suite.h"
#include "base/command_line.h"
-#include "base/debug_util.h"
+#include "base/debug/debugger.h"
#include "base/file_path.h"
#include "base/path_service.h"
#include "base/perftimer.h"
@@ -34,7 +34,7 @@ void PerfTestSuite::Initialize() {
// Raise to high priority to have more precise measurements. Since we don't
// aim at 1% precision, it is not necessary to run at realtime level.
- if (!DebugUtil::BeingDebugged())
+ if (!base::debug::BeingDebugged())
base::RaiseProcessToHighPriority();
}
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index f2e6069..7d25a60 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -10,6 +10,8 @@
#include "base/command_line.h"
#include "base/debug_on_start.h"
#include "base/debug_util.h"
+#include "base/debug/debugger.h"
+#include "base/debug/debugger.h"
#include "base/file_path.h"
#include "base/i18n/icu_util.h"
#include "base/logging.h"
@@ -191,7 +193,7 @@ void TestSuite::Initialize() {
#endif // defined(OS_WIN)
// In some cases, we do not want to see standard error dialogs.
- if (!DebugUtil::BeingDebugged() &&
+ if (!base::debug::BeingDebugged() &&
!CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
SuppressErrorDialogs();
DebugUtil::SuppressDialogs();
diff --git a/base/thread_restrictions.cc b/base/thread_restrictions.cc
index 1ee8eee..270d663 100644
--- a/base/thread_restrictions.cc
+++ b/base/thread_restrictions.cc
@@ -21,8 +21,10 @@ LazyInstance<ThreadLocalBoolean, LeakyLazyInstanceTraits<ThreadLocalBoolean> >
} // anonymous namespace
// static
-void ThreadRestrictions::SetIOAllowed(bool allowed) {
+bool ThreadRestrictions::SetIOAllowed(bool allowed) {
+ bool previous_allowed = g_io_disallowed.Get().Get();
g_io_disallowed.Get().Set(!allowed);
+ return !previous_allowed;
}
// static
diff --git a/base/thread_restrictions.h b/base/thread_restrictions.h
index 4aa2cd6..a10aaec 100644
--- a/base/thread_restrictions.h
+++ b/base/thread_restrictions.h
@@ -5,6 +5,8 @@
#ifndef BASE_THREAD_RESTRICTIONS_H_
#define BASE_THREAD_RESTRICTIONS_H_
+#include "base/basictypes.h"
+
namespace base {
// ThreadRestrictions helps protect threads that should not block from
@@ -21,27 +23,49 @@ namespace base {
//
// ThreadRestrictions does nothing in release builds; it is debug-only.
//
+// Style tip: where should you put AssertIOAllowed checks? It's best
+// if you put them as close to the disk access as possible, at the
+// lowest level. This rule is simple to follow and helps catch all
+// callers. For example, if your function GoDoSomeBlockingDiskCall()
+// only calls other functions in Chrome and not fopen(), you should go
+// add the AssertIOAllowed checks in the helper functions.
+
class ThreadRestrictions {
public:
+ // Constructing a ScopedAllowIO temporarily allows IO for the current
+ // thread. Doing this is almost certainly always incorrect.
+ class ScopedAllowIO {
+ public:
+ ScopedAllowIO() { previous_value_ = SetIOAllowed(true); }
+ ~ScopedAllowIO() { SetIOAllowed(previous_value_); }
+ private:
+ // Whether IO is allowed when the ScopedAllowIO was constructed.
+ bool previous_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
+ };
+
+#ifndef NDEBUG
// Set whether the current thread to make IO calls.
// Threads start out in the *allowed* state.
- static void SetIOAllowed(bool allowed);
+ // Returns the previous value.
+ static bool SetIOAllowed(bool allowed);
// Check whether the current thread is allowed to make IO calls,
- // and DCHECK if not.
+ // and DCHECK if not. See the block comment above the class for
+ // a discussion of where to add these checks.
static void AssertIOAllowed();
+#else
+ // In Release builds, inline the empty definitions of these functions so
+ // that they can be compiled out.
+ static bool SetIOAllowed(bool allowed) { return true; }
+ static void AssertIOAllowed() {}
+#endif
private:
ThreadRestrictions(); // class for namespacing only
};
-// In Release builds, inline the empty definitions of these functions so
-// that they can be compiled out.
-#ifdef NDEBUG
-void ThreadRestrictions::SetIOAllowed(bool allowed) {}
-void ThreadRestrictions::AssertIOAllowed() {}
-#endif
-
} // namespace base
#endif // BASE_THREAD_RESTRICTIONS_H_
diff --git a/base/tracked.cc b/base/tracked.cc
index 8ae7447..767f072 100644
--- a/base/tracked.cc
+++ b/base/tracked.cc
@@ -65,6 +65,10 @@ void Location::WriteFunctionName(std::string* output) const {
Tracked::Tracked() {}
Tracked::~Tracked() {}
void Tracked::SetBirthPlace(const Location& from_here) {}
+const Location Tracked::GetBirthPlace() const {
+ static Location kNone("NoFunctionName", "NeedToSetBirthPlace", -1);
+ return kNone;
+}
bool Tracked::MissingBirthplace() const { return false; }
void Tracked::ResetBirthTime() {}
@@ -96,6 +100,10 @@ void Tracked::SetBirthPlace(const Location& from_here) {
tracked_births_ = current_thread_data->TallyABirth(from_here);
}
+const Location Tracked::GetBirthPlace() const {
+ return tracked_births_->location();
+}
+
void Tracked::ResetBirthTime() {
tracked_birth_time_ = TimeTicks::Now();
}
diff --git a/base/tracked.h b/base/tracked.h
index 7af05ff..b4f6e36 100644
--- a/base/tracked.h
+++ b/base/tracked.h
@@ -94,6 +94,7 @@ class Tracked {
// Used to record the FROM_HERE location of a caller.
void SetBirthPlace(const Location& from_here);
+ const Location GetBirthPlace() const;
// When a task sits around a long time, such as in a timer, or object watcher,
// this method should be called when the task becomes active, and its
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 4831e4a..4631f34 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -156,7 +156,7 @@ void ThreadData::WriteHTML(const std::string& query, std::string* output) {
DCHECK(ThreadData::current());
- output->append("<html><head><title>About Objects");
+ output->append("<html><head><title>About Tasks");
std::string escaped_query = UnescapeQuery(query);
if (!escaped_query.empty())
output->append(" - " + escaped_query);
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index b76a295..87912c0 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -21,18 +21,18 @@
// across a series of objects so that the counts and times can be rapidly
// updated without (usually) having to lock the data, and hence there is usually
// very little contention caused by the tracking. The data can be viewed via
-// the about:objects URL, with a variety of sorting and filtering choices.
+// the about:tasks URL, with a variety of sorting and filtering choices.
//
-// Theese classes serve as the basis of a profiler of sorts for the Tasks
-// system. As a result, design decisions were made to maximize speed, by
-// minimizing recurring allocation/deallocation, lock contention and data
-// copying. In the "stable" state, which is reached relatively quickly, there
-// is no separate marginal allocation cost associated with construction or
-// destruction of tracked objects, no locks are generally employed, and probably
-// the largest computational cost is associated with obtaining start and stop
-// times for instances as they are created and destroyed. The introduction of
-// worker threads had a slight impact on this approach, and required use of some
-// locks when accessing data from the worker threads.
+// These classes serve as the basis of a profiler of sorts for the Tasks system.
+// As a result, design decisions were made to maximize speed, by minimizing
+// recurring allocation/deallocation, lock contention and data copying. In the
+// "stable" state, which is reached relatively quickly, there is no separate
+// marginal allocation cost associated with construction or destruction of
+// tracked objects, no locks are generally employed, and probably the largest
+// computational cost is associated with obtaining start and stop times for
+// instances as they are created and destroyed. The introduction of worker
+// threads had a slight impact on this approach, and required use of some locks
+// when accessing data from the worker threads.
//
// The following describes the lifecycle of tracking an instance.
//
@@ -111,7 +111,7 @@
//
// The above description tries to define the high performance (run time)
// portions of these classes. After gathering statistics, calls instigated
-// by visiting about:objects will assemble and aggregate data for display. The
+// by visiting about:tasks will assemble and aggregate data for display. The
// following data structures are used for producing such displays. They are
// not performance critical, and their only major constraint is that they should
// be able to run concurrently with ongoing augmentation of the birth and death
@@ -137,8 +137,7 @@
// need to be sorted, and possibly aggregated (example: how many threads are in
// a specific consecutive set of Snapshots? What was the total birth count for
// that set? etc.). Aggregation instances collect running sums of any set of
-// snapshot instances, and are used to print sub-totals in an about:objects
-// page.
+// snapshot instances, and are used to print sub-totals in an about:tasks page.
//
// TODO(jar): I need to store DataCollections, and provide facilities for taking
// the difference between two gathered DataCollections. For now, I'm just
diff --git a/base/vlog.cc b/base/vlog.cc
index 6075b0b..cda9cea 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -5,22 +5,44 @@
#include "base/vlog.h"
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
-#include "base/string_util.h"
namespace logging {
const int VlogInfo::kDefaultVlogLevel = 0;
+VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern)
+ : pattern(pattern),
+ vlog_level(VlogInfo::kDefaultVlogLevel),
+ match_target(MATCH_MODULE) {
+ // If the pattern contains a {forward,back} slash, we assume that
+ // it's meant to be tested against the entire __FILE__ string.
+ std::string::size_type first_slash = pattern.find_first_of("\\/");
+ if (first_slash != std::string::npos)
+ match_target = MATCH_FILE;
+}
+
+VlogInfo::VmodulePattern::VmodulePattern()
+ : vlog_level(VlogInfo::kDefaultVlogLevel),
+ match_target(MATCH_MODULE) {}
+
VlogInfo::VlogInfo(const std::string& v_switch,
- const std::string& vmodule_switch)
- : max_vlog_level_(kDefaultVlogLevel) {
+ const std::string& vmodule_switch,
+ int* min_log_level)
+ : min_log_level_(min_log_level) {
+ DCHECK(min_log_level != NULL);
+
typedef std::pair<std::string, std::string> KVPair;
- if (!base::StringToInt(v_switch, &max_vlog_level_)) {
+ int vlog_level = 0;
+ if (base::StringToInt(v_switch, &vlog_level)) {
+ SetMaxVlogLevel(vlog_level);
+ } else {
LOG(WARNING) << "Parsed v switch \""
- << v_switch << "\" as " << max_vlog_level_;
+ << v_switch << "\" as " << vlog_level;
}
+
std::vector<KVPair> kv_pairs;
if (!base::SplitStringIntoKeyValuePairs(
vmodule_switch, '=', ',', &kv_pairs)) {
@@ -29,43 +51,114 @@ VlogInfo::VlogInfo(const std::string& v_switch,
}
for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
it != kv_pairs.end(); ++it) {
- int vlog_level = kDefaultVlogLevel;
- if (!base::StringToInt(it->second, &vlog_level)) {
+ VmodulePattern pattern(it->first);
+ if (!base::StringToInt(it->second, &pattern.vlog_level)) {
LOG(WARNING) << "Parsed vlog level for \""
<< it->first << "=" << it->second
- << "\" as " << vlog_level;
+ << "\" as " << pattern.vlog_level;
}
- vmodule_levels_.push_back(std::make_pair(it->first, vlog_level));
+ vmodule_levels_.push_back(pattern);
}
}
VlogInfo::~VlogInfo() {}
-int VlogInfo::GetVlogLevel(const base::StringPiece& file) {
+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
+// (and any -inl suffix). We avoid using FilePath to minimize the
+// number of dependencies the logging system has.
+base::StringPiece GetModule(const base::StringPiece& file) {
+ base::StringPiece module(file);
+ base::StringPiece::size_type last_slash_pos =
+ module.find_last_of("\\/");
+ if (last_slash_pos != base::StringPiece::npos)
+ module.remove_prefix(last_slash_pos + 1);
+ base::StringPiece::size_type extension_start = module.rfind('.');
+ module = module.substr(0, extension_start);
+ static const char kInlSuffix[] = "-inl";
+ static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
+ if (module.ends_with(kInlSuffix))
+ module.remove_suffix(kInlSuffixLen);
+ return module;
+}
+
+} // namespace
+
+int VlogInfo::GetVlogLevel(const base::StringPiece& file) const {
if (!vmodule_levels_.empty()) {
- base::StringPiece module(file);
- base::StringPiece::size_type last_slash_pos =
- module.find_last_of("\\/");
- if (last_slash_pos != base::StringPiece::npos) {
- module.remove_prefix(last_slash_pos + 1);
- }
- base::StringPiece::size_type extension_start = module.find('.');
- module = module.substr(0, extension_start);
- static const char kInlSuffix[] = "-inl";
- static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
- if (module.ends_with(kInlSuffix)) {
- module.remove_suffix(kInlSuffixLen);
- }
+ base::StringPiece module(GetModule(file));
for (std::vector<VmodulePattern>::const_iterator it =
vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) {
- // TODO(akalin): Use a less-heavyweight version of MatchPattern
- // (we can pretty much assume we're dealing with ASCII).
- if (MatchPattern(module, it->first)) {
- return it->second;
- }
+ base::StringPiece target(
+ (it->match_target == VmodulePattern::MATCH_FILE) ? file : module);
+ if (MatchVlogPattern(target, it->pattern))
+ return it->vlog_level;
+ }
+ }
+ return GetMaxVlogLevel();
+}
+
+bool MatchVlogPattern(const base::StringPiece& string,
+ const base::StringPiece& vlog_pattern) {
+ base::StringPiece p(vlog_pattern);
+ base::StringPiece s(string);
+ // Consume characters until the next star.
+ while (!p.empty() && !s.empty() && (p[0] != '*')) {
+ switch (p[0]) {
+ // A slash (forward or back) must match a slash (forward or back).
+ case '/':
+ case '\\':
+ if ((s[0] != '/') && (s[0] != '\\'))
+ return false;
+ break;
+
+ // A '?' matches anything.
+ case '?':
+ break;
+
+ // Anything else must match literally.
+ default:
+ if (p[0] != s[0])
+ return false;
+ break;
}
+ p.remove_prefix(1), s.remove_prefix(1);
}
- return max_vlog_level_;
+
+ // An empty pattern here matches only an empty string.
+ if (p.empty())
+ return s.empty();
+
+ // Coalesce runs of consecutive stars. There should be at least
+ // one.
+ while (!p.empty() && (p[0] == '*'))
+ p.remove_prefix(1);
+
+ // Since we moved past the stars, an empty pattern here matches
+ // anything.
+ if (p.empty())
+ return true;
+
+ // Since we moved past the stars and p is non-empty, if some
+ // non-empty substring of s matches p, then we ourselves match.
+ while (!s.empty()) {
+ if (MatchVlogPattern(s, p))
+ return true;
+ s.remove_prefix(1);
+ }
+
+ // Otherwise, we couldn't find a match.
+ return false;
}
} // namespace
diff --git a/base/vlog.h b/base/vlog.h
index d4cffe4..529afd5 100644
--- a/base/vlog.h
+++ b/base/vlog.h
@@ -8,7 +8,6 @@
#include <cstddef>
#include <string>
-#include <utility>
#include <vector>
#include "base/basictypes.h"
@@ -28,25 +27,63 @@ class VlogInfo {
// E.g. "my_module=2,foo*=3" would change the logging level for all
// code in source files "my_module.*" and "foo*.*" ("-inl" suffixes
// are also disregarded for this matching).
+ //
+ // |log_severity| points to an int that stores the log level. If a valid
+ // |v_switch| is provided, it will set the log level, and the default
+ // vlog severity will be read from there..
+ //
+ // Any pattern containing a forward or backward slash will be tested
+ // against the whole pathname and not just the module. E.g.,
+ // "*/foo/bar/*=2" would change the logging level for all code in
+ // source files under a "foo/bar" directory.
VlogInfo(const std::string& v_switch,
- const std::string& vmodule_switch);
+ const std::string& vmodule_switch,
+ int* min_log_level);
~VlogInfo();
// Returns the vlog level for a given file (usually taken from
// __FILE__).
- int GetVlogLevel(const base::StringPiece& file);
+ int GetVlogLevel(const base::StringPiece& file) const;
static const int kDefaultVlogLevel;
private:
- typedef std::pair<std::string, int> VmodulePattern;
+ 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;
+ };
- int max_vlog_level_;
std::vector<VmodulePattern> vmodule_levels_;
+ int* min_log_level_;
DISALLOW_COPY_AND_ASSIGN(VlogInfo);
};
+// Returns true if the string passed in matches the vlog pattern. The
+// vlog pattern string can contain wildcards like * and ?. ? matches
+// exactly one character while * matches 0 or more characters. Also,
+// as a special case, a / or \ character matches either / or \.
+//
+// Examples:
+// "kh?n" matches "khan" but not "khn" or "khaan"
+// "kh*n" matches "khn", "khan", or even "khaaaaan"
+// "/foo\bar" matches "/foo/bar", "\foo\bar", or "/foo\bar"
+// (disregarding C escaping rules)
+bool MatchVlogPattern(const base::StringPiece& string,
+ const base::StringPiece& vlog_pattern);
+
} // namespace logging
#endif // BASE_VLOG_H_
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc
index 95aa1b9..f583f44 100644
--- a/base/vlog_unittest.cc
+++ b/base/vlog_unittest.cc
@@ -18,19 +18,69 @@ class VlogTest : public testing::Test {
};
TEST_F(VlogTest, NoVmodule) {
- EXPECT_EQ(0, VlogInfo("", "").GetVlogLevel("test1"));
- EXPECT_EQ(0, VlogInfo("0", "").GetVlogLevel("test2"));
- EXPECT_EQ(0, VlogInfo("blah", "").GetVlogLevel("test3"));
- EXPECT_EQ(0, VlogInfo("0blah1", "").GetVlogLevel("test4"));
- EXPECT_EQ(1, VlogInfo("1", "").GetVlogLevel("test5"));
- EXPECT_EQ(5, VlogInfo("5", "").GetVlogLevel("test6"));
+ int min_log_level = 0;
+ EXPECT_EQ(0, VlogInfo("", "", &min_log_level).GetVlogLevel("test1"));
+ EXPECT_EQ(0, VlogInfo("0", "", &min_log_level).GetVlogLevel("test2"));
+ EXPECT_EQ(0, VlogInfo("blah", "", &min_log_level).GetVlogLevel("test3"));
+ EXPECT_EQ(0, VlogInfo("0blah1", "", &min_log_level).GetVlogLevel("test4"));
+ EXPECT_EQ(1, VlogInfo("1", "", &min_log_level).GetVlogLevel("test5"));
+ EXPECT_EQ(5, VlogInfo("5", "", &min_log_level).GetVlogLevel("test6"));
}
-TEST_F(VlogTest, Vmodule) {
+TEST_F(VlogTest, MatchVlogPattern) {
+ // Degenerate cases.
+ EXPECT_TRUE(MatchVlogPattern("", ""));
+ EXPECT_TRUE(MatchVlogPattern("", "****"));
+ EXPECT_FALSE(MatchVlogPattern("", "x"));
+ EXPECT_FALSE(MatchVlogPattern("x", ""));
+
+ // Basic.
+ EXPECT_TRUE(MatchVlogPattern("blah", "blah"));
+
+ // ? should match exactly one character.
+ EXPECT_TRUE(MatchVlogPattern("blah", "bl?h"));
+ EXPECT_FALSE(MatchVlogPattern("blh", "bl?h"));
+ EXPECT_FALSE(MatchVlogPattern("blaah", "bl?h"));
+ EXPECT_TRUE(MatchVlogPattern("blah", "?lah"));
+ EXPECT_FALSE(MatchVlogPattern("lah", "?lah"));
+ EXPECT_FALSE(MatchVlogPattern("bblah", "?lah"));
+
+ // * can match any number (even 0) of characters.
+ EXPECT_TRUE(MatchVlogPattern("blah", "bl*h"));
+ EXPECT_TRUE(MatchVlogPattern("blabcdefh", "bl*h"));
+ EXPECT_TRUE(MatchVlogPattern("blh", "bl*h"));
+ EXPECT_TRUE(MatchVlogPattern("blah", "*blah"));
+ EXPECT_TRUE(MatchVlogPattern("ohblah", "*blah"));
+ EXPECT_TRUE(MatchVlogPattern("blah", "blah*"));
+ EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*"));
+ EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*"));
+ EXPECT_TRUE(MatchVlogPattern("blah", "*blah*"));
+ EXPECT_TRUE(MatchVlogPattern("blahhhh", "*blah*"));
+ EXPECT_TRUE(MatchVlogPattern("bbbblahhhh", "*blah*"));
+
+ // Multiple *s should work fine.
+ EXPECT_TRUE(MatchVlogPattern("ballaah", "b*la*h"));
+ EXPECT_TRUE(MatchVlogPattern("blah", "b*la*h"));
+ EXPECT_TRUE(MatchVlogPattern("bbbblah", "b*la*h"));
+ EXPECT_TRUE(MatchVlogPattern("blaaah", "b*la*h"));
+
+ // There should be no escaping going on.
+ EXPECT_TRUE(MatchVlogPattern("bl\\ah", "bl\\?h"));
+ EXPECT_FALSE(MatchVlogPattern("bl?h", "bl\\?h"));
+ EXPECT_TRUE(MatchVlogPattern("bl\\aaaah", "bl\\*h"));
+ EXPECT_FALSE(MatchVlogPattern("bl*h", "bl\\*h"));
+
+ // Any slash matches any slash.
+ EXPECT_TRUE(MatchVlogPattern("/b\\lah", "/b\\lah"));
+ EXPECT_TRUE(MatchVlogPattern("\\b/lah", "/b\\lah"));
+}
+
+TEST_F(VlogTest, VmoduleBasic) {
const char kVSwitch[] = "-1";
const char kVModuleSwitch[] =
- "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge=5";
- VlogInfo vlog_info(kVSwitch, kVModuleSwitch);
+ "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge.ext=5";
+ int min_log_level = 0;
+ VlogInfo vlog_info(kVSwitch, kVModuleSwitch, &min_log_level);
EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc"));
EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc"));
EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm"));
@@ -38,70 +88,34 @@ TEST_F(VlogTest, Vmodule) {
EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h"));
EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h"));
EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux"));
- EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.h"));
-}
-
-#define BENCHMARK(iters, elapsed, code) \
- do { \
- base::TimeTicks start = base::TimeTicks::Now(); \
- for (int i = 0; i < iters; ++i) code; \
- base::TimeTicks end = base::TimeTicks::Now(); \
- elapsed = end - start; \
- double cps = iters / elapsed.InSecondsF(); \
- LOG(INFO) << cps << " cps (" << elapsed.InSecondsF() \
- << "s elapsed)"; \
- } while (0)
-
-double GetSlowdown(const base::TimeDelta& base,
- const base::TimeDelta& elapsed) {
- return elapsed.InSecondsF() / base.InSecondsF();
+ EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.ext.h"));
}
-
-TEST_F(VlogTest, Perf) {
- const char* kVlogs[] = {
- "/path/to/foo.cc",
- "C:\\path\\to\\bar.h",
- "/path/to/not-matched.mm",
- "C:\\path\\to\\baz-inl.mm",
- "C:\\path\\to\\qux.mm",
- "/path/to/quux.mm",
- "/path/to/another-not-matched.mm",
- };
- const int kVlogCount = arraysize(kVlogs);
- const int kBenchmarkIterations = RunningOnValgrind() ? 30000 : 10000000;
-
- base::TimeDelta null_elapsed;
- {
- VlogInfo null_vlog_info("", "");
- BENCHMARK(kBenchmarkIterations, null_elapsed, {
- EXPECT_NE(-1, null_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
- });
- }
-
- {
- VlogInfo small_vlog_info("0", "foo=1,bar=2,baz=3,qux=4,quux=5");
- base::TimeDelta elapsed;
- BENCHMARK(kBenchmarkIterations, elapsed, {
- EXPECT_NE(-1, small_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
- });
- LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
- << "x";
- }
-
- {
- VlogInfo pattern_vlog_info("0", "fo*=1,ba?=2,b*?z=3,*ux=4,?uux=5");
- base::TimeDelta elapsed;
- BENCHMARK(kBenchmarkIterations, elapsed, {
- EXPECT_NE(-1, pattern_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
- });
- LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
- << "x";
- }
+TEST_F(VlogTest, VmoduleDirs) {
+ const char kVModuleSwitch[] =
+ "foo/bar.cc=1,baz\\*\\qux.cc=2,*quux/*=3,*/*-inl.h=4";
+ int min_log_level = 0;
+ VlogInfo vlog_info("", kVModuleSwitch, &min_log_level);
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar.cc"));
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("bar.cc"));
+ EXPECT_EQ(1, vlog_info.GetVlogLevel("foo/bar.cc"));
+
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("baz/grault/qux.h"));
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("/baz/grault/qux.cc"));
+ EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/qux.cc"));
+ EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/blah/qux.cc"));
+ EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault\\qux.cc"));
+ EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault//blah\\qux.cc"));
+
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar/baz/quux.cc"));
+ EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo/bar/baz/quux/grault.cc"));
+ EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo\\bar/baz\\quux/grault.cc"));
+
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("foo/bar/test-inl.cc"));
+ EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/test-inl.h"));
+ EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/baz/blah-inl.h"));
}
-#undef BENCHMARK
-
} // namespace
} // namespace logging
diff --git a/base/waitable_event_watcher_unittest.cc b/base/waitable_event_watcher_unittest.cc
index 86acee0..e6a6ac0 100644
--- a/base/waitable_event_watcher_unittest.cc
+++ b/base/waitable_event_watcher_unittest.cc
@@ -151,7 +151,13 @@ TEST(WaitableEventWatcherTest, OutlivesMessageLoop) {
RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
}
-TEST(WaitableEventWatcherTest, DeleteUnder) {
+#if defined(OS_WIN)
+// Crashes sometimes on vista. http://crbug.com/62119
+#define MAYBE_DeleteUnder DISABLED_DeleteUnder
+#else
+#define MAYBE_DeleteUnder DeleteUnder
+#endif
+TEST(WaitableEventWatcherTest, MAYBE_DeleteUnder) {
RunTest_DeleteUnder(MessageLoop::TYPE_DEFAULT);
RunTest_DeleteUnder(MessageLoop::TYPE_IO);
RunTest_DeleteUnder(MessageLoop::TYPE_UI);
diff --git a/base/event_trace_consumer_win.h b/base/win/event_trace_consumer.h
index de53ab2..1ceb9ee 100644
--- a/base/event_trace_consumer_win.h
+++ b/base/win/event_trace_consumer.h
@@ -3,8 +3,8 @@
// found in the LICENSE file.
//
// Declaration of a Windows event trace consumer base class.
-#ifndef BASE_EVENT_TRACE_CONSUMER_WIN_H_
-#define BASE_EVENT_TRACE_CONSUMER_WIN_H_
+#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
+#define BASE_WIN_EVENT_TRACE_CONSUMER_H_
#pragma once
#include <windows.h>
@@ -13,6 +13,9 @@
#include <vector>
#include "base/basictypes.h"
+namespace base {
+namespace win {
+
// This class is a base class that makes it easier to consume events
// from realtime or file sessions. Concrete consumers need to sublass
// a specialization of this class and override the ProcessEvent and/or
@@ -141,4 +144,7 @@ HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
return hr;
}
-#endif // BASE_EVENT_TRACE_CONSUMER_WIN_H_
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_EVENT_TRACE_CONSUMER_H_
diff --git a/base/event_trace_consumer_win_unittest.cc b/base/win/event_trace_consumer_unittest.cc
index 412ca0c..f11f459 100644
--- a/base/event_trace_consumer_win_unittest.cc
+++ b/base/win/event_trace_consumer_unittest.cc
@@ -3,11 +3,11 @@
// found in the LICENSE file.
//
// Unit tests for event trace consumer_ base class.
-#include "base/event_trace_consumer_win.h"
+#include "base/win/event_trace_consumer.h"
#include <list>
#include "base/basictypes.h"
-#include "base/event_trace_controller_win.h"
-#include "base/event_trace_provider_win.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
@@ -18,6 +18,12 @@
namespace {
+using base::win::EtwMofEvent;
+using base::win::EtwTraceController;
+using base::win::EtwTraceConsumerBase;
+using base::win::EtwTraceProperties;
+using base::win::EtwTraceProvider;
+
typedef std::list<EVENT_TRACE> EventQueue;
class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
diff --git a/base/event_trace_controller_win.cc b/base/win/event_trace_controller.cc
index 0e11d8a..0391fbc 100644
--- a/base/event_trace_controller_win.cc
+++ b/base/win/event_trace_controller.cc
@@ -3,9 +3,12 @@
// found in the LICENSE file.
//
// Implementation of a Windows event trace controller class.
-#include "base/event_trace_controller_win.h"
+#include "base/win/event_trace_controller.h"
#include "base/logging.h"
+namespace base {
+namespace win {
+
EtwTraceProperties::EtwTraceProperties() {
memset(buffer_, 0, sizeof(buffer_));
EVENT_TRACE_PROPERTIES* prop = get();
@@ -165,3 +168,6 @@ HRESULT EtwTraceController::Flush(const wchar_t* session_name,
EVENT_TRACE_CONTROL_FLUSH);
return HRESULT_FROM_WIN32(err);
}
+
+} // namespace win
+} // namespace base
diff --git a/base/event_trace_controller_win.h b/base/win/event_trace_controller.h
index bf44fa9..8eb172e 100644
--- a/base/event_trace_controller_win.h
+++ b/base/win/event_trace_controller.h
@@ -17,8 +17,8 @@
//
// A trace consumer consumes events from zero or one realtime session,
// as well as potentially from multiple binary trace files.
-#ifndef BASE_EVENT_TRACE_CONTROLLER_WIN_H_
-#define BASE_EVENT_TRACE_CONTROLLER_WIN_H_
+#ifndef BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+#define BASE_WIN_EVENT_TRACE_CONTROLLER_H_
#pragma once
#include <windows.h>
@@ -27,6 +27,9 @@
#include <string>
#include "base/basictypes.h"
+namespace base {
+namespace win {
+
// Utility class to make it easier to work with EVENT_TRACE_PROPERTIES.
// The EVENT_TRACE_PROPERTIES structure contains information about an
// event tracing session.
@@ -141,4 +144,7 @@ class EtwTraceController {
DISALLOW_COPY_AND_ASSIGN(EtwTraceController);
};
-#endif // BASE_EVENT_TRACE_CONTROLLER_WIN_H_
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_EVENT_TRACE_CONTROLLER_H_
diff --git a/base/event_trace_controller_win_unittest.cc b/base/win/event_trace_controller_unittest.cc
index 1fcb616..2b3cd66 100644
--- a/base/event_trace_controller_win_unittest.cc
+++ b/base/win/event_trace_controller_unittest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
//
// Unit tests for event trace controller.
-#include "base/event_trace_controller_win.h"
-#include "base/event_trace_provider_win.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
@@ -15,6 +15,10 @@
namespace {
+using base::win::EtwTraceController;
+using base::win::EtwTraceProvider;
+using base::win::EtwTraceProperties;
+
const wchar_t kTestSessionName[] = L"TestLogSession";
// {0D236A42-CD18-4e3d-9975-DCEEA2106E05}
diff --git a/base/event_trace_provider_win.cc b/base/win/event_trace_provider.cc
index 826a4bf..332fac3 100644
--- a/base/event_trace_provider_win.cc
+++ b/base/win/event_trace_provider.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-#include "base/event_trace_provider_win.h"
+#include "base/win/event_trace_provider.h"
#include <windows.h>
#include <cguid.h>
+namespace base {
+namespace win {
+
TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = {
&GUID_NULL,
NULL
@@ -126,3 +129,6 @@ ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) {
return ::TraceEvent(session_handle_, event);
}
+
+} // namespace win
+} // namespace base
diff --git a/base/event_trace_provider_win.h b/base/win/event_trace_provider.h
index 5c89d1a..6614c91 100644
--- a/base/event_trace_provider_win.h
+++ b/base/win/event_trace_provider.h
@@ -4,8 +4,8 @@
//
// Declaration of a Windows event trace provider class, to allow using
// Windows Event Tracing for logging transport and control.
-#ifndef BASE_EVENT_TRACE_PROVIDER_WIN_H_
-#define BASE_EVENT_TRACE_PROVIDER_WIN_H_
+#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
+#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
#pragma once
#include <windows.h>
@@ -13,6 +13,9 @@
#include <evntrace.h>
#include "base/basictypes.h"
+namespace base {
+namespace win {
+
typedef GUID EtwEventClass;
typedef UCHAR EtwEventType;
typedef UCHAR EtwEventLevel;
@@ -165,4 +168,7 @@ class EtwTraceProvider {
DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider);
};
-#endif // BASE_EVENT_TRACE_PROVIDER_WIN_H_
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_EVENT_TRACE_PROVIDER_H_
diff --git a/base/event_trace_provider_win_unittest.cc b/base/win/event_trace_provider_unittest.cc
index 1efa74f..55b5ae6 100644
--- a/base/event_trace_provider_win_unittest.cc
+++ b/base/win/event_trace_provider_unittest.cc
@@ -3,13 +3,16 @@
// found in the LICENSE file.
//
// Unit tests for event trace provider.
-#include "base/event_trace_provider_win.h"
+#include "base/win/event_trace_provider.h"
#include <new>
#include "testing/gtest/include/gtest/gtest.h"
#include <initguid.h> // NOLINT - has to be last
namespace {
+using base::win::EtwTraceProvider;
+using base::win::EtwMofEvent;
+
// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
DEFINE_GUID(kTestProvider,
0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
diff --git a/base/win/registry.cc b/base/win/registry.cc
index 545c337..977ea00 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -7,6 +7,7 @@
#include <shlwapi.h>
#include "base/logging.h"
+#include "base/thread_restrictions.h"
#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
@@ -15,6 +16,8 @@ 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;
@@ -35,6 +38,7 @@ RegistryValueIterator::RegistryValueIterator(HKEY root_key,
}
RegistryValueIterator::~RegistryValueIterator() {
+ base::ThreadRestrictions::AssertIOAllowed();
if (key_)
::RegCloseKey(key_);
}
@@ -49,6 +53,7 @@ void RegistryValueIterator::operator++() {
}
bool RegistryValueIterator::Read() {
+ base::ThreadRestrictions::AssertIOAllowed();
if (Valid()) {
DWORD ncount = arraysize(name_);
value_size_ = sizeof(value_);
@@ -65,6 +70,7 @@ bool RegistryValueIterator::Read() {
}
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);
@@ -77,6 +83,7 @@ DWORD RegistryValueIterator::ValueCount() const {
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;
@@ -97,6 +104,7 @@ RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
}
RegistryKeyIterator::~RegistryKeyIterator() {
+ base::ThreadRestrictions::AssertIOAllowed();
if (key_)
::RegCloseKey(key_);
}
@@ -111,6 +119,7 @@ void RegistryKeyIterator::operator++() {
}
bool RegistryKeyIterator::Read() {
+ base::ThreadRestrictions::AssertIOAllowed();
if (Valid()) {
DWORD ncount = arraysize(name_);
FILETIME written;
@@ -125,6 +134,7 @@ bool RegistryKeyIterator::Read() {
}
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);
@@ -143,6 +153,7 @@ RegKey::RegKey()
RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
: key_(NULL),
watch_event_(0) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
Create(rootkey, subkey, access);
@@ -158,6 +169,7 @@ RegKey::~RegKey() {
}
void RegKey::Close() {
+ base::ThreadRestrictions::AssertIOAllowed();
StopWatching();
if (key_) {
::RegCloseKey(key_);
@@ -172,6 +184,7 @@ bool RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
bool RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access) {
+ base::ThreadRestrictions::AssertIOAllowed();
DCHECK(rootkey && subkey && access && disposition);
Close();
@@ -193,6 +206,7 @@ bool RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
}
bool RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+ base::ThreadRestrictions::AssertIOAllowed();
DCHECK(rootkey && subkey && access);
Close();
@@ -205,6 +219,7 @@ bool RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
}
bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
+ base::ThreadRestrictions::AssertIOAllowed();
DCHECK(name && access);
HKEY subkey = NULL;
@@ -217,6 +232,7 @@ bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
}
bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
+ base::ThreadRestrictions::AssertIOAllowed();
DCHECK(name && access);
HKEY subkey = NULL;
@@ -229,6 +245,7 @@ bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
}
DWORD RegKey::ValueCount() {
+ base::ThreadRestrictions::AssertIOAllowed();
DWORD count = 0;
HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
NULL, &count, NULL, NULL, NULL, NULL);
@@ -236,6 +253,7 @@ DWORD RegKey::ValueCount() {
}
bool RegKey::ReadName(int index, std::wstring* name) {
+ base::ThreadRestrictions::AssertIOAllowed();
wchar_t buf[256];
DWORD bufsize = arraysize(buf);
LRESULT r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL,
@@ -248,6 +266,7 @@ bool RegKey::ReadName(int index, std::wstring* name) {
}
bool RegKey::ValueExists(const wchar_t* name) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (!key_)
return false;
HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
@@ -256,6 +275,7 @@ bool RegKey::ValueExists(const wchar_t* name) {
bool RegKey::ReadValue(const wchar_t* name, void* data,
DWORD* dsize, DWORD* dtype) {
+ base::ThreadRestrictions::AssertIOAllowed();
if (!key_)
return false;
HRESULT result = RegQueryValueEx(key_, name, 0, dtype,
@@ -264,6 +284,7 @@ bool RegKey::ReadValue(const wchar_t* name, void* data,
}
bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) {
+ 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.
@@ -308,6 +329,7 @@ bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) {
bool RegKey::WriteValue(const wchar_t* name, const void * data,
DWORD dsize, DWORD dtype) {
+ base::ThreadRestrictions::AssertIOAllowed();
DCHECK(data);
if (!key_)
@@ -334,10 +356,12 @@ bool RegKey::WriteValue(const wchar_t* name, DWORD value) {
}
bool RegKey::DeleteKey(const wchar_t* name) {
+ base::ThreadRestrictions::AssertIOAllowed();
return (!key_) ? false : (ERROR_SUCCESS == SHDeleteKey(key_, name));
}
bool RegKey::DeleteValue(const wchar_t* value_name) {
+ base::ThreadRestrictions::AssertIOAllowed();
DCHECK(value_name);
HRESULT result = RegDeleteValue(key_, value_name);
return (result == ERROR_SUCCESS);
diff --git a/base/win_util.cc b/base/win_util.cc
index a576122..3fcfb92 100644
--- a/base/win_util.cc
+++ b/base/win_util.cc
@@ -17,6 +17,7 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
#include "base/win/windows_version.h"
namespace win_util {
@@ -127,6 +128,11 @@ std::wstring GetClassName(HWND window) {
}
bool UserAccountControlIsEnabled() {
+ // This can be slow if Windows ends up going to disk. Should watch this key
+ // for changes and only read it once, preferably on the file thread.
+ // http://code.google.com/p/chromium/issues/detail?id=61644
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
base::win::RegKey key(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
KEY_READ);
diff --git a/base/win_util.h b/base/win_util.h
index 18400f2..4ba7eeb 100644
--- a/base/win_util.h
+++ b/base/win_util.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_WIN_UTIL_H__
-#define BASE_WIN_UTIL_H__
+#ifndef BASE_WIN_UTIL_H_
+#define BASE_WIN_UTIL_H_
#pragma once
#include <windows.h>
@@ -16,36 +16,10 @@ struct IPropertyStore;
struct _tagpropertykey;
typedef _tagpropertykey PROPERTYKEY;
-// TODO(brettw) remove this once RLZ is updated to use the new version in
-// base/win/windows_version.h.
-#if defined(RLZ_WIN_LIB_LIB_MUTEX_H_) || defined(RLZ_WIN_LIB_USER_KEY_H_) \
- || defined(RLZ_WIN_LIB_PROCESS_INFO_H_)
-#include "base/win/windows_version.h"
-#endif
-
namespace win_util {
void GetNonClientMetrics(NONCLIENTMETRICS* metrics);
-// TODO(brettw) remove this once RLZ is updated to use the new version in
-// base/win/windows_version.h.
-#if defined(RLZ_WIN_LIB_LIB_MUTEX_H_) || defined(RLZ_WIN_LIB_USER_KEY_H_) \
- || defined(RLZ_WIN_LIB_PROCESS_INFO_H_)
-// These must match the values in base::win!
-enum WinVersion {
- WINVERSION_PRE_2000 = 0, // Not supported
- WINVERSION_2000 = 1, // Not supported
- WINVERSION_XP = 2,
- WINVERSION_SERVER_2003 = 3,
- WINVERSION_VISTA = 4,
- WINVERSION_2008 = 5,
- WINVERSION_WIN7 = 6,
-};
-inline WinVersion GetWinVersion() {
- return static_cast<WinVersion>(base::win::GetVersion());
-}
-#endif // RLZ_*
-
// Returns the string representing the current user sid.
bool GetUserSidString(std::wstring* user_sid);
@@ -101,4 +75,4 @@ bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name);
} // namespace win_util
-#endif // BASE_WIN_UTIL_H__
+#endif // BASE_WIN_UTIL_H_
diff --git a/base/worker_pool_linux.cc b/base/worker_pool_linux.cc
index 2aa1df2..8c96ca0 100644
--- a/base/worker_pool_linux.cc
+++ b/base/worker_pool_linux.cc
@@ -84,11 +84,29 @@ void WorkerThread::ThreadMain() {
} // namespace
+// NOTE(shess): Temporarily allow the Mac WorkerPool implementation to
+// call into the linux so that it can provide a command-line flag for
+// switching back and forth. After evaluating, either remove the
+// ifdef, or shift this to a shared POSIX implementation.
+// http://crbug.com/44392
+#if defined(OS_MACOSX)
+namespace worker_pool_mac {
+
+bool MacPostTaskHelper(const tracked_objects::Location& from_here,
+ Task* task, bool task_is_slow) {
+ g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
+ return true;
+}
+
+} // namespace worker_pool_mac
+
+#else
bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
Task* task, bool task_is_slow) {
g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
return true;
}
+#endif
namespace base {
diff --git a/base/worker_pool_linux.h b/base/worker_pool_linux.h
index e8c1931..ea6bab7 100644
--- a/base/worker_pool_linux.h
+++ b/base/worker_pool_linux.h
@@ -86,4 +86,18 @@ class LinuxDynamicThreadPool
} // namespace base
+#if defined(OS_MACOSX)
+namespace worker_pool_mac {
+
+// NOTE(shess): Helper so that Mac WorkerPool implementation can call
+// into Linux implementation while determining if the implementations
+// should be merged. After evaluating, either remove the ifdef, or
+// shift this to a shared POSIX implementation.
+// http://crbug.com/44392
+bool MacPostTaskHelper(const tracked_objects::Location& from_here,
+ Task* task, bool task_is_slow);
+
+} // namespace worker_pool_mac
+#endif
+
#endif // BASE_WORKER_POOL_LINUX_H_
diff --git a/base/worker_pool_mac.h b/base/worker_pool_mac.h
index 85cab8b..1e86891 100644
--- a/base/worker_pool_mac.h
+++ b/base/worker_pool_mac.h
@@ -24,4 +24,10 @@
@end // @interface WorkerPoolObjC
+namespace worker_pool_mac {
+
+void SetUseLinuxWorkerPool(bool flag);
+
+} // namespace worker_pool_mac
+
#endif // BASE_WORKER_POOL_MAC_H_
diff --git a/base/worker_pool_mac.mm b/base/worker_pool_mac.mm
index 01c0a98..bbc7892 100644
--- a/base/worker_pool_mac.mm
+++ b/base/worker_pool_mac.mm
@@ -5,12 +5,13 @@
#include "base/worker_pool_mac.h"
#include "base/logging.h"
-#import "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/metrics/histogram.h"
#include "base/scoped_ptr.h"
#import "base/singleton_objc.h"
#include "base/task.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/worker_pool_linux.h"
// When C++ exceptions are disabled, the C++ library defines |try| and
// |catch| so as to allow exception-expecting C++ code to build properly when
@@ -23,6 +24,10 @@
namespace {
+// |true| to use the Linux WorkerPool implementation for
+// |WorkerPool::PostTask()|.
+bool use_linux_workerpool_ = true;
+
Lock lock_;
base::Time last_check_; // Last hung-test check.
std::vector<id> outstanding_ops_; // Outstanding operations at last check.
@@ -31,6 +36,14 @@ size_t outstanding_ = 0; // Operations posted but not completed.
} // namespace
+namespace worker_pool_mac {
+
+void SetUseLinuxWorkerPool(bool flag) {
+ use_linux_workerpool_ = flag;
+}
+
+} // namespace worker_pool_mac
+
@implementation WorkerPoolObjC
+ (NSOperationQueue*)sharedOperationQueue {
@@ -117,6 +130,10 @@ size_t outstanding_ = 0; // Operations posted but not completed.
bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
Task* task, bool task_is_slow) {
+ if (use_linux_workerpool_) {
+ return worker_pool_mac::MacPostTaskHelper(from_here, task, task_is_slow);
+ }
+
base::mac::ScopedNSAutoreleasePool autorelease_pool;
// Ignore |task_is_slow|, it doesn't map directly to any tunable aspect of