diff options
author | Kristian Monsen <kristianm@google.com> | 2011-05-11 20:53:37 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2011-05-16 13:54:48 +0100 |
commit | 21d179b334e59e9a3bfcaed4c4430bef1bc5759d (patch) | |
tree | 64e2bb6da27af6a5c93ca34f6051584aafbfcb9e /base | |
parent | 0c63f00edd6ed0482fd5cbcea937ca088baf7858 (diff) | |
download | external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.zip external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.tar.gz external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.tar.bz2 |
Merge Chromium at 10.0.621.0: Initial merge by git.
Change-Id: I070cc91c608dfa4a968a5a54c173260765ac8097
Diffstat (limited to 'base')
140 files changed, 2393 insertions, 3001 deletions
diff --git a/base/atomicops.h b/base/atomicops.h index cf2f2bb..445696b 100644 --- a/base/atomicops.h +++ b/base/atomicops.h @@ -43,8 +43,14 @@ typedef __w64 int32 Atomic32; #ifdef ARCH_CPU_64_BITS // We need to be able to go between Atomic64 and AtomicWord implicitly. This // means Atomic64 and AtomicWord should be the same type on 64-bit. +#if defined(OS_NACL) +// NaCl's intptr_t is not actually 64-bits on 64-bit! +// http://code.google.com/p/nativeclient/issues/detail?id=1162 +typedef int64_t Atomic64; +#else typedef intptr_t Atomic64; #endif +#endif // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or // Atomic64 routines below, depending on your architecture. diff --git a/base/base.gyp b/base/base.gyp index f68359a..075561b 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -31,6 +31,8 @@ 'base', ], 'sources': [ + 'i18n/break_iterator.cc', + 'i18n/break_iterator.h', 'i18n/char_iterator.cc', 'i18n/char_iterator.h', 'i18n/file_util_icu.cc', @@ -47,8 +49,6 @@ 'i18n/rtl.h', 'i18n/time_formatting.cc', 'i18n/time_formatting.h', - 'i18n/word_iterator.cc', - 'i18n/word_iterator.h', ], }, { @@ -74,7 +74,6 @@ 'crypto/signature_creator_unittest.cc', 'crypto/signature_verifier_unittest.cc', 'crypto/symmetric_key_unittest.cc', - 'data_pack_unittest.cc', 'debug/leak_tracker_unittest.cc', 'debug/stack_trace_unittest.cc', 'debug/trace_event_win_unittest.cc', @@ -87,11 +86,11 @@ 'gmock_unittest.cc', 'hmac_unittest.cc', 'id_map_unittest.cc', + 'i18n/break_iterator_unittest.cc', 'i18n/char_iterator_unittest.cc', 'i18n/file_util_icu_unittest.cc', 'i18n/icu_string_conversions_unittest.cc', 'i18n/rtl_unittest.cc', - 'i18n/word_iterator_unittest.cc', 'json/json_reader_unittest.cc', 'json/json_writer_unittest.cc', 'json/string_escape_unittest.cc', @@ -141,6 +140,7 @@ 'sys_string_conversions_mac_unittest.mm', 'sys_string_conversions_unittest.cc', 'task_queue_unittest.cc', + 'task_unittest.cc', 'thread_checker_unittest.cc', 'thread_collision_warner_unittest.cc', 'thread_local_storage_unittest.cc', @@ -171,13 +171,9 @@ 'win/scoped_bstr_unittest.cc', 'win/scoped_comptr_unittest.cc', 'win/scoped_variant_unittest.cc', + 'worker_pool_posix_unittest.cc', 'worker_pool_unittest.cc', ], - 'include_dirs': [ - # word_iterator.h (used by word_iterator_unittest.cc) leaks an ICU - # #include for unicode/uchar.h. This should probably be cleaned up. - '../third_party/icu/public/common', - ], 'dependencies': [ 'base', 'base_i18n', @@ -189,7 +185,6 @@ ['OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'sources!': [ 'file_version_info_unittest.cc', - 'worker_pool_linux_unittest.cc', ], 'sources': [ 'nix/xdg_util_unittest.cc', @@ -222,6 +217,7 @@ 'sources!': [ 'dir_reader_posix_unittest.cc', 'file_descriptor_shuffle_unittest.cc', + 'worker_pool_posix_unittest.cc', ], }, { # OS != "win" 'sources/': [ @@ -261,6 +257,8 @@ ], 'sources': [ 'perftimer.cc', + 'test/mock_chrome_application_mac.h', + 'test/mock_chrome_application_mac.mm', 'test/multiprocess_test.cc', 'test/multiprocess_test.h', 'test/perf_test_suite.cc', diff --git a/base/base.gypi b/base/base.gypi index a71ccf4..3eaedfa 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -6,7 +6,6 @@ 'target_defaults': { 'variables': { 'base_target': 0, - 'base_extra_target': 0, }, 'target_conditions': [ # This part is shared between the targets defined below. @@ -42,9 +41,6 @@ 'callback.h', 'cancellation_flag.cc', 'cancellation_flag.h', - 'chrome_application_mac.h', - 'chrome_application_mac.mm', - 'cocoa_protocols_mac.h', 'command_line.cc', 'command_line.h', 'compiler_specific.h', @@ -120,6 +116,7 @@ 'logging_win.cc', 'mac_util.h', 'mac_util.mm', + 'mac/cocoa_protocols.h', 'mac/scoped_aedesc.h', 'mac/scoped_cftyperef.h', 'mac/scoped_nsautorelease_pool.h', @@ -272,7 +269,6 @@ 'tracked_objects.cc', 'tracked_objects.h', 'tuple.h', - 'unix_domain_socket_posix.cc', 'utf_offset_string_conversions.cc', 'utf_offset_string_conversions.h', 'utf_string_conversion_utils.cc', @@ -323,10 +319,8 @@ 'win_util.cc', 'win_util.h', 'worker_pool.h', - 'worker_pool_linux.cc', - 'worker_pool_linux.h', - 'worker_pool_mac.h', - 'worker_pool_mac.mm', + 'worker_pool_posix.cc', + 'worker_pool_posix.h', 'worker_pool_win.cc', 'nix/xdg_util.h', 'nix/xdg_util.cc', @@ -363,13 +357,6 @@ ], }, ], - # 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' @@ -406,180 +393,6 @@ },], ], }], - ['base_extra_target==1', { - 'sources': [ - 'crypto/capi_util.cc', - 'crypto/capi_util.h', - 'crypto/cssm_init.cc', - 'crypto/cssm_init.h', - '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', - 'third_party/nspr/prtypes.h', - 'third_party/nss/blapi.h', - 'third_party/nss/blapit.h', - 'third_party/nss/sha256.h', - 'third_party/nss/sha512.cc', - 'third_party/purify/pure.h', - 'third_party/purify/pure_api.c', - 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc', - 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h', - 'auto_reset.h', - 'base64.cc', - 'base64.h', - 'data_pack.cc', - 'event_recorder.cc', - 'event_recorder.h', - 'event_recorder_stubs.cc', - 'file_descriptor_shuffle.cc', - 'file_descriptor_shuffle.h', - 'hmac.h', - 'hmac_mac.cc', - 'hmac_nss.cc', - 'hmac_openssl.cc', - 'hmac_win.cc', - 'image_util.cc', - 'image_util.h', - 'linux_util.cc', - 'linux_util.h', - 'md5.cc', - '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', - 'message_pump_mac.mm', - 'metrics/field_trial.cc', - 'metrics/field_trial.h', - 'nsimage_cache_mac.h', - 'nsimage_cache_mac.mm', - 'nss_util.cc', - 'nss_util.h', - 'openssl_util.cc', - 'openssl_util.h', - 'setproctitle_linux.c', - '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', - 'time_mac.cc', - 'time_posix.cc', - ], - 'conditions': [ - [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { - 'conditions': [ - [ 'chromeos==1', { - 'sources/': [ ['include', '_chromeos\\.cc$'] ] - }, - ], - ], - 'defines': [ - 'USE_SYMBOLIZE', - ], - 'cflags': [ - '-Wno-write-strings', - ], - }, { # OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris" - 'sources/': [ - ['exclude', '/xdg_user_dirs/'], - ['exclude', '_nss\.cc$'], - ], - }], - [ 'OS != "mac"', { - 'sources!': [ - 'crypto/cssm_init.cc', - 'crypto/cssm_init.h', - ], - },], - [ 'OS != "win"', { - 'sources!': [ - 'third_party/purify/pure_api.c', - 'base_drag_source.cc', - 'base_drop_target.cc', - 'cpu.cc', - 'crypto/capi_util.h', - 'crypto/capi_util.cc', - 'debug_on_start.cc', - 'event_recorder.cc', - 'file_version_info.cc', - 'image_util.cc', - 'object_watcher.cc', - 'pe_image.cc', - 'registry.cc', - 'resource_util.cc', - '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', - 'openssl_util.cc', - 'openssl_util.h', - 'sha2_openssl.cc', - ], - },], - ], - }], ], }, 'targets': [ @@ -589,7 +402,6 @@ 'msvs_guid': '1832A374-8A74-4F9E-B536-69A699B3E165', 'variables': { 'base_target': 1, - 'base_extra_target': 1, }, 'dependencies': [ '../third_party/modp_b64/modp_b64.gyp:modp_b64', @@ -603,8 +415,12 @@ ], }, 'conditions': [ - [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', { + [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'conditions': [ + [ 'chromeos==1', { + 'sources/': [ ['include', '_chromeos\\.cc$'] ] + }, + ], [ 'linux_use_tcmalloc==0', { 'defines': [ 'NO_TCMALLOC', @@ -618,7 +434,7 @@ ], [ 'use_openssl==1', { 'dependencies': [ - '../build/linux/system.gyp:openssl', + '../third_party/openssl/openssl.gyp:openssl', ], }, { # use_openssl==0 'dependencies': [ @@ -634,11 +450,22 @@ '../build/linux/system.gyp:x11', 'xdg_mime', ], + 'defines': [ + 'USE_SYMBOLIZE', + ], + 'cflags': [ + '-Wno-write-strings', + ], 'export_dependent_settings': [ '../build/linux/system.gyp:gtk', '../build/linux/system.gyp:x11', ], - },], + }, { # OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris" + 'sources/': [ + ['exclude', '/xdg_user_dirs/'], + ['exclude', '_nss\.cc$'], + ], + }], [ 'OS == "freebsd" or OS == "openbsd"', { 'link_settings': { 'libraries': [ @@ -668,7 +495,12 @@ '$(SDKROOT)/System/Library/Frameworks/Security.framework', ], }, - },], + }, { # OS != "mac" + 'sources!': [ + 'crypto/cssm_init.cc', + 'crypto/cssm_init.h', + ], + }], [ 'OS == "mac" or OS == "win"', { 'dependencies': [ '../third_party/nss/nss.gyp:nss', @@ -676,8 +508,145 @@ },], [ 'OS != "win"', { 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'], + 'sources!': [ + 'third_party/purify/pure_api.c', + 'base_drag_source.cc', + 'base_drop_target.cc', + 'cpu.cc', + 'crypto/capi_util.h', + 'crypto/capi_util.cc', + 'debug_on_start.cc', + 'event_recorder.cc', + 'file_version_info.cc', + 'object_watcher.cc', + 'pe_image.cc', + 'registry.cc', + 'resource_util.cc', + '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', + 'openssl_util.cc', + 'openssl_util.h', + 'sha2_openssl.cc', + ], },], ], + 'sources': [ + 'crypto/capi_util.cc', + 'crypto/capi_util.h', + 'crypto/cssm_init.cc', + 'crypto/cssm_init.h', + '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', + 'third_party/nspr/prtypes.h', + 'third_party/nss/blapi.h', + 'third_party/nss/blapit.h', + 'third_party/nss/sha256.h', + 'third_party/nss/sha512.cc', + 'third_party/purify/pure.h', + 'third_party/purify/pure_api.c', + 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc', + 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h', + 'auto_reset.h', + 'base64.cc', + 'base64.h', + 'event_recorder.cc', + 'event_recorder.h', + 'event_recorder_stubs.cc', + 'file_descriptor_shuffle.cc', + 'file_descriptor_shuffle.h', + 'hmac.h', + 'hmac_mac.cc', + 'hmac_nss.cc', + 'hmac_openssl.cc', + 'hmac_win.cc', + 'linux_util.cc', + 'linux_util.h', + 'md5.cc', + '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', + 'message_pump_mac.mm', + 'metrics/field_trial.cc', + 'metrics/field_trial.h', + 'nss_util.cc', + 'nss_util.h', + 'openssl_util.cc', + 'openssl_util.h', + 'setproctitle_linux.c', + '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', + 'time_mac.cc', + 'time_posix.cc', + ], }, ], 'conditions': [ @@ -714,59 +683,6 @@ }, ], }], - [ 'OS == "linux" and internal_pdf', { - 'targets': [ - { - 'target_name': 'base_fpic', - 'type': '<(library)', - 'variables': { - 'base_target': 1, - 'base_extra_target': 1, - }, - 'cflags': [ - '-fPIC', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '..', - ], - }, - 'conditions': [ - [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', { - 'dependencies': [ - '../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"', { - 'link_settings': { - 'libraries': [ - # We need rt for clock_gettime(). - '-lrt', - # For 'native_library_linux.cc' - '-ldl', - ], - }, - }], - [ 'OS == "mac" or OS == "win"', { - 'dependencies': [ - '../third_party/nss/nss.gyp:nss', - ], - },], - [ 'OS != "win"', { - 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'], - },], - ], - }, - ], - }], [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'targets': [ { diff --git a/base/base_paths_linux.cc b/base/base_paths_linux.cc index b2f2b57..48db3f8 100644 --- a/base/base_paths_linux.cc +++ b/base/base_paths_linux.cc @@ -37,14 +37,12 @@ bool PathProviderPosix(int key, FilePath* result) { case base::FILE_EXE: case base::FILE_MODULE: { // TODO(evanm): is this correct? #if defined(OS_LINUX) - char bin_dir[PATH_MAX + 1]; - int bin_dir_size = readlink(kSelfExe, bin_dir, PATH_MAX); - if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) { + FilePath bin_dir; + if (!file_util::ReadSymbolicLink(FilePath(kSelfExe), &bin_dir)) { NOTREACHED() << "Unable to resolve " << kSelfExe << "."; return false; } - bin_dir[bin_dir_size] = 0; - *result = FilePath(bin_dir); + *result = bin_dir; return true; #elif defined(OS_FREEBSD) int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; @@ -76,7 +74,7 @@ bool PathProviderPosix(int key, FilePath* result) { } } // On POSIX, unit tests execute two levels deep from the source root. - // For example: sconsbuild/{Debug|Release}/net_unittest + // For example: out/{Debug|Release}/net_unittest if (PathService::Get(base::DIR_EXE, &path)) { path = path.DirName().DirName(); if (file_util::PathExists(path.Append(kThisSourceFile))) { diff --git a/base/callback.h b/base/callback.h index 7f2eb70..e5ea771 100644 --- a/base/callback.h +++ b/base/callback.h @@ -206,8 +206,9 @@ template <class T, class Method, class Params> class UnboundMethod { public: UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { - COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), - badunboundmethodparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badunboundmethodparams); } void Run(T* obj) const { DispatchToMethod(obj, m_, p_); diff --git a/base/chrome_application_mac.h b/base/chrome_application_mac.h deleted file mode 100644 index 676959e..0000000 --- a/base/chrome_application_mac.h +++ /dev/null @@ -1,61 +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. - -#ifndef BASE_CHROME_APPLICATION_MAC_H_ -#define BASE_CHROME_APPLICATION_MAC_H_ -#pragma once - -#import <AppKit/AppKit.h> - -#include "base/basictypes.h" -#include "base/scoped_nsobject.h" - -// Event hooks must implement this protocol. -@protocol CrApplicationEventHookProtocol -- (void)hookForEvent:(NSEvent*)theEvent; -@end - - -@interface CrApplication : NSApplication { - @private - BOOL handlingSendEvent_; - // Array of objects implementing the CrApplicationEventHookProtocol - scoped_nsobject<NSMutableArray> eventHooks_; -} -@property(readonly, - getter=isHandlingSendEvent, - nonatomic) BOOL handlingSendEvent; - -// Add or remove an event hook to be called for every sendEvent: -// that the application receives. These handlers are called before -// the normal [NSApplication sendEvent:] call is made. - -// This is not a good alternative to a nested event loop. It should -// be used only when normal event logic and notification breaks down -// (e.g. when clicking outside a canBecomeKey:NO window to "switch -// context" out of it). -- (void)addEventHook:(id<CrApplicationEventHookProtocol>)hook; -- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)hook; - -+ (NSApplication*)sharedApplication; -@end - -namespace chrome_application_mac { - -// Controls the state of |handlingSendEvent_| in the event loop so that it is -// reset properly. -class ScopedSendingEvent { - public: - ScopedSendingEvent(); - ~ScopedSendingEvent(); - - private: - CrApplication* app_; - BOOL handling_; - DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent); -}; - -} // chrome_application_mac - -#endif // BASE_CHROME_APPLICATION_MAC_H_ diff --git a/base/chrome_application_mac.mm b/base/chrome_application_mac.mm deleted file mode 100644 index a163534..0000000 --- a/base/chrome_application_mac.mm +++ /dev/null @@ -1,68 +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. - -#import "chrome_application_mac.h" - -#include "base/logging.h" - -@interface CrApplication () -@property(readwrite, - getter=isHandlingSendEvent, - nonatomic) BOOL handlingSendEvent; -@end - -@implementation CrApplication -@synthesize handlingSendEvent = handlingSendEvent_; - -// Initialize NSApplication using the custom subclass. Check whether NSApp -// was already initialized using another class, because that would break -// some things. -+ (NSApplication*)sharedApplication { - NSApplication* app = [super sharedApplication]; - if (![NSApp isKindOfClass:self]) { - LOG(ERROR) << "NSApp should be of type " << [[self className] UTF8String] - << ", not " << [[NSApp className] UTF8String]; - DCHECK(false) << "NSApp is of wrong type"; - } - return app; -} - -- (id)init { - if ((self = [super init])) { - eventHooks_.reset([[NSMutableArray alloc] init]); - } - return self; -} - -- (void)sendEvent:(NSEvent*)event { - chrome_application_mac::ScopedSendingEvent sendingEventScoper; - for (id<CrApplicationEventHookProtocol> handler in eventHooks_.get()) { - [handler hookForEvent:event]; - } - [super sendEvent:event]; -} - -- (void)addEventHook:(id<CrApplicationEventHookProtocol>)handler { - [eventHooks_ addObject:handler]; -} - -- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)handler { - [eventHooks_ removeObject:handler]; -} - -@end - -namespace chrome_application_mac { - -ScopedSendingEvent::ScopedSendingEvent() - : app_(static_cast<CrApplication*>([CrApplication sharedApplication])), - handling_([app_ isHandlingSendEvent]) { - [app_ setHandlingSendEvent:YES]; -} - -ScopedSendingEvent::~ScopedSendingEvent() { - [app_ setHandlingSendEvent:handling_]; -} - -} // namespace chrome_application_mac diff --git a/base/command_line.cc b/base/command_line.cc index b335e7c..70d6872 100644 --- a/base/command_line.cc +++ b/base/command_line.cc @@ -19,6 +19,7 @@ #include <algorithm> #include "base/file_path.h" +#include "base/file_util.h" #include "base/logging.h" #include "base/singleton.h" #include "base/string_split.h" @@ -237,13 +238,11 @@ void CommandLine::SetProcTitle() { // show up as "exe" in process listings. Read the symlink /proc/self/exe and // use the path it points at for our process title. Note that this is only for // display purposes and has no TOCTTOU security implications. - char buffer[PATH_MAX]; - // Note: readlink() does not append a null byte to terminate the string. - ssize_t length = readlink("/proc/self/exe", buffer, sizeof(buffer)); - DCHECK(length <= static_cast<ssize_t>(sizeof(buffer))); - if (length > 0) { + FilePath target; + FilePath self_exe("/proc/self/exe"); + if (file_util::ReadSymbolicLink(self_exe, &target)) { have_argv0 = true; - title.assign(buffer, length); + title = target.value(); // If the binary has since been deleted, Linux appends " (deleted)" to the // symlink target. Remove it, since this is not really part of our name. const std::string kDeletedSuffix = " (deleted)"; @@ -288,13 +287,6 @@ bool CommandLine::HasSwitch(const std::string& switch_string) const { return switches_.find(lowercased_switch) != switches_.end(); } -#if defined(OS_WIN) -// Deprecated; still temporarily available on Windows. -bool CommandLine::HasSwitch(const std::wstring& switch_string) const { - return HasSwitch(WideToASCII(switch_string)); -} -#endif - std::string CommandLine::GetSwitchValueASCII( const std::string& switch_string) const { CommandLine::StringType value = GetSwitchValueNative(switch_string); diff --git a/base/command_line.h b/base/command_line.h index a5bdd1a..df0293c 100644 --- a/base/command_line.h +++ b/base/command_line.h @@ -161,13 +161,6 @@ class CommandLine { void CopySwitchesFrom(const CommandLine& source, const char* const switches[], size_t count); - // APIs that work with wstrings are deprecated. - // TODO(evanm): remove all of these. -#if defined(OS_WIN) - // Deprecated on non-Windows. - bool HasSwitch(const std::wstring& switch_string) const; -#endif - private: friend class InProcessBrowserTest; diff --git a/base/crypto/cssm_init.cc b/base/crypto/cssm_init.cc index b04cbe7..46a6ffe 100644 --- a/base/crypto/cssm_init.cc +++ b/base/crypto/cssm_init.cc @@ -22,6 +22,13 @@ namespace { class CSSMInitSingleton { public: + static CSSMInitSingleton* GetInstance() { + return Singleton<CSSMInitSingleton>::get(); + } + + CSSM_CSP_HANDLE csp_handle() const {return csp_handle_;} + + private: CSSMInitSingleton() : inited_(false), loaded_(false), csp_handle_(NULL) { static CSSM_VERSION version = {2, 0}; // TODO(wtc): what should our caller GUID be? @@ -68,18 +75,21 @@ class CSSMInitSingleton { } } - CSSM_CSP_HANDLE csp_handle() const {return csp_handle_;} - - private: bool inited_; // True if CSSM_Init has been called successfully. bool loaded_; // True if CSSM_ModuleLoad has been called successfully. CSSM_CSP_HANDLE csp_handle_; + + friend struct DefaultSingletonTraits<CSSMInitSingleton>; }; // This singleton is separate as it pertains to Apple's wrappers over // their own CSSM handles, as opposed to our own CSSM_CSP_HANDLE. class SecurityServicesSingleton { public: + static SecurityServicesSingleton* GetInstance() { + return Singleton<SecurityServicesSingleton>::get(); + } + ~SecurityServicesSingleton() {} Lock& lock() { return lock_; } @@ -100,11 +110,11 @@ class SecurityServicesSingleton { namespace base { void EnsureCSSMInit() { - Singleton<CSSMInitSingleton>::get(); + CSSMInitSingleton::GetInstance(); } CSSM_CSP_HANDLE GetSharedCSPHandle() { - return Singleton<CSSMInitSingleton>::get()->csp_handle(); + return CSSMInitSingleton::GetInstance()->csp_handle(); } void* CSSMMalloc(CSSM_SIZE size, void *alloc_ref) { @@ -145,7 +155,7 @@ void LogCSSMError(const char *fn_name, CSSM_RETURN err) { } Lock& GetMacSecurityServicesLock() { - return Singleton<SecurityServicesSingleton>::get()->lock(); + return SecurityServicesSingleton::GetInstance()->lock(); } } // namespace base diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h index ecec015..bac4250 100644 --- a/base/crypto/rsa_private_key.h +++ b/base/crypto/rsa_private_key.h @@ -165,6 +165,7 @@ class PrivateKeyInfoCodec { // Encapsulates an RSA private key. Can be used to generate new keys, export // keys to other formats, or to extract a public key. +// TODO(hclam): This class should be ref-counted so it can be reused easily. class RSAPrivateKey { public: // Create a new random instance. Can return NULL if initialization fails. @@ -208,6 +209,7 @@ class RSAPrivateKey { EVP_PKEY* key() { return key_; } #elif defined(USE_NSS) SECKEYPrivateKeyStr* key() { return key_; } + SECKEYPublicKeyStr* public_key() { return public_key_; } #elif defined(OS_WIN) HCRYPTPROV provider() { return provider_; } HCRYPTKEY key() { return key_; } diff --git a/base/crypto/rsa_private_key_openssl.cc b/base/crypto/rsa_private_key_openssl.cc index 0776b63..891ea52 100644 --- a/base/crypto/rsa_private_key_openssl.cc +++ b/base/crypto/rsa_private_key_openssl.cc @@ -50,9 +50,13 @@ bool ExportKey(EVP_PKEY* key, // static RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { OpenSSLErrStackTracer err_tracer(FROM_HERE); - ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_generate_key(num_bits, 65537L, - NULL, NULL)); - if (!rsa_key.get()) + + ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_new()); + ScopedOpenSSL<BIGNUM, BN_free> bn(BN_new()); + if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L)) + return NULL; + + if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), NULL)) return NULL; scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); @@ -75,7 +79,8 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( OpenSSLErrStackTracer err_tracer(FROM_HERE); // BIO_new_mem_buf is not const aware, but it does not modify the buffer. - char* data = reinterpret_cast<char*>(const_cast<uint8*>(input.data())); + char* data = reinterpret_cast<char*>(const_cast<uint8*>( + vector_as_array(&input))); ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data, input.size())); if (!bio.get()) return NULL; diff --git a/base/crypto/signature_creator_openssl.cc b/base/crypto/signature_creator_openssl.cc index 7eed379..5bdb783 100644 --- a/base/crypto/signature_creator_openssl.cc +++ b/base/crypto/signature_creator_openssl.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/openssl_util.h" #include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" namespace base { @@ -41,7 +42,7 @@ bool SignatureCreator::Final(std::vector<uint8>* signature) { signature->resize(EVP_PKEY_size(key)); unsigned int len = 0; - int rv = EVP_SignFinal(sign_context_, signature->data(), &len, key); + int rv = EVP_SignFinal(sign_context_, vector_as_array(signature), &len, key); if (!rv) { signature->clear(); return false; diff --git a/base/crypto/signature_verifier_openssl.cc b/base/crypto/signature_verifier_openssl.cc index b4fff78..4850efa 100644 --- a/base/crypto/signature_verifier_openssl.cc +++ b/base/crypto/signature_verifier_openssl.cc @@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/openssl_util.h" #include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" namespace base { @@ -77,7 +78,7 @@ bool SignatureVerifier::VerifyFinal() { DCHECK(verify_context_); OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = EVP_VerifyFinal(verify_context_->ctx.get(), - signature_.data(), signature_.size(), + vector_as_array(&signature_), signature_.size(), verify_context_->public_key.get()); DCHECK_GE(rv, 0); Reset(); diff --git a/base/data/data_pack_unittest/sample.pak b/base/data/data_pack_unittest/sample.pak Binary files differdeleted file mode 100644 index fdbe2b5..0000000 --- a/base/data/data_pack_unittest/sample.pak +++ /dev/null diff --git a/base/data_pack.cc b/base/data_pack.cc deleted file mode 100644 index e01318f..0000000 --- a/base/data_pack.cc +++ /dev/null @@ -1,216 +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/data_pack.h" - -#include <errno.h> - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/ref_counted_memory.h" -#include "base/string_piece.h" - -// For details of the file layout, see -// http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings - -namespace { - -// A word is four bytes. -static const size_t kWord = 4; - -static const uint32 kFileFormatVersion = 1; -// Length of file header: version and entry count. -static const size_t kHeaderLength = 2 * sizeof(uint32); - -struct DataPackEntry { - uint32 resource_id; - uint32 file_offset; - uint32 length; - - static int CompareById(const void* void_key, const void* void_entry) { - uint32 key = *reinterpret_cast<const uint32*>(void_key); - const DataPackEntry* entry = - reinterpret_cast<const DataPackEntry*>(void_entry); - if (key < entry->resource_id) { - return -1; - } else if (key > entry->resource_id) { - return 1; - } else { - return 0; - } - } -}; - -COMPILE_ASSERT(sizeof(DataPackEntry) == 12, size_of_header_must_be_twelve); - -// We're crashing when trying to load a pak file on Windows. Add some error -// codes for logging. -// http://crbug.com/58056 -enum LoadErrors { - INIT_FAILED = 1, - BAD_VERSION, - INDEX_TRUNCATED, - ENTRY_NOT_FOUND, - - LOAD_ERRORS_COUNT, -}; - -} // anonymous namespace - -namespace base { - -// In .cc for MemoryMappedFile dtor. -DataPack::DataPack() : resource_count_(0) { -} -DataPack::~DataPack() { -} - -bool DataPack::Load(const FilePath& path) { - mmap_.reset(new file_util::MemoryMappedFile); - if (!mmap_->Initialize(path)) { - DLOG(ERROR) << "Failed to mmap datapack"; - UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED, - LOAD_ERRORS_COUNT); - return false; - } - - // Parse the header of the file. - // First uint32: version; second: resource count. - const uint32* ptr = reinterpret_cast<const uint32*>(mmap_->data()); - uint32 version = ptr[0]; - if (version != kFileFormatVersion) { - LOG(ERROR) << "Bad data pack version: got " << version << ", expected " - << kFileFormatVersion; - UMA_HISTOGRAM_ENUMERATION("DataPack.Load", BAD_VERSION, - LOAD_ERRORS_COUNT); - mmap_.reset(); - return false; - } - resource_count_ = ptr[1]; - - // Sanity check the file. - // 1) Check we have enough entries. - if (kHeaderLength + resource_count_ * sizeof(DataPackEntry) > - mmap_->length()) { - LOG(ERROR) << "Data pack file corruption: too short for number of " - "entries specified."; - UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED, - LOAD_ERRORS_COUNT); - mmap_.reset(); - return false; - } - // 2) Verify the entries are within the appropriate bounds. - for (size_t i = 0; i < resource_count_; ++i) { - const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( - mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry))); - if (entry->file_offset + entry->length > mmap_->length()) { - LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " - << "Was the file corrupted?"; - UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND, - LOAD_ERRORS_COUNT); - mmap_.reset(); - return false; - } - } - - return true; -} - -bool DataPack::GetStringPiece(uint32 resource_id, StringPiece* data) const { - // It won't be hard to make this endian-agnostic, but it's not worth - // bothering to do right now. -#if defined(__BYTE_ORDER) - // Linux check - COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, - datapack_assumes_little_endian); -#elif defined(__BIG_ENDIAN__) - // Mac check - #error DataPack assumes little endian -#endif - - DataPackEntry* target = reinterpret_cast<DataPackEntry*>( - bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, - sizeof(DataPackEntry), DataPackEntry::CompareById)); - if (!target) { - return false; - } - - data->set(mmap_->data() + target->file_offset, target->length); - return true; -} - -RefCountedStaticMemory* DataPack::GetStaticMemory(uint32 resource_id) const { - base::StringPiece piece; - if (!GetStringPiece(resource_id, &piece)) - return NULL; - - return new RefCountedStaticMemory( - reinterpret_cast<const unsigned char*>(piece.data()), piece.length()); -} - -// static -bool DataPack::WritePack(const FilePath& path, - const std::map<uint32, StringPiece>& resources) { - FILE* file = file_util::OpenFile(path, "wb"); - if (!file) - return false; - - if (fwrite(&kFileFormatVersion, 1, kWord, file) != kWord) { - LOG(ERROR) << "Failed to write file version"; - file_util::CloseFile(file); - return false; - } - - // Note: the python version of this function explicitly sorted keys, but - // std::map is a sorted associative container, we shouldn't have to do that. - uint32 entry_count = resources.size(); - if (fwrite(&entry_count, 1, kWord, file) != kWord) { - LOG(ERROR) << "Failed to write entry count"; - file_util::CloseFile(file); - return false; - } - - // Each entry is 3 uint32s. - uint32 index_length = entry_count * 3 * kWord; - uint32 data_offset = kHeaderLength + index_length; - for (std::map<uint32, StringPiece>::const_iterator it = resources.begin(); - it != resources.end(); ++it) { - if (fwrite(&it->first, 1, kWord, file) != kWord) { - LOG(ERROR) << "Failed to write id for " << it->first; - file_util::CloseFile(file); - return false; - } - - if (fwrite(&data_offset, 1, kWord, file) != kWord) { - LOG(ERROR) << "Failed to write offset for " << it->first; - file_util::CloseFile(file); - return false; - } - - uint32 len = it->second.length(); - if (fwrite(&len, 1, kWord, file) != kWord) { - LOG(ERROR) << "Failed to write length for " << it->first; - file_util::CloseFile(file); - return false; - } - - data_offset += len; - } - - for (std::map<uint32, StringPiece>::const_iterator it = resources.begin(); - it != resources.end(); ++it) { - if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) { - LOG(ERROR) << "Failed to write data for " << it->first; - file_util::CloseFile(file); - return false; - } - } - - file_util::CloseFile(file); - - return true; -} - -} // namespace base diff --git a/base/data_pack.h b/base/data_pack.h deleted file mode 100644 index 2836715..0000000 --- a/base/data_pack.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2008 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. - -// DataPack represents a read-only view onto an on-disk file that contains -// (key, value) pairs of data. It's used to store static resources like -// translation strings and images. - -#ifndef BASE_DATA_PACK_H_ -#define BASE_DATA_PACK_H_ -#pragma once - -#include <map> - -#include "base/basictypes.h" -#include "base/scoped_ptr.h" - -namespace file_util { - class MemoryMappedFile; -} -class FilePath; -class RefCountedStaticMemory; - -namespace base { - -class StringPiece; - -class DataPack { - public: - DataPack(); - ~DataPack(); - - // Load a pack file from |path|, returning false on error. - bool Load(const FilePath& path); - - // Get resource by id |resource_id|, filling in |data|. - // The data is owned by the DataPack object and should not be modified. - // Returns false if the resource id isn't found. - bool GetStringPiece(uint32 resource_id, StringPiece* data) const; - - // Like GetStringPiece(), but returns a reference to memory. This interface - // is used for image data, while the StringPiece interface is usually used - // for localization strings. - RefCountedStaticMemory* GetStaticMemory(uint32 resource_id) const; - - // Writes a pack file containing |resources| to |path|. - static bool WritePack(const FilePath& path, - const std::map<uint32, StringPiece>& resources); - - private: - // The memory-mapped data. - scoped_ptr<file_util::MemoryMappedFile> mmap_; - - // Number of resources in the data. - size_t resource_count_; - - DISALLOW_COPY_AND_ASSIGN(DataPack); -}; - -} // namespace base - -#endif // BASE_DATA_PACK_H_ diff --git a/base/data_pack_unittest.cc b/base/data_pack_unittest.cc deleted file mode 100644 index d089b28..0000000 --- a/base/data_pack_unittest.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2008 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/data_pack.h" - -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/path_service.h" -#include "base/scoped_temp_dir.h" -#include "base/string_piece.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(DataPackTest, Load) { - FilePath data_path; - PathService::Get(base::DIR_SOURCE_ROOT, &data_path); - data_path = data_path.Append( - FILE_PATH_LITERAL("base/data/data_pack_unittest/sample.pak")); - - base::DataPack pack; - ASSERT_TRUE(pack.Load(data_path)); - - base::StringPiece data; - ASSERT_TRUE(pack.GetStringPiece(4, &data)); - EXPECT_EQ("this is id 4", data); - ASSERT_TRUE(pack.GetStringPiece(6, &data)); - EXPECT_EQ("this is id 6", data); - - // Try reading zero-length data blobs, just in case. - ASSERT_TRUE(pack.GetStringPiece(1, &data)); - EXPECT_EQ(0U, data.length()); - ASSERT_TRUE(pack.GetStringPiece(10, &data)); - EXPECT_EQ(0U, data.length()); - - // Try looking up an invalid key. - ASSERT_FALSE(pack.GetStringPiece(140, &data)); -} - -TEST(DataPackTest, Write) { - ScopedTempDir dir; - ASSERT_TRUE(dir.CreateUniqueTempDir()); - FilePath file = dir.path().Append(FILE_PATH_LITERAL("data.pak")); - - std::string one("one"); - std::string two("two"); - std::string three("three"); - std::string four("four"); - std::string fifteen("fifteen"); - - std::map<uint32, base::StringPiece> resources; - resources.insert(std::make_pair(1, base::StringPiece(one))); - resources.insert(std::make_pair(2, base::StringPiece(two))); - resources.insert(std::make_pair(15, base::StringPiece(fifteen))); - resources.insert(std::make_pair(3, base::StringPiece(three))); - resources.insert(std::make_pair(4, base::StringPiece(four))); - ASSERT_TRUE(base::DataPack::WritePack(file, resources)); - - // Now try to read the data back in. - base::DataPack pack; - ASSERT_TRUE(pack.Load(file)); - - base::StringPiece data; - ASSERT_TRUE(pack.GetStringPiece(1, &data)); - EXPECT_EQ(one, data); - ASSERT_TRUE(pack.GetStringPiece(2, &data)); - EXPECT_EQ(two, data); - ASSERT_TRUE(pack.GetStringPiece(3, &data)); - EXPECT_EQ(three, data); - ASSERT_TRUE(pack.GetStringPiece(4, &data)); - EXPECT_EQ(four, data); - ASSERT_TRUE(pack.GetStringPiece(15, &data)); - EXPECT_EQ(fifteen, data); -} diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc index 2df3c4c..1e0c2ba 100644 --- a/base/debug/debugger_posix.cc +++ b/base/debug/debugger_posix.cc @@ -3,13 +3,16 @@ // found in the LICENSE file. #include "base/debug/debugger.h" +#include "build/build_config.h" #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> +#if !defined(OS_NACL) #include <sys/sysctl.h> +#endif #include <sys/types.h> #include <unistd.h> @@ -125,6 +128,13 @@ bool BeingDebugged() { return pid_index < status.size() && status[pid_index] != '0'; } +#elif defined(OS_NACL) + +bool BeingDebugged() { + NOTIMPLEMENTED(); + return false; +} + #elif defined(OS_FREEBSD) bool DebugUtil::BeingDebugged() { @@ -151,6 +161,11 @@ bool DebugUtil::BeingDebugged() { #if defined(NDEBUG) && !defined(OS_MACOSX) #define DEBUG_BREAK() abort() +#elif defined(OS_NACL) +// The NaCl verifier doesn't let use use int3. For now, we call abort(). We +// should ask for advice from some NaCl experts about the optimum thing here. +// http://code.google.com/p/nativeclient/issues/detail?id=645 +#define DEBUG_BREAK() abort() #elif defined(ARCH_CPU_ARM_FAMILY) #define DEBUG_BREAK() asm("bkpt 0") #else @@ -159,9 +174,6 @@ bool DebugUtil::BeingDebugged() { void BreakDebugger() { DEBUG_BREAK(); -#if defined(NDEBUG) - _exit(1); -#endif } } // namespace debug diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc index 51a067e..d1d47cd 100644 --- a/base/debug/debugger_win.cc +++ b/base/debug/debugger_win.cc @@ -106,9 +106,6 @@ void BreakDebugger() { if (DebugUtil::AreDialogsSuppressed()) _exit(1); __debugbreak(); -#if defined(NDEBUG) - _exit(1); -#endif } } // namespace debug diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h index 9709aa1..a8ea5f4 100644 --- a/base/debug/leak_tracker.h +++ b/base/debug/leak_tracker.h @@ -24,8 +24,8 @@ // before destroying that thread, one can check that there are no remaining // instances of that class. // -// For example, to enable leak tracking for class URLRequest, start by -// adding a member variable of type LeakTracker<URLRequest>. +// For example, to enable leak tracking for class net::URLRequest, start by +// adding a member variable of type LeakTracker<net::URLRequest>. // // class URLRequest { // ... @@ -34,11 +34,11 @@ // }; // // -// Next, when we believe all instances of URLRequest have been deleted: +// Next, when we believe all instances of net::URLRequest have been deleted: // -// LeakTracker<URLRequest>::CheckForLeaks(); +// LeakTracker<net::URLRequest>::CheckForLeaks(); // -// Should the check fail (because there are live instances of URLRequest), +// Should the check fail (because there are live instances of net::URLRequest), // then the allocation callstack for each leaked instances is dumped to // the error log. // diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc index 5d5d88d..90e302e 100644 --- a/base/debug/stack_trace_posix.cc +++ b/base/debug/stack_trace_posix.cc @@ -56,9 +56,9 @@ const char kSymbolCharacters[] = #if !defined(USE_SYMBOLIZE) // Demangles C++ symbols in the given text. Example: // -// "sconsbuild/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" +// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" // => -// "sconsbuild/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" +// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" void DemangleSymbols(std::string* text) { #if defined(__GLIBCXX__) diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc index 653d234..6f4ad02 100644 --- a/base/debug/stack_trace_win.cc +++ b/base/debug/stack_trace_win.cc @@ -36,7 +36,7 @@ namespace { // just ignore it. class SymbolContext { public: - static SymbolContext* Get() { + static SymbolContext* GetInstance() { // We use a leaky singleton because code may call this during process // termination. return @@ -179,7 +179,7 @@ void StackTrace::PrintBacktrace() { } void StackTrace::OutputToStream(std::ostream* os) { - SymbolContext* context = SymbolContext::Get(); + SymbolContext* context = SymbolContext::GetInstance(); DWORD error = context->init_error(); if (error != ERROR_SUCCESS) { (*os) << "Error initializing symbols (" << error diff --git a/base/debug/trace_event.cc b/base/debug/trace_event.cc index 616d7ca..9b9ed1f 100644 --- a/base/debug/trace_event.cc +++ b/base/debug/trace_event.cc @@ -49,15 +49,18 @@ TraceLog::~TraceLog() { } // static +TraceLog* TraceLog::GetInstance() { + return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get(); +} + +// static bool TraceLog::IsTracing() { - TraceLog* trace = Singleton<TraceLog>::get(); - return trace->enabled_; + return TraceLog::GetInstance()->enabled_; } // static bool TraceLog::StartTracing() { - TraceLog* trace = Singleton<TraceLog>::get(); - return trace->Start(); + return TraceLog::GetInstance()->Start(); } bool TraceLog::Start() { @@ -78,8 +81,7 @@ bool TraceLog::Start() { // static void TraceLog::StopTracing() { - TraceLog* trace = Singleton<TraceLog>::get(); - return trace->Stop(); + return TraceLog::GetInstance()->Stop(); } void TraceLog::Stop() { diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h index 38b4d05..476f065 100644 --- a/base/debug/trace_event.h +++ b/base/debug/trace_event.h @@ -52,7 +52,7 @@ // 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::debug::TraceLog>::get()->Trace( \ + base::debug::TraceLog::GetInstance()->Trace( \ name, \ base::debug::TraceLog::EVENT_BEGIN, \ reinterpret_cast<const void*>(id), \ @@ -63,7 +63,7 @@ // 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::debug::TraceLog>::get()->Trace( \ + base::debug::TraceLog::GetInstance()->Trace( \ name, \ base::debug::TraceLog::EVENT_END, \ reinterpret_cast<const void*>(id), \ @@ -73,7 +73,7 @@ // Record that an event (of name, id) with no duration has happened. #define TRACE_EVENT_INSTANT(name, id, extra) \ - Singleton<base::debug::TraceLog>::get()->Trace( \ + base::debug::TraceLog::GetInstance()->Trace( \ name, \ base::debug::TraceLog::EVENT_INSTANT, \ reinterpret_cast<const void*>(id), \ @@ -96,6 +96,8 @@ class TraceLog { EVENT_INSTANT }; + static TraceLog* GetInstance(); + // Is tracing currently enabled. static bool IsTracing(); // Start logging trace events. diff --git a/base/debug/trace_event_win.cc b/base/debug/trace_event_win.cc index 8405699..005ff62 100644 --- a/base/debug/trace_event_win.cc +++ b/base/debug/trace_event_win.cc @@ -31,8 +31,8 @@ TraceLog::TraceLog() : EtwTraceProvider(kChromeTraceProviderName) { Register(); } -TraceLog* TraceLog::Get() { - return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog>>::get(); +TraceLog* TraceLog::GetInstance() { + return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get(); } bool TraceLog::StartTracing() { @@ -99,7 +99,7 @@ void TraceLog::Trace(const char* name, const void* id, const char* extra, size_t extra_len) { - TraceLog* provider = TraceLog::Get(); + TraceLog* provider = TraceLog::GetInstance(); if (provider && provider->IsTracing()) { // Compute the name & extra lengths if not supplied already. if (name_len == -1) diff --git a/base/debug/trace_event_win.h b/base/debug/trace_event_win.h index dd3f512..a1c79ba 100644 --- a/base/debug/trace_event_win.h +++ b/base/debug/trace_event_win.h @@ -85,7 +85,7 @@ class TraceLog : public base::win::EtwTraceProvider { // Retrieves the singleton. // Note that this may return NULL post-AtExit processing. - static TraceLog* Get(); + static TraceLog* GetInstance(); // Returns true iff tracing is turned on. bool IsTracing() { diff --git a/base/debug/trace_event_win_unittest.cc b/base/debug/trace_event_win_unittest.cc index 8544bc7..4c5ed45 100644 --- a/base/debug/trace_event_win_unittest.cc +++ b/base/debug/trace_event_win_unittest.cc @@ -106,7 +106,7 @@ class TraceEventTest: public testing::Test { TraceLog* tracelog = NULL; if (!is_xp) { TraceLog::Resurrect(); - tracelog = TraceLog::Get(); + tracelog = TraceLog::GetInstance(); ASSERT_TRUE(tracelog != NULL); ASSERT_FALSE(tracelog->IsTracing()); } @@ -142,7 +142,7 @@ class TraceEventTest: public testing::Test { if (is_xp) { TraceLog::Resurrect(); - tracelog = TraceLog::Get(); + tracelog = TraceLog::GetInstance(); } ASSERT_TRUE(tracelog != NULL); EXPECT_TRUE(tracelog->IsTracing()); diff --git a/base/file_descriptor_shuffle.h b/base/file_descriptor_shuffle.h index a5c08e4..e193035 100644 --- a/base/file_descriptor_shuffle.h +++ b/base/file_descriptor_shuffle.h @@ -46,9 +46,9 @@ class InjectionDelegate { // An implementation of the InjectionDelegate interface using the file // descriptor table of the current process as the domain. class FileDescriptorTableInjection : public InjectionDelegate { - bool Duplicate(int* result, int fd); - bool Move(int src, int dest); - void Close(int fd); + virtual bool Duplicate(int* result, int fd); + virtual bool Move(int src, int dest); + virtual void Close(int fd); }; // A single arc of the directed graph which describes an injective multimapping. diff --git a/base/file_util.cc b/base/file_util.cc index 254e649..2b5dc84 100644 --- a/base/file_util.cc +++ b/base/file_util.cc @@ -361,14 +361,6 @@ bool MemoryMappedFile::IsValid() { // Deprecated functions ---------------------------------------------------- #if defined(OS_WIN) -bool AbsolutePath(std::wstring* path_str) { - FilePath path(FilePath::FromWStringHack(*path_str)); - if (!AbsolutePath(&path)) - return false; - *path_str = path.ToWStringHack(); - return true; -} - void AppendToPath(std::wstring* path, const std::wstring& new_ending) { if (!path) { NOTREACHED(); diff --git a/base/file_util_deprecated.h b/base/file_util_deprecated.h index 45e60b7..9bafb31 100644 --- a/base/file_util_deprecated.h +++ b/base/file_util_deprecated.h @@ -49,8 +49,6 @@ void AppendToPath(std::wstring* path, const std::wstring& new_ending); FilePath::StringType GetFileExtensionFromPath(const FilePath& path); std::wstring GetFileExtensionFromPath(const std::wstring& path); -bool AbsolutePath(std::wstring* path); - // Use version that takes a FilePath. bool Delete(const std::wstring& path, bool recursive); bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path, diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index 56b1ce0..ac6dabb 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -388,11 +388,12 @@ bool ReadSymbolicLink(const FilePath& symlink_path, char buf[PATH_MAX]; ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf)); - if (count <= 0) + if (count <= 0) { + target_path->clear(); return false; + } *target_path = FilePath(FilePath::StringType(buf, count)); - return true; } diff --git a/base/file_util_win.cc b/base/file_util_win.cc index 4645acc..3ca52ae 100644 --- a/base/file_util_win.cc +++ b/base/file_util_win.cc @@ -163,6 +163,14 @@ bool Delete(const FilePath& path, bool recursive) { if (!recursive) file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY; int err = SHFileOperation(&file_operation); + + // Since we're passing flags to the operation telling it to be silent, + // it's possible for the operation to be aborted/cancelled without err + // being set (although MSDN doesn't give any scenarios for how this can + // happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT. + if (file_operation.fAnyOperationsAborted) + return false; + // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting // an empty directory and some return 0x402 when they should be returning // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. diff --git a/base/file_version_info.h b/base/file_version_info.h index 19407d2..481e88d 100644 --- a/base/file_version_info.h +++ b/base/file_version_info.h @@ -6,15 +6,23 @@ #define BASE_FILE_VERSION_INFO_H__ #pragma once +#include "build/build_config.h" + #include <string> -#include "build/build_config.h" +#include "base/string16.h" class FilePath; -// Provides an interface for accessing the version information for a file. -// This is the information you access when you select a file in the Windows -// explorer, right-click select Properties, then click the Version tab. +// Provides an interface for accessing the version information for a file. This +// is the information you access when you select a file in the Windows Explorer, +// right-click select Properties, then click the Version tab, and on the Mac +// when you select a file in the Finder and do a Get Info. +// +// This list of properties is straight out of Win32's VerQueryValue +// <http://msdn.microsoft.com/en-us/library/ms647464.aspx> and the Mac +// version returns values from the Info.plist as appropriate. TODO(avi): make +// this a less-obvious Windows-ism. class FileVersionInfo { public: @@ -24,10 +32,7 @@ class FileVersionInfo { // goes wrong (typically the file does not exit or cannot be opened). The // returned object should be deleted when you are done with it. static FileVersionInfo* CreateFileVersionInfo(const FilePath& file_path); - // This version, taking a wstring, is deprecated and only kept around - // until we can fix all callers. - static FileVersionInfo* CreateFileVersionInfo(const std::wstring& file_path); -#endif +#endif // OS_WIN || OS_MACOSX // Creates a FileVersionInfo for the current module. Returns NULL in case // of error. The returned object should be deleted when you are done with it. @@ -35,21 +40,21 @@ class FileVersionInfo { // Accessors to the different version properties. // Returns an empty string if the property is not found. - virtual std::wstring company_name() = 0; - virtual std::wstring company_short_name() = 0; - virtual std::wstring product_name() = 0; - virtual std::wstring product_short_name() = 0; - virtual std::wstring internal_name() = 0; - virtual std::wstring product_version() = 0; - virtual std::wstring private_build() = 0; - virtual std::wstring special_build() = 0; - virtual std::wstring comments() = 0; - virtual std::wstring original_filename() = 0; - virtual std::wstring file_description() = 0; - virtual std::wstring file_version() = 0; - virtual std::wstring legal_copyright() = 0; - virtual std::wstring legal_trademarks() = 0; - virtual std::wstring last_change() = 0; + virtual string16 company_name() = 0; + virtual string16 company_short_name() = 0; + virtual string16 product_name() = 0; + virtual string16 product_short_name() = 0; + virtual string16 internal_name() = 0; + virtual string16 product_version() = 0; + virtual string16 private_build() = 0; + virtual string16 special_build() = 0; + virtual string16 comments() = 0; + virtual string16 original_filename() = 0; + virtual string16 file_description() = 0; + virtual string16 file_version() = 0; + virtual string16 legal_copyright() = 0; + virtual string16 legal_trademarks() = 0; + virtual string16 last_change() = 0; virtual bool is_official_build() = 0; }; diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h index d66c4e6..879edb3 100644 --- a/base/file_version_info_mac.h +++ b/base/file_version_info_mac.h @@ -8,9 +8,8 @@ #include <string> -#include "base/basictypes.h" #include "base/file_version_info.h" -#include "base/scoped_ptr.h" +#include "base/scoped_nsobject.h" #ifdef __OBJC__ @class NSBundle; @@ -18,43 +17,37 @@ class NSBundle; #endif -// Provides a way to access the version information for a file. -// This is the information you access when you select a file in the Windows -// explorer, right-click select Properties, then click the Version tab. - class FileVersionInfoMac : public FileVersionInfo { public: explicit FileVersionInfoMac(NSBundle *bundle); - ~FileVersionInfoMac(); // Accessors to the different version properties. // Returns an empty string if the property is not found. - virtual std::wstring company_name(); - virtual std::wstring company_short_name(); - virtual std::wstring product_name(); - virtual std::wstring product_short_name(); - virtual std::wstring internal_name(); - virtual std::wstring product_version(); - virtual std::wstring private_build(); - virtual std::wstring special_build(); - virtual std::wstring comments(); - virtual std::wstring original_filename(); - virtual std::wstring file_description(); - virtual std::wstring file_version(); - virtual std::wstring legal_copyright(); - virtual std::wstring legal_trademarks(); - virtual std::wstring last_change(); + virtual string16 company_name(); + virtual string16 company_short_name(); + virtual string16 product_name(); + virtual string16 product_short_name(); + virtual string16 internal_name(); + virtual string16 product_version(); + virtual string16 private_build(); + virtual string16 special_build(); + virtual string16 comments(); + virtual string16 original_filename(); + virtual string16 file_description(); + virtual string16 file_version(); + virtual string16 legal_copyright(); + virtual string16 legal_trademarks(); + virtual string16 last_change(); virtual bool is_official_build(); private: - // Lets you access other properties not covered above. - bool GetValue(const wchar_t* name, std::wstring* value); - // Similar to GetValue but returns a wstring (empty string if the property - // does not exist). - std::wstring GetStringValue(const wchar_t* name); - NSBundle *bundle_; + // Returns a string16 value for a property name. + // Returns the empty string if the property does not exist. + string16 GetString16Value(CFStringRef name); + + scoped_nsobject<NSBundle> bundle_; DISALLOW_COPY_AND_ASSIGN(FileVersionInfoMac); }; diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm index 57be79a..fa97df8 100644 --- a/base/file_version_info_mac.mm +++ b/base/file_version_info_mac.mm @@ -4,103 +4,87 @@ #include "base/file_version_info_mac.h" -#import <Cocoa/Cocoa.h> +#import <Foundation/Foundation.h> -#include "base/basictypes.h" #include "base/file_path.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" +#include "base/logging.h" +#include "base/sys_string_conversions.h" +#include "base/mac_util.h" FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle) : bundle_(bundle) { - [bundle_ retain]; -} - -FileVersionInfoMac::~FileVersionInfoMac() { - [bundle_ release]; } // static FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() { - // TODO(erikkay): this should really use bundleForClass, but we don't have - // a class to hang onto yet. - NSBundle* bundle = [NSBundle mainBundle]; - return new FileVersionInfoMac(bundle); -} - -// static -FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( - const std::wstring& file_path) { - NSString* path = [NSString stringWithCString: - reinterpret_cast<const char*>(file_path.c_str()) - encoding:NSUTF32StringEncoding]; - return new FileVersionInfoMac([NSBundle bundleWithPath:path]); + return CreateFileVersionInfo(mac_util::MainAppBundlePath()); } // static FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( const FilePath& file_path) { - NSString* path = [NSString stringWithUTF8String:file_path.value().c_str()]; - return new FileVersionInfoMac([NSBundle bundleWithPath:path]); + NSString* path = base::SysUTF8ToNSString(file_path.value()); + NSBundle* bundle = [NSBundle bundleWithPath:path]; + return new FileVersionInfoMac(bundle); } -std::wstring FileVersionInfoMac::company_name() { - return std::wstring(); +string16 FileVersionInfoMac::company_name() { + return string16(); } -std::wstring FileVersionInfoMac::company_short_name() { - return std::wstring(); +string16 FileVersionInfoMac::company_short_name() { + return string16(); } -std::wstring FileVersionInfoMac::internal_name() { - return std::wstring(); +string16 FileVersionInfoMac::internal_name() { + return string16(); } -std::wstring FileVersionInfoMac::product_name() { - return GetStringValue(L"CFBundleName"); +string16 FileVersionInfoMac::product_name() { + return GetString16Value(kCFBundleNameKey); } -std::wstring FileVersionInfoMac::product_short_name() { - return GetStringValue(L"CFBundleName"); +string16 FileVersionInfoMac::product_short_name() { + return GetString16Value(kCFBundleNameKey); } -std::wstring FileVersionInfoMac::comments() { - return std::wstring(); +string16 FileVersionInfoMac::comments() { + return string16(); } -std::wstring FileVersionInfoMac::legal_copyright() { - return GetStringValue(L"CFBundleGetInfoString"); +string16 FileVersionInfoMac::legal_copyright() { + return GetString16Value(CFSTR("CFBundleGetInfoString")); } -std::wstring FileVersionInfoMac::product_version() { - return GetStringValue(L"CFBundleShortVersionString"); +string16 FileVersionInfoMac::product_version() { + return GetString16Value(CFSTR("CFBundleShortVersionString")); } -std::wstring FileVersionInfoMac::file_description() { - return std::wstring(); +string16 FileVersionInfoMac::file_description() { + return string16(); } -std::wstring FileVersionInfoMac::legal_trademarks() { - return std::wstring(); +string16 FileVersionInfoMac::legal_trademarks() { + return string16(); } -std::wstring FileVersionInfoMac::private_build() { - return std::wstring(); +string16 FileVersionInfoMac::private_build() { + return string16(); } -std::wstring FileVersionInfoMac::file_version() { +string16 FileVersionInfoMac::file_version() { return product_version(); } -std::wstring FileVersionInfoMac::original_filename() { - return GetStringValue(L"CFBundleName"); +string16 FileVersionInfoMac::original_filename() { + return GetString16Value(kCFBundleNameKey); } -std::wstring FileVersionInfoMac::special_build() { - return std::wstring(); +string16 FileVersionInfoMac::special_build() { + return string16(); } -std::wstring FileVersionInfoMac::last_change() { - return GetStringValue(L"SVNRevision"); +string16 FileVersionInfoMac::last_change() { + return GetString16Value(CFSTR("SVNRevision")); } bool FileVersionInfoMac::is_official_build() { @@ -111,23 +95,13 @@ bool FileVersionInfoMac::is_official_build() { #endif } -bool FileVersionInfoMac::GetValue(const wchar_t* name, - std::wstring* value_str) { +string16 FileVersionInfoMac::GetString16Value(CFStringRef name) { if (bundle_) { - NSString* value = [bundle_ objectForInfoDictionaryKey: - [NSString stringWithUTF8String:WideToUTF8(name).c_str()]]; + NSString *ns_name = mac_util::CFToNSCast(name); + NSString* value = [bundle_ objectForInfoDictionaryKey:ns_name]; if (value) { - *value_str = reinterpret_cast<const wchar_t*>( - [value cStringUsingEncoding:NSUTF32StringEncoding]); - return true; + return base::SysNSStringToUTF16(value); } } - return false; -} - -std::wstring FileVersionInfoMac::GetStringValue(const wchar_t* name) { - std::wstring str; - if (GetValue(name, &str)) - return str; - return std::wstring(); + return string16(); } diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc index 6c69708..e2bc84b 100644 --- a/base/file_version_info_win.cc +++ b/base/file_version_info_win.cc @@ -77,70 +77,63 @@ FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( } } -// static -FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( - const std::wstring& file_path) { - FilePath file_path_fp = FilePath::FromWStringHack(file_path); - return CreateFileVersionInfo(file_path_fp); -} - -std::wstring FileVersionInfoWin::company_name() { +string16 FileVersionInfoWin::company_name() { return GetStringValue(L"CompanyName"); } -std::wstring FileVersionInfoWin::company_short_name() { +string16 FileVersionInfoWin::company_short_name() { return GetStringValue(L"CompanyShortName"); } -std::wstring FileVersionInfoWin::internal_name() { +string16 FileVersionInfoWin::internal_name() { return GetStringValue(L"InternalName"); } -std::wstring FileVersionInfoWin::product_name() { +string16 FileVersionInfoWin::product_name() { return GetStringValue(L"ProductName"); } -std::wstring FileVersionInfoWin::product_short_name() { +string16 FileVersionInfoWin::product_short_name() { return GetStringValue(L"ProductShortName"); } -std::wstring FileVersionInfoWin::comments() { +string16 FileVersionInfoWin::comments() { return GetStringValue(L"Comments"); } -std::wstring FileVersionInfoWin::legal_copyright() { +string16 FileVersionInfoWin::legal_copyright() { return GetStringValue(L"LegalCopyright"); } -std::wstring FileVersionInfoWin::product_version() { +string16 FileVersionInfoWin::product_version() { return GetStringValue(L"ProductVersion"); } -std::wstring FileVersionInfoWin::file_description() { +string16 FileVersionInfoWin::file_description() { return GetStringValue(L"FileDescription"); } -std::wstring FileVersionInfoWin::legal_trademarks() { +string16 FileVersionInfoWin::legal_trademarks() { return GetStringValue(L"LegalTrademarks"); } -std::wstring FileVersionInfoWin::private_build() { +string16 FileVersionInfoWin::private_build() { return GetStringValue(L"PrivateBuild"); } -std::wstring FileVersionInfoWin::file_version() { +string16 FileVersionInfoWin::file_version() { return GetStringValue(L"FileVersion"); } -std::wstring FileVersionInfoWin::original_filename() { +string16 FileVersionInfoWin::original_filename() { return GetStringValue(L"OriginalFilename"); } -std::wstring FileVersionInfoWin::special_build() { +string16 FileVersionInfoWin::special_build() { return GetStringValue(L"SpecialBuild"); } -std::wstring FileVersionInfoWin::last_change() { +string16 FileVersionInfoWin::last_change() { return GetStringValue(L"LastChange"); } diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h index 3d60d69..4a49314 100644 --- a/base/file_version_info_win.h +++ b/base/file_version_info_win.h @@ -15,10 +15,6 @@ struct tagVS_FIXEDFILEINFO; typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO; -// Provides a way to access the version information for a file. -// This is the information you access when you select a file in the Windows -// explorer, right-click select Properties, then click the Version tab. - class FileVersionInfoWin : public FileVersionInfo { public: FileVersionInfoWin(void* data, int language, int code_page); @@ -26,21 +22,21 @@ class FileVersionInfoWin : public FileVersionInfo { // Accessors to the different version properties. // Returns an empty string if the property is not found. - virtual std::wstring company_name(); - virtual std::wstring company_short_name(); - virtual std::wstring product_name(); - virtual std::wstring product_short_name(); - virtual std::wstring internal_name(); - virtual std::wstring product_version(); - virtual std::wstring private_build(); - virtual std::wstring special_build(); - virtual std::wstring comments(); - virtual std::wstring original_filename(); - virtual std::wstring file_description(); - virtual std::wstring file_version(); - virtual std::wstring legal_copyright(); - virtual std::wstring legal_trademarks(); - virtual std::wstring last_change(); + virtual string16 company_name(); + virtual string16 company_short_name(); + virtual string16 product_name(); + virtual string16 product_short_name(); + virtual string16 internal_name(); + virtual string16 product_version(); + virtual string16 private_build(); + virtual string16 special_build(); + virtual string16 comments(); + virtual string16 original_filename(); + virtual string16 file_description(); + virtual string16 file_version(); + virtual string16 legal_copyright(); + virtual string16 legal_trademarks(); + virtual string16 last_change(); virtual bool is_official_build(); // Lets you access other properties not covered above. diff --git a/base/global_descriptors_posix.cc b/base/global_descriptors_posix.cc index 8c853a0..2fe953c 100644 --- a/base/global_descriptors_posix.cc +++ b/base/global_descriptors_posix.cc @@ -15,6 +15,14 @@ GlobalDescriptors::GlobalDescriptors() {} GlobalDescriptors::~GlobalDescriptors() {} +// static +GlobalDescriptors* GlobalDescriptors::GetInstance() { + typedef Singleton<base::GlobalDescriptors, + LeakySingletonTraits<base::GlobalDescriptors> > + GlobalDescriptorsSingleton; + return GlobalDescriptorsSingleton::get(); +} + int GlobalDescriptors::MaybeGet(Key key) const { for (Mapping::const_iterator i = descriptors_.begin(); i != descriptors_.end(); ++i) { diff --git a/base/global_descriptors_posix.h b/base/global_descriptors_posix.h index 8ea743e..ab2b86b 100644 --- a/base/global_descriptors_posix.h +++ b/base/global_descriptors_posix.h @@ -41,6 +41,9 @@ class GlobalDescriptors { // the following constant to the key value: static const int kBaseDescriptor = 3; // 0, 1, 2 are already taken. + // Return the singleton instance of GlobalDescriptors. + static GlobalDescriptors* GetInstance(); + // Get a descriptor given a key. It is a fatal error if the key is not known. int Get(Key key) const; // Get a descriptor give a key. Returns -1 on error. diff --git a/base/hash_tables.h b/base/hash_tables.h index 5fbe466..d11e19f 100644 --- a/base/hash_tables.h +++ b/base/hash_tables.h @@ -58,10 +58,14 @@ using __gnu_cxx::hash_set; namespace __gnu_cxx { +<<<<<<< HEAD #ifndef ANDROID // Already defined for android // The GNU C++ library provides identiy hash functions for many integral types, +======= +// The GNU C++ library provides identity hash functions for many integral types, +>>>>>>> chromium.org at r10.0.621.0 // but not for |long long|. This hash function will truncate if |size_t| is // narrower than |long long|. This is probably good enough for what we will // use it for. diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc new file mode 100644 index 0000000..e1b5e29 --- /dev/null +++ b/base/i18n/break_iterator.cc @@ -0,0 +1,101 @@ +// 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/i18n/break_iterator.h" + +#include "base/logging.h" +#include "unicode/ubrk.h" +#include "unicode/uchar.h" +#include "unicode/ustring.h" + +namespace base { + +const size_t npos = -1; + +BreakIterator::BreakIterator(const string16* str, BreakType break_type) + : iter_(NULL), + string_(str), + break_type_(break_type), + prev_(npos), + pos_(0) { +} + +BreakIterator::~BreakIterator() { + if (iter_) + ubrk_close(static_cast<UBreakIterator*>(iter_)); +} + +bool BreakIterator::Init() { + UErrorCode status = U_ZERO_ERROR; + UBreakIteratorType break_type; + switch (break_type_) { + case BREAK_WORD: + break_type = UBRK_WORD; + break; + case BREAK_SPACE: + case BREAK_NEWLINE: + break_type = UBRK_LINE; + break; + default: + NOTREACHED() << "invalid break_type_"; + return false; + } + iter_ = ubrk_open(break_type, NULL, + string_->data(), static_cast<int32_t>(string_->size()), + &status); + if (U_FAILURE(status)) { + NOTREACHED() << "ubrk_open failed"; + return false; + } + // Move the iterator to the beginning of the string. + ubrk_first(static_cast<UBreakIterator*>(iter_)); + return true; +} + +bool BreakIterator::Advance() { + int32_t pos; + int32_t status; + prev_ = pos_; + switch (break_type_) { + case BREAK_WORD: + case BREAK_SPACE: + pos = ubrk_next(static_cast<UBreakIterator*>(iter_)); + if (pos == UBRK_DONE) { + pos_ = npos; + return false; + } + pos_ = static_cast<size_t>(pos); + return true; + case BREAK_NEWLINE: + do { + pos = ubrk_next(static_cast<UBreakIterator*>(iter_)); + if (pos == UBRK_DONE) { + break; + } + pos_ = static_cast<size_t>(pos); + status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_)); + } while (status >= UBRK_LINE_SOFT && status < UBRK_LINE_SOFT_LIMIT); + if (pos == UBRK_DONE && prev_ == pos_) { + pos_ = npos; + return false; + } + return true; + default: + NOTREACHED() << "invalid break_type_"; + return false; + } +} + +bool BreakIterator::IsWord() const { + return (break_type_ == BREAK_WORD && + ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_)) != + UBRK_WORD_NONE); +} + +string16 BreakIterator::GetString() const { + DCHECK(prev_ != npos && pos_ != npos); + return string_->substr(prev_, pos_ - prev_); +} + +} // namespace base diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h new file mode 100644 index 0000000..9de7ac7 --- /dev/null +++ b/base/i18n/break_iterator.h @@ -0,0 +1,108 @@ +// 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_I18N_BREAK_ITERATOR_H_ +#define BASE_I18N_BREAK_ITERATOR_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/string16.h" + +// The BreakIterator class iterates through the words, word breaks, and +// line breaks in a UTF-16 string. +// +// It provides several modes, BREAK_WORD, BREAK_SPACE, and BREAK_NEWLINE, +// which modify how characters are aggregated into the returned string. +// +// Under BREAK_WORD mode, once a word is encountered any non-word +// characters are not included in the returned string (e.g. in the +// UTF-16 equivalent of the string " foo bar! ", the word breaks are at +// the periods in ". .foo. .bar.!. ."). +// +// Under BREAK_SPACE mode, once a word is encountered, any non-word +// characters are included in the returned string, breaking only when a +// space-equivalent character is encountered (e.g. in the +// UTF16-equivalent of the string " foo bar! ", the word breaks are at +// the periods in ". .foo .bar! ."). +// +// Under BREAK_NEWLINE mode, all characters are included in the returned +// string, breking only when a newline-equivalent character is encountered +// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line +// breaks are at the periods in ".foo\n.bar\n.\n."). +// +// To extract the words from a string, move a BREAK_WORD BreakIterator +// through the string and test whether IsWord() is true. E.g., +// BreakIterator iter(&str, BreakIterator::BREAK_WORD); +// if (!iter.Init()) return false; +// while (iter.Advance()) { +// if (iter.IsWord()) { +// // region [iter.prev(),iter.pos()) contains a word. +// VLOG(1) << "word: " << iter.GetString(); +// } +// } + +namespace base { + +class BreakIterator { + public: + enum BreakType { + BREAK_WORD, + BREAK_SPACE, + BREAK_NEWLINE, + }; + + // Requires |str| to live as long as the BreakIterator does. + BreakIterator(const string16* str, BreakType break_type); + ~BreakIterator(); + + // Init() must be called before any of the iterators are valid. + // Returns false if ICU failed to initialize. + bool Init(); + + // Return the current break position within the string, + // or BreakIterator::npos when done. + size_t pos() const { return pos_; } + + // Return the value of pos() returned before Advance() was last called. + size_t prev() const { return prev_; } + + // Advance to the next break. Returns false if we've run past the end of + // the string. (Note that the very last "break" is after the final + // character in the string, and when we advance to that position it's the + // last time Advance() returns true.) + bool Advance(); + + // Under BREAK_WORD mode, returns true if the break we just hit is the + // end of a word. (Otherwise, the break iterator just skipped over e.g. + // whitespace or punctuation.) Under BREAK_SPACE and BREAK_NEWLINE modes, + // this distinction doesn't apply and it always retuns false. + bool IsWord() const; + + // Return the string between prev() and pos(). + // Advance() must have been called successfully at least once + // for pos() to have advanced to somewhere useful. + string16 GetString() const; + + private: + // ICU iterator, avoiding ICU ubrk.h dependence. + // This is actually an ICU UBreakiterator* type, which turns out to be + // a typedef for a void* in the ICU headers. Using void* directly prevents + // callers from needing access to the ICU public headers directory. + void* iter_; + + // The string we're iterating over. + const string16* string_; + + // The breaking style (word/space/newline). + BreakType break_type_; + + // Previous and current iterator positions. + size_t prev_, pos_; + + DISALLOW_COPY_AND_ASSIGN(BreakIterator); +}; + +} // namespace base + +#endif // BASE_I18N_BREAK_ITERATOR_H__ diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc new file mode 100644 index 0000000..bf4fdc1 --- /dev/null +++ b/base/i18n/break_iterator_unittest.cc @@ -0,0 +1,308 @@ +// 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/i18n/break_iterator.h" + +#include "base/string_piece.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(BreakIteratorTest, BreakWordEmpty) { + string16 empty; + base::BreakIterator iter(&empty, base::BreakIterator::BREAK_WORD); + ASSERT_TRUE(iter.Init()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakWord) { + string16 space(UTF8ToUTF16(" ")); + string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_WORD); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(space, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(space, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(space, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(space, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakWide16) { + // Two greek words separated by space. + const string16 str(WideToUTF16( + L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" + L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); + const string16 word1(str.substr(0, 10)); + const string16 word2(str.substr(11, 5)); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_WORD); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(word1, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(word2, iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakWide32) { + // U+1D49C MATHEMATICAL SCRIPT CAPITAL A + const char* very_wide_char = "\xF0\x9D\x92\x9C"; + const string16 str( + UTF8ToUTF16(StringPrintf("%s a", very_wide_char))); + const string16 very_wide_word(str.substr(0, 2)); + + base::BreakIterator iter(&str, base::BreakIterator::BREAK_WORD); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(very_wide_word, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_TRUE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakSpaceEmpty) { + string16 empty; + base::BreakIterator iter(&empty, base::BreakIterator::BREAK_SPACE); + ASSERT_TRUE(iter.Init()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakSpace) { + string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakSpaceSP) { + string16 str(UTF8ToUTF16(" foo bar! \npouet boom ")); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakSpacekWide16) { + // Two Greek words. + const string16 str(WideToUTF16( + L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" + L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); + const string16 word1(str.substr(0, 11)); + const string16 word2(str.substr(11, 5)); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(word1, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(word2, iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakSpaceWide32) { + // U+1D49C MATHEMATICAL SCRIPT CAPITAL A + const char* very_wide_char = "\xF0\x9D\x92\x9C"; + const string16 str( + UTF8ToUTF16(StringPrintf("%s a", very_wide_char))); + const string16 very_wide_word(str.substr(0, 3)); + + base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(very_wide_word, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakLineEmpty) { + string16 empty; + base::BreakIterator iter(&empty, base::BreakIterator::BREAK_NEWLINE); + ASSERT_TRUE(iter.Init()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakLine) { + string16 nl(UTF8ToUTF16("\n")); + string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom")); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(nl, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(nl, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakLineNL) { + string16 nl(UTF8ToUTF16("\n")); + string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n")); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(nl, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(nl, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakLineWide16) { + // Two Greek words separated by newline. + const string16 str(WideToUTF16( + L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" + L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2")); + const string16 line1(str.substr(0, 11)); + const string16 line2(str.substr(11, 5)); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(line1, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(line2, iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} + +TEST(BreakIteratorTest, BreakLineWide32) { + // U+1D49C MATHEMATICAL SCRIPT CAPITAL A + const char* very_wide_char = "\xF0\x9D\x92\x9C"; + const string16 str( + UTF8ToUTF16(StringPrintf("%s\na", very_wide_char))); + const string16 very_wide_line(str.substr(0, 3)); + base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE); + ASSERT_TRUE(iter.Init()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(very_wide_line, iter.GetString()); + EXPECT_TRUE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); + EXPECT_FALSE(iter.Advance()); + EXPECT_FALSE(iter.IsWord()); + EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. + EXPECT_FALSE(iter.IsWord()); +} diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc index 0e9c2cd..34eefac 100644 --- a/base/i18n/file_util_icu.cc +++ b/base/i18n/file_util_icu.cc @@ -21,6 +21,10 @@ namespace { class IllegalCharacters { public: + static IllegalCharacters* GetInstance() { + return Singleton<IllegalCharacters>::get(); + } + bool contains(UChar32 ucs4) { return !!set->contains(ucs4); } @@ -76,19 +80,8 @@ IllegalCharacters::IllegalCharacters() { class LocaleAwareComparator { public: - LocaleAwareComparator() { - UErrorCode error_code = U_ZERO_ERROR; - // Use the default collator. The default locale should have been properly - // set by the time this constructor is called. - collator_.reset(icu::Collator::createInstance(error_code)); - DCHECK(U_SUCCESS(error_code)); - // Make it case-sensitive. - collator_->setStrength(icu::Collator::TERTIARY); - // Note: We do not set UCOL_NORMALIZATION_MODE attribute. In other words, we - // do not pay performance penalty to guarantee sort order correctness for - // non-FCD (http://unicode.org/notes/tn5/#FCD) file names. This should be a - // reasonable tradeoff because such file names should be rare and the sort - // order doesn't change much anyway. + static LocaleAwareComparator* GetInstance() { + return Singleton<LocaleAwareComparator>::get(); } // Note: A similar function is available in l10n_util. @@ -111,6 +104,21 @@ class LocaleAwareComparator { } private: + LocaleAwareComparator() { + UErrorCode error_code = U_ZERO_ERROR; + // Use the default collator. The default locale should have been properly + // set by the time this constructor is called. + collator_.reset(icu::Collator::createInstance(error_code)); + DCHECK(U_SUCCESS(error_code)); + // Make it case-sensitive. + collator_->setStrength(icu::Collator::TERTIARY); + // Note: We do not set UCOL_NORMALIZATION_MODE attribute. In other words, we + // do not pay performance penalty to guarantee sort order correctness for + // non-FCD (http://unicode.org/notes/tn5/#FCD) file names. This should be a + // reasonable tradeoff because such file names should be rare and the sort + // order doesn't change much anyway. + } + scoped_ptr<icu::Collator> collator_; Lock lock_; friend struct DefaultSingletonTraits<LocaleAwareComparator>; @@ -123,19 +131,19 @@ class LocaleAwareComparator { namespace file_util { bool IsFilenameLegal(const string16& file_name) { - return Singleton<IllegalCharacters>()->containsNone(file_name); + return IllegalCharacters::GetInstance()->containsNone(file_name); } void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name, char replace_char) { DCHECK(file_name); - DCHECK(!(Singleton<IllegalCharacters>()->contains(replace_char))); + DCHECK(!(IllegalCharacters::GetInstance()->contains(replace_char))); // Remove leading and trailing whitespace. TrimWhitespace(*file_name, TRIM_ALL, file_name); - IllegalCharacters* illegal = Singleton<IllegalCharacters>::get(); + IllegalCharacters* illegal = IllegalCharacters::GetInstance(); int cursor = 0; // The ICU macros expect an int. while (cursor < static_cast<int>(file_name->size())) { int char_begin = cursor; @@ -171,8 +179,8 @@ void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name, bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) { #if defined(OS_WIN) - return Singleton<LocaleAwareComparator>()->Compare(a.value().c_str(), - b.value().c_str()) < 0; + return LocaleAwareComparator::GetInstance()->Compare(a.value().c_str(), + b.value().c_str()) < 0; #elif defined(OS_POSIX) // On linux, the file system encoding is not defined. We assume @@ -181,7 +189,7 @@ bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) { // ICU's collator can take strings in OS native encoding. But we convert the // strings to UTF-16 ourselves to ensure conversion consistency. // TODO(yuzo): Perhaps we should define SysNativeMBToUTF16? - return Singleton<LocaleAwareComparator>()->Compare( + return LocaleAwareComparator::GetInstance()->Compare( WideToUTF16(base::SysNativeMBToWide(a.value().c_str())), WideToUTF16(base::SysNativeMBToWide(b.value().c_str()))) < 0; #else diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc index 7a69294..df6af14 100644 --- a/base/i18n/number_formatting.cc +++ b/base/i18n/number_formatting.cc @@ -6,7 +6,8 @@ #include "base/format_macros.h" #include "base/logging.h" -#include "base/singleton.h" +#include "base/lazy_instance.h" +#include "base/scoped_ptr.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "unicode/numfmt.h" @@ -16,25 +17,26 @@ namespace base { namespace { -struct NumberFormatSingletonTraits - : public DefaultSingletonTraits<icu::NumberFormat> { - static icu::NumberFormat* New() { +struct NumberFormatWrapper { + NumberFormatWrapper() { + // There's no ICU call to destroy a NumberFormat object other than + // operator delete, so use the default Delete, which calls operator delete. + // This can cause problems if a different allocator is used by this file + // than by ICU. UErrorCode status = U_ZERO_ERROR; - icu::NumberFormat* formatter = icu::NumberFormat::createInstance(status); + number_format.reset(icu::NumberFormat::createInstance(status)); DCHECK(U_SUCCESS(status)); - return formatter; } - // There's no ICU call to destroy a NumberFormat object other than - // operator delete, so use the default Delete, which calls operator delete. - // This can cause problems if a different allocator is used by this file than - // by ICU. + + scoped_ptr<icu::NumberFormat> number_format; }; } // namespace +static LazyInstance<NumberFormatWrapper> g_number_format(LINKER_INITIALIZED); + string16 FormatNumber(int64 number) { - icu::NumberFormat* number_format = - Singleton<icu::NumberFormat, NumberFormatSingletonTraits>::get(); + icu::NumberFormat* number_format = g_number_format.Get().number_format.get(); if (!number_format) { // As a fallback, just return the raw number in a string. diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc index 6a5d293..12b376d 100644 --- a/base/i18n/rtl.cc +++ b/base/i18n/rtl.cc @@ -163,6 +163,7 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) { } #endif +#if defined(OS_WIN) bool AdjustStringForLocaleDirection(string16* text) { if (!IsRTL() || text->empty()) return false; @@ -177,6 +178,57 @@ bool AdjustStringForLocaleDirection(string16* text) { return true; } +#else +bool AdjustStringForLocaleDirection(string16* text) { + // On OS X & GTK the directionality of a label is determined by the first + // strongly directional character. + // However, we want to make sure that in an LTR-language-UI all strings are + // left aligned and vice versa. + // A problem can arise if we display a string which starts with user input. + // User input may be of the opposite directionality to the UI. So the whole + // string will be displayed in the opposite directionality, e.g. if we want to + // display in an LTR UI [such as US English]: + // + // EMAN_NOISNETXE is now installed. + // + // Since EXTENSION_NAME begins with a strong RTL char, the label's + // directionality will be set to RTL and the string will be displayed visually + // as: + // + // .is now installed EMAN_NOISNETXE + // + // In order to solve this issue, we prepend an LRM to the string. An LRM is a + // strongly directional LTR char. + // We also append an LRM at the end, which ensures that we're in an LTR + // context. + + // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the + // box so there is no issue with displaying zero-width bidi control characters + // on any system. Thus no need for the !IsRTL() check here. + if (text->empty()) + return false; + + bool ui_direction_is_rtl = IsRTL(); + + bool has_rtl_chars = StringContainsStrongRTLChars(*text); + if (!ui_direction_is_rtl && has_rtl_chars) { + WrapStringWithRTLFormatting(text); + text->insert(0, 1, kLeftToRightMark); + text->push_back(kLeftToRightMark); + } else if (ui_direction_is_rtl && has_rtl_chars) { + WrapStringWithRTLFormatting(text); + text->insert(0, 1, kRightToLeftMark); + text->push_back(kRightToLeftMark); + } else if (ui_direction_is_rtl) { + WrapStringWithLTRFormatting(text); + text->insert(0, 1, kRightToLeftMark); + text->push_back(kRightToLeftMark); + } + + return true; +} + +#endif // !OS_WIN #if defined(WCHAR_T_IS_UTF32) bool AdjustStringForLocaleDirection(std::wstring* text) { diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h index 82ac576..a75ed4f 100644 --- a/base/i18n/rtl.h +++ b/base/i18n/rtl.h @@ -84,6 +84,7 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text); // string is always treated as a right-to-left string. This is done by // inserting certain Unicode formatting marks into the returned string. // +// ** Notes about the Windows version of this function: // TODO(idana) bug 6806: this function adjusts the string in question only // if the current locale is right-to-left. The function does not take care of // the opposite case (an RTL string displayed in an LTR context) since diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc index 406145d..3fa984a 100644 --- a/base/i18n/time_formatting.cc +++ b/base/i18n/time_formatting.cc @@ -14,24 +14,21 @@ using base::Time; namespace { -std::wstring TimeFormat(const icu::DateFormat* formatter, - const Time& time) { +string16 TimeFormat(const icu::DateFormat* formatter, + const Time& time) { DCHECK(formatter); icu::UnicodeString date_string; formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string); - std::wstring output; - bool success = UTF16ToWide(date_string.getBuffer(), date_string.length(), - &output); - DCHECK(success); - return output; + return string16(date_string.getBuffer(), + static_cast<size_t>(date_string.length())); } } // namespace namespace base { -std::wstring TimeFormatTimeOfDay(const Time& time) { +string16 TimeFormatTimeOfDay(const Time& time) { // We can omit the locale parameter because the default should match // Chrome's application locale. scoped_ptr<icu::DateFormat> formatter( @@ -39,31 +36,31 @@ std::wstring TimeFormatTimeOfDay(const Time& time) { return TimeFormat(formatter.get(), time); } -std::wstring TimeFormatShortDate(const Time& time) { +string16 TimeFormatShortDate(const Time& time) { scoped_ptr<icu::DateFormat> formatter( icu::DateFormat::createDateInstance(icu::DateFormat::kMedium)); return TimeFormat(formatter.get(), time); } -std::wstring TimeFormatShortDateNumeric(const Time& time) { +string16 TimeFormatShortDateNumeric(const Time& time) { scoped_ptr<icu::DateFormat> formatter( icu::DateFormat::createDateInstance(icu::DateFormat::kShort)); return TimeFormat(formatter.get(), time); } -std::wstring TimeFormatShortDateAndTime(const Time& time) { +string16 TimeFormatShortDateAndTime(const Time& time) { scoped_ptr<icu::DateFormat> formatter( icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort)); return TimeFormat(formatter.get(), time); } -std::wstring TimeFormatFriendlyDateAndTime(const Time& time) { +string16 TimeFormatFriendlyDateAndTime(const Time& time) { scoped_ptr<icu::DateFormat> formatter( icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull)); return TimeFormat(formatter.get(), time); } -std::wstring TimeFormatFriendlyDate(const Time& time) { +string16 TimeFormatFriendlyDate(const Time& time) { scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateInstance( icu::DateFormat::kFull)); return TimeFormat(formatter.get(), time); diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h index d78ae9b..e70ad3d 100644 --- a/base/i18n/time_formatting.h +++ b/base/i18n/time_formatting.h @@ -9,32 +9,32 @@ #define BASE_I18N_TIME_FORMATTING_H_ #pragma once -#include <string> +#include "base/string16.h" namespace base { class Time; // Returns the time of day, e.g., "3:07 PM". -std::wstring TimeFormatTimeOfDay(const Time& time); +string16 TimeFormatTimeOfDay(const Time& time); // Returns a shortened date, e.g. "Nov 7, 2007" -std::wstring TimeFormatShortDate(const Time& time); +string16 TimeFormatShortDate(const Time& time); // Returns a numeric date such as 12/13/52. -std::wstring TimeFormatShortDateNumeric(const Time& time); +string16 TimeFormatShortDateNumeric(const Time& time); // Formats a time in a friendly sentence format, e.g. // "Monday, March 6, 2008 2:44:30 PM". -std::wstring TimeFormatShortDateAndTime(const Time& time); +string16 TimeFormatShortDateAndTime(const Time& time); // Formats a time in a friendly sentence format, e.g. // "Monday, March 6, 2008 2:44:30 PM". -std::wstring TimeFormatFriendlyDateAndTime(const Time& time); +string16 TimeFormatFriendlyDateAndTime(const Time& time); // Formats a time in a friendly sentence format, e.g. // "Monday, March 6, 2008". -std::wstring TimeFormatFriendlyDate(const Time& time); +string16 TimeFormatFriendlyDate(const Time& time); } // namespace base diff --git a/base/i18n/word_iterator.cc b/base/i18n/word_iterator.cc deleted file mode 100644 index a9fa4af..0000000 --- a/base/i18n/word_iterator.cc +++ /dev/null @@ -1,70 +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/i18n/word_iterator.h" - -#include "base/logging.h" -#include "unicode/ubrk.h" -#include "unicode/ustring.h" - -const size_t npos = -1; - -WordIterator::WordIterator(const string16* str, BreakType break_type) - : iter_(NULL), - string_(str), - break_type_(break_type), - prev_(npos), - pos_(0) { -} - -WordIterator::~WordIterator() { - if (iter_) - ubrk_close(iter_); -} - -bool WordIterator::Init() { - UErrorCode status = U_ZERO_ERROR; - UBreakIteratorType break_type; - switch (break_type_) { - case BREAK_WORD: - break_type = UBRK_WORD; - break; - case BREAK_LINE: - break_type = UBRK_LINE; - break; - default: - NOTREACHED(); - break_type = UBRK_LINE; - } - iter_ = ubrk_open(break_type, NULL, - string_->data(), static_cast<int32_t>(string_->size()), - &status); - if (U_FAILURE(status)) { - NOTREACHED() << "ubrk_open failed"; - return false; - } - ubrk_first(iter_); // Move the iterator to the beginning of the string. - return true; -} - -bool WordIterator::Advance() { - prev_ = pos_; - const int32_t pos = ubrk_next(iter_); - if (pos == UBRK_DONE) { - pos_ = npos; - return false; - } else { - pos_ = static_cast<size_t>(pos); - return true; - } -} - -bool WordIterator::IsWord() const { - return (ubrk_getRuleStatus(iter_) != UBRK_WORD_NONE); -} - -string16 WordIterator::GetWord() const { - DCHECK(prev_ != npos && pos_ != npos); - return string_->substr(prev_, pos_ - prev_); -} diff --git a/base/i18n/word_iterator.h b/base/i18n/word_iterator.h deleted file mode 100644 index b097bc2..0000000 --- a/base/i18n/word_iterator.h +++ /dev/null @@ -1,89 +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_I18N_WORD_ITERATOR_H_ -#define BASE_I18N_WORD_ITERATOR_H_ -#pragma once - -#include <vector> - -#include "unicode/ubrk.h" -#include "unicode/uchar.h" - -#include "base/basictypes.h" -#include "base/string16.h" - -// The WordIterator class iterates through the words and word breaks -// in a string. (In the string " foo bar! ", the word breaks are at the -// periods in ". .foo. .bar.!. .".) -// -// To extract the words from a string, move a WordIterator through the -// string and test whether IsWord() is true. E.g., -// WordIterator iter(&str, WordIterator::BREAK_WORD); -// if (!iter.Init()) return false; -// while (iter.Advance()) { -// if (iter.IsWord()) { -// // region [iter.prev(),iter.pos()) contains a word. -// VLOG(1) << "word: " << iter.GetWord(); -// } -// } - - -class WordIterator { - public: - enum BreakType { - BREAK_WORD, - BREAK_LINE - }; - - // Requires |str| to live as long as the WordIterator does. - WordIterator(const string16* str, BreakType break_type); - ~WordIterator(); - - // Init() must be called before any of the iterators are valid. - // Returns false if ICU failed to initialize. - bool Init(); - - // Return the current break position within the string, - // or WordIterator::npos when done. - size_t pos() const { return pos_; } - // Return the value of pos() returned before Advance() was last called. - size_t prev() const { return prev_; } - - // Advance to the next break. Returns false if we've run past the end of - // the string. (Note that the very last "word break" is after the final - // character in the string, and when we advance to that position it's the - // last time Advance() returns true.) - bool Advance(); - - // Returns true if the break we just hit is the end of a word. - // (Otherwise, the break iterator just skipped over e.g. whitespace - // or punctuation.) - bool IsWord() const; - - // Return the word between prev() and pos(). - // Advance() must have been called successfully at least once - // for pos() to have advanced to somewhere useful. - string16 GetWord() const; - - private: - // ICU iterator. - UBreakIterator* iter_; -#if !defined(WCHAR_T_IS_UTF16) - std::vector<UChar> chars_; -#endif - - // The string we're iterating over. - const string16* string_; - - // The breaking style (word/line). - BreakType break_type_; - - // Previous and current iterator positions. - size_t prev_, pos_; - - DISALLOW_COPY_AND_ASSIGN(WordIterator); -}; - -#endif // BASE_I18N_WORD_ITERATOR_H__ diff --git a/base/i18n/word_iterator_unittest.cc b/base/i18n/word_iterator_unittest.cc deleted file mode 100644 index 92aff76..0000000 --- a/base/i18n/word_iterator_unittest.cc +++ /dev/null @@ -1,117 +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/i18n/word_iterator.h" - -#include "base/string_piece.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(WordIteratorTest, BreakWord) { - string16 space(UTF8ToUTF16(" ")); - - string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); - WordIterator iter(&str, WordIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("!"), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetWord()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); -} - -TEST(WordIteratorTest, BreakLine) { - string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); - WordIterator iter(&str, WordIterator::BREAK_LINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetWord()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); -} - -TEST(WordIteratorTest, BreakWide16) { - // "Παγκόσμιος Ιστός" - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 word1(str.substr(0, 10)); - const string16 word2(str.substr(11, 5)); - WordIterator iter(&str, WordIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(word1, iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(word2, iter.GetWord()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); -} - -TEST(WordIteratorTest, BreakWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char* very_wide_char = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(StringPrintf("%s a", very_wide_char))); - const string16 very_wide_word(str.substr(0, 2)); - - WordIterator iter(&str, WordIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(very_wide_word, iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetWord()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetWord()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); -} diff --git a/base/image_util.cc b/base/image_util.cc deleted file mode 100644 index d17158f..0000000 --- a/base/image_util.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2006-2008 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 <windows.h> -#include <ImageHlp.h> -#include <psapi.h> - -#include "base/image_util.h" -#include "base/process_util.h" - -// imagehlp.dll appears to ship in all win versions after Win95. -// nsylvain verified it is present in win2k. -// Using #pragma comment for dependency, instead of LoadLibrary/GetProcAddress. -#pragma comment(lib, "imagehlp.lib") - -namespace image_util { - -// ImageMetrics -ImageMetrics::ImageMetrics(HANDLE process) : process_(process) { -} - -ImageMetrics::~ImageMetrics() { -} - -bool ImageMetrics::GetDllImageSectionData(const std::string& loaded_dll_name, - ImageSectionsData* section_sizes) { - // Get a handle to the loaded DLL - HMODULE the_dll = GetModuleHandleA(loaded_dll_name.c_str()); - char full_filename[MAX_PATH]; - // Get image path - if (GetModuleFileNameExA(process_, the_dll, full_filename, MAX_PATH)) { - return GetImageSectionSizes(full_filename, section_sizes); - } - return false; -} - -bool ImageMetrics::GetProcessImageSectionData(ImageSectionsData* - section_sizes) { - char exe_path[MAX_PATH]; - // Get image path - if (GetModuleFileNameExA(process_, NULL, exe_path, MAX_PATH)) { - return GetImageSectionSizes(exe_path, section_sizes); - } - return false; -} - -// private -bool ImageMetrics::GetImageSectionSizes(char* qualified_path, - ImageSectionsData* result) { - LOADED_IMAGE li; - // TODO (timsteele): There is no unicode version for MapAndLoad, hence - // why ansi functions are used in this class. Should we try and rewrite - // this call ourselves to be safe? - if (MapAndLoad(qualified_path, 0, &li, FALSE, TRUE)) { - IMAGE_SECTION_HEADER* section_header = li.Sections; - for (unsigned i = 0; i < li.NumberOfSections; i++, section_header++) { - std::string name(reinterpret_cast<char*>(section_header->Name)); - ImageSectionData data(name, section_header->Misc.VirtualSize ? - section_header->Misc.VirtualSize : - section_header->SizeOfRawData); - // copy into result - result->push_back(data); - } - } else { - // map and load failed - return false; - } - UnMapAndLoad(&li); - return true; -} - -} // namespace image_util diff --git a/base/image_util.h b/base/image_util.h deleted file mode 100644 index ccdffc3..0000000 --- a/base/image_util.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file/namespace contains utility functions for gathering -// information about PE (Portable Executable) headers within -// images (dll's / exe's ) - -#ifndef BASE_IMAGE_UTIL_H_ -#define BASE_IMAGE_UTIL_H_ -#pragma once - -#include <windows.h> -#include <vector> - -#include "base/basictypes.h" - -namespace image_util { - -// Contains both the PE section name (.text, .reloc etc) and its size. -struct ImageSectionData { - ImageSectionData(const std::string& section_name, size_t section_size) - : name(section_name), - size_in_bytes(section_size) { - } - - std::string name; - size_t size_in_bytes; -}; - -typedef std::vector<ImageSectionData> ImageSectionsData; - -// Provides image statistics for modules of a specified process, or for the -// specified process' own executable file. To use, invoke CreateImageMetrics() -// to get an instance for a specified process, then access the information via -// methods. -class ImageMetrics { - public: - // Creates an ImageMetrics instance for given process owned by - // the caller. - explicit ImageMetrics(HANDLE process); - ~ImageMetrics(); - - // Fills a vector of ImageSectionsData containing name/size info - // for every section found in the specified dll's PE section table. - // The DLL must be loaded by the process associated with this ImageMetrics - // instance. - bool GetDllImageSectionData(const std::string& loaded_dll_name, - ImageSectionsData* section_sizes); - - // Fills a vector if ImageSectionsData containing name/size info - // for every section found in the executable file of the process - // associated with this ImageMetrics instance. - bool GetProcessImageSectionData(ImageSectionsData* section_sizes); - - private: - // Helper for GetDllImageSectionData and GetProcessImageSectionData - bool GetImageSectionSizes(char* qualified_path, ImageSectionsData* result); - - HANDLE process_; - - DISALLOW_COPY_AND_ASSIGN(ImageMetrics); -}; - -} // namespace image_util - -#endif // BASE_IMAGE_UTIL_H_ diff --git a/base/lazy_instance.h b/base/lazy_instance.h index f8d5987..bdf5ce3 100644 --- a/base/lazy_instance.h +++ b/base/lazy_instance.h @@ -127,7 +127,9 @@ class LazyInstance : public LazyInstanceHelper { NeedsInstance()) { // Create the instance in the space provided by |buf_|. instance_ = Traits::New(buf_); - CompleteInstance(instance_, Traits::Delete); + // Traits::Delete will be null for LeakyLazyInstannceTraits + void (*dtor)(void*) = Traits::Delete; + CompleteInstance(this, (dtor == NULL) ? NULL : OnExit); } // This annotation helps race detectors recognize correct lock-less @@ -140,6 +142,17 @@ class LazyInstance : public LazyInstanceHelper { } private: + // Adapter function for use with AtExit. This should be called single + // threaded, so don't use atomic operations. + // Calling OnExit while the instance is in use by other threads is a mistake. + static void OnExit(void* lazy_instance) { + LazyInstance<Type, Traits>* me = + reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance); + Traits::Delete(me->instance_); + me->instance_ = NULL; + base::subtle::Release_Store(&me->state_, STATE_EMPTY); + } + int8 buf_[sizeof(Type)]; // Preallocate the space for the Type instance. Type *instance_; diff --git a/base/linux_util.cc b/base/linux_util.cc index 62931ce..e1f7275 100644 --- a/base/linux_util.cc +++ b/base/linux_util.cc @@ -38,7 +38,7 @@ enum LinuxDistroState { class LinuxDistroHelper { public: // Retrieves the Singleton. - static LinuxDistroHelper* Get() { + static LinuxDistroHelper* GetInstance() { return Singleton<LinuxDistroHelper>::get(); } @@ -141,7 +141,7 @@ std::string GetLinuxDistro() { #if defined(OS_CHROMEOS) return g_linux_distro; #elif defined(OS_LINUX) - LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::Get(); + LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance(); LinuxDistroState state = distro_state_singleton->State(); if (STATE_DID_NOT_CHECK == state) { // We do this check only once per process. If it fails, there's diff --git a/base/logging.cc b/base/logging.cc index a202e05..17db628 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -51,14 +51,19 @@ typedef pthread_mutex_t* MutexHandle; #include "base/debug/stack_trace.h" #include "base/eintr_wrapper.h" #include "base/lock_impl.h" -#if defined(OS_POSIX) -#include "base/safe_strerror_posix.h" -#endif -#include "base/process_util.h" #include "base/string_piece.h" #include "base/utf_string_conversions.h" #ifndef ANDROID #include "base/vlog.h" +<<<<<<< HEAD +======= +#if defined(OS_POSIX) +#include "base/safe_strerror_posix.h" +#endif +#if defined(OS_MACOSX) +#include "base/mac/scoped_cftyperef.h" +#include "base/sys_string_conversions.h" +>>>>>>> chromium.org at r10.0.621.0 #endif namespace logging { @@ -469,6 +474,9 @@ template std::string* MakeCheckOpString<std::string, std::string>( // Displays a message box to the user with the error message in it. // Used for fatal messages, where we close the app simultaneously. +// This is for developers only; we don't use this in circumstances +// (like release builds) where users could see it, since users don't +// understand these messages anyway. void DisplayDebugMessageInDialog(const std::string& str) { if (str.empty()) return; @@ -509,19 +517,15 @@ void DisplayDebugMessageInDialog(const std::string& str) { MessageBoxW(NULL, &cmdline[0], L"Fatal error", MB_OK | MB_ICONHAND | MB_TOPMOST); } -#elif defined(USE_X11) && !defined(OS_CHROMEOS) - // Shell out to xmessage, which behaves like debug_message.exe, but is - // way more retro. We could use zenity/kdialog but then we're starting - // to get into needing to check the desktop env and this dialog should - // only be coming up in Very Bad situations. - std::vector<std::string> argv; - argv.push_back("xmessage"); - argv.push_back(str); - base::LaunchApp(argv, base::file_handle_mapping_vector(), true /* wait */, - NULL); +#elif defined(OS_MACOSX) + base::mac::ScopedCFTypeRef<CFStringRef> message( + base::SysUTF8ToCFStringRef(str)); + CFUserNotificationDisplayNotice(0, kCFUserNotificationStopAlertLevel, + NULL, NULL, NULL, CFSTR("Fatal Error"), + message, NULL); #else - // http://code.google.com/p/chromium/issues/detail?id=37026 - NOTIMPLEMENTED(); + // We intentionally don't implement a dialog on other platforms. + // You can just look at stderr. #endif } @@ -602,7 +606,7 @@ void LogMessage::Init(const char* file, int line) { else stream_ << "VERBOSE" << -severity_; - stream_ << ":" << file << "(" << line << ")] "; + stream_ << ":" << filename << "(" << line << ")] "; message_start_ = stream_.tellp(); } diff --git a/base/logging_win.cc b/base/logging_win.cc index 42610b5..f780b5e 100644 --- a/base/logging_win.cc +++ b/base/logging_win.cc @@ -6,14 +6,6 @@ #include "base/singleton.h" #include <initguid.h> // NOLINT -namespace { - -typedef StaticMemorySingletonTraits<logging::LogEventProvider> - LogEventSingletonTraits; -Singleton<logging::LogEventProvider, LogEventSingletonTraits> log_provider; - -} // namespace - namespace logging { using base::win::EtwEventLevel; @@ -25,6 +17,11 @@ DEFINE_GUID(kLogEventId, LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) { } +LogEventProvider* LogEventProvider::GetInstance() { + return Singleton<LogEventProvider, + StaticMemorySingletonTraits<LogEventProvider> >::get(); +} + bool LogEventProvider::LogMessage(logging::LogSeverity severity, const char* file, int line, size_t message_start, const std::string& message) { @@ -53,7 +50,7 @@ bool LogEventProvider::LogMessage(logging::LogSeverity severity, // Bail if we're not logging, not at that level, // or if we're post-atexit handling. - LogEventProvider* provider = log_provider.get(); + LogEventProvider* provider = LogEventProvider::GetInstance(); if (provider == NULL || level > provider->enable_level()) return false; @@ -100,7 +97,7 @@ bool LogEventProvider::LogMessage(logging::LogSeverity severity, } void LogEventProvider::Initialize(const GUID& provider_name) { - LogEventProvider* provider = log_provider.get(); + LogEventProvider* provider = LogEventProvider::GetInstance(); provider->set_provider_name(provider_name); provider->Register(); @@ -110,7 +107,7 @@ void LogEventProvider::Initialize(const GUID& provider_name) { } void LogEventProvider::Uninitialize() { - log_provider.get()->Unregister(); + LogEventProvider::GetInstance()->Unregister(); } void LogEventProvider::OnEventsEnabled() { diff --git a/base/logging_win.h b/base/logging_win.h index 695c7f2..9058c84 100644 --- a/base/logging_win.h +++ b/base/logging_win.h @@ -11,6 +11,9 @@ #include "base/win/event_trace_provider.h" #include "base/logging.h" +template <typename Type> +struct StaticMemorySingletonTraits; + namespace logging { // Event ID for the log messages we generate. @@ -47,7 +50,7 @@ enum LogMessageTypes { // with Event Tracing for Windows. class LogEventProvider : public base::win::EtwTraceProvider { public: - LogEventProvider(); + static LogEventProvider* GetInstance(); static bool LogMessage(logging::LogSeverity severity, const char* file, int line, size_t message_start, const std::string& str); @@ -61,10 +64,13 @@ class LogEventProvider : public base::win::EtwTraceProvider { virtual void OnEventsDisabled(); private: + LogEventProvider(); + // The log severity prior to OnEventsEnabled, // restored in OnEventsDisabled. logging::LogSeverity old_log_level_; + friend struct StaticMemorySingletonTraits<LogEventProvider>; DISALLOW_COPY_AND_ASSIGN(LogEventProvider); }; diff --git a/base/cocoa_protocols_mac.h b/base/mac/cocoa_protocols.h index 9482d51..9482d51 100644 --- a/base/cocoa_protocols_mac.h +++ b/base/mac/cocoa_protocols.h diff --git a/base/mac_util.h b/base/mac_util.h index d31bf82..076865d 100644 --- a/base/mac_util.h +++ b/base/mac_util.h @@ -10,16 +10,20 @@ #include <string> #include <vector> -class FilePath; +#include "base/logging.h" + +#if defined(__OBJC__) +#import <Foundation/Foundation.h> -#ifdef __OBJC__ @class NSBundle; @class NSWindow; -#else +#else // __OBJC__ class NSBundle; class NSImage; class NSWindow; -#endif +#endif // __OBJC__ + +class FilePath; // Adapted from NSPathUtilities.h and NSObjCRuntime.h. #if __LP64__ || NS_BUILD_32_LIKE_64 @@ -188,6 +192,56 @@ bool WasLaunchedAsHiddenLoginItem(); void NSObjectRetain(void* obj); void NSObjectRelease(void* obj); +#if defined(__OBJC__) + +// Convert toll-free bridged CFTypes to NSTypes. This does not autorelease +// |cf_val|. This is useful for the case where there is a CFType in a call that +// expects an NSType and the compiler is complaining about const casting +// problems. +// The call is used like this: +// NSString *foo = CFToNSCast(CFSTR("Hello")); +// The macro magic below is to enforce safe casting. It could possibly have +// been done using template function specialization, but template function +// specialization doesn't always work intuitively, +// (http://www.gotw.ca/publications/mill17.htm) so the trusty combination +// of macros and function overloading is used instead. + +#define CF_TO_NS_CAST(TypeCF, TypeNS) \ +inline TypeNS* CFToNSCast(TypeCF cf_val) { \ + TypeNS* ns_val = \ + const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \ + DCHECK(!ns_val || [ns_val isKindOfClass:[TypeNS class]]); \ + return ns_val; \ +} + +// List of toll-free bridged types taken from: +// http://www.cocoadev.com/index.pl?TollFreeBridged + +CF_TO_NS_CAST(CFArrayRef, NSArray); +CF_TO_NS_CAST(CFMutableArrayRef, NSMutableArray); +CF_TO_NS_CAST(CFAttributedStringRef, NSAttributedString); +CF_TO_NS_CAST(CFMutableAttributedStringRef, NSMutableAttributedString); +CF_TO_NS_CAST(CFCalendarRef, NSCalendar); +CF_TO_NS_CAST(CFCharacterSetRef, NSCharacterSet); +CF_TO_NS_CAST(CFMutableCharacterSetRef, NSMutableCharacterSet); +CF_TO_NS_CAST(CFDataRef, NSData); +CF_TO_NS_CAST(CFMutableDataRef, NSMutableData); +CF_TO_NS_CAST(CFDateRef, NSDate); +CF_TO_NS_CAST(CFDictionaryRef, NSDictionary); +CF_TO_NS_CAST(CFMutableDictionaryRef, NSMutableDictionary); +CF_TO_NS_CAST(CFNumberRef, NSNumber); +CF_TO_NS_CAST(CFRunLoopTimerRef, NSTimer); +CF_TO_NS_CAST(CFSetRef, NSSet); +CF_TO_NS_CAST(CFMutableSetRef, NSMutableSet); +CF_TO_NS_CAST(CFStringRef, NSString); +CF_TO_NS_CAST(CFMutableStringRef, NSMutableString); +CF_TO_NS_CAST(CFURLRef, NSURL); +CF_TO_NS_CAST(CFTimeZoneRef, NSTimeZone); +CF_TO_NS_CAST(CFReadStreamRef, NSInputStream); +CF_TO_NS_CAST(CFWriteStreamRef, NSOutputStream); + +#endif // __OBJC__ + } // namespace mac_util #endif // BASE_MAC_UTIL_H_ diff --git a/base/mac_util.mm b/base/mac_util.mm index 9610d37..598f69b 100644 --- a/base/mac_util.mm +++ b/base/mac_util.mm @@ -55,19 +55,17 @@ void SetUIMode() { bool WasLaunchedAsLoginItem() { ProcessSerialNumber psn = { 0, kCurrentProcess }; - scoped_nsobject<const NSDictionary> process_info( - reinterpret_cast<const NSDictionary*>( - ProcessInformationCopyDictionary(&psn, - kProcessDictionaryIncludeAllInformationMask))); + scoped_nsobject<NSDictionary> process_info( + mac_util::CFToNSCast(ProcessInformationCopyDictionary(&psn, + kProcessDictionaryIncludeAllInformationMask))); long long temp = [[process_info objectForKey:@"ParentPSN"] longLongValue]; ProcessSerialNumber parent_psn = { (temp >> 32) & 0x00000000FFFFFFFFLL, temp & 0x00000000FFFFFFFFLL }; - scoped_nsobject<const NSDictionary> parent_info( - reinterpret_cast<const NSDictionary*>( - ProcessInformationCopyDictionary(&parent_psn, - kProcessDictionaryIncludeAllInformationMask))); + scoped_nsobject<NSDictionary> parent_info( + mac_util::CFToNSCast(ProcessInformationCopyDictionary(&parent_psn, + kProcessDictionaryIncludeAllInformationMask))); // Check that creator process code is that of loginwindow. BOOL result = @@ -88,9 +86,8 @@ LSSharedFileListItemRef GetLoginItemForApp() { return NULL; } - scoped_nsobject<const NSArray> login_items_array( - reinterpret_cast<const NSArray*>( - LSSharedFileListCopySnapshot(login_items, NULL))); + scoped_nsobject<NSArray> login_items_array( + mac_util::CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL))); NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; @@ -563,7 +560,7 @@ void SetProcessName(CFStringRef process_name) { if (!ls_set_application_information_item_func) LOG(ERROR) << "Could not find _LSSetApplicationInformationItem"; - const CFStringRef* key_pointer = reinterpret_cast<const CFStringRef*>( + CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>( CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey"))); ls_display_name_key = key_pointer ? *key_pointer : NULL; diff --git a/base/mac_util_unittest.mm b/base/mac_util_unittest.mm index 7999878..63ea9b2 100644 --- a/base/mac_util_unittest.mm +++ b/base/mac_util_unittest.mm @@ -7,10 +7,10 @@ #include "base/mac_util.h" -#import "base/chrome_application_mac.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/mac/scoped_cftyperef.h" +#include "base/test/mock_chrome_application_mac.h" #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" @@ -54,7 +54,7 @@ TEST_F(MacUtilTest, TestLibraryPath) { TEST_F(MacUtilTest, TestGrabWindowSnapshot) { // Launch a test window so we can take a snapshot. - [CrApplication sharedApplication]; + [MockCrApp sharedApplication]; NSRect frame = NSMakeRect(0, 0, 400, 400); scoped_nsobject<NSWindow> window( [[NSWindow alloc] initWithContentRect:frame diff --git a/base/message_loop.cc b/base/message_loop.cc index 11c7198..98c7ceb 100644 --- a/base/message_loop.cc +++ b/base/message_loop.cc @@ -26,7 +26,6 @@ #include "base/message_pump_glib_x.h" #endif -using base::Time; using base::TimeDelta; using base::TimeTicks; @@ -141,9 +140,13 @@ MessageLoop::MessageLoop(Type type) #define MESSAGE_PUMP_UI new base::MessagePumpDefault() #define MESSAGE_PUMP_IO new base::MessagePumpLibevent() #elif defined(TOUCH_UI) -// TODO(sadrul): enable the new message pump when ready -#define MESSAGE_PUMP_UI new base::MessagePumpForUI() +#define MESSAGE_PUMP_UI new base::MessagePumpGlibX() #define MESSAGE_PUMP_IO new base::MessagePumpLibevent() +#elif defined(OS_NACL) +// Currently NaCl doesn't have a UI or an IO MessageLoop. +// TODO(abarth): Figure out if we need these. +#define MESSAGE_PUMP_UI NULL +#define MESSAGE_PUMP_IO NULL #elif defined(OS_POSIX) // POSIX but not MACOSX. #define MESSAGE_PUMP_UI new base::MessagePumpForUI() #define MESSAGE_PUMP_IO new base::MessagePumpLibevent() @@ -347,9 +350,9 @@ void MessageLoop::PostTask_Helper( // res timers for any timer which is within 2x of the granularity. // This is a tradeoff between accuracy and power management. bool needs_high_res_timers = - delay_ms < (2 * Time::kMinLowResolutionThresholdMs); + delay_ms < (2 * base::Time::kMinLowResolutionThresholdMs); if (needs_high_res_timers) { - Time::ActivateHighResolutionTimer(true); + base::Time::ActivateHighResolutionTimer(true); high_resolution_timer_expiration_ = TimeTicks::Now() + TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); } @@ -362,7 +365,7 @@ void MessageLoop::PostTask_Helper( #if defined(OS_WIN) if (!high_resolution_timer_expiration_.is_null()) { if (TimeTicks::Now() > high_resolution_timer_expiration_) { - Time::ActivateHighResolutionTimer(false); + base::Time::ActivateHighResolutionTimer(false); high_resolution_timer_expiration_ = TimeTicks(); } } @@ -640,7 +643,7 @@ void MessageLoop::EnableHistogrammer(bool enable) { void MessageLoop::StartHistogrammer() { if (enable_histogrammer_ && !message_histogram_.get() - && base::StatisticsRecorder::WasStarted()) { + && base::StatisticsRecorder::IsActive()) { DCHECK(!thread_name_.empty()); message_histogram_ = base::LinearHistogram::FactoryGet( "MsgLoop:" + thread_name_, @@ -665,7 +668,11 @@ void MessageLoopForUI::DidProcessMessage(const MSG& message) { } #endif // defined(OS_WIN) +<<<<<<< HEAD #if !defined(OS_MACOSX) && !defined(ANDROID) +======= +#if !defined(OS_MACOSX) && !defined(OS_NACL) +>>>>>>> chromium.org at r10.0.621.0 void MessageLoopForUI::AddObserver(Observer* observer) { pump_ui()->AddObserver(observer); } @@ -679,7 +686,7 @@ void MessageLoopForUI::Run(Dispatcher* dispatcher) { state_->dispatcher = dispatcher; RunHandler(); } -#endif // !defined(OS_MACOSX) +#endif // !defined(OS_MACOSX) && !defined(OS_NACL) //------------------------------------------------------------------------------ // MessageLoopForIO @@ -694,7 +701,7 @@ bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { return pump_io()->WaitForIOCompletion(timeout, filter); } -#elif defined(OS_POSIX) +#elif defined(OS_POSIX) && !defined(OS_NACL) bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, diff --git a/base/message_loop_proxy_impl.h b/base/message_loop_proxy_impl.h index 87ae70a..44ab2ea 100644 --- a/base/message_loop_proxy_impl.h +++ b/base/message_loop_proxy_impl.h @@ -18,7 +18,7 @@ namespace base { class MessageLoopProxyImpl : public MessageLoopProxy, public MessageLoop::DestructionObserver { public: - ~MessageLoopProxyImpl(); + virtual ~MessageLoopProxyImpl(); // MessageLoopProxy implementation virtual bool PostTask(const tracked_objects::Location& from_here, @@ -33,8 +33,8 @@ class MessageLoopProxyImpl : public MessageLoopProxy, int64 delay_ms); virtual bool BelongsToCurrentThread(); -// MessageLoop::DestructionObserver implementation - void WillDestroyCurrentMessageLoop(); + // MessageLoop::DestructionObserver implementation + virtual void WillDestroyCurrentMessageLoop(); protected: // Override OnDestruct so that we can delete the object on the target message diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc index 537c606..a196519 100644 --- a/base/message_loop_unittest.cc +++ b/base/message_loop_unittest.cc @@ -1576,7 +1576,7 @@ TEST(MessageLoopTest, HighResolutionTimer) { #endif // defined(OS_WIN) -#if defined(OS_POSIX) +#if defined(OS_POSIX) && !defined(OS_NACL) namespace { @@ -1646,7 +1646,7 @@ TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) { } // namespace -#endif // defined(OS_POSIX) +#endif // defined(OS_POSIX) && !defined(OS_NACL) namespace { class RunAtDestructionTask : public Task { diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc index fa5b726..fd24285 100644 --- a/base/message_pump_glib.cc +++ b/base/message_pump_glib.cc @@ -315,6 +315,10 @@ void MessagePumpForUI::DidProcessEvent(GdkEvent* event) { FOR_EACH_OBSERVER(Observer, observers_, DidProcessEvent(event)); } +void MessagePumpForUI::Run(Delegate* delegate) { + RunWithDispatcher(delegate, NULL); +} + void MessagePumpForUI::Quit() { if (state_) { state_->should_quit = true; diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h index 06635de..c118155 100644 --- a/base/message_pump_glib.h +++ b/base/message_pump_glib.h @@ -62,7 +62,7 @@ class MessagePumpForUI : public MessagePump { // is ready for processing. virtual bool RunOnce(GMainContext* context, bool block); - virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); } + virtual void Run(Delegate* delegate); virtual void Quit(); virtual void ScheduleWork(); virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time); diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc index 78c1799..26c4b87 100644 --- a/base/message_pump_glib_x.cc +++ b/base/message_pump_glib_x.cc @@ -85,6 +85,8 @@ MessagePumpGlibX::~MessagePumpGlibX() { bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { GdkDisplay* gdisp = gdk_display_get_default(); Display* display = GDK_DISPLAY_XDISPLAY(gdisp); + bool should_quit = false; + if (XPending(display)) { XEvent xev; XPeekEvent(display, &xev); @@ -95,10 +97,22 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { ) { XNextEvent(display, &xev); - bool processed = static_cast<MessagePumpGlibXDispatcher*> +#if defined(HAVE_XINPUT2) + bool have_cookie = false; + if (xev.type == GenericEvent && + XGetEventData(xev.xgeneric.display, &xev.xcookie)) { + have_cookie = true; + } +#endif + + MessagePumpGlibXDispatcher::DispatchStatus status = + static_cast<MessagePumpGlibXDispatcher*> (GetDispatcher())->Dispatch(&xev); - if (!processed) { + if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) { + should_quit = true; + Quit(); + } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) { DLOG(WARNING) << "Event (" << xev.type << ") not handled."; // TODO(sad): It is necessary to put back the event so that the default @@ -106,16 +120,29 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { // impossible to use the omnibox at the moment. However, this will // eventually be removed once the omnibox code is updated for touchui. XPutBackEvent(display, &xev); + if (gdksource_) + gdksource_->source_funcs->dispatch = gdkdispatcher_; g_main_context_iteration(context, FALSE); } + +#if defined(HAVE_XINPUT2) + if (have_cookie) { + XFreeEventData(xev.xgeneric.display, &xev.xcookie); + } +#endif } 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. + if (gdksource_) + gdksource_->source_funcs->dispatch = gdkdispatcher_; g_main_context_iteration(context, FALSE); } } + if (should_quit) + return true; + bool retvalue; if (gdksource_) { // Replace the dispatch callback of the GDK event source temporarily so that @@ -178,6 +205,9 @@ void MessagePumpGlibX::InitializeXInput2(void) { return; } + // TODO(sad): Here, we only setup so that the X windows created by GTK+ are + // setup for XInput2 events. We need a way to listen for XInput2 events for X + // windows created by other means (e.g. for context menus). SetupGtkWidgetRealizeNotifier(this); // Instead of asking X for the list of devices all the time, let's maintain a @@ -242,6 +272,7 @@ void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { if (!pump_x->gdksource_) { pump_x->gdksource_ = g_main_current_source(); + pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch; } else if (!pump_x->IsDispatchingEvent()) { if (event->type != GDK_NOTHING && pump_x->capture_gdk_events_[event->type]) { diff --git a/base/message_pump_glib_x.h b/base/message_pump_glib_x.h index c6d98e3..fc3f3b1 100644 --- a/base/message_pump_glib_x.h +++ b/base/message_pump_glib_x.h @@ -60,6 +60,10 @@ class MessagePumpGlibX : public MessagePumpForUI { // The event source for GDK events. GSource* gdksource_; + // The default GDK event dispatcher. This is stored so that it can be restored + // when necessary during nested event dispatching. + gboolean (*gdkdispatcher_)(GSource*, GSourceFunc, void*); + // 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_; diff --git a/base/message_pump_glib_x_dispatch.h b/base/message_pump_glib_x_dispatch.h index 95364a2..faee5b5 100644 --- a/base/message_pump_glib_x_dispatch.h +++ b/base/message_pump_glib_x_dispatch.h @@ -18,9 +18,18 @@ namespace base { // 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; + + typedef enum { + EVENT_IGNORED, // The event was not processed. + EVENT_PROCESSED, // The event has been processed. + EVENT_QUIT // The event was processed and the message-loop should + // terminate. + } DispatchStatus; + + // Dispatches the event. EVENT_IGNORED is returned if the event was ignored + // (i.e. not processed). EVENT_PROCESSED is returned if the event was + // processed. The nested loop exits immediately if EVENT_QUIT is returned. + virtual DispatchStatus Dispatch(XEvent* xevent) = 0; }; } // namespace base diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h index e016d54..c30a8ea 100644 --- a/base/message_pump_mac.h +++ b/base/message_pump_mac.h @@ -36,11 +36,20 @@ #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> -#if defined(__OBJC__) -@class NSAutoreleasePool; -#else // defined(__OBJC__) +#if !defined(__OBJC__) class NSAutoreleasePool; -#endif // defined(__OBJC__) +#else // !defined(__OBJC__) +#import <AppKit/AppKit.h> + +// Clients must subclass NSApplication and implement this protocol if they use +// MessagePumpMac. +@protocol CrAppProtocol +// Must return true if -[NSApplication sendEvent:] is currently on the stack. +// See the comment for |CreateAutoreleasePool()| in the cc file for why this is +// necessary. +- (BOOL)isHandlingSendEvent; +@end +#endif // !defined(__OBJC__) namespace base { diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm index 9091006..8c5461c 100644 --- a/base/message_pump_mac.mm +++ b/base/message_pump_mac.mm @@ -11,7 +11,6 @@ #include <limits> -#import "base/chrome_application_mac.h" #include "base/logging.h" #include "base/time.h" @@ -673,10 +672,6 @@ MessagePumpNSApplication::MessagePumpNSApplication() void MessagePumpNSApplication::DoRun(Delegate* delegate) { bool last_running_own_loop_ = running_own_loop_; - // TODO(dmaclach): Get rid of this gratuitous sharedApplication. - // Tests should be setting up their applications on their own. - [CrApplication sharedApplication]; - if (![NSApp isRunning]) { running_own_loop_ = false; // NSApplication manages autorelease pools itself when run this way. @@ -749,12 +744,12 @@ void MessagePumpNSApplication::Quit() { // autorelease pool stack. // // CrApplication is responsible for setting handlingSendEvent to true just -// before it sends the event throught the event handling mechanism, and +// before it sends the event through the event handling mechanism, and // returning it to its previous value once the event has been sent. NSAutoreleasePool* MessagePumpNSApplication::CreateAutoreleasePool() { NSAutoreleasePool* pool = nil; - DCHECK([NSApp isKindOfClass:[CrApplication class]]); - if (![static_cast<CrApplication*>(NSApp) isHandlingSendEvent]) { + DCHECK([NSApp conformsToProtocol:@protocol(CrAppProtocol)]); + if (![NSApp isHandlingSendEvent]) { pool = MessagePumpCFRunLoopBase::CreateAutoreleasePool(); } return pool; diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 63d9ed5..d29ed2d 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc @@ -17,6 +17,9 @@ const int FieldTrial::kNotParticipating = -1; const int FieldTrial::kAllRemainingProbability = -2; // static +bool FieldTrial::enable_benchmarking_ = false; + +// static const char FieldTrialList::kPersistentStringSeparator('/'); static const char kHistogramFieldTrialSeparator('_'); @@ -40,10 +43,13 @@ int FieldTrial::AppendGroup(const std::string& name, DCHECK(group_probability <= divisor_); DCHECK(group_probability >=0 || group_probability == kAllRemainingProbability); - if (group_probability == kAllRemainingProbability) + if (group_probability == kAllRemainingProbability) { accumulated_group_probability_ = divisor_; - else + } else { + if (enable_benchmarking_) + group_probability = 0; accumulated_group_probability_ += group_probability; + } DCHECK(accumulated_group_probability_ <= divisor_); if (group_ == kNotParticipating && accumulated_group_probability_ > random_) { // This is the group that crossed the random line, so we do the assignment. @@ -64,6 +70,12 @@ std::string FieldTrial::MakeName(const std::string& name_prefix, return big_string.append(FieldTrialList::FindFullName(trial_name)); } +// static +void FieldTrial::EnableBenchmarking() { + DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount()); + enable_benchmarking_ = true; +} + FieldTrial::~FieldTrial() {} //------------------------------------------------------------------------------ @@ -190,4 +202,12 @@ bool FieldTrialList::StringAugmentsState(const std::string& prior_state) { return true; } +// static +size_t FieldTrialList::GetFieldTrialCount() { + if (!global_) + return 0; + AutoLock auto_lock(global_->lock_); + return global_->registered_.size(); +} + } // namespace base diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index 348a1a7..1f0af9e 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h @@ -117,6 +117,9 @@ class FieldTrial : public RefCounted<FieldTrial> { static std::string MakeName(const std::string& name_prefix, const std::string& trial_name); + // Enable benchmarking sets field trials to a common setting. + static void EnableBenchmarking(); + private: friend class RefCounted<FieldTrial>; @@ -148,6 +151,10 @@ class FieldTrial : public RefCounted<FieldTrial> { // If this Trial is not a member of an group, this string is empty. std::string group_name_; + // When benchmarking is enabled, field trials all revert to the 'default' + // bucket. + static bool enable_benchmarking_; + DISALLOW_COPY_AND_ASSIGN(FieldTrial); }; @@ -206,6 +213,9 @@ class FieldTrialList { return TimeTicks::Now(); } + // Return the number of active field trials. + static size_t GetFieldTrialCount(); + private: // Helper function should be called only while holding lock_. FieldTrial* PreLockedFind(const std::string& name); diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc index 729e3b9..75df12e 100644 --- a/base/metrics/histogram.cc +++ b/base/metrics/histogram.cc @@ -571,6 +571,18 @@ Histogram::Inconsistencies Histogram::FindCorruption( return static_cast<Inconsistencies>(inconsistencies); } +Histogram::ClassType Histogram::histogram_type() const { + return HISTOGRAM; +} + +Histogram::Sample Histogram::ranges(size_t i) const { + return ranges_[i]; +} + +size_t Histogram::bucket_count() const { + return bucket_count_; +} + //------------------------------------------------------------------------------ // Methods for the Histogram::SampleSet class //------------------------------------------------------------------------------ @@ -892,12 +904,21 @@ double CustomHistogram::GetBucketSize(Count current, size_t i) const { // provide support for all future calls. StatisticsRecorder::StatisticsRecorder() { DCHECK(!histograms_); - lock_ = new Lock; + if (lock_ == NULL) { + // This will leak on purpose. It's the only way to make sure we won't race + // against the static uninitialization of the module while one of our + // static methods relying on the lock get called at an inappropriate time + // during the termination phase. Since it's a static data member, we will + // leak one per process, which would be similar to the instance allocated + // during static initialization and released only on process termination. + lock_ = new Lock; + } + AutoLock auto_lock(*lock_); histograms_ = new HistogramMap; } StatisticsRecorder::~StatisticsRecorder() { - DCHECK(histograms_); + DCHECK(histograms_ && lock_); if (dump_on_exit_) { std::string output; @@ -905,14 +926,22 @@ StatisticsRecorder::~StatisticsRecorder() { LOG(INFO) << output; } // Clean up. - delete histograms_; - histograms_ = NULL; - delete lock_; - lock_ = NULL; + HistogramMap* histograms = NULL; + { + AutoLock auto_lock(*lock_); + histograms = histograms_; + histograms_ = NULL; + } + delete histograms; + // We don't delete lock_ on purpose to avoid having to properly protect + // against it going away after we checked for NULL in the static methods. } // static -bool StatisticsRecorder::WasStarted() { +bool StatisticsRecorder::IsActive() { + if (lock_ == NULL) + return false; + AutoLock auto_lock(*lock_); return NULL != histograms_; } @@ -923,10 +952,12 @@ bool StatisticsRecorder::WasStarted() { // destroyed before assignment (when value was returned by new). // static void StatisticsRecorder::Register(Histogram* histogram) { + if (lock_ == NULL) + return; + AutoLock auto_lock(*lock_); if (!histograms_) return; const std::string name = histogram->histogram_name(); - AutoLock auto_lock(*lock_); // Avoid overwriting a previous registration. if (histograms_->end() == histograms_->find(name)) (*histograms_)[name] = histogram; @@ -935,7 +966,7 @@ void StatisticsRecorder::Register(Histogram* histogram) { // static void StatisticsRecorder::WriteHTMLGraph(const std::string& query, std::string* output) { - if (!histograms_) + if (!IsActive()) return; output->append("<html><head><title>About Histograms"); if (!query.empty()) @@ -959,7 +990,7 @@ void StatisticsRecorder::WriteHTMLGraph(const std::string& query, // static void StatisticsRecorder::WriteGraph(const std::string& query, std::string* output) { - if (!histograms_) + if (!IsActive()) return; if (query.length()) StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); @@ -978,9 +1009,11 @@ void StatisticsRecorder::WriteGraph(const std::string& query, // static void StatisticsRecorder::GetHistograms(Histograms* output) { - if (!histograms_) + if (lock_ == NULL) return; AutoLock auto_lock(*lock_); + if (!histograms_) + return; for (HistogramMap::iterator it = histograms_->begin(); histograms_->end() != it; ++it) { @@ -991,9 +1024,11 @@ void StatisticsRecorder::GetHistograms(Histograms* output) { bool StatisticsRecorder::FindHistogram(const std::string& name, scoped_refptr<Histogram>* histogram) { - if (!histograms_) + if (lock_ == NULL) return false; AutoLock auto_lock(*lock_); + if (!histograms_) + return false; HistogramMap::iterator it = histograms_->find(name); if (histograms_->end() == it) return false; @@ -1004,7 +1039,11 @@ bool StatisticsRecorder::FindHistogram(const std::string& name, // private static void StatisticsRecorder::GetSnapshot(const std::string& query, Histograms* snapshot) { + if (lock_ == NULL) + return; AutoLock auto_lock(*lock_); + if (!histograms_) + return; for (HistogramMap::iterator it = histograms_->begin(); histograms_->end() != it; ++it) { diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h index b87c891..6b09aa3 100644 --- a/base/metrics/histogram.h +++ b/base/metrics/histogram.h @@ -403,13 +403,13 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> { //---------------------------------------------------------------------------- // Accessors for factory constuction, serialization and testing. //---------------------------------------------------------------------------- - virtual ClassType histogram_type() const { return HISTOGRAM; } + virtual ClassType histogram_type() const; const std::string& histogram_name() const { return histogram_name_; } Sample declared_min() const { return declared_min_; } Sample declared_max() const { return declared_max_; } - virtual Sample ranges(size_t i) const { return ranges_[i];} + virtual Sample ranges(size_t i) const; Sample range_checksum() const { return range_checksum_; } - virtual size_t bucket_count() const { return bucket_count_; } + virtual size_t bucket_count() const; // Snapshot the current complete set of sample data. // Override with atomic/locked snapshot if needed. virtual void SnapshotSample(SampleSet* sample) const; @@ -643,7 +643,7 @@ class StatisticsRecorder { ~StatisticsRecorder(); // Find out if histograms can now be registered into our list. - static bool WasStarted(); + static bool IsActive(); // Register, or add a new histogram to the collection of statistics. static void Register(Histogram* histogram); diff --git a/base/mime_util_xdg.cc b/base/mime_util_xdg.cc index 5dc4960..8be1d0d 100644 --- a/base/mime_util_xdg.cc +++ b/base/mime_util_xdg.cc @@ -28,6 +28,9 @@ class IconTheme; class MimeUtilConstants { public: + static MimeUtilConstants* GetInstance() { + return Singleton<MimeUtilConstants>::get(); + } // In seconds, specified by icon theme specs. const int kUpdateInterval; @@ -157,7 +160,7 @@ IconTheme::IconTheme(const std::string& name) std::map<FilePath, int>::iterator iter; FilePath theme_path; std::map<FilePath, int>* icon_dirs = - Singleton<MimeUtilConstants>::get()->icon_dirs_; + MimeUtilConstants::GetInstance()->icon_dirs_; for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { theme_path = iter->first.Append(name); if (!file_util::DirectoryExists(theme_path)) @@ -218,7 +221,7 @@ FilePath IconTheme::GetIconPath(const std::string& icon_name, int size, IconTheme* IconTheme::LoadTheme(const std::string& theme_name) { scoped_ptr<IconTheme> theme; std::map<std::string, IconTheme*>* icon_themes = - Singleton<MimeUtilConstants>::get()->icon_themes_; + MimeUtilConstants::GetInstance()->icon_themes_; if (icon_themes->find(theme_name) != icon_themes->end()) { theme.reset((*icon_themes)[theme_name]); } else { @@ -235,7 +238,7 @@ FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name, FilePath icon_path; std::list<FilePath>::iterator dir_iter; std::vector<std::string>* icon_formats = - &Singleton<MimeUtilConstants>::get()->icon_formats_; + &MimeUtilConstants::GetInstance()->icon_formats_; for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) { for (size_t i = 0; i < icon_formats->size(); ++i) { icon_path = dir_iter->Append(subdir); @@ -383,7 +386,7 @@ bool IconTheme::SetDirectories(const std::string& dirs) { void TryAddIconDir(const FilePath& dir) { if (!file_util::DirectoryExists(dir)) return; - (*Singleton<MimeUtilConstants>::get()->icon_dirs_)[dir] = 0; + (*MimeUtilConstants::GetInstance()->icon_dirs_)[dir] = 0; } // For a xdg directory |dir|, add the appropriate icon sub-directories. @@ -396,7 +399,7 @@ void AddXDGDataDir(const FilePath& dir) { // Add all the xdg icon directories. void InitIconDir() { - Singleton<MimeUtilConstants>::get()->icon_dirs_->clear(); + MimeUtilConstants::GetInstance()->icon_dirs_->clear(); FilePath home = file_util::GetHomeDir(); if (!home.empty()) { FilePath legacy_data_dir(home); @@ -435,7 +438,7 @@ void EnsureUpdated() { struct timeval t; gettimeofday(&t, NULL); time_t now = t.tv_sec; - MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get(); + MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); if (constants->last_check_time_ == 0) { constants->icon_dirs_ = new std::map<FilePath, int>; @@ -453,7 +456,7 @@ void EnsureUpdated() { // Find a fallback icon if we cannot find it in the default theme. FilePath LookupFallbackIcon(const std::string& icon_name) { FilePath icon; - MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get(); + MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); std::map<FilePath, int>::iterator iter; std::map<FilePath, int>* icon_dirs = constants->icon_dirs_; std::vector<std::string>* icon_formats = &constants->icon_formats_; @@ -470,7 +473,7 @@ FilePath LookupFallbackIcon(const std::string& icon_name) { // Initialize the list of default themes. void InitDefaultThemes() { IconTheme** default_themes = - Singleton<MimeUtilConstants>::get()->default_themes_; + MimeUtilConstants::GetInstance()->default_themes_; char* env = getenv("KDE_FULL_SESSION"); if (env) { @@ -498,7 +501,7 @@ void InitDefaultThemes() { } else { // Assume it's Gnome and use GTK to figure out the theme. default_themes[1] = IconTheme::LoadTheme( - Singleton<MimeUtilConstants>::get()->gtk_theme_name_); + MimeUtilConstants::GetInstance()->gtk_theme_name_); default_themes[2] = IconTheme::LoadTheme("gnome"); } // hicolor needs to be last per icon theme spec. @@ -518,7 +521,7 @@ void InitDefaultThemes() { // Try to find an icon with the name |icon_name| that's |size| pixels. FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) { EnsureUpdated(); - MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get(); + MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); std::map<std::string, IconTheme*>* icon_themes = constants->icon_themes_; if (icon_themes->size() == 0) InitDefaultThemes(); @@ -558,7 +561,7 @@ void DetectGtkTheme() { // If the theme name is already loaded, do nothing. Chrome doesn't respond // to changes in the system theme, so we never need to set this more than // once. - if (!Singleton<MimeUtilConstants>::get()->gtk_theme_name_.empty()) + if (!MimeUtilConstants::GetInstance()->gtk_theme_name_.empty()) return; // We should only be called on the UI thread. @@ -568,7 +571,7 @@ void DetectGtkTheme() { g_object_get(gtk_settings_get_default(), "gtk-icon-theme-name", >k_theme_name, NULL); - Singleton<MimeUtilConstants>::get()->gtk_theme_name_.assign(gtk_theme_name); + MimeUtilConstants::GetInstance()->gtk_theme_name_.assign(gtk_theme_name); g_free(gtk_theme_name); } diff --git a/base/nsimage_cache_mac.h b/base/nsimage_cache_mac.h deleted file mode 100644 index b13eac9..0000000 --- a/base/nsimage_cache_mac.h +++ /dev/null @@ -1,33 +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. - -#ifndef BASE_NSIMAGE_CACHE_MAC_H_ -#define BASE_NSIMAGE_CACHE_MAC_H_ -#pragma once - -#ifdef __OBJC__ -@class NSImage; -@class NSString; -#else -class NSImage; -class NSString; -#endif - -namespace nsimage_cache { - -// Returns an autoreleased image from the main app bundle -// (mac_util::MainAppBundle()) with the given name, and keeps it in memory so -// future fetches are fast. -// NOTE: -// - This should only be called on the main thread. -// - The caller should retain the image if they want to keep it around, as -// the cache could have limit on size/lifetime, etc. -NSImage* ImageNamed(NSString* name); - -// Clears the cache. -void Clear(void); - -} // namespace nsimage_cache - -#endif // BASE_NSIMAGE_CACHE_MAC_H_ diff --git a/base/nsimage_cache_mac.mm b/base/nsimage_cache_mac.mm deleted file mode 100644 index e693ed4..0000000 --- a/base/nsimage_cache_mac.mm +++ /dev/null @@ -1,73 +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/nsimage_cache_mac.h" - -#import <AppKit/AppKit.h> - -#include "base/logging.h" -#include "base/mac_util.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 -// language support for exceptions is not present. These macros interfere -// with the use of |@try| and |@catch| in Objective-C files such as this one. -// Undefine these macros here, after everything has been #included, since -// there will be no C++ uses and only Objective-C uses from this point on. -#undef try -#undef catch - -namespace nsimage_cache { - -static NSMutableDictionary* image_cache = nil; - -NSImage* ImageNamed(NSString* name) { - DCHECK(name); - - // NOTE: to make this thread safe, we'd have to sync on the cache and - // also force all the bundle calls on the main thread. - - if (!image_cache) { - image_cache = [[NSMutableDictionary alloc] init]; - DCHECK(image_cache); - } - - NSImage* result = [image_cache objectForKey:name]; - if (!result) { - DVLOG_IF(1, [[name pathExtension] length] == 0) << "Suggest including the " - "extension in the image name"; - - NSString* path = [mac_util::MainAppBundle() pathForImageResource:name]; - if (path) { - @try { - result = [[[NSImage alloc] initWithContentsOfFile:path] autorelease]; - if (result) { - // Auto-template images with names ending in "Template". - NSString* extensionlessName = [name stringByDeletingPathExtension]; - if ([extensionlessName hasSuffix:@"Template"]) - [result setTemplate:YES]; - - [image_cache setObject:result forKey:name]; - } - } - @catch (id err) { - DLOG(ERROR) << "Failed to load the image for name '" - << [name UTF8String] << "' from path '" << [path UTF8String] - << "', error: " << [[err description] UTF8String]; - result = nil; - } - } - } - - // TODO: if we ever limit the cache size, this should retain & autorelease - // the image. - return result; -} - -void Clear(void) { - // NOTE: to make this thread safe, we'd have to sync on the cache. - [image_cache removeAllObjects]; -} - -} // namespace nsimage_cache diff --git a/base/nss_util.cc b/base/nss_util.cc index 580fb60..36394da 100644 --- a/base/nss_util.cc +++ b/base/nss_util.cc @@ -333,6 +333,10 @@ void EnsureNSSInit() { g_nss_singleton.Get(); } +bool CheckNSSVersion(const char* version) { + return !!NSS_VersionCheck(version); +} + #if defined(USE_NSS) bool OpenTestNSSDB(const FilePath& path, const char* description) { return g_nss_singleton.Get().OpenTestNSSDB(path, description); diff --git a/base/nss_util.h b/base/nss_util.h index 15b624c..d1e36ac 100644 --- a/base/nss_util.h +++ b/base/nss_util.h @@ -30,6 +30,10 @@ void EnsureNSPRInit(); // ever be initialized once. NSS will be properly shut down on program exit. void EnsureNSSInit(); +// Check if the current NSS version is greater than or equals to |version|. +// A sample version string is "3.12.3". +bool CheckNSSVersion(const char* version); + #if defined(OS_CHROMEOS) // Open the r/w nssdb that's stored inside the user's encrypted home directory. void OpenPersistentNSSDB(); diff --git a/base/openssl_util.cc b/base/openssl_util.cc index 5cfc34a..bc174fa 100644 --- a/base/openssl_util.cc +++ b/base/openssl_util.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/scoped_vector.h" #include "base/singleton.h" +#include "base/string_piece.h" namespace base { @@ -23,7 +24,7 @@ unsigned long CurrentThreadId() { // Singleton for initializing and cleaning up the OpenSSL library. class OpenSSLInitSingleton { public: - static OpenSSLInitSingleton* Get() { + static OpenSSLInitSingleton* GetInstance() { // We allow the SSL environment to leak for multiple reasons: // - it is used from a non-joinable worker thread that is not stopped on // shutdown, hence may still be using OpenSSL library after the AtExit @@ -57,7 +58,7 @@ class OpenSSLInitSingleton { } static void LockingCallback(int mode, int n, const char* file, int line) { - OpenSSLInitSingleton::Get()->OnLockingCallback(mode, n, file, line); + OpenSSLInitSingleton::GetInstance()->OnLockingCallback(mode, n, file, line); } void OnLockingCallback(int mode, int n, const char* file, int line) { @@ -74,27 +75,36 @@ class OpenSSLInitSingleton { DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton); }; +// Callback routine for OpenSSL to print error messages. |str| is a +// NULL-terminated string of length |len| containing diagnostic information +// such as the library, function and reason for the error, the file and line +// where the error originated, plus potentially any context-specific +// information about the error. |context| contains a pointer to user-supplied +// data, which is currently unused. +// If this callback returns a value <= 0, OpenSSL will stop processing the +// error queue and return, otherwise it will continue calling this function +// until all errors have been removed from the queue. +int OpenSSLErrorCallback(const char* str, size_t len, void* context) { + DVLOG(1) << "\t" << StringPiece(str, len); + return 1; +} + } // namespace void EnsureOpenSSLInit() { - (void)OpenSSLInitSingleton::Get(); + (void)OpenSSLInitSingleton::GetInstance(); } void ClearOpenSSLERRStack(const tracked_objects::Location& location) { if (logging::DEBUG_MODE && VLOG_IS_ON(1)) { - int error_num = ERR_get_error(); + int error_num = ERR_peek_error(); if (error_num == 0) return; std::string message; location.Write(true, true, &message); DVLOG(1) << "OpenSSL ERR_get_error stack from " << message; - char buf[140]; - do { - ERR_error_string_n(error_num, buf, arraysize(buf)); - DVLOG(1) << "\t" << error_num << ": " << buf; - error_num = ERR_get_error(); - } while (error_num != 0); + ERR_print_errors_cb(&OpenSSLErrorCallback, NULL); } else { ERR_clear_error(); } diff --git a/base/openssl_util.h b/base/openssl_util.h index 60cb0b7..9ce7f81 100644 --- a/base/openssl_util.h +++ b/base/openssl_util.h @@ -18,7 +18,9 @@ class ScopedOpenSSL { public: ScopedOpenSSL() : ptr_(NULL) { } explicit ScopedOpenSSL(T* ptr) : ptr_(ptr) { } - ~ScopedOpenSSL() { if (ptr_) (*destructor)(ptr_); } + ~ScopedOpenSSL() { + reset(NULL); + } T* get() const { return ptr_; } void reset(T* ptr) { diff --git a/base/path_service.cc b/base/path_service.cc index 8660c42..56ce5fa 100644 --- a/base/path_service.cc +++ b/base/path_service.cc @@ -13,9 +13,9 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/hash_tables.h" +#include "base/lazy_instance.h" #include "base/lock.h" #include "base/logging.h" -#include "base/singleton.h" namespace base { bool PathProvider(int key, FilePath* result); @@ -118,8 +118,10 @@ struct PathData { } }; +static base::LazyInstance<PathData> g_path_data(base::LINKER_INITIALIZED); + static PathData* GetPathData() { - return Singleton<PathData>::get(); + return g_path_data.Pointer(); } } // namespace @@ -203,18 +205,6 @@ bool PathService::Get(int key, FilePath* result) { return true; } -#if defined(OS_WIN) -// static -bool PathService::Get(int key, std::wstring* result) { - // Deprecated compatibility function. - FilePath path; - if (!Get(key, &path)) - return false; - *result = path.ToWStringHack(); - return true; -} -#endif - bool PathService::Override(int key, const FilePath& path) { PathData* path_data = GetPathData(); DCHECK(path_data); diff --git a/base/path_service.h b/base/path_service.h index 4d99cdc..edaa5e3 100644 --- a/base/path_service.h +++ b/base/path_service.h @@ -27,11 +27,6 @@ class PathService { // Returns true if the directory or file was successfully retrieved. On // failure, 'path' will not be changed. static bool Get(int key, FilePath* path); -#if defined(OS_WIN) - // This version, producing a wstring, is deprecated and only kept around - // until we can fix all callers. - static bool Get(int key, std::wstring* path); -#endif // Overrides the path to a special directory or file. This cannot be used to // change the value of DIR_CURRENT, but that should be obvious. Also, if the diff --git a/base/pickle.cc b/base/pickle.cc index 7745527..3f376e3 100644 --- a/base/pickle.cc +++ b/base/pickle.cc @@ -406,9 +406,6 @@ const char* Pickle::FindNext(size_t header_size, DCHECK(header_size == AlignInt(header_size, sizeof(uint32))); DCHECK(header_size <= static_cast<size_t>(kPayloadUnit)); - if (static_cast<size_t>(end - start) < sizeof(Header)) - return NULL; - const Header* hdr = reinterpret_cast<const Header*>(start); const char* payload_base = start + header_size; const char* payload_end = payload_base + hdr->payload_size; diff --git a/base/pickle.h b/base/pickle.h index 03f0af1..6006e62 100644 --- a/base/pickle.h +++ b/base/pickle.h @@ -236,7 +236,6 @@ class Pickle { FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize); FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext); - FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader); FRIEND_TEST_ALL_PREFIXES(PickleTest, IteratorHasRoom); }; diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc index 39eaa1b..fdc0664 100644 --- a/base/pickle_unittest.cc +++ b/base/pickle_unittest.cc @@ -171,17 +171,6 @@ TEST(PickleTest, FindNext) { EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1)); } -TEST(PickleTest, FindNextWithIncompleteHeader) { - size_t header_size = sizeof(Pickle::Header); - scoped_array<char> buffer(new char[header_size - 1]); - memset(buffer.get(), 0x1, header_size - 1); - - const char* start = buffer.get(); - const char* end = start + header_size - 1; - - EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end)); -} - TEST(PickleTest, IteratorHasRoom) { Pickle pickle; EXPECT_TRUE(pickle.WriteInt(1)); diff --git a/base/platform_thread_mac.mm b/base/platform_thread_mac.mm index 34afea7..36e08be 100644 --- a/base/platform_thread_mac.mm +++ b/base/platform_thread_mac.mm @@ -9,21 +9,6 @@ #include "base/logging.h" -// A simple class that demonstrates our impressive ability to do nothing. -@interface NoOp : NSObject - -// Does the deed. Or does it? -+ (void)noOp; - -@end - -@implementation NoOp - -+ (void)noOp { -} - -@end - namespace base { // If Cocoa is to be used on more than one thread, it must know that the @@ -37,8 +22,9 @@ namespace base { void InitThreading() { static BOOL multithreaded = [NSThread isMultiThreaded]; if (!multithreaded) { - [NSThread detachNewThreadSelector:@selector(noOp) - toTarget:[NoOp class] + // +[NSObject class] is idempotent. + [NSThread detachNewThreadSelector:@selector(class) + toTarget:[NSObject class] withObject:nil]; multithreaded = YES; diff --git a/base/platform_thread_posix.cc b/base/platform_thread_posix.cc index e442e9c..9807ac6 100644 --- a/base/platform_thread_posix.cc +++ b/base/platform_thread_posix.cc @@ -219,5 +219,9 @@ bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { // static void PlatformThread::Join(PlatformThreadHandle thread_handle) { + // Joining another thread may block the current thread for a long time, since + // the thread referred to by |thread_handle| may still be running long-lived / + // blocking tasks. + base::ThreadRestrictions::AssertIOAllowed(); pthread_join(thread_handle, NULL); } diff --git a/base/platform_thread_win.cc b/base/platform_thread_win.cc index e5afc52..ac8a5db 100644 --- a/base/platform_thread_win.cc +++ b/base/platform_thread_win.cc @@ -125,6 +125,14 @@ bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { // static void PlatformThread::Join(PlatformThreadHandle thread_handle) { DCHECK(thread_handle); + // TODO(willchan): Enable this check once I can get it to work for Windows + // shutdown. + // Joining another thread may block the current thread for a long time, since + // the thread referred to by |thread_handle| may still be running long-lived / + // blocking tasks. +#if 0 + base::ThreadRestrictions::AssertIOAllowed(); +#endif // Wait for the thread to exit. It should already have terminated but make // sure this assumption is valid. diff --git a/base/process_util.cc b/base/process_util.cc index 6293740..7b2935d 100644 --- a/base/process_util.cc +++ b/base/process_util.cc @@ -11,7 +11,7 @@ ProcessEntry::ProcessEntry() {} ProcessEntry::~ProcessEntry() {} #endif -int GetProcessCount(const std::wstring& executable_name, +int GetProcessCount(const FilePath::StringType& executable_name, const ProcessFilter* filter) { int count = 0; NamedProcessIterator iter(executable_name, filter); @@ -20,7 +20,7 @@ int GetProcessCount(const std::wstring& executable_name, return count; } -bool KillProcesses(const std::wstring& executable_name, int exit_code, +bool KillProcesses(const FilePath::StringType& executable_name, int exit_code, const ProcessFilter* filter) { bool result = true; NamedProcessIterator iter(executable_name, filter); @@ -56,10 +56,10 @@ ProcessIterator::ProcessEntries ProcessIterator::Snapshot() { return found; } -NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name, - const ProcessFilter* filter) - : ProcessIterator(filter), - executable_name_(executable_name) { +NamedProcessIterator::NamedProcessIterator( + const FilePath::StringType& executable_name, + const ProcessFilter* filter) : ProcessIterator(filter), + executable_name_(executable_name) { } NamedProcessIterator::~NamedProcessIterator() { diff --git a/base/process_util.h b/base/process_util.h index ca43289..ce4b0bb 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -34,10 +34,10 @@ typedef struct _malloc_zone_t malloc_zone_t; #include <vector> #include "base/file_descriptor_shuffle.h" +#include "base/file_path.h" #include "base/process.h" class CommandLine; -class FilePath; namespace base { @@ -118,13 +118,15 @@ const uint32 kProcessAccessQueryLimitedInfomation = 0; const uint32 kProcessAccessWaitForTermination = 0; #endif // defined(OS_POSIX) -// A minimalistic but hopefully cross-platform set of exit codes. -// Do not change the enumeration values or you will break third-party -// installers. -enum { - PROCESS_END_NORMAL_TERMINATION = 0, - PROCESS_END_KILLED_BY_USER = 1, - PROCESS_END_PROCESS_WAS_HUNG = 2 +// Return status values from GetTerminationStatus. Don't use these as +// exit code arguments to KillProcess*(), use platform/application +// specific values instead. +enum TerminationStatus { + TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status + TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status + TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill + TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault + TERMINATION_STATUS_STILL_RUNNING // child hasn't exited yet }; // Returns the id of the current process. @@ -180,7 +182,7 @@ bool AdjustOOMScore(ProcessId process, int score); #endif #if defined(OS_POSIX) -// Close all file descriptors, expect those which are a destination in the +// Close all file descriptors, except those which are a destination in the // given multimap. Only call this function in a child process where you know // that there aren't any other threads. void CloseSuperfluousFds(const InjectiveMultimap& saved_map); @@ -320,7 +322,7 @@ class ProcessFilter { // Returns the number of processes on the machine that are running from the // given executable name. If filter is non-null, then only processes selected // by the filter will be counted. -int GetProcessCount(const std::wstring& executable_name, +int GetProcessCount(const FilePath::StringType& executable_name, const ProcessFilter* filter); // Attempts to kill all the processes on the current machine that were launched @@ -328,7 +330,7 @@ int GetProcessCount(const std::wstring& executable_name, // filter is non-null, then only processes selected by the filter are killed. // Returns true if all processes were able to be killed off, false if at least // one couldn't be killed. -bool KillProcesses(const std::wstring& executable_name, int exit_code, +bool KillProcesses(const FilePath::StringType& executable_name, int exit_code, const ProcessFilter* filter); // Attempts to kill the process identified by the given process @@ -347,10 +349,15 @@ bool KillProcessGroup(ProcessHandle process_group_id); bool KillProcessById(ProcessId process_id, int exit_code, bool wait); #endif -// Get the termination status (exit code) of the process and return true if the -// status indicates the process crashed. |child_exited| is set to true iff the -// child process has terminated. (|child_exited| may be NULL.) -bool DidProcessCrash(bool* child_exited, ProcessHandle handle); +// Get the termination status of the process by interpreting the +// circumstances of the child process' death. |exit_code| is set to +// the status returned by waitpid() on POSIX, and from +// GetExitCodeProcess() on Windows. |exit_code| may be NULL if the +// caller is not interested in it. Note that on Linux, this function +// will only return a useful result the first time it is called after +// the child exits (because it will reap the child and the information +// will no longer be available). +TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code); // Waits for process to exit. In POSIX systems, if the process hasn't been // signaled then puts the exit code in |exit_code|; otherwise it's considered @@ -370,7 +377,7 @@ bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code, // is non-null, then only processes selected by the filter are waited on. // Returns after all processes have exited or wait_milliseconds have expired. // Returns true if all the processes exited, false otherwise. -bool WaitForProcessesToExit(const std::wstring& executable_name, +bool WaitForProcessesToExit(const FilePath::StringType& executable_name, int64 wait_milliseconds, const ProcessFilter* filter); @@ -389,7 +396,7 @@ bool CrashAwareSleep(ProcessHandle handle, int64 wait_milliseconds); // on. Killed processes are ended with the given exit code. Returns false if // any processes needed to be killed, true if they all exited cleanly within // the wait_milliseconds delay. -bool CleanupProcesses(const std::wstring& executable_name, +bool CleanupProcesses(const FilePath::StringType& executable_name, int64 wait_milliseconds, int exit_code, const ProcessFilter* filter); @@ -450,7 +457,7 @@ class ProcessIterator { // until it returns false. class NamedProcessIterator : public ProcessIterator { public: - NamedProcessIterator(const std::wstring& executable_name, + NamedProcessIterator(const FilePath::StringType& executable_name, const ProcessFilter* filter); virtual ~NamedProcessIterator(); @@ -458,7 +465,7 @@ class NamedProcessIterator : public ProcessIterator { virtual bool IncludeEntry(); private: - std::wstring executable_name_; + FilePath::StringType executable_name_; DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator); }; diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc index 6138c07..670de6a 100644 --- a/base/process_util_linux.cc +++ b/base/process_util_linux.cc @@ -111,13 +111,12 @@ FilePath GetProcessExecutablePath(ProcessHandle process) { FilePath stat_file("/proc"); stat_file = stat_file.Append(base::IntToString(process)); stat_file = stat_file.Append("exe"); - char exename[2048]; - ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); - if (len < 1) { + FilePath exe_name; + if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) { // No such process. Happens frequently in e.g. TerminateAllChromeProcesses return FilePath(); } - return FilePath(std::string(exename, len)); + return exe_name; } ProcessIterator::ProcessIterator(const ProcessFilter* filter) @@ -221,8 +220,7 @@ bool ProcessIterator::CheckForNextProcess() { } bool NamedProcessIterator::IncludeEntry() { - // TODO(port): make this also work for non-ASCII filenames - if (WideToASCII(executable_name_) != entry().exe_file()) + if (executable_name_ != entry().exe_file()) return false; return ProcessIterator::IncludeEntry(); } @@ -320,13 +318,20 @@ 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"); + FilePath proc_dir = FilePath("/proc").Append(base::IntToString(process_)); std::string smaps; int private_kb = 0; int pss_kb = 0; bool have_pss = false; - if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) { + bool ret; + + { + FilePath smaps_file = proc_dir.Append("smaps"); + // Synchronously reading files in /proc is safe. + base::ThreadRestrictions::ScopedAllowIO allow_io; + ret = file_util::ReadFileToString(smaps_file, &smaps); + } + if (ret && smaps.length() > 0) { const std::string private_prefix = "Private_"; const std::string pss_prefix = "Pss"; StringTokenizer tokenizer(smaps, ":\n"); @@ -364,10 +369,14 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { if (page_size_kb <= 0) return false; - stat_file = - FilePath("/proc").Append(base::IntToString(process_)).Append("statm"); std::string statm; - if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) + { + FilePath statm_file = proc_dir.Append("statm"); + // Synchronously reading files in /proc is safe. + base::ThreadRestrictions::ScopedAllowIO allow_io; + ret = file_util::ReadFileToString(statm_file, &statm); + } + if (!ret || statm.length() == 0) return false; std::vector<std::string> statm_vec; diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm index b167aa2..aa0f14d 100644 --- a/base/process_util_mac.mm +++ b/base/process_util_mac.mm @@ -10,6 +10,8 @@ #include <dlfcn.h> #include <mach/mach.h> #include <mach/mach_init.h> +#include <mach/mach_vm.h> +#include <mach/shared_region.h> #include <mach/task.h> #include <malloc/malloc.h> #import <objc/runtime.h> @@ -25,6 +27,7 @@ #include "base/debug/debugger.h" #include "base/eintr_wrapper.h" +#include "base/hash_tables.h" #include "base/logging.h" #include "base/string_util.h" #include "base/sys_info.h" @@ -166,7 +169,7 @@ bool ProcessIterator::CheckForNextProcess() { } bool NamedProcessIterator::IncludeEntry() { - return (SysWideToUTF8(executable_name_) == entry().exe_file() && + return (executable_name_ == entry().exe_file() && ProcessIterator::IncludeEntry()); } @@ -235,13 +238,130 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const { return 0; } -// OSX appears to use a different system to get its memory. +static bool GetCPUTypeForProcess(pid_t pid, cpu_type_t* cpu_type) { + size_t len = sizeof(*cpu_type); + int result = sysctlbyname("sysctl.proc_cputype", + cpu_type, + &len, + NULL, + 0); + if (result != 0) { + PLOG(ERROR) << "sysctlbyname(""sysctl.proc_cputype"")"; + return false; + } + + return true; +} + +static bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) { + if (type == CPU_TYPE_I386) + return addr >= SHARED_REGION_BASE_I386 && + addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386); + else if (type == CPU_TYPE_X86_64) + return addr >= SHARED_REGION_BASE_X86_64 && + addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64); + else + return false; +} + +// This is a rough approximation of the algorithm that libtop uses. +// private_bytes is the size of private resident memory. +// shared_bytes is the size of shared resident memory. bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, size_t* shared_bytes) { + kern_return_t kr; + size_t private_pages_count = 0; + size_t shared_pages_count = 0; + + if (!private_bytes && !shared_bytes) + return true; + + mach_port_t task = TaskForPid(process_); + if (task == MACH_PORT_NULL) { + LOG(ERROR) << "Invalid process"; + return false; + } + + cpu_type_t cpu_type; + if (!GetCPUTypeForProcess(process_, &cpu_type)) + return false; + + // The same region can be referenced multiple times. To avoid double counting + // we need to keep track of which regions we've already counted. + base::hash_set<int> seen_objects; + + // We iterate through each VM region in the task's address map. For shared + // memory we add up all the pages that are marked as shared. Like libtop we + // try to avoid counting pages that are also referenced by other tasks. Since + // we don't have access to the VM regions of other tasks the only hint we have + // is if the address is in the shared region area. + // + // Private memory is much simpler. We simply count the pages that are marked + // as private or copy on write (COW). + // + // See libtop_update_vm_regions in + // http://www.opensource.apple.com/source/top/top-67/libtop.c + mach_vm_size_t size = 0; + for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) { + vm_region_top_info_data_t info; + mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; + mach_port_t object_name; + kr = mach_vm_region(task, + &address, + &size, + VM_REGION_TOP_INFO, + (vm_region_info_t)&info, + &info_count, + &object_name); + if (kr == KERN_INVALID_ADDRESS) { + // We're at the end of the address space. + break; + } else if (kr != KERN_SUCCESS) { + LOG(ERROR) << "Calling mach_vm_region failed with error: " + << mach_error_string(kr); + return false; + } + + if (IsAddressInSharedRegion(address, cpu_type) && + info.share_mode != SM_PRIVATE) + continue; + + if (info.share_mode == SM_COW && info.ref_count == 1) + info.share_mode = SM_PRIVATE; + + switch (info.share_mode) { + case SM_PRIVATE: + private_pages_count += info.private_pages_resident; + private_pages_count += info.shared_pages_resident; + break; + case SM_COW: + private_pages_count += info.private_pages_resident; + // Fall through + case SM_SHARED: + if (seen_objects.count(info.obj_id) == 0) { + // Only count the first reference to this region. + seen_objects.insert(info.obj_id); + shared_pages_count += info.shared_pages_resident; + } + break; + default: + break; + } + } + + vm_size_t page_size; + kr = host_page_size(task, &page_size); + if (kr != KERN_SUCCESS) { + LOG(ERROR) << "Failed to fetch host page size, error: " + << mach_error_string(kr); + return false; + } + if (private_bytes) - *private_bytes = 0; + *private_bytes = private_pages_count * page_size; if (shared_bytes) - *shared_bytes = 0; + *shared_bytes = shared_pages_count * page_size; + return true; } @@ -596,7 +716,7 @@ void EnableTerminationOnOutOfMemory() { !g_old_valloc_purgeable && !g_old_realloc_purgeable && !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null"; - // See http://trac.webkit.org/changeset/53362/trunk/WebKitTools/DumpRenderTree/mac + // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac bool zone_allocators_protected = darwin_version > 10; ChromeMallocZone* default_zone = diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc index 43096c0..f31ffdd 100644 --- a/base/process_util_posix.cc +++ b/base/process_util_posix.cc @@ -26,6 +26,7 @@ #include "base/process_util.h" #include "base/scoped_ptr.h" #include "base/stringprintf.h" +#include "base/thread_restrictions.h" #include "base/time.h" #include "base/waitable_event.h" @@ -241,6 +242,8 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { sleep_ms *= 2; } + // If we're waiting and the child hasn't died by now, force it + // with a SIGKILL. if (!exited) result = kill(process_id, SIGKILL) == 0; } @@ -558,6 +561,9 @@ bool LaunchAppImpl( } else { // Parent process if (wait) { + // While this isn't strictly disk IO, waiting for another process to + // finish is the sort of thing ThreadRestrictions is trying to prevent. + base::ThreadRestrictions::AssertIOAllowed(); pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); DPCHECK(ret > 0); } @@ -635,40 +641,45 @@ void RaiseProcessToHighPriority() { // setpriority() or sched_getscheduler, but these all require extra rights. } -bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { - int status; +TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { + int status = 0; const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); if (result == -1) { PLOG(ERROR) << "waitpid(" << handle << ")"; - if (child_exited) - *child_exited = false; - return false; + if (exit_code) + *exit_code = 0; + return TERMINATION_STATUS_NORMAL_TERMINATION; } else if (result == 0) { // the child hasn't exited yet. - if (child_exited) - *child_exited = false; - return false; + if (exit_code) + *exit_code = 0; + return TERMINATION_STATUS_STILL_RUNNING; } - if (child_exited) - *child_exited = true; + if (exit_code) + *exit_code = status; if (WIFSIGNALED(status)) { switch (WTERMSIG(status)) { - case SIGSEGV: - case SIGILL: case SIGABRT: + case SIGBUS: case SIGFPE: - return true; + case SIGILL: + case SIGSEGV: + return TERMINATION_STATUS_PROCESS_CRASHED; + case SIGINT: + case SIGKILL: + case SIGTERM: + return TERMINATION_STATUS_PROCESS_WAS_KILLED; default: - return false; + break; } } - if (WIFEXITED(status)) - return WEXITSTATUS(status) != 0; + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) + return TERMINATION_STATUS_ABNORMAL_TERMINATION; - return false; + return TERMINATION_STATUS_NORMAL_TERMINATION; } bool WaitForExitCode(ProcessHandle handle, int* exit_code) { @@ -753,6 +764,9 @@ int64 TimeValToMicroseconds(const struct timeval& tv) { static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], std::string* output, size_t max_output, bool do_search_path) { + // Doing a blocking wait for another command to finish counts as IO. + base::ThreadRestrictions::AssertIOAllowed(); + int pipe_fd[2]; pid_t pid; InjectiveMultimap fd_shuffle1, fd_shuffle2; @@ -868,7 +882,7 @@ bool GetAppOutputRestricted(const CommandLine& cl, return GetAppOutputInternal(cl, &empty_environ, output, max_output, false); } -bool WaitForProcessesToExit(const std::wstring& executable_name, +bool WaitForProcessesToExit(const FilePath::StringType& executable_name, int64 wait_milliseconds, const ProcessFilter* filter) { bool result = false; @@ -890,7 +904,7 @@ bool WaitForProcessesToExit(const std::wstring& executable_name, return result; } -bool CleanupProcesses(const std::wstring& executable_name, +bool CleanupProcesses(const FilePath::StringType& executable_name, int64 wait_milliseconds, int exit_code, const ProcessFilter* filter) { diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc index 34c444c..0eaf5d4 100644 --- a/base/process_util_unittest.cc +++ b/base/process_util_unittest.cc @@ -7,6 +7,7 @@ #include <limits> #include "base/command_line.h" +#include "base/debug_util.h" #include "base/eintr_wrapper.h" #include "base/file_path.h" #include "base/logging.h" @@ -15,6 +16,7 @@ #include "base/process_util.h" #include "base/scoped_ptr.h" #include "base/test/multiprocess_test.h" +#include "base/test/test_timeouts.h" #include "base/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" @@ -27,6 +29,7 @@ #if defined(OS_POSIX) #include <dlfcn.h> #include <fcntl.h> +#include <signal.h> #include <sys/resource.h> #include <sys/socket.h> #endif @@ -41,11 +44,25 @@ namespace { #if defined(OS_WIN) -const wchar_t* const kProcessName = L"base_unittests.exe"; +const wchar_t kProcessName[] = L"base_unittests.exe"; #else -const wchar_t* const kProcessName = L"base_unittests"; +const wchar_t kProcessName[] = L"base_unittests"; #endif // defined(OS_WIN) +const char kSignalFileSlow[] = "SlowChildProcess.die"; +const char kSignalFileCrash[] = "CrashingChildProcess.die"; +const char kSignalFileKill[] = "KilledChildProcess.die"; + +#if defined(OS_WIN) +const int kExpectedStillRunningExitCode = 0x102; +const int kExpectedKilledExitCode = 1; +#else +const int kExpectedStillRunningExitCode = 0; +#endif + +// The longest we'll wait for a process, in milliseconds. +const int kMaxWaitTimeMs = TestTimeouts::action_max_timeout_ms(); + // Sleeps until file filename is created. void WaitToDie(const char* filename) { FILE *fp; @@ -62,6 +79,27 @@ void SignalChildren(const char* filename) { fclose(fp); } +// Using a pipe to the child to wait for an event was considered, but +// there were cases in the past where pipes caused problems (other +// libraries closing the fds, child deadlocking). This is a simple +// case, so it's not worth the risk. Using wait loops is discouraged +// in most instances. +base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle, + int* exit_code) { + // Now we wait until the result is something other than STILL_RUNNING. + base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING; + const int kIntervalMs = 20; + int waited = 0; + do { + status = base::GetTerminationStatus(handle, exit_code); + PlatformThread::Sleep(kIntervalMs); + waited += kIntervalMs; + } while (status == base::TERMINATION_STATUS_STILL_RUNNING && + waited < kMaxWaitTimeMs); + + return status; +} + } // namespace class ProcessUtilTest : public base::MultiProcessTest { @@ -79,40 +117,140 @@ MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { TEST_F(ProcessUtilTest, SpawnChild) { base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); ASSERT_NE(base::kNullProcessHandle, handle); - EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); + EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs)); base::CloseProcessHandle(handle); } MULTIPROCESS_TEST_MAIN(SlowChildProcess) { - WaitToDie("SlowChildProcess.die"); + WaitToDie(kSignalFileSlow); return 0; } TEST_F(ProcessUtilTest, KillSlowChild) { - remove("SlowChildProcess.die"); + remove(kSignalFileSlow); base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); ASSERT_NE(base::kNullProcessHandle, handle); - SignalChildren("SlowChildProcess.die"); - EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); + SignalChildren(kSignalFileSlow); + EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs)); base::CloseProcessHandle(handle); - remove("SlowChildProcess.die"); + remove(kSignalFileSlow); } -TEST_F(ProcessUtilTest, DidProcessCrash) { - remove("SlowChildProcess.die"); +TEST_F(ProcessUtilTest, GetTerminationStatusExit) { + remove(kSignalFileSlow); base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); ASSERT_NE(base::kNullProcessHandle, handle); - bool child_exited = true; - EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); - EXPECT_FALSE(child_exited); + int exit_code = 42; + EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(handle, &exit_code)); + EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); + + SignalChildren(kSignalFileSlow); + exit_code = 42; + base::TerminationStatus status = + WaitForChildTermination(handle, &exit_code); + EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status); + EXPECT_EQ(0, exit_code); + base::CloseProcessHandle(handle); + remove(kSignalFileSlow); +} - SignalChildren("SlowChildProcess.die"); - EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); +#if !defined(OS_MACOSX) +// This test is disabled on Mac, since it's flaky due to ReportCrash +// taking a variable amount of time to parse and load the debug and +// symbol data for this unit test's executable before firing the +// signal handler. +// +// TODO(gspencer): turn this test process into a very small program +// with no symbols (instead of using the multiprocess testing +// framework) to reduce the ReportCrash overhead. + +MULTIPROCESS_TEST_MAIN(CrashingChildProcess) { + WaitToDie(kSignalFileCrash); +#if defined(OS_POSIX) + // Have to disable to signal handler for segv so we can get a crash + // instead of an abnormal termination through the crash dump handler. + ::signal(SIGSEGV, SIG_DFL); +#endif + // Make this process have a segmentation fault. + int* oops = NULL; + *oops = 0xDEAD; + return 1; +} + +TEST_F(ProcessUtilTest, GetTerminationStatusCrash) { + remove(kSignalFileCrash); + base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess", + false); + ASSERT_NE(base::kNullProcessHandle, handle); - EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); + int exit_code = 42; + EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(handle, &exit_code)); + EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); + + SignalChildren(kSignalFileCrash); + exit_code = 42; + base::TerminationStatus status = + WaitForChildTermination(handle, &exit_code); + EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status); + +#if defined(OS_WIN) + EXPECT_EQ(0xc0000005, exit_code); +#elif defined(OS_POSIX) + int signaled = WIFSIGNALED(exit_code); + EXPECT_NE(0, signaled); + int signal = WTERMSIG(exit_code); + EXPECT_EQ(SIGSEGV, signal); +#endif + base::CloseProcessHandle(handle); + + // Reset signal handlers back to "normal". + base::EnableInProcessStackDumping(); + remove(kSignalFileCrash); +} +#endif // !defined(OS_MACOSX) + +MULTIPROCESS_TEST_MAIN(KilledChildProcess) { + WaitToDie(kSignalFileKill); +#if defined(OS_WIN) + // Kill ourselves. + HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId()); + ::TerminateProcess(handle, kExpectedKilledExitCode); +#elif defined(OS_POSIX) + // Send a SIGKILL to this process, just like the OOM killer would. + ::kill(getpid(), SIGKILL); +#endif + return 1; +} + +TEST_F(ProcessUtilTest, GetTerminationStatusKill) { + remove(kSignalFileKill); + base::ProcessHandle handle = this->SpawnChild("KilledChildProcess", + false); + ASSERT_NE(base::kNullProcessHandle, handle); + + int exit_code = 42; + EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(handle, &exit_code)); + EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); + + SignalChildren(kSignalFileKill); + exit_code = 42; + base::TerminationStatus status = + WaitForChildTermination(handle, &exit_code); + EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); +#if defined(OS_WIN) + EXPECT_EQ(kExpectedKilledExitCode, exit_code); +#elif defined(OS_POSIX) + int signaled = WIFSIGNALED(exit_code); + EXPECT_NE(0, signaled); + int signal = WTERMSIG(exit_code); + EXPECT_EQ(SIGKILL, signal); +#endif base::CloseProcessHandle(handle); - remove("SlowChildProcess.die"); + remove(kSignalFileKill); } // Ensure that the priority of a process is restored correctly after diff --git a/base/process_util_win.cc b/base/process_util_win.cc index 097888e..71f0a1a 100644 --- a/base/process_util_win.cc +++ b/base/process_util_win.cc @@ -30,6 +30,20 @@ namespace { // System pagesize. This value remains constant on x86/64 architectures. const int PAGESIZE_KB = 4; +// Exit codes with special meanings on Windows. +const DWORD kNormalTerminationExitCode = 0; +const DWORD kDebuggerInactiveExitCode = 0xC0000354; +const DWORD kKeyboardInterruptExitCode = 0xC000013A; +const DWORD kDebuggerTerminatedExitCode = 0x40010004; + +// This exit code is used by the Windows task manager when it kills a +// process. It's value is obviously not that unique, and it's +// surprising to me that the task manager uses this value, but it +// seems to be common practice on Windows to test for it as an +// indication that the task manager has killed something if the +// process goes away. +const DWORD kProcessKilledExitCode = 1; + // HeapSetInformation function pointer. typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); @@ -105,10 +119,10 @@ bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) { ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE | - PROCESS_TERMINATE | - PROCESS_QUERY_INFORMATION | - PROCESS_VM_READ | - SYNCHRONIZE, + PROCESS_TERMINATE | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ | + SYNCHRONIZE, FALSE, pid); if (result == INVALID_HANDLE_VALUE) @@ -394,22 +408,33 @@ bool KillProcess(ProcessHandle process, int exit_code, bool wait) { return result; } -bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { - DWORD exitcode = 0; +TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { + DWORD tmp_exit_code = 0; - if (!::GetExitCodeProcess(handle, &exitcode)) { + if (!::GetExitCodeProcess(handle, &tmp_exit_code)) { NOTREACHED(); - // Assume the child has exited. - if (child_exited) - *child_exited = true; - return false; + if (exit_code) { + // This really is a random number. We haven't received any + // information about the exit code, presumably because this + // process doesn't have permission to get the exit code, or + // because of some other cause for GetExitCodeProcess to fail + // (MSDN docs don't give the possible failure error codes for + // this function, so it could be anything). But we don't want + // to leave exit_code uninitialized, since that could cause + // random interpretations of the exit code. So we assume it + // terminated "normally" in this case. + *exit_code = kNormalTerminationExitCode; + } + // Assume the child has exited normally if we can't get the exit + // code. + return TERMINATION_STATUS_NORMAL_TERMINATION; } - if (exitcode == STILL_ACTIVE) { + if (tmp_exit_code == STILL_ACTIVE) { DWORD wait_result = WaitForSingleObject(handle, 0); if (wait_result == WAIT_TIMEOUT) { - if (child_exited) - *child_exited = false; - return false; + if (exit_code) + *exit_code = wait_result; + return TERMINATION_STATUS_STILL_RUNNING; } DCHECK_EQ(WAIT_OBJECT_0, wait_result); @@ -417,27 +442,24 @@ bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { // Strange, the process used 0x103 (STILL_ACTIVE) as exit code. NOTREACHED(); - return false; + return TERMINATION_STATUS_ABNORMAL_TERMINATION; } - // We're sure the child has exited. - if (child_exited) - *child_exited = true; + if (exit_code) + *exit_code = tmp_exit_code; - // Warning, this is not generic code; it heavily depends on the way - // the rest of the code kills a process. - - if (exitcode == PROCESS_END_NORMAL_TERMINATION || - exitcode == PROCESS_END_KILLED_BY_USER || - exitcode == PROCESS_END_PROCESS_WAS_HUNG || - exitcode == 0xC0000354 || // STATUS_DEBUGGER_INACTIVE. - exitcode == 0xC000013A || // Control-C/end session. - exitcode == 0x40010004) { // Debugger terminated process/end session. - return false; + switch (tmp_exit_code) { + case kNormalTerminationExitCode: + return TERMINATION_STATUS_NORMAL_TERMINATION; + case kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE. + case kKeyboardInterruptExitCode: // Control-C/end session. + case kDebuggerTerminatedExitCode: // Debugger terminated process. + case kProcessKilledExitCode: // Task manager kill. + return TERMINATION_STATUS_PROCESS_WAS_KILLED; + default: + // All other exit codes indicate crashes. + return TERMINATION_STATUS_PROCESS_CRASHED; } - - // All other exit codes indicate crashes. - return true; } bool WaitForExitCode(ProcessHandle handle, int* exit_code) { diff --git a/base/raw_scoped_refptr_mismatch_checker.h b/base/raw_scoped_refptr_mismatch_checker.h index d2913e7..b79cfb5 100644 --- a/base/raw_scoped_refptr_mismatch_checker.h +++ b/base/raw_scoped_refptr_mismatch_checker.h @@ -7,165 +7,124 @@ #pragma once #include "base/ref_counted.h" +#include "base/template_util.h" #include "base/tuple.h" +#include "build/build_config.h" -// It is dangerous to post a task with a raw pointer argument to a function -// that expects a scoped_refptr<>. The compiler will happily accept the -// situation, but it will not attempt to increase the refcount until the task -// runs. Callers expecting the argument to be refcounted up at post time are -// in for a nasty surprise! Example: http://crbug.com/27191 +// It is dangerous to post a task with a T* argument where T is a subtype of +// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the +// object may already have been deleted since it was not held with a +// scoped_refptr. Example: http://crbug.com/27191 // The following set of traits are designed to generate a compile error // whenever this antipattern is attempted. -template <class A, class B> -struct ExpectsScopedRefptrButGetsRawPtr { + +namespace base { + +// This is a base internal implementation file used by task.h and callback.h. +// Not for public consumption, so we wrap it in namespace internal. +namespace internal { + +template <typename T> +struct NeedsScopedRefptrButGetsRawPtr { +#if defined(OS_WIN) + enum { + value = base::false_type::value + }; +#else + enum { + // Human readable translation: you needed to be a scoped_refptr if you are a + // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) + // type. + value = (is_pointer<T>::value && + (is_convertible<T, subtle::RefCountedBase*>::value || + is_convertible<T, subtle::RefCountedThreadSafeBase*>::value)) + }; +#endif +}; + +template <typename Params> +struct ParamsUseScopedRefptrCorrectly { enum { value = 0 }; }; -template <class A, class B> -struct ExpectsScopedRefptrButGetsRawPtr<scoped_refptr<A>, B*> { +template <> +struct ParamsUseScopedRefptrCorrectly<Tuple0> { enum { value = 1 }; }; -template <class Function, class Params> -struct FunctionUsesScopedRefptrCorrectly { - enum { value = 1 }; +template <typename A> +struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > { + enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value }; }; -template <class A1, class A2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1), Tuple1<A2> > { - enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value }; +template <typename A, typename B> +struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value) }; }; -template <class A1, class B1, class A2, class B2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1), Tuple2<A2, B2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value) }; +template <typename A, typename B, typename C> +struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value) }; }; -template <class A1, class B1, class C1, class A2, class B2, class C2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1), - Tuple3<A2, B2, C2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value) }; +template <typename A, typename B, typename C, typename D> +struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value) }; }; -template <class A1, class B1, class C1, class D1, - class A2, class B2, class C2, class D2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1), - Tuple4<A2, B2, C2, D2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value) }; +template <typename A, typename B, typename C, typename D, typename E> +struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value) }; }; -template <class A1, class B1, class C1, class D1, class E1, - class A2, class B2, class C2, class D2, class E2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1), - Tuple5<A2, B2, C2, D2, E2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value) }; +template <typename A, typename B, typename C, typename D, typename E, + typename F> +struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value || + NeedsScopedRefptrButGetsRawPtr<F>::value) }; }; -template <class A1, class B1, class C1, class D1, class E1, class F1, - class A2, class B2, class C2, class D2, class E2, class F2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1, F1), - Tuple6<A2, B2, C2, D2, E2, F2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value) }; +template <typename A, typename B, typename C, typename D, typename E, + typename F, typename G> +struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value || + NeedsScopedRefptrButGetsRawPtr<F>::value || + NeedsScopedRefptrButGetsRawPtr<G>::value) }; }; -template <class A1, class B1, class C1, class D1, class E1, class F1, class G1, - class A2, class B2, class C2, class D2, class E2, class F2, class G2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1, F1, G1), - Tuple7<A2, B2, C2, D2, E2, F2, G2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value || - ExpectsScopedRefptrButGetsRawPtr<G1, G2>::value) }; +template <typename A, typename B, typename C, typename D, typename E, + typename F, typename G, typename H> +struct ParamsUseScopedRefptrCorrectly<Tuple8<A, B, C, D, E, F, G, H> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value || + NeedsScopedRefptrButGetsRawPtr<F>::value || + NeedsScopedRefptrButGetsRawPtr<G>::value || + NeedsScopedRefptrButGetsRawPtr<H>::value) }; }; -template <class Method, class Params> -struct MethodUsesScopedRefptrCorrectly { - enum { value = 1 }; -}; +} // namespace internal -template <class T, class A1, class A2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1), Tuple1<A2> > { - enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value }; -}; - -template <class T, class A1, class B1, class A2, class B2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1), Tuple2<A2, B2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value) }; -}; - -template <class T, class A1, class B1, class C1, - class A2, class B2, class C2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1), - Tuple3<A2, B2, C2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value) }; -}; - -template <class T, class A1, class B1, class C1, class D1, - class A2, class B2, class C2, class D2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1), - Tuple4<A2, B2, C2, D2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value) }; -}; - -template <class T, class A1, class B1, class C1, class D1, class E1, - class A2, class B2, class C2, class D2, class E2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1), - Tuple5<A2, B2, C2, D2, E2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value) }; -}; - -template <class T, class A1, class B1, class C1, class D1, class E1, class F1, - class A2, class B2, class C2, class D2, class E2, class F2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1, F1), - Tuple6<A2, B2, C2, D2, E2, F2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value) }; -}; - -template <class T, - class A1, class B1, class C1, class D1, class E1, class F1, class G1, - class A2, class B2, class C2, class D2, class E2, class F2, class G2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1, F1, G1), - Tuple7<A2, B2, C2, D2, E2, F2, G2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value || - ExpectsScopedRefptrButGetsRawPtr<G1, G2>::value) }; -}; +} // namespace base #endif // BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ diff --git a/base/scoped_handle_win.h b/base/scoped_handle_win.h index a98114b..09bb2cb 100644 --- a/base/scoped_handle_win.h +++ b/base/scoped_handle_win.h @@ -4,14 +4,13 @@ // TODO(brettw) remove this file when all callers are converted to using the // new location/namespace -#include "base/win/scoped_handle.h" #include "base/win/scoped_gdi_object.h" #include "base/win/scoped_handle.h" +#include "base/win/scoped_handle.h" #include "base/win/scoped_hdc.h" #include "base/win/scoped_hglobal.h" using base::win::ScopedBitmap; -using base::win::ScopedGDIObject; using base::win::ScopedHandle; using base::win::ScopedHDC; using base::win::ScopedHFONT; diff --git a/base/scoped_variant_win.h b/base/scoped_variant_win.h deleted file mode 100644 index 3d6b650..0000000 --- a/base/scoped_variant_win.h +++ /dev/null @@ -1,9 +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. - -// TODO(brettw) remove this file when all callers are converted to using the -// new location/namespace -#include "base/win/scoped_variant.h" - -using base::win::ScopedVariant; diff --git a/base/singleton.h b/base/singleton.h index 8435c43..e5713c4 100644 --- a/base/singleton.h +++ b/base/singleton.h @@ -114,7 +114,6 @@ template <typename Type> intptr_t template <typename Type> base::subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0; - // The Singleton<Type, Traits, DifferentiatingType> class manages a single // instance of Type which will be created on first use and will be destroyed at // normal process exit). The Trait::Delete function will not be called on @@ -124,15 +123,37 @@ template <typename Type> base::subtle::Atomic32 // singletons having the same memory allocation functions but serving a // different purpose. This is mainly used for Locks serving different purposes. // -// Example usages: (none are preferred, they all result in the same code) -// 1. FooClass* ptr = Singleton<FooClass>::get(); -// ptr->Bar(); -// 2. Singleton<FooClass>()->Bar(); -// 3. Singleton<FooClass>::get()->Bar(); +// Example usage: +// +// In your header: +// #include "base/singleton.h" +// class FooClass { +// public: +// static FooClass* GetInstance(); <-- See comment below on this. +// void Bar() { ... } +// private: +// FooClass() { ... } +// friend struct DefaultSingletonTraits<FooClass>; +// +// DISALLOW_COPY_AND_ASSIGN(FooClass); +// }; +// +// In your source file: +// FooClass* FooClass::GetInstance() { +// return Singleton<FooClass>::get(); +// } +// +// And to call methods on FooClass: +// FooClass::GetInstance()->Bar(); +// +// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance +// and it is important that FooClass::GetInstance() is not inlined in the +// header. This makes sure that when source files from multiple targets include +// this header they don't end up with different copies of the inlined code +// creating multiple copies of the singleton. // // Singleton<> has no non-static members and doesn't need to actually be -// instantiated. It does no harm to instantiate it and use it as a class member -// or at global level since it is acting as a POD type. +// instantiated. // // This class is itself thread-safe. The underlying Type must of course be // thread-safe if you want to use it concurrently. Two parameters may be tuned @@ -152,20 +173,6 @@ template <typename Type> base::subtle::Atomic32 // shouldn't be false unless absolutely necessary. Remember that the heap where // the object is allocated may be destroyed by the CRT anyway. // -// If you want to ensure that your class can only exist as a singleton, make -// its constructors private, and make DefaultSingletonTraits<> a friend: -// -// #include "base/singleton.h" -// class FooClass { -// public: -// void Bar() { ... } -// private: -// FooClass() { ... } -// friend struct DefaultSingletonTraits<FooClass>; -// -// DISALLOW_COPY_AND_ASSIGN(FooClass); -// }; -// // Caveats: // (a) Every call to get(), operator->() and operator*() incurs some overhead // (16ns on my P4/2.8GHz) to check whether the object has already been @@ -179,7 +186,11 @@ template <typename Type, typename Traits = DefaultSingletonTraits<Type>, typename DifferentiatingType = Type> class Singleton { - public: + private: + // Classes using the Singleton<T> pattern should declare a GetInstance() + // method and call Singleton::get() from within that. + friend Type* Type::GetInstance(); + // This class is safe to be constructed and copy-constructed since it has no // member. @@ -240,16 +251,6 @@ class Singleton { return reinterpret_cast<Type*>(value); } - // Shortcuts. - Type& operator*() { - return *get(); - } - - Type* operator->() { - return get(); - } - - private: // Adapter function for use with AtExit(). This should be called single // threaded, so don't use atomic operations. // Calling OnExit while singleton is in use by other threads is a mistake. diff --git a/base/singleton_unittest.cc b/base/singleton_unittest.cc index acb1247..3d7e7e6 100644 --- a/base/singleton_unittest.cc +++ b/base/singleton_unittest.cc @@ -12,87 +12,131 @@ namespace { COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a); -template<typename Type> -struct LockTrait : public DefaultSingletonTraits<Type> { -}; +typedef void (*CallbackFunc)(); -struct Init5Trait : public DefaultSingletonTraits<int> { - static int* New() { - return new int(5); +class IntSingleton { + public: + static IntSingleton* GetInstance() { + return Singleton<IntSingleton>::get(); } + + int value_; }; -typedef void (*CallbackFunc)(); +class Init5Singleton { + public: + struct Trait; -struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> { - static void Delete(CallbackFunc* p) { - if (*p) - (*p)(); - DefaultSingletonTraits<CallbackFunc>::Delete(p); + static Init5Singleton* GetInstance() { + return Singleton<Init5Singleton, Trait>::get(); } + + int value_; }; -struct StaticCallbackTrait : public StaticMemorySingletonTraits<CallbackFunc> { - static void Delete(CallbackFunc* p) { - if (*p) - (*p)(); - StaticMemorySingletonTraits<CallbackFunc>::Delete(p); +struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> { + static Init5Singleton* New() { + Init5Singleton* instance = new Init5Singleton(); + instance->value_ = 5; + return instance; } }; +int* SingletonInt() { + return &IntSingleton::GetInstance()->value_; +} + +int* SingletonInt5() { + return &Init5Singleton::GetInstance()->value_; +} -struct NoLeakTrait : public CallbackTrait { +template <typename Type> +struct CallbackTrait : public DefaultSingletonTraits<Type> { + static void Delete(Type* instance) { + if (instance->callback_) + (instance->callback_)(); + DefaultSingletonTraits<Type>::Delete(instance); + } }; -struct LeakTrait : public CallbackTrait { - static const bool kRegisterAtExit = false; +class CallbackSingleton { + public: + CallbackSingleton() : callback_(NULL) { } + CallbackFunc callback_; }; -int* SingletonInt1() { - return Singleton<int>::get(); -} +class CallbackSingletonWithNoLeakTrait : public CallbackSingleton { + public: + struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { }; -int* SingletonInt2() { - // Force to use a different singleton than SingletonInt1. - return Singleton<int, DefaultSingletonTraits<int> >::get(); -} + CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { } -class DummyDifferentiatingClass { + static CallbackSingletonWithNoLeakTrait* GetInstance() { + return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get(); + } }; -int* SingletonInt3() { - // Force to use a different singleton than SingletonInt1 and SingletonInt2. - // Note that any type can be used; int, float, std::wstring... - return Singleton<int, DefaultSingletonTraits<int>, - DummyDifferentiatingClass>::get(); -} +class CallbackSingletonWithLeakTrait : public CallbackSingleton { + public: + struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> { + static const bool kRegisterAtExit = false; + }; -int* SingletonInt4() { - return Singleton<int, LockTrait<int> >::get(); -} + CallbackSingletonWithLeakTrait() : CallbackSingleton() { } + + static CallbackSingletonWithLeakTrait* GetInstance() { + return Singleton<CallbackSingletonWithLeakTrait, Trait>::get(); + } +}; + +class CallbackSingletonWithStaticTrait : public CallbackSingleton { + public: + struct Trait; + + CallbackSingletonWithStaticTrait() : CallbackSingleton() { } + + static CallbackSingletonWithStaticTrait* GetInstance() { + return Singleton<CallbackSingletonWithStaticTrait, Trait>::get(); + } +}; + +struct CallbackSingletonWithStaticTrait::Trait + : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> { + static void Delete(CallbackSingletonWithStaticTrait* instance) { + if (instance->callback_) + (instance->callback_)(); + StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete( + instance); + } +}; -int* SingletonInt5() { - return Singleton<int, Init5Trait>::get(); -} void SingletonNoLeak(CallbackFunc CallOnQuit) { - *Singleton<CallbackFunc, NoLeakTrait>::get() = CallOnQuit; + CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit; } void SingletonLeak(CallbackFunc CallOnQuit) { - *Singleton<CallbackFunc, LeakTrait>::get() = CallOnQuit; + CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit; } CallbackFunc* GetLeakySingleton() { - return Singleton<CallbackFunc, LeakTrait>::get(); + return &CallbackSingletonWithLeakTrait::GetInstance()->callback_; +} + +void DeleteLeakySingleton() { + DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete( + CallbackSingletonWithLeakTrait::GetInstance()); } void SingletonStatic(CallbackFunc CallOnQuit) { - *Singleton<CallbackFunc, StaticCallbackTrait>::get() = CallOnQuit; + CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit; } CallbackFunc* GetStaticSingleton() { - return Singleton<CallbackFunc, StaticCallbackTrait>::get(); + return &CallbackSingletonWithStaticTrait::GetInstance()->callback_; +} + +void ResurrectStaticSingleton() { } } // namespace @@ -149,10 +193,7 @@ bool SingletonTest::leaky_called_ = false; bool SingletonTest::static_called_ = false; TEST_F(SingletonTest, Basic) { - int* singleton_int_1; - int* singleton_int_2; - int* singleton_int_3; - int* singleton_int_4; + int* singleton_int; int* singleton_int_5; CallbackFunc* leaky_singleton; CallbackFunc* static_singleton; @@ -160,49 +201,20 @@ TEST_F(SingletonTest, Basic) { { base::ShadowingAtExitManager sem; { - singleton_int_1 = SingletonInt1(); + singleton_int = SingletonInt(); } // Ensure POD type initialization. - EXPECT_EQ(*singleton_int_1, 0); - *singleton_int_1 = 1; - - EXPECT_EQ(singleton_int_1, SingletonInt1()); - EXPECT_EQ(*singleton_int_1, 1); - - { - singleton_int_2 = SingletonInt2(); - } - // Same instance that 1. - EXPECT_EQ(*singleton_int_2, 1); - EXPECT_EQ(singleton_int_1, singleton_int_2); + EXPECT_EQ(*singleton_int, 0); + *singleton_int = 1; - { - singleton_int_3 = SingletonInt3(); - } - // Different instance than 1 and 2. - EXPECT_EQ(*singleton_int_3, 0); - EXPECT_NE(singleton_int_1, singleton_int_3); - *singleton_int_3 = 3; - EXPECT_EQ(*singleton_int_1, 1); - EXPECT_EQ(*singleton_int_2, 1); - - { - singleton_int_4 = SingletonInt4(); - } - // Use a lock for creation. Not really tested at length. - EXPECT_EQ(*singleton_int_4, 0); - *singleton_int_4 = 4; - EXPECT_NE(singleton_int_1, singleton_int_4); - EXPECT_NE(singleton_int_3, singleton_int_4); + EXPECT_EQ(singleton_int, SingletonInt()); + EXPECT_EQ(*singleton_int, 1); { singleton_int_5 = SingletonInt5(); } // Is default initialized to 5. EXPECT_EQ(*singleton_int_5, 5); - EXPECT_NE(singleton_int_1, singleton_int_5); - EXPECT_NE(singleton_int_3, singleton_int_5); - EXPECT_NE(singleton_int_4, singleton_int_5); SingletonNoLeak(&CallbackNoLeak); SingletonLeak(&CallbackLeak); @@ -216,7 +228,7 @@ TEST_F(SingletonTest, Basic) { VerifiesCallbacks(); // Delete the leaky singleton. It is interesting to note that Purify does // *not* detect the leak when this call is commented out. :( - DefaultSingletonTraits<CallbackFunc>::Delete(leaky_singleton); + DeleteLeakySingleton(); // The static singleton can't be acquired post-atexit. EXPECT_EQ(NULL, GetStaticSingleton()); @@ -225,8 +237,8 @@ TEST_F(SingletonTest, Basic) { base::ShadowingAtExitManager sem; // Verifiy that the variables were reset. { - singleton_int_1 = SingletonInt1(); - EXPECT_EQ(*singleton_int_1, 0); + singleton_int = SingletonInt(); + EXPECT_EQ(*singleton_int, 0); } { singleton_int_5 = SingletonInt5(); @@ -235,7 +247,7 @@ TEST_F(SingletonTest, Basic) { { // Resurrect the static singleton, and assert that it // still points to the same (static) memory. - StaticMemorySingletonTraits<CallbackFunc>::Resurrect(); + CallbackSingletonWithStaticTrait::Trait::Resurrect(); EXPECT_EQ(GetStaticSingleton(), static_singleton); } } diff --git a/base/string_util.cc b/base/string_util.cc index 1c97487..0e0f17b 100644 --- a/base/string_util.cc +++ b/base/string_util.cc @@ -38,6 +38,10 @@ struct EmptyStrings { const std::string s; const std::wstring ws; const string16 s16; + + static EmptyStrings* GetInstance() { + return Singleton<EmptyStrings>::get(); + } }; // Used by ReplaceStringPlaceholders to track the position in the string of @@ -102,15 +106,15 @@ bool IsWprintfFormatPortable(const wchar_t* format) { const std::string& EmptyString() { - return Singleton<EmptyStrings>::get()->s; + return EmptyStrings::GetInstance()->s; } const std::wstring& EmptyWString() { - return Singleton<EmptyStrings>::get()->ws; + return EmptyStrings::GetInstance()->ws; } const string16& EmptyString16() { - return Singleton<EmptyStrings>::get()->s16; + return EmptyStrings::GetInstance()->s16; } #define WHITESPACE_UNICODE \ @@ -1094,40 +1098,3 @@ size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { return lcpyT<wchar_t>(dst, src, dst_size); } - -bool ElideString(const std::wstring& input, int max_len, std::wstring* output) { - DCHECK(max_len >= 0); - if (static_cast<int>(input.length()) <= max_len) { - output->assign(input); - return false; - } - - switch (max_len) { - case 0: - output->clear(); - break; - case 1: - output->assign(input.substr(0, 1)); - break; - case 2: - output->assign(input.substr(0, 2)); - break; - case 3: - output->assign(input.substr(0, 1) + L"." + - input.substr(input.length() - 1)); - break; - case 4: - output->assign(input.substr(0, 1) + L".." + - input.substr(input.length() - 1)); - break; - default: { - int rstr_len = (max_len - 3) / 2; - int lstr_len = rstr_len + ((max_len - 3) % 2); - output->assign(input.substr(0, lstr_len) + L"..." + - input.substr(input.length() - rstr_len)); - break; - } - } - - return true; -} diff --git a/base/string_util.h b/base/string_util.h index 498ccc5..f65652c 100644 --- a/base/string_util.h +++ b/base/string_util.h @@ -523,14 +523,6 @@ string16 ReplaceStringPlaceholders(const string16& format_string, const string16& a, size_t* offset); -// If the size of |input| is more than |max_len|, this function returns true and -// |input| is shortened into |output| by removing chars in the middle (they are -// replaced with up to 3 dots, as size permits). -// Ex: ElideString(L"Hello", 10, &str) puts Hello in str and returns false. -// ElideString(L"Hello my name is Tom", 10, &str) puts "Hell...Tom" in str and -// returns true. -bool ElideString(const std::wstring& input, int max_len, std::wstring* output); - // Returns true if the string passed in matches the pattern. The pattern // string can contain wildcards like * and ? // The backslash character (\) is an escape character for * and ? diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc index b7639bb..cd45642 100644 --- a/base/string_util_unittest.cc +++ b/base/string_util_unittest.cc @@ -1056,33 +1056,6 @@ TEST(StringUtilTest, WprintfFormatPortabilityTest) { } } -TEST(StringUtilTest, ElideString) { - struct TestData { - const wchar_t* input; - int max_len; - bool result; - const wchar_t* output; - } cases[] = { - { L"Hello", 0, true, L"" }, - { L"", 0, false, L"" }, - { L"Hello, my name is Tom", 1, true, L"H" }, - { L"Hello, my name is Tom", 2, true, L"He" }, - { L"Hello, my name is Tom", 3, true, L"H.m" }, - { L"Hello, my name is Tom", 4, true, L"H..m" }, - { L"Hello, my name is Tom", 5, true, L"H...m" }, - { L"Hello, my name is Tom", 6, true, L"He...m" }, - { L"Hello, my name is Tom", 7, true, L"He...om" }, - { L"Hello, my name is Tom", 10, true, L"Hell...Tom" }, - { L"Hello, my name is Tom", 100, false, L"Hello, my name is Tom" } - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - std::wstring output; - EXPECT_EQ(cases[i].result, - ElideString(cases[i].input, cases[i].max_len, &output)); - EXPECT_TRUE(output == cases[i].output); - } -} - TEST(StringUtilTest, RemoveChars) { const char* kRemoveChars = "-/+*"; std::string input = "A-+bc/d!*"; diff --git a/base/stringprintf.h b/base/stringprintf.h index f3ca6e7..9170ddd 100644 --- a/base/stringprintf.h +++ b/base/stringprintf.h @@ -49,6 +49,5 @@ 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::StringAppendV; #endif // BASE_STRINGPRINTF_H_ diff --git a/base/task.h b/base/task.h index b21ccd8..e6e0d2d 100644 --- a/base/task.h +++ b/base/task.h @@ -149,8 +149,9 @@ class ScopedRunnableMethodFactory { : obj_(obj), meth_(meth), params_(params) { - COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), - badscopedrunnablemethodparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badscopedrunnablemethodparams); } virtual void Run() { @@ -317,8 +318,9 @@ class RunnableMethod : public CancelableTask { RunnableMethod(T* obj, Method meth, const Params& params) : obj_(obj), meth_(meth), params_(params) { traits_.RetainCallee(obj_); - COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), - badrunnablemethodparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badrunnablemethodparams); } ~RunnableMethod() { @@ -336,10 +338,10 @@ class RunnableMethod : public CancelableTask { private: void ReleaseCallee() { - if (obj_) { - traits_.ReleaseCallee(obj_); - obj_ = NULL; - } + T* obj = obj_; + obj_ = NULL; + if (obj) + traits_.ReleaseCallee(obj); } T* obj_; @@ -429,8 +431,9 @@ class RunnableFunction : public CancelableTask { public: RunnableFunction(Function function, const Params& params) : function_(function), params_(params) { - COMPILE_ASSERT((FunctionUsesScopedRefptrCorrectly<Function, Params>::value), - badrunnablefunctionparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badrunnablefunctionparams); } ~RunnableFunction() { diff --git a/base/task_unittest.cc b/base/task_unittest.cc new file mode 100644 index 0000000..cc975e0 --- /dev/null +++ b/base/task_unittest.cc @@ -0,0 +1,52 @@ +// 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/ref_counted.h" +#include "base/task.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class CancelInDestructor : public base::RefCounted<CancelInDestructor> { + public: + CancelInDestructor() : cancelable_task_(NULL) {} + + void Start() { + if (cancelable_task_) { + ADD_FAILURE(); + return; + } + AddRef(); + cancelable_task_ = NewRunnableMethod( + this, &CancelInDestructor::NeverIssuedCallback); + Release(); + } + + CancelableTask* cancelable_task() { + return cancelable_task_; + } + + private: + friend class base::RefCounted<CancelInDestructor>; + + ~CancelInDestructor() { + if (cancelable_task_) + cancelable_task_->Cancel(); + } + + void NeverIssuedCallback() { NOTREACHED(); } + + CancelableTask* cancelable_task_; +}; + +TEST(TaskTest, TestCancelInDestructor) { + // Intentionally not using a scoped_refptr for cancel_in_destructor. + CancelInDestructor* cancel_in_destructor = new CancelInDestructor(); + cancel_in_destructor->Start(); + CancelableTask* cancelable_task = cancel_in_destructor->cancelable_task(); + ASSERT_TRUE(cancelable_task); + delete cancelable_task; +} + +} // namespace diff --git a/base/template_util.h b/base/template_util.h index 2cfe04c..27bdb73 100644 --- a/base/template_util.h +++ b/base/template_util.h @@ -6,6 +6,8 @@ #define BASE_TEMPLATE_UTIL_H_ #pragma once +#include "build/build_config.h" + namespace base { // template definitions from tr1 @@ -25,6 +27,51 @@ typedef integral_constant<bool, false> false_type; template <class T> struct is_pointer : false_type {}; template <class T> struct is_pointer<T*> : true_type {}; +namespace internal { + +// Types small_ and big_ are guaranteed such that sizeof(small_) < +// sizeof(big_) +typedef char small_; + +struct big_ { + small_ dummy[2]; +}; + +#if !defined(OS_WIN) + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +template <typename From, typename To> +struct ConvertHelper { + static small_ Test(To); + static big_ Test(...); + static From Create(); +}; + +#endif // !defined(OS_WIN) + +} // namespace internal + +#if !defined(OS_WIN) + +// Inherits from true_type if From is convertible to To, false_type otherwise. +template <typename From, typename To> +struct is_convertible + : integral_constant<bool, + sizeof(internal::ConvertHelper<From, To>::Test( + internal::ConvertHelper<From, To>::Create())) + == sizeof(internal::small_)> { +}; + +#endif // !defined(OS_WIN) + } // namespace base #endif // BASE_TEMPLATE_UTIL_H_ diff --git a/base/test/mock_chrome_application_mac.h b/base/test/mock_chrome_application_mac.h new file mode 100644 index 0000000..e7e2c67 --- /dev/null +++ b/base/test/mock_chrome_application_mac.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_TEST_MOCK_CHROME_APPLICATION_MAC_H_ +#define BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_ +#pragma once + +#if defined(__OBJC__) + +#import <AppKit/AppKit.h> + +#include "base/message_pump_mac.h" + +// A mock implementation of CrAppProtocol that claims that -sendEvent: is never +// on the stack. This can be used in tests that need an NSApplication and use a +// runloop, but don't run nested message loops. +@interface MockCrApp : NSApplication<CrAppProtocol> +@end + +#endif + +// To be used to instantiate MockCrApp from C++ code. +namespace mock_cr_app { +void RegisterMockCrApp(); +} // namespace mock_cr_app + +#endif // BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_ diff --git a/base/test/mock_chrome_application_mac.mm b/base/test/mock_chrome_application_mac.mm new file mode 100644 index 0000000..f7010c4 --- /dev/null +++ b/base/test/mock_chrome_application_mac.mm @@ -0,0 +1,19 @@ +// 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/test/mock_chrome_application_mac.h" + +@implementation MockCrApp +- (BOOL)isHandlingSendEvent { + return NO; +} +@end + +namespace mock_cr_app { + +void RegisterMockCrApp() { + [MockCrApp sharedApplication]; +} + +} // namespace mock_cr_app diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc index 1dfd63f..991f4f3 100644 --- a/base/test/test_switches.cc +++ b/base/test/test_switches.cc @@ -10,6 +10,7 @@ const char switches::kLiveOperationTimeout[] = "live-operation-timeout"; // Time (in milliseconds) that the tests should wait before timing out. // TODO(phajdan.jr): Clean up the switch names. const char switches::kTestLargeTimeout[] = "test-large-timeout"; +const char switches::kTestTinyTimeout[] = "test-tiny-timeout"; const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout"; const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout"; const char switches::kUiTestCommandExecutionTimeout[] = "ui-test-timeout"; diff --git a/base/test/test_switches.h b/base/test/test_switches.h index 2194596..44ebd23 100644 --- a/base/test/test_switches.h +++ b/base/test/test_switches.h @@ -11,6 +11,7 @@ namespace switches { // alongside the definition of their values in the .cc file. extern const char kLiveOperationTimeout[]; extern const char kTestLargeTimeout[]; +extern const char kTestTinyTimeout[]; extern const char kUiTestActionTimeout[]; extern const char kUiTestActionMaxTimeout[]; extern const char kUiTestCommandExecutionTimeout[]; diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc index 7ee1b70..046f320 100644 --- a/base/test/test_timeouts.cc +++ b/base/test/test_timeouts.cc @@ -42,6 +42,7 @@ bool TestTimeouts::initialized_ = false; // The timeout values should increase in the order they appear in this block. // static +int TestTimeouts::tiny_timeout_ms_ = 100; int TestTimeouts::action_timeout_ms_ = 2000; int TestTimeouts::action_max_timeout_ms_ = 15000; int TestTimeouts::large_test_timeout_ms_ = 3 * 60 * 1000; @@ -66,7 +67,9 @@ void TestTimeouts::Initialize() { // Note that these timeouts MUST be initialized in the correct order as // per the CHECKS below. - InitializeTimeout(switches::kUiTestActionTimeout, &action_timeout_ms_); + InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_); + InitializeTimeout(switches::kUiTestActionTimeout, tiny_timeout_ms_, + &action_timeout_ms_); InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_, &action_max_timeout_ms_); InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_, @@ -75,6 +78,7 @@ void TestTimeouts::Initialize() { &huge_test_timeout_ms_); // The timeout values should be increasing in the right order. + CHECK(tiny_timeout_ms_ <= action_timeout_ms_); CHECK(action_timeout_ms_ <= action_max_timeout_ms_); CHECK(action_max_timeout_ms_ <= large_test_timeout_ms_); CHECK(large_test_timeout_ms_ <= huge_test_timeout_ms_); diff --git a/base/test/test_timeouts.h b/base/test/test_timeouts.h index d49ca2c..f4cb1ff 100644 --- a/base/test/test_timeouts.h +++ b/base/test/test_timeouts.h @@ -15,6 +15,9 @@ class TestTimeouts { // by the test suite. static void Initialize(); + // Timeout for actions that are expected to finish "almost instantly". + static int tiny_timeout_ms() { return tiny_timeout_ms_; } + // Timeout to wait for something to happen. If you are not sure // which timeout to use, this is the one you want. static int action_timeout_ms() { return action_timeout_ms_; } @@ -52,6 +55,7 @@ class TestTimeouts { private: static bool initialized_; + static int tiny_timeout_ms_; static int action_timeout_ms_; static int action_max_timeout_ms_; static int large_test_timeout_ms_; diff --git a/base/third_party/nspr/prcpucfg.h b/base/third_party/nspr/prcpucfg.h index 8651edd..95c2c0a 100644 --- a/base/third_party/nspr/prcpucfg.h +++ b/base/third_party/nspr/prcpucfg.h @@ -34,7 +34,11 @@ #include "base/third_party/nspr/prcpucfg_win.h" #elif defined(__APPLE__) #include "base/third_party/nspr/prcpucfg_mac.h" +<<<<<<< HEAD #elif defined(__linux__) || defined(ANDROID) +======= +#elif defined(__linux__) || defined(__native_client__) +>>>>>>> chromium.org at r10.0.621.0 #include "base/third_party/nspr/prcpucfg_linux.h" #elif defined(__FreeBSD__) #include "base/third_party/nspr/prcpucfg_freebsd.h" diff --git a/base/time_win.cc b/base/time_win.cc index 5d3ecd6..ca3aef1 100644 --- a/base/time_win.cc +++ b/base/time_win.cc @@ -310,16 +310,8 @@ TimeDelta RolloverProtectedNow() { // retrieve and more reliable. class HighResNowSingleton { public: - HighResNowSingleton() - : ticks_per_microsecond_(0.0), - skew_(0) { - InitializeClock(); - - // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is - // unreliable. Fallback to low-res clock. - base::CPU cpu; - if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) - DisableHighResClock(); + static HighResNowSingleton* GetInstance() { + return Singleton<HighResNowSingleton>::get(); } bool IsUsingHighResClock() { @@ -346,6 +338,18 @@ class HighResNowSingleton { } private: + HighResNowSingleton() + : ticks_per_microsecond_(0.0), + skew_(0) { + InitializeClock(); + + // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is + // unreliable. Fallback to low-res clock. + base::CPU cpu; + if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) + DisableHighResClock(); + } + // Synchronize the QPC clock with GetSystemTimeAsFileTime. void InitializeClock() { LARGE_INTEGER ticks_per_sec = {0}; @@ -374,7 +378,7 @@ class HighResNowSingleton { float ticks_per_microsecond_; // 0 indicates QPF failed and we're broken. int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). - DISALLOW_COPY_AND_ASSIGN(HighResNowSingleton); + friend struct DefaultSingletonTraits<HighResNowSingleton>; }; } // namespace @@ -394,15 +398,15 @@ TimeTicks TimeTicks::Now() { // static TimeTicks TimeTicks::HighResNow() { - return TimeTicks() + Singleton<HighResNowSingleton>::get()->Now(); + return TimeTicks() + HighResNowSingleton::GetInstance()->Now(); } // static int64 TimeTicks::GetQPCDriftMicroseconds() { - return Singleton<HighResNowSingleton>::get()->GetQPCDriftMicroseconds(); + return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds(); } // static bool TimeTicks::IsHighResClockWorking() { - return Singleton<HighResNowSingleton>::get()->IsUsingHighResClock(); + return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); }
\ No newline at end of file diff --git a/base/tuple.h b/base/tuple.h index bfe6562..6b0d336 100644 --- a/base/tuple.h +++ b/base/tuple.h @@ -30,6 +30,10 @@ #define BASE_TUPLE_H__ #pragma once +#if defined(OS_CHROMEOS) +// To troubleshoot crosbug.com/7327. +#include "base/logging.h" +#endif // Traits ---------------------------------------------------------------------- // // A simple traits class for tuple arguments. @@ -545,7 +549,7 @@ inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) { template <class ObjT, class Method, class A> inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) { -#if defined(OS_CHROMEOS) && defined(CHECK) +#if defined(OS_CHROMEOS) // To troubleshoot crosbug.com/7327. CHECK(obj); CHECK(&arg); diff --git a/base/unix_domain_socket_posix.cc b/base/unix_domain_socket_posix.cc deleted file mode 100644 index 73fa260..0000000 --- a/base/unix_domain_socket_posix.cc +++ /dev/null @@ -1,143 +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/unix_domain_socket_posix.h" - -#include <errno.h> -#include <unistd.h> -#include <sys/uio.h> -#include <sys/socket.h> - -#include "base/eintr_wrapper.h" -#include "base/logging.h" -#include "base/pickle.h" - -namespace base { - -bool SendMsg(int fd, const void* buf, size_t length, - const std::vector<int>& fds) { - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - struct iovec iov = {const_cast<void*>(buf), length}; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - char* control_buffer = NULL; - if (fds.size()) { - const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size()); - control_buffer = new char[control_len]; - - struct cmsghdr *cmsg; - msg.msg_control = control_buffer; - msg.msg_controllen = control_len; - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size()); - memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size()); - msg.msg_controllen = cmsg->cmsg_len; - } - - const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, 0)); - const bool ret = static_cast<ssize_t>(length) == r; - delete[] control_buffer; - return ret; -} - -ssize_t RecvMsg(int fd, void* buf, size_t length, std::vector<int>* fds) { - static const unsigned kMaxDescriptors = 16; - - fds->clear(); - - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - struct iovec iov = {buf, length}; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - char control_buffer[CMSG_SPACE(sizeof(int) * kMaxDescriptors)]; - msg.msg_control = control_buffer; - msg.msg_controllen = sizeof(control_buffer); - - const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, 0)); - if (r == -1) - return -1; - - int* wire_fds = NULL; - unsigned wire_fds_len = 0; - - if (msg.msg_controllen > 0) { - struct cmsghdr* cmsg; - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); - DCHECK(payload_len % sizeof(int) == 0); - wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); - wire_fds_len = payload_len / sizeof(int); - break; - } - } - } - - if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) { - for (unsigned i = 0; i < wire_fds_len; ++i) - close(wire_fds[i]); - errno = EMSGSIZE; - return -1; - } - - fds->resize(wire_fds_len); - memcpy(&(*fds)[0], wire_fds, sizeof(int) * wire_fds_len); - - return r; -} - -ssize_t SendRecvMsg(int fd, uint8_t* reply, unsigned max_reply_len, int* result_fd, - const Pickle& request) { - int fds[2]; - - // This socketpair is only used for the IPC and is cleaned up before - // returning. - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == -1) - return false; - - std::vector<int> fd_vector; - fd_vector.push_back(fds[1]); - if (!SendMsg(fd, request.data(), request.size(), fd_vector)) { - close(fds[0]); - close(fds[1]); - return -1; - } - close(fds[1]); - - fd_vector.clear(); - const ssize_t reply_len = RecvMsg(fds[0], reply, max_reply_len, &fd_vector); - close(fds[0]); - if (reply_len == -1) - return -1; - - if ((fd_vector.size() > 0 && result_fd == NULL) || fd_vector.size() > 1) { - for (std::vector<int>::const_iterator - i = fd_vector.begin(); i != fd_vector.end(); ++i) { - close(*i); - } - - NOTREACHED(); - - return -1; - } - - if (result_fd) { - if (fd_vector.size() == 0) { - *result_fd = -1; - } else { - *result_fd = fd_vector[0]; - } - } - - return reply_len; -} - -} // namespace base diff --git a/base/unix_domain_socket_posix.h b/base/unix_domain_socket_posix.h deleted file mode 100644 index 51c821b..0000000 --- a/base/unix_domain_socket_posix.h +++ /dev/null @@ -1,43 +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. - -#ifndef BASE_UNIX_DOMAIN_SOCKET_POSIX_H_ -#define BASE_UNIX_DOMAIN_SOCKET_POSIX_H_ -#pragma once - -#include <stdint.h> -#include <sys/types.h> -#include <vector> - -class Pickle; - -namespace base { - -// Use sendmsg to write the given msg and include a vector -// of file descriptors. Returns true iff successful. -bool SendMsg(int fd, const void* msg, size_t length, - const std::vector<int>& fds); -// Use recvmsg to read a message and an array of file descriptors. Returns -// -1 on failure. Note: will read, at most, 16 descriptors. -ssize_t RecvMsg(int fd, void* msg, size_t length, std::vector<int>* fds); -// Perform a sendmsg/recvmsg pair. -// 1. This process creates a UNIX DGRAM socketpair. -// 2. This proces writes a request to |fd| with an SCM_RIGHTS control message -// containing on end of the fresh socket pair. -// 3. This process blocks reading from the other end of the fresh socketpair. -// 4. The target process receives the request, processes it and writes the -// reply to the end of the socketpair contained in the request. -// 5. This process wakes up and continues. -// -// fd: descriptor to send the request on -// reply: buffer for the reply -// reply_len: size of |reply| -// result_fd: (may be NULL) the file descriptor returned in the reply (if any) -// request: the bytes to send in the request -ssize_t SendRecvMsg(int fd, uint8_t* reply, unsigned reply_len, int* result_fd, - const Pickle& request); - -} // namespace base - -#endif // BASE_UNIX_DOMAIN_SOCKET_POSIX_H_ diff --git a/base/values.cc b/base/values.cc index cd0f6a8..4553e68 100644 --- a/base/values.cc +++ b/base/values.cc @@ -119,6 +119,10 @@ bool Value::GetAsString(string16* out_value) const { return false; } +bool Value::GetAsList(ListValue** out_value) { + return false; +} + Value* Value::DeepCopy() const { // This method should only be getting called for null Values--all subclasses // need to provide their own implementation;. @@ -133,6 +137,13 @@ bool Value::Equals(const Value* other) const { return other->IsType(TYPE_NULL); } +// static +bool Value::Equals(const Value* a, const Value* b) { + if ((a == NULL) && (b == NULL)) return true; + if ((a == NULL) ^ (b == NULL)) return false; + return a->Equals(b); +} + Value::Value(ValueType type) : type_(type) { } @@ -674,114 +685,6 @@ void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) { } } -bool DictionaryValue::GetDifferingPathsHelper( - const std::string& path_prefix, - const DictionaryValue* other, - std::vector<std::string>* different_paths) const { - bool added_path = false; - std::map<std::string, Value*>::const_iterator current_this; - std::map<std::string, Value*>::const_iterator end_this; - current_this = dictionary_.begin(); - end_this = dictionary_.end(); - if (!other) { - // Recursively add all paths from the |this| dictionary, since they are - // not in |other|. - for (; current_this != end_this; ++current_this) { - std::string full_path_for_key(path_prefix.empty() ? current_this->first : - path_prefix + "." + current_this->first); - different_paths->push_back(full_path_for_key); - added_path = true; - if (current_this->second->IsType(Value::TYPE_DICTIONARY)) { - const DictionaryValue* dictionary_this = - static_cast<const DictionaryValue*>(current_this->second); - dictionary_this->GetDifferingPathsHelper(full_path_for_key, - NULL, - different_paths); - } - } - } else { - // Both the |this| and |other| dictionaries have entries. Iterate over - // both simultaneously. Paths that are in one but not the other are - // added to |different_paths| and DictionaryValues are processed - // recursively. - std::map<std::string, Value*>::const_iterator current_other = - other->dictionary_.begin(); - std::map<std::string, Value*>::const_iterator end_other = - other->dictionary_.end(); - while (current_this != end_this || current_other != end_other) { - const Value* recursion_this = NULL; - const Value* recursion_other = NULL; - const std::string* key_name = NULL; - bool current_value_known_equal = false; - if (current_this == end_this || - (current_other != end_other && - (current_other->first < current_this->first))) { - key_name = ¤t_other->first; - if (current_other->second->IsType(Value::TYPE_DICTIONARY)) - recursion_this = current_other->second; - ++current_other; - } else { - key_name = ¤t_this->first; - if (current_other == end_other || - current_this->first < current_other->first) { - if (current_this->second->IsType(Value::TYPE_DICTIONARY)) - recursion_this = current_this->second; - ++current_this; - } else { - DCHECK(current_this->first == current_other->first); - if (current_this->second->IsType(Value::TYPE_DICTIONARY)) { - recursion_this = current_this->second; - if (current_other->second->IsType(Value::TYPE_DICTIONARY)) { - recursion_other = current_other->second; - } - } else { - if (current_other->second->IsType(Value::TYPE_DICTIONARY)) { - recursion_this = current_other->second; - } else { - current_value_known_equal = - current_this->second->Equals(current_other->second); - } - } - ++current_this; - ++current_other; - } - } - const std::string& full_path_for_key(path_prefix.empty() ? - *key_name : path_prefix + "." + *key_name); - if (!current_value_known_equal) - different_paths->push_back(full_path_for_key); - if (recursion_this) { - const DictionaryValue* dictionary_this = - static_cast<const DictionaryValue*>(recursion_this); - bool subtree_changed = dictionary_this->GetDifferingPathsHelper( - full_path_for_key, - static_cast<const DictionaryValue*>(recursion_other), - different_paths); - if (subtree_changed) { - added_path = true; - } else { - // In order to maintain lexicographical sorting order, directory - // paths are pushed "optimistically" assuming that their subtree will - // contain differences. If in retrospect there were no differences - // in the subtree, the assumption was false and the dictionary path - // must be removed. - different_paths->pop_back(); - } - } else { - added_path |= !current_value_known_equal; - } - } - } - return added_path; -} - -void DictionaryValue::GetDifferingPaths( - const DictionaryValue* other, - std::vector<std::string>* different_paths) const { - different_paths->clear(); - GetDifferingPathsHelper("", other, different_paths); -} - ///////////////////// ListValue //////////////////// ListValue::ListValue() : Value(TYPE_LIST) { @@ -954,6 +857,12 @@ bool ListValue::Insert(size_t index, Value* in_value) { return true; } +bool ListValue::GetAsList(ListValue** out_value) { + if (out_value) + *out_value = this; + return true; +} + Value* ListValue::DeepCopy() const { ListValue* result = new ListValue; diff --git a/base/values.h b/base/values.h index 07d4985..2719d27 100644 --- a/base/values.h +++ b/base/values.h @@ -92,6 +92,7 @@ class Value { virtual bool GetAsReal(double* out_value) const; virtual bool GetAsString(std::string* out_value) const; virtual bool GetAsString(string16* out_value) const; + virtual bool GetAsList(ListValue** out_value); // This creates a deep copy of the entire Value tree, and returns a pointer // to the copy. The caller gets ownership of the copy, of course. @@ -100,6 +101,10 @@ class Value { // Compares if two Value objects have equal contents. virtual bool Equals(const Value* other) const; + // Compares if two Value objects have equal contents. Can handle NULLs. + // NULLs are considered equal but different from Value::CreateNullValue(). + static bool Equals(const Value* a, const Value* b); + protected: // This isn't safe for end-users (they should use the Create*Value() // static methods above), but it's useful for subclasses. @@ -119,7 +124,7 @@ class FundamentalValue : public Value { explicit FundamentalValue(bool in_value); explicit FundamentalValue(int in_value); explicit FundamentalValue(double in_value); - ~FundamentalValue(); + virtual ~FundamentalValue(); // Subclassed methods virtual bool GetAsBoolean(bool* out_value) const; @@ -146,12 +151,12 @@ class StringValue : public Value { // Initializes a StringValue with a string16. explicit StringValue(const string16& in_value); - ~StringValue(); + virtual ~StringValue(); // Subclassed methods - bool GetAsString(std::string* out_value) const; - bool GetAsString(string16* out_value) const; - Value* DeepCopy() const; + virtual bool GetAsString(std::string* out_value) const; + virtual bool GetAsString(string16* out_value) const; + virtual Value* DeepCopy() const; virtual bool Equals(const Value* other) const; private: @@ -173,10 +178,10 @@ class BinaryValue: public Value { // Returns NULL if buffer is NULL. static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size); - ~BinaryValue(); + virtual ~BinaryValue(); // Subclassed methods - Value* DeepCopy() const; + virtual Value* DeepCopy() const; virtual bool Equals(const Value* other) const; size_t GetSize() const { return size_; } @@ -200,10 +205,10 @@ class BinaryValue: public Value { class DictionaryValue : public Value { public: DictionaryValue(); - ~DictionaryValue(); + virtual ~DictionaryValue(); // Subclassed methods - Value* DeepCopy() const; + virtual Value* DeepCopy() const; virtual bool Equals(const Value* other) const; // Returns true if the current dictionary has a value for the given key. @@ -303,16 +308,6 @@ class DictionaryValue : public Value { // replaced. void MergeDictionary(const DictionaryValue* dictionary); - // Builds a vector containing all of the paths that are different between - // the dictionary and a second specified dictionary. These are paths of - // values that are either in one dictionary or the other but not both, OR - // paths that are present in both dictionaries but differ in value. - // Path strings are in ascending lexicographical order in the generated - // vector. |different_paths| is cleared before added any paths. - void GetDifferingPaths( - const DictionaryValue* other, - std::vector<std::string>* different_paths) const; - // This class provides an iterator for the keys in the dictionary. // It can't be used to modify the dictionary. // @@ -339,17 +334,6 @@ class DictionaryValue : public Value { key_iterator end_keys() const { return key_iterator(dictionary_.end()); } private: - // Does the actual heavy lifting for GetDifferingPaths. - // Returns true if a path is added to different_paths, otherwise false. - // The difference compuation is calculated recursively. The keys for - // dictionaries that are handled by recursive calls more shallow than - // the current one are concatenated and passed through to deeper calls in - // |path_prefix|. - bool GetDifferingPathsHelper( - const std::string& path_prefix, - const DictionaryValue* other, - std::vector<std::string>* different_paths) const; - ValueMap dictionary_; DISALLOW_COPY_AND_ASSIGN(DictionaryValue); @@ -362,7 +346,8 @@ class ListValue : public Value { ~ListValue(); // Subclassed methods - Value* DeepCopy() const; + virtual bool GetAsList(ListValue** out_value); + virtual Value* DeepCopy() const; virtual bool Equals(const Value* other) const; // Clears the contents of this ListValue diff --git a/base/values_unittest.cc b/base/values_unittest.cc index 9f34c62..adcd07e 100644 --- a/base/values_unittest.cc +++ b/base/values_unittest.cc @@ -10,27 +10,7 @@ #include "base/values.h" #include "testing/gtest/include/gtest/gtest.h" -class ValuesTest: public testing::Test { - protected: - void CompareDictionariesAndCheckResult( - const DictionaryValue* dict1, - const DictionaryValue* dict2, - const char* expected_paths[], - size_t expected_paths_count) { - std::vector<std::string> differing_paths; - std::vector<std::string> expected_paths_vector(expected_paths, - expected_paths+expected_paths_count); - // All comparisons should be commutative, check dict1 against dict2 - // and vice-versa. - dict1->GetDifferingPaths(dict2, &differing_paths); - ASSERT_EQ(expected_paths_count, differing_paths.size()); - EXPECT_TRUE(equal(differing_paths.begin(), differing_paths.end(), - expected_paths_vector.begin())); - dict2->GetDifferingPaths(dict1, &differing_paths); - ASSERT_EQ(expected_paths_count, differing_paths.size()); - EXPECT_TRUE(equal(differing_paths.begin(), differing_paths.end(), - expected_paths_vector.begin())); - } +class ValuesTest : public testing::Test { }; TEST_F(ValuesTest, Basic) { @@ -508,6 +488,29 @@ TEST_F(ValuesTest, Equals) { EXPECT_FALSE(dv.Equals(copy.get())); } +TEST_F(ValuesTest, StaticEquals) { + scoped_ptr<Value> null1(Value::CreateNullValue()); + scoped_ptr<Value> null2(Value::CreateNullValue()); + EXPECT_TRUE(Value::Equals(null1.get(), null2.get())); + EXPECT_TRUE(Value::Equals(NULL, NULL)); + + scoped_ptr<Value> i42(Value::CreateIntegerValue(42)); + scoped_ptr<Value> j42(Value::CreateIntegerValue(42)); + scoped_ptr<Value> i17(Value::CreateIntegerValue(17)); + EXPECT_TRUE(Value::Equals(i42.get(), i42.get())); + EXPECT_TRUE(Value::Equals(j42.get(), i42.get())); + EXPECT_TRUE(Value::Equals(i42.get(), j42.get())); + EXPECT_FALSE(Value::Equals(i42.get(), i17.get())); + EXPECT_FALSE(Value::Equals(i42.get(), NULL)); + EXPECT_FALSE(Value::Equals(NULL, i42.get())); + + // NULL and Value::CreateNullValue() are intentionally different: We need + // support for NULL as a return value for "undefined" without caring for + // ownership of the pointer. + EXPECT_FALSE(Value::Equals(null1.get(), NULL)); + EXPECT_FALSE(Value::Equals(NULL, null1.get())); +} + TEST_F(ValuesTest, RemoveEmptyChildren) { scoped_ptr<DictionaryValue> root(new DictionaryValue); // Remove empty lists and dictionaries. @@ -627,114 +630,3 @@ TEST_F(ValuesTest, MergeDictionary) { EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value)); EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in. } - -TEST_F(ValuesTest, GetDifferingPaths) { - scoped_ptr<DictionaryValue> dict1(new DictionaryValue()); - scoped_ptr<DictionaryValue> dict2(new DictionaryValue()); - std::vector<std::string> differing_paths; - - // Test comparing empty dictionaries. - dict1->GetDifferingPaths(dict2.get(), &differing_paths); - EXPECT_EQ(differing_paths.size(), 0UL); - - // Compare an empty dictionary with various non-empty dictionaries. - static const char* expected_paths1[] = { - "segment1" - }; - dict1->SetString("segment1", "value1"); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths1, - arraysize(expected_paths1)); - - static const char* expected_paths2[] = { - "segment1", - "segment2", - "segment2.segment3" - }; - dict1->SetString("segment2.segment3", "value2"); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths2, - arraysize(expected_paths2)); - - static const char* expected_paths3[] = { - "segment1", - "segment2", - "segment2.segment3", - "segment4", - "segment4.segment5" - }; - dict1->SetString("segment4.segment5", "value3"); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths3, - arraysize(expected_paths3)); - - // Now various tests with two populated dictionaries. - static const char* expected_paths4[] = { - "segment1", - "segment2", - "segment2.segment3", - "segment4", - "segment4.segment5" - }; - dict2->Set("segment2", new DictionaryValue()); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths4, - arraysize(expected_paths4)); - - static const char* expected_paths5[] = { - "segment1", - "segment4", - "segment4.segment5" - }; - dict2->SetString("segment2.segment3", "value2"); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths5, - arraysize(expected_paths5)); - - dict2->SetBoolean("segment2.segment3", true); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths4, - arraysize(expected_paths4)); - - // Test two identical dictionaries. - dict2.reset(static_cast<DictionaryValue*>(dict1->DeepCopy())); - dict2->GetDifferingPaths(dict1.get(), &differing_paths); - EXPECT_EQ(differing_paths.size(), 0UL); - - // Test a deep dictionary structure. - static const char* expected_paths6[] = { - "s1", - "s1.s2", - "s1.s2.s3", - "s1.s2.s3.s4", - "s1.s2.s3.s4.s5" - }; - dict1.reset(new DictionaryValue()); - dict2.reset(new DictionaryValue()); - dict1->Set("s1.s2.s3.s4.s5", new DictionaryValue()); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths6, - arraysize(expected_paths6)); - - // Make sure disjoint dictionaries generate the right differing path list. - static const char* expected_paths7[] = { - "a", - "b", - "c", - "d" - }; - dict1.reset(new DictionaryValue()); - dict1->SetBoolean("a", true); - dict1->SetBoolean("c", true); - dict2.reset(new DictionaryValue()); - dict1->SetBoolean("b", true); - dict1->SetBoolean("d", true); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths7, - arraysize(expected_paths7)); - - // For code coverage completeness. Make sure that all branches - // that were not covered are executed. - static const char* expected_paths8[] = { - "s1", - "s1.s2" - }; - dict1.reset(new DictionaryValue()); - dict1->Set("s1.s2", new DictionaryValue()); - dict2.reset(new DictionaryValue()); - dict2->SetInteger("s1", 1); - CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths8, - arraysize(expected_paths8)); -} diff --git a/base/values_util.cc b/base/values_util.cc index 31d8e8c..fbc616b 100644 --- a/base/values_util.cc +++ b/base/values_util.cc @@ -12,3 +12,7 @@ RefCountedList::~RefCountedList() { if (list_) delete list_; } + +ListValue* RefCountedList::Get() { + return list_; +} diff --git a/base/values_util.h b/base/values_util.h index 57b35c1..1626bb5 100644 --- a/base/values_util.h +++ b/base/values_util.h @@ -15,9 +15,7 @@ class RefCountedList : public base::RefCountedThreadSafe<RefCountedList> { explicit RefCountedList(ListValue* list); virtual ~RefCountedList(); - virtual ListValue* Get() { - return list_; - } + virtual ListValue* Get(); private: ListValue* list_; diff --git a/base/version.cc b/base/version.cc index fe224eb..384be0a 100644 --- a/base/version.cc +++ b/base/version.cc @@ -4,6 +4,8 @@ #include "base/version.h" +#include <algorithm> + #include "base/logging.h" #include "base/string_number_conversions.h" #include "base/string_split.h" @@ -11,13 +13,6 @@ #include "base/utf_string_conversions.h" // static -Version* Version::GetVersionFromString(const std::wstring& version_str) { - if (!IsStringASCII(version_str)) - return NULL; - return GetVersionFromString(WideToUTF8(version_str)); -} - -// static Version* Version::GetVersionFromString(const std::string& version_str) { Version* vers = new Version(); if (vers->InitFromString(version_str)) { @@ -32,6 +27,14 @@ Version::Version() : is_valid_(false) {} Version::~Version() {} +Version* Version::Clone() const { + DCHECK(is_valid_); + Version* copy = new Version(); + copy->components_ = components_; + copy->is_valid_ = true; + return copy; +} + bool Version::Equals(const Version& that) const { DCHECK(is_valid_); DCHECK(that.is_valid_); diff --git a/base/version.h b/base/version.h index 2b182bb..2fda4ad 100644 --- a/base/version.h +++ b/base/version.h @@ -12,12 +12,14 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" +// Version represents a dotted version number, like "1.2.3.4", supporting +// parsing and comparison. +// Each component is limited to a uint16. class Version { public: // The version string must be made up of 1 or more uint16's separated // by '.'. Returns NULL if string is not in this format. // Caller is responsible for freeing the Version object once done. - static Version* GetVersionFromString(const std::wstring& version_str); static Version* GetVersionFromString(const std::string& version_str); // Exposed only so that a Version can be stored in STL containers; @@ -27,6 +29,9 @@ class Version { ~Version(); + // Creates a copy of this version. Caller takes ownership. + Version* Clone() const; + bool Equals(const Version& other) const; // Returns -1, 0, 1 for <, ==, >. diff --git a/base/waitable_event_watcher.h b/base/waitable_event_watcher.h index b6f5e9e..04aa8cf 100644 --- a/base/waitable_event_watcher.h +++ b/base/waitable_event_watcher.h @@ -145,7 +145,7 @@ class WaitableEventWatcher // --------------------------------------------------------------------------- // Implementation of MessageLoop::DestructionObserver // --------------------------------------------------------------------------- - void WillDestroyCurrentMessageLoop(); + virtual void WillDestroyCurrentMessageLoop(); MessageLoop* message_loop_; scoped_refptr<Flag> cancel_flag_; diff --git a/base/watchdog_unittest.cc b/base/watchdog_unittest.cc index 19dfe28..658a31a 100644 --- a/base/watchdog_unittest.cc +++ b/base/watchdog_unittest.cc @@ -86,7 +86,7 @@ TEST_F(WatchdogTest, AlarmTest) { // Make sure a basic alarm fires when the time has expired. TEST_F(WatchdogTest, AlarmPriorTimeTest) { - WatchdogCounter watchdog(TimeDelta::TimeDelta(), "Enabled2", true); + WatchdogCounter watchdog(TimeDelta(), "Enabled2", true); // Set a time in the past. watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2)); // It should instantly go off, but certainly in less than 5 minutes. diff --git a/base/win/registry.cc b/base/win/registry.cc index 3372cf4..f8e05a7 100644 --- a/base/win/registry.cc +++ b/base/win/registry.cc @@ -244,7 +244,7 @@ bool RegKey::OpenKey(const wchar_t* name, REGSAM access) { return (result == ERROR_SUCCESS); } -DWORD RegKey::ValueCount() { +DWORD RegKey::ValueCount() const { base::ThreadRestrictions::AssertIOAllowed(); DWORD count = 0; HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, @@ -252,7 +252,7 @@ DWORD RegKey::ValueCount() { return (result != ERROR_SUCCESS) ? 0 : count; } -bool RegKey::ReadName(int index, std::wstring* name) { +bool RegKey::ReadName(int index, std::wstring* name) const { base::ThreadRestrictions::AssertIOAllowed(); wchar_t buf[256]; DWORD bufsize = arraysize(buf); @@ -274,7 +274,7 @@ bool RegKey::ValueExists(const wchar_t* name) { } bool RegKey::ReadValue(const wchar_t* name, void* data, - DWORD* dsize, DWORD* dtype) { + DWORD* dsize, DWORD* dtype) const { base::ThreadRestrictions::AssertIOAllowed(); if (!key_) return false; @@ -283,7 +283,7 @@ bool RegKey::ReadValue(const wchar_t* name, void* data, return (result == ERROR_SUCCESS); } -bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) { +bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) const { base::ThreadRestrictions::AssertIOAllowed(); DCHECK(value); const size_t kMaxStringLength = 1024; // This is after expansion. @@ -312,7 +312,7 @@ bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) { return false; } -bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) { +bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const { DCHECK(value); DWORD type = REG_DWORD; DWORD size = sizeof(DWORD); diff --git a/base/win/registry.h b/base/win/registry.h index d1ef25b..96a2bb3 100644 --- a/base/win/registry.h +++ b/base/win/registry.h @@ -38,10 +38,10 @@ class RegKey { void Close(); - DWORD ValueCount(); + DWORD ValueCount() const; // Determine the nth value's name. - bool ReadName(int index, std::wstring* name); + bool ReadName(int index, std::wstring* name) const; // True while the key is valid. bool Valid() const { return key_ != NULL; } @@ -55,9 +55,10 @@ class RegKey { bool ValueExists(const wchar_t* name); - bool ReadValue(const wchar_t* name, void* data, DWORD* dsize, DWORD* dtype); - bool ReadValue(const wchar_t* name, std::wstring* value); - bool ReadValueDW(const wchar_t* name, DWORD* value); + bool ReadValue(const wchar_t* name, void* data, DWORD* dsize, + DWORD* dtype) const; + bool ReadValue(const wchar_t* name, std::wstring* value) const; + bool ReadValueDW(const wchar_t* name, DWORD* value) const; bool WriteValue(const wchar_t* name, const void* data, DWORD dsize, DWORD dtype); @@ -65,7 +66,7 @@ class RegKey { bool WriteValue(const wchar_t* name, DWORD value); // Starts watching the key to see if any of its values have changed. - // The key must have been opened with the KEY_NOTIFY access privelege. + // The key must have been opened with the KEY_NOTIFY access privilege. bool StartWatching(); // If StartWatching hasn't been called, always returns false. diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc index 278e976..40ccdf2 100644 --- a/base/win/scoped_variant.cc +++ b/base/win/scoped_variant.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/scoped_variant_win.h" +#include "base/win/scoped_variant.h" #include "base/logging.h" namespace base { diff --git a/base/worker_pool_mac.h b/base/worker_pool_mac.h deleted file mode 100644 index 1e86891..0000000 --- a/base/worker_pool_mac.h +++ /dev/null @@ -1,33 +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. - -#ifndef BASE_WORKER_POOL_MAC_H_ -#define BASE_WORKER_POOL_MAC_H_ -#pragma once - -#include "base/worker_pool.h" - -#import <Foundation/Foundation.h> - -// WorkerPoolObjC provides an Objective-C interface to the same WorkerPool -// used by the rest of the application. -@interface WorkerPoolObjC : NSObject - -// Returns the underlying NSOperationQueue back end that WorkerPool::PostTask -// would post tasks to. This can be used to add NSOperation subclasses -// directly to the same NSOperationQueue, by calling -[NSOperationQueue -// addOperation:]. Most Objective-C code wishing to dispatch tasks to the -// WorkerPool will find it handy to add an operation of type -// NSInvocationOperation. -+ (NSOperationQueue*)sharedOperationQueue; - -@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 deleted file mode 100644 index bbc7892..0000000 --- a/base/worker_pool_mac.mm +++ /dev/null @@ -1,205 +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/worker_pool_mac.h" - -#include "base/logging.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 -// language support for exceptions is not present. These macros interfere -// with the use of |@try| and |@catch| in Objective-C files such as this one. -// Undefine these macros here, after everything has been #included, since -// there will be no C++ uses and only Objective-C uses from this point on. -#undef try -#undef catch - -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. -size_t running_ = 0; // Operations in |Run()|. -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 { - return SingletonObjC<NSOperationQueue>::get(); -} - -@end // @implementation WorkerPoolObjC - -// TaskOperation adapts Task->Run() for use in an NSOperationQueue. -@interface TaskOperation : NSOperation { - @private - scoped_ptr<Task> task_; -} - -// Returns an autoreleased instance of TaskOperation. See -initWithTask: for -// details. -+ (id)taskOperationWithTask:(Task*)task; - -// Designated initializer. |task| is adopted as the Task* whose Run method -// this operation will call when executed. -- (id)initWithTask:(Task*)task; - -@end // @interface TaskOperation - -@implementation TaskOperation - -+ (id)taskOperationWithTask:(Task*)task { - return [[[TaskOperation alloc] initWithTask:task] autorelease]; -} - -- (id)init { - return [self initWithTask:NULL]; -} - -- (id)initWithTask:(Task*)task { - if ((self = [super init])) { - task_.reset(task); - } - return self; -} - -- (void)main { - DCHECK(task_.get()) << "-[TaskOperation main] called with no task"; - if (!task_.get()) { - return; - } - - { - AutoLock locked(lock_); - ++running_; - } - - base::mac::ScopedNSAutoreleasePool autoreleasePool; - - @try { - task_->Run(); - } @catch(NSException* exception) { - LOG(ERROR) << "-[TaskOperation main] caught an NSException: " - << [[exception description] UTF8String]; - } @catch(id exception) { - LOG(ERROR) << "-[TaskOperation main] caught an unknown exception"; - } - - task_.reset(NULL); - - { - AutoLock locked(lock_); - --running_; - --outstanding_; - } -} - -- (void)dealloc { - // Getting the task_ contents without a lock can lead to a benign data race. - // We annotate it to stay silent under ThreadSanitizer. - ANNOTATE_IGNORE_READS_BEGIN(); - DCHECK(!task_.get()) - << "-[TaskOperation dealloc] called without running task"; - ANNOTATE_IGNORE_READS_END(); - [super dealloc]; -} - -@end // @implementation TaskOperation - -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 - // an NSOperation. - - DCHECK(task) << "WorkerPool::PostTask called with no task"; - if (!task) { - return false; - } - - task->SetBirthPlace(from_here); - - NSOperationQueue* operation_queue = [WorkerPoolObjC sharedOperationQueue]; - [operation_queue addOperation:[TaskOperation taskOperationWithTask:task]]; - - if ([operation_queue isSuspended]) { - LOG(WARNING) << "WorkerPool::PostTask freeing stuck NSOperationQueue"; - - // Nothing should ever be suspending this queue, but in case it winds up - // happening, free things up. This is a purely speculative shot in the - // dark for http://crbug.com/20471. - [operation_queue setSuspended:NO]; - } - - // Periodically calculate the set of operations which have not made - // progress and report how many there are. This should provide a - // sense of how many clients are seeing hung operations of any sort, - // and a sense of how many clients are seeing "too many" hung - // operations. - std::vector<id> hung_ops; - size_t outstanding_delta = 0; - size_t running_ops = 0; - { - const base::TimeDelta kCheckPeriod(base::TimeDelta::FromMinutes(10)); - base::Time now = base::Time::Now(); - - AutoLock locked(lock_); - ++outstanding_; - running_ops = running_; - if (last_check_.is_null() || now - last_check_ > kCheckPeriod) { - base::mac::ScopedNSAutoreleasePool autoreleasePool; - std::vector<id> ops; - for (id op in [operation_queue operations]) { - // DO NOT RETAIN. - ops.push_back(op); - } - std::sort(ops.begin(), ops.end()); - - outstanding_delta = outstanding_ - ops.size(); - - std::set_intersection(outstanding_ops_.begin(), outstanding_ops_.end(), - ops.begin(), ops.end(), - std::back_inserter(hung_ops)); - - outstanding_ops_.swap(ops); - last_check_ = now; - } - } - - // Don't report "nothing to report". - const size_t kUnaccountedOpsDelta = 10; - if (hung_ops.size() > 0 || outstanding_delta > kUnaccountedOpsDelta) { - UMA_HISTOGRAM_COUNTS_100("OSX.HungWorkers", hung_ops.size()); - UMA_HISTOGRAM_COUNTS_100("OSX.OutstandingDelta", outstanding_delta); - UMA_HISTOGRAM_COUNTS_100("OSX.RunningOps", running_ops); - } - - return true; -} diff --git a/base/worker_pool_linux.cc b/base/worker_pool_posix.cc index 8c96ca0..85e1d8e 100644 --- a/base/worker_pool_linux.cc +++ b/base/worker_pool_posix.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "base/worker_pool.h" -#include "base/worker_pool_linux.h" +#include "base/worker_pool_posix.h" #include "base/lazy_instance.h" #include "base/logging.h" @@ -28,11 +28,11 @@ class WorkerPoolImpl { bool task_is_slow); private: - scoped_refptr<base::LinuxDynamicThreadPool> pool_; + scoped_refptr<base::PosixDynamicThreadPool> pool_; }; WorkerPoolImpl::WorkerPoolImpl() - : pool_(new base::LinuxDynamicThreadPool( + : pool_(new base::PosixDynamicThreadPool( "WorkerPool", kIdleSecondsBeforeExit)) {} WorkerPoolImpl::~WorkerPoolImpl() { @@ -50,7 +50,7 @@ base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool(base::LINKER_INITIALIZED); class WorkerThread : public PlatformThread::Delegate { public: WorkerThread(const std::string& name_prefix, int idle_seconds_before_exit, - base::LinuxDynamicThreadPool* pool) + base::PosixDynamicThreadPool* pool) : name_prefix_(name_prefix), idle_seconds_before_exit_(idle_seconds_before_exit), pool_(pool) {} @@ -60,7 +60,7 @@ class WorkerThread : public PlatformThread::Delegate { private: const std::string name_prefix_; const int idle_seconds_before_exit_; - scoped_refptr<base::LinuxDynamicThreadPool> pool_; + scoped_refptr<base::PosixDynamicThreadPool> pool_; DISALLOW_COPY_AND_ASSIGN(WorkerThread); }; @@ -84,33 +84,15 @@ 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 { -LinuxDynamicThreadPool::LinuxDynamicThreadPool( +PosixDynamicThreadPool::PosixDynamicThreadPool( const std::string& name_prefix, int idle_seconds_before_exit) : name_prefix_(name_prefix), @@ -120,7 +102,7 @@ LinuxDynamicThreadPool::LinuxDynamicThreadPool( terminated_(false), num_idle_threads_cv_(NULL) {} -LinuxDynamicThreadPool::~LinuxDynamicThreadPool() { +PosixDynamicThreadPool::~PosixDynamicThreadPool() { while (!tasks_.empty()) { Task* task = tasks_.front(); tasks_.pop(); @@ -128,7 +110,7 @@ LinuxDynamicThreadPool::~LinuxDynamicThreadPool() { } } -void LinuxDynamicThreadPool::Terminate() { +void PosixDynamicThreadPool::Terminate() { { AutoLock locked(lock_); DCHECK(!terminated_) << "Thread pool is already terminated."; @@ -137,7 +119,7 @@ void LinuxDynamicThreadPool::Terminate() { tasks_available_cv_.Broadcast(); } -void LinuxDynamicThreadPool::PostTask(Task* task) { +void PosixDynamicThreadPool::PostTask(Task* task) { AutoLock locked(lock_); DCHECK(!terminated_) << "This thread pool is already terminated. Do not post new tasks."; @@ -156,7 +138,7 @@ void LinuxDynamicThreadPool::PostTask(Task* task) { } } -Task* LinuxDynamicThreadPool::WaitForTask() { +Task* PosixDynamicThreadPool::WaitForTask() { AutoLock locked(lock_); if (terminated_) diff --git a/base/worker_pool_linux.h b/base/worker_pool_posix.h index ea6bab7..73d8287 100644 --- a/base/worker_pool_linux.h +++ b/base/worker_pool_posix.h @@ -2,27 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// The thread pool used in the Linux implementation of WorkerPool dynamically +// The thread pool used in the POSIX implementation of WorkerPool dynamically // adds threads as necessary to handle all tasks. It keeps old threads around // for a period of time to allow them to be reused. After this waiting period, // the threads exit. This thread pool uses non-joinable threads, therefore // worker threads are not joined during process shutdown. This means that // potentially long running tasks (such as DNS lookup) do not block process // shutdown, but also means that process shutdown may "leak" objects. Note that -// although LinuxDynamicThreadPool spawns the worker threads and manages the +// although PosixDynamicThreadPool spawns the worker threads and manages the // task queue, it does not own the worker threads. The worker threads ask the -// LinuxDynamicThreadPool for work and eventually clean themselves up. The -// worker threads all maintain scoped_refptrs to the LinuxDynamicThreadPool -// instance, which prevents LinuxDynamicThreadPool from disappearing before all -// worker threads exit. The owner of LinuxDynamicThreadPool should likewise -// maintain a scoped_refptr to the LinuxDynamicThreadPool instance. +// PosixDynamicThreadPool for work and eventually clean themselves up. The +// worker threads all maintain scoped_refptrs to the PosixDynamicThreadPool +// instance, which prevents PosixDynamicThreadPool from disappearing before all +// worker threads exit. The owner of PosixDynamicThreadPool should likewise +// maintain a scoped_refptr to the PosixDynamicThreadPool instance. // -// NOTE: The classes defined in this file are only meant for use by the Linux +// NOTE: The classes defined in this file are only meant for use by the POSIX // implementation of WorkerPool. No one else should be using these classes. // These symbols are exported in a header purely for testing purposes. -#ifndef BASE_WORKER_POOL_LINUX_H_ -#define BASE_WORKER_POOL_LINUX_H_ +#ifndef BASE_WORKER_POOL_POSIX_H_ +#define BASE_WORKER_POOL_POSIX_H_ #pragma once #include <queue> @@ -39,22 +39,22 @@ class Task; namespace base { -class LinuxDynamicThreadPool - : public RefCountedThreadSafe<LinuxDynamicThreadPool> { +class PosixDynamicThreadPool + : public RefCountedThreadSafe<PosixDynamicThreadPool> { public: - class LinuxDynamicThreadPoolPeer; + class PosixDynamicThreadPoolPeer; // All worker threads will share the same |name_prefix|. They will exit after // |idle_seconds_before_exit|. - LinuxDynamicThreadPool(const std::string& name_prefix, + PosixDynamicThreadPool(const std::string& name_prefix, int idle_seconds_before_exit); - ~LinuxDynamicThreadPool(); + ~PosixDynamicThreadPool(); // Indicates that the thread pool is going away. Stops handing out tasks to // worker threads. Wakes up all the idle threads to let them exit. void Terminate(); - // Adds |task| to the thread pool. LinuxDynamicThreadPool assumes ownership + // Adds |task| to the thread pool. PosixDynamicThreadPool assumes ownership // of |task|. void PostTask(Task* task); @@ -63,7 +63,7 @@ class LinuxDynamicThreadPool Task* WaitForTask(); private: - friend class LinuxDynamicThreadPoolPeer; + friend class PosixDynamicThreadPoolPeer; const std::string name_prefix_; const int idle_seconds_before_exit_; @@ -81,23 +81,9 @@ class LinuxDynamicThreadPool // NULL in non-test code. scoped_ptr<ConditionVariable> num_idle_threads_cv_; - DISALLOW_COPY_AND_ASSIGN(LinuxDynamicThreadPool); + DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool); }; } // 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_ +#endif // BASE_WORKER_POOL_POSIX_H_ diff --git a/base/worker_pool_linux_unittest.cc b/base/worker_pool_posix_unittest.cc index f98f37a..55453c8 100644 --- a/base/worker_pool_linux_unittest.cc +++ b/base/worker_pool_posix_unittest.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/worker_pool_linux.h" +#include "base/worker_pool_posix.h" #include <set> @@ -15,10 +15,10 @@ namespace base { -// Peer class to provide passthrough access to LinuxDynamicThreadPool internals. -class LinuxDynamicThreadPool::LinuxDynamicThreadPoolPeer { +// Peer class to provide passthrough access to PosixDynamicThreadPool internals. +class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer { public: - explicit LinuxDynamicThreadPoolPeer(LinuxDynamicThreadPool* pool) + explicit PosixDynamicThreadPoolPeer(PosixDynamicThreadPool* pool) : pool_(pool) {} Lock* lock() { return &pool_->lock_; } @@ -35,9 +35,9 @@ class LinuxDynamicThreadPool::LinuxDynamicThreadPoolPeer { } private: - LinuxDynamicThreadPool* pool_; + PosixDynamicThreadPool* pool_; - DISALLOW_COPY_AND_ASSIGN(LinuxDynamicThreadPoolPeer); + DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPoolPeer); }; } // namespace base @@ -120,10 +120,10 @@ class BlockingIncrementingTask : public Task { DISALLOW_COPY_AND_ASSIGN(BlockingIncrementingTask); }; -class LinuxDynamicThreadPoolTest : public testing::Test { +class PosixDynamicThreadPoolTest : public testing::Test { protected: - LinuxDynamicThreadPoolTest() - : pool_(new base::LinuxDynamicThreadPool("dynamic_pool", 60*60)), + PosixDynamicThreadPoolTest() + : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)), peer_(pool_.get()), counter_(0), num_waiting_to_start_(0), @@ -165,8 +165,8 @@ class LinuxDynamicThreadPoolTest : public testing::Test { &num_waiting_to_start_cv_, &start_); } - scoped_refptr<base::LinuxDynamicThreadPool> pool_; - base::LinuxDynamicThreadPool::LinuxDynamicThreadPoolPeer peer_; + scoped_refptr<base::PosixDynamicThreadPool> pool_; + base::PosixDynamicThreadPool::PosixDynamicThreadPoolPeer peer_; Lock counter_lock_; int counter_; Lock unique_threads_lock_; @@ -177,7 +177,7 @@ class LinuxDynamicThreadPoolTest : public testing::Test { base::WaitableEvent start_; }; -TEST_F(LinuxDynamicThreadPoolTest, Basic) { +TEST_F(PosixDynamicThreadPoolTest, Basic) { EXPECT_EQ(0, peer_.num_idle_threads()); EXPECT_EQ(0U, unique_threads_.size()); EXPECT_EQ(0U, peer_.tasks().size()); @@ -193,7 +193,7 @@ TEST_F(LinuxDynamicThreadPoolTest, Basic) { EXPECT_EQ(1, counter_); } -TEST_F(LinuxDynamicThreadPoolTest, ReuseIdle) { +TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) { // Add one task and wait for it to be completed. pool_->PostTask(CreateNewIncrementingTask()); @@ -212,7 +212,7 @@ TEST_F(LinuxDynamicThreadPoolTest, ReuseIdle) { EXPECT_EQ(3, counter_); } -TEST_F(LinuxDynamicThreadPoolTest, TwoActiveTasks) { +TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) { // Add two blocking tasks. pool_->PostTask(CreateNewBlockingIncrementingTask()); pool_->PostTask(CreateNewBlockingIncrementingTask()); @@ -228,7 +228,7 @@ TEST_F(LinuxDynamicThreadPoolTest, TwoActiveTasks) { EXPECT_EQ(2, counter_); } -TEST_F(LinuxDynamicThreadPoolTest, Complex) { +TEST_F(PosixDynamicThreadPoolTest, Complex) { // Add two non blocking tasks and wait for them to finish. pool_->PostTask(CreateNewIncrementingTask()); |