summaryrefslogtreecommitdiffstats
path: root/chromium/base
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/base
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/base')
-rw-r--r--chromium/base/BUILD.gn663
-rw-r--r--chromium/base/DEPS1
-rw-r--r--chromium/base/OWNERS26
-rw-r--r--chromium/base/PRESUBMIT.py2
-rw-r--r--chromium/base/allocator/BUILD.gn35
-rw-r--r--chromium/base/allocator/allocator.gyp555
-rw-r--r--chromium/base/allocator/allocator_extension.h6
-rw-r--r--chromium/base/allocator/allocator_extension_thunks.h6
-rw-r--r--chromium/base/allocator/allocator_shim.cc378
-rw-r--r--chromium/base/allocator/allocator_shim.h27
-rw-r--r--chromium/base/allocator/allocator_shim_win.cc319
-rw-r--r--chromium/base/allocator/allocator_unittest.cc292
-rw-r--r--chromium/base/allocator/generic_allocators.cc176
-rwxr-xr-xchromium/base/allocator/prep_libc.py55
-rw-r--r--chromium/base/allocator/tcmalloc_unittest.cc25
-rw-r--r--chromium/base/allocator/win_allocator.cc78
-rw-r--r--chromium/base/android/animation_frame_time_histogram.cc36
-rw-r--r--chromium/base/android/animation_frame_time_histogram.h18
-rw-r--r--chromium/base/android/application_status_listener.cc3
-rw-r--r--chromium/base/android/application_status_listener_unittest.cc7
-rw-r--r--chromium/base/android/build_info.cc7
-rw-r--r--chromium/base/android/build_info.h15
-rw-r--r--chromium/base/android/command_line_android.cc1
-rw-r--r--chromium/base/android/content_uri_utils.cc10
-rw-r--r--chromium/base/android/content_uri_utils.h10
-rw-r--r--chromium/base/android/content_uri_utils_unittest.cc37
-rw-r--r--chromium/base/android/important_file_writer_android.h6
-rw-r--r--chromium/base/android/jni_generator/jni_generator.gyp6
-rw-r--r--chromium/base/android/library_loader/library_load_from_apk_status_codes.h6
-rw-r--r--chromium/base/android/library_loader/library_loader_hooks.cc30
-rw-r--r--chromium/base/android/library_loader/library_loader_hooks.h26
-rw-r--r--chromium/base/android/library_loader/library_prefetcher.cc150
-rw-r--r--chromium/base/android/library_loader/library_prefetcher.h67
-rw-r--r--chromium/base/android/library_loader/library_prefetcher_unittest.cc95
-rw-r--r--chromium/base/android/linker/BUILD.gn10
-rw-r--r--chromium/base/android/record_histogram.cc245
-rw-r--r--chromium/base/android/record_histogram.h18
-rw-r--r--chromium/base/android/record_user_action.cc24
-rw-r--r--chromium/base/android/record_user_action.h19
-rw-r--r--chromium/base/android/scoped_java_ref.h2
-rw-r--r--chromium/base/android/scoped_java_ref_unittest.cc4
-rw-r--r--chromium/base/android/trace_event_binding.cc53
-rw-r--r--chromium/base/android/trace_event_binding.h6
-rw-r--r--chromium/base/async_socket_io_handler.h6
-rw-r--r--chromium/base/async_socket_io_handler_unittest.cc17
-rw-r--r--chromium/base/atomic_ref_count.h3
-rw-r--r--chromium/base/atomicops.h8
-rw-r--r--chromium/base/atomicops_internals_arm64_gcc.h2
-rw-r--r--chromium/base/atomicops_internals_arm_gcc.h2
-rw-r--r--chromium/base/atomicops_internals_atomicword_compat.h4
-rw-r--r--chromium/base/atomicops_internals_gcc.h2
-rw-r--r--chromium/base/atomicops_internals_mac.h4
-rw-r--r--chromium/base/atomicops_internals_mips_gcc.h8
-rw-r--r--chromium/base/atomicops_internals_portable.h4
-rw-r--r--chromium/base/atomicops_internals_x86_gcc.h4
-rw-r--r--chromium/base/atomicops_internals_x86_msvc.h5
-rw-r--r--chromium/base/auto_reset.h2
-rw-r--r--chromium/base/barrier_closure.cc5
-rw-r--r--chromium/base/barrier_closure_unittest.cc56
-rw-r--r--chromium/base/base.gyp270
-rw-r--r--chromium/base/base.gypi194
-rw-r--r--chromium/base/base.isolate55
-rw-r--r--chromium/base/base64.h11
-rw-r--r--chromium/base/base64_unittest.cc13
-rw-r--r--chromium/base/base_nacl.gyp11
-rw-r--r--chromium/base/base_paths_win.cc23
-rw-r--r--chromium/base/base_paths_win.h16
-rw-r--r--chromium/base/base_switches.cc9
-rw-r--r--chromium/base/base_switches.h3
-rw-r--r--chromium/base/base_unittests.isolate40
-rw-r--r--chromium/base/bind.h445
-rw-r--r--chromium/base/bind.h.pump153
-rw-r--r--chromium/base/bind_helpers.h124
-rw-r--r--chromium/base/bind_internal.h2689
-rw-r--r--chromium/base/bind_internal.h.pump500
-rw-r--r--chromium/base/bind_unittest.cc4
-rw-r--r--chromium/base/bind_unittest.nc4
-rw-r--r--chromium/base/build_time.h6
-rw-r--r--chromium/base/callback.h375
-rw-r--r--chromium/base/callback.h.pump436
-rw-r--r--chromium/base/callback_forward.h2
-rw-r--r--chromium/base/callback_internal.cc14
-rw-r--r--chromium/base/callback_internal.h74
-rw-r--r--chromium/base/callback_list.h190
-rw-r--r--chromium/base/callback_list.h.pump269
-rw-r--r--chromium/base/callback_unittest.cc15
-rw-r--r--chromium/base/cancelable_callback.h164
-rw-r--r--chromium/base/cancelable_callback_unittest.cc8
-rw-r--r--chromium/base/chromeos/OWNERS3
-rw-r--r--chromium/base/chromeos/memory_pressure_monitor.cc272
-rw-r--r--chromium/base/chromeos/memory_pressure_monitor.h119
-rw-r--r--chromium/base/chromeos/memory_pressure_monitor_unittest.cc165
-rw-r--r--chromium/base/command_line.cc57
-rw-r--r--chromium/base/command_line.h8
-rw-r--r--chromium/base/command_line_unittest.cc30
-rw-r--r--chromium/base/compiler_specific.h18
-rw-r--r--chromium/base/containers/hash_tables.h2
-rw-r--r--chromium/base/containers/mru_cache.h7
-rw-r--r--chromium/base/containers/scoped_ptr_hash_map.h55
-rw-r--r--chromium/base/containers/scoped_ptr_hash_map_unittest.cc85
-rw-r--r--chromium/base/containers/stack_container.h1
-rw-r--r--chromium/base/critical_closure.h2
-rw-r--r--chromium/base/debug/BUILD.gn76
-rw-r--r--chromium/base/debug/crash_logging_unittest.cc4
-rw-r--r--chromium/base/debug/debugger.h6
-rw-r--r--chromium/base/debug/debugger_unittest.cc43
-rw-r--r--chromium/base/debug/debugger_win.cc4
-rw-r--r--chromium/base/debug/leak_annotations.h11
-rw-r--r--chromium/base/debug/proc_maps_linux_unittest.cc65
-rw-r--r--chromium/base/debug/profiler.h6
-rw-r--r--chromium/base/debug/stack_trace.h6
-rw-r--r--chromium/base/debug/stack_trace_unittest.cc8
-rw-r--r--chromium/base/debug/stack_trace_win.cc33
-rw-r--r--chromium/base/debug/task_annotator.cc3
-rw-r--r--chromium/base/debug/trace_event_unittest.h14
-rw-r--r--chromium/base/deferred_sequenced_task_runner.h6
-rw-r--r--chromium/base/deferred_sequenced_task_runner_unittest.cc32
-rw-r--r--chromium/base/event_recorder.h109
-rw-r--r--chromium/base/event_recorder_stubs.cc28
-rw-r--r--chromium/base/event_recorder_win.cc258
-rw-r--r--chromium/base/event_types.h6
-rw-r--r--chromium/base/file_version_info.h15
-rw-r--r--chromium/base/file_version_info_mac.h5
-rw-r--r--chromium/base/file_version_info_win.h42
-rw-r--r--chromium/base/files/dir_reader_linux.h2
-rw-r--r--chromium/base/files/dir_reader_posix.h2
-rw-r--r--chromium/base/files/file.cc25
-rw-r--r--chromium/base/files/file.h54
-rw-r--r--chromium/base/files/file_enumerator_win.cc3
-rw-r--r--chromium/base/files/file_path.cc8
-rw-r--r--chromium/base/files/file_path.h13
-rw-r--r--chromium/base/files/file_path_unittest.cc10
-rw-r--r--chromium/base/files/file_path_watcher.cc2
-rw-r--r--chromium/base/files/file_path_watcher.h13
-rw-r--r--chromium/base/files/file_path_watcher_fsevents.cc165
-rw-r--r--chromium/base/files/file_path_watcher_fsevents.h47
-rw-r--r--chromium/base/files/file_path_watcher_kqueue.cc15
-rw-r--r--chromium/base/files/file_path_watcher_kqueue.h6
-rw-r--r--chromium/base/files/file_path_watcher_linux.cc75
-rw-r--r--chromium/base/files/file_path_watcher_stub.cc12
-rw-r--r--chromium/base/files/file_path_watcher_unittest.cc (renamed from chromium/base/files/file_path_watcher_browsertest.cc)80
-rw-r--r--chromium/base/files/file_path_watcher_win.cc36
-rw-r--r--chromium/base/files/file_posix.cc280
-rw-r--r--chromium/base/files/file_proxy.cc1
-rw-r--r--chromium/base/files/file_proxy_unittest.cc5
-rw-r--r--chromium/base/files/file_tracing.cc56
-rw-r--r--chromium/base/files/file_tracing.h95
-rw-r--r--chromium/base/files/file_unittest.cc43
-rw-r--r--chromium/base/files/file_util.cc6
-rw-r--r--chromium/base/files/file_util.h5
-rw-r--r--chromium/base/files/file_util_linux.cc15
-rw-r--r--chromium/base/files/file_util_mac.mm7
-rw-r--r--chromium/base/files/file_util_posix.cc102
-rw-r--r--chromium/base/files/file_util_proxy_unittest.cc9
-rw-r--r--chromium/base/files/file_util_unittest.cc66
-rw-r--r--chromium/base/files/file_util_win.cc112
-rw-r--r--chromium/base/files/file_win.cc268
-rw-r--r--chromium/base/files/important_file_writer.cc54
-rw-r--r--chromium/base/files/important_file_writer.h4
-rw-r--r--chromium/base/files/important_file_writer_unittest.cc39
-rw-r--r--chromium/base/files/memory_mapped_file.cc2
-rw-r--r--chromium/base/files/memory_mapped_file_posix.cc2
-rw-r--r--chromium/base/files/memory_mapped_file_unittest.cc4
-rw-r--r--chromium/base/float_util.h36
-rw-r--r--chromium/base/format_macros.h21
-rw-r--r--chromium/base/guid_posix.cc2
-rw-r--r--chromium/base/guid_win.cc2
-rw-r--r--chromium/base/i18n/break_iterator.cc3
-rw-r--r--chromium/base/i18n/build_utf8_validator_tables.cc8
-rw-r--r--chromium/base/i18n/char_iterator.h2
-rw-r--r--chromium/base/i18n/file_util_icu.cc89
-rw-r--r--chromium/base/i18n/file_util_icu.h20
-rw-r--r--chromium/base/i18n/file_util_icu_unittest.cc80
-rw-r--r--chromium/base/i18n/i18n_constants.cc2
-rw-r--r--chromium/base/i18n/i18n_constants.h5
-rw-r--r--chromium/base/i18n/icu_string_conversions.cc76
-rw-r--r--chromium/base/i18n/icu_string_conversions.h15
-rw-r--r--chromium/base/i18n/icu_string_conversions_unittest.cc108
-rw-r--r--chromium/base/i18n/icu_util.cc85
-rw-r--r--chromium/base/i18n/icu_util.h15
-rw-r--r--chromium/base/i18n/rtl.cc4
-rw-r--r--chromium/base/i18n/rtl.h2
-rw-r--r--chromium/base/i18n/streaming_utf8_validator_perftest.cc4
-rw-r--r--chromium/base/i18n/string_compare.cc5
-rw-r--r--chromium/base/i18n/string_compare.h10
-rw-r--r--chromium/base/i18n/time_formatting.cc6
-rw-r--r--chromium/base/i18n/time_formatting.h5
-rw-r--r--chromium/base/i18n/time_formatting_unittest.cc35
-rw-r--r--chromium/base/i18n/timezone.h2
-rw-r--r--chromium/base/id_map.h26
-rw-r--r--chromium/base/id_map_unittest.cc3
-rw-r--r--chromium/base/ios/block_types.h14
-rw-r--r--chromium/base/ios/crb_protocol_observers.h36
-rw-r--r--chromium/base/ios/crb_protocol_observers.mm99
-rw-r--r--chromium/base/ios/crb_protocol_observers_unittest.mm159
-rw-r--r--chromium/base/ios/device_util.mm1
-rw-r--r--chromium/base/ios/device_util_unittest.mm1
-rw-r--r--chromium/base/ios/ios_util.h3
-rw-r--r--chromium/base/ios/ios_util.mm4
-rw-r--r--chromium/base/ios/weak_nsobject.h189
-rw-r--r--chromium/base/ios/weak_nsobject.mm61
-rw-r--r--chromium/base/ios/weak_nsobject_unittest.mm140
-rw-r--r--chromium/base/json/BUILD.gn37
-rw-r--r--chromium/base/json/json_file_value_serializer.cc42
-rw-r--r--chromium/base/json/json_file_value_serializer.h44
-rw-r--r--chromium/base/json/json_parser.cc9
-rw-r--r--chromium/base/json/json_string_value_serializer.cc22
-rw-r--r--chromium/base/json/json_string_value_serializer.h59
-rw-r--r--chromium/base/json/json_value_converter.cc37
-rw-r--r--chromium/base/json/json_value_converter.h59
-rw-r--r--chromium/base/json/json_value_serializer_unittest.cc130
-rw-r--r--chromium/base/json/json_writer_unittest.cc96
-rw-r--r--chromium/base/json/string_escape_unittest.cc2
-rw-r--r--chromium/base/location.cc7
-rw-r--r--chromium/base/location.h43
-rw-r--r--chromium/base/logging.cc28
-rw-r--r--chromium/base/logging.h40
-rw-r--r--chromium/base/logging_unittest.cc15
-rw-r--r--chromium/base/logging_win.h4
-rw-r--r--chromium/base/mac/authorization_util.mm7
-rw-r--r--chromium/base/mac/close_nocancel.cc31
-rw-r--r--chromium/base/mac/cocoa_protocols.h10
-rw-r--r--chromium/base/mac/dispatch_source_mach.cc62
-rw-r--r--chromium/base/mac/dispatch_source_mach.h61
-rw-r--r--chromium/base/mac/dispatch_source_mach_unittest.cc125
-rw-r--r--chromium/base/mac/foundation_util.h10
-rw-r--r--chromium/base/mac/foundation_util.mm16
-rw-r--r--chromium/base/mac/launch_services_util.cc1
-rw-r--r--chromium/base/mac/launch_services_util.h2
-rw-r--r--chromium/base/mac/libdispatch_task_runner.h6
-rw-r--r--chromium/base/mac/libdispatch_task_runner_unittest.cc2
-rw-r--r--chromium/base/mac/mac_logging.h8
-rw-r--r--chromium/base/mac/mac_util.h3
-rw-r--r--chromium/base/mac/mac_util_unittest.mm3
-rw-r--r--chromium/base/mac/mach_logging.h16
-rw-r--r--chromium/base/mac/memory_pressure_monitor.cc78
-rw-r--r--chromium/base/mac/memory_pressure_monitor.h63
-rw-r--r--chromium/base/mac/memory_pressure_monitor_unittest.cc61
-rw-r--r--chromium/base/mac/scoped_authorizationref.h4
-rw-r--r--chromium/base/mac/scoped_mach_port.cc8
-rw-r--r--chromium/base/mac/scoped_mach_port.h25
-rw-r--r--chromium/base/mac/scoped_mach_vm.cc4
-rw-r--r--chromium/base/mac/scoped_mach_vm.h7
-rw-r--r--chromium/base/mac/scoped_nsobject.h23
-rw-r--r--chromium/base/mac/scoped_sending_event_unittest.mm4
-rw-r--r--chromium/base/mac/sdk_forward_declarations.h446
-rw-r--r--chromium/base/mac/sdk_forward_declarations.mm18
-rw-r--r--chromium/base/macros.h14
-rw-r--r--chromium/base/md5.cc383
-rw-r--r--chromium/base/md5.h12
-rw-r--r--chromium/base/md5_unittest.cc2
-rw-r--r--chromium/base/memory/BUILD.gn58
-rw-r--r--chromium/base/memory/discardable_memory.cc75
-rw-r--r--chromium/base/memory/discardable_memory.h107
-rw-r--r--chromium/base/memory/discardable_memory_allocator.cc34
-rw-r--r--chromium/base/memory/discardable_memory_allocator.h32
-rw-r--r--chromium/base/memory/discardable_memory_android.cc114
-rw-r--r--chromium/base/memory/discardable_memory_ashmem.cc79
-rw-r--r--chromium/base/memory/discardable_memory_ashmem.h56
-rw-r--r--chromium/base/memory/discardable_memory_ashmem_allocator.cc528
-rw-r--r--chromium/base/memory/discardable_memory_ashmem_allocator.h93
-rw-r--r--chromium/base/memory/discardable_memory_ashmem_allocator_unittest.cc319
-rw-r--r--chromium/base/memory/discardable_memory_emulated.cc121
-rw-r--r--chromium/base/memory/discardable_memory_emulated.h55
-rw-r--r--chromium/base/memory/discardable_memory_linux.cc70
-rw-r--r--chromium/base/memory/discardable_memory_mac.cc82
-rw-r--r--chromium/base/memory/discardable_memory_mach.cc162
-rw-r--r--chromium/base/memory/discardable_memory_mach.h49
-rw-r--r--chromium/base/memory/discardable_memory_manager.cc246
-rw-r--r--chromium/base/memory/discardable_memory_manager.h173
-rw-r--r--chromium/base/memory/discardable_memory_manager_unittest.cc494
-rw-r--r--chromium/base/memory/discardable_memory_shmem.cc121
-rw-r--r--chromium/base/memory/discardable_memory_shmem.h52
-rw-r--r--chromium/base/memory/discardable_memory_shmem_allocator.cc58
-rw-r--r--chromium/base/memory/discardable_memory_shmem_allocator.h32
-rw-r--r--chromium/base/memory/discardable_memory_unittest.cc134
-rw-r--r--chromium/base/memory/discardable_memory_win.cc70
-rw-r--r--chromium/base/memory/discardable_shared_memory.cc224
-rw-r--r--chromium/base/memory/discardable_shared_memory.h83
-rw-r--r--chromium/base/memory/discardable_shared_memory_unittest.cc175
-rw-r--r--chromium/base/memory/manual_constructor.h66
-rw-r--r--chromium/base/memory/memory_pressure_listener.cc5
-rw-r--r--chromium/base/memory/memory_pressure_listener.h23
-rw-r--r--chromium/base/memory/memory_pressure_monitor.cc31
-rw-r--r--chromium/base/memory/memory_pressure_monitor.h43
-rw-r--r--chromium/base/memory/raw_scoped_refptr_mismatch_checker.h18
-rw-r--r--chromium/base/memory/ref_counted.h50
-rw-r--r--chromium/base/memory/ref_counted_delete_on_message_loop.h20
-rw-r--r--chromium/base/memory/ref_counted_unittest.cc400
-rw-r--r--chromium/base/memory/scoped_open_process.h48
-rw-r--r--chromium/base/memory/scoped_ptr.h6
-rw-r--r--chromium/base/memory/scoped_ptr_unittest.cc17
-rw-r--r--chromium/base/memory/scoped_vector.h2
-rw-r--r--chromium/base/memory/scoped_vector_unittest.cc13
-rw-r--r--chromium/base/memory/shared_memory.h3
-rw-r--r--chromium/base/memory/shared_memory_nacl.cc6
-rw-r--r--chromium/base/memory/shared_memory_posix.cc34
-rw-r--r--chromium/base/memory/shared_memory_unittest.cc35
-rw-r--r--chromium/base/memory/shared_memory_win.cc25
-rw-r--r--chromium/base/memory/singleton.h9
-rw-r--r--chromium/base/memory/singleton_unittest.cc2
-rw-r--r--chromium/base/memory/weak_ptr_unittest.cc45
-rw-r--r--chromium/base/message_loop/incoming_task_queue.cc57
-rw-r--r--chromium/base/message_loop/incoming_task_queue.h8
-rw-r--r--chromium/base/message_loop/message_loop.cc53
-rw-r--r--chromium/base/message_loop/message_loop.h15
-rw-r--r--chromium/base/message_loop/message_loop_proxy.h12
-rw-r--r--chromium/base/message_loop/message_loop_proxy_impl_unittest.cc4
-rw-r--r--chromium/base/message_loop/message_loop_proxy_unittest.cc4
-rw-r--r--chromium/base/message_loop/message_loop_unittest.cc9
-rw-r--r--chromium/base/message_loop/message_pump_android.h10
-rw-r--r--chromium/base/message_loop/message_pump_default.cc3
-rw-r--r--chromium/base/message_loop/message_pump_default.h2
-rw-r--r--chromium/base/message_loop/message_pump_dispatcher.h6
-rw-r--r--chromium/base/message_loop/message_pump_glib_unittest.cc4
-rw-r--r--chromium/base/message_loop/message_pump_io_ios.h2
-rw-r--r--chromium/base/message_loop/message_pump_io_ios_unittest.cc32
-rw-r--r--chromium/base/message_loop/message_pump_libevent.cc6
-rw-r--r--chromium/base/message_loop/message_pump_libevent_unittest.cc79
-rw-r--r--chromium/base/message_loop/message_pump_mac.h6
-rw-r--r--chromium/base/message_loop/message_pump_perftest.cc10
-rw-r--r--chromium/base/message_loop/message_pump_win.cc81
-rw-r--r--chromium/base/message_loop/message_pump_win.h21
-rw-r--r--chromium/base/metrics/BUILD.gn49
-rw-r--r--chromium/base/metrics/field_trial.cc42
-rw-r--r--chromium/base/metrics/field_trial.h27
-rw-r--r--chromium/base/metrics/field_trial_unittest.cc105
-rw-r--r--chromium/base/metrics/histogram.cc8
-rw-r--r--chromium/base/metrics/histogram.h237
-rw-r--r--chromium/base/metrics/histogram_base.cc4
-rw-r--r--chromium/base/metrics/histogram_base_unittest.cc4
-rw-r--r--chromium/base/metrics/histogram_macros.h264
-rw-r--r--chromium/base/metrics/histogram_macros_unittest.cc18
-rw-r--r--chromium/base/metrics/histogram_snapshot_manager_unittest.cc2
-rw-r--r--chromium/base/metrics/histogram_unittest.cc6
-rw-r--r--chromium/base/metrics/sparse_histogram_unittest.cc6
-rw-r--r--chromium/base/metrics/statistics_recorder.cc6
-rw-r--r--chromium/base/metrics/statistics_recorder.h1
-rw-r--r--chromium/base/metrics/statistics_recorder_unittest.cc6
-rw-r--r--chromium/base/metrics/stats_counters.cc125
-rw-r--r--chromium/base/metrics/stats_counters.h197
-rw-r--r--chromium/base/metrics/stats_table.cc617
-rw-r--r--chromium/base/metrics/stats_table.h220
-rw-r--r--chromium/base/metrics/stats_table_unittest.cc402
-rw-r--r--chromium/base/move.h13
-rw-r--r--chromium/base/move_unittest.cc49
-rw-r--r--chromium/base/native_library_ios.mm40
-rw-r--r--chromium/base/nix/xdg_util.cc10
-rw-r--r--chromium/base/nix/xdg_util_unittest.cc93
-rw-r--r--chromium/base/numerics/safe_conversions.h7
-rw-r--r--chromium/base/numerics/safe_conversions_impl.h7
-rw-r--r--chromium/base/numerics/safe_math.h6
-rw-r--r--chromium/base/numerics/safe_math_impl.h10
-rw-r--r--chromium/base/numerics/safe_numerics_unittest.cc14
-rw-r--r--chromium/base/observer_list.h55
-rw-r--r--chromium/base/observer_list_threadsafe.h82
-rw-r--r--chromium/base/observer_list_unittest.cc43
-rw-r--r--chromium/base/path_service.cc2
-rw-r--r--chromium/base/path_service.h2
-rw-r--r--chromium/base/path_service_unittest.cc52
-rw-r--r--chromium/base/pending_task.h6
-rw-r--r--chromium/base/pickle.cc32
-rw-r--r--chromium/base/pickle.h116
-rw-r--r--chromium/base/pickle_unittest.cc95
-rw-r--r--chromium/base/port.h12
-rw-r--r--chromium/base/posix/global_descriptors.cc39
-rw-r--r--chromium/base/posix/global_descriptors.h26
-rw-r--r--chromium/base/posix/unix_domain_socket_linux.cc8
-rw-r--r--chromium/base/posix/unix_domain_socket_linux_unittest.cc14
-rw-r--r--chromium/base/power_monitor/power_monitor.cc7
-rw-r--r--chromium/base/power_monitor/power_monitor_device_source_win.cc6
-rw-r--r--chromium/base/power_monitor/power_monitor_unittest.cc2
-rw-r--r--chromium/base/prefs/json_pref_store.cc233
-rw-r--r--chromium/base/prefs/json_pref_store.h89
-rw-r--r--chromium/base/prefs/json_pref_store_unittest.cc409
-rw-r--r--chromium/base/prefs/mock_pref_change_callback.h3
-rw-r--r--chromium/base/prefs/overlay_user_pref_store.cc23
-rw-r--r--chromium/base/prefs/overlay_user_pref_store.h12
-rw-r--r--chromium/base/prefs/overlay_user_pref_store_unittest.cc89
-rw-r--r--chromium/base/prefs/pref_change_registrar.cc11
-rw-r--r--chromium/base/prefs/pref_change_registrar.h6
-rw-r--r--chromium/base/prefs/pref_change_registrar_unittest.cc10
-rw-r--r--chromium/base/prefs/pref_member.cc51
-rw-r--r--chromium/base/prefs/pref_member.h33
-rw-r--r--chromium/base/prefs/pref_member_unittest.cc30
-rw-r--r--chromium/base/prefs/pref_notifier_impl.cc8
-rw-r--r--chromium/base/prefs/pref_notifier_impl.h4
-rw-r--r--chromium/base/prefs/pref_notifier_impl_unittest.cc6
-rw-r--r--chromium/base/prefs/pref_registry.cc19
-rw-r--r--chromium/base/prefs/pref_registry.h33
-rw-r--r--chromium/base/prefs/pref_registry_simple.cc137
-rw-r--r--chromium/base/prefs/pref_registry_simple.h64
-rw-r--r--chromium/base/prefs/pref_service.cc177
-rw-r--r--chromium/base/prefs/pref_service.h85
-rw-r--r--chromium/base/prefs/pref_service_factory.cc2
-rw-r--r--chromium/base/prefs/pref_service_unittest.cc110
-rw-r--r--chromium/base/prefs/pref_value_map.cc76
-rw-r--r--chromium/base/prefs/pref_value_map.h9
-rw-r--r--chromium/base/prefs/pref_value_store.cc46
-rw-r--r--chromium/base/prefs/pref_value_store.h31
-rw-r--r--chromium/base/prefs/pref_value_store_unittest.cc4
-rw-r--r--chromium/base/prefs/scoped_user_pref_update.cc8
-rw-r--r--chromium/base/prefs/scoped_user_pref_update.h4
-rw-r--r--chromium/base/prefs/scoped_user_pref_update_unittest.cc4
-rw-r--r--chromium/base/prefs/testing_pref_service.h119
-rw-r--r--chromium/base/prefs/testing_pref_store.cc18
-rw-r--r--chromium/base/prefs/testing_pref_store.h12
-rw-r--r--chromium/base/prefs/value_map_pref_store.cc12
-rw-r--r--chromium/base/prefs/value_map_pref_store.h12
-rw-r--r--chromium/base/prefs/writeable_pref_store.h29
-rw-r--r--chromium/base/process/BUILD.gn108
-rw-r--r--chromium/base/process/internal_linux.cc6
-rw-r--r--chromium/base/process/internal_linux.h6
-rw-r--r--chromium/base/process/kill.cc7
-rw-r--r--chromium/base/process/kill.h45
-rw-r--r--chromium/base/process/kill_mac.cc8
-rw-r--r--chromium/base/process/kill_posix.cc286
-rw-r--r--chromium/base/process/kill_win.cc98
-rw-r--r--chromium/base/process/launch.cc4
-rw-r--r--chromium/base/process/launch.h90
-rw-r--r--chromium/base/process/launch_posix.cc165
-rw-r--r--chromium/base/process/launch_win.cc63
-rw-r--r--chromium/base/process/memory.cc20
-rw-r--r--chromium/base/process/memory.h4
-rw-r--r--chromium/base/process/memory_mac.mm248
-rw-r--r--chromium/base/process/memory_unittest.cc110
-rw-r--r--chromium/base/process/memory_win.cc18
-rw-r--r--chromium/base/process/process.h74
-rw-r--r--chromium/base/process/process_handle.h37
-rw-r--r--chromium/base/process/process_handle_posix.cc26
-rw-r--r--chromium/base/process/process_handle_win.cc98
-rw-r--r--chromium/base/process/process_info.h25
-rw-r--r--chromium/base/process/process_info_win.cc56
-rw-r--r--chromium/base/process/process_iterator.h37
-rw-r--r--chromium/base/process/process_linux.cc2
-rw-r--r--chromium/base/process/process_mac.cc128
-rw-r--r--chromium/base/process/process_metrics.cc6
-rw-r--r--chromium/base/process/process_metrics.h24
-rw-r--r--chromium/base/process/process_metrics_ios.cc17
-rw-r--r--chromium/base/process/process_metrics_linux.cc39
-rw-r--r--chromium/base/process/process_metrics_mac.cc23
-rw-r--r--chromium/base/process/process_metrics_posix.cc7
-rw-r--r--chromium/base/process/process_metrics_unittest.cc63
-rw-r--r--chromium/base/process/process_metrics_win.cc4
-rw-r--r--chromium/base/process/process_posix.cc312
-rw-r--r--chromium/base/process/process_unittest.cc77
-rw-r--r--chromium/base/process/process_util_unittest.cc316
-rw-r--r--chromium/base/process/process_win.cc96
-rw-r--r--chromium/base/profiler/alternate_timer.cc3
-rw-r--r--chromium/base/profiler/native_stack_sampler.cc13
-rw-r--r--chromium/base/profiler/native_stack_sampler.h50
-rw-r--r--chromium/base/profiler/scoped_profile.cc1
-rw-r--r--chromium/base/profiler/scoped_profile.h10
-rw-r--r--chromium/base/profiler/scoped_tracker.cc16
-rw-r--r--chromium/base/profiler/scoped_tracker.h19
-rw-r--r--chromium/base/profiler/stack_sampling_profiler.cc311
-rw-r--r--chromium/base/profiler/stack_sampling_profiler.h264
-rw-r--r--chromium/base/profiler/stack_sampling_profiler_posix.cc14
-rw-r--r--chromium/base/profiler/stack_sampling_profiler_unittest.cc445
-rw-r--r--chromium/base/profiler/stack_sampling_profiler_win.cc357
-rw-r--r--chromium/base/profiler/tracked_time.cc10
-rw-r--r--chromium/base/profiler/tracked_time_unittest.cc7
-rw-r--r--chromium/base/rand_util_unittest.cc4
-rw-r--r--chromium/base/scoped_generic.h14
-rw-r--r--chromium/base/scoped_generic_unittest.cc19
-rw-r--r--chromium/base/scoped_native_library.h2
-rw-r--r--chromium/base/scoped_observer.h2
-rw-r--r--chromium/base/security_unittest.cc126
-rw-r--r--chromium/base/sequence_checker_unittest.cc15
-rw-r--r--chromium/base/sequenced_task_runner.h6
-rw-r--r--chromium/base/single_thread_task_runner.h3
-rw-r--r--chromium/base/stl_util.h19
-rw-r--r--chromium/base/stl_util_unittest.cc27
-rw-r--r--chromium/base/strings/nullable_string16.h2
-rw-r--r--chromium/base/strings/safe_sprintf.cc6
-rw-r--r--chromium/base/strings/safe_sprintf_unittest.cc2
-rw-r--r--chromium/base/strings/string16.h2
-rw-r--r--chromium/base/strings/string_piece_unittest.cc6
-rw-r--r--chromium/base/strings/string_split.cc10
-rw-r--r--chromium/base/strings/string_util.cc100
-rw-r--r--chromium/base/strings/string_util.h2
-rw-r--r--chromium/base/strings/string_util_unittest.cc41
-rw-r--r--chromium/base/strings/string_util_win.h18
-rw-r--r--chromium/base/strings/stringprintf.cc16
-rw-r--r--chromium/base/strings/stringprintf.h11
-rw-r--r--chromium/base/strings/stringprintf_unittest.cc23
-rw-r--r--chromium/base/strings/sys_string_conversions_posix.cc3
-rw-r--r--chromium/base/strings/sys_string_conversions_unittest.cc6
-rw-r--r--chromium/base/strings/utf_offset_string_conversions_unittest.cc2
-rw-r--r--chromium/base/strings/utf_string_conversions.cc5
-rw-r--r--chromium/base/strings/utf_string_conversions.h5
-rw-r--r--chromium/base/strings/utf_string_conversions_unittest.cc2
-rw-r--r--chromium/base/supports_user_data.h2
-rw-r--r--chromium/base/sync_socket.h10
-rw-r--r--chromium/base/synchronization/cancellation_flag.cc4
-rw-r--r--chromium/base/synchronization/cancellation_flag.h5
-rw-r--r--chromium/base/synchronization/cancellation_flag_unittest.cc5
-rw-r--r--chromium/base/synchronization/condition_variable_unittest.cc4
-rw-r--r--chromium/base/synchronization/condition_variable_win.cc20
-rw-r--r--chromium/base/synchronization/waitable_event.h9
-rw-r--r--chromium/base/synchronization/waitable_event_unittest.cc54
-rw-r--r--chromium/base/synchronization/waitable_event_watcher.h2
-rw-r--r--chromium/base/synchronization/waitable_event_watcher_posix.cc6
-rw-r--r--chromium/base/synchronization/waitable_event_watcher_win.cc5
-rw-r--r--chromium/base/synchronization/waitable_event_win.cc26
-rw-r--r--chromium/base/sys_info.cc20
-rw-r--r--chromium/base/sys_info.h2
-rw-r--r--chromium/base/sys_info_android.cc6
-rw-r--r--chromium/base/sys_info_chromeos.cc2
-rw-r--r--chromium/base/sys_info_freebsd.cc4
-rw-r--r--chromium/base/sys_info_linux.cc14
-rw-r--r--chromium/base/sys_info_openbsd.cc4
-rw-r--r--chromium/base/sys_info_win.cc17
-rw-r--r--chromium/base/system_monitor/system_monitor.cc2
-rw-r--r--chromium/base/system_monitor/system_monitor_unittest.cc2
-rw-r--r--chromium/base/task/cancelable_task_tracker.cc9
-rw-r--r--chromium/base/task/cancelable_task_tracker_unittest.cc49
-rw-r--r--chromium/base/task_runner_util_unittest.cc20
-rw-r--r--chromium/base/third_party/dynamic_annotations/BUILD.gn29
-rw-r--r--chromium/base/third_party/dynamic_annotations/README.chromium7
-rw-r--r--chromium/base/third_party/dynamic_annotations/dynamic_annotations.gyp2
-rw-r--r--chromium/base/third_party/nspr/BUILD.gn20
-rw-r--r--chromium/base/third_party/xdg_mime/README.chromium6
-rw-r--r--chromium/base/third_party/xdg_mime/free_pointer_later.patch22
-rw-r--r--chromium/base/third_party/xdg_mime/xdgmime.c8
-rw-r--r--chromium/base/threading/platform_thread.h34
-rw-r--r--chromium/base/threading/platform_thread_android.cc99
-rw-r--r--chromium/base/threading/platform_thread_freebsd.cc94
-rw-r--r--chromium/base/threading/platform_thread_internal_posix.cc35
-rw-r--r--chromium/base/threading/platform_thread_internal_posix.h45
-rw-r--r--chromium/base/threading/platform_thread_linux.cc98
-rw-r--r--chromium/base/threading/platform_thread_mac.mm14
-rw-r--r--chromium/base/threading/platform_thread_posix.cc83
-rw-r--r--chromium/base/threading/platform_thread_unittest.cc182
-rw-r--r--chromium/base/threading/platform_thread_win.cc60
-rw-r--r--chromium/base/threading/post_task_and_reply_impl.cc18
-rw-r--r--chromium/base/threading/post_task_and_reply_impl.h6
-rw-r--r--chromium/base/threading/sequenced_worker_pool.cc121
-rw-r--r--chromium/base/threading/sequenced_worker_pool.h13
-rw-r--r--chromium/base/threading/sequenced_worker_pool_unittest.cc128
-rw-r--r--chromium/base/threading/simple_thread.cc2
-rw-r--r--chromium/base/threading/thread.cc13
-rw-r--r--chromium/base/threading/thread.h4
-rw-r--r--chromium/base/threading/thread_checker.h2
-rw-r--r--chromium/base/threading/thread_checker_impl.h3
-rw-r--r--chromium/base/threading/thread_collision_warner_unittest.cc72
-rw-r--r--chromium/base/threading/thread_id_name_manager.cc11
-rw-r--r--chromium/base/threading/thread_id_name_manager.h2
-rw-r--r--chromium/base/threading/thread_local_android.cc5
-rw-r--r--chromium/base/threading/thread_local_storage.cc9
-rw-r--r--chromium/base/threading/thread_local_storage.h4
-rw-r--r--chromium/base/threading/thread_local_storage_unittest.cc9
-rw-r--r--chromium/base/threading/thread_local_unittest.cc23
-rw-r--r--chromium/base/threading/thread_perftest.cc36
-rw-r--r--chromium/base/threading/thread_restrictions.h6
-rw-r--r--chromium/base/threading/thread_unittest.cc26
-rw-r--r--chromium/base/threading/watchdog.cc2
-rw-r--r--chromium/base/threading/watchdog_unittest.cc4
-rw-r--r--chromium/base/threading/worker_pool.h2
-rw-r--r--chromium/base/threading/worker_pool_posix.cc18
-rw-r--r--chromium/base/threading/worker_pool_posix_unittest.cc4
-rw-r--r--chromium/base/threading/worker_pool_win.cc8
-rw-r--r--chromium/base/time/clock.h6
-rw-r--r--chromium/base/time/default_clock.h6
-rw-r--r--chromium/base/time/default_tick_clock.h6
-rw-r--r--chromium/base/time/pr_time_unittest.cc2
-rw-r--r--chromium/base/time/tick_clock.h10
-rw-r--r--chromium/base/time/time.cc47
-rw-r--r--chromium/base/time/time.h448
-rw-r--r--chromium/base/time/time_mac.cc9
-rw-r--r--chromium/base/time/time_posix.cc11
-rw-r--r--chromium/base/time/time_unittest.cc239
-rw-r--r--chromium/base/time/time_win.cc311
-rw-r--r--chromium/base/time/time_win_unittest.cc128
-rw-r--r--chromium/base/timer/elapsed_timer.h5
-rw-r--r--chromium/base/timer/mock_timer.h2
-rw-r--r--chromium/base/timer/timer.cc4
-rw-r--r--chromium/base/timer/timer.h5
-rw-r--r--chromium/base/timer/timer_unittest.cc6
-rw-r--r--chromium/base/trace_event/BUILD.gn107
-rw-r--r--chromium/base/trace_event/OWNERS4
-rw-r--r--chromium/base/trace_event/etw_manifest/BUILD.gn48
-rw-r--r--chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py16
-rw-r--r--chromium/base/trace_event/etw_manifest/chrome_events_win.man84
-rw-r--r--chromium/base/trace_event/etw_manifest/etw_manifest.gyp41
-rw-r--r--chromium/base/trace_event/java_heap_dump_provider_android.cc43
-rw-r--r--chromium/base/trace_event/java_heap_dump_provider_android.h34
-rw-r--r--chromium/base/trace_event/java_heap_dump_provider_android_unittest.cc21
-rw-r--r--chromium/base/trace_event/malloc_dump_provider.cc52
-rw-r--r--chromium/base/trace_event/malloc_dump_provider.h36
-rw-r--r--chromium/base/trace_event/memory_allocator_dump.cc119
-rw-r--r--chromium/base/trace_event/memory_allocator_dump.h82
-rw-r--r--chromium/base/trace_event/memory_allocator_dump_unittest.cc151
-rw-r--r--chromium/base/trace_event/memory_dump_manager.cc405
-rw-r--r--chromium/base/trace_event/memory_dump_manager.h170
-rw-r--r--chromium/base/trace_event/memory_dump_manager_unittest.cc276
-rw-r--r--chromium/base/trace_event/memory_dump_provider.h36
-rw-r--r--chromium/base/trace_event/memory_dump_request_args.h41
-rw-r--r--chromium/base/trace_event/memory_dump_session_state.cc17
-rw-r--r--chromium/base/trace_event/memory_dump_session_state.h31
-rw-r--r--chromium/base/trace_event/process_memory_dump.cc59
-rw-r--r--chromium/base/trace_event/process_memory_dump.h94
-rw-r--r--chromium/base/trace_event/process_memory_maps.cc53
-rw-r--r--chromium/base/trace_event/process_memory_maps.h58
-rw-r--r--chromium/base/trace_event/process_memory_maps_dump_provider.cc189
-rw-r--r--chromium/base/trace_event/process_memory_maps_dump_provider.h42
-rw-r--r--chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc175
-rw-r--r--chromium/base/trace_event/process_memory_totals.cc20
-rw-r--r--chromium/base/trace_event/process_memory_totals.h36
-rw-r--r--chromium/base/trace_event/process_memory_totals_dump_provider.cc60
-rw-r--r--chromium/base/trace_event/process_memory_totals_dump_provider.h44
-rw-r--r--chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc43
-rw-r--r--chromium/base/trace_event/trace_event.gypi70
-rw-r--r--chromium/base/trace_event/trace_event.h (renamed from chromium/base/debug/trace_event.h)244
-rw-r--r--chromium/base/trace_event/trace_event_android.cc (renamed from chromium/base/debug/trace_event_android.cc)23
-rw-r--r--chromium/base/trace_event/trace_event_argument.cc (renamed from chromium/base/debug/trace_event_argument.cc)14
-rw-r--r--chromium/base/trace_event/trace_event_argument.h (renamed from chromium/base/debug/trace_event_argument.h)16
-rw-r--r--chromium/base/trace_event/trace_event_argument_unittest.cc (renamed from chromium/base/debug/trace_event_argument_unittest.cc)6
-rw-r--r--chromium/base/trace_event/trace_event_etw_export_win.cc251
-rw-r--r--chromium/base/trace_event/trace_event_etw_export_win.h75
-rw-r--r--chromium/base/trace_event/trace_event_impl.cc (renamed from chromium/base/debug/trace_event_impl.cc)253
-rw-r--r--chromium/base/trace_event/trace_event_impl.h (renamed from chromium/base/debug/trace_event_impl.h)59
-rw-r--r--chromium/base/trace_event/trace_event_impl_constants.cc (renamed from chromium/base/debug/trace_event_impl_constants.cc)6
-rw-r--r--chromium/base/trace_event/trace_event_memory.cc (renamed from chromium/base/debug/trace_event_memory.cc)49
-rw-r--r--chromium/base/trace_event/trace_event_memory.h (renamed from chromium/base/debug/trace_event_memory.h)31
-rw-r--r--chromium/base/trace_event/trace_event_memory_unittest.cc (renamed from chromium/base/debug/trace_event_memory_unittest.cc)20
-rw-r--r--chromium/base/trace_event/trace_event_synthetic_delay.cc (renamed from chromium/base/debug/trace_event_synthetic_delay.cc)20
-rw-r--r--chromium/base/trace_event/trace_event_synthetic_delay.h (renamed from chromium/base/debug/trace_event_synthetic_delay.h)16
-rw-r--r--chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc (renamed from chromium/base/debug/trace_event_synthetic_delay_unittest.cc)10
-rw-r--r--chromium/base/trace_event/trace_event_system_stats_monitor.cc (renamed from chromium/base/debug/trace_event_system_stats_monitor.cc)12
-rw-r--r--chromium/base/trace_event/trace_event_system_stats_monitor.h (renamed from chromium/base/debug/trace_event_system_stats_monitor.h)14
-rw-r--r--chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc (renamed from chromium/base/debug/trace_event_system_stats_monitor_unittest.cc)14
-rw-r--r--chromium/base/trace_event/trace_event_unittest.cc (renamed from chromium/base/debug/trace_event_unittest.cc)116
-rw-r--r--chromium/base/trace_event/trace_event_win.cc (renamed from chromium/base/debug/trace_event_win.cc)7
-rw-r--r--chromium/base/trace_event/trace_event_win.h (renamed from chromium/base/debug/trace_event_win.h)12
-rw-r--r--chromium/base/trace_event/trace_event_win_unittest.cc (renamed from chromium/base/debug/trace_event_win_unittest.cc)14
-rw-r--r--chromium/base/trace_event/winheap_dump_provider_win.cc99
-rw-r--r--chromium/base/trace_event/winheap_dump_provider_win.h52
-rw-r--r--chromium/base/trace_event/winheap_dump_provider_win_unittest.cc27
-rw-r--r--chromium/base/tracked_objects.cc570
-rw-r--r--chromium/base/tracked_objects.h401
-rw-r--r--chromium/base/tracked_objects_unittest.cc968
-rw-r--r--chromium/base/tracking_info.cc2
-rw-r--r--chromium/base/tracking_info.h11
-rw-r--r--chromium/base/tuple.h1369
-rw-r--r--chromium/base/tuple_unittest.cc68
-rw-r--r--chromium/base/value_conversions.h2
-rw-r--r--chromium/base/values.cc65
-rw-r--r--chromium/base/values.h36
-rw-r--r--chromium/base/values_unittest.cc402
-rw-r--r--chromium/base/version.cc30
-rw-r--r--chromium/base/version.h5
-rw-r--r--chromium/base/version_unittest.cc51
-rw-r--r--chromium/base/vlog.cc7
-rw-r--r--chromium/base/win/enum_variant.h2
-rw-r--r--chromium/base/win/event_trace_consumer.h2
-rw-r--r--chromium/base/win/event_trace_consumer_unittest.cc12
-rw-r--r--chromium/base/win/event_trace_controller_unittest.cc12
-rw-r--r--chromium/base/win/iunknown_impl.h6
-rw-r--r--chromium/base/win/iunknown_impl_unittest.cc4
-rw-r--r--chromium/base/win/memory_pressure_monitor.cc254
-rw-r--r--chromium/base/win/memory_pressure_monitor.h144
-rw-r--r--chromium/base/win/memory_pressure_monitor_unittest.cc298
-rw-r--r--chromium/base/win/message_window.cc5
-rw-r--r--chromium/base/win/metro.cc35
-rw-r--r--chromium/base/win/metro.h6
-rw-r--r--chromium/base/win/object_watcher.cc8
-rw-r--r--chromium/base/win/object_watcher.h14
-rw-r--r--chromium/base/win/object_watcher_unittest.cc14
-rw-r--r--chromium/base/win/pe_image.cc59
-rw-r--r--chromium/base/win/pe_image.h13
-rw-r--r--chromium/base/win/pe_image_test.cc31
-rw-r--r--chromium/base/win/pe_image_unittest.cc230
-rw-r--r--chromium/base/win/registry.cc8
-rw-r--r--chromium/base/win/registry_unittest.cc4
-rw-r--r--chromium/base/win/resource_util.h6
-rw-r--r--chromium/base/win/scoped_bstr.h2
-rw-r--r--chromium/base/win/scoped_comptr.h3
-rw-r--r--chromium/base/win/scoped_comptr_unittest.cc30
-rw-r--r--chromium/base/win/scoped_handle.cc194
-rw-r--r--chromium/base/win/scoped_handle.h2
-rw-r--r--chromium/base/win/scoped_hdc.h2
-rw-r--r--chromium/base/win/scoped_process_information.cc49
-rw-r--r--chromium/base/win/scoped_process_information_unittest.cc9
-rw-r--r--chromium/base/win/scoped_propvariant.h3
-rw-r--r--chromium/base/win/scoped_variant.h6
-rw-r--r--chromium/base/win/scoped_variant_unittest.cc96
-rw-r--r--chromium/base/win/shortcut.cc29
-rw-r--r--chromium/base/win/shortcut.h6
-rw-r--r--chromium/base/win/shortcut_unittest.cc2
-rw-r--r--chromium/base/win/startup_information.h5
-rw-r--r--chromium/base/win/win_util.cc94
-rw-r--r--chromium/base/win/win_util_unittest.cc6
-rw-r--r--chromium/base/win/windows_version.cc4
-rw-r--r--chromium/base/win/windows_version.h3
695 files changed, 23322 insertions, 21464 deletions
diff --git a/chromium/base/BUILD.gn b/chromium/base/BUILD.gn
index a0cdf662285..de282cfe35d 100644
--- a/chromium/base/BUILD.gn
+++ b/chromium/base/BUILD.gn
@@ -3,25 +3,75 @@
# found in the LICENSE file.
import("//build/config/ui.gni")
+import("//testing/test.gni")
if (is_android) {
import("//build/config/android/rules.gni")
}
+config("base_implementation") {
+ defines = [ "BASE_IMPLEMENTATION" ]
+}
+
+if (is_win) {
+ # This is in a separate config so the flags can be applied to dependents.
+ # ldflags in GN aren't automatically inherited.
+ config("base_win_linker_flags") {
+ ldflags = [
+ "/DELAYLOAD:cfgmgr32.dll",
+ "/DELAYLOAD:powrprof.dll",
+ "/DELAYLOAD:setupapi.dll",
+ ]
+ }
+}
+
+source_set("base_paths") {
+ sources = [
+ "base_paths.cc",
+ "base_paths.h",
+ "base_paths_android.cc",
+ "base_paths_android.h",
+ "base_paths_mac.h",
+ "base_paths_mac.mm",
+ "base_paths_posix.cc",
+ "base_paths_posix.h",
+ "base_paths_win.cc",
+ "base_paths_win.h",
+ ]
+
+ if (is_android || is_mac) {
+ sources -= [ "base_paths_posix.cc" ]
+ }
+
+ if (is_nacl) {
+ sources -= [
+ "base_paths.cc",
+ "base_paths_posix.cc",
+ ]
+ }
+
+ configs += [ ":base_implementation" ]
+
+ deps = [
+ "//base/memory",
+ "//base/process",
+ ]
+
+ visibility = [ ":base" ]
+}
+
component("base") {
sources = [
- "third_party/dmg_fp/dmg_fp.h",
- "third_party/dmg_fp/g_fmt.cc",
- "third_party/dmg_fp/dtoa_wrapper.cc",
- "third_party/icu/icu_utf.cc",
- "third_party/icu/icu_utf.h",
- "third_party/superfasthash/superfasthash.c",
"allocator/allocator_extension.cc",
"allocator/allocator_extension.h",
"allocator/type_profiler_control.cc",
"allocator/type_profiler_control.h",
+ "android/animation_frame_time_histogram.cc",
+ "android/animation_frame_time_histogram.h",
"android/application_status_listener.cc",
"android/application_status_listener.h",
+ "android/base_jni_onload.cc",
+ "android/base_jni_onload.h",
"android/base_jni_registrar.cc",
"android/base_jni_registrar.h",
"android/build_info.cc",
@@ -39,10 +89,10 @@ component("base") {
"android/fifo_utils.h",
"android/important_file_writer_android.cc",
"android/important_file_writer_android.h",
- "android/locale_utils.cc",
- "android/locale_utils.h",
- "android/scoped_java_ref.cc",
- "android/scoped_java_ref.h",
+ "android/java_handler_thread.cc",
+ "android/java_handler_thread.h",
+ "android/java_runtime.cc",
+ "android/java_runtime.h",
"android/jni_android.cc",
"android/jni_android.h",
"android/jni_array.cc",
@@ -55,17 +105,25 @@ component("base") {
"android/jni_utils.h",
"android/jni_weak_ref.cc",
"android/jni_weak_ref.h",
+ "android/library_loader/library_load_from_apk_status_codes.h",
"android/library_loader/library_loader_hooks.cc",
"android/library_loader/library_loader_hooks.h",
- "android/library_loader/library_load_from_apk_status_codes.h",
+ "android/library_loader/library_prefetcher.cc",
+ "android/library_loader/library_prefetcher.h",
+ "android/locale_utils.cc",
+ "android/locale_utils.h",
"android/memory_pressure_listener_android.cc",
"android/memory_pressure_listener_android.h",
- "android/java_handler_thread.cc",
- "android/java_handler_thread.h",
"android/path_service_android.cc",
"android/path_service_android.h",
"android/path_utils.cc",
"android/path_utils.h",
+ "android/record_histogram.cc",
+ "android/record_histogram.h",
+ "android/record_user_action.cc",
+ "android/record_user_action.h",
+ "android/scoped_java_ref.cc",
+ "android/scoped_java_ref.h",
"android/sys_utils.cc",
"android/sys_utils.h",
"android/thread_utils.h",
@@ -88,20 +146,10 @@ component("base") {
"auto_reset.h",
"barrier_closure.cc",
"barrier_closure.h",
- "base_export.h",
- "base_paths.cc",
- "base_paths.h",
- "base_paths_android.cc",
- "base_paths_android.h",
- "base_paths_mac.h",
- "base_paths_mac.mm",
- "base_paths_posix.cc",
- "base_paths_posix.h",
- "base_paths_win.cc",
- "base_paths_win.h",
- "base_switches.h",
"base64.cc",
"base64.h",
+ "base_export.h",
+ "base_switches.h",
"basictypes.h",
"big_endian.cc",
"big_endian.h",
@@ -119,6 +167,8 @@ component("base") {
"callback_internal.cc",
"callback_internal.h",
"cancelable_callback.h",
+ "chromeos/memory_pressure_monitor.cc",
+ "chromeos/memory_pressure_monitor.h",
"command_line.cc",
"command_line.h",
"compiler_specific.h",
@@ -126,63 +176,17 @@ component("base") {
"containers/hash_tables.h",
"containers/linked_list.h",
"containers/mru_cache.h",
+ "containers/scoped_ptr_hash_map.h",
"containers/small_map.h",
"containers/stack_container.h",
"cpu.cc",
"cpu.h",
"critical_closure.h",
"critical_closure_internal_ios.mm",
- "debug/alias.cc",
- "debug/alias.h",
- "debug/asan_invalid_access.cc",
- "debug/asan_invalid_access.h",
- "debug/crash_logging.cc",
- "debug/crash_logging.h",
- "debug/debugger.cc",
- "debug/debugger.h",
- "debug/debugger_posix.cc",
- "debug/debugger_win.cc",
- "debug/dump_without_crashing.cc",
- "debug/dump_without_crashing.h",
- "debug/gdi_debug_util_win.cc",
- "debug/gdi_debug_util_win.h",
- # This file depends on files from the "allocator" target,
- # but this target does not depend on "allocator" (see
- # allocator.gyp for details).
- "debug/leak_annotations.h",
- "debug/leak_tracker.h",
- "debug/proc_maps_linux.cc",
- "debug/proc_maps_linux.h",
- "debug/profiler.cc",
- "debug/profiler.h",
- "debug/stack_trace.cc",
- "debug/stack_trace.h",
- "debug/stack_trace_android.cc",
- "debug/stack_trace_posix.cc",
- "debug/stack_trace_win.cc",
- "debug/task_annotator.cc",
- "debug/task_annotator.h",
- "debug/trace_event.h",
- "debug/trace_event_android.cc",
- "debug/trace_event_argument.cc",
- "debug/trace_event_argument.h",
- "debug/trace_event_impl.cc",
- "debug/trace_event_impl.h",
- "debug/trace_event_impl_constants.cc",
- "debug/trace_event_memory.cc",
- "debug/trace_event_memory.h",
- "debug/trace_event_synthetic_delay.cc",
- "debug/trace_event_synthetic_delay.h",
- "debug/trace_event_system_stats_monitor.cc",
- "debug/trace_event_system_stats_monitor.h",
- "debug/trace_event_win.cc",
"deferred_sequenced_task_runner.cc",
"deferred_sequenced_task_runner.h",
"environment.cc",
"environment.h",
- "event_recorder.h",
- "event_recorder_stubs.cc",
- "event_recorder_win.cc",
"file_descriptor_posix.h",
"file_version_info.h",
"file_version_info_mac.h",
@@ -193,8 +197,6 @@ component("base") {
"files/dir_reader_linux.h",
"files/dir_reader_posix.h",
"files/file.cc",
- "files/file_posix.cc",
- "files/file_win.cc",
"files/file_enumerator.cc",
"files/file_enumerator.h",
"files/file_enumerator_posix.cc",
@@ -211,8 +213,11 @@ component("base") {
"files/file_path_watcher_linux.cc",
"files/file_path_watcher_mac.cc",
"files/file_path_watcher_win.cc",
+ "files/file_posix.cc",
"files/file_proxy.cc",
"files/file_proxy.h",
+ "files/file_tracing.cc",
+ "files/file_tracing.h",
"files/file_util.cc",
"files/file_util.h",
"files/file_util_android.cc",
@@ -222,6 +227,7 @@ component("base") {
"files/file_util_proxy.cc",
"files/file_util_proxy.h",
"files/file_util_win.cc",
+ "files/file_win.cc",
"files/important_file_writer.cc",
"files/important_file_writer.h",
"files/memory_mapped_file.cc",
@@ -232,7 +238,6 @@ component("base") {
"files/scoped_file.h",
"files/scoped_temp_dir.cc",
"files/scoped_temp_dir.h",
- "float_util.h",
"format_macros.h",
"gtest_prod_util.h",
"guid.cc",
@@ -248,19 +253,8 @@ component("base") {
"ios/ios_util.mm",
"ios/scoped_critical_action.h",
"ios/scoped_critical_action.mm",
- "json/json_file_value_serializer.cc",
- "json/json_file_value_serializer.h",
- "json/json_parser.cc",
- "json/json_parser.h",
- "json/json_reader.cc",
- "json/json_reader.h",
- "json/json_string_value_serializer.cc",
- "json/json_string_value_serializer.h",
- "json/json_value_converter.h",
- "json/json_writer.cc",
- "json/json_writer.h",
- "json/string_escape.cc",
- "json/string_escape.h",
+ "ios/weak_nsobject.h",
+ "ios/weak_nsobject.mm",
"lazy_instance.cc",
"lazy_instance.h",
"linux_util.cc",
@@ -277,6 +271,8 @@ component("base") {
"mac/bundle_locations.h",
"mac/bundle_locations.mm",
"mac/cocoa_protocols.h",
+ "mac/dispatch_source_mach.cc",
+ "mac/dispatch_source_mach.h",
"mac/foundation_util.h",
"mac/foundation_util.mm",
"mac/launch_services_util.cc",
@@ -285,12 +281,14 @@ component("base") {
"mac/launchd.h",
"mac/libdispatch_task_runner.cc",
"mac/libdispatch_task_runner.h",
- "mac/mac_logging.h",
"mac/mac_logging.cc",
+ "mac/mac_logging.h",
"mac/mac_util.h",
"mac/mac_util.mm",
"mac/mach_logging.cc",
"mac/mach_logging.h",
+ "mac/memory_pressure_monitor.cc",
+ "mac/memory_pressure_monitor.h",
"mac/objc_property_releaser.h",
"mac/objc_property_releaser.mm",
"mac/os_crash_dumps.cc",
@@ -316,50 +314,10 @@ component("base") {
"mac/scoped_sending_event.h",
"mac/scoped_sending_event.mm",
"mac/sdk_forward_declarations.h",
+ "mac/sdk_forward_declarations.mm",
"macros.h",
"md5.cc",
"md5.h",
- "memory/aligned_memory.cc",
- "memory/aligned_memory.h",
- "memory/discardable_memory.cc",
- "memory/discardable_memory.h",
- "memory/discardable_memory_android.cc",
- "memory/discardable_memory_emulated.cc",
- "memory/discardable_memory_emulated.h",
- "memory/discardable_memory_linux.cc",
- "memory/discardable_memory_mac.cc",
- "memory/discardable_memory_manager.cc",
- "memory/discardable_memory_manager.h",
- "memory/discardable_memory_shmem.cc",
- "memory/discardable_memory_shmem.h",
- "memory/discardable_memory_shmem_allocator.cc",
- "memory/discardable_memory_shmem_allocator.h",
- "memory/discardable_memory_win.cc",
- "memory/discardable_shared_memory.cc",
- "memory/discardable_shared_memory.h",
- "memory/linked_ptr.h",
- "memory/manual_constructor.h",
- "memory/memory_pressure_listener.cc",
- "memory/memory_pressure_listener.h",
- "memory/raw_scoped_refptr_mismatch_checker.h",
- "memory/ref_counted.cc",
- "memory/ref_counted.h",
- "memory/ref_counted_delete_on_message_loop.h",
- "memory/ref_counted_memory.cc",
- "memory/ref_counted_memory.h",
- "memory/scoped_open_process.h",
- "memory/scoped_policy.h",
- "memory/scoped_ptr.h",
- "memory/scoped_vector.h",
- "memory/shared_memory.h",
- "memory/shared_memory_android.cc",
- "memory/shared_memory_nacl.cc",
- "memory/shared_memory_posix.cc",
- "memory/shared_memory_win.cc",
- "memory/singleton.cc",
- "memory/singleton.h",
- "memory/weak_ptr.cc",
- "memory/weak_ptr.h",
"message_loop/incoming_task_queue.cc",
"message_loop/incoming_task_queue.h",
"message_loop/message_loop.cc",
@@ -384,49 +342,20 @@ component("base") {
"message_loop/message_pump_mac.mm",
"message_loop/message_pump_win.cc",
"message_loop/message_pump_win.h",
- "metrics/field_trial.cc",
- "metrics/field_trial.h",
- "metrics/sample_map.cc",
- "metrics/sample_map.h",
- "metrics/sample_vector.cc",
- "metrics/sample_vector.h",
- "metrics/bucket_ranges.cc",
- "metrics/bucket_ranges.h",
- "metrics/histogram.cc",
- "metrics/histogram.h",
- "metrics/histogram_base.cc",
- "metrics/histogram_base.h",
- "metrics/histogram_delta_serialization.cc",
- "metrics/histogram_delta_serialization.",
- "metrics/histogram_flattener.h",
- "metrics/histogram_samples.cc",
- "metrics/histogram_samples.h",
- "metrics/histogram_snapshot_manager.cc",
- "metrics/histogram_snapshot_manager.h",
- "metrics/sparse_histogram.cc",
- "metrics/sparse_histogram.h",
- "metrics/statistics_recorder.cc",
- "metrics/statistics_recorder.h",
- "metrics/stats_counters.cc",
- "metrics/stats_counters.h",
- "metrics/stats_table.cc",
- "metrics/stats_table.h",
- "metrics/user_metrics.cc",
- "metrics/user_metrics.h",
- "metrics/user_metrics_action.h",
"move.h",
"native_library.h",
+ "native_library_ios.mm",
"native_library_mac.mm",
"native_library_posix.cc",
"native_library_win.cc",
- "numerics/safe_conversions.h",
- "numerics/safe_conversions_impl.h",
- "numerics/safe_math.h",
- "numerics/safe_math_impl.h",
"nix/mime_util_xdg.cc",
"nix/mime_util_xdg.h",
"nix/xdg_util.cc",
"nix/xdg_util.h",
+ "numerics/safe_conversions.h",
+ "numerics/safe_conversions_impl.h",
+ "numerics/safe_math.h",
+ "numerics/safe_math_impl.h",
"observer_list.h",
"observer_list_threadsafe.h",
"os_compat_android.cc",
@@ -460,60 +389,18 @@ component("base") {
"power_monitor/power_monitor_source.cc",
"power_monitor/power_monitor_source.h",
"power_monitor/power_observer.h",
- "process/internal_linux.cc",
- "process/internal_linux.h",
- "process/kill.cc",
- "process/kill.h",
- "process/kill_mac.cc",
- "process/kill_posix.cc",
- "process/kill_win.cc",
- "process/launch.cc",
- "process/launch.h",
- "process/launch_ios.cc",
- "process/launch_mac.cc",
- "process/launch_posix.cc",
- "process/launch_win.cc",
- "process/memory.cc",
- "process/memory.h",
- "process/memory_linux.cc",
- "process/memory_mac.mm",
- "process/memory_win.cc",
- "process/process.h",
- "process/process_handle_freebsd.cc",
- "process/process_handle_linux.cc",
- "process/process_handle_mac.cc",
- "process/process_handle_openbsd.cc",
- "process/process_handle_posix.cc",
- "process/process_handle_win.cc",
- "process/process_info.h",
- "process/process_info_linux.cc",
- "process/process_info_mac.cc",
- "process/process_info_win.cc",
- "process/process_iterator.cc",
- "process/process_iterator.h",
- "process/process_iterator_freebsd.cc",
- "process/process_iterator_linux.cc",
- "process/process_iterator_mac.cc",
- "process/process_iterator_openbsd.cc",
- "process/process_iterator_win.cc",
- "process/process_linux.cc",
- "process/process_metrics.cc",
- "process/process_metrics.h",
- "process/process_metrics_freebsd.cc",
- "process/process_metrics_ios.cc",
- "process/process_metrics_linux.cc",
- "process/process_metrics_mac.cc",
- "process/process_metrics_openbsd.cc",
- "process/process_metrics_posix.cc",
- "process/process_metrics_win.cc",
- "process/process_posix.cc",
- "process/process_win.cc",
"profiler/alternate_timer.cc",
"profiler/alternate_timer.h",
+ "profiler/native_stack_sampler.cc",
+ "profiler/native_stack_sampler.h",
"profiler/scoped_profile.cc",
"profiler/scoped_profile.h",
"profiler/scoped_tracker.cc",
"profiler/scoped_tracker.h",
+ "profiler/stack_sampling_profiler.cc",
+ "profiler/stack_sampling_profiler.h",
+ "profiler/stack_sampling_profiler_posix.cc",
+ "profiler/stack_sampling_profiler_win.cc",
"profiler/tracked_time.cc",
"profiler/tracked_time.h",
"rand_util.cc",
@@ -549,11 +436,11 @@ component("base") {
"strings/string16.cc",
"strings/string16.h",
"strings/string_number_conversions.cc",
- "strings/string_split.cc",
- "strings/string_split.h",
"strings/string_number_conversions.h",
"strings/string_piece.cc",
"strings/string_piece.h",
+ "strings/string_split.cc",
+ "strings/string_split.h",
"strings/string_tokenizer.h",
"strings/string_util.cc",
"strings/string_util.h",
@@ -595,8 +482,6 @@ component("base") {
"synchronization/waitable_event_watcher_posix.cc",
"synchronization/waitable_event_watcher_win.cc",
"synchronization/waitable_event_win.cc",
- "system_monitor/system_monitor.cc",
- "system_monitor/system_monitor.h",
"sys_byteorder.h",
"sys_info.cc",
"sys_info.h",
@@ -609,12 +494,22 @@ component("base") {
"sys_info_openbsd.cc",
"sys_info_posix.cc",
"sys_info_win.cc",
+ "system_monitor/system_monitor.cc",
+ "system_monitor/system_monitor.h",
"task/cancelable_task_tracker.cc",
"task/cancelable_task_tracker.h",
"task_runner.cc",
"task_runner.h",
"task_runner_util.h",
"template_util.h",
+ "third_party/dmg_fp/dmg_fp.h",
+ "third_party/dmg_fp/dtoa_wrapper.cc",
+ "third_party/dmg_fp/g_fmt.cc",
+ "third_party/icu/icu_utf.cc",
+ "third_party/icu/icu_utf.h",
+ "third_party/nspr/prtime.cc",
+ "third_party/nspr/prtime.h",
+ "third_party/superfasthash/superfasthash.c",
"thread_task_runner_handle.cc",
"thread_task_runner_handle.h",
"threading/non_thread_safe.h",
@@ -622,6 +517,8 @@ component("base") {
"threading/non_thread_safe_impl.h",
"threading/platform_thread.h",
"threading/platform_thread_android.cc",
+ "threading/platform_thread_internal_posix.cc",
+ "threading/platform_thread_internal_posix.h",
"threading/platform_thread_linux.cc",
"threading/platform_thread_mac.mm",
"threading/platform_thread_posix.cc",
@@ -649,12 +546,12 @@ component("base") {
"threading/thread_local_storage_posix.cc",
"threading/thread_local_storage_win.cc",
"threading/thread_local_win.cc",
- "threading/thread_restrictions.h",
"threading/thread_restrictions.cc",
+ "threading/thread_restrictions.h",
"threading/watchdog.cc",
"threading/watchdog.h",
- "threading/worker_pool.h",
"threading/worker_pool.cc",
+ "threading/worker_pool.h",
"threading/worker_pool_posix.cc",
"threading/worker_pool_posix.h",
"threading/worker_pool_win.cc",
@@ -685,10 +582,10 @@ component("base") {
"tracking_info.cc",
"tracking_info.h",
"tuple.h",
- "values.cc",
- "values.h",
"value_conversions.cc",
"value_conversions.h",
+ "values.cc",
+ "values.h",
"version.cc",
"version.h",
"vlog.cc",
@@ -706,6 +603,8 @@ component("base") {
"win/iat_patch_function.h",
"win/iunknown_impl.cc",
"win/iunknown_impl.h",
+ "win/memory_pressure_monitor.cc",
+ "win/memory_pressure_monitor.h",
"win/message_window.cc",
"win/message_window.h",
"win/metro.cc",
@@ -744,55 +643,43 @@ component("base") {
"win/wrapped_window_proc.h",
]
- if (is_nacl) {
- sources += [ "files/file_path_watcher_stub.cc" ]
- }
-
sources -= [
- "process/process_handle_freebsd.cc",
- "process/process_handle_openbsd.cc",
- "process/process_iterator_freebsd.cc",
- "process/process_iterator_openbsd.cc",
- "process/process_metrics_freebsd.cc",
- "process/process_metrics_openbsd.cc",
"sys_info_freebsd.cc",
"sys_info_openbsd.cc",
]
- defines = [
- "BASE_IMPLEMENTATION",
- ]
+ configs += [ ":base_implementation" ]
deps = [
":base_static",
"//base/allocator:allocator_extension_thunks",
"//base/third_party/dynamic_annotations",
- "//base/third_party/nspr",
"//third_party/modp_b64",
]
+ public_deps = [
+ ":base_paths",
+ "//base/debug",
+ "//base/json",
+ "//base/memory",
+ "//base/metrics",
+ "//base/process",
+ "//base/trace_event",
+ ]
+
+ # Allow more direct string conversions on platforms with native utf8
+ # strings
+ if (is_mac || is_ios || is_chromeos) {
+ defines = [ "SYSTEM_NATIVE_UTF8" ]
+ }
+
if (is_android) {
- sources += [
- "memory/discardable_memory_ashmem_allocator.cc",
- "memory/discardable_memory_ashmem_allocator.h",
- "memory/discardable_memory_ashmem.cc",
- "memory/discardable_memory_ashmem.h",
- ]
- sources -= [
- "base_paths_posix.cc",
- "power_monitor/power_monitor_device_source_posix.cc",
- ]
+ sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
# Android uses some Linux sources, put those back.
set_sources_assignment_filter([])
sources += [
- "debug/proc_maps_linux.cc",
"files/file_path_watcher_linux.cc",
- "process/memory_linux.cc",
- "process/internal_linux.cc",
- "process/process_handle_linux.cc",
- "process/process_iterator_linux.cc",
- "process/process_metrics_linux.cc",
"posix/unix_domain_socket_linux.cc",
"sys_info_linux.cc",
]
@@ -801,64 +688,72 @@ component("base") {
deps += [
":base_jni_headers",
"//third_party/ashmem",
- "//third_party/android_tools:cpu_features"
+ "//third_party/android_tools:cpu_features",
]
# logging.cc uses the Android logging library.
libs = [ "log" ]
-
- sources -= [
- "debug/stack_trace_posix.cc",
- ]
}
if (is_chromeos) {
- sources -= [
- "power_monitor/power_monitor_device_source_posix.cc",
- ]
+ sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
}
if (is_nacl) {
- # These things would otherwise be built on a Posix build but aren't
- # supported on NaCl.
+ # We reset sources_assignment_filter in order to explicitly include
+ # the linux file (which would otherwise be filtered out).
+ set_sources_assignment_filter([])
+ sources += [
+ "files/file_path_watcher_stub.cc",
+ "sync_socket_nacl.cc",
+ "threading/platform_thread_linux.cc",
+ ]
+ set_sources_assignment_filter(sources_assignment_filter)
+
sources -= [
- "debug/stack_trace_posix.cc",
+ "allocator/type_profiler_control.cc",
+ "allocator/type_profiler_control.h",
+ "async_socket_io_handler_posix.cc",
+ "cpu.cc",
"files/file_enumerator_posix.cc",
+ "files/file_proxy.cc",
+ "files/file_util.cc",
"files/file_util_posix.cc",
+ "files/file_util_proxy.cc",
+ "files/important_file_writer.cc",
+ "files/important_file_writer.h",
+ "files/scoped_temp_dir.cc",
"message_loop/message_pump_libevent.cc",
- "process/kill_posix.cc",
- "process/launch_posix.cc",
- "process/process_metrics_posix.cc",
- "process/process_posix.cc",
- "metrics/field_trial.cc",
"native_library_posix.cc",
- "memory/shared_memory_posix.cc",
+ "path_service.cc",
+ "rand_util_posix.cc",
+ "scoped_native_library.cc",
"sync_socket_posix.cc",
+ "sys_info.cc",
"sys_info_posix.cc",
]
} else {
- # Remove nacl stuff.
+ # Remove NaCl stuff.
sources -= [
"os_compat_nacl.cc",
"os_compat_nacl.h",
"rand_util_nacl.cc",
- "memory/shared_memory_nacl.cc",
]
}
# Windows.
if (is_win) {
sources -= [
- "event_recorder_stubs.cc",
"message_loop/message_pump_libevent.cc",
"strings/string16.cc",
+
# Not using sha1_win.cc because it may have caused a
# regression to page cycler moz.
"sha1_win.cc",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
libs = [
"cfgmgr32.lib",
@@ -866,11 +761,7 @@ component("base") {
"powrprof.lib",
"setupapi.lib",
]
- ldflags = [
- "/DELAYLOAD:cfgmgr32.dll",
- "/DELAYLOAD:powrprof.dll",
- "/DELAYLOAD:setupapi.dll",
- ]
+ all_dependent_configs = [ ":base_win_linker_flags" ]
} else if (!is_nacl) {
# Non-Windows.
deps += [ "//third_party/libevent" ]
@@ -878,16 +769,11 @@ component("base") {
# Mac.
if (is_mac) {
- sources += [
- "memory/discardable_memory_mach.cc",
- "memory/discardable_memory_mach.h",
- ]
sources -= [
- "base_paths_posix.cc",
"native_library_posix.cc",
"strings/sys_string_conversions_posix.cc",
+ "threading/platform_thread_internal_posix.cc",
]
- deps += [ "//third_party/mach_override" ]
} else {
# Non-Mac.
sources -= [
@@ -901,19 +787,17 @@ component("base") {
# Linux.
if (is_linux) {
# TODO(brettw) this will need to be parameterized at some point.
- linux_configs = [
- "//build/config/linux:glib",
- ]
+ linux_configs = []
+ if (use_glib) {
+ linux_configs += [ "//build/config/linux:glib" ]
+ }
configs += linux_configs
all_dependent_configs = linux_configs
- defines += [ "USE_SYMBOLIZE" ]
-
# These dependencies are not required on Android, and in the case
# of xdg_mime must be excluded due to licensing restrictions.
deps += [
- "//base/third_party/symbolize",
"//base/third_party/xdg_mime",
"//base/third_party/xdg_user_dirs",
]
@@ -946,6 +830,8 @@ component("base") {
configs -= [ "//build/config/compiler:optimize" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
+
+ allow_circular_includes_from = public_deps
}
# This is the subset of files from base that should not be used with a dynamic
@@ -1017,13 +903,68 @@ component("i18n") {
configs += [ "//build/config/compiler:optimize_max" ]
}
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+}
+
+if (is_win || (is_linux && !is_chromeos)) {
+ # TODO(GYP): Figure out which of these work and are needed on other platforms.
+ test("base_perftests") {
+ sources = [
+ "message_loop/message_pump_perftest.cc",
+
+ # "test/run_all_unittests.cc",
+ "threading/thread_perftest.cc",
+ ]
+ deps = [
+ ":base",
+ "//base/test:test_support",
+ "//base/test:test_support_perf",
+ "//testing/perf",
+ "//testing/gtest",
+ ]
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_native_code" ]
+ }
+ }
+
+ test("base_i18n_perftests") {
+ sources = [
+ "i18n/streaming_utf8_validator_perftest.cc",
+ ]
+ deps = [
+ ":base",
+ ":i18n",
+ "//base/test:test_support",
+ "//base/test:test_support_perf",
+ "//testing/gtest",
+ ]
+ }
+
+ if (!is_ios) {
+ executable("build_utf8_validator_tables") {
+ sources = [
+ "i18n/build_utf8_validator_tables.cc",
+ ]
+ deps = [
+ ":base",
+ "//third_party/icu:icuuc",
+ ]
+ }
+
+ executable("check_example") {
+ sources = [
+ "check_example.cc",
+ ]
+ deps = [
+ ":base",
+ ]
+ }
}
}
-source_set("prefs") {
+component("prefs") {
sources = [
"prefs/base_prefs_export.h",
"prefs/default_pref_store.cc",
@@ -1065,7 +1006,9 @@ source_set("prefs") {
defines = [ "BASE_PREFS_IMPLEMENTATION" ]
- deps = [ ":base" ]
+ deps = [
+ ":base",
+ ]
if (is_android && !is_debug) {
configs -= [ "//build/config/compiler:optimize" ]
@@ -1086,9 +1029,11 @@ source_set("prefs_test_support") {
"prefs/testing_pref_store.h",
]
+ public_deps = [
+ ":prefs",
+ ]
deps = [
":base",
- ":prefs",
"//testing/gmock",
"//testing/gtest",
]
@@ -1107,12 +1052,33 @@ source_set("message_loop_tests") {
]
}
+if (is_win) {
+ # Target to manually rebuild pe_image_test.dll which is checked into
+ # base/test/data/pe_image.
+ shared_library("pe_image_test") {
+ sources = [
+ "win/pe_image_test.cc",
+ ]
+ ldflags = [
+ "/DELAYLOAD:cfgmgr32.dll",
+ "/DELAYLOAD:shell32.dll",
+ "/SUBSYSTEM:WINDOWS",
+ ]
+ libs = [
+ "cfgmgr32.lib",
+ "shell32.lib",
+ ]
+ }
+}
+
test("base_unittests") {
sources = [
"android/application_status_listener_unittest.cc",
+ "android/content_uri_utils_unittest.cc",
"android/jni_android_unittest.cc",
"android/jni_array_unittest.cc",
"android/jni_string_unittest.cc",
+ "android/library_loader/library_prefetcher_unittest.cc",
"android/path_utils_unittest.cc",
"android/scoped_java_ref_unittest.cc",
"android/sys_utils_unittest.cc",
@@ -1132,31 +1098,28 @@ test("base_unittests") {
"callback_unittest.cc",
"callback_unittest.nc",
"cancelable_callback_unittest.cc",
+ "chromeos/memory_pressure_monitor_unittest.cc",
"command_line_unittest.cc",
"containers/adapters_unittest.cc",
"containers/hash_tables_unittest.cc",
"containers/linked_list_unittest.cc",
"containers/mru_cache_unittest.cc",
+ "containers/scoped_ptr_hash_map_unittest.cc",
"containers/small_map_unittest.cc",
"containers/stack_container_unittest.cc",
"cpu_unittest.cc",
"debug/crash_logging_unittest.cc",
+ "debug/debugger_unittest.cc",
"debug/leak_tracker_unittest.cc",
"debug/proc_maps_linux_unittest.cc",
"debug/stack_trace_unittest.cc",
"debug/task_annotator_unittest.cc",
- "debug/trace_event_argument_unittest.cc",
- "debug/trace_event_memory_unittest.cc",
- "debug/trace_event_synthetic_delay_unittest.cc",
- "debug/trace_event_system_stats_monitor_unittest.cc",
- "debug/trace_event_unittest.cc",
- "debug/trace_event_unittest.h",
- "debug/trace_event_win_unittest.cc",
"deferred_sequenced_task_runner_unittest.cc",
"environment_unittest.cc",
"file_version_info_unittest.cc",
"files/dir_reader_posix_unittest.cc",
"files/file_path_unittest.cc",
+ "files/file_path_watcher_unittest.cc",
"files/file_proxy_unittest.cc",
"files/file_unittest.cc",
"files/file_util_proxy_unittest.cc",
@@ -1166,10 +1129,9 @@ test("base_unittests") {
"gmock_unittest.cc",
"guid_unittest.cc",
"hash_unittest.cc",
- "id_map_unittest.cc",
"i18n/break_iterator_unittest.cc",
- "i18n/char_iterator_unittest.cc",
"i18n/case_conversion_unittest.cc",
+ "i18n/char_iterator_unittest.cc",
"i18n/file_util_icu_unittest.cc",
"i18n/icu_string_conversions_unittest.cc",
"i18n/number_formatting_unittest.cc",
@@ -1178,7 +1140,9 @@ test("base_unittests") {
"i18n/string_search_unittest.cc",
"i18n/time_formatting_unittest.cc",
"i18n/timezone_unittest.cc",
+ "id_map_unittest.cc",
"ios/device_util_unittest.mm",
+ "ios/weak_nsobject_unittest.mm",
"json/json_parser_unittest.cc",
"json/json_reader_unittest.cc",
"json/json_value_converter_unittest.cc",
@@ -1188,6 +1152,7 @@ test("base_unittests") {
"lazy_instance_unittest.cc",
"logging_unittest.cc",
"mac/bind_objc_block_unittest.mm",
+ "mac/dispatch_source_mach_unittest.cc",
"mac/foundation_util_unittest.mm",
"mac/libdispatch_task_runner_unittest.cc",
"mac/mac_util_unittest.mm",
@@ -1197,8 +1162,6 @@ test("base_unittests") {
"mac/scoped_sending_event_unittest.mm",
"md5_unittest.cc",
"memory/aligned_memory_unittest.cc",
- "memory/discardable_memory_manager_unittest.cc",
- "memory/discardable_memory_unittest.cc",
"memory/discardable_shared_memory_unittest.cc",
"memory/linked_ptr_unittest.cc",
"memory/ref_counted_memory_unittest.cc",
@@ -1215,17 +1178,18 @@ test("base_unittests") {
"message_loop/message_loop_unittest.cc",
"message_loop/message_pump_glib_unittest.cc",
"message_loop/message_pump_io_ios_unittest.cc",
- "metrics/sample_map_unittest.cc",
- "metrics/sample_vector_unittest.cc",
"metrics/bucket_ranges_unittest.cc",
"metrics/field_trial_unittest.cc",
"metrics/histogram_base_unittest.cc",
"metrics/histogram_delta_serialization_unittest.cc",
"metrics/histogram_snapshot_manager_unittest.cc",
"metrics/histogram_unittest.cc",
+ "metrics/sample_map_unittest.cc",
+ "metrics/sample_vector_unittest.cc",
"metrics/sparse_histogram_unittest.cc",
- "metrics/stats_table_unittest.cc",
"metrics/statistics_recorder_unittest.cc",
+ "move_unittest.cc",
+ "numerics/safe_numerics_unittest.cc",
"observer_list_unittest.cc",
"os_compat_android_unittest.cc",
"path_service_unittest.cc",
@@ -1251,9 +1215,9 @@ test("base_unittests") {
"process/process_unittest.cc",
"process/process_util_unittest.cc",
"process/process_util_unittest_ios.cc",
+ "profiler/stack_sampling_profiler_unittest.cc",
"profiler/tracked_time_unittest.cc",
"rand_util_unittest.cc",
- "numerics/safe_numerics_unittest.cc",
"scoped_clear_errno_unittest.cc",
"scoped_generic_unittest.cc",
"scoped_native_library_unittest.cc",
@@ -1264,13 +1228,13 @@ test("base_unittests") {
"strings/nullable_string16_unittest.cc",
"strings/safe_sprintf_unittest.cc",
"strings/string16_unittest.cc",
- "strings/stringprintf_unittest.cc",
"strings/string_number_conversions_unittest.cc",
"strings/string_piece_unittest.cc",
"strings/string_split_unittest.cc",
"strings/string_tokenizer_unittest.cc",
"strings/string_util_unittest.cc",
"strings/stringize_macros_unittest.cc",
+ "strings/stringprintf_unittest.cc",
"strings/sys_string_conversions_mac_unittest.mm",
"strings/sys_string_conversions_unittest.cc",
"strings/utf_offset_string_conversions_unittest.cc",
@@ -1292,6 +1256,7 @@ test("base_unittests") {
"test/histogram_tester_unittest.cc",
"test/test_reg_util_win_unittest.cc",
"test/trace_event_analyzer_unittest.cc",
+ "test/user_action_tester_unittest.cc",
"threading/non_thread_safe_unittest.cc",
"threading/platform_thread_unittest.cc",
"threading/sequenced_worker_pool_unittest.cc",
@@ -1324,6 +1289,7 @@ test("base_unittests") {
"win/event_trace_provider_unittest.cc",
"win/i18n_unittest.cc",
"win/iunknown_impl_unittest.cc",
+ "win/memory_pressure_monitor_unittest.cc",
"win/message_window_unittest.cc",
"win/object_watcher_unittest.cc",
"win/pe_image_unittest.cc",
@@ -1348,14 +1314,27 @@ test("base_unittests") {
"//base/test:run_all_unittests",
"//base/test:test_support",
"//base/third_party/dynamic_annotations",
+ "//base/trace_event:trace_event_unittests",
"//testing/gmock",
"//testing/gtest",
"//third_party/icu",
]
+ # Allow more direct string conversions on platforms with native utf8
+ # strings
+ if (is_mac || is_ios || is_chromeos) {
+ defines = [ "SYSTEM_NATIVE_UTF8" ]
+ }
+
+ if (is_android) {
+ apk_deps = [
+ ":base_java",
+ ":base_java_unittest_support",
+ ]
+ }
+
if (is_ios) {
sources -= [
- "metrics/stats_table_uinittest.cc", # Requires spawning a process.
"process/memory_unittest.cc",
"process/memory_unittest_mac.h",
"process/memory_unittest_mac.mm",
@@ -1381,8 +1360,11 @@ test("base_unittests") {
if (is_linux) {
sources -= [ "file_version_info_unittest.cc" ]
sources += [ "nix/xdg_util_unittest.cc" ]
- defines = [ "USE_SYMBOLIZE" ]
- configs += [ "//build/config/linux:glib" ]
+ deps += [ "//base/test:malloc_wrapper" ]
+
+ if (use_glib) {
+ configs += [ "//build/config/linux:glib" ]
+ }
}
if (!is_linux || use_ozone) {
@@ -1395,19 +1377,21 @@ test("base_unittests") {
}
if (is_android) {
- deps += [
- "//testing/android:native_test_native_code",
- ]
+ deps += [ "//testing/android/native_test:native_test_native_code" ]
set_sources_assignment_filter([])
sources += [ "debug/proc_maps_linux_unittest.cc" ]
set_sources_assignment_filter(sources_assignment_filter)
}
+
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
if (is_android) {
# GYP: //base.gyp:base_jni_headers
generate_jni("base_jni_headers") {
sources = [
+ "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java",
"android/java/src/org/chromium/base/ApplicationStatus.java",
"android/java/src/org/chromium/base/BuildInfo.java",
"android/java/src/org/chromium/base/CommandLine.java",
@@ -1417,19 +1401,32 @@ if (is_android) {
"android/java/src/org/chromium/base/FieldTrialList.java",
"android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
"android/java/src/org/chromium/base/JNIUtils.java",
- "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
+ "android/java/src/org/chromium/base/JavaHandlerThread.java",
"android/java/src/org/chromium/base/LocaleUtils.java",
"android/java/src/org/chromium/base/MemoryPressureListener.java",
- "android/java/src/org/chromium/base/JavaHandlerThread.java",
"android/java/src/org/chromium/base/PathService.java",
"android/java/src/org/chromium/base/PathUtils.java",
"android/java/src/org/chromium/base/PowerMonitor.java",
- "android/java/src/org/chromium/base/SystemMessageHandler.java",
"android/java/src/org/chromium/base/SysUtils.java",
+ "android/java/src/org/chromium/base/SystemMessageHandler.java",
"android/java/src/org/chromium/base/ThreadUtils.java",
"android/java/src/org/chromium/base/TraceEvent.java",
+ "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
+ "android/java/src/org/chromium/base/metrics/RecordHistogram.java",
+ "android/java/src/org/chromium/base/metrics/RecordUserAction.java",
+ ]
+
+ deps = [
+ ":android_runtime_jni_headers",
]
+
+ jni_package = "base"
+ }
+
+ # GYP: //base.gyp:android_runtime_jni_headers
+ generate_jar_jni("android_runtime_jni_headers") {
jni_package = "base"
+ classes = [ "java/lang/Runtime.class" ]
}
# GYP: //base.gyp:base_java
@@ -1440,7 +1437,7 @@ if (is_android) {
]
deps = [
- "//third_party/jsr-305:jsr_305_javalib"
+ "//third_party/jsr-305:jsr_305_javalib",
]
DEPRECATED_java_in_dir = "android/java/src"
@@ -1466,22 +1463,35 @@ if (is_android) {
android_library("base_java_test_support") {
deps = [
":base_java",
+ "//testing/android/reporter:reporter_java",
]
DEPRECATED_java_in_dir = "test/android/javatests/src"
}
+ # GYP: //base.gyp:base_junit_tests
+ junit_binary("base_junit_tests") {
+ java_files = [ "android/junit/src/org/chromium/base/LogTest.java" ]
+ deps = [
+ ":base_java",
+ ":base_java_test_support",
+ ]
+ }
+
# GYP: //base.gyp:base_java_application_state
# GYP: //base.gyp:base_java_library_load_from_apk_status_codes
+ # GYP: //base.gyp:base_java_library_process_type
# GYP: //base.gyp:base_java_memory_pressure_level
java_cpp_enum("base_android_java_enums_srcjar") {
sources = [
"android/application_status_listener.h",
"android/library_loader/library_load_from_apk_status_codes.h",
+ "android/library_loader/library_loader_hooks.h",
"memory/memory_pressure_listener.h",
]
outputs = [
"org/chromium/base/ApplicationState.java",
"org/chromium/base/library_loader/LibraryLoadFromApkStatusCodes.java",
+ "org/chromium/base/library_loader/LibraryProcessType.java",
"org/chromium/base/MemoryPressureLevel.java",
]
}
@@ -1496,19 +1506,10 @@ if (is_android) {
# GYP: //base.gyp:base_java_unittest_support
android_library("base_java_unittest_support") {
- deps = [":base_java"]
- java_files = [
- "test/android/java/src/org/chromium/base/ContentUriTestUtils.java"
- ]
- }
-
- # GYP: //base.gyp:base_unittests_apk
- unittest_apk("base_unittests_apk") {
deps = [
":base_java",
- ":base_java_unittest_support",
- ":base_unittests",
]
- unittests_dep = ":base_unittests"
+ java_files =
+ [ "test/android/java/src/org/chromium/base/ContentUriTestUtils.java" ]
}
}
diff --git a/chromium/base/DEPS b/chromium/base/DEPS
index 2407baaa53c..c632e35d83a 100644
--- a/chromium/base/DEPS
+++ b/chromium/base/DEPS
@@ -4,7 +4,6 @@ include_rules = [
"+third_party/apple_apsl",
"+third_party/libevent",
"+third_party/dmg_fp",
- "+third_party/google_toolbox_for_mac/src",
"+third_party/mach_override",
"+third_party/modp_b64",
"+third_party/tcmalloc",
diff --git a/chromium/base/OWNERS b/chromium/base/OWNERS
index 92844b617f3..9890491e471 100644
--- a/chromium/base/OWNERS
+++ b/chromium/base/OWNERS
@@ -1,6 +1,5 @@
mark@chromium.org
darin@chromium.org
-ajwong@chromium.org
thakis@chromium.org
danakj@chromium.org
rvargas@chromium.org
@@ -24,24 +23,9 @@ willchan@chromium.org
per-file *.isolate=csharp@chromium.org
per-file *.isolate=maruel@chromium.org
-per-file bind.h=ajwong@chromium.org
-per-file bind_helpers.cc=ajwong@chromium.org
-per-file bind_helpers.h=ajwong@chromium.org
-per-file bind_helpers_unittest.cc=ajwong@chromium.org
-per-file bind.h.pump=ajwong@chromium.org
-per-file bind_internal.h=ajwong@chromium.org
-per-file bind_internal.h.pump=ajwong@chromium.org
-per-file bind_internal_win.h=ajwong@chromium.org
-per-file bind_internal_win.h.pump=ajwong@chromium.org
-per-file bind_unittest.cc=ajwong@chromium.org
-per-file bind_unittest.nc=ajwong@chromium.org
-per-file callback_forward.h=ajwong@chromium.org
-per-file callback.h=ajwong@chromium.org
-per-file callback_helpers.h=ajwong@chromium.org
-per-file callback.h.pump=ajwong@chromium.org
-per-file callback_internal.cc=ajwong@chromium.org
-per-file callback_internal.h=ajwong@chromium.org
-per-file callback_unittest.cc=ajwong@chromium.org
-per-file callback_unittest.h=ajwong@chromium.org
-per-file callback_unittest.nc=ajwong@chromium.org
per-file security_unittest.cc=jln@chromium.org
+
+# For Android-specific changes:
+per-file *android*=nyquist@chromium.org
+per-file *android*=rmcilroy@chromium.org
+per-file *android*=yfriedman@chromium.org
diff --git a/chromium/base/PRESUBMIT.py b/chromium/base/PRESUBMIT.py
index 46ab02e3264..7fc8107658c 100644
--- a/chromium/base/PRESUBMIT.py
+++ b/chromium/base/PRESUBMIT.py
@@ -5,7 +5,7 @@
"""Chromium presubmit script for src/base.
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details on the presubmit API built into gcl.
+for more details on the presubmit API built into depot_tools.
"""
def _CheckNoInterfacesInBase(input_api, output_api):
diff --git a/chromium/base/allocator/BUILD.gn b/chromium/base/allocator/BUILD.gn
index 510c3d38f52..a07a356e5d8 100644
--- a/chromium/base/allocator/BUILD.gn
+++ b/chromium/base/allocator/BUILD.gn
@@ -10,7 +10,9 @@ import("//build/config/allocator.gni")
# to the build settings.
group("allocator") {
if (use_allocator == "tcmalloc") {
- deps = [ ":tcmalloc" ]
+ deps = [
+ ":tcmalloc",
+ ]
}
}
@@ -28,20 +30,27 @@ if (is_win) {
action("prep_libc") {
script = "prep_libc.py"
- outputs = [ "$target_gen_dir/allocator/libcmt.lib" ]
+ outputs = [
+ "$target_gen_dir/allocator/libcmt.lib",
+ ]
args = [
visual_studio_path + "/vc/lib",
rebase_path("$target_gen_dir/allocator"),
- cpu_arch,
+ current_cpu,
]
}
}
-if (!is_android) {
+if (use_allocator == "tcmalloc") {
# tcmalloc currently won't compile on Android.
source_set("tcmalloc") {
tcmalloc_dir = "//third_party/tcmalloc/chromium"
+ # Don't check tcmalloc's includes. These files include various files like
+ # base/foo.h and they actually refer to tcmalloc's forked copy of base
+ # rather than the regular one, which confuses the header checker.
+ check_includes = false
+
sources = [
# Generated for our configuration from tcmalloc"s build
# and checked in.
@@ -54,6 +63,7 @@ if (!is_android) {
"$tcmalloc_dir/src/base/abort.cc",
"$tcmalloc_dir/src/base/abort.h",
"$tcmalloc_dir/src/base/arm_instruction_set_select.h",
+
# We don't list dynamic_annotations.c since its copy is already
# present in the dynamic_annotations target.
"$tcmalloc_dir/src/base/elf_mem_image.cc",
@@ -79,6 +89,7 @@ if (!is_android) {
"$tcmalloc_dir/src/central_freelist.h",
"$tcmalloc_dir/src/common.cc",
"$tcmalloc_dir/src/common.h",
+
# #included by debugallocation_shim.cc
#"$tcmalloc_dir/src/debugallocation.cc",
"$tcmalloc_dir/src/deep-heap-profile.cc",
@@ -120,15 +131,14 @@ if (!is_android) {
"$tcmalloc_dir/src/symbolize.h",
"$tcmalloc_dir/src/system-alloc.cc",
"$tcmalloc_dir/src/system-alloc.h",
+
# #included by debugallocation_shim.cc
#"$tcmalloc_dir/src/tcmalloc.cc",
"$tcmalloc_dir/src/thread_cache.cc",
"$tcmalloc_dir/src/thread_cache.h",
"$tcmalloc_dir/src/windows/port.cc",
"$tcmalloc_dir/src/windows/port.h",
-
"allocator_shim.cc",
- "allocator_shim.h",
"debugallocation_shim.cc",
# These are both #included by allocator_shim for maximal linking.
@@ -170,10 +180,10 @@ if (!is_android) {
# cpuprofiler
"$tcmalloc_dir/src/base/thread_lister.c",
"$tcmalloc_dir/src/base/thread_lister.h",
- "$tcmalloc_dir/src/profiledata.cc",
- "$tcmalloc_dir/src/profiledata.h",
"$tcmalloc_dir/src/profile-handler.cc",
"$tcmalloc_dir/src/profile-handler.h",
+ "$tcmalloc_dir/src/profiledata.cc",
+ "$tcmalloc_dir/src/profiledata.h",
"$tcmalloc_dir/src/profiler.cc",
]
defines += [ "PERFTOOLS_DLL_DECL=" ]
@@ -186,9 +196,7 @@ if (!is_android) {
public_configs = [ ":nocmt" ]
- deps += [
- ":prep_libc",
- ]
+ deps += [ ":prep_libc" ]
}
if (is_linux || is_android) {
@@ -215,6 +223,7 @@ if (!is_android) {
# Don't let linker rip this symbol out, otherwise the heap&cpu
# profilers will not initialize properly on startup.
"-Wl,-uIsHeapProfilerRunning,-uProfilerStart",
+
# Do the same for heap leak checker.
"-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi",
"-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl",
@@ -229,9 +238,7 @@ if (!is_android) {
configs += [ "//build/config/compiler:optimize_max" ]
}
- deps += [
- "//base/third_party/dynamic_annotations",
- ]
+ deps += [ "//base/third_party/dynamic_annotations" ]
if (is_win) {
ldflags = [ "/ignore:4006:4221" ]
diff --git a/chromium/base/allocator/allocator.gyp b/chromium/base/allocator/allocator.gyp
index 323d79ede60..d426c9c3f17 100644
--- a/chromium/base/allocator/allocator.gyp
+++ b/chromium/base/allocator/allocator.gyp
@@ -8,7 +8,7 @@
# This code gets run a lot and debugged rarely, so it should be fast
# by default. See http://crbug.com/388949.
'debug_optimize': '2',
- 'win_debug_Optimization': '2',
+ 'win_debug_Optimization': '0',
# Run time checks are incompatible with any level of optimizations.
'win_debug_RuntimeChecks': '0',
},
@@ -24,17 +24,6 @@
{
'target_name': 'allocator',
'type': 'static_library',
- # Make sure the allocation library is optimized to
- # the hilt in official builds.
- 'variables': {
- 'optimize': 'max',
- },
- 'include_dirs': [
- '.',
- '<(tcmalloc_dir)/src/base',
- '<(tcmalloc_dir)/src',
- '../..',
- ],
'direct_dependent_settings': {
'configurations': {
'Common_Base': {
@@ -56,242 +45,6 @@
}],
],
},
- 'sources': [
- # Generated for our configuration from tcmalloc's build
- # and checked in.
- '<(tcmalloc_dir)/src/config.h',
- '<(tcmalloc_dir)/src/config_android.h',
- '<(tcmalloc_dir)/src/config_linux.h',
- '<(tcmalloc_dir)/src/config_win.h',
-
- # all tcmalloc native and forked files
- '<(tcmalloc_dir)/src/addressmap-inl.h',
- '<(tcmalloc_dir)/src/base/abort.cc',
- '<(tcmalloc_dir)/src/base/abort.h',
- '<(tcmalloc_dir)/src/base/arm_instruction_set_select.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-arm-generic.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-arm-v6plus.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
- '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
- '<(tcmalloc_dir)/src/base/atomicops.h',
- '<(tcmalloc_dir)/src/base/basictypes.h',
- '<(tcmalloc_dir)/src/base/commandlineflags.h',
- '<(tcmalloc_dir)/src/base/cycleclock.h',
- # We don't list dynamic_annotations.c since its copy is already
- # present in the dynamic_annotations target.
- '<(tcmalloc_dir)/src/base/dynamic_annotations.h',
- '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
- '<(tcmalloc_dir)/src/base/elf_mem_image.h',
- '<(tcmalloc_dir)/src/base/elfcore.h',
- '<(tcmalloc_dir)/src/base/googleinit.h',
- '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
- '<(tcmalloc_dir)/src/base/linuxthreads.cc',
- '<(tcmalloc_dir)/src/base/linuxthreads.h',
- '<(tcmalloc_dir)/src/base/logging.cc',
- '<(tcmalloc_dir)/src/base/logging.h',
- '<(tcmalloc_dir)/src/base/low_level_alloc.cc',
- '<(tcmalloc_dir)/src/base/low_level_alloc.h',
- '<(tcmalloc_dir)/src/base/simple_mutex.h',
- '<(tcmalloc_dir)/src/base/spinlock.cc',
- '<(tcmalloc_dir)/src/base/spinlock.h',
- '<(tcmalloc_dir)/src/base/spinlock_internal.cc',
- '<(tcmalloc_dir)/src/base/spinlock_internal.h',
- '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
- '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
- '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
- '<(tcmalloc_dir)/src/base/stl_allocator.h',
- '<(tcmalloc_dir)/src/base/synchronization_profiling.h',
- '<(tcmalloc_dir)/src/base/sysinfo.cc',
- '<(tcmalloc_dir)/src/base/sysinfo.h',
- '<(tcmalloc_dir)/src/base/thread_annotations.h',
- '<(tcmalloc_dir)/src/base/thread_lister.c',
- '<(tcmalloc_dir)/src/base/thread_lister.h',
- '<(tcmalloc_dir)/src/base/vdso_support.cc',
- '<(tcmalloc_dir)/src/base/vdso_support.h',
- '<(tcmalloc_dir)/src/central_freelist.cc',
- '<(tcmalloc_dir)/src/central_freelist.h',
- '<(tcmalloc_dir)/src/common.cc',
- '<(tcmalloc_dir)/src/common.h',
- '<(tcmalloc_dir)/src/debugallocation.cc',
- '<(tcmalloc_dir)/src/deep-heap-profile.cc',
- '<(tcmalloc_dir)/src/deep-heap-profile.h',
- '<(tcmalloc_dir)/src/free_list.cc',
- '<(tcmalloc_dir)/src/free_list.h',
- '<(tcmalloc_dir)/src/getpc.h',
- '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
- '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
- '<(tcmalloc_dir)/src/gperftools/profiler.h',
- '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
- '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
- '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
- '<(tcmalloc_dir)/src/heap-checker.cc',
- '<(tcmalloc_dir)/src/heap-profile-table.cc',
- '<(tcmalloc_dir)/src/heap-profile-table.h',
- '<(tcmalloc_dir)/src/heap-profiler.cc',
- '<(tcmalloc_dir)/src/internal_logging.cc',
- '<(tcmalloc_dir)/src/internal_logging.h',
- '<(tcmalloc_dir)/src/libc_override.h',
- '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
- '<(tcmalloc_dir)/src/libc_override_glibc.h',
- '<(tcmalloc_dir)/src/libc_override_osx.h',
- '<(tcmalloc_dir)/src/libc_override_redefine.h',
- '<(tcmalloc_dir)/src/linked_list.h',
- '<(tcmalloc_dir)/src/malloc_extension.cc',
- '<(tcmalloc_dir)/src/malloc_hook-inl.h',
- '<(tcmalloc_dir)/src/malloc_hook.cc',
- '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
- '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
- '<(tcmalloc_dir)/src/maybe_threads.cc',
- '<(tcmalloc_dir)/src/maybe_threads.h',
- '<(tcmalloc_dir)/src/memfs_malloc.cc',
- '<(tcmalloc_dir)/src/memory_region_map.cc',
- '<(tcmalloc_dir)/src/memory_region_map.h',
- '<(tcmalloc_dir)/src/packed-cache-inl.h',
- '<(tcmalloc_dir)/src/page_heap.cc',
- '<(tcmalloc_dir)/src/page_heap.h',
- '<(tcmalloc_dir)/src/page_heap_allocator.h',
- '<(tcmalloc_dir)/src/pagemap.h',
- '<(tcmalloc_dir)/src/profile-handler.cc',
- '<(tcmalloc_dir)/src/profile-handler.h',
- '<(tcmalloc_dir)/src/profiledata.cc',
- '<(tcmalloc_dir)/src/profiledata.h',
- '<(tcmalloc_dir)/src/profiler.cc',
- '<(tcmalloc_dir)/src/raw_printer.cc',
- '<(tcmalloc_dir)/src/raw_printer.h',
- '<(tcmalloc_dir)/src/sampler.cc',
- '<(tcmalloc_dir)/src/sampler.h',
- '<(tcmalloc_dir)/src/span.cc',
- '<(tcmalloc_dir)/src/span.h',
- '<(tcmalloc_dir)/src/stack_trace_table.cc',
- '<(tcmalloc_dir)/src/stack_trace_table.h',
- '<(tcmalloc_dir)/src/stacktrace.cc',
- '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_config.h',
- '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
- '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
- '<(tcmalloc_dir)/src/static_vars.cc',
- '<(tcmalloc_dir)/src/static_vars.h',
- '<(tcmalloc_dir)/src/symbolize.cc',
- '<(tcmalloc_dir)/src/symbolize.h',
- '<(tcmalloc_dir)/src/system-alloc.cc',
- '<(tcmalloc_dir)/src/system-alloc.h',
- '<(tcmalloc_dir)/src/tcmalloc.cc',
- '<(tcmalloc_dir)/src/tcmalloc_guard.h',
- '<(tcmalloc_dir)/src/thread_cache.cc',
- '<(tcmalloc_dir)/src/thread_cache.h',
- '<(tcmalloc_dir)/src/windows/config.h',
- '<(tcmalloc_dir)/src/windows/get_mangled_names.cc',
- '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h',
- '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc',
- '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc',
- '<(tcmalloc_dir)/src/windows/mingw.h',
- '<(tcmalloc_dir)/src/windows/mini_disassembler.cc',
- '<(tcmalloc_dir)/src/windows/mini_disassembler.h',
- '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h',
- '<(tcmalloc_dir)/src/windows/override_functions.cc',
- '<(tcmalloc_dir)/src/windows/patch_functions.cc',
- '<(tcmalloc_dir)/src/windows/port.cc',
- '<(tcmalloc_dir)/src/windows/port.h',
- '<(tcmalloc_dir)/src/windows/preamble_patcher.cc',
- '<(tcmalloc_dir)/src/windows/preamble_patcher.h',
- '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc',
-
- 'allocator_shim.cc',
- 'allocator_shim.h',
- 'debugallocation_shim.cc',
- 'generic_allocators.cc',
- 'win_allocator.cc',
- ],
- # sources! means that these are not compiled directly.
- 'sources!': [
- # Included by allocator_shim.cc for maximal inlining.
- 'generic_allocators.cc',
- 'win_allocator.cc',
-
- # Included by debugallocation_shim.cc.
- '<(tcmalloc_dir)/src/debugallocation.cc',
- '<(tcmalloc_dir)/src/tcmalloc.cc',
-
- # We simply don't use these, but list them above so that IDE
- # users can view the full available source for reference, etc.
- '<(tcmalloc_dir)/src/addressmap-inl.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h',
- '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
- '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
- '<(tcmalloc_dir)/src/base/atomicops.h',
- '<(tcmalloc_dir)/src/base/basictypes.h',
- '<(tcmalloc_dir)/src/base/commandlineflags.h',
- '<(tcmalloc_dir)/src/base/cycleclock.h',
- '<(tcmalloc_dir)/src/base/elf_mem_image.h',
- '<(tcmalloc_dir)/src/base/elfcore.h',
- '<(tcmalloc_dir)/src/base/googleinit.h',
- '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
- '<(tcmalloc_dir)/src/base/simple_mutex.h',
- '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
- '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
- '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
- '<(tcmalloc_dir)/src/base/stl_allocator.h',
- '<(tcmalloc_dir)/src/base/thread_annotations.h',
- '<(tcmalloc_dir)/src/getpc.h',
- '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
- '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
- '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
- '<(tcmalloc_dir)/src/gperftools/profiler.h',
- '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
- '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
- '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
- '<(tcmalloc_dir)/src/heap-checker.cc',
- '<(tcmalloc_dir)/src/libc_override.h',
- '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
- '<(tcmalloc_dir)/src/libc_override_glibc.h',
- '<(tcmalloc_dir)/src/libc_override_osx.h',
- '<(tcmalloc_dir)/src/libc_override_redefine.h',
- '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
- '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
- '<(tcmalloc_dir)/src/memfs_malloc.cc',
- '<(tcmalloc_dir)/src/packed-cache-inl.h',
- '<(tcmalloc_dir)/src/page_heap_allocator.h',
- '<(tcmalloc_dir)/src/pagemap.h',
- '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_config.h',
- '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
- '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
- '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
- '<(tcmalloc_dir)/src/tcmalloc_guard.h',
- '<(tcmalloc_dir)/src/windows/config.h',
- '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h',
- '<(tcmalloc_dir)/src/windows/get_mangled_names.cc',
- '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc',
- '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc',
- '<(tcmalloc_dir)/src/windows/mingw.h',
- '<(tcmalloc_dir)/src/windows/mini_disassembler.cc',
- '<(tcmalloc_dir)/src/windows/mini_disassembler.h',
- '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h',
- '<(tcmalloc_dir)/src/windows/override_functions.cc',
- '<(tcmalloc_dir)/src/windows/patch_functions.cc',
- '<(tcmalloc_dir)/src/windows/preamble_patcher.cc',
- '<(tcmalloc_dir)/src/windows/preamble_patcher.h',
- '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc',
- ],
'dependencies': [
'../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
],
@@ -318,8 +71,7 @@
'disable_debugallocation%': 0,
},
'conditions': [
- # TODO(phajdan.jr): Also enable on Windows.
- ['disable_debugallocation==0 and OS!="win"', {
+ ['disable_debugallocation==0', {
'defines': [
# Use debugallocation for Debug builds to catch problems early
# and cleanly, http://crbug.com/30715 .
@@ -329,76 +81,257 @@
],
},
},
- # Disable the heap checker in tcmalloc.
- 'defines': [
- 'NO_HEAP_CHECK',
- ],
'conditions': [
- ['OS=="linux" and clang_type_profiler==1', {
- 'dependencies': [
- 'type_profiler_tcmalloc',
- ],
- # It is undoing dependencies and cflags_cc for type_profiler which
- # build/common.gypi injects into all targets.
- 'dependencies!': [
- 'type_profiler',
- ],
- 'cflags_cc!': [
- '-fintercept-allocation-functions',
- ],
- }],
- ['OS=="win"', {
+ ['use_allocator=="tcmalloc"', {
+ # Disable the heap checker in tcmalloc.
'defines': [
- 'PERFTOOLS_DLL_DECL=',
- ],
- 'defines!': [
- # tcmalloc source files unconditionally define this, remove it from
- # the list of defines that common.gypi defines globally.
- 'NOMINMAX',
- ],
- 'dependencies': [
- 'libcmt',
+ 'NO_HEAP_CHECK',
],
'include_dirs': [
- '<(tcmalloc_dir)/src/windows',
+ '.',
+ '<(tcmalloc_dir)/src/base',
+ '<(tcmalloc_dir)/src',
+ '../..',
],
- 'sources!': [
+ 'sources': [
+ # Generated for our configuration from tcmalloc's build
+ # and checked in.
+ '<(tcmalloc_dir)/src/config.h',
+ '<(tcmalloc_dir)/src/config_android.h',
+ '<(tcmalloc_dir)/src/config_linux.h',
+ '<(tcmalloc_dir)/src/config_win.h',
+
+ # all tcmalloc native and forked files
+ '<(tcmalloc_dir)/src/addressmap-inl.h',
+ '<(tcmalloc_dir)/src/base/abort.cc',
+ '<(tcmalloc_dir)/src/base/abort.h',
+ '<(tcmalloc_dir)/src/base/arm_instruction_set_select.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-arm-generic.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-arm-v6plus.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+ '<(tcmalloc_dir)/src/base/atomicops.h',
+ '<(tcmalloc_dir)/src/base/basictypes.h',
+ '<(tcmalloc_dir)/src/base/commandlineflags.h',
+ '<(tcmalloc_dir)/src/base/cycleclock.h',
+ # We don't list dynamic_annotations.c since its copy is already
+ # present in the dynamic_annotations target.
+ '<(tcmalloc_dir)/src/base/dynamic_annotations.h',
'<(tcmalloc_dir)/src/base/elf_mem_image.cc',
'<(tcmalloc_dir)/src/base/elf_mem_image.h',
+ '<(tcmalloc_dir)/src/base/elfcore.h',
+ '<(tcmalloc_dir)/src/base/googleinit.h',
+ '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
'<(tcmalloc_dir)/src/base/linuxthreads.cc',
'<(tcmalloc_dir)/src/base/linuxthreads.h',
+ '<(tcmalloc_dir)/src/base/logging.cc',
+ '<(tcmalloc_dir)/src/base/logging.h',
+ '<(tcmalloc_dir)/src/base/low_level_alloc.cc',
+ '<(tcmalloc_dir)/src/base/low_level_alloc.h',
+ '<(tcmalloc_dir)/src/base/simple_mutex.h',
+ '<(tcmalloc_dir)/src/base/spinlock.cc',
+ '<(tcmalloc_dir)/src/base/spinlock.h',
+ '<(tcmalloc_dir)/src/base/spinlock_internal.cc',
+ '<(tcmalloc_dir)/src/base/spinlock_internal.h',
+ '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+ '<(tcmalloc_dir)/src/base/stl_allocator.h',
+ '<(tcmalloc_dir)/src/base/synchronization_profiling.h',
+ '<(tcmalloc_dir)/src/base/sysinfo.cc',
+ '<(tcmalloc_dir)/src/base/sysinfo.h',
+ '<(tcmalloc_dir)/src/base/thread_annotations.h',
+ '<(tcmalloc_dir)/src/base/thread_lister.c',
+ '<(tcmalloc_dir)/src/base/thread_lister.h',
'<(tcmalloc_dir)/src/base/vdso_support.cc',
'<(tcmalloc_dir)/src/base/vdso_support.h',
+ '<(tcmalloc_dir)/src/central_freelist.cc',
+ '<(tcmalloc_dir)/src/central_freelist.h',
+ '<(tcmalloc_dir)/src/common.cc',
+ '<(tcmalloc_dir)/src/common.h',
+ '<(tcmalloc_dir)/src/debugallocation.cc',
+ '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+ '<(tcmalloc_dir)/src/deep-heap-profile.h',
+ '<(tcmalloc_dir)/src/free_list.cc',
+ '<(tcmalloc_dir)/src/free_list.h',
+ '<(tcmalloc_dir)/src/getpc.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+ '<(tcmalloc_dir)/src/gperftools/profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+ '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+ '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+ '<(tcmalloc_dir)/src/heap-checker.cc',
+ '<(tcmalloc_dir)/src/heap-profile-table.cc',
+ '<(tcmalloc_dir)/src/heap-profile-table.h',
+ '<(tcmalloc_dir)/src/heap-profiler.cc',
+ '<(tcmalloc_dir)/src/internal_logging.cc',
+ '<(tcmalloc_dir)/src/internal_logging.h',
+ '<(tcmalloc_dir)/src/libc_override.h',
+ '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+ '<(tcmalloc_dir)/src/libc_override_glibc.h',
+ '<(tcmalloc_dir)/src/libc_override_osx.h',
+ '<(tcmalloc_dir)/src/libc_override_redefine.h',
+ '<(tcmalloc_dir)/src/linked_list.h',
+ '<(tcmalloc_dir)/src/malloc_extension.cc',
+ '<(tcmalloc_dir)/src/malloc_hook-inl.h',
+ '<(tcmalloc_dir)/src/malloc_hook.cc',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
'<(tcmalloc_dir)/src/maybe_threads.cc',
'<(tcmalloc_dir)/src/maybe_threads.h',
+ '<(tcmalloc_dir)/src/memfs_malloc.cc',
+ '<(tcmalloc_dir)/src/memory_region_map.cc',
+ '<(tcmalloc_dir)/src/memory_region_map.h',
+ '<(tcmalloc_dir)/src/packed-cache-inl.h',
+ '<(tcmalloc_dir)/src/page_heap.cc',
+ '<(tcmalloc_dir)/src/page_heap.h',
+ '<(tcmalloc_dir)/src/page_heap_allocator.h',
+ '<(tcmalloc_dir)/src/pagemap.h',
+ '<(tcmalloc_dir)/src/profile-handler.cc',
+ '<(tcmalloc_dir)/src/profile-handler.h',
+ '<(tcmalloc_dir)/src/profiledata.cc',
+ '<(tcmalloc_dir)/src/profiledata.h',
+ '<(tcmalloc_dir)/src/profiler.cc',
+ '<(tcmalloc_dir)/src/raw_printer.cc',
+ '<(tcmalloc_dir)/src/raw_printer.h',
+ '<(tcmalloc_dir)/src/sampler.cc',
+ '<(tcmalloc_dir)/src/sampler.h',
+ '<(tcmalloc_dir)/src/span.cc',
+ '<(tcmalloc_dir)/src/span.h',
+ '<(tcmalloc_dir)/src/stack_trace_table.cc',
+ '<(tcmalloc_dir)/src/stack_trace_table.h',
+ '<(tcmalloc_dir)/src/stacktrace.cc',
+ '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_config.h',
+ '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+ '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+ '<(tcmalloc_dir)/src/static_vars.cc',
+ '<(tcmalloc_dir)/src/static_vars.h',
+ '<(tcmalloc_dir)/src/symbolize.cc',
'<(tcmalloc_dir)/src/symbolize.h',
'<(tcmalloc_dir)/src/system-alloc.cc',
'<(tcmalloc_dir)/src/system-alloc.h',
+ '<(tcmalloc_dir)/src/tcmalloc.cc',
+ '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+ '<(tcmalloc_dir)/src/thread_cache.cc',
+ '<(tcmalloc_dir)/src/thread_cache.h',
- # included by allocator_shim.cc
'debugallocation_shim.cc',
],
+ # sources! means that these are not compiled directly.
+ 'sources!': [
+ # We simply don't use these, but list them above so that IDE
+ # users can view the full available source for reference, etc.
+ '<(tcmalloc_dir)/src/addressmap-inl.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+ '<(tcmalloc_dir)/src/base/atomicops.h',
+ '<(tcmalloc_dir)/src/base/basictypes.h',
+ '<(tcmalloc_dir)/src/base/commandlineflags.h',
+ '<(tcmalloc_dir)/src/base/cycleclock.h',
+ '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+ '<(tcmalloc_dir)/src/base/elfcore.h',
+ '<(tcmalloc_dir)/src/base/googleinit.h',
+ '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+ '<(tcmalloc_dir)/src/base/simple_mutex.h',
+ '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+ '<(tcmalloc_dir)/src/base/stl_allocator.h',
+ '<(tcmalloc_dir)/src/base/thread_annotations.h',
+ '<(tcmalloc_dir)/src/getpc.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+ '<(tcmalloc_dir)/src/gperftools/profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+ '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+ '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+ '<(tcmalloc_dir)/src/heap-checker.cc',
+ '<(tcmalloc_dir)/src/libc_override.h',
+ '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+ '<(tcmalloc_dir)/src/libc_override_glibc.h',
+ '<(tcmalloc_dir)/src/libc_override_osx.h',
+ '<(tcmalloc_dir)/src/libc_override_redefine.h',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+ '<(tcmalloc_dir)/src/memfs_malloc.cc',
+ '<(tcmalloc_dir)/src/packed-cache-inl.h',
+ '<(tcmalloc_dir)/src/page_heap_allocator.h',
+ '<(tcmalloc_dir)/src/pagemap.h',
+ '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_config.h',
+ '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+ '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+ '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+
+ # Included by debugallocation_shim.cc.
+ '<(tcmalloc_dir)/src/debugallocation.cc',
+ '<(tcmalloc_dir)/src/tcmalloc.cc',
+ ]
+ },{
+ 'include_dirs': [
+ '.',
+ '../..',
+ ],
+ }],
+ ['OS=="linux" and clang_type_profiler==1', {
+ 'dependencies': [
+ 'type_profiler_tcmalloc',
+ ],
+ # It is undoing dependencies and cflags_cc for type_profiler which
+ # build/common.gypi injects into all targets.
+ 'dependencies!': [
+ 'type_profiler',
+ ],
+ 'cflags_cc!': [
+ '-fintercept-allocation-functions',
+ ],
+ }],
+ ['OS=="win"', {
+ 'dependencies': [
+ 'libcmt',
+ ],
+ 'sources': [
+ 'allocator_shim_win.cc',
+ ],
}],
- ['OS=="win" or profiling!=1', {
+ ['profiling!=1', {
'sources!': [
# cpuprofiler
'<(tcmalloc_dir)/src/base/thread_lister.c',
'<(tcmalloc_dir)/src/base/thread_lister.h',
- '<(tcmalloc_dir)/src/profiledata.cc',
- '<(tcmalloc_dir)/src/profiledata.h',
'<(tcmalloc_dir)/src/profile-handler.cc',
'<(tcmalloc_dir)/src/profile-handler.h',
+ '<(tcmalloc_dir)/src/profiledata.cc',
+ '<(tcmalloc_dir)/src/profiledata.h',
'<(tcmalloc_dir)/src/profiler.cc',
],
}],
['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
'sources!': [
'<(tcmalloc_dir)/src/system-alloc.h',
- '<(tcmalloc_dir)/src/windows/port.cc',
- '<(tcmalloc_dir)/src/windows/port.h',
-
- # TODO(willchan): Support allocator shim later on.
- 'allocator_shim.cc',
],
# We enable all warnings by default, but upstream disables a few.
# Keep "-Wno-*" flags in sync with upstream by comparing against:
@@ -498,31 +431,12 @@
],
'include_dirs': [
'.',
- '<(tcmalloc_dir)/src/base',
- '<(tcmalloc_dir)/src',
'../..',
],
'sources': [
- 'allocator_unittest.cc',
'../profiler/alternate_timer.cc',
'../profiler/alternate_timer.h',
- ],
- },
- {
- 'target_name': 'tcmalloc_unittest',
- 'type': 'executable',
- 'sources': [
- 'tcmalloc_unittest.cc',
- ],
- 'include_dirs': [
- '../..',
- # For constants of TCMalloc.
- '<(tcmalloc_dir)/src',
- ],
- 'dependencies': [
- '../../testing/gtest.gyp:gtest',
- '../base.gyp:base',
- 'allocator',
+ 'allocator_unittest.cc',
],
},
],
@@ -585,10 +499,10 @@
'../..',
],
'sources': [
- 'type_profiler_tcmalloc.cc',
- 'type_profiler_tcmalloc.h',
'<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
'<(tcmalloc_dir)/src/type_profiler_map.cc',
+ 'type_profiler_tcmalloc.cc',
+ 'type_profiler_tcmalloc.h',
],
},
{
@@ -628,9 +542,28 @@
'../..',
],
'sources': [
- 'type_profiler_map_unittest.cc',
'<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
'<(tcmalloc_dir)/src/type_profiler_map.cc',
+ 'type_profiler_map_unittest.cc',
+ ],
+ },
+ ],
+ }],
+ ['use_allocator=="tcmalloc"', {
+ 'targets': [
+ {
+ 'target_name': 'tcmalloc_unittest',
+ 'type': 'executable',
+ 'sources': [
+ 'tcmalloc_unittest.cc',
+ ],
+ 'include_dirs': [
+ '<(tcmalloc_dir)/src',
+ '../..',
+ ],
+ 'dependencies': [
+ '../../testing/gtest.gyp:gtest',
+ 'allocator',
],
},
],
diff --git a/chromium/base/allocator/allocator_extension.h b/chromium/base/allocator/allocator_extension.h
index de3119f85e6..e65822b359e 100644
--- a/chromium/base/allocator/allocator_extension.h
+++ b/chromium/base/allocator/allocator_extension.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
-#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
#include <stddef.h> // for size_t
@@ -56,4 +56,4 @@ BASE_EXPORT void SetReleaseFreeMemoryFunction(
} // namespace allocator
} // namespace base
-#endif
+#endif // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
diff --git a/chromium/base/allocator/allocator_extension_thunks.h b/chromium/base/allocator/allocator_extension_thunks.h
index 1e97a84b63c..4e5027b2921 100644
--- a/chromium/base/allocator/allocator_extension_thunks.h
+++ b/chromium/base/allocator/allocator_extension_thunks.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
-#define BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
#include <stddef.h> // for size_t
@@ -33,4 +33,4 @@ ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
} // namespace allocator
} // namespace base
-#endif
+#endif // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
diff --git a/chromium/base/allocator/allocator_shim.cc b/chromium/base/allocator/allocator_shim.cc
deleted file mode 100644
index 961cda4c5c4..00000000000
--- a/chromium/base/allocator/allocator_shim.cc
+++ /dev/null
@@ -1,378 +0,0 @@
-// Copyright (c) 2012 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/allocator/allocator_shim.h"
-
-#include <config.h>
-#include "base/allocator/allocator_extension_thunks.h"
-#include "base/profiler/alternate_timer.h"
-#include "base/sysinfo.h"
-
-// This shim make it possible to use different allocators via an environment
-// variable set before running the program. This may reduce the
-// amount of inlining that we get with malloc/free/etc.
-
-// TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth
-// from the "user code" so that debugging tools (HeapChecker) can work.
-
-// new_mode behaves similarly to MSVC's _set_new_mode.
-// If flag is 0 (default), calls to malloc will behave normally.
-// If flag is 1, calls to malloc will behave like calls to new,
-// and the std_new_handler will be invoked on failure.
-// Can be set by calling _set_new_mode().
-static int new_mode = 0;
-
-typedef enum {
- TCMALLOC, // TCMalloc is the default allocator.
- WINHEAP, // Windows Heap (standard Windows allocator).
- WINLFH, // Windows LFH Heap.
-} Allocator;
-
-// This is the default allocator. This value can be changed at startup by
-// specifying environment variables shown below it.
-// See SetupSubprocessAllocator() to specify a default secondary (subprocess)
-// allocator.
-// TODO(jar): Switch to using TCMALLOC for the renderer as well.
-#if defined(SYZYASAN)
-// SyzyASan requires the use of "WINHEAP".
-static Allocator allocator = WINHEAP;
-#else
-static Allocator allocator = TCMALLOC;
-#endif
-// The names of the environment variables that can optionally control the
-// selection of the allocator. The primary may be used to control overall
-// allocator selection, and the secondary can be used to specify an allocator
-// to use in sub-processes.
-static const char primary_name[] = "CHROME_ALLOCATOR";
-static const char secondary_name[] = "CHROME_ALLOCATOR_2";
-
-// We include tcmalloc and the win_allocator to get as much inlining as
-// possible.
-#include "debugallocation_shim.cc"
-#include "win_allocator.cc"
-
-// Call the new handler, if one has been set.
-// Returns true on successfully calling the handler, false otherwise.
-inline bool call_new_handler(bool nothrow) {
- // Get the current new handler. NB: this function is not
- // thread-safe. We make a feeble stab at making it so here, but
- // this lock only protects against tcmalloc interfering with
- // itself, not with other libraries calling set_new_handler.
- std::new_handler nh;
- {
- SpinLockHolder h(&set_new_handler_lock);
- nh = std::set_new_handler(0);
- (void) std::set_new_handler(nh);
- }
-#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
- (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
- if (!nh)
- return false;
- // Since exceptions are disabled, we don't really know if new_handler
- // failed. Assume it will abort if it fails.
- (*nh)();
- return false; // break out of the retry loop.
-#else
- // If no new_handler is established, the allocation failed.
- if (!nh) {
- if (nothrow)
- return false;
- throw std::bad_alloc();
- }
- // Otherwise, try the new_handler. If it returns, retry the
- // allocation. If it throws std::bad_alloc, fail the allocation.
- // if it throws something else, don't interfere.
- try {
- (*nh)();
- } catch (const std::bad_alloc&) {
- if (!nothrow)
- throw;
- return true;
- }
-#endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
- return false;
-}
-
-extern "C" {
-void* malloc(size_t size) {
- void* ptr;
- for (;;) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- ptr = win_heap_malloc(size);
- break;
- case TCMALLOC:
- default:
- ptr = do_malloc(size);
- break;
- }
- if (ptr)
- return ptr;
-
- if (!new_mode || !call_new_handler(true))
- break;
- }
- return ptr;
-}
-
-void free(void* p) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- win_heap_free(p);
- return;
- case TCMALLOC:
- do_free(p);
- return;
- }
-}
-
-void* realloc(void* ptr, size_t size) {
- // Webkit is brittle for allocators that return NULL for malloc(0). The
- // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
- // to call malloc for this case.
- if (!ptr)
- return malloc(size);
-
- void* new_ptr;
- for (;;) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- new_ptr = win_heap_realloc(ptr, size);
- break;
- case TCMALLOC:
- default:
- new_ptr = do_realloc(ptr, size);
- break;
- }
-
- // Subtle warning: NULL return does not alwas indicate out-of-memory. If
- // the requested new size is zero, realloc should free the ptr and return
- // NULL.
- if (new_ptr || !size)
- return new_ptr;
- if (!new_mode || !call_new_handler(true))
- break;
- }
- return new_ptr;
-}
-
-// TODO(mbelshe): Implement this for other allocators.
-void malloc_stats(void) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- // No stats.
- return;
- case TCMALLOC:
- tc_malloc_stats();
- return;
- }
-}
-
-#ifdef WIN32
-
-extern "C" size_t _msize(void* p) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- return win_heap_msize(p);
- }
-
- // TCMALLOC
- return MallocExtension::instance()->GetAllocatedSize(p);
-}
-
-// This is included to resolve references from libcmt.
-extern "C" intptr_t _get_heap_handle() {
- return 0;
-}
-
-static bool get_allocator_waste_size_thunk(size_t* size) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- // TODO(alexeif): Implement for allocators other than tcmalloc.
- return false;
- }
- size_t heap_size, allocated_bytes, unmapped_bytes;
- MallocExtension* ext = MallocExtension::instance();
- if (ext->GetNumericProperty("generic.heap_size", &heap_size) &&
- ext->GetNumericProperty("generic.current_allocated_bytes",
- &allocated_bytes) &&
- ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes",
- &unmapped_bytes)) {
- *size = heap_size - allocated_bytes - unmapped_bytes;
- return true;
- }
- return false;
-}
-
-static void get_stats_thunk(char* buffer, int buffer_length) {
- MallocExtension::instance()->GetStats(buffer, buffer_length);
-}
-
-static void release_free_memory_thunk() {
- MallocExtension::instance()->ReleaseFreeMemory();
-}
-
-// The CRT heap initialization stub.
-extern "C" int _heap_init() {
-// Don't use the environment variable if SYZYASAN is defined, as the
-// implementation requires Winheap to be the allocator.
-#if !defined(SYZYASAN)
- const char* environment_value = GetenvBeforeMain(primary_name);
- if (environment_value) {
- if (!stricmp(environment_value, "winheap"))
- allocator = WINHEAP;
- else if (!stricmp(environment_value, "winlfh"))
- allocator = WINLFH;
- else if (!stricmp(environment_value, "tcmalloc"))
- allocator = TCMALLOC;
- }
-#endif
-
- switch (allocator) {
- case WINHEAP:
- return win_heap_init(false) ? 1 : 0;
- case WINLFH:
- return win_heap_init(true) ? 1 : 0;
- case TCMALLOC:
- default:
- // fall through
- break;
- }
-
- // Initializing tcmalloc.
- // We intentionally leak this object. It lasts for the process
- // lifetime. Trying to teardown at _heap_term() is so late that
- // you can't do anything useful anyway.
- new TCMallocGuard();
-
- // Provide optional hook for monitoring allocation quantities on a per-thread
- // basis. Only set the hook if the environment indicates this needs to be
- // enabled.
- const char* profiling =
- GetenvBeforeMain(tracked_objects::kAlternateProfilerTime);
- if (profiling && *profiling == '1') {
- tracked_objects::SetAlternateTimeSource(
- tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread,
- tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
- }
-
- base::allocator::thunks::SetGetAllocatorWasteSizeFunction(
- get_allocator_waste_size_thunk);
- base::allocator::thunks::SetGetStatsFunction(get_stats_thunk);
- base::allocator::thunks::SetReleaseFreeMemoryFunction(
- release_free_memory_thunk);
-
- return 1;
-}
-
-// The CRT heap cleanup stub.
-extern "C" void _heap_term() {}
-
-// We set this to 1 because part of the CRT uses a check of _crtheap != 0
-// to test whether the CRT has been initialized. Once we've ripped out
-// the allocators from libcmt, we need to provide this definition so that
-// the rest of the CRT is still usable.
-extern "C" void* _crtheap = reinterpret_cast<void*>(1);
-
-// Provide support for aligned memory through Windows only _aligned_malloc().
-void* _aligned_malloc(size_t size, size_t alignment) {
- // _aligned_malloc guarantees parameter validation, so do so here. These
- // checks are somewhat stricter than _aligned_malloc() since we're effectively
- // using memalign() under the hood.
- DCHECK_GT(size, 0U);
- DCHECK_EQ(alignment & (alignment - 1), 0U);
- DCHECK_EQ(alignment % sizeof(void*), 0U);
-
- void* ptr;
- for (;;) {
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- ptr = win_heap_memalign(alignment, size);
- break;
- case TCMALLOC:
- default:
- ptr = tc_memalign(alignment, size);
- break;
- }
-
- if (ptr) {
- // Sanity check alignment.
- DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
- return ptr;
- }
-
- if (!new_mode || !call_new_handler(true))
- break;
- }
- return ptr;
-}
-
-void _aligned_free(void* p) {
- // TCMalloc returns pointers from memalign() that are safe to use with free().
- // Pointers allocated with win_heap_memalign() MUST be freed via
- // win_heap_memalign_free() since the aligned pointer is not the real one.
- switch (allocator) {
- case WINHEAP:
- case WINLFH:
- win_heap_memalign_free(p);
- return;
- case TCMALLOC:
- do_free(p);
- }
-}
-
-#endif // WIN32
-
-#include "generic_allocators.cc"
-
-} // extern C
-
-namespace base {
-namespace allocator {
-
-void SetupSubprocessAllocator() {
- size_t primary_length = 0;
- getenv_s(&primary_length, NULL, 0, primary_name);
-
- size_t secondary_length = 0;
- char buffer[20];
- getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name);
- DCHECK_GT(sizeof(buffer), secondary_length);
- buffer[sizeof(buffer) - 1] = '\0';
-
- if (secondary_length || !primary_length) {
-// Don't use the environment variable if SYZYASAN is defined, as the
-// implementation require Winheap to be the allocator.
-#if !defined(SYZYASAN)
- const char* secondary_value = secondary_length ? buffer : "TCMALLOC";
- // Force renderer (or other subprocesses) to use secondary_value.
-#else
- const char* secondary_value = "WINHEAP";
-#endif
- int ret_val = _putenv_s(primary_name, secondary_value);
- DCHECK_EQ(0, ret_val);
- }
-}
-
-void* TCMallocDoMallocForTest(size_t size) {
- return do_malloc(size);
-}
-
-void TCMallocDoFreeForTest(void* ptr) {
- do_free(ptr);
-}
-
-size_t ExcludeSpaceForMarkForTest(size_t size) {
- return ExcludeSpaceForMark(size);
-}
-
-} // namespace allocator.
-} // namespace base.
diff --git a/chromium/base/allocator/allocator_shim.h b/chromium/base/allocator/allocator_shim.h
deleted file mode 100644
index ca70ab0e10f..00000000000
--- a/chromium/base/allocator/allocator_shim.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 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_ALLOCATOR_ALLOCATOR_SHIM_H_
-#define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
-
-#include <stddef.h>
-
-namespace base {
-namespace allocator {
-
-// Resets the environment variable CHROME_ALLOCATOR to specify the choice to
-// be used by subprocesses. Priority is given to the current value of
-// CHROME_ALLOCATOR_2 (if specified), then CHROME_ALLOCATOR (if specified), and
-// then a default value (typically set to TCMALLOC).
-void SetupSubprocessAllocator();
-
-// Expose some of tcmalloc functions for test.
-void* TCMallocDoMallocForTest(size_t size);
-void TCMallocDoFreeForTest(void* ptr);
-size_t ExcludeSpaceForMarkForTest(size_t size);
-
-} // namespace allocator.
-} // namespace base.
-
-#endif // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
diff --git a/chromium/base/allocator/allocator_shim_win.cc b/chromium/base/allocator/allocator_shim_win.cc
new file mode 100644
index 00000000000..a1473e5fd29
--- /dev/null
+++ b/chromium/base/allocator/allocator_shim_win.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2012 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 <malloc.h>
+#include <new.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+// This shim make it possible to perform additional checks on allocations
+// before passing them to the Heap functions.
+
+// Heap functions are stripped from libcmt.lib using the prep_libc.py
+// for each object file stripped, we re-implement them here to allow us to
+// perform additional checks:
+// 1. Enforcing the maximum size that can be allocated to 2Gb.
+// 2. Calling new_handler if malloc fails.
+
+extern "C" {
+// We set this to 1 because part of the CRT uses a check of _crtheap != 0
+// to test whether the CRT has been initialized. Once we've ripped out
+// the allocators from libcmt, we need to provide this definition so that
+// the rest of the CRT is still usable.
+// heapinit.c
+void* _crtheap = reinterpret_cast<void*>(1);
+}
+
+namespace {
+
+const size_t kWindowsPageSize = 4096;
+const size_t kMaxWindowsAllocation = INT_MAX - kWindowsPageSize;
+int new_mode = 0;
+
+// VS2013 crt uses the process heap as its heap, so we do the same here.
+// See heapinit.c in VS CRT sources.
+bool win_heap_init() {
+ // Set the _crtheap global here. THis allows us to offload most of the
+ // memory management to the CRT, except the functions we need to shim.
+ _crtheap = GetProcessHeap();
+ if (_crtheap == NULL)
+ return false;
+
+ ULONG enable_lfh = 2;
+ // NOTE: Setting LFH may fail. Vista already has it enabled.
+ // And under the debugger, it won't use LFH. So we
+ // ignore any errors.
+ HeapSetInformation(_crtheap, HeapCompatibilityInformation, &enable_lfh,
+ sizeof(enable_lfh));
+
+ return true;
+}
+
+void* win_heap_malloc(size_t size) {
+ if (size < kMaxWindowsAllocation)
+ return HeapAlloc(_crtheap, 0, size);
+ return NULL;
+}
+
+void win_heap_free(void* size) {
+ HeapFree(_crtheap, 0, size);
+}
+
+void* win_heap_realloc(void* ptr, size_t size) {
+ if (!ptr)
+ return win_heap_malloc(size);
+ if (!size) {
+ win_heap_free(ptr);
+ return NULL;
+ }
+ if (size < kMaxWindowsAllocation)
+ return HeapReAlloc(_crtheap, 0, ptr, size);
+ return NULL;
+}
+
+void win_heap_term() {
+ _crtheap = NULL;
+}
+
+// Call the new handler, if one has been set.
+// Returns true on successfully calling the handler, false otherwise.
+inline bool call_new_handler(bool nothrow, size_t size) {
+ // Get the current new handler.
+ _PNH nh = _query_new_handler();
+#if defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+ if (!nh)
+ return false;
+ // Since exceptions are disabled, we don't really know if new_handler
+ // failed. Assume it will abort if it fails.
+ return nh(size);
+#else
+#error "Exceptions in allocator shim are not supported!"
+#endif // defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+ return false;
+}
+
+// Implement a C++ style allocation, which always calls the new_handler
+// on failure.
+inline void* generic_cpp_alloc(size_t size, bool nothrow) {
+ void* ptr;
+ for (;;) {
+ ptr = malloc(size);
+ if (ptr)
+ return ptr;
+ if (!call_new_handler(nothrow, size))
+ break;
+ }
+ return ptr;
+}
+
+} // namespace
+
+// new.cpp
+void* operator new(size_t size) {
+ return generic_cpp_alloc(size, false);
+}
+
+// delete.cpp
+void operator delete(void* p) throw() {
+ free(p);
+}
+
+// new2.cpp
+void* operator new[](size_t size) {
+ return generic_cpp_alloc(size, false);
+}
+
+// delete2.cpp
+void operator delete[](void* p) throw() {
+ free(p);
+}
+
+// newopnt.cpp
+void* operator new(size_t size, const std::nothrow_t& nt) {
+ return generic_cpp_alloc(size, true);
+}
+
+// newaopnt.cpp
+void* operator new[](size_t size, const std::nothrow_t& nt) {
+ return generic_cpp_alloc(size, true);
+}
+
+// This function behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Returns the previous mode.
+// new_mode.cpp
+int _set_new_mode(int flag) throw() {
+ int old_mode = new_mode;
+ new_mode = flag;
+ return old_mode;
+}
+
+// new_mode.cpp
+int _query_new_mode() {
+ return new_mode;
+}
+
+extern "C" {
+// malloc.c
+void* malloc(size_t size) {
+ void* ptr;
+ for (;;) {
+ ptr = win_heap_malloc(size);
+ if (ptr)
+ return ptr;
+
+ if (!new_mode || !call_new_handler(true, size))
+ break;
+ }
+ return ptr;
+}
+
+// free.c
+void free(void* p) {
+ win_heap_free(p);
+ return;
+}
+
+// realloc.c
+void* realloc(void* ptr, size_t size) {
+ // Webkit is brittle for allocators that return NULL for malloc(0). The
+ // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
+ // to call malloc for this case.
+ if (!ptr)
+ return malloc(size);
+
+ void* new_ptr;
+ for (;;) {
+ new_ptr = win_heap_realloc(ptr, size);
+
+ // Subtle warning: NULL return does not alwas indicate out-of-memory. If
+ // the requested new size is zero, realloc should free the ptr and return
+ // NULL.
+ if (new_ptr || !size)
+ return new_ptr;
+ if (!new_mode || !call_new_handler(true, size))
+ break;
+ }
+ return new_ptr;
+}
+
+// heapinit.c
+intptr_t _get_heap_handle() {
+ return reinterpret_cast<intptr_t>(_crtheap);
+}
+
+// heapinit.c
+int _heap_init() {
+ return win_heap_init() ? 1 : 0;
+}
+
+// heapinit.c
+void _heap_term() {
+ win_heap_term();
+}
+
+// calloc.c
+void* calloc(size_t n, size_t elem_size) {
+ // Overflow check.
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n)
+ return NULL;
+
+ void* result = malloc(size);
+ if (result != NULL) {
+ memset(result, 0, size);
+ }
+ return result;
+}
+
+// recalloc.c
+void* _recalloc(void* p, size_t n, size_t elem_size) {
+ if (!p)
+ return calloc(n, elem_size);
+
+ // This API is a bit odd.
+ // Note: recalloc only guarantees zeroed memory when p is NULL.
+ // Generally, calls to malloc() have padding. So a request
+ // to malloc N bytes actually malloc's N+x bytes. Later, if
+ // that buffer is passed to recalloc, we don't know what N
+ // was anymore. We only know what N+x is. As such, there is
+ // no way to know what to zero out.
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n)
+ return NULL;
+ return realloc(p, size);
+}
+
+// calloc_impl.c
+void* _calloc_impl(size_t n, size_t size) {
+ return calloc(n, size);
+}
+
+#ifndef NDEBUG
+#undef malloc
+#undef free
+#undef calloc
+
+static int error_handler(int reportType) {
+ switch (reportType) {
+ case 0: // _CRT_WARN
+ __debugbreak();
+ return 0;
+
+ case 1: // _CRT_ERROR
+ __debugbreak();
+ return 0;
+
+ case 2: // _CRT_ASSERT
+ __debugbreak();
+ return 0;
+ }
+ char* p = NULL;
+ *p = '\0';
+ return 0;
+}
+
+int _CrtDbgReport(int reportType,
+ const char*,
+ int,
+ const char*,
+ const char*,
+ ...) {
+ return error_handler(reportType);
+}
+
+int _CrtDbgReportW(int reportType,
+ const wchar_t*,
+ int,
+ const wchar_t*,
+ const wchar_t*,
+ ...) {
+ return error_handler(reportType);
+}
+
+int _CrtSetReportMode(int, int) {
+ return 0;
+}
+
+void* _malloc_dbg(size_t size, int, const char*, int) {
+ return malloc(size);
+}
+
+void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
+ return realloc(ptr, size);
+}
+
+void _free_dbg(void* ptr, int) {
+ free(ptr);
+}
+
+void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
+ return calloc(n, size);
+}
+#endif // NDEBUG
+
+} // extern C
diff --git a/chromium/base/allocator/allocator_unittest.cc b/chromium/base/allocator/allocator_unittest.cc
index a39b8384452..a1d1ef0c639 100644
--- a/chromium/base/allocator/allocator_unittest.cc
+++ b/chromium/base/allocator/allocator_unittest.cc
@@ -6,7 +6,7 @@
#include <stdlib.h>
#include <algorithm> // for min()
-#include "base/atomicops.h"
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
// Number of bits in a size_t.
@@ -15,10 +15,6 @@ static const int kSizeBits = 8 * sizeof(size_t);
static const size_t kMaxSize = ~static_cast<size_t>(0);
// Maximum positive size of a size_t if it were signed.
static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
-// An allocation size which is not too big to be reasonable.
-static const size_t kNotTooBig = 100000;
-// An allocation size which is just too big.
-static const size_t kTooBig = ~static_cast<size_t>(0);
namespace {
@@ -82,197 +78,6 @@ static int NextSize(int size) {
}
}
-template <class AtomicType>
-static void TestAtomicIncrement() {
- // For now, we just test single threaded execution
-
- // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
- // outside the expected address bounds. This is in particular to
- // test that some future change to the asm code doesn't cause the
- // 32-bit NoBarrier_AtomicIncrement to do the wrong thing on 64-bit machines.
- struct {
- AtomicType prev_word;
- AtomicType count;
- AtomicType next_word;
- } s;
-
- AtomicType prev_word_value, next_word_value;
- memset(&prev_word_value, 0xFF, sizeof(AtomicType));
- memset(&next_word_value, 0xEE, sizeof(AtomicType));
-
- s.prev_word = prev_word_value;
- s.count = 0;
- s.next_word = next_word_value;
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
- EXPECT_EQ(s.count, 1);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
- EXPECT_EQ(s.count, 3);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
- EXPECT_EQ(s.count, 6);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
- EXPECT_EQ(s.count, 3);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
- EXPECT_EQ(s.count, 1);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
- EXPECT_EQ(s.count, 0);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
- EXPECT_EQ(s.count, -1);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
- EXPECT_EQ(s.count, -5);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-
- EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
- EXPECT_EQ(s.count, 0);
- EXPECT_EQ(s.prev_word, prev_word_value);
- EXPECT_EQ(s.next_word, next_word_value);
-}
-
-
-#define NUM_BITS(T) (sizeof(T) * 8)
-
-
-template <class AtomicType>
-static void TestCompareAndSwap() {
- AtomicType value = 0;
- AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
- EXPECT_EQ(1, value);
- EXPECT_EQ(0, prev);
-
- // Use test value that has non-zero bits in both halves, more for testing
- // 64-bit implementation on 32-bit platforms.
- const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
- (NUM_BITS(AtomicType) - 2)) + 11;
- value = k_test_val;
- prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
- EXPECT_EQ(k_test_val, value);
- EXPECT_EQ(k_test_val, prev);
-
- value = k_test_val;
- prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
- EXPECT_EQ(5, value);
- EXPECT_EQ(k_test_val, prev);
-}
-
-
-template <class AtomicType>
-static void TestAtomicExchange() {
- AtomicType value = 0;
- AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
- EXPECT_EQ(1, value);
- EXPECT_EQ(0, new_value);
-
- // Use test value that has non-zero bits in both halves, more for testing
- // 64-bit implementation on 32-bit platforms.
- const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
- (NUM_BITS(AtomicType) - 2)) + 11;
- value = k_test_val;
- new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
- EXPECT_EQ(k_test_val, value);
- EXPECT_EQ(k_test_val, new_value);
-
- value = k_test_val;
- new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
- EXPECT_EQ(5, value);
- EXPECT_EQ(k_test_val, new_value);
-}
-
-
-template <class AtomicType>
-static void TestAtomicIncrementBounds() {
- // Test increment at the half-width boundary of the atomic type.
- // It is primarily for testing at the 32-bit boundary for 64-bit atomic type.
- AtomicType test_val = static_cast<uint64_t>(1) << (NUM_BITS(AtomicType) / 2);
- AtomicType value = test_val - 1;
- AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
- EXPECT_EQ(test_val, value);
- EXPECT_EQ(value, new_value);
-
- base::subtle::NoBarrier_AtomicIncrement(&value, -1);
- EXPECT_EQ(test_val - 1, value);
-}
-
-// This is a simple sanity check that values are correct. Not testing
-// atomicity
-template <class AtomicType>
-static void TestStore() {
- const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
- const AtomicType kVal2 = static_cast<AtomicType>(-1);
-
- AtomicType value;
-
- base::subtle::NoBarrier_Store(&value, kVal1);
- EXPECT_EQ(kVal1, value);
- base::subtle::NoBarrier_Store(&value, kVal2);
- EXPECT_EQ(kVal2, value);
-
- base::subtle::Acquire_Store(&value, kVal1);
- EXPECT_EQ(kVal1, value);
- base::subtle::Acquire_Store(&value, kVal2);
- EXPECT_EQ(kVal2, value);
-
- base::subtle::Release_Store(&value, kVal1);
- EXPECT_EQ(kVal1, value);
- base::subtle::Release_Store(&value, kVal2);
- EXPECT_EQ(kVal2, value);
-}
-
-// This is a simple sanity check that values are correct. Not testing
-// atomicity
-template <class AtomicType>
-static void TestLoad() {
- const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
- const AtomicType kVal2 = static_cast<AtomicType>(-1);
-
- AtomicType value;
-
- value = kVal1;
- EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
- value = kVal2;
- EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
-
- value = kVal1;
- EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
- value = kVal2;
- EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
-
- value = kVal1;
- EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
- value = kVal2;
- EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
-}
-
-template <class AtomicType>
-static void TestAtomicOps() {
- TestCompareAndSwap<AtomicType>();
- TestAtomicExchange<AtomicType>();
- TestAtomicIncrementBounds<AtomicType>();
- TestStore<AtomicType>();
- TestLoad<AtomicType>();
-}
-
static void TestCalloc(size_t n, size_t s, bool ok) {
char* p = reinterpret_cast<char*>(calloc(n, s));
if (!ok) {
@@ -280,87 +85,17 @@ static void TestCalloc(size_t n, size_t s, bool ok) {
} else {
EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
"calloc(n, s) should succeed";
- for (int i = 0; i < n*s; i++) {
+ for (size_t i = 0; i < n*s; i++) {
EXPECT_EQ('\0', p[i]);
}
free(p);
}
}
-// MSVC C4530 complains about exception handler usage when exceptions are
-// disabled. Temporarily disable that warning so we can test that they are, in
-// fact, disabled.
-#if defined(OS_WIN)
-#pragma warning(push)
-#pragma warning(disable: 4530)
-#endif
-
-// A global test counter for number of times the NewHandler is called.
-static int news_handled = 0;
-static void TestNewHandler() {
- ++news_handled;
- throw std::bad_alloc();
-}
-
-// Because we compile without exceptions, we expect these will not throw.
-static void TestOneNewWithoutExceptions(void* (*func)(size_t),
- bool should_throw) {
- // success test
- try {
- void* ptr = (*func)(kNotTooBig);
- EXPECT_NE(reinterpret_cast<void*>(NULL), ptr) <<
- "allocation should not have failed.";
- } catch(...) {
- EXPECT_EQ(0, 1) << "allocation threw unexpected exception.";
- }
-
- // failure test
- try {
- void* rv = (*func)(kTooBig);
- EXPECT_EQ(NULL, rv);
- EXPECT_FALSE(should_throw) << "allocation should have thrown.";
- } catch(...) {
- EXPECT_TRUE(should_throw) << "allocation threw unexpected exception.";
- }
-}
-
-static void TestNothrowNew(void* (*func)(size_t)) {
- news_handled = 0;
-
- // test without new_handler:
- std::new_handler saved_handler = std::set_new_handler(0);
- TestOneNewWithoutExceptions(func, false);
-
- // test with new_handler:
- std::set_new_handler(TestNewHandler);
- TestOneNewWithoutExceptions(func, true);
- EXPECT_EQ(news_handled, 1) << "nothrow new_handler was not called.";
- std::set_new_handler(saved_handler);
-}
-
-#if defined(OS_WIN)
-#pragma warning(pop)
-#endif
-
} // namespace
//-----------------------------------------------------------------------------
-TEST(Atomics, AtomicIncrementWord) {
- TestAtomicIncrement<AtomicWord>();
-}
-
-TEST(Atomics, AtomicIncrement32) {
- TestAtomicIncrement<Atomic32>();
-}
-
-TEST(Atomics, AtomicOpsWord) {
- TestAtomicIncrement<AtomicWord>();
-}
-
-TEST(Atomics, AtomicOps32) {
- TestAtomicIncrement<Atomic32>();
-}
TEST(Allocators, Malloc) {
// Try allocating data with a bunch of alignments and sizes
@@ -394,11 +129,6 @@ TEST(Allocators, Calloc) {
TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
}
-TEST(Allocators, New) {
- TestNothrowNew(&::operator new);
- TestNothrowNew(&::operator new[]);
-}
-
// This makes sure that reallocing a small number of bytes in either
// direction doesn't cause us to allocate new memory.
TEST(Allocators, Realloc1) {
@@ -458,19 +188,6 @@ TEST(Allocators, Realloc2) {
free(p);
}
-TEST(Allocators, ReallocZero) {
- // Test that realloc to zero does not return NULL.
- for (int size = 0; size >= 0; size = NextSize(size)) {
- char* ptr = reinterpret_cast<char*>(malloc(size));
- EXPECT_NE(static_cast<char*>(NULL), ptr);
- ptr = reinterpret_cast<char*>(realloc(ptr, 0));
- EXPECT_NE(static_cast<char*>(NULL), ptr);
- if (ptr)
- free(ptr);
- }
-}
-
-#ifdef WIN32
// Test recalloc
TEST(Allocators, Recalloc) {
for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
@@ -495,7 +212,7 @@ TEST(Allocators, AlignedMalloc) {
// Try allocating data with a bunch of alignments and sizes
static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384};
for (int size = 1; size > 0; size = NextSize(size)) {
- for (int i = 0; i < ARRAYSIZE(kTestAlignments); ++i) {
+ for (int i = 0; i < arraysize(kTestAlignments); ++i) {
unsigned char* ptr = static_cast<unsigned char*>(
_aligned_malloc(size, kTestAlignments[i]));
CheckAlignment(ptr, kTestAlignments[i]);
@@ -522,9 +239,6 @@ TEST(Allocators, AlignedMalloc) {
}
}
-#endif
-
-
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/chromium/base/allocator/generic_allocators.cc b/chromium/base/allocator/generic_allocators.cc
deleted file mode 100644
index d12f3b976ac..00000000000
--- a/chromium/base/allocator/generic_allocators.cc
+++ /dev/null
@@ -1,176 +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.
-
-// When possible, we implement allocator functions on top of the basic
-// low-level functions malloc() and free(). This way, including a new
-// allocator is as simple as providing just a small interface.
-//
-// As such, this file should not contain any allocator-specific code.
-
-// Implement a C++ style allocation, which always calls the new_handler
-// on failure.
-inline void* generic_cpp_alloc(size_t size, bool nothrow) {
- void* ptr;
- for (;;) {
- ptr = malloc(size);
- if (ptr)
- return ptr;
- if (!call_new_handler(nothrow))
- break;
- }
- return ptr;
-}
-
-extern "C++" {
-
-void* operator new(size_t size) {
- return generic_cpp_alloc(size, false);
-}
-
-void operator delete(void* p) {
- free(p);
-}
-
-void* operator new[](size_t size) {
- return generic_cpp_alloc(size, false);
-}
-
-void operator delete[](void* p) {
- free(p);
-}
-
-void* operator new(size_t size, const std::nothrow_t& nt) {
- return generic_cpp_alloc(size, true);
-}
-
-void operator delete(void* p, const std::nothrow_t& nt) {
- free(p);
-}
-
-void* operator new[](size_t size, const std::nothrow_t& nt) {
- return generic_cpp_alloc(size, true);
-}
-
-void operator delete[](void* p, const std::nothrow_t& nt) {
- free(p);
-}
-
-// This function behaves similarly to MSVC's _set_new_mode.
-// If flag is 0 (default), calls to malloc will behave normally.
-// If flag is 1, calls to malloc will behave like calls to new,
-// and the std_new_handler will be invoked on failure.
-// Returns the previous mode.
-int _set_new_mode(int flag) throw() {
- int old_mode = new_mode;
- new_mode = flag;
- return old_mode;
-}
-
-} // extern "C++"
-
-extern "C" {
-
-void* calloc(size_t n, size_t elem_size) {
- // Overflow check
- const size_t size = n * elem_size;
- if (elem_size != 0 && size / elem_size != n) return NULL;
-
- void* result = malloc(size);
- if (result != NULL) {
- memset(result, 0, size);
- }
- return result;
-}
-
-void cfree(void* p) __THROW {
- free(p);
-}
-
-#ifdef WIN32
-
-void* _recalloc(void* p, size_t n, size_t elem_size) {
- if (!p)
- return calloc(n, elem_size);
-
- // This API is a bit odd.
- // Note: recalloc only guarantees zeroed memory when p is NULL.
- // Generally, calls to malloc() have padding. So a request
- // to malloc N bytes actually malloc's N+x bytes. Later, if
- // that buffer is passed to recalloc, we don't know what N
- // was anymore. We only know what N+x is. As such, there is
- // no way to know what to zero out.
- const size_t size = n * elem_size;
- if (elem_size != 0 && size / elem_size != n) return NULL;
- return realloc(p, size);
-}
-
-void* _calloc_impl(size_t n, size_t size) {
- return calloc(n, size);
-}
-
-#ifndef NDEBUG
-#undef malloc
-#undef free
-#undef calloc
-
-static int error_handler(int reportType) {
- switch (reportType) {
- case 0: // _CRT_WARN
- __debugbreak();
- return 0;
-
- case 1: // _CRT_ERROR
- __debugbreak();
- return 0;
-
- case 2: // _CRT_ASSERT
- __debugbreak();
- return 0;
- }
- char* p = NULL;
- *p = '\0';
- return 0;
-}
-
-int _CrtDbgReport(int reportType,
- const char*,
- int, const char*,
- const char*,
- ...) {
- return error_handler(reportType);
-}
-
-int _CrtDbgReportW(int reportType,
- const wchar_t*,
- int, const wchar_t*,
- const wchar_t*,
- ...) {
- return error_handler(reportType);
-}
-
-int _CrtSetReportMode(int, int) {
- return 0;
-}
-
-void* _malloc_dbg(size_t size, int , const char*, int) {
- return malloc(size);
-}
-
-void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
- return realloc(ptr, size);
-}
-
-void _free_dbg(void* ptr, int) {
- free(ptr);
-}
-
-void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
- return calloc(n, size);
-}
-#endif // NDEBUG
-
-#endif // WIN32
-
-} // extern C
-
diff --git a/chromium/base/allocator/prep_libc.py b/chromium/base/allocator/prep_libc.py
index 471140cb548..079297b4629 100755
--- a/chromium/base/allocator/prep_libc.py
+++ b/chromium/base/allocator/prep_libc.py
@@ -4,8 +4,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
-# This script takes libcmt.lib for VS2005/08/10/12/13 and removes the allocation
-# related functions from it.
+# This script takes libcmt.lib for VS2013 and removes the allocation related
+# functions from it.
#
# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch>
#
@@ -19,16 +19,18 @@ import shutil
import subprocess
import sys
-def run(command, filter=None):
- """Run |command|, removing any lines that match |filter|. The filter is
- to remove the echoing of input filename that 'lib' does."""
+def run(command):
+ """Run |command|. If any lines that match an error condition then
+ terminate."""
+ error = 'cannot find member object'
popen = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = popen.communicate()
for line in out.splitlines():
- if filter and line.strip() != filter:
- print line
- return popen.returncode
+ print line
+ if error and line.find(error) != -1:
+ print 'prep_libc.py: Error stripping object from C runtime.'
+ sys.exit(1)
def main():
bindir = 'SELF_X86'
@@ -43,28 +45,23 @@ def main():
shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
os.path.join(outdir, 'libcmt.pdb'))
+ cvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
+ '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativec\\\\';
+ cppvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
+ '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\';
- vspaths = [
- 'build\\intel\\mt_obj\\',
- 'f:\\dd\\vctools\\crt_bld\\' + bindir + \
- '\\crt\\src\\build\\' + objdir + '\\mt_obj\\',
- 'F:\\dd\\vctools\\crt_bld\\' + bindir + \
- '\\crt\\src\\build\\' + objdir + '\\mt_obj\\nativec\\\\',
- 'F:\\dd\\vctools\\crt_bld\\' + bindir + \
- '\\crt\\src\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\',
- 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
- '\\crt\\prebuild\\build\\INTEL\\mt_obj\\cpp_obj\\\\',
- ]
-
- objfiles = ['malloc', 'free', 'realloc', 'new', 'delete', 'new2', 'delete2',
- 'align', 'msize', 'heapinit', 'expand', 'heapchk', 'heapwalk',
- 'heapmin', 'sbheap', 'calloc', 'recalloc', 'calloc_impl',
- 'new_mode', 'newopnt', 'newaopnt']
- for obj in objfiles:
- for vspath in vspaths:
- cmd = ('lib /nologo /ignore:4006,4014,4221 /remove:%s%s.obj %s' %
- (vspath, obj, output_lib))
- run(cmd, obj + '.obj')
+ cobjfiles = ['malloc', 'free', 'realloc', 'heapinit', 'calloc', 'recalloc',
+ 'calloc_impl']
+ cppobjfiles = ['new', 'new2', 'delete', 'delete2', 'new_mode', 'newopnt',
+ 'newaopnt']
+ for obj in cobjfiles:
+ cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
+ (cvspath, obj, output_lib))
+ run(cmd)
+ for obj in cppobjfiles:
+ cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
+ (cppvspath, obj, output_lib))
+ run(cmd)
if __name__ == "__main__":
sys.exit(main())
diff --git a/chromium/base/allocator/tcmalloc_unittest.cc b/chromium/base/allocator/tcmalloc_unittest.cc
index 053a9d50d79..0f7082eb026 100644
--- a/chromium/base/allocator/tcmalloc_unittest.cc
+++ b/chromium/base/allocator/tcmalloc_unittest.cc
@@ -1,17 +1,32 @@
// Copyright (c) 2012 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 <stddef.h>
#include <stdio.h>
-#include "base/allocator/allocator_shim.h"
#include "testing/gtest/include/gtest/gtest.h"
-// TCMalloc header files
+// TCMalloc header files.
#include "common.h" // For TCMalloc constants like page size, etc.
-using base::allocator::TCMallocDoMallocForTest;
-using base::allocator::TCMallocDoFreeForTest;
-using base::allocator::ExcludeSpaceForMarkForTest;
+// TCMalloc implementation.
+#include "debugallocation_shim.cc"
+
+namespace {
+
+void* TCMallocDoMallocForTest(size_t size) {
+ return do_malloc(size);
+}
+
+void TCMallocDoFreeForTest(void* ptr) {
+ do_free(ptr);
+}
+
+size_t ExcludeSpaceForMarkForTest(size_t size) {
+ return ExcludeSpaceForMark(size);
+}
+
+} // namespace
TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
char* p = reinterpret_cast<char*>(
diff --git a/chromium/base/allocator/win_allocator.cc b/chromium/base/allocator/win_allocator.cc
deleted file mode 100644
index ee451f54610..00000000000
--- a/chromium/base/allocator/win_allocator.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This is a simple allocator based on the windows heap.
-
-extern "C" {
-
-HANDLE win_heap;
-
-bool win_heap_init(bool use_lfh) {
- win_heap = HeapCreate(0, 0, 0);
- if (win_heap == NULL)
- return false;
-
- if (use_lfh) {
- ULONG enable_lfh = 2;
- HeapSetInformation(win_heap, HeapCompatibilityInformation,
- &enable_lfh, sizeof(enable_lfh));
- // NOTE: Setting LFH may fail. Vista already has it enabled.
- // And under the debugger, it won't use LFH. So we
- // ignore any errors.
- }
-
- return true;
-}
-
-void* win_heap_malloc(size_t size) {
- return HeapAlloc(win_heap, 0, size);
-}
-
-void win_heap_free(void* size) {
- HeapFree(win_heap, 0, size);
-}
-
-void* win_heap_realloc(void* ptr, size_t size) {
- if (!ptr)
- return win_heap_malloc(size);
- if (!size) {
- win_heap_free(ptr);
- return NULL;
- }
- return HeapReAlloc(win_heap, 0, ptr, size);
-}
-
-size_t win_heap_msize(void* ptr) {
- return HeapSize(win_heap, 0, ptr);
-}
-
-void* win_heap_memalign(size_t alignment, size_t size) {
- // Reserve enough space to ensure we can align and set aligned_ptr[-1] to the
- // original allocation for use with win_heap_memalign_free() later.
- size_t allocation_size = size + (alignment - 1) + sizeof(void*);
-
- // Check for overflow. Alignment and size are checked in allocator_shim.
- DCHECK_LT(size, allocation_size);
- DCHECK_LT(alignment, allocation_size);
-
- // Since we're directly calling the allocator function, before OOM handling,
- // we need to NULL check to ensure the allocation succeeded.
- void* ptr = win_heap_malloc(allocation_size);
- if (!ptr)
- return ptr;
-
- char* aligned_ptr = static_cast<char*>(ptr) + sizeof(void*);
- aligned_ptr +=
- alignment - reinterpret_cast<uintptr_t>(aligned_ptr) & (alignment - 1);
-
- reinterpret_cast<void**>(aligned_ptr)[-1] = ptr;
- return aligned_ptr;
-}
-
-void win_heap_memalign_free(void* ptr) {
- if (ptr)
- win_heap_free(static_cast<void**>(ptr)[-1]);
-}
-
-} // extern "C"
diff --git a/chromium/base/android/animation_frame_time_histogram.cc b/chromium/base/android/animation_frame_time_histogram.cc
new file mode 100644
index 00000000000..0d796193829
--- /dev/null
+++ b/chromium/base/android/animation_frame_time_histogram.cc
@@ -0,0 +1,36 @@
+// Copyright 2015 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/android/animation_frame_time_histogram.h"
+
+#include "base/android/jni_string.h"
+#include "base/metrics/histogram_macros.h"
+#include "jni/AnimationFrameTimeHistogram_jni.h"
+
+// static
+void SaveHistogram(JNIEnv* env,
+ jobject jcaller,
+ jstring j_histogram_name,
+ jlongArray j_frame_times_ms,
+ jint j_count) {
+ jlong *frame_times_ms = env->GetLongArrayElements(j_frame_times_ms, NULL);
+ std::string histogram_name = base::android::ConvertJavaStringToUTF8(
+ env, j_histogram_name);
+
+ for (int i = 0; i < j_count; ++i) {
+ UMA_HISTOGRAM_TIMES(histogram_name.c_str(),
+ base::TimeDelta::FromMilliseconds(frame_times_ms[i]));
+ }
+}
+
+namespace base {
+namespace android {
+
+// static
+bool RegisterAnimationFrameTimeHistogram(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/animation_frame_time_histogram.h b/chromium/base/android/animation_frame_time_histogram.h
new file mode 100644
index 00000000000..63f938b922d
--- /dev/null
+++ b/chromium/base/android/animation_frame_time_histogram.h
@@ -0,0 +1,18 @@
+// Copyright 2015 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_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
+#define BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterAnimationFrameTimeHistogram(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
diff --git a/chromium/base/android/application_status_listener.cc b/chromium/base/android/application_status_listener.cc
index f48707282f5..02178c47bf3 100644
--- a/chromium/base/android/application_status_listener.cc
+++ b/chromium/base/android/application_status_listener.cc
@@ -60,7 +60,8 @@ bool ApplicationStatusListener::RegisterBindings(JNIEnv* env) {
// static
void ApplicationStatusListener::NotifyApplicationStateChange(
ApplicationState state) {
- g_observers.Get().Notify(&ApplicationStatusListener::Notify, state);
+ g_observers.Get().Notify(FROM_HERE, &ApplicationStatusListener::Notify,
+ state);
}
static void OnApplicationStateChange(JNIEnv* env,
diff --git a/chromium/base/android/application_status_listener_unittest.cc b/chromium/base/android/application_status_listener_unittest.cc
index 1049628f5a3..ce78bf9c862 100644
--- a/chromium/base/android/application_status_listener_unittest.cc
+++ b/chromium/base/android/application_status_listener_unittest.cc
@@ -7,7 +7,7 @@
#include "base/callback_forward.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
@@ -49,9 +49,8 @@ class MultiThreadedTest {
void Run() {
// Start the thread and tell it to register for events.
thread_.Start();
- thread_.message_loop()
- ->PostTask(FROM_HERE,
- base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
+ thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
base::Unretained(this)));
// Wait for its completion.
diff --git a/chromium/base/android/build_info.cc b/chromium/base/android/build_info.cc
index 11202a0627e..4d3cd559ede 100644
--- a/chromium/base/android/build_info.cc
+++ b/chromium/base/android/build_info.cc
@@ -68,11 +68,16 @@ BuildInfo* BuildInfo::GetInstance() {
return Singleton<BuildInfo, BuildInfoSingletonTraits >::get();
}
-void BuildInfo::set_java_exception_info(const std::string& info) {
+void BuildInfo::SetJavaExceptionInfo(const std::string& info) {
DCHECK(!java_exception_info_) << "info should be set only once.";
java_exception_info_ = strndup(info.c_str(), 4096);
}
+void BuildInfo::ClearJavaExceptionInfo() {
+ delete java_exception_info_;
+ java_exception_info_ = nullptr;
+}
+
// static
bool BuildInfo::RegisterBindings(JNIEnv* env) {
return RegisterNativesImpl(env);
diff --git a/chromium/base/android/build_info.h b/chromium/base/android/build_info.h
index cef8145fa6a..d6155b9eed9 100644
--- a/chromium/base/android/build_info.h
+++ b/chromium/base/android/build_info.h
@@ -15,6 +15,17 @@
namespace base {
namespace android {
+// This enumeration maps to the values returned by BuildInfo::sdk_int(),
+// indicating the Android release associated with a given SDK version.
+enum SdkVersion {
+ SDK_VERSION_JELLY_BEAN = 16,
+ SDK_VERSION_JELLY_BEAN_MR1 = 17,
+ SDK_VERSION_JELLY_BEAN_MR2 = 18,
+ SDK_VERSION_KITKAT = 19,
+ SDK_VERSION_KITKAT_WEAR = 20,
+ SDK_VERSION_LOLLIPOP = 21
+};
+
// BuildInfo is a singleton class that stores android build and device
// information. It will be called from Android specific code and gets used
// primarily in crash reporting.
@@ -88,7 +99,9 @@ class BASE_EXPORT BuildInfo {
return java_exception_info_;
}
- void set_java_exception_info(const std::string& info);
+ void SetJavaExceptionInfo(const std::string& info);
+
+ void ClearJavaExceptionInfo();
static bool RegisterBindings(JNIEnv* env);
diff --git a/chromium/base/android/command_line_android.cc b/chromium/base/android/command_line_android.cc
index 895ffab4f95..064450dd725 100644
--- a/chromium/base/android/command_line_android.cc
+++ b/chromium/base/android/command_line_android.cc
@@ -12,6 +12,7 @@
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
+using base::CommandLine;
namespace {
diff --git a/chromium/base/android/content_uri_utils.cc b/chromium/base/android/content_uri_utils.cc
index 0e0c0ea6bb1..0482feef891 100644
--- a/chromium/base/android/content_uri_utils.cc
+++ b/chromium/base/android/content_uri_utils.cc
@@ -35,4 +35,14 @@ File OpenContentUriForRead(const FilePath& content_uri) {
return File(fd);
}
+std::string GetContentUriMimeType(const FilePath& content_uri) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_uri =
+ ConvertUTF8ToJavaString(env, content_uri.value());
+ ScopedJavaLocalRef<jstring> j_mime =
+ Java_ContentUriUtils_getMimeType(
+ env, base::android::GetApplicationContext(), j_uri.obj());
+ return base::android::ConvertJavaStringToUTF8(env, j_mime.obj());
+}
+
} // namespace base
diff --git a/chromium/base/android/content_uri_utils.h b/chromium/base/android/content_uri_utils.h
index 827ec92fa39..e66b77077e1 100644
--- a/chromium/base/android/content_uri_utils.h
+++ b/chromium/base/android/content_uri_utils.h
@@ -16,13 +16,17 @@ namespace base {
bool RegisterContentUriUtils(JNIEnv* env);
-// Opens a content uri for read and returns the file descriptor to the caller.
-// Returns -1 if the uri is invalid.
+// Opens a content URI for read and returns the file descriptor to the caller.
+// Returns -1 if the URI is invalid.
BASE_EXPORT File OpenContentUriForRead(const FilePath& content_uri);
-// Check whether a content uri exists.
+// Check whether a content URI exists.
BASE_EXPORT bool ContentUriExists(const FilePath& content_uri);
+// Gets MIME type from a content URI. Returns an empty string if the URI is
+// invalid.
+BASE_EXPORT std::string GetContentUriMimeType(const FilePath& content_uri);
+
} // namespace base
#endif // BASE_ANDROID_CONTENT_URI_UTILS_H_
diff --git a/chromium/base/android/content_uri_utils_unittest.cc b/chromium/base/android/content_uri_utils_unittest.cc
new file mode 100644
index 00000000000..c762035afb2
--- /dev/null
+++ b/chromium/base/android/content_uri_utils_unittest.cc
@@ -0,0 +1,37 @@
+// Copyright 2014 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/android/content_uri_utils.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/test_file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(ContentUriUtilsTest, ContentUriMimeTest) {
+ // Get the test image path.
+ FilePath data_dir;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+ data_dir = data_dir.AppendASCII("file_util");
+ ASSERT_TRUE(PathExists(data_dir));
+ FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
+
+ // Insert the image into MediaStore. MediaStore will do some conversions, and
+ // return the content URI.
+ FilePath path = base::InsertImageIntoMediaStore(image_file);
+ EXPECT_TRUE(path.IsContentUri());
+ EXPECT_TRUE(PathExists(path));
+
+ std::string mime = GetContentUriMimeType(path);
+ EXPECT_EQ(mime, std::string("image/png"));
+
+ FilePath invalid_path("content://foo.bar");
+ mime = GetContentUriMimeType(invalid_path);
+ EXPECT_TRUE(mime.empty());
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/important_file_writer_android.h b/chromium/base/android/important_file_writer_android.h
index 20956babcea..88e44418a29 100644
--- a/chromium/base/android/important_file_writer_android.h
+++ b/chromium/base/android/important_file_writer_android.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NATIVE_FRAMEWORK_CHROME_IMPORTANT_FILE_WRITE_ANDROID_H_
-#define NATIVE_FRAMEWORK_CHROME_IMPORTANT_FILE_WRITE_ANDROID_H_
+#ifndef BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
+#define BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
#include <jni.h>
@@ -15,4 +15,4 @@ bool RegisterImportantFileWriterAndroid(JNIEnv* env);
} // namespace android
} // namespace base
-#endif // NATIVE_FRAMEWORK_CHROME_IMPORTANT_FILE_WRITE_ANDROID_H_
+#endif // BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
diff --git a/chromium/base/android/jni_generator/jni_generator.gyp b/chromium/base/android/jni_generator/jni_generator.gyp
index 2ea36b0b389..4a17f3e57c1 100644
--- a/chromium/base/android/jni_generator/jni_generator.gyp
+++ b/chromium/base/android/jni_generator/jni_generator.gyp
@@ -7,6 +7,9 @@
{
'target_name': 'jni_generator_py_tests',
'type': 'none',
+ 'variables': {
+ 'stamp': '<(INTERMEDIATE_DIR)/jni_generator_py_tests.stamp',
+ },
'actions': [
{
'action_name': 'run_jni_generator_py_tests',
@@ -17,10 +20,11 @@
'golden_sample_for_tests_jni.h',
],
'outputs': [
- '',
+ '<(stamp)',
],
'action': [
'python', 'jni_generator_tests.py',
+ '--stamp=<(stamp)',
],
},
],
diff --git a/chromium/base/android/library_loader/library_load_from_apk_status_codes.h b/chromium/base/android/library_loader/library_load_from_apk_status_codes.h
index f99eebc8989..9591d3f6a37 100644
--- a/chromium/base/android/library_loader/library_load_from_apk_status_codes.h
+++ b/chromium/base/android/library_loader/library_load_from_apk_status_codes.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_ANDROID_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
-#define BASE_ANDROID_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
namespace base {
namespace android {
@@ -43,4 +43,4 @@ enum LibraryLoadFromApkStatusCodes {
} // namespace android
} // namespace base
-#endif // BASE_ANDROID_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+#endif // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
diff --git a/chromium/base/android/library_loader/library_loader_hooks.cc b/chromium/base/android/library_loader/library_loader_hooks.cc
index 809275dc431..0b59a304296 100644
--- a/chromium/base/android/library_loader/library_loader_hooks.cc
+++ b/chromium/base/android/library_loader/library_loader_hooks.cc
@@ -7,6 +7,7 @@
#include "base/android/command_line_android.h"
#include "base/android/jni_string.h"
#include "base/android/library_loader/library_load_from_apk_status_codes.h"
+#include "base/android/library_loader/library_prefetcher.h"
#include "base/at_exit.h"
#include "base/metrics/histogram.h"
#include "jni/LibraryLoader_jni.h"
@@ -51,7 +52,7 @@ RendererHistogramCode g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
static void RegisterChromiumAndroidLinkerRendererHistogram(
JNIEnv* env,
- jclass clazz,
+ jobject jcaller,
jboolean requested_shared_relro,
jboolean load_at_fixed_address_failed) {
// Note a pending histogram value for later recording.
@@ -75,7 +76,7 @@ void RecordChromiumAndroidLinkerRendererHistogram() {
static void RecordChromiumAndroidLinkerBrowserHistogram(
JNIEnv* env,
- jclass clazz,
+ jobject jcaller,
jboolean is_using_browser_shared_relros,
jboolean load_at_fixed_address_failed,
jint library_load_from_apk_status) {
@@ -102,16 +103,17 @@ void SetLibraryLoadedHook(LibraryLoadedHook* func) {
g_registration_callback = func;
}
-static void InitCommandLine(JNIEnv* env, jclass clazz,
+static void InitCommandLine(JNIEnv* env,
+ jobject jcaller,
jobjectArray init_command_line) {
InitNativeCommandLineFromJavaArray(env, init_command_line);
}
-static jboolean LibraryLoaded(JNIEnv* env, jclass clazz) {
+static jboolean LibraryLoaded(JNIEnv* env, jobject jcaller) {
if (g_registration_callback == NULL) {
return true;
}
- return g_registration_callback(env, clazz);
+ return g_registration_callback(env, NULL);
}
void LibraryLoaderExitHook() {
@@ -121,10 +123,11 @@ void LibraryLoaderExitHook() {
}
}
-bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
- // We need the AtExitManager to be created at the very beginning.
- g_at_exit_manager = new base::AtExitManager();
+static jboolean ForkAndPrefetchNativeLibrary(JNIEnv* env, jclass clazz) {
+ return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+}
+bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
return RegisterNativesImpl(env);
}
@@ -132,12 +135,17 @@ void SetVersionNumber(const char* version_number) {
g_library_version_number = strdup(version_number);
}
-jstring GetVersionNumber(JNIEnv* env, jclass clazz) {
+jstring GetVersionNumber(JNIEnv* env, jobject jcaller) {
return ConvertUTF8ToJavaString(env, g_library_version_number).Release();
}
-static void RecordNativeLibraryHack(JNIEnv*, jclass, jboolean usedHack) {
- UMA_HISTOGRAM_BOOLEAN("LibraryLoader.NativeLibraryHack", usedHack);
+LibraryProcessType GetLibraryProcessType(JNIEnv* env) {
+ return static_cast<LibraryProcessType>(
+ Java_LibraryLoader_getLibraryProcessType(env));
+}
+
+void InitAtExitManager() {
+ g_at_exit_manager = new base::AtExitManager();
}
} // namespace android
diff --git a/chromium/base/android/library_loader/library_loader_hooks.h b/chromium/base/android/library_loader/library_loader_hooks.h
index 78dc5359f3e..ca3c5a20ae8 100644
--- a/chromium/base/android/library_loader/library_loader_hooks.h
+++ b/chromium/base/android/library_loader/library_loader_hooks.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_ANDROID_LIBRARY_LOADER_HOOKS_H_
-#define BASE_ANDROID_LIBRARY_LOADER_HOOKS_H_
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
#include <jni.h>
@@ -12,6 +12,19 @@
namespace base {
namespace android {
+// The process the shared library is loaded in.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.library_loader
+enum LibraryProcessType {
+ // The LibraryLoad has not been initialized.
+ PROCESS_UNINITIALIZED = 0,
+ // Shared library is running in browser process.
+ PROCESS_BROWSER = 1,
+ // Shared library is running in child process.
+ PROCESS_CHILD = 2,
+ // Shared library is running in webview process.
+ PROCESS_WEBVIEW = 3,
+};
+
// Record any pending renderer histogram value as a histogram. Pending values
// are set by RegisterChromiumAndroidLinkerRendererHistogram.
BASE_EXPORT void RecordChromiumAndroidLinkerRendererHistogram();
@@ -48,7 +61,14 @@ BASE_EXPORT void SetVersionNumber(const char* version_number);
// created.
BASE_EXPORT void LibraryLoaderExitHook();
+// Return the process type the shared library is loaded in.
+BASE_EXPORT LibraryProcessType GetLibraryProcessType(JNIEnv* env);
+
+// Initialize AtExitManager, this must be done at the begining of loading
+// shared library.
+void InitAtExitManager();
+
} // namespace android
} // namespace base
-#endif // BASE_ANDROID_LIBRARY_LOADER_HOOKS_H_
+#endif // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
diff --git a/chromium/base/android/library_loader/library_prefetcher.cc b/chromium/base/android/library_loader/library_prefetcher.cc
new file mode 100644
index 00000000000..798a283d71b
--- /dev/null
+++ b/chromium/base/android/library_loader/library_prefetcher.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 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/android/library_loader/library_prefetcher.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+// Android defines the background priority to this value since at least 2009
+// (see Process.java).
+const int kBackgroundPriority = 10;
+// Valid for all the Android architectures.
+const size_t kPageSize = 4096;
+const char* kLibchromeSuffix = "libchrome.so";
+// "base.apk" is a suffix because the library may be loaded directly from the
+// APK.
+const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
+
+bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
+ return region.permissions & base::debug::MappedMemoryRegion::READ &&
+ region.permissions & base::debug::MappedMemoryRegion::PRIVATE;
+}
+
+bool PathMatchesSuffix(const std::string& path) {
+ for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
+ if (EndsWith(path, kSuffixesToMatch[i], true)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// For each range, reads a byte per page to force it into the page cache.
+// Heap allocations, syscalls and library functions are not allowed in this
+// function.
+// Returns true for success.
+bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
+ for (const auto& range : ranges) {
+ const uintptr_t page_mask = kPageSize - 1;
+ // If start or end is not page-aligned, parsing went wrong. It is better to
+ // exit with an error.
+ if ((range.first & page_mask) || (range.second & page_mask)) {
+ return false; // CHECK() is not allowed here.
+ }
+ unsigned char* start_ptr = reinterpret_cast<unsigned char*>(range.first);
+ unsigned char* end_ptr = reinterpret_cast<unsigned char*>(range.second);
+ unsigned char dummy = 0;
+ for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
+ // Volatile is required to prevent the compiler from eliminating this
+ // loop.
+ dummy ^= *static_cast<volatile unsigned char*>(ptr);
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+bool NativeLibraryPrefetcher::IsGoodToPrefetch(
+ const base::debug::MappedMemoryRegion& region) {
+ return PathMatchesSuffix(region.path) &&
+ IsReadableAndPrivate(region); // .text and .data mappings are private.
+}
+
+// static
+void NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(
+ const std::vector<base::debug::MappedMemoryRegion>& regions,
+ std::vector<AddressRange>* ranges) {
+ bool has_libchrome_region = false;
+ for (const base::debug::MappedMemoryRegion& region : regions) {
+ if (EndsWith(region.path, kLibchromeSuffix, true)) {
+ has_libchrome_region = true;
+ break;
+ }
+ }
+ for (const base::debug::MappedMemoryRegion& region : regions) {
+ if (has_libchrome_region &&
+ !EndsWith(region.path, kLibchromeSuffix, true)) {
+ continue;
+ }
+ ranges->push_back(std::make_pair(region.start, region.end));
+ }
+}
+
+// static
+bool NativeLibraryPrefetcher::FindRanges(std::vector<AddressRange>* ranges) {
+ std::string proc_maps;
+ if (!base::debug::ReadProcMaps(&proc_maps))
+ return false;
+ std::vector<base::debug::MappedMemoryRegion> regions;
+ if (!base::debug::ParseProcMaps(proc_maps, &regions))
+ return false;
+
+ std::vector<base::debug::MappedMemoryRegion> regions_to_prefetch;
+ for (const auto& region : regions) {
+ if (IsGoodToPrefetch(region)) {
+ regions_to_prefetch.push_back(region);
+ }
+ }
+
+ FilterLibchromeRangesOnlyIfPossible(regions_to_prefetch, ranges);
+ return true;
+}
+
+// static
+bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+ // Looking for ranges is done before the fork, to avoid syscalls and/or memory
+ // allocations in the forked process. The child process inherits the lock
+ // state of its parent thread. It cannot rely on being able to acquire any
+ // lock (unless special care is taken in a pre-fork handler), including being
+ // able to call malloc().
+ std::vector<AddressRange> ranges;
+ if (!FindRanges(&ranges))
+ return false;
+ pid_t pid = fork();
+ if (pid == 0) {
+ setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
+ // _exit() doesn't call the atexit() handlers.
+ _exit(Prefetch(ranges) ? 0 : 1);
+ } else {
+ if (pid < 0) {
+ return false;
+ }
+ int status;
+ const pid_t result = HANDLE_EINTR(waitpid(pid, &status, 0));
+ if (result == pid) {
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status) == 0;
+ }
+ }
+ return false;
+ }
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/library_loader/library_prefetcher.h b/chromium/base/android/library_loader/library_prefetcher.h
new file mode 100644
index 00000000000..64e5e1ecb4b
--- /dev/null
+++ b/chromium/base/android/library_loader/library_prefetcher.h
@@ -0,0 +1,67 @@
+// Copyright 2015 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_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+
+#include <jni.h>
+
+#include <stdint.h>
+#include <string>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace android {
+
+// Forks and waits for a process prefetching the native library. This is done in
+// a forked process for the following reasons:
+// - Isolating the main process from mistakes in the parsing. If the parsing
+// returns an incorrect address, only the forked process will crash.
+// - Not inflating the memory used by the main process uselessly, which could
+// increase its likelihood to be killed.
+// The forked process has background priority and, since it is not declared to
+// the Android runtime, can be killed at any time, which is not an issue here.
+class BASE_EXPORT NativeLibraryPrefetcher {
+ public:
+ // Finds the ranges matching the native library, forks a low priority
+ // process pre-fetching these ranges and wait()s for it.
+ // Returns true for success.
+ static bool ForkAndPrefetchNativeLibrary();
+
+ private:
+ using AddressRange = std::pair<uintptr_t, uintptr_t>;
+ // Returns true if the region matches native code or data.
+ static bool IsGoodToPrefetch(const base::debug::MappedMemoryRegion& region);
+ // Filters the regions to keep only libchrome ranges if possible.
+ static void FilterLibchromeRangesOnlyIfPossible(
+ const std::vector<base::debug::MappedMemoryRegion>& regions,
+ std::vector<AddressRange>* ranges);
+ // Finds the ranges matching the native library in /proc/self/maps.
+ // Returns true for success.
+ static bool FindRanges(std::vector<AddressRange>* ranges);
+
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchNoRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchUnreadableRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchSkipSharedRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchLibchromeRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestIsGoodToPrefetchBaseApkRange);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
+};
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
diff --git a/chromium/base/android/library_loader/library_prefetcher_unittest.cc b/chromium/base/android/library_loader/library_prefetcher_unittest.cc
new file mode 100644
index 00000000000..7b7296f5f61
--- /dev/null
+++ b/chromium/base/android/library_loader/library_prefetcher_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 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/android/library_loader/library_prefetcher.h"
+
+#include <string>
+#include <vector>
+#include "base/debug/proc_maps_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+const uint8 kRead = base::debug::MappedMemoryRegion::READ;
+const uint8 kReadPrivate = base::debug::MappedMemoryRegion::READ |
+ base::debug::MappedMemoryRegion::PRIVATE;
+const uint8 kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
+ base::debug::MappedMemoryRegion::PRIVATE;
+} // namespace
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
+ const base::debug::MappedMemoryRegion regions[4] = {
+ base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, ""},
+ base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, "foo"},
+ base::debug::MappedMemoryRegion{
+ 0x4000, 0x5000, 10, kReadPrivate, "foobar.apk"},
+ base::debug::MappedMemoryRegion{
+ 0x4000, 0x5000, 10, kReadPrivate, "libchromium.so"}};
+ for (int i = 0; i < 4; ++i) {
+ ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(regions[i]));
+ }
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchUnreadableRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kExecutePrivate, "base.apk"};
+ ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchSkipSharedRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kRead, "base.apk"};
+ ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchLibchromeRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kReadPrivate, "libchrome.so"};
+ ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchBaseApkRange) {
+ const base::debug::MappedMemoryRegion region = {
+ 0x4000, 0x5000, 10, kReadPrivate, "base.apk"};
+ ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome) {
+ std::vector<base::debug::MappedMemoryRegion> regions;
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+ std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+ NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+ &ranges);
+ EXPECT_EQ(ranges.size(), 2U);
+ EXPECT_EQ(ranges[0].first, 0x1U);
+ EXPECT_EQ(ranges[0].second, 0x2U);
+ EXPECT_EQ(ranges[1].first, 0x3U);
+ EXPECT_EQ(ranges[1].second, 0x4U);
+}
+
+TEST(NativeLibraryPrefetcherTest,
+ TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome) {
+ std::vector<base::debug::MappedMemoryRegion> regions;
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+ regions.push_back(base::debug::MappedMemoryRegion{
+ 0x6, 0x7, 0, kReadPrivate, "libchrome.so"});
+ regions.push_back(
+ base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+ std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+ NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+ &ranges);
+ EXPECT_EQ(ranges.size(), 1U);
+ EXPECT_EQ(ranges[0].first, 0x6U);
+ EXPECT_EQ(ranges[0].second, 0x7U);
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/linker/BUILD.gn b/chromium/base/android/linker/BUILD.gn
index b26e3b041f6..190ea4776d4 100644
--- a/chromium/base/android/linker/BUILD.gn
+++ b/chromium/base/android/linker/BUILD.gn
@@ -5,15 +5,19 @@
import("//build/config/android/config.gni")
assert(is_android)
-assert(!is_android_webview_build)
# GYP: //base/base.gyp:chromium_android_linker
shared_library("chromium_android_linker") {
- sources = [ "linker_jni.cc" ]
+ sources = [
+ "linker_jni.cc",
+ ]
+
# The NDK contains the crazy_linker here:
# '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
# However, we use our own fork. See bug 384700.
- deps = [ "//third_party/android_crazy_linker" ]
+ deps = [
+ "//third_party/android_crazy_linker",
+ ]
# TODO(GYP):
# The crazy linker is never instrumented.
diff --git a/chromium/base/android/record_histogram.cc b/chromium/base/android/record_histogram.cc
new file mode 100644
index 00000000000..9a68deca54f
--- /dev/null
+++ b/chromium/base/android/record_histogram.cc
@@ -0,0 +1,245 @@
+// Copyright 2014 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/android/record_histogram.h"
+
+#include <map>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/lazy_instance.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "jni/RecordHistogram_jni.h"
+
+namespace base {
+namespace android {
+namespace {
+
+// Simple thread-safe wrapper for caching histograms. This avoids
+// relatively expensive JNI string translation for each recording.
+class HistogramCache {
+ public:
+ HistogramCache() {}
+
+ HistogramBase* BooleanHistogram(JNIEnv* env,
+ jstring j_histogram_name,
+ jint j_histogram_key) {
+ DCHECK(j_histogram_name);
+ DCHECK(j_histogram_key);
+ HistogramBase* histogram = FindLocked(j_histogram_key);
+ if (histogram)
+ return histogram;
+
+ std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+ histogram = BooleanHistogram::FactoryGet(
+ histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
+ return InsertLocked(j_histogram_key, histogram);
+ }
+
+ HistogramBase* EnumeratedHistogram(JNIEnv* env,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jint j_boundary) {
+ DCHECK(j_histogram_name);
+ DCHECK(j_histogram_key);
+ HistogramBase* histogram = FindLocked(j_histogram_key);
+ int boundary = static_cast<int>(j_boundary);
+ if (histogram) {
+ DCHECK(histogram->HasConstructionArguments(1, boundary, boundary + 1));
+ return histogram;
+ }
+
+ std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+ histogram =
+ LinearHistogram::FactoryGet(histogram_name, 1, boundary, boundary + 1,
+ HistogramBase::kUmaTargetedHistogramFlag);
+ return InsertLocked(j_histogram_key, histogram);
+ }
+
+ HistogramBase* CustomCountHistogram(JNIEnv* env,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jint j_min,
+ jint j_max,
+ jint j_num_buckets) {
+ DCHECK(j_histogram_name);
+ DCHECK(j_histogram_key);
+ int64 min = static_cast<int64>(j_min);
+ int64 max = static_cast<int64>(j_max);
+ int num_buckets = static_cast<int>(j_num_buckets);
+ HistogramBase* histogram = FindLocked(j_histogram_key);
+ if (histogram) {
+ DCHECK(histogram->HasConstructionArguments(min, max, num_buckets));
+ return histogram;
+ }
+
+ std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+ histogram =
+ Histogram::FactoryGet(histogram_name, min, max, num_buckets,
+ HistogramBase::kUmaTargetedHistogramFlag);
+ return InsertLocked(j_histogram_key, histogram);
+ }
+
+ HistogramBase* SparseHistogram(JNIEnv* env,
+ jstring j_histogram_name,
+ jint j_histogram_key) {
+ DCHECK(j_histogram_name);
+ DCHECK(j_histogram_key);
+ HistogramBase* histogram = FindLocked(j_histogram_key);
+ if (histogram)
+ return histogram;
+
+ std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+ histogram = SparseHistogram::FactoryGet(
+ histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
+ return InsertLocked(j_histogram_key, histogram);
+ }
+
+ HistogramBase* CustomTimesHistogram(JNIEnv* env,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jlong j_min,
+ jlong j_max,
+ jint j_bucket_count) {
+ DCHECK(j_histogram_name);
+ DCHECK(j_histogram_key);
+ HistogramBase* histogram = FindLocked(j_histogram_key);
+ int64 min = static_cast<int64>(j_min);
+ int64 max = static_cast<int64>(j_max);
+ int bucket_count = static_cast<int>(j_bucket_count);
+ if (histogram) {
+ DCHECK(histogram->HasConstructionArguments(min, max, bucket_count));
+ return histogram;
+ }
+
+ std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+ // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
+ // is just a convenience for constructing the underlying Histogram with
+ // TimeDelta arguments.
+ histogram = Histogram::FactoryGet(histogram_name, min, max, bucket_count,
+ HistogramBase::kUmaTargetedHistogramFlag);
+ return InsertLocked(j_histogram_key, histogram);
+ }
+
+ private:
+ HistogramBase* FindLocked(jint j_histogram_key) {
+ base::AutoLock locked(lock_);
+ auto histogram_it = histograms_.find(j_histogram_key);
+ return histogram_it != histograms_.end() ? histogram_it->second : nullptr;
+ }
+
+ HistogramBase* InsertLocked(jint j_histogram_key, HistogramBase* histogram) {
+ base::AutoLock locked(lock_);
+ histograms_.insert(std::make_pair(j_histogram_key, histogram));
+ return histogram;
+ }
+
+ base::Lock lock_;
+ std::map<jint, HistogramBase*> histograms_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistogramCache);
+};
+
+base::LazyInstance<HistogramCache>::Leaky g_histograms;
+
+} // namespace
+
+void RecordBooleanHistogram(JNIEnv* env,
+ jclass clazz,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jboolean j_sample) {
+ bool sample = static_cast<bool>(j_sample);
+ g_histograms.Get()
+ .BooleanHistogram(env, j_histogram_name, j_histogram_key)
+ ->AddBoolean(sample);
+}
+
+void RecordEnumeratedHistogram(JNIEnv* env,
+ jclass clazz,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jint j_sample,
+ jint j_boundary) {
+ int sample = static_cast<int>(j_sample);
+
+ g_histograms.Get()
+ .EnumeratedHistogram(env, j_histogram_name, j_histogram_key, j_boundary)
+ ->Add(sample);
+}
+
+void RecordCustomCountHistogram(JNIEnv* env,
+ jclass clazz,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jint j_sample,
+ jint j_min,
+ jint j_max,
+ jint j_num_buckets) {
+ int sample = static_cast<int>(j_sample);
+
+ g_histograms.Get()
+ .CustomCountHistogram(env, j_histogram_name, j_histogram_key, j_min,
+ j_max, j_num_buckets)
+ ->Add(sample);
+}
+
+void RecordSparseHistogram(JNIEnv* env,
+ jclass clazz,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jint j_sample) {
+ int sample = static_cast<int>(j_sample);
+ g_histograms.Get()
+ .SparseHistogram(env, j_histogram_name, j_histogram_key)
+ ->Add(sample);
+}
+
+void RecordCustomTimesHistogramMilliseconds(JNIEnv* env,
+ jclass clazz,
+ jstring j_histogram_name,
+ jint j_histogram_key,
+ jlong j_duration,
+ jlong j_min,
+ jlong j_max,
+ jint j_num_buckets) {
+ g_histograms.Get()
+ .CustomTimesHistogram(env, j_histogram_name, j_histogram_key, j_min,
+ j_max, j_num_buckets)
+ ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64>(j_duration)));
+}
+
+void Initialize(JNIEnv* env, jclass) {
+ StatisticsRecorder::Initialize();
+}
+
+// This backs a Java test util for testing histograms -
+// MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
+// currently can't have test-specific native code packaged in test-specific Java
+// targets - see http://crbug.com/415945.
+jint GetHistogramValueCountForTesting(JNIEnv* env,
+ jclass clazz,
+ jstring histogram_name,
+ jint sample) {
+ HistogramBase* histogram = StatisticsRecorder::FindHistogram(
+ android::ConvertJavaStringToUTF8(env, histogram_name));
+ if (histogram == nullptr) {
+ // No samples have been recorded for this histogram (yet?).
+ return 0;
+ }
+
+ scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+ return samples->GetCount(static_cast<int>(sample));
+}
+
+bool RegisterRecordHistogram(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/record_histogram.h b/chromium/base/android/record_histogram.h
new file mode 100644
index 00000000000..caa10f06c42
--- /dev/null
+++ b/chromium/base/android/record_histogram.h
@@ -0,0 +1,18 @@
+// Copyright 2014 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_ANDROID_RECORD_HISTOGRAM_H_
+#define BASE_ANDROID_RECORD_HISTOGRAM_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterRecordHistogram(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_RECORD_HISTOGRAM_H_
diff --git a/chromium/base/android/record_user_action.cc b/chromium/base/android/record_user_action.cc
new file mode 100644
index 00000000000..6172f2e5667
--- /dev/null
+++ b/chromium/base/android/record_user_action.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 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/android/record_user_action.h"
+
+#include "base/android/jni_string.h"
+#include "base/metrics/user_metrics.h"
+#include "jni/RecordUserAction_jni.h"
+
+namespace base {
+namespace android {
+
+static void RecordUserAction(JNIEnv* env, jclass clazz, jstring j_action) {
+ RecordComputedAction(ConvertJavaStringToUTF8(env, j_action));
+}
+
+// Register native methods
+bool RegisterRecordUserAction(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/record_user_action.h b/chromium/base/android/record_user_action.h
new file mode 100644
index 00000000000..2c2b854a490
--- /dev/null
+++ b/chromium/base/android/record_user_action.h
@@ -0,0 +1,19 @@
+// Copyright 2015 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_ANDROID_RECORD_USER_ACTION_H_
+#define BASE_ANDROID_RECORD_USER_ACTION_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+// Registers the native methods through jni
+bool RegisterRecordUserAction(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_RECORD_USER_ACTION_H_
diff --git a/chromium/base/android/scoped_java_ref.h b/chromium/base/android/scoped_java_ref.h
index 7863c0bef3a..8047ee8c167 100644
--- a/chromium/base/android/scoped_java_ref.h
+++ b/chromium/base/android/scoped_java_ref.h
@@ -178,6 +178,8 @@ class ScopedJavaGlobalRef : public JavaRef<T> {
this->Reset(other);
}
+ ScopedJavaGlobalRef(JNIEnv* env, T obj) { this->Reset(env, obj); }
+
template<typename U>
explicit ScopedJavaGlobalRef(const U& other) {
this->Reset(other);
diff --git a/chromium/base/android/scoped_java_ref_unittest.cc b/chromium/base/android/scoped_java_ref_unittest.cc
index 36f253c4e99..3f4419af6d2 100644
--- a/chromium/base/android/scoped_java_ref_unittest.cc
+++ b/chromium/base/android/scoped_java_ref_unittest.cc
@@ -40,7 +40,7 @@ void DeleteLocalRef(JNIEnv* env, jobject obj) {
class ScopedJavaRefTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
g_local_refs = 0;
g_global_refs = 0;
JNIEnv* env = AttachCurrentThread();
@@ -55,7 +55,7 @@ class ScopedJavaRefTest : public testing::Test {
hooked_functions.DeleteLocalRef = &DeleteLocalRef;
}
- virtual void TearDown() {
+ void TearDown() override {
JNIEnv* env = AttachCurrentThread();
env->functions = g_previous_functions;
}
diff --git a/chromium/base/android/trace_event_binding.cc b/chromium/base/android/trace_event_binding.cc
index 216ba7b096d..791b67fcf23 100644
--- a/chromium/base/android/trace_event_binding.cc
+++ b/chromium/base/android/trace_event_binding.cc
@@ -8,9 +8,9 @@
#include <set>
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_impl.h"
#include "base/lazy_instance.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
#include "jni/TraceEvent_jni.h"
namespace base {
@@ -55,13 +55,14 @@ class TraceEventDataConverter {
DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
};
-class TraceEnabledObserver : public debug::TraceLog::EnabledStateObserver {
+class TraceEnabledObserver
+ : public trace_event::TraceLog::EnabledStateObserver {
public:
- virtual void OnTraceLogEnabled() override {
+ void OnTraceLogEnabled() override {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::Java_TraceEvent_setEnabled(env, true);
}
- virtual void OnTraceLogDisabled() override {
+ void OnTraceLogDisabled() override {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::Java_TraceEvent_setEnabled(env, false);
}
@@ -72,18 +73,18 @@ base::LazyInstance<TraceEnabledObserver>::Leaky g_trace_enabled_state_observer_;
} // namespace
static void RegisterEnabledObserver(JNIEnv* env, jclass clazz) {
- bool enabled = debug::TraceLog::GetInstance()->IsEnabled();
+ bool enabled = trace_event::TraceLog::GetInstance()->IsEnabled();
base::android::Java_TraceEvent_setEnabled(env, enabled);
- debug::TraceLog::GetInstance()->AddEnabledStateObserver(
+ trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(
g_trace_enabled_state_observer_.Pointer());
}
static void StartATrace(JNIEnv* env, jclass clazz) {
- base::debug::TraceLog::GetInstance()->StartATrace();
+ base::trace_event::TraceLog::GetInstance()->StartATrace();
}
static void StopATrace(JNIEnv* env, jclass clazz) {
- base::debug::TraceLog::GetInstance()->StopATrace();
+ base::trace_event::TraceLog::GetInstance()->StopATrace();
}
static void Instant(JNIEnv* env, jclass clazz,
@@ -129,36 +130,14 @@ static void EndToplevel(JNIEnv* env, jclass clazz) {
TRACE_EVENT_END0(kToplevelCategory, kLooperDispatchMessage);
}
-static void StartAsync(JNIEnv* env, jclass clazz,
- jstring jname, jlong jid, jstring jarg) {
- TraceEventDataConverter converter(env, jname, jarg);
- if (converter.arg()) {
- TRACE_EVENT_COPY_ASYNC_BEGIN1(kJavaCategory,
- converter.name(),
- jid,
- converter.arg_name(),
- converter.arg());
- } else {
- TRACE_EVENT_COPY_ASYNC_BEGIN0(kJavaCategory,
- converter.name(),
- jid);
- }
+static void StartAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+ TraceEventDataConverter converter(env, jname, nullptr);
+ TRACE_EVENT_COPY_ASYNC_BEGIN0(kJavaCategory, converter.name(), jid);
}
-static void FinishAsync(JNIEnv* env, jclass clazz,
- jstring jname, jlong jid, jstring jarg) {
- TraceEventDataConverter converter(env, jname, jarg);
- if (converter.arg()) {
- TRACE_EVENT_COPY_ASYNC_END1(kJavaCategory,
- converter.name(),
- jid,
- converter.arg_name(),
- converter.arg());
- } else {
- TRACE_EVENT_COPY_ASYNC_END0(kJavaCategory,
- converter.name(),
- jid);
- }
+static void FinishAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+ TraceEventDataConverter converter(env, jname, nullptr);
+ TRACE_EVENT_COPY_ASYNC_END0(kJavaCategory, converter.name(), jid);
}
bool RegisterTraceEvent(JNIEnv* env) {
diff --git a/chromium/base/android/trace_event_binding.h b/chromium/base/android/trace_event_binding.h
index ed0626620aa..1c1a60b2ce9 100644
--- a/chromium/base/android/trace_event_binding.h
+++ b/chromium/base/android/trace_event_binding.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_ANDROID_TRACE_EVENT_H_
-#define BASE_ANDROID_TRACE_EVENT_H_
+#ifndef BASE_ANDROID_TRACE_EVENT_BINDING_H_
+#define BASE_ANDROID_TRACE_EVENT_BINDING_H_
#include <jni.h>
@@ -15,4 +15,4 @@ extern bool RegisterTraceEvent(JNIEnv* env);
} // namespace android
} // namespace base
-#endif // CONTENT_COMMON_ANDROID_TRACE_EVENT_H_
+#endif // BASE_ANDROID_TRACE_EVENT_BINDING_H_
diff --git a/chromium/base/async_socket_io_handler.h b/chromium/base/async_socket_io_handler.h
index bedb00f215b..a22c29d907d 100644
--- a/chromium/base/async_socket_io_handler.h
+++ b/chromium/base/async_socket_io_handler.h
@@ -76,9 +76,9 @@ class BASE_EXPORT AsyncSocketIoHandler
private:
#if defined(OS_WIN)
// Implementation of IOHandler on Windows.
- virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered,
- DWORD error) override;
+ void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered,
+ DWORD error) override;
#elif defined(OS_POSIX)
// Implementation of base::MessageLoopForIO::Watcher.
void OnFileCanWriteWithoutBlocking(int socket) override {}
diff --git a/chromium/base/async_socket_io_handler_unittest.cc b/chromium/base/async_socket_io_handler_unittest.cc
index 2b0e3c25c30..721de9cd72d 100644
--- a/chromium/base/async_socket_io_handler_unittest.cc
+++ b/chromium/base/async_socket_io_handler_unittest.cc
@@ -5,6 +5,9 @@
#include "base/async_socket_io_handler.h"
#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -104,8 +107,8 @@ TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
TestSocketReader reader(&pair[0], -1, false, false);
pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitClosure(),
base::TimeDelta::FromMilliseconds(100));
base::MessageLoop::current()->Run();
@@ -135,15 +138,15 @@ TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
// Issue sends on an interval to satisfy the Read() requirements.
int64 milliseconds = 0;
for (int i = 0; i < kReadOperationCount; ++i) {
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
- kAsyncSocketIoTestStringLength),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
+ kAsyncSocketIoTestStringLength),
base::TimeDelta::FromMilliseconds(milliseconds));
milliseconds += 10;
}
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitClosure(),
base::TimeDelta::FromMilliseconds(100 + milliseconds));
base::MessageLoop::current()->Run();
diff --git a/chromium/base/atomic_ref_count.h b/chromium/base/atomic_ref_count.h
index 553fab6a8c6..2ab72420020 100644
--- a/chromium/base/atomic_ref_count.h
+++ b/chromium/base/atomic_ref_count.h
@@ -4,9 +4,6 @@
// This is a low level implementation of atomic semantics for reference
// counting. Please use base/memory/ref_counted.h directly instead.
-//
-// The implementation includes annotations to avoid some false positives
-// when using data race detection tools.
#ifndef BASE_ATOMIC_REF_COUNT_H_
#define BASE_ATOMIC_REF_COUNT_H_
diff --git a/chromium/base/atomicops.h b/chromium/base/atomicops.h
index 833e1704291..6a5371c75c2 100644
--- a/chromium/base/atomicops.h
+++ b/chromium/base/atomicops.h
@@ -28,10 +28,14 @@
#ifndef BASE_ATOMICOPS_H_
#define BASE_ATOMICOPS_H_
-#include <cassert> // Small C++ header which defines implementation specific
- // macros used to identify the STL implementation.
#include <stdint.h>
+// Small C++ header which defines implementation specific macros used to
+// identify the STL implementation.
+// - libc++: captures __config for _LIBCPP_VERSION
+// - libstdc++: captures bits/c++config.h for __GLIBCXX__
+#include <cstddef>
+
#include "base/base_export.h"
#include "build/build_config.h"
diff --git a/chromium/base/atomicops_internals_arm64_gcc.h b/chromium/base/atomicops_internals_arm64_gcc.h
index bb6a346eccb..ddcfec901f9 100644
--- a/chromium/base/atomicops_internals_arm64_gcc.h
+++ b/chromium/base/atomicops_internals_arm64_gcc.h
@@ -301,7 +301,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
return *ptr;
}
-} // namespace base::subtle
+} // namespace subtle
} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
diff --git a/chromium/base/atomicops_internals_arm_gcc.h b/chromium/base/atomicops_internals_arm_gcc.h
index e654afa7d27..44c91c87a25 100644
--- a/chromium/base/atomicops_internals_arm_gcc.h
+++ b/chromium/base/atomicops_internals_arm_gcc.h
@@ -288,7 +288,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
return *ptr;
}
-} // namespace base::subtle
+} // namespace subtle
} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/chromium/base/atomicops_internals_atomicword_compat.h b/chromium/base/atomicops_internals_atomicword_compat.h
index e02d11d29bf..342a6e4592c 100644
--- a/chromium/base/atomicops_internals_atomicword_compat.h
+++ b/chromium/base/atomicops_internals_atomicword_compat.h
@@ -92,8 +92,8 @@ inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
reinterpret_cast<volatile const Atomic32*>(ptr));
}
-} // namespace base::subtle
-} // namespace base
+} // namespace subtle
+} // namespace base
#endif // !defined(ARCH_CPU_64_BITS)
diff --git a/chromium/base/atomicops_internals_gcc.h b/chromium/base/atomicops_internals_gcc.h
index ed1b2d79134..35c95fee56d 100644
--- a/chromium/base/atomicops_internals_gcc.h
+++ b/chromium/base/atomicops_internals_gcc.h
@@ -99,7 +99,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
return *ptr;
}
-} // namespace base::subtle
+} // namespace subtle
} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_GCC_H_
diff --git a/chromium/base/atomicops_internals_mac.h b/chromium/base/atomicops_internals_mac.h
index ccbb896e4cb..98864a77da2 100644
--- a/chromium/base/atomicops_internals_mac.h
+++ b/chromium/base/atomicops_internals_mac.h
@@ -191,7 +191,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
#endif // defined(__LP64__)
-} // namespace base::subtle
-} // namespace base
+} // namespace subtle
+} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/chromium/base/atomicops_internals_mips_gcc.h b/chromium/base/atomicops_internals_mips_gcc.h
index 9111a535b26..b4551b8351e 100644
--- a/chromium/base/atomicops_internals_mips_gcc.h
+++ b/chromium/base/atomicops_internals_mips_gcc.h
@@ -38,7 +38,7 @@ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
"2:\n"
".set pop\n"
: "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
- : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+ : "r" (old_value), "r" (new_value), "m" (*ptr)
: "memory");
return prev;
}
@@ -167,7 +167,7 @@ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
"2:\n"
".set pop\n"
: "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
- : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+ : "r" (old_value), "r" (new_value), "m" (*ptr)
: "memory");
return prev;
}
@@ -274,7 +274,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
}
#endif
-} // namespace base::subtle
-} // namespace base
+} // namespace subtle
+} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/chromium/base/atomicops_internals_portable.h b/chromium/base/atomicops_internals_portable.h
index b25099fd220..d28561076dd 100644
--- a/chromium/base/atomicops_internals_portable.h
+++ b/chromium/base/atomicops_internals_portable.h
@@ -221,7 +221,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
}
#endif // defined(ARCH_CPU_64_BITS)
-}
-} // namespace base::subtle
+} // namespace subtle
+} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
diff --git a/chromium/base/atomicops_internals_x86_gcc.h b/chromium/base/atomicops_internals_x86_gcc.h
index 69eacdb0873..f0d224264b9 100644
--- a/chromium/base/atomicops_internals_x86_gcc.h
+++ b/chromium/base/atomicops_internals_x86_gcc.h
@@ -220,8 +220,8 @@ inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
#endif // defined(__x86_64__)
-} // namespace base::subtle
-} // namespace base
+} // namespace subtle
+} // namespace base
#undef ATOMICOPS_COMPILER_BARRIER
diff --git a/chromium/base/atomicops_internals_x86_msvc.h b/chromium/base/atomicops_internals_x86_msvc.h
index 0269d894a1f..71ddca2ba38 100644
--- a/chromium/base/atomicops_internals_x86_msvc.h
+++ b/chromium/base/atomicops_internals_x86_msvc.h
@@ -55,9 +55,6 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
return Barrier_AtomicIncrement(ptr, increment);
}
-#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
-#error "We require at least vs2005 for MemoryBarrier"
-#endif
inline void MemoryBarrier() {
#if defined(ARCH_CPU_64_BITS)
// See #undef and note at the top of this file.
@@ -192,7 +189,7 @@ inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
#endif // defined(_WIN64)
-} // namespace base::subtle
+} // namespace subtle
} // namespace base
#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/chromium/base/auto_reset.h b/chromium/base/auto_reset.h
index 32f138e2440..a5bcfaae8a8 100644
--- a/chromium/base/auto_reset.h
+++ b/chromium/base/auto_reset.h
@@ -36,6 +36,6 @@ class AutoReset {
DISALLOW_COPY_AND_ASSIGN(AutoReset);
};
-}
+} // namespace base
#endif // BASE_AUTO_RESET_H_
diff --git a/chromium/base/barrier_closure.cc b/chromium/base/barrier_closure.cc
index 5abe2bfaec2..1dcc50238fb 100644
--- a/chromium/base/barrier_closure.cc
+++ b/chromium/base/barrier_closure.cc
@@ -28,8 +28,9 @@ BarrierInfo::BarrierInfo(int num_callbacks, const base::Closure& done_closure)
void BarrierInfo::Run() {
DCHECK(!base::AtomicRefCountIsZero(&num_callbacks_left_));
if (!base::AtomicRefCountDec(&num_callbacks_left_)) {
- done_closure_.Run();
+ base::Closure done_closure = done_closure_;
done_closure_.Reset();
+ done_closure.Run();
}
}
@@ -39,7 +40,7 @@ namespace base {
base::Closure BarrierClosure(int num_callbacks_left,
const base::Closure& done_closure) {
- DCHECK(num_callbacks_left >= 0);
+ DCHECK_GE(num_callbacks_left, 0);
if (num_callbacks_left == 0)
done_closure.Run();
diff --git a/chromium/base/barrier_closure_unittest.cc b/chromium/base/barrier_closure_unittest.cc
index ab05cb8af54..dcea09feffa 100644
--- a/chromium/base/barrier_closure_unittest.cc
+++ b/chromium/base/barrier_closure_unittest.cc
@@ -13,24 +13,68 @@ void Increment(int* count) { (*count)++; }
TEST(BarrierClosureTest, RunImmediatelyForZeroClosures) {
int count = 0;
- base::Closure doneClosure(base::Bind(&Increment, base::Unretained(&count)));
+ base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count)));
- base::Closure barrierClosure = base::BarrierClosure(0, doneClosure);
+ base::Closure barrier_closure = base::BarrierClosure(0, done_closure);
EXPECT_EQ(1, count);
}
TEST(BarrierClosureTest, RunAfterNumClosures) {
int count = 0;
- base::Closure doneClosure(base::Bind(&Increment, base::Unretained(&count)));
+ base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count)));
- base::Closure barrierClosure = base::BarrierClosure(2, doneClosure);
+ base::Closure barrier_closure = base::BarrierClosure(2, done_closure);
EXPECT_EQ(0, count);
- barrierClosure.Run();
+ barrier_closure.Run();
EXPECT_EQ(0, count);
- barrierClosure.Run();
+ barrier_closure.Run();
EXPECT_EQ(1, count);
}
+class DestructionIndicator {
+ public:
+ // Sets |*destructed| to true in destructor.
+ DestructionIndicator(bool* destructed) : destructed_(destructed) {
+ *destructed_ = false;
+ }
+
+ ~DestructionIndicator() { *destructed_ = true; }
+
+ void DoNothing() {}
+
+ private:
+ bool* destructed_;
+};
+
+TEST(BarrierClosureTest, ReleasesDoneClosureWhenDone) {
+ bool done_destructed = false;
+ base::Closure barrier_closure = base::BarrierClosure(
+ 1, base::Bind(&DestructionIndicator::DoNothing,
+ base::Owned(new DestructionIndicator(&done_destructed))));
+ EXPECT_FALSE(done_destructed);
+ barrier_closure.Run();
+ EXPECT_TRUE(done_destructed);
+}
+
+void ResetBarrierClosure(base::Closure* closure) {
+ *closure = base::Closure();
+}
+
+// Tests a case when |done_closure| resets a |barrier_closure|.
+// |barrier_closure| is a Closure holding the |done_closure|. |done_closure|
+// holds a pointer back to the |barrier_closure|. When |barrier_closure| is
+// Run() it calls ResetBarrierClosure() which erases the |barrier_closure| while
+// still inside of its Run(). The Run() implementation (in base::BarrierClosure)
+// must not try use itself after executing ResetBarrierClosure() or this test
+// would crash inside Run().
+TEST(BarrierClosureTest, KeepingClosureAliveUntilDone) {
+ base::Closure barrier_closure;
+ base::Closure done_closure =
+ base::Bind(ResetBarrierClosure, &barrier_closure);
+ barrier_closure = base::BarrierClosure(1, done_closure);
+ barrier_closure.Run();
+}
+
} // namespace
diff --git a/chromium/base/base.gyp b/chromium/base/base.gyp
index ad4dd226792..ff6ce00e246 100644
--- a/chromium/base/base.gyp
+++ b/chromium/base/base.gyp
@@ -103,7 +103,9 @@
}],
],
'dependencies': [
+ 'base_java',
'base_jni_headers',
+ '../build/android/ndk.gyp:cpu_features',
'../third_party/ashmem/ashmem.gyp:ashmem',
],
'link_settings': {
@@ -114,14 +116,6 @@
'sources!': [
'debug/stack_trace_posix.cc',
],
- 'includes': [
- '../build/android/cpufeatures.gypi',
- ],
- }],
- ['OS == "android" and _toolset == "target" and android_webview_build == 0', {
- 'dependencies': [
- 'base_java',
- ],
}],
['os_bsd==1', {
'include_dirs': [
@@ -188,6 +182,17 @@
},
},
},
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/',
+ 'files': [
+ '../build/win/dbghelp_xp/dbghelp.dll',
+ ],
+ },
+ ],
+ 'dependencies': [
+ 'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
+ ],
}],
['OS == "mac" or (OS == "ios" and _toolset == "host")', {
'link_settings': {
@@ -201,9 +206,6 @@
'$(SDKROOT)/System/Library/Frameworks/Security.framework',
],
},
- 'dependencies': [
- '../third_party/mach_override/mach_override.gyp:mach_override',
- ],
}],
['OS == "ios" and _toolset != "host"', {
'link_settings': {
@@ -230,15 +232,10 @@
}],
],
'sources': [
- 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
- 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
'async_socket_io_handler.h',
'async_socket_io_handler_posix.cc',
'async_socket_io_handler_win.cc',
'auto_reset.h',
- 'event_recorder.h',
- 'event_recorder_stubs.cc',
- 'event_recorder_win.cc',
'linux_util.cc',
'linux_util.h',
'message_loop/message_pump_android.cc',
@@ -256,8 +253,10 @@
'posix/file_descriptor_shuffle.cc',
'posix/file_descriptor_shuffle.h',
'sync_socket.h',
- 'sync_socket_win.cc',
'sync_socket_posix.cc',
+ 'sync_socket_win.cc',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
],
'includes': [
'../build/android/increase_size_for_speed.gypi',
@@ -435,9 +434,11 @@
'type': '<(gtest_target_type)',
'sources': [
'android/application_status_listener_unittest.cc',
+ 'android/content_uri_utils_unittest.cc',
'android/jni_android_unittest.cc',
'android/jni_array_unittest.cc',
'android/jni_string_unittest.cc',
+ 'android/library_loader/library_prefetcher_unittest.cc',
'android/path_utils_unittest.cc',
'android/scoped_java_ref_unittest.cc',
'android/sys_utils_unittest.cc',
@@ -457,31 +458,28 @@
'callback_unittest.cc',
'callback_unittest.nc',
'cancelable_callback_unittest.cc',
+ 'chromeos/memory_pressure_monitor_unittest.cc',
'command_line_unittest.cc',
'containers/adapters_unittest.cc',
'containers/hash_tables_unittest.cc',
'containers/linked_list_unittest.cc',
'containers/mru_cache_unittest.cc',
+ 'containers/scoped_ptr_hash_map_unittest.cc',
'containers/small_map_unittest.cc',
'containers/stack_container_unittest.cc',
'cpu_unittest.cc',
'debug/crash_logging_unittest.cc',
+ 'debug/debugger_unittest.cc',
'debug/leak_tracker_unittest.cc',
'debug/proc_maps_linux_unittest.cc',
'debug/stack_trace_unittest.cc',
'debug/task_annotator_unittest.cc',
- 'debug/trace_event_argument_unittest.cc',
- 'debug/trace_event_memory_unittest.cc',
- 'debug/trace_event_synthetic_delay_unittest.cc',
- 'debug/trace_event_system_stats_monitor_unittest.cc',
- 'debug/trace_event_unittest.cc',
- 'debug/trace_event_unittest.h',
- 'debug/trace_event_win_unittest.cc',
'deferred_sequenced_task_runner_unittest.cc',
'environment_unittest.cc',
'file_version_info_unittest.cc',
'files/dir_reader_posix_unittest.cc',
'files/file_path_unittest.cc',
+ 'files/file_path_watcher_unittest.cc',
'files/file_proxy_unittest.cc',
'files/file_unittest.cc',
'files/file_util_proxy_unittest.cc',
@@ -492,10 +490,9 @@
'gmock_unittest.cc',
'guid_unittest.cc',
'hash_unittest.cc',
- 'id_map_unittest.cc',
'i18n/break_iterator_unittest.cc',
- 'i18n/char_iterator_unittest.cc',
'i18n/case_conversion_unittest.cc',
+ 'i18n/char_iterator_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
'i18n/number_formatting_unittest.cc',
@@ -504,7 +501,10 @@
'i18n/string_search_unittest.cc',
'i18n/time_formatting_unittest.cc',
'i18n/timezone_unittest.cc',
+ 'id_map_unittest.cc',
+ 'ios/crb_protocol_observers_unittest.mm',
'ios/device_util_unittest.mm',
+ 'ios/weak_nsobject_unittest.mm',
'json/json_parser_unittest.cc',
'json/json_reader_unittest.cc',
'json/json_value_converter_unittest.cc',
@@ -514,17 +514,17 @@
'lazy_instance_unittest.cc',
'logging_unittest.cc',
'mac/bind_objc_block_unittest.mm',
+ 'mac/dispatch_source_mach_unittest.cc',
'mac/foundation_util_unittest.mm',
'mac/libdispatch_task_runner_unittest.cc',
'mac/mac_util_unittest.mm',
+ 'mac/memory_pressure_monitor_unittest.cc',
'mac/objc_property_releaser_unittest.mm',
'mac/scoped_nsobject_unittest.mm',
'mac/scoped_objc_class_swizzler_unittest.mm',
'mac/scoped_sending_event_unittest.mm',
'md5_unittest.cc',
'memory/aligned_memory_unittest.cc',
- 'memory/discardable_memory_manager_unittest.cc',
- 'memory/discardable_memory_unittest.cc',
'memory/discardable_shared_memory_unittest.cc',
'memory/linked_ptr_unittest.cc',
'memory/ref_counted_memory_unittest.cc',
@@ -542,17 +542,19 @@
'message_loop/message_pump_glib_unittest.cc',
'message_loop/message_pump_io_ios_unittest.cc',
'message_loop/message_pump_libevent_unittest.cc',
- 'metrics/sample_map_unittest.cc',
- 'metrics/sample_vector_unittest.cc',
'metrics/bucket_ranges_unittest.cc',
'metrics/field_trial_unittest.cc',
'metrics/histogram_base_unittest.cc',
'metrics/histogram_delta_serialization_unittest.cc',
+ 'metrics/histogram_macros_unittest.cc',
'metrics/histogram_snapshot_manager_unittest.cc',
'metrics/histogram_unittest.cc',
+ 'metrics/sample_map_unittest.cc',
+ 'metrics/sample_vector_unittest.cc',
'metrics/sparse_histogram_unittest.cc',
- 'metrics/stats_table_unittest.cc',
'metrics/statistics_recorder_unittest.cc',
+ 'move_unittest.cc',
+ 'numerics/safe_numerics_unittest.cc',
'observer_list_unittest.cc',
'os_compat_android_unittest.cc',
'path_service_unittest.cc',
@@ -578,9 +580,9 @@
'process/process_metrics_unittest_ios.cc',
'process/process_unittest.cc',
'process/process_util_unittest.cc',
+ 'profiler/stack_sampling_profiler_unittest.cc',
'profiler/tracked_time_unittest.cc',
'rand_util_unittest.cc',
- 'numerics/safe_numerics_unittest.cc',
'scoped_clear_errno_unittest.cc',
'scoped_generic_unittest.cc',
'scoped_native_library_unittest.cc',
@@ -591,13 +593,13 @@
'strings/nullable_string16_unittest.cc',
'strings/safe_sprintf_unittest.cc',
'strings/string16_unittest.cc',
- 'strings/stringprintf_unittest.cc',
'strings/string_number_conversions_unittest.cc',
'strings/string_piece_unittest.cc',
'strings/string_split_unittest.cc',
'strings/string_tokenizer_unittest.cc',
'strings/string_util_unittest.cc',
'strings/stringize_macros_unittest.cc',
+ 'strings/stringprintf_unittest.cc',
'strings/sys_string_conversions_mac_unittest.mm',
'strings/sys_string_conversions_unittest.cc',
'strings/utf_offset_string_conversions_unittest.cc',
@@ -620,6 +622,7 @@
'test/test_pending_task_unittest.cc',
'test/test_reg_util_win_unittest.cc',
'test/trace_event_analyzer_unittest.cc',
+ 'test/user_action_tester_unittest.cc',
'threading/non_thread_safe_unittest.cc',
'threading/platform_thread_unittest.cc',
'threading/sequenced_worker_pool_unittest.cc',
@@ -652,6 +655,7 @@
'win/event_trace_provider_unittest.cc',
'win/i18n_unittest.cc',
'win/iunknown_impl_unittest.cc',
+ 'win/memory_pressure_monitor_unittest.cc',
'win/message_window_unittest.cc',
'win/object_watcher_unittest.cc',
'win/pe_image_unittest.cc',
@@ -664,6 +668,7 @@
'win/startup_information_unittest.cc',
'win/win_util_unittest.cc',
'win/wrapped_window_proc_unittest.cc',
+ '<@(trace_event_test_sources)',
],
'dependencies': [
'base',
@@ -699,8 +704,6 @@
['exclude', '^process/process_unittest\\.cc$'],
['exclude', '^process/process_util_unittest\\.cc$'],
['include', '^process/process_util_unittest_ios\\.cc$'],
- # Requires spawning processes.
- ['exclude', '^metrics/stats_table_unittest\\.cc$'],
# iOS does not use message_pump_libevent.
['exclude', '^message_loop/message_pump_libevent_unittest\\.cc$'],
],
@@ -746,18 +749,24 @@
'message_loop/message_pump_glib_unittest.cc',
]
}],
- ['OS == "linux" and use_allocator!="none"', {
- 'dependencies': [
- 'allocator/allocator.gyp:allocator',
- ],
- },
+ ['OS == "linux"', {
+ 'dependencies': [
+ 'malloc_wrapper',
+ ],
+ 'conditions': [
+ ['use_allocator!="none"', {
+ 'dependencies': [
+ 'allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ]},
],
['OS == "win"', {
'sources!': [
'file_descriptor_shuffle_unittest.cc',
'files/dir_reader_posix_unittest.cc',
- 'threading/worker_pool_posix_unittest.cc',
'message_loop/message_pump_libevent_unittest.cc',
+ 'threading/worker_pool_posix_unittest.cc',
],
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [
@@ -781,14 +790,6 @@
'../third_party/icu/icu.gyp:icudata',
],
}],
- ['incremental_chrome_dll', {
- 'defines': [
- # Used only to workaround a linker bug, do not use this
- # otherwise, and don't make it broader scope. See
- # http://crbug.com/251251.
- 'INCREMENTAL_LINKING',
- ],
- }],
],
}, { # OS != "win"
'dependencies': [
@@ -808,19 +809,20 @@
['include', '^sys_string_conversions_mac_unittest\\.mm$'],
],
}],
- ['OS == "android" and _toolset == "target"', {
- 'sources': [
- 'memory/discardable_memory_ashmem_allocator_unittest.cc',
- ],
- }],
['OS == "android"', {
'sources/': [
['include', '^debug/proc_maps_linux_unittest\\.cc$'],
],
}],
+ # Enable more direct string conversions on platforms with native utf8
+ # strings
+ ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+ 'defines': ['SYSTEM_NATIVE_UTF8'],
+ }],
], # target_conditions
},
{
+ # GN: //base:base_perftests
'target_name': 'base_perftests',
'type': '<(gtest_target_type)',
'dependencies': [
@@ -829,9 +831,9 @@
'../testing/gtest.gyp:gtest',
],
'sources': [
- 'threading/thread_perftest.cc',
'message_loop/message_pump_perftest.cc',
'test/run_all_unittests.cc',
+ 'threading/thread_perftest.cc',
'../testing/perf/perf_test.cc'
],
'conditions': [
@@ -843,6 +845,7 @@
],
},
{
+ # GN: //base:base_i18n_perftests
'target_name': 'base_i18n_perftests',
'type': '<(gtest_target_type)',
'dependencies': [
@@ -866,6 +869,7 @@
'base_i18n',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
+ '../third_party/icu/icu.gyp:icuuc',
'../third_party/libxml/libxml.gyp:libxml',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
],
@@ -899,8 +903,14 @@
'test/expectations/expectation.h',
'test/expectations/parser.cc',
'test/expectations/parser.h',
+ 'test/gtest_util.cc',
+ 'test/gtest_util.h',
'test/gtest_xml_util.cc',
'test/gtest_xml_util.h',
+ 'test/histogram_tester.cc',
+ 'test/histogram_tester.h',
+ 'test/ios/wait_util.h',
+ 'test/ios/wait_util.mm',
'test/launcher/test_launcher.cc',
'test/launcher/test_launcher.h',
'test/launcher/test_result.cc',
@@ -914,8 +924,10 @@
'test/mock_chrome_application_mac.mm',
'test/mock_devices_changed_observer.cc',
'test/mock_devices_changed_observer.h',
- 'test/mock_time_provider.cc',
- 'test/mock_time_provider.h',
+ 'test/mock_entropy_provider.cc',
+ 'test/mock_entropy_provider.h',
+ 'test/mock_log.cc',
+ 'test/mock_log.h',
'test/multiprocess_test.cc',
'test/multiprocess_test.h',
'test/multiprocess_test_android.cc',
@@ -943,10 +955,10 @@
'test/simple_test_clock.h',
'test/simple_test_tick_clock.cc',
'test/simple_test_tick_clock.h',
- 'test/histogram_tester.cc',
- 'test/histogram_tester.h',
'test/task_runner_test_template.cc',
'test/task_runner_test_template.h',
+ 'test/test_discardable_memory_allocator.cc',
+ 'test/test_discardable_memory_allocator.h',
'test/test_file_util.cc',
'test/test_file_util.h',
'test/test_file_util_android.cc',
@@ -958,6 +970,8 @@
'test/test_io_thread.h',
'test/test_listener_ios.h',
'test/test_listener_ios.mm',
+ 'test/test_mock_time_task_runner.cc',
+ 'test/test_mock_time_task_runner.h',
'test/test_pending_task.cc',
'test/test_pending_task.h',
'test/test_reg_util_win.cc',
@@ -982,6 +996,8 @@
'test/trace_event_analyzer.h',
'test/trace_to_file.cc',
'test/trace_to_file.h',
+ 'test/user_action_tester.cc',
+ 'test/user_action_tester.h',
'test/values_test_util.cc',
'test/values_test_util.h',
],
@@ -1045,6 +1061,7 @@
['OS!="ios"', {
'targets': [
{
+ # GN: //base:check_example
'target_name': 'check_example',
'type': 'executable',
'sources': [
@@ -1083,6 +1100,7 @@
'allocator/allocator.gyp:allocator_extension_thunks_win64',
'../third_party/modp_b64/modp_b64.gyp:modp_b64_win64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+ 'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
],
# TODO(gregoryd): direct_dependent_settings should be shared with the
# 32-bit target, but it doesn't work due to a bug in gyp
@@ -1146,15 +1164,10 @@
4267,
],
'sources': [
- 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
- 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
'async_socket_io_handler.h',
'async_socket_io_handler_posix.cc',
'async_socket_io_handler_win.cc',
'auto_reset.h',
- 'event_recorder.h',
- 'event_recorder_stubs.cc',
- 'event_recorder_win.cc',
'linux_util.cc',
'linux_util.h',
'md5.cc',
@@ -1166,8 +1179,10 @@
'posix/file_descriptor_shuffle.cc',
'posix/file_descriptor_shuffle.h',
'sync_socket.h',
- 'sync_socket_win.cc',
'sync_socket_posix.cc',
+ 'sync_socket_win.cc',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
],
},
{
@@ -1306,6 +1321,20 @@
},
],
}],
+ ['OS == "linux"', {
+ 'targets': [
+ {
+ 'target_name': 'malloc_wrapper',
+ 'type': 'shared_library',
+ 'dependencies': [
+ 'base',
+ ],
+ 'sources': [
+ 'test/malloc_wrapper.cc',
+ ],
+ }
+ ],
+ }],
['OS == "android"', {
'targets': [
{
@@ -1314,6 +1343,7 @@
'type': 'none',
'sources': [
'android/java/src/org/chromium/base/ApplicationStatus.java',
+ 'android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java',
'android/java/src/org/chromium/base/BuildInfo.java',
'android/java/src/org/chromium/base/CommandLine.java',
'android/java/src/org/chromium/base/ContentUriUtils.java',
@@ -1322,24 +1352,39 @@
'android/java/src/org/chromium/base/FieldTrialList.java',
'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java',
'android/java/src/org/chromium/base/JNIUtils.java',
- 'android/java/src/org/chromium/base/library_loader/LibraryLoader.java',
+ 'android/java/src/org/chromium/base/JavaHandlerThread.java',
'android/java/src/org/chromium/base/LocaleUtils.java',
'android/java/src/org/chromium/base/MemoryPressureListener.java',
- 'android/java/src/org/chromium/base/JavaHandlerThread.java',
'android/java/src/org/chromium/base/PathService.java',
'android/java/src/org/chromium/base/PathUtils.java',
'android/java/src/org/chromium/base/PowerMonitor.java',
- 'android/java/src/org/chromium/base/SystemMessageHandler.java',
'android/java/src/org/chromium/base/SysUtils.java',
+ 'android/java/src/org/chromium/base/SystemMessageHandler.java',
'android/java/src/org/chromium/base/ThreadUtils.java',
'android/java/src/org/chromium/base/TraceEvent.java',
+ 'android/java/src/org/chromium/base/library_loader/LibraryLoader.java',
+ 'android/java/src/org/chromium/base/metrics/RecordHistogram.java',
+ 'android/java/src/org/chromium/base/metrics/RecordUserAction.java',
],
'variables': {
'jni_gen_package': 'base',
},
+ 'dependencies': [
+ 'android_runtime_jni_headers',
+ ],
'includes': [ '../build/jni_generator.gypi' ],
},
{
+ # GN: //base:android_runtime_jni_headers
+ 'target_name': 'android_runtime_jni_headers',
+ 'type': 'none',
+ 'variables': {
+ 'jni_gen_package': 'base',
+ 'input_java_class': 'java/lang/Runtime.class',
+ },
+ 'includes': [ '../build/jar_file_jni_generator.gypi' ],
+ },
+ {
# TODO(GN)
'target_name': 'base_unittests_jni_headers',
'type': 'none',
@@ -1365,6 +1410,15 @@
'includes': [ '../build/android/java_cpp_template.gypi' ],
},
{
+ # GN: //base:base_android_java_enums_srcjar
+ 'target_name': 'base_java_library_process_type',
+ 'type': 'none',
+ 'variables': {
+ 'source_file': 'android/library_loader/library_loader_hooks.h',
+ },
+ 'includes': [ '../build/android/java_cpp_enum.gypi' ],
+ },
+ {
# GN: //base:base_java
'target_name': 'base_java',
'type': 'none',
@@ -1375,17 +1429,12 @@
'dependencies': [
'base_java_application_state',
'base_java_library_load_from_apk_status_codes',
+ 'base_java_library_process_type',
'base_java_memory_pressure_level',
'base_native_libraries_gen',
+ '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
],
'includes': [ '../build/java.gypi' ],
- 'conditions': [
- ['android_webview_build==0', {
- 'dependencies': [
- '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
- ],
- }]
- ],
},
{
# GN: //base:base_java_unittest_support
@@ -1432,6 +1481,7 @@
'type': 'none',
'dependencies': [
'base_java',
+ '../testing/android/on_device_instrumentation.gyp:reporter_java',
],
'variables': {
'java_in_dir': '../base/test/android/javatests',
@@ -1439,6 +1489,23 @@
'includes': [ '../build/java.gypi' ],
},
{
+ # GN: //base:base_junit_tests
+ 'target_name': 'base_junit_tests',
+ 'type': 'none',
+ 'dependencies': [
+ 'base_java',
+ 'base_java_test_support',
+ '../testing/android/junit/junit_test.gyp:junit_test_support',
+ ],
+ 'variables': {
+ 'main_class': 'org.chromium.testing.local.JunitTestMain',
+ 'src_paths': [
+ '../base/android/junit/',
+ ],
+ },
+ 'includes': [ '../build/host_jar.gypi' ],
+ },
+ {
# GN: //base:base_javatests
'target_name': 'base_javatests',
'type': 'none',
@@ -1455,25 +1522,18 @@
# GN: //base/android/linker:chromium_android_linker
'target_name': 'chromium_android_linker',
'type': 'shared_library',
- 'conditions': [
- # Avoid breaking the webview build because it
- # does not have <(android_ndk_root)/crazy_linker.gyp.
- # Note that webview never uses the linker anyway.
- ['android_webview_build == 0', {
- 'sources': [
- 'android/linker/linker_jni.cc',
- ],
- # The crazy linker is never instrumented.
- 'cflags!': [
- '-finstrument-functions',
- ],
- 'dependencies': [
- # The NDK contains the crazy_linker here:
- # '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
- # However, we use our own fork. See bug 384700.
- '../third_party/android_crazy_linker/crazy_linker.gyp:crazy_linker',
- ],
- }],
+ 'sources': [
+ 'android/linker/linker_jni.cc',
+ ],
+ # The crazy linker is never instrumented.
+ 'cflags!': [
+ '-finstrument-functions',
+ ],
+ 'dependencies': [
+ # The NDK contains the crazy_linker here:
+ # '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
+ # However, we use our own fork. See bug 384700.
+ '../third_party/android_crazy_linker/crazy_linker.gyp:crazy_linker',
],
},
{
@@ -1517,6 +1577,28 @@
},
},
},
+ {
+ # Target to manually rebuild pe_image_test.dll which is checked into
+ # base/test/data/pe_image.
+ 'target_name': 'pe_image_test',
+ 'type': 'shared_library',
+ 'sources': [
+ 'win/pe_image_test.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
+ 'DelayLoadDLLs': [
+ 'cfgmgr32.dll',
+ 'shell32.dll',
+ ],
+ 'AdditionalDependencies': [
+ 'cfgmgr32.lib',
+ 'shell32.lib',
+ ],
+ },
+ },
+ },
],
}],
['test_isolation_mode != "noop"', {
diff --git a/chromium/base/base.gypi b/chromium/base/base.gypi
index 416a7e5aa6e..a39952d5c76 100644
--- a/chromium/base/base.gypi
+++ b/chromium/base/base.gypi
@@ -3,6 +3,9 @@
# found in the LICENSE file.
{
+ 'includes': [
+ 'trace_event/trace_event.gypi',
+ ],
'target_defaults': {
'variables': {
'base_target': 0,
@@ -13,21 +16,16 @@
['base_target==1', {
'sources': [
'../build/build_config.h',
- 'third_party/dmg_fp/dmg_fp.h',
- 'third_party/dmg_fp/g_fmt.cc',
- 'third_party/dmg_fp/dtoa_wrapper.cc',
- 'third_party/icu/icu_utf.cc',
- 'third_party/icu/icu_utf.h',
- 'third_party/nspr/prtime.cc',
- 'third_party/nspr/prtime.h',
- 'third_party/superfasthash/superfasthash.c',
- 'third_party/xdg_mime/xdgmime.h',
'allocator/allocator_extension.cc',
'allocator/allocator_extension.h',
'allocator/type_profiler_control.cc',
'allocator/type_profiler_control.h',
+ 'android/animation_frame_time_histogram.cc',
+ 'android/animation_frame_time_histogram.h',
'android/application_status_listener.cc',
'android/application_status_listener.h',
+ 'android/base_jni_onload.cc',
+ 'android/base_jni_onload.h',
'android/base_jni_registrar.cc',
'android/base_jni_registrar.h',
'android/build_info.cc',
@@ -45,10 +43,10 @@
'android/fifo_utils.h',
'android/important_file_writer_android.cc',
'android/important_file_writer_android.h',
- 'android/locale_utils.h',
- 'android/locale_utils.cc',
- 'android/scoped_java_ref.cc',
- 'android/scoped_java_ref.h',
+ 'android/java_handler_thread.cc',
+ 'android/java_handler_thread.h',
+ 'android/java_runtime.cc',
+ 'android/java_runtime.h',
'android/jni_android.cc',
'android/jni_android.h',
'android/jni_array.cc',
@@ -61,17 +59,25 @@
'android/jni_utils.h',
'android/jni_weak_ref.cc',
'android/jni_weak_ref.h',
+ 'android/library_loader/library_load_from_apk_status_codes.h',
'android/library_loader/library_loader_hooks.cc',
'android/library_loader/library_loader_hooks.h',
- 'android/library_loader/library_load_from_apk_status_codes.h',
+ 'android/library_loader/library_prefetcher.cc',
+ 'android/library_loader/library_prefetcher.h',
+ 'android/locale_utils.cc',
+ 'android/locale_utils.h',
'android/memory_pressure_listener_android.cc',
'android/memory_pressure_listener_android.h',
- 'android/java_handler_thread.cc',
- 'android/java_handler_thread.h',
'android/path_service_android.cc',
'android/path_service_android.h',
'android/path_utils.cc',
'android/path_utils.h',
+ 'android/record_histogram.cc',
+ 'android/record_histogram.h',
+ 'android/record_user_action.cc',
+ 'android/record_user_action.h',
+ 'android/scoped_java_ref.cc',
+ 'android/scoped_java_ref.h',
'android/sys_utils.cc',
'android/sys_utils.h',
'android/thread_utils.h',
@@ -122,6 +128,8 @@
'callback_internal.h',
'callback_list.h',
'cancelable_callback.h',
+ 'chromeos/memory_pressure_monitor.cc',
+ 'chromeos/memory_pressure_monitor.h',
'command_line.cc',
'command_line.h',
'compiler_specific.h',
@@ -166,19 +174,6 @@
'debug/stack_trace_win.cc',
'debug/task_annotator.cc',
'debug/task_annotator.h',
- 'debug/trace_event.h',
- 'debug/trace_event_android.cc',
- 'debug/trace_event_argument.cc',
- 'debug/trace_event_argument.h',
- 'debug/trace_event_impl.cc',
- 'debug/trace_event_impl.h',
- 'debug/trace_event_impl_constants.cc',
- 'debug/trace_event_synthetic_delay.cc',
- 'debug/trace_event_synthetic_delay.h',
- 'debug/trace_event_system_stats_monitor.cc',
- 'debug/trace_event_memory.cc',
- 'debug/trace_event_memory.h',
- 'debug/trace_event_win.cc',
'deferred_sequenced_task_runner.cc',
'deferred_sequenced_task_runner.h',
'environment.cc',
@@ -214,6 +209,8 @@
'files/file_posix.cc',
'files/file_proxy.cc',
'files/file_proxy.h',
+ 'files/file_tracing.cc',
+ 'files/file_tracing.h',
'files/file_util.cc',
'files/file_util.h',
'files/file_util_android.cc',
@@ -224,8 +221,8 @@
'files/file_util_proxy.h',
'files/file_util_win.cc',
'files/file_win.cc',
- 'files/important_file_writer.h',
'files/important_file_writer.cc',
+ 'files/important_file_writer.h',
'files/memory_mapped_file.cc',
'files/memory_mapped_file.h',
'files/memory_mapped_file_posix.cc',
@@ -234,7 +231,6 @@
'files/scoped_file.h',
'files/scoped_temp_dir.cc',
'files/scoped_temp_dir.h',
- 'float_util.h',
'format_macros.h',
'gtest_prod_util.h',
'guid.cc',
@@ -244,12 +240,17 @@
'hash.cc',
'hash.h',
'id_map.h',
+ 'ios/block_types.h',
+ 'ios/crb_protocol_observers.h',
+ 'ios/crb_protocol_observers.mm',
'ios/device_util.h',
'ios/device_util.mm',
'ios/ios_util.h',
'ios/ios_util.mm',
'ios/scoped_critical_action.h',
'ios/scoped_critical_action.mm',
+ 'ios/weak_nsobject.h',
+ 'ios/weak_nsobject.mm',
'json/json_file_value_serializer.cc',
'json/json_file_value_serializer.h',
'json/json_parser.cc',
@@ -258,6 +259,7 @@
'json/json_reader.h',
'json/json_string_value_serializer.cc',
'json/json_string_value_serializer.h',
+ 'json/json_value_converter.cc',
'json/json_value_converter.h',
'json/json_writer.cc',
'json/json_writer.h',
@@ -278,6 +280,8 @@
'mac/bundle_locations.mm',
'mac/close_nocancel.cc',
'mac/cocoa_protocols.h',
+ 'mac/dispatch_source_mach.cc',
+ 'mac/dispatch_source_mach.h',
'mac/foundation_util.h',
'mac/foundation_util.mm',
'mac/launch_services_util.cc',
@@ -286,12 +290,14 @@
'mac/launchd.h',
'mac/libdispatch_task_runner.cc',
'mac/libdispatch_task_runner.h',
- 'mac/mac_logging.h',
'mac/mac_logging.cc',
+ 'mac/mac_logging.h',
'mac/mac_util.h',
'mac/mac_util.mm',
'mac/mach_logging.cc',
'mac/mach_logging.h',
+ 'mac/memory_pressure_monitor.cc',
+ 'mac/memory_pressure_monitor.h',
'mac/objc_property_releaser.h',
'mac/objc_property_releaser.mm',
'mac/os_crash_dumps.cc',
@@ -326,31 +332,22 @@
'memory/aligned_memory.h',
'memory/discardable_memory.cc',
'memory/discardable_memory.h',
- 'memory/discardable_memory_android.cc',
- 'memory/discardable_memory_emulated.cc',
- 'memory/discardable_memory_emulated.h',
- 'memory/discardable_memory_linux.cc',
- 'memory/discardable_memory_mac.cc',
- 'memory/discardable_memory_manager.cc',
- 'memory/discardable_memory_manager.h',
- 'memory/discardable_memory_shmem.cc',
- 'memory/discardable_memory_shmem.h',
- 'memory/discardable_memory_shmem_allocator.cc',
- 'memory/discardable_memory_shmem_allocator.h',
- 'memory/discardable_memory_win.cc',
+ 'memory/discardable_memory_allocator.cc',
+ 'memory/discardable_memory_allocator.h',
'memory/discardable_shared_memory.cc',
'memory/discardable_shared_memory.h',
'memory/linked_ptr.h',
'memory/manual_constructor.h',
'memory/memory_pressure_listener.cc',
'memory/memory_pressure_listener.h',
+ 'memory/memory_pressure_monitor.cc',
+ 'memory/memory_pressure_monitor.h',
'memory/raw_scoped_refptr_mismatch_checker.h',
'memory/ref_counted.cc',
'memory/ref_counted.h',
'memory/ref_counted_delete_on_message_loop.h',
'memory/ref_counted_memory.cc',
'memory/ref_counted_memory.h',
- 'memory/scoped_open_process.h',
'memory/scoped_policy.h',
'memory/scoped_ptr.h',
'memory/scoped_vector.h',
@@ -380,10 +377,6 @@
'message_loop/message_pump_win.cc',
'message_loop/message_pump_win.h',
'message_loop/timer_slack.h',
- 'metrics/sample_map.cc',
- 'metrics/sample_map.h',
- 'metrics/sample_vector.cc',
- 'metrics/sample_vector.h',
'metrics/bucket_ranges.cc',
'metrics/bucket_ranges.h',
'metrics/histogram.cc',
@@ -393,23 +386,25 @@
'metrics/histogram_delta_serialization.cc',
'metrics/histogram_delta_serialization.h',
'metrics/histogram_flattener.h',
+ 'metrics/histogram_macros.h',
'metrics/histogram_samples.cc',
'metrics/histogram_samples.h',
'metrics/histogram_snapshot_manager.cc',
'metrics/histogram_snapshot_manager.h',
+ 'metrics/sample_map.cc',
+ 'metrics/sample_map.h',
+ 'metrics/sample_vector.cc',
+ 'metrics/sample_vector.h',
'metrics/sparse_histogram.cc',
'metrics/sparse_histogram.h',
'metrics/statistics_recorder.cc',
'metrics/statistics_recorder.h',
- 'metrics/stats_counters.cc',
- 'metrics/stats_counters.h',
- 'metrics/stats_table.cc',
- 'metrics/stats_table.h',
'metrics/user_metrics.cc',
'metrics/user_metrics.h',
'metrics/user_metrics_action.h',
'move.h',
'native_library.h',
+ 'native_library_ios.mm',
'native_library_mac.mm',
'native_library_posix.cc',
'native_library_win.cc',
@@ -417,6 +412,10 @@
'nix/mime_util_xdg.h',
'nix/xdg_util.cc',
'nix/xdg_util.h',
+ 'numerics/safe_conversions.h',
+ 'numerics/safe_conversions_impl.h',
+ 'numerics/safe_math.h',
+ 'numerics/safe_math_impl.h',
'observer_list.h',
'observer_list_threadsafe.h',
'os_compat_android.cc',
@@ -437,11 +436,11 @@
'posix/unix_domain_socket_linux.h',
'power_monitor/power_monitor.cc',
'power_monitor/power_monitor.h',
+ 'power_monitor/power_monitor_device_source.cc',
+ 'power_monitor/power_monitor_device_source.h',
'power_monitor/power_monitor_device_source_android.cc',
'power_monitor/power_monitor_device_source_android.h',
'power_monitor/power_monitor_device_source_chromeos.cc',
- 'power_monitor/power_monitor_device_source.cc',
- 'power_monitor/power_monitor_device_source.h',
'power_monitor/power_monitor_device_source_ios.mm',
'power_monitor/power_monitor_device_source_mac.mm',
'power_monitor/power_monitor_device_source_posix.cc',
@@ -462,8 +461,8 @@
'process/launch_mac.cc',
'process/launch_posix.cc',
'process/launch_win.cc',
- 'process/memory.h',
'process/memory.cc',
+ 'process/memory.h',
'process/memory_linux.cc',
'process/memory_mac.mm',
'process/memory_win.cc',
@@ -486,8 +485,9 @@
'process/process_iterator_openbsd.cc',
'process/process_iterator_win.cc',
'process/process_linux.cc',
- 'process/process_metrics.h',
+ 'process/process_mac.cc',
'process/process_metrics.cc',
+ 'process/process_metrics.h',
'process/process_metrics_freebsd.cc',
'process/process_metrics_ios.cc',
'process/process_metrics_linux.cc',
@@ -499,10 +499,16 @@
'process/process_win.cc',
'profiler/alternate_timer.cc',
'profiler/alternate_timer.h',
+ 'profiler/native_stack_sampler.cc',
+ 'profiler/native_stack_sampler.h',
'profiler/scoped_profile.cc',
'profiler/scoped_profile.h',
'profiler/scoped_tracker.cc',
'profiler/scoped_tracker.h',
+ 'profiler/stack_sampling_profiler.cc',
+ 'profiler/stack_sampling_profiler.h',
+ 'profiler/stack_sampling_profiler_posix.cc',
+ 'profiler/stack_sampling_profiler_win.cc',
'profiler/tracked_time.cc',
'profiler/tracked_time.h',
'rand_util.cc',
@@ -512,10 +518,6 @@
'rand_util_win.cc',
'run_loop.cc',
'run_loop.h',
- 'numerics/safe_conversions.h',
- 'numerics/safe_conversions_impl.h',
- 'numerics/safe_math.h',
- 'numerics/safe_math_impl.h',
'safe_strerror_posix.cc',
'safe_strerror_posix.h',
'scoped_generic.h',
@@ -542,11 +544,11 @@
'strings/string16.cc',
'strings/string16.h',
'strings/string_number_conversions.cc',
- 'strings/string_split.cc',
- 'strings/string_split.h',
'strings/string_number_conversions.h',
'strings/string_piece.cc',
'strings/string_piece.h',
+ 'strings/string_split.cc',
+ 'strings/string_split.h',
'strings/string_tokenizer.h',
'strings/string_util.cc',
'strings/string_util.h',
@@ -585,8 +587,6 @@
'synchronization/waitable_event_watcher_posix.cc',
'synchronization/waitable_event_watcher_win.cc',
'synchronization/waitable_event_win.cc',
- 'system_monitor/system_monitor.cc',
- 'system_monitor/system_monitor.h',
'sys_byteorder.h',
'sys_info.cc',
'sys_info.h',
@@ -600,12 +600,23 @@
'sys_info_openbsd.cc',
'sys_info_posix.cc',
'sys_info_win.cc',
+ 'system_monitor/system_monitor.cc',
+ 'system_monitor/system_monitor.h',
'task/cancelable_task_tracker.cc',
'task/cancelable_task_tracker.h',
'task_runner.cc',
'task_runner.h',
'task_runner_util.h',
'template_util.h',
+ 'third_party/dmg_fp/dmg_fp.h',
+ 'third_party/dmg_fp/dtoa_wrapper.cc',
+ 'third_party/dmg_fp/g_fmt.cc',
+ 'third_party/icu/icu_utf.cc',
+ 'third_party/icu/icu_utf.h',
+ 'third_party/nspr/prtime.cc',
+ 'third_party/nspr/prtime.h',
+ 'third_party/superfasthash/superfasthash.c',
+ 'third_party/xdg_mime/xdgmime.h',
'thread_task_runner_handle.cc',
'thread_task_runner_handle.h',
'threading/non_thread_safe.h',
@@ -613,6 +624,8 @@
'threading/non_thread_safe_impl.h',
'threading/platform_thread.h',
'threading/platform_thread_android.cc',
+ 'threading/platform_thread_internal_posix.cc',
+ 'threading/platform_thread_internal_posix.h',
'threading/platform_thread_linux.cc',
'threading/platform_thread_mac.mm',
'threading/platform_thread_posix.cc',
@@ -640,12 +653,12 @@
'threading/thread_local_storage_posix.cc',
'threading/thread_local_storage_win.cc',
'threading/thread_local_win.cc',
- 'threading/thread_restrictions.h',
'threading/thread_restrictions.cc',
+ 'threading/thread_restrictions.h',
'threading/watchdog.cc',
'threading/watchdog.h',
- 'threading/worker_pool.h',
'threading/worker_pool.cc',
+ 'threading/worker_pool.h',
'threading/worker_pool_posix.cc',
'threading/worker_pool_posix.h',
'threading/worker_pool_win.cc',
@@ -676,10 +689,10 @@
'tracking_info.cc',
'tracking_info.h',
'tuple.h',
- 'values.cc',
- 'values.h',
'value_conversions.cc',
'value_conversions.h',
+ 'values.cc',
+ 'values.h',
'version.cc',
'version.h',
'vlog.cc',
@@ -697,6 +710,8 @@
'win/iat_patch_function.h',
'win/iunknown_impl.cc',
'win/iunknown_impl.h',
+ 'win/memory_pressure_monitor.cc',
+ 'win/memory_pressure_monitor.h',
'win/message_window.cc',
'win/message_window.h',
'win/metro.cc',
@@ -733,6 +748,7 @@
'win/windows_version.h',
'win/wrapped_window_proc.cc',
'win/wrapped_window_proc.h',
+ '<@(trace_event_sources)',
],
'defines': [
'BASE_IMPLEMENTATION',
@@ -770,6 +786,7 @@
'allocator/type_profiler_control.h',
'base_paths.cc',
'cpu.cc',
+ 'debug/stack_trace.cc',
'debug/stack_trace_posix.cc',
'files/file_enumerator_posix.cc',
'files/file_path_watcher_fsevents.cc',
@@ -780,17 +797,22 @@
'files/file_util.cc',
'files/file_util_posix.cc',
'files/file_util_proxy.cc',
+ 'files/important_file_writer.cc',
+ 'files/scoped_temp_dir.cc',
'memory/shared_memory_posix.cc',
'native_library_posix.cc',
'path_service.cc',
'posix/unix_domain_socket_linux.cc',
+ 'process/kill.cc',
'process/kill_posix.cc',
+ 'process/launch.cc',
'process/launch_posix.cc',
+ 'process/process_metrics.cc',
'process/process_metrics_posix.cc',
'process/process_posix.cc',
'rand_util_posix.cc',
'scoped_native_library.cc',
- 'files/scoped_temp_dir.cc',
+ 'sys_info.cc',
'sys_info_posix.cc',
'third_party/dynamic_annotations/dynamic_annotations.c',
],
@@ -798,14 +820,6 @@
['include', '^threading/platform_thread_linux\\.cc$'],
],
}],
- ['OS == "android" and _toolset == "target" and >(nacl_untrusted_build)==0', {
- 'sources': [
- 'memory/discardable_memory_ashmem_allocator.cc',
- 'memory/discardable_memory_ashmem_allocator.h',
- 'memory/discardable_memory_ashmem.cc',
- 'memory/discardable_memory_ashmem.h',
- ],
- }],
['OS == "android" and >(nacl_untrusted_build)==0', {
'sources!': [
'base_paths_posix.cc',
@@ -841,13 +855,6 @@
['include', '^threading/platform_thread_linux\\.cc$'],
],
}],
- ['OS == "android" and <(android_webview_build)==1', {
- 'defines': [
- # WebView builds as part of the system which already has sincos;
- # avoid defining it again as it causes a linker warning.
- 'ANDROID_SINCOS_PROVIDED',
- ],
- }],
['<(chromeos) == 1', {
'sources!': [
'power_monitor/power_monitor_device_source_posix.cc',
@@ -870,7 +877,7 @@
['include', '^mac/scoped_mach_vm\\.'],
['include', '^mac/scoped_nsautorelease_pool\\.'],
['include', '^mac/scoped_nsobject\\.'],
- ['include', '^memory/discardable_memory_mac\\.'],
+ ['include', '^mac/scoped_objc_class_swizzler\\.'],
['include', '^message_loop/message_pump_mac\\.'],
['include', '^strings/sys_string_conversions_mac\\.'],
['include', '^threading/platform_thread_mac\\.'],
@@ -882,6 +889,8 @@
['include', '^process/.*_ios\.(cc|mm)$'],
['include', '^process/memory_stubs\.cc$'],
['include', '^process/process_handle_posix\.cc$'],
+ ['include', '^process/process_metrics\\.cc$'],
+ ['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
['exclude', 'files/file_path_watcher_fsevents.cc'],
['exclude', 'files/file_path_watcher_fsevents.h'],
['include', 'files/file_path_watcher_mac.cc'],
@@ -920,7 +929,6 @@
'<(DEPTH)/third_party/wtl/include',
],
'sources!': [
- 'event_recorder_stubs.cc',
'files/file_path_watcher_fsevents.cc',
'files/file_path_watcher_fsevents.h',
'files/file_path_watcher_kqueue.cc',
@@ -949,15 +957,12 @@
],
}],
['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', {
- 'sources': [
- 'memory/discardable_memory_mach.cc',
- 'memory/discardable_memory_mach.h',
- ],
'sources/': [
- ['exclude', '^files/file_path_watcher_stub\\.cc$'],
['exclude', '^base_paths_posix\\.cc$'],
+ ['exclude', '^files/file_path_watcher_stub\\.cc$'],
['exclude', '^native_library_posix\\.cc$'],
['exclude', '^strings/sys_string_conversions_posix\\.cc$'],
+ ['exclude', '^threading/platform_thread_internal_posix\\.cc$'],
],
}],
['<(os_bsd)==1 and >(nacl_untrusted_build)==0', {
@@ -977,6 +982,11 @@
['OS == "win" and >(nacl_untrusted_build)==1', {
'sources/': [ ['exclude', '\\.h$'] ],
}],
+ # Enable more direct string conversions on platforms with native utf8
+ # strings
+ ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+ 'defines': ['SYSTEM_NATIVE_UTF8'],
+ }],
],
}],
['base_i18n_target==1', {
diff --git a/chromium/base/base.isolate b/chromium/base/base.isolate
index 0416935e373..c7ba651ac71 100644
--- a/chromium/base/base.isolate
+++ b/chromium/base/base.isolate
@@ -7,9 +7,11 @@
# itself, virtually all targets using it has to include icu. The only
# exception is the Windows sandbox (?).
'../third_party/icu/icu.isolate',
+ # Sanitizer-instrumented third-party libraries (if enabled).
+ '../third_party/instrumented_libraries/instrumented_libraries.isolate',
],
'conditions': [
- ['OS=="linux" and asan==1 and chromeos==0', {
+ ['use_custom_libcxx==1', {
'variables': {
'files': [
'<(PRODUCT_DIR)/lib/libc++.so',
@@ -23,35 +25,42 @@
],
},
}],
- ['OS=="linux" and asan==1', {
+ ['OS=="win"', {
+ # Required for base/stack_trace_win.cc to symbolize correctly.
'variables': {
'files': [
- '../third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6',
+ '<(PRODUCT_DIR)/dbghelp.dll',
],
},
}],
- ['asan==1', {
+ ['OS=="win" and asan==1 and component=="shared_library"', {
'variables': {
'files': [
- '../tools/valgrind/asan/',
- '../third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer',
+ '../third_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll',
+ ],
+ },
+ }],
+ ['OS=="linux" and (asan==1 or lsan==1 or msan==1 or tsan==1)', {
+ 'variables': {
+ 'files': [
+ # For llvm-symbolizer.
+ '../third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6',
],
},
}],
- ['lsan==1', {
+ ['asan==1 or lsan==1 or msan==1 or tsan==1', {
'variables': {
'files': [
- '../tools/lsan/suppressions.txt',
+ '../tools/valgrind/asan/',
+ '../third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer<(EXECUTABLE_SUFFIX)',
],
},
}],
+ # Copy the VS runtime DLLs into the isolate so that they
+ # don't have to be preinstalled on the target machine.
['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
'variables': {
'files': [
- # Copy the VS runtime DLLs into the isolate so that they
- # don't have to be preinstalled on the target machine.
- '<(PRODUCT_DIR)/msvcp120d.dll',
- '<(PRODUCT_DIR)/msvcr120d.dll',
'<(PRODUCT_DIR)/x64/msvcp120d.dll',
'<(PRODUCT_DIR)/x64/msvcr120d.dll',
],
@@ -60,12 +69,30 @@
['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Release"', {
'variables': {
'files': [
- # Copy the VS runtime DLLs into the isolate so that they
- # don't have to be preinstalled on the target machine.
+ '<(PRODUCT_DIR)/x64/msvcp120.dll',
+ '<(PRODUCT_DIR)/x64/msvcr120.dll',
+ ],
+ },
+ }],
+ ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Debug" or CONFIGURATION_NAME=="Debug_x64")', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/msvcp120d.dll',
+ '<(PRODUCT_DIR)/msvcr120d.dll',
+ ],
+ },
+ }],
+ ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
+ 'variables': {
+ 'files': [
'<(PRODUCT_DIR)/msvcp120.dll',
'<(PRODUCT_DIR)/msvcr120.dll',
],
},
}],
+ # Workaround for https://code.google.com/p/swarming/issues/detail?id=211
+ ['asan==0 or lsan==0 or msan==0 or tsan==0', {
+ 'variables': {},
+ }],
],
}
diff --git a/chromium/base/base64.h b/chromium/base/base64.h
index 43d8f76eb76..dd72c39a239 100644
--- a/chromium/base/base64.h
+++ b/chromium/base/base64.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_BASE64_H__
-#define BASE_BASE64_H__
+#ifndef BASE_BASE64_H_
+#define BASE_BASE64_H_
#include <string>
@@ -12,13 +12,14 @@
namespace base {
-// Encodes the input string in base64.
+// Encodes the input string in base64. The encoding can be done in-place.
BASE_EXPORT void Base64Encode(const StringPiece& input, std::string* output);
// Decodes the base64 input string. Returns true if successful and false
-// otherwise. The output string is only modified if successful.
+// otherwise. The output string is only modified if successful. The decoding can
+// be done in-place.
BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
} // namespace base
-#endif // BASE_BASE64_H__
+#endif // BASE_BASE64_H_
diff --git a/chromium/base/base64_unittest.cc b/chromium/base/base64_unittest.cc
index 9b23194ccf6..91651f4d39b 100644
--- a/chromium/base/base64_unittest.cc
+++ b/chromium/base/base64_unittest.cc
@@ -24,4 +24,17 @@ TEST(Base64Test, Basic) {
EXPECT_EQ(kText, decoded);
}
+TEST(Base64Test, InPlace) {
+ const std::string kText = "hello world";
+ const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+ std::string text(kText);
+
+ Base64Encode(text, &text);
+ EXPECT_EQ(kBase64Text, text);
+
+ bool ok = Base64Decode(text, &text);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(text, kText);
+}
+
} // namespace base
diff --git a/chromium/base/base_nacl.gyp b/chromium/base/base_nacl.gyp
index 63e1ed422bd..40005d2cafb 100644
--- a/chromium/base/base_nacl.gyp
+++ b/chromium/base/base_nacl.gyp
@@ -7,8 +7,12 @@
'chromium_code': 1,
},
'includes': [
- '../build/common_untrusted.gypi',
+ # base.gypi must be included before common_untrusted.gypi.
+ #
+ # TODO(sergeyu): Replace the target_defaults magic in base.gypi with a
+ # sources variables lists. That way order of includes will not matter.
'base.gypi',
+ '../build/common_untrusted.gypi',
],
'conditions': [
['disable_nacl==0 and disable_nacl_untrusted==0', {
@@ -35,9 +39,6 @@
'-fno-strict-aliasing',
],
},
- 'dependencies': [
- '../native_client/tools.gyp:prep_toolchain',
- ],
},
{
'target_name': 'base_i18n_nacl',
@@ -59,7 +60,6 @@
],
},
'dependencies': [
- '../native_client/tools.gyp:prep_toolchain',
'../third_party/icu/icu_nacl.gyp:icudata_nacl',
'../third_party/icu/icu_nacl.gyp:icui18n_nacl',
'../third_party/icu/icu_nacl.gyp:icuuc_nacl',
@@ -109,7 +109,6 @@
'rand_util_nacl.cc',
],
'dependencies': [
- '../native_client/tools.gyp:prep_toolchain',
'../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
],
},
diff --git a/chromium/base/base_paths_win.cc b/chromium/base/base_paths_win.cc
index 5bef3106aaf..4ecb59d4dec 100644
--- a/chromium/base/base_paths_win.cc
+++ b/chromium/base/base_paths_win.cc
@@ -6,8 +6,10 @@
#include <shlobj.h>
#include "base/base_paths.h"
+#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/windows_version.h"
@@ -65,6 +67,27 @@ bool PathProviderWin(int key, FilePath* result) {
return false;
cur = FilePath(system_buffer);
break;
+ case base::DIR_PROGRAM_FILES6432:
+#if !defined(_WIN64)
+ if (base::win::OSInfo::GetInstance()->wow64_status() ==
+ base::win::OSInfo::WOW64_ENABLED) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string programfiles_w6432;
+ // 32-bit process running in WOW64 sets ProgramW6432 environment
+ // variable. See
+ // https://msdn.microsoft.com/library/windows/desktop/aa384274.aspx.
+ if (!env->GetVar("ProgramW6432", &programfiles_w6432))
+ return false;
+ // GetVar returns UTF8 - convert back to Wide.
+ cur = FilePath(UTF8ToWide(programfiles_w6432));
+ break;
+ }
+#endif
+ if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
+ SHGFP_TYPE_CURRENT, system_buffer)))
+ return false;
+ cur = FilePath(system_buffer);
+ break;
case base::DIR_IE_INTERNET_CACHE:
if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
SHGFP_TYPE_CURRENT, system_buffer)))
diff --git a/chromium/base/base_paths_win.h b/chromium/base/base_paths_win.h
index 032de348c5c..9ac9e45e0a7 100644
--- a/chromium/base/base_paths_win.h
+++ b/chromium/base/base_paths_win.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_BASE_PATHS_WIN_H__
-#define BASE_BASE_PATHS_WIN_H__
+#ifndef BASE_BASE_PATHS_WIN_H_
+#define BASE_BASE_PATHS_WIN_H_
// This file declares windows-specific path keys for the base module.
// These can be used with the PathService to access various special
@@ -16,8 +16,14 @@ enum {
DIR_WINDOWS, // Windows directory, usually "c:\windows"
DIR_SYSTEM, // Usually c:\windows\system32"
- DIR_PROGRAM_FILES, // Usually c:\program files
- DIR_PROGRAM_FILESX86, // Usually c:\program files or c:\program files (x86)
+ // 32-bit 32-bit on 64-bit 64-bit on 64-bit
+ // DIR_PROGRAM_FILES 1 2 1
+ // DIR_PROGRAM_FILESX86 1 2 2
+ // DIR_PROGRAM_FILES6432 1 1 1
+ // 1 - C:\Program Files 2 - C:\Program Files (x86)
+ DIR_PROGRAM_FILES, // See table above.
+ DIR_PROGRAM_FILESX86, // See table above.
+ DIR_PROGRAM_FILES6432, // See table above.
DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory.
DIR_COMMON_START_MENU, // Usually "C:\Documents and Settings\All Users\
@@ -45,4 +51,4 @@ enum {
} // namespace base
-#endif // BASE_BASE_PATHS_WIN_H__
+#endif // BASE_BASE_PATHS_WIN_H_
diff --git a/chromium/base/base_switches.cc b/chromium/base/base_switches.cc
index 27f52cdb330..30765405de1 100644
--- a/chromium/base/base_switches.cc
+++ b/chromium/base/base_switches.cc
@@ -17,10 +17,11 @@ const char kEnableCrashReporter[] = "enable-crash-reporter";
// Generates full memory crash dump.
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
-// Force low-end device when set to 1;
-// Auto-detect low-end device when set to 2;
-// Force non-low-end device when set to other values or empty;
-const char kLowEndDeviceMode[] = "low-end-device-mode";
+// Force low-end device mode when set.
+const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
+
+// Force disabling of low-end device mode when set.
+const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
// Suppresses all error dialogs when present.
const char kNoErrorDialogs[] = "noerrdialogs";
diff --git a/chromium/base/base_switches.h b/chromium/base/base_switches.h
index 96cbd5bbb56..c579f6a240d 100644
--- a/chromium/base/base_switches.h
+++ b/chromium/base/base_switches.h
@@ -14,7 +14,8 @@ namespace switches {
extern const char kDisableBreakpad[];
extern const char kEnableCrashReporter[];
extern const char kFullMemoryCrashReport[];
-extern const char kLowEndDeviceMode[];
+extern const char kEnableLowEndDeviceMode[];
+extern const char kDisableLowEndDeviceMode[];
extern const char kNoErrorDialogs[];
extern const char kProfilerTiming[];
extern const char kProfilerTimingDisabledValue[];
diff --git a/chromium/base/base_unittests.isolate b/chromium/base/base_unittests.isolate
index f561d209cf5..b1c270ca89d 100644
--- a/chromium/base/base_unittests.isolate
+++ b/chromium/base/base_unittests.isolate
@@ -3,14 +3,20 @@
# found in the LICENSE file.
{
'conditions': [
- ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
+ ['use_x11==0', {
'variables': {
- 'files': [
- 'test/data/',
+ 'command': [
+ '../testing/test_env.py',
+ '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
],
},
}],
- ['OS=="linux"', {
+ ['use_x11==1', {
'variables': {
'command': [
'../testing/xvfb.py',
@@ -19,17 +25,19 @@
'--brave-new-test-launcher',
'--test-launcher-bot-mode',
'--asan=<(asan)',
- '--lsan=<(lsan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
],
'files': [
'../testing/xvfb.py',
+ '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
],
},
}],
- ['OS=="linux" and use_ozone==0', {
+ ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'files': [
- '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+ 'test/data/',
],
},
}],
@@ -42,15 +50,17 @@
'read_only': 1,
},
}],
- ['OS=="mac" or OS=="win"', {
+ ['OS=="linux"', {
'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--lsan=<(lsan)',
+ 'files': [
+ '<(PRODUCT_DIR)/lib/libmalloc_wrapper.so',
+ ],
+ },
+ }],
+ ['OS=="mac" and asan==1 and fastbuild==0', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/base_unittests.dSYM/',
],
},
}],
diff --git a/chromium/base/bind.h b/chromium/base/bind.h
index b14f70c109f..51be10dd7e6 100644
--- a/chromium/base/bind.h
+++ b/chromium/base/bind.h
@@ -1,8 +1,3 @@
-// This file was GENERATED by command:
-// pump.py bind.h.pump
-// DO NOT EDIT BY HAND!!!
-
-
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -46,10 +41,9 @@
//
// TODO(ajwong): We might be able to avoid this now, but need to test.
//
-// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
-// but it feels a little nicer to have the asserts here so people do not
-// need to crack open bind_internal.h. On the other hand, it makes Bind()
-// harder to read.
+// It is possible to move most of the static_assert into BindState<>, but it
+// feels a little nicer to have the asserts here so people do not need to crack
+// open bind_internal.h. On the other hand, it makes Bind() harder to read.
namespace base {
@@ -58,317 +52,28 @@ base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
- void()>
- ::UnboundRunType>
+ internal::TypeList<>>::UnboundRunType>
Bind(Functor functor) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
- typedef internal::BindState<RunnableType, RunType, void()> BindState;
-
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor)));
-}
-
-template <typename Functor, typename P1>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType)>
- ::UnboundRunType>
-Bind(Functor functor, const P1& p1) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;
-
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1));
-}
-
-template <typename Functor, typename P1, typename P2>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType)>
- ::UnboundRunType>
-Bind(Functor functor, const P1& p1, const P2& p2) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
- p2_is_refcounted_type_and_needs_scoped_refptr);
- typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType)> BindState;
-
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1, p2));
-}
-
-template <typename Functor, typename P1, typename P2, typename P3>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType)>
- ::UnboundRunType>
-Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
- p2_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
- p3_is_refcounted_type_and_needs_scoped_refptr);
- typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType)> BindState;
-
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1, p2, p3));
-}
-
-template <typename Functor, typename P1, typename P2, typename P3, typename P4>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType)>
- ::UnboundRunType>
-Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
- p2_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
- p3_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
- p4_is_refcounted_type_and_needs_scoped_refptr);
- typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType)> BindState;
-
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
-}
-
-template <typename Functor, typename P1, typename P2, typename P3, typename P4,
- typename P5>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType,
- typename internal::CallbackParamTraits<P5>::StorageType)>
- ::UnboundRunType>
-Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
- const P5& p5) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
- p2_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
- p3_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
- p4_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
- p5_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType,
- typename internal::CallbackParamTraits<P5>::StorageType)> BindState;
-
+ internal::TypeList<>> BindState;
return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
+ new BindState(internal::MakeRunnable(functor)));
}
-template <typename Functor, typename P1, typename P2, typename P3, typename P4,
- typename P5, typename P6>
+template <typename Functor, typename... Args>
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType,
- typename internal::CallbackParamTraits<P5>::StorageType,
- typename internal::CallbackParamTraits<P6>::StorageType)>
+ internal::TypeList<
+ typename internal::CallbackParamTraits<Args>::StorageType...>>
::UnboundRunType>
-Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
- const P5& p5, const P6& p6) {
+Bind(Functor functor, const Args&... args) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
@@ -376,134 +81,36 @@ Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
+ typedef typename RunnableType::RunType BoundRunType;
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
- p2_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
- p3_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
- p4_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
- p5_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
- p6_is_refcounted_type_and_needs_scoped_refptr);
- typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType,
- typename internal::CallbackParamTraits<P5>::StorageType,
- typename internal::CallbackParamTraits<P6>::StorageType)> BindState;
+ static_assert(!internal::HasNonConstReferenceParam<BoundRunType>::value,
+ "do_not_bind_functions_with_nonconst_ref");
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
-}
-
-template <typename Functor, typename P1, typename P2, typename P3, typename P4,
- typename P5, typename P6, typename P7>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType,
- typename internal::CallbackParamTraits<P5>::StorageType,
- typename internal::CallbackParamTraits<P6>::StorageType,
- typename internal::CallbackParamTraits<P7>::StorageType)>
- ::UnboundRunType>
-Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
- const P5& p5, const P6& p6, const P7& p7) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ||
- is_non_const_reference<typename BoundFunctorTraits::A7Type>::value ),
- do_not_bind_functions_with_nonconst_ref);
+ const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
- p1_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P1>::value,
- first_bound_argument_to_method_cannot_be_array);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
- p2_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
- p3_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
- p4_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
- p5_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
- p6_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
- p7_is_refcounted_type_and_needs_scoped_refptr);
- typedef internal::BindState<RunnableType, RunType,
- void(typename internal::CallbackParamTraits<P1>::StorageType,
- typename internal::CallbackParamTraits<P2>::StorageType,
- typename internal::CallbackParamTraits<P3>::StorageType,
- typename internal::CallbackParamTraits<P4>::StorageType,
- typename internal::CallbackParamTraits<P5>::StorageType,
- typename internal::CallbackParamTraits<P6>::StorageType,
- typename internal::CallbackParamTraits<P7>::StorageType)> BindState;
-
+ static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
+ "first_bound_argument_to_method_cannot_be_array");
+ static_assert(
+ !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
+ "a_parameter_is_refcounted_type_and_needs_scoped_refptr");
+
+ typedef internal::BindState<
+ RunnableType, RunType,
+ internal::TypeList<
+ typename internal::CallbackParamTraits<Args>::StorageType...>>
+ BindState;
return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
- p7));
+ new BindState(internal::MakeRunnable(functor), args...));
}
} // namespace base
diff --git a/chromium/base/bind.h.pump b/chromium/base/bind.h.pump
deleted file mode 100644
index 2cdd7d5e498..00000000000
--- a/chromium/base/bind.h.pump
+++ /dev/null
@@ -1,153 +0,0 @@
-$$ This is a pump file for generating file templates. Pump is a python
-$$ script that is part of the Google Test suite of utilities. Description
-$$ can be found here:
-$$
-$$ http://code.google.com/p/googletest/wiki/PumpManual
-$$
-
-$$
-$$ MAX_ARITY controls the number of arguments that Bind() supports.
-$$ The amount of code, and more importantly, the number of template types
-$$ generated by pump grows at O(MAX_ARITY^2).
-$$
-$$ We tried going to 11 and found it imposed an extra 10 penalty on windows
-$$ cycle times compared to our original baseline of 6.
-$$
-$$ Currently 7 is chosen as a compromise between supporting a convenient
-$$ number of arguments and keeping compile times low. At 7, we have 115
-$$ templates being generated by pump.
-$$
-$$ Be careful when adjusting this number. If people find a need to bind
-$$ a larger number of arguments, consider refactoring the function to use
-$$ a param struct instead of raising the MAX_ARITY.
-$$
-$$ See http://crbug.com/98542 for more context.
-$$
-$var MAX_ARITY = 7
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_BIND_H_
-#define BASE_BIND_H_
-
-#include "base/bind_internal.h"
-#include "base/callback_internal.h"
-
-// -----------------------------------------------------------------------------
-// Usage documentation
-// -----------------------------------------------------------------------------
-//
-// See base/callback.h for documentation.
-//
-//
-// -----------------------------------------------------------------------------
-// Implementation notes
-// -----------------------------------------------------------------------------
-//
-// If you're reading the implementation, before proceeding further, you should
-// read the top comment of base/bind_internal.h for a definition of common
-// terms and concepts.
-//
-// RETURN TYPES
-//
-// Though Bind()'s result is meant to be stored in a Callback<> type, it
-// cannot actually return the exact type without requiring a large amount
-// of extra template specializations. The problem is that in order to
-// discern the correct specialization of Callback<>, Bind would need to
-// unwrap the function signature to determine the signature's arity, and
-// whether or not it is a method.
-//
-// Each unique combination of (arity, function_type, num_prebound) where
-// function_type is one of {function, method, const_method} would require
-// one specialization. We eventually have to do a similar number of
-// specializations anyways in the implementation (see the Invoker<>,
-// classes). However, it is avoidable in Bind if we return the result
-// via an indirection like we do below.
-//
-// TODO(ajwong): We might be able to avoid this now, but need to test.
-//
-// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
-// but it feels a little nicer to have the asserts here so people do not
-// need to crack open bind_internal.h. On the other hand, it makes Bind()
-// harder to read.
-
-namespace base {
-
-$range ARITY 0..MAX_ARITY
-$for ARITY [[
-$range ARG 1..ARITY
-
-template <typename Functor[[]]
-$if ARITY > 0 [[, ]] $for ARG , [[typename P$(ARG)]]>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])>
- ::UnboundRunType>
-Bind(Functor functor
-$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]]) {
- // Typedefs for how to store and run the functor.
- typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
- typedef typename internal::FunctorTraits<Functor>::RunType RunType;
-
-$if ARITY > 0 [[
-
- // Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
- // functor is going to interpret the argument as.
- typedef internal::FunctionTraits<typename RunnableType::RunType>
- BoundFunctorTraits;
-
- // Do not allow binding a non-const reference parameter. Non-const reference
- // parameters are disallowed by the Google style guide. Also, binding a
- // non-const reference parameter can make for subtle bugs because the
- // invoked function will receive a reference to the stored copy of the
- // argument and not the original.
- COMPILE_ASSERT(
- !($for ARG || [[
-is_non_const_reference<typename BoundFunctorTraits::A$(ARG)Type>::value ]]),
- do_not_bind_functions_with_nonconst_ref);
-
-]]
-
-
-$for ARG [[
-
-
-$if ARG == 1 [[
- // For methods, we need to be careful for parameter 1. We do not require
- // a scoped_refptr because BindState<> itself takes care of AddRef() for
- // methods. We also disallow binding of an array as the method's target
- // object.
- COMPILE_ASSERT(
- internal::HasIsMethodTag<RunnableType>::value ||
- !internal::NeedsScopedRefptrButGetsRawPtr<P$(ARG)>::value,
- p$(ARG)_is_refcounted_type_and_needs_scoped_refptr);
- COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
- !is_array<P$(ARG)>::value,
- first_bound_argument_to_method_cannot_be_array);
-]] $else [[
- COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P$(ARG)>::value,
- p$(ARG)_is_refcounted_type_and_needs_scoped_refptr);
-]] $$ $if ARG
-
-]] $$ $for ARG
-
- typedef internal::BindState<RunnableType, RunType, [[]]
-void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])> [[]]
-BindState;
-
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor)[[]]
-$if ARITY > 0 [[, ]] $for ARG , [[p$(ARG)]]));
-}
-
-]] $$ for ARITY
-
-} // namespace base
-
-#endif // BASE_BIND_H_
diff --git a/chromium/base/bind_helpers.h b/chromium/base/bind_helpers.h
index f3efc31953c..24063ad1ce5 100644
--- a/chromium/base/bind_helpers.h
+++ b/chromium/base/bind_helpers.h
@@ -129,7 +129,7 @@
// Passed() is particularly useful with PostTask() when you are transferring
// ownership of an argument into a task, but don't necessarily know if the
// task will always be executed. This can happen if the task is cancellable
-// or if it is posted to a MessageLoopProxy.
+// or if it is posted to a TaskRunner.
//
//
// SIMPLE FUNCTIONS AND UTILITIES.
@@ -435,45 +435,46 @@ struct UnwrapTraits<PassedWrapper<T> > {
// Utility for handling different refcounting semantics in the Bind()
// function.
-template <bool is_method, typename T>
-struct MaybeRefcount;
+template <bool is_method, typename... T>
+struct MaybeScopedRefPtr;
-template <typename T>
-struct MaybeRefcount<false, T> {
- static void AddRef(const T&) {}
- static void Release(const T&) {}
+template <bool is_method>
+struct MaybeScopedRefPtr<is_method> {
+ MaybeScopedRefPtr() {}
};
-template <typename T, size_t n>
-struct MaybeRefcount<false, T[n]> {
- static void AddRef(const T*) {}
- static void Release(const T*) {}
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<false, T, Rest...> {
+ MaybeScopedRefPtr(const T&, const Rest&...) {}
};
-template <typename T>
-struct MaybeRefcount<true, T> {
- static void AddRef(const T&) {}
- static void Release(const T&) {}
+template <typename T, size_t n, typename... Rest>
+struct MaybeScopedRefPtr<false, T[n], Rest...> {
+ MaybeScopedRefPtr(const T*, const Rest&...) {}
};
-template <typename T>
-struct MaybeRefcount<true, T*> {
- static void AddRef(T* o) { o->AddRef(); }
- static void Release(T* o) { o->Release(); }
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, T, Rest...> {
+ MaybeScopedRefPtr(const T& o, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, T*, Rest...> {
+ MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
+ scoped_refptr<T> ref_;
};
// No need to additionally AddRef() and Release() since we are storing a
// scoped_refptr<> inside the storage object already.
-template <typename T>
-struct MaybeRefcount<true, scoped_refptr<T> > {
- static void AddRef(const scoped_refptr<T>& o) {}
- static void Release(const scoped_refptr<T>& o) {}
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
+ MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
};
-template <typename T>
-struct MaybeRefcount<true, const T*> {
- static void AddRef(const T* o) { o->AddRef(); }
- static void Release(const T* o) { o->Release(); }
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, const T*, Rest...> {
+ MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
+ scoped_refptr<const T> ref_;
};
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
@@ -481,15 +482,72 @@ struct MaybeRefcount<true, const T*> {
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
// the target object is invalidated.
//
-// P1 should be the type of the object that will be received of the method.
-template <bool IsMethod, typename P1>
+// The first argument should be the type of the object that will be received by
+// the method.
+template <bool IsMethod, typename... Args>
struct IsWeakMethod : public false_type {};
-template <typename T>
-struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
+template <typename T, typename... Args>
+struct IsWeakMethod<true, WeakPtr<T>, Args...> : public true_type {};
-template <typename T>
-struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T> > > : public true_type {};
+template <typename T, typename... Args>
+struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...>
+ : public true_type {};
+
+
+// Packs a list of types to hold them in a single type.
+template <typename... Types>
+struct TypeList {};
+
+// Used for DropTypeListItem implementation.
+template <size_t n, typename List>
+struct DropTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List>
+struct DropTypeListItemImpl<n, TypeList<T, List...>>
+ : DropTypeListItemImpl<n - 1, TypeList<List...>> {};
+
+template <typename T, typename... List>
+struct DropTypeListItemImpl<0, TypeList<T, List...>> {
+ typedef TypeList<T, List...> Type;
+};
+
+template <>
+struct DropTypeListItemImpl<0, TypeList<>> {
+ typedef TypeList<> Type;
+};
+
+// A type-level function that drops |n| list item from given TypeList.
+template <size_t n, typename List>
+using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
+
+// Used for ConcatTypeLists implementation.
+template <typename List1, typename List2>
+struct ConcatTypeListsImpl;
+
+template <typename... Types1, typename... Types2>
+struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
+ typedef TypeList<Types1..., Types2...> Type;
+};
+
+// A type-level function that concats two TypeLists.
+template <typename List1, typename List2>
+using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
+
+// Used for MakeFunctionType implementation.
+template <typename R, typename ArgList>
+struct MakeFunctionTypeImpl;
+
+template <typename R, typename... Args>
+struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
+ typedef R(Type)(Args...);
+};
+
+// A type-level function that constructs a function type that has |R| as its
+// return type and has TypeLists items as its arguments.
+template <typename R, typename ArgList>
+using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
} // namespace internal
diff --git a/chromium/base/bind_internal.h b/chromium/base/bind_internal.h
index ae17ebf86c1..e0532188622 100644
--- a/chromium/base/bind_internal.h
+++ b/chromium/base/bind_internal.h
@@ -1,8 +1,3 @@
-// This file was GENERATED by command:
-// pump.py bind_internal.h.pump
-// DO NOT EDIT BY HAND!!!
-
-
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,6 +10,7 @@
#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
#include "base/memory/weak_ptr.h"
#include "base/template_util.h"
+#include "base/tuple.h"
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -51,33 +47,79 @@ namespace internal {
// Types:
// RunnableAdapter<> -- Wraps the various "function" pointer types into an
// object that adheres to the Runnable interface.
-// There are |3*ARITY| RunnableAdapter types.
-// FunctionTraits<> -- Type traits that unwrap a function signature into a
-// a set of easier to use typedefs. Used mainly for
-// compile time asserts.
-// There are |ARITY| FunctionTraits types.
// ForceVoidReturn<> -- Helper class for translating function signatures to
// equivalent forms with a "void" return type.
-// There are |ARITY| ForceVoidReturn types.
// FunctorTraits<> -- Type traits used determine the correct RunType and
// RunnableType for a Functor. This is where function
// signature adapters are applied.
-// There are |ARITY| ForceVoidReturn types.
// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
// type class that represents the underlying Functor.
// There are |O(1)| MakeRunnable types.
// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
-// Handle the differing syntaxes needed for WeakPtr<> support,
-// and for ignoring return values. This is separate from
-// Invoker to avoid creating multiple version of Invoker<>
-// which grows at O(n^2) with the arity.
-// There are |k*ARITY| InvokeHelper types.
+// Handle the differing syntaxes needed for WeakPtr<>
+// support, and for ignoring return values. This is separate
+// from Invoker to avoid creating multiple version of
+// Invoker<>.
// Invoker<> -- Unwraps the curried parameters and executes the Runnable.
-// There are |(ARITY^2 + ARITY)/2| Invoketypes.
// BindState<> -- Stores the curried parameters, and is the main entry point
// into the Bind() system, doing most of the type resolution.
// There are ARITY BindState types.
+// HasNonConstReferenceParam selects true_type when any of the parameters in
+// |Sig| is a non-const reference.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename Sig>
+struct HasNonConstReferenceParam : false_type {};
+
+// Implementation note: Select true_type if the first parameter is a non-const
+// reference. Otherwise, skip the first parameter and check rest of parameters
+// recursively.
+template <typename R, typename T, typename... Args>
+struct HasNonConstReferenceParam<R(T, Args...)>
+ : SelectType<is_non_const_reference<T>::value,
+ true_type,
+ HasNonConstReferenceParam<R(Args...)>>::Type {};
+
+// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
+// pointer to a RefCounted type.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename... Args>
+struct HasRefCountedTypeAsRawPtr : false_type {};
+
+// Implementation note: Select true_type if the first parameter is a raw pointer
+// to a RefCounted type. Otherwise, skip the first parameter and check rest of
+// parameters recursively.
+template <typename T, typename... Args>
+struct HasRefCountedTypeAsRawPtr<T, Args...>
+ : SelectType<NeedsScopedRefptrButGetsRawPtr<T>::value,
+ true_type,
+ HasRefCountedTypeAsRawPtr<Args...>>::Type {};
+
+// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
+// item of |Args| is an array type.
+// Implementation note: This non-specialized case handles !is_method case and
+// zero-arity case only. Other cases should be handled by the specialization
+// below.
+template <bool is_method, typename... Args>
+struct BindsArrayToFirstArg : false_type {};
+
+template <typename T, typename... Args>
+struct BindsArrayToFirstArg<true, T, Args...> : is_array<T> {};
+
+// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
+// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
+// Implementation note: This non-specialized case handles !is_method case and
+// zero-arity case only. Other cases should be handled by the specialization
+// below.
+template <bool is_method, typename... Args>
+struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
+
+template <typename T, typename... Args>
+struct HasRefCountedParamAsRawPtr<true, T, Args...>
+ : HasRefCountedTypeAsRawPtr<Args...> {};
+
// RunnableAdapter<>
//
// The RunnableAdapter<> templates provide a uniform interface for invoking
@@ -101,625 +143,61 @@ namespace internal {
template <typename Functor>
class RunnableAdapter;
-// Function: Arity 0.
-template <typename R>
-class RunnableAdapter<R(*)()> {
- public:
- typedef R (RunType)();
-
- explicit RunnableAdapter(R(*function)())
- : function_(function) {
- }
-
- R Run() {
- return function_();
- }
-
- private:
- R (*function_)();
-};
-
-// Method: Arity 0.
-template <typename R, typename T>
-class RunnableAdapter<R(T::*)()> {
- public:
- typedef R (RunType)(T*);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)())
- : method_(method) {
- }
-
- R Run(T* object) {
- return (object->*method_)();
- }
-
- private:
- R (T::*method_)();
-};
-
-// Const Method: Arity 0.
-template <typename R, typename T>
-class RunnableAdapter<R(T::*)() const> {
- public:
- typedef R (RunType)(const T*);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)() const)
- : method_(method) {
- }
-
- R Run(const T* object) {
- return (object->*method_)();
- }
-
- private:
- R (T::*method_)() const;
-};
-
-// Function: Arity 1.
-template <typename R, typename A1>
-class RunnableAdapter<R(*)(A1)> {
- public:
- typedef R (RunType)(A1);
-
- explicit RunnableAdapter(R(*function)(A1))
- : function_(function) {
- }
-
- R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
- return function_(CallbackForward(a1));
- }
-
- private:
- R (*function_)(A1);
-};
-
-// Method: Arity 1.
-template <typename R, typename T, typename A1>
-class RunnableAdapter<R(T::*)(A1)> {
- public:
- typedef R (RunType)(T*, A1);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1))
- : method_(method) {
- }
-
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1) {
- return (object->*method_)(CallbackForward(a1));
- }
-
- private:
- R (T::*method_)(A1);
-};
-
-// Const Method: Arity 1.
-template <typename R, typename T, typename A1>
-class RunnableAdapter<R(T::*)(A1) const> {
- public:
- typedef R (RunType)(const T*, A1);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1) const)
- : method_(method) {
- }
-
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1) {
- return (object->*method_)(CallbackForward(a1));
- }
-
- private:
- R (T::*method_)(A1) const;
-};
-
-// Function: Arity 2.
-template <typename R, typename A1, typename A2>
-class RunnableAdapter<R(*)(A1, A2)> {
- public:
- typedef R (RunType)(A1, A2);
-
- explicit RunnableAdapter(R(*function)(A1, A2))
- : function_(function) {
- }
-
- R Run(typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2) {
- return function_(CallbackForward(a1), CallbackForward(a2));
- }
-
- private:
- R (*function_)(A1, A2);
-};
-
-// Method: Arity 2.
-template <typename R, typename T, typename A1, typename A2>
-class RunnableAdapter<R(T::*)(A1, A2)> {
- public:
- typedef R (RunType)(T*, A1, A2);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2))
- : method_(method) {
- }
-
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2));
- }
-
- private:
- R (T::*method_)(A1, A2);
-};
-
-// Const Method: Arity 2.
-template <typename R, typename T, typename A1, typename A2>
-class RunnableAdapter<R(T::*)(A1, A2) const> {
- public:
- typedef R (RunType)(const T*, A1, A2);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2) const)
- : method_(method) {
- }
-
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2));
- }
-
- private:
- R (T::*method_)(A1, A2) const;
-};
-
-// Function: Arity 3.
-template <typename R, typename A1, typename A2, typename A3>
-class RunnableAdapter<R(*)(A1, A2, A3)> {
- public:
- typedef R (RunType)(A1, A2, A3);
-
- explicit RunnableAdapter(R(*function)(A1, A2, A3))
- : function_(function) {
- }
-
- R Run(typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3) {
- return function_(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3));
- }
-
- private:
- R (*function_)(A1, A2, A3);
-};
-
-// Method: Arity 3.
-template <typename R, typename T, typename A1, typename A2, typename A3>
-class RunnableAdapter<R(T::*)(A1, A2, A3)> {
- public:
- typedef R (RunType)(T*, A1, A2, A3);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3))
- : method_(method) {
- }
-
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3));
- }
-
- private:
- R (T::*method_)(A1, A2, A3);
-};
-
-// Const Method: Arity 3.
-template <typename R, typename T, typename A1, typename A2, typename A3>
-class RunnableAdapter<R(T::*)(A1, A2, A3) const> {
- public:
- typedef R (RunType)(const T*, A1, A2, A3);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3) const)
- : method_(method) {
- }
-
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3));
- }
-
- private:
- R (T::*method_)(A1, A2, A3) const;
-};
-
-// Function: Arity 4.
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-class RunnableAdapter<R(*)(A1, A2, A3, A4)> {
- public:
- typedef R (RunType)(A1, A2, A3, A4);
-
- explicit RunnableAdapter(R(*function)(A1, A2, A3, A4))
- : function_(function) {
- }
-
- R Run(typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4) {
- return function_(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4));
- }
-
- private:
- R (*function_)(A1, A2, A3, A4);
-};
-
-// Method: Arity 4.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4)> {
- public:
- typedef R (RunType)(T*, A1, A2, A3, A4);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4))
- : method_(method) {
- }
-
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4));
- }
-
- private:
- R (T::*method_)(A1, A2, A3, A4);
-};
-
-// Const Method: Arity 4.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4) const> {
- public:
- typedef R (RunType)(const T*, A1, A2, A3, A4);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4) const)
- : method_(method) {
- }
-
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4));
- }
-
- private:
- R (T::*method_)(A1, A2, A3, A4) const;
-};
-
-// Function: Arity 5.
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-class RunnableAdapter<R(*)(A1, A2, A3, A4, A5)> {
- public:
- typedef R (RunType)(A1, A2, A3, A4, A5);
-
- explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5))
- : function_(function) {
- }
-
- R Run(typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5) {
- return function_(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
- }
-
- private:
- R (*function_)(A1, A2, A3, A4, A5);
-};
-
-// Method: Arity 5.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4, typename A5>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5)> {
- public:
- typedef R (RunType)(T*, A1, A2, A3, A4, A5);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5))
- : method_(method) {
- }
-
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
- }
-
- private:
- R (T::*method_)(A1, A2, A3, A4, A5);
-};
-
-// Const Method: Arity 5.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4, typename A5>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5) const> {
- public:
- typedef R (RunType)(const T*, A1, A2, A3, A4, A5);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5) const)
- : method_(method) {
- }
-
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
- }
-
- private:
- R (T::*method_)(A1, A2, A3, A4, A5) const;
-};
-
-// Function: Arity 6.
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-class RunnableAdapter<R(*)(A1, A2, A3, A4, A5, A6)> {
- public:
- typedef R (RunType)(A1, A2, A3, A4, A5, A6);
-
- explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6))
- : function_(function) {
- }
-
- R Run(typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5,
- typename CallbackParamTraits<A6>::ForwardType a6) {
- return function_(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6));
- }
-
- private:
- R (*function_)(A1, A2, A3, A4, A5, A6);
-};
-
-// Method: Arity 6.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6)> {
- public:
- typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6))
- : method_(method) {
- }
-
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5,
- typename CallbackParamTraits<A6>::ForwardType a6) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6));
- }
-
- private:
- R (T::*method_)(A1, A2, A3, A4, A5, A6);
-};
-
-// Const Method: Arity 6.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6) const> {
- public:
- typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6) const)
- : method_(method) {
- }
-
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5,
- typename CallbackParamTraits<A6>::ForwardType a6) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6));
- }
-
- private:
- R (T::*method_)(A1, A2, A3, A4, A5, A6) const;
-};
-
-// Function: Arity 7.
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-class RunnableAdapter<R(*)(A1, A2, A3, A4, A5, A6, A7)> {
+// Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(*)(Args...)> {
public:
- typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
+ typedef R (RunType)(Args...);
- explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6, A7))
+ explicit RunnableAdapter(R(*function)(Args...))
: function_(function) {
}
- R Run(typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5,
- typename CallbackParamTraits<A6>::ForwardType a6,
- typename CallbackParamTraits<A7>::ForwardType a7) {
- return function_(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6), CallbackForward(a7));
+ R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+ return function_(CallbackForward(args)...);
}
private:
- R (*function_)(A1, A2, A3, A4, A5, A6, A7);
+ R (*function_)(Args...);
};
-// Method: Arity 7.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6, typename A7>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6, A7)> {
+// Method.
+template <typename R, typename T, typename... Args>
+class RunnableAdapter<R(T::*)(Args...)> {
public:
- typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6, A7);
+ typedef R (RunType)(T*, Args...);
typedef true_type IsMethod;
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7))
+ explicit RunnableAdapter(R(T::*method)(Args...))
: method_(method) {
}
- R Run(T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5,
- typename CallbackParamTraits<A6>::ForwardType a6,
- typename CallbackParamTraits<A7>::ForwardType a7) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6), CallbackForward(a7));
+ R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) {
+ return (object->*method_)(CallbackForward(args)...);
}
private:
- R (T::*method_)(A1, A2, A3, A4, A5, A6, A7);
+ R (T::*method_)(Args...);
};
-// Const Method: Arity 7.
-template <typename R, typename T, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6, typename A7>
-class RunnableAdapter<R(T::*)(A1, A2, A3, A4, A5, A6, A7) const> {
+// Const Method.
+template <typename R, typename T, typename... Args>
+class RunnableAdapter<R(T::*)(Args...) const> {
public:
- typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6, A7);
+ typedef R (RunType)(const T*, Args...);
typedef true_type IsMethod;
- explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7) const)
+ explicit RunnableAdapter(R(T::*method)(Args...) const)
: method_(method) {
}
- R Run(const T* object, typename CallbackParamTraits<A1>::ForwardType a1,
- typename CallbackParamTraits<A2>::ForwardType a2,
- typename CallbackParamTraits<A3>::ForwardType a3,
- typename CallbackParamTraits<A4>::ForwardType a4,
- typename CallbackParamTraits<A5>::ForwardType a5,
- typename CallbackParamTraits<A6>::ForwardType a6,
- typename CallbackParamTraits<A7>::ForwardType a7) {
- return (object->*method_)(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6), CallbackForward(a7));
+ R Run(const T* object,
+ typename CallbackParamTraits<Args>::ForwardType... args) {
+ return (object->*method_)(CallbackForward(args)...);
}
private:
- R (T::*method_)(A1, A2, A3, A4, A5, A6, A7) const;
-};
-
-
-// FunctionTraits<>
-//
-// Breaks a function signature apart into typedefs for easier introspection.
-template <typename Sig>
-struct FunctionTraits;
-
-template <typename R>
-struct FunctionTraits<R()> {
- typedef R ReturnType;
-};
-
-template <typename R, typename A1>
-struct FunctionTraits<R(A1)> {
- typedef R ReturnType;
- typedef A1 A1Type;
-};
-
-template <typename R, typename A1, typename A2>
-struct FunctionTraits<R(A1, A2)> {
- typedef R ReturnType;
- typedef A1 A1Type;
- typedef A2 A2Type;
-};
-
-template <typename R, typename A1, typename A2, typename A3>
-struct FunctionTraits<R(A1, A2, A3)> {
- typedef R ReturnType;
- typedef A1 A1Type;
- typedef A2 A2Type;
- typedef A3 A3Type;
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-struct FunctionTraits<R(A1, A2, A3, A4)> {
- typedef R ReturnType;
- typedef A1 A1Type;
- typedef A2 A2Type;
- typedef A3 A3Type;
- typedef A4 A4Type;
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-struct FunctionTraits<R(A1, A2, A3, A4, A5)> {
- typedef R ReturnType;
- typedef A1 A1Type;
- typedef A2 A2Type;
- typedef A3 A3Type;
- typedef A4 A4Type;
- typedef A5 A5Type;
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-struct FunctionTraits<R(A1, A2, A3, A4, A5, A6)> {
- typedef R ReturnType;
- typedef A1 A1Type;
- typedef A2 A2Type;
- typedef A3 A3Type;
- typedef A4 A4Type;
- typedef A5 A5Type;
- typedef A6 A6Type;
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-struct FunctionTraits<R(A1, A2, A3, A4, A5, A6, A7)> {
- typedef R ReturnType;
- typedef A1 A1Type;
- typedef A2 A2Type;
- typedef A3 A3Type;
- typedef A4 A4Type;
- typedef A5 A5Type;
- typedef A6 A6Type;
- typedef A7 A7Type;
+ R (T::*method_)(Args...) const;
};
@@ -729,47 +207,9 @@ struct FunctionTraits<R(A1, A2, A3, A4, A5, A6, A7)> {
template <typename Sig>
struct ForceVoidReturn;
-template <typename R>
-struct ForceVoidReturn<R()> {
- typedef void(RunType)();
-};
-
-template <typename R, typename A1>
-struct ForceVoidReturn<R(A1)> {
- typedef void(RunType)(A1);
-};
-
-template <typename R, typename A1, typename A2>
-struct ForceVoidReturn<R(A1, A2)> {
- typedef void(RunType)(A1, A2);
-};
-
-template <typename R, typename A1, typename A2, typename A3>
-struct ForceVoidReturn<R(A1, A2, A3)> {
- typedef void(RunType)(A1, A2, A3);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-struct ForceVoidReturn<R(A1, A2, A3, A4)> {
- typedef void(RunType)(A1, A2, A3, A4);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-struct ForceVoidReturn<R(A1, A2, A3, A4, A5)> {
- typedef void(RunType)(A1, A2, A3, A4, A5);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-struct ForceVoidReturn<R(A1, A2, A3, A4, A5, A6)> {
- typedef void(RunType)(A1, A2, A3, A4, A5, A6);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-struct ForceVoidReturn<R(A1, A2, A3, A4, A5, A6, A7)> {
- typedef void(RunType)(A1, A2, A3, A4, A5, A6, A7);
+template <typename R, typename... Args>
+struct ForceVoidReturn<R(Args...)> {
+ typedef void(RunType)(Args...);
};
@@ -783,14 +223,14 @@ struct FunctorTraits {
};
template <typename T>
-struct FunctorTraits<IgnoreResultHelper<T> > {
+struct FunctorTraits<IgnoreResultHelper<T>> {
typedef typename FunctorTraits<T>::RunnableType RunnableType;
typedef typename ForceVoidReturn<
typename RunnableType::RunType>::RunType RunType;
};
template <typename T>
-struct FunctorTraits<Callback<T> > {
+struct FunctorTraits<Callback<T>> {
typedef Callback<T> RunnableType;
typedef typename Callback<T>::RunType RunType;
};
@@ -812,7 +252,7 @@ MakeRunnable(const IgnoreResultHelper<T>& t) {
}
template <typename T>
-const typename FunctorTraits<Callback<T> >::RunnableType&
+const typename FunctorTraits<Callback<T>>::RunnableType&
MakeRunnable(const Callback<T>& t) {
DCHECK(!t.is_null());
return t;
@@ -840,246 +280,27 @@ template <bool IsWeakCall, typename ReturnType, typename Runnable,
typename ArgsType>
struct InvokeHelper;
-template <typename ReturnType, typename Runnable>
-struct InvokeHelper<false, ReturnType, Runnable,
- void()> {
- static ReturnType MakeItSo(Runnable runnable) {
- return runnable.Run();
- }
-};
-
-template <typename Runnable>
-struct InvokeHelper<false, void, Runnable,
- void()> {
- static void MakeItSo(Runnable runnable) {
- runnable.Run();
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1) {
- return runnable.Run(CallbackForward(a1));
- }
-};
-
-template <typename Runnable,typename A1>
-struct InvokeHelper<false, void, Runnable,
- void(A1)> {
- static void MakeItSo(Runnable runnable, A1 a1) {
- runnable.Run(CallbackForward(a1));
- }
-};
-
-template <typename Runnable, typename BoundWeakPtr>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get());
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1, typename A2>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1, A2)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2) {
- return runnable.Run(CallbackForward(a1), CallbackForward(a2));
- }
-};
-
-template <typename Runnable,typename A1, typename A2>
-struct InvokeHelper<false, void, Runnable,
- void(A1, A2)> {
- static void MakeItSo(Runnable runnable, A1 a1, A2 a2) {
- runnable.Run(CallbackForward(a1), CallbackForward(a2));
- }
-};
-
-template <typename Runnable, typename BoundWeakPtr, typename A2>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr, A2)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get(), CallbackForward(a2));
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1, typename A2,
- typename A3>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1, A2, A3)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) {
- return runnable.Run(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3));
- }
-};
-
-template <typename Runnable,typename A1, typename A2, typename A3>
-struct InvokeHelper<false, void, Runnable,
- void(A1, A2, A3)> {
- static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) {
- runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3));
- }
-};
-
-template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr, A2, A3)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3));
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1, typename A2,
- typename A3, typename A4>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1, A2, A3, A4)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) {
- return runnable.Run(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4));
- }
-};
-
-template <typename Runnable,typename A1, typename A2, typename A3, typename A4>
-struct InvokeHelper<false, void, Runnable,
- void(A1, A2, A3, A4)> {
- static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) {
- runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4));
- }
-};
-
-template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3,
- typename A4>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr, A2, A3, A4)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3,
- A4 a4) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4));
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1, typename A2,
- typename A3, typename A4, typename A5>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1, A2, A3, A4, A5)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4,
- A5 a5) {
- return runnable.Run(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5));
+template <typename ReturnType, typename Runnable, typename... Args>
+struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> {
+ static ReturnType MakeItSo(Runnable runnable, Args... args) {
+ return runnable.Run(CallbackForward(args)...);
}
};
-template <typename Runnable,typename A1, typename A2, typename A3, typename A4,
- typename A5>
-struct InvokeHelper<false, void, Runnable,
- void(A1, A2, A3, A4, A5)> {
- static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
- runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4), CallbackForward(a5));
+template <typename Runnable, typename... Args>
+struct InvokeHelper<false, void, Runnable, TypeList<Args...>> {
+ static void MakeItSo(Runnable runnable, Args... args) {
+ runnable.Run(CallbackForward(args)...);
}
};
-template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3,
- typename A4, typename A5>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr, A2, A3, A4, A5)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3,
- A4 a4, A5 a5) {
+template <typename Runnable, typename BoundWeakPtr, typename... Args>
+struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> {
+ static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) {
if (!weak_ptr.get()) {
return;
}
- runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4), CallbackForward(a5));
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1, typename A2,
- typename A3, typename A4, typename A5, typename A6>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1, A2, A3, A4, A5, A6)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4,
- A5 a5, A6 a6) {
- return runnable.Run(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6));
- }
-};
-
-template <typename Runnable,typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-struct InvokeHelper<false, void, Runnable,
- void(A1, A2, A3, A4, A5, A6)> {
- static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5,
- A6 a6) {
- runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4), CallbackForward(a5), CallbackForward(a6));
- }
-};
-
-template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3,
- typename A4, typename A5, typename A6>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr, A2, A3, A4, A5, A6)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3,
- A4 a4, A5 a5, A6 a6) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4), CallbackForward(a5), CallbackForward(a6));
- }
-};
-
-template <typename ReturnType, typename Runnable,typename A1, typename A2,
- typename A3, typename A4, typename A5, typename A6, typename A7>
-struct InvokeHelper<false, ReturnType, Runnable,
- void(A1, A2, A3, A4, A5, A6, A7)> {
- static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4,
- A5 a5, A6 a6, A7 a7) {
- return runnable.Run(CallbackForward(a1), CallbackForward(a2),
- CallbackForward(a3), CallbackForward(a4), CallbackForward(a5),
- CallbackForward(a6), CallbackForward(a7));
- }
-};
-
-template <typename Runnable,typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-struct InvokeHelper<false, void, Runnable,
- void(A1, A2, A3, A4, A5, A6, A7)> {
- static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5,
- A6 a6, A7 a7) {
- runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4), CallbackForward(a5), CallbackForward(a6),
- CallbackForward(a7));
- }
-};
-
-template <typename Runnable, typename BoundWeakPtr, typename A2, typename A3,
- typename A4, typename A5, typename A6, typename A7>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr, A2, A3, A4, A5, A6, A7)> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3,
- A4 a4, A5 a5, A6 a6, A7 a7) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3),
- CallbackForward(a4), CallbackForward(a5), CallbackForward(a6),
- CallbackForward(a7));
+ runnable.Run(weak_ptr.get(), CallbackForward(args)...);
}
};
@@ -1099,1419 +320,30 @@ struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
// Invoker<>
//
// See description at the top of the file.
-template <int NumBound, typename Storage, typename RunType>
+template <typename BoundIndices,
+ typename StorageType, typename Unwrappers,
+ typename InvokeHelperType, typename UnboundForwardRunType>
struct Invoker;
-// Arity 0 -> 0.
-template <typename StorageType, typename R>
-struct Invoker<0, StorageType, R()> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void()>
- ::MakeItSo(storage->runnable_);
- }
-};
-
-// Arity 1 -> 1.
-template <typename StorageType, typename R,typename X1>
-struct Invoker<0, StorageType, R(X1)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType);
-
- typedef R(UnboundRunType)(X1);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1));
- }
-};
-
-// Arity 1 -> 0.
-template <typename StorageType, typename R,typename X1>
-struct Invoker<1, StorageType, R(X1)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1));
- }
-};
-
-// Arity 2 -> 2.
-template <typename StorageType, typename R,typename X1, typename X2>
-struct Invoker<0, StorageType, R(X1, X2)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType);
-
- typedef R(UnboundRunType)(X1, X2);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2));
- }
-};
-
-// Arity 2 -> 1.
-template <typename StorageType, typename R,typename X1, typename X2>
-struct Invoker<1, StorageType, R(X1, X2)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X2>::ForwardType);
-
- typedef R(UnboundRunType)(X2);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X2>::ForwardType x2) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType x2)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2));
- }
-};
-
-// Arity 2 -> 0.
-template <typename StorageType, typename R,typename X1, typename X2>
-struct Invoker<2, StorageType, R(X1, X2)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2));
- }
-};
-
-// Arity 3 -> 3.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3>
-struct Invoker<0, StorageType, R(X1, X2, X3)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType);
-
- typedef R(UnboundRunType)(X1, X2, X3);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3));
- }
-};
-
-// Arity 3 -> 2.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3>
-struct Invoker<1, StorageType, R(X1, X2, X3)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType);
-
- typedef R(UnboundRunType)(X2, X3);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3));
- }
-};
-
-// Arity 3 -> 1.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3>
-struct Invoker<2, StorageType, R(X1, X2, X3)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X3>::ForwardType);
-
- typedef R(UnboundRunType)(X3);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X3>::ForwardType x3) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType x3)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3));
- }
-};
-
-// Arity 3 -> 0.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3>
-struct Invoker<3, StorageType, R(X1, X2, X3)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3));
- }
-};
-
-// Arity 4 -> 4.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4>
-struct Invoker<0, StorageType, R(X1, X2, X3, X4)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType);
-
- typedef R(UnboundRunType)(X1, X2, X3, X4);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4));
- }
-};
-
-// Arity 4 -> 3.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4>
-struct Invoker<1, StorageType, R(X1, X2, X3, X4)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType);
-
- typedef R(UnboundRunType)(X2, X3, X4);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4));
- }
-};
-
-// Arity 4 -> 2.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4>
-struct Invoker<2, StorageType, R(X1, X2, X3, X4)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType);
-
- typedef R(UnboundRunType)(X3, X4);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4));
- }
-};
-
-// Arity 4 -> 1.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4>
-struct Invoker<3, StorageType, R(X1, X2, X3, X4)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X4>::ForwardType);
-
- typedef R(UnboundRunType)(X4);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X4>::ForwardType x4) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType x4)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4));
- }
-};
-
-// Arity 4 -> 0.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4>
-struct Invoker<4, StorageType, R(X1, X2, X3, X4)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4));
- }
-};
-
-// Arity 5 -> 5.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5>
-struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType);
-
- typedef R(UnboundRunType)(X1, X2, X3, X4, X5);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5));
- }
-};
-
-// Arity 5 -> 4.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5>
-struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType);
-
- typedef R(UnboundRunType)(X2, X3, X4, X5);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5));
- }
-};
-
-// Arity 5 -> 3.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5>
-struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType);
-
- typedef R(UnboundRunType)(X3, X4, X5);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5));
- }
-};
-
-// Arity 5 -> 2.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5>
-struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType);
-
- typedef R(UnboundRunType)(X4, X5);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5));
- }
-};
-
-// Arity 5 -> 1.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5>
-struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X5>::ForwardType);
-
- typedef R(UnboundRunType)(X5);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X5>::ForwardType x5) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType x5)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5));
- }
-};
-
-// Arity 5 -> 0.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5>
-struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
- typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- typename Bound5UnwrapTraits::ForwardType x5 =
- Bound5UnwrapTraits::Unwrap(storage->p5_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename Bound5UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5));
- }
-};
-
-// Arity 6 -> 6.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType);
-
- typedef R(UnboundRunType)(X1, X2, X3, X4, X5, X6);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 6 -> 5.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType);
-
- typedef R(UnboundRunType)(X2, X3, X4, X5, X6);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 6 -> 4.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType);
-
- typedef R(UnboundRunType)(X3, X4, X5, X6);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 6 -> 3.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType);
-
- typedef R(UnboundRunType)(X4, X5, X6);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 6 -> 2.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType);
-
- typedef R(UnboundRunType)(X5, X6);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 6 -> 1.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X6>::ForwardType);
-
- typedef R(UnboundRunType)(X6);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X6>::ForwardType x6) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
- typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- typename Bound5UnwrapTraits::ForwardType x5 =
- Bound5UnwrapTraits::Unwrap(storage->p5_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename Bound5UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType x6)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 6 -> 0.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6>
-struct Invoker<6, StorageType, R(X1, X2, X3, X4, X5, X6)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
- typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
- typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- typename Bound5UnwrapTraits::ForwardType x5 =
- Bound5UnwrapTraits::Unwrap(storage->p5_);
- typename Bound6UnwrapTraits::ForwardType x6 =
- Bound6UnwrapTraits::Unwrap(storage->p6_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename Bound5UnwrapTraits::ForwardType,
- typename Bound6UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6));
- }
-};
-
-// Arity 7 -> 7.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X1>::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X1, X2, X3, X4, X5, X6, X7);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename CallbackParamTraits<X1>::ForwardType x1,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 6.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X2>::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X2, X3, X4, X5, X6, X7);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X2>::ForwardType x2,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 5.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X3>::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X3, X4, X5, X6, X7);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X3>::ForwardType x3,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 4.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X4>::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X4, X5, X6, X7);
-
+template <size_t... bound_indices,
+ typename StorageType,
+ typename... Unwrappers,
+ typename InvokeHelperType,
+ typename R,
+ typename... UnboundForwardArgs>
+struct Invoker<IndexSequence<bound_indices...>,
+ StorageType, TypeList<Unwrappers...>,
+ InvokeHelperType, R(UnboundForwardArgs...)> {
static R Run(BindStateBase* base,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7) {
+ UnboundForwardArgs... unbound_args) {
StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X4>::ForwardType x4,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 3.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X5>::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X5, X6, X7);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7) {
- StorageType* storage = static_cast<StorageType*>(base);
-
// Local references to make debugger stepping easier. If in a debugger,
// you really want to warp ahead and step through the
// InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X5>::ForwardType x5,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 2.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X6>::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X6, X7);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
- typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- typename Bound5UnwrapTraits::ForwardType x5 =
- Bound5UnwrapTraits::Unwrap(storage->p5_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename Bound5UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X6>::ForwardType x6,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 1.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<6, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*,
- typename CallbackParamTraits<X7>::ForwardType);
-
- typedef R(UnboundRunType)(X7);
-
- static R Run(BindStateBase* base,
- typename CallbackParamTraits<X7>::ForwardType x7) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
- typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
- typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- typename Bound5UnwrapTraits::ForwardType x5 =
- Bound5UnwrapTraits::Unwrap(storage->p5_);
- typename Bound6UnwrapTraits::ForwardType x6 =
- Bound6UnwrapTraits::Unwrap(storage->p6_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename Bound5UnwrapTraits::ForwardType,
- typename Bound6UnwrapTraits::ForwardType,
- typename CallbackParamTraits<X7>::ForwardType x7)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
- }
-};
-
-// Arity 7 -> 0.
-template <typename StorageType, typename R,typename X1, typename X2,
- typename X3, typename X4, typename X5, typename X6, typename X7>
-struct Invoker<7, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
- typedef R(RunType)(BindStateBase*);
-
- typedef R(UnboundRunType)();
-
- static R Run(BindStateBase* base) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
- typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits;
- typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits;
- typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits;
- typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits;
- typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits;
- typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits;
- typedef typename StorageType::Bound7UnwrapTraits Bound7UnwrapTraits;
-
- typename Bound1UnwrapTraits::ForwardType x1 =
- Bound1UnwrapTraits::Unwrap(storage->p1_);
- typename Bound2UnwrapTraits::ForwardType x2 =
- Bound2UnwrapTraits::Unwrap(storage->p2_);
- typename Bound3UnwrapTraits::ForwardType x3 =
- Bound3UnwrapTraits::Unwrap(storage->p3_);
- typename Bound4UnwrapTraits::ForwardType x4 =
- Bound4UnwrapTraits::Unwrap(storage->p4_);
- typename Bound5UnwrapTraits::ForwardType x5 =
- Bound5UnwrapTraits::Unwrap(storage->p5_);
- typename Bound6UnwrapTraits::ForwardType x6 =
- Bound6UnwrapTraits::Unwrap(storage->p6_);
- typename Bound7UnwrapTraits::ForwardType x7 =
- Bound7UnwrapTraits::Unwrap(storage->p7_);
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(typename Bound1UnwrapTraits::ForwardType,
- typename Bound2UnwrapTraits::ForwardType,
- typename Bound3UnwrapTraits::ForwardType,
- typename Bound4UnwrapTraits::ForwardType,
- typename Bound5UnwrapTraits::ForwardType,
- typename Bound6UnwrapTraits::ForwardType,
- typename Bound7UnwrapTraits::ForwardType)>
- ::MakeItSo(storage->runnable_, CallbackForward(x1),
- CallbackForward(x2), CallbackForward(x3),
- CallbackForward(x4), CallbackForward(x5),
- CallbackForward(x6), CallbackForward(x7));
+ return InvokeHelperType::MakeItSo(
+ storage->runnable_,
+ Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
+ CallbackForward(unbound_args)...);
}
};
@@ -2528,259 +360,60 @@ struct Invoker<7, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> {
//
// BoundArgsType contains the storage type for all the bound arguments by
// (ab)using a function type.
-template <typename Runnable, typename RunType, typename BoundArgsType>
+template <typename Runnable, typename RunType, typename BoundArgList>
struct BindState;
-template <typename Runnable, typename RunType>
-struct BindState<Runnable, RunType, void()> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef false_type IsWeakCall;
- typedef Invoker<0, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
- explicit BindState(const Runnable& runnable)
- : runnable_(runnable) {
- }
-
- virtual ~BindState() { }
-
- RunnableType runnable_;
-};
-
-template <typename Runnable, typename RunType, typename P1>
-struct BindState<Runnable, RunType, void(P1)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<1, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
-
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
-
- BindState(const Runnable& runnable, const P1& p1)
- : runnable_(runnable),
- p1_(p1) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
- }
-
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
-
- RunnableType runnable_;
- P1 p1_;
-};
-
-template <typename Runnable, typename RunType, typename P1, typename P2>
-struct BindState<Runnable, RunType, void(P1, P2)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<2, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
-
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
- typedef UnwrapTraits<P2> Bound2UnwrapTraits;
-
- BindState(const Runnable& runnable, const P1& p1, const P2& p2)
- : runnable_(runnable),
- p1_(p1),
- p2_(p2) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
- }
-
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
-
- RunnableType runnable_;
- P1 p1_;
- P2 p2_;
-};
-
-template <typename Runnable, typename RunType, typename P1, typename P2,
- typename P3>
-struct BindState<Runnable, RunType, void(P1, P2, P3)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<3, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
-
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
- typedef UnwrapTraits<P2> Bound2UnwrapTraits;
- typedef UnwrapTraits<P3> Bound3UnwrapTraits;
-
- BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3)
- : runnable_(runnable),
- p1_(p1),
- p2_(p2),
- p3_(p3) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
- }
-
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
-
- RunnableType runnable_;
- P1 p1_;
- P2 p2_;
- P3 p3_;
-};
-
-template <typename Runnable, typename RunType, typename P1, typename P2,
- typename P3, typename P4>
-struct BindState<Runnable, RunType, void(P1, P2, P3,
- P4)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<4, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
-
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
- typedef UnwrapTraits<P2> Bound2UnwrapTraits;
- typedef UnwrapTraits<P3> Bound3UnwrapTraits;
- typedef UnwrapTraits<P4> Bound4UnwrapTraits;
-
- BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
- const P4& p4)
- : runnable_(runnable),
- p1_(p1),
- p2_(p2),
- p3_(p3),
- p4_(p4) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
- }
-
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
-
- RunnableType runnable_;
- P1 p1_;
- P2 p2_;
- P3 p3_;
- P4 p4_;
-};
-
-template <typename Runnable, typename RunType, typename P1, typename P2,
- typename P3, typename P4, typename P5>
-struct BindState<Runnable, RunType, void(P1, P2, P3, P4,
- P5)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<5, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
-
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
- typedef UnwrapTraits<P2> Bound2UnwrapTraits;
- typedef UnwrapTraits<P3> Bound3UnwrapTraits;
- typedef UnwrapTraits<P4> Bound4UnwrapTraits;
- typedef UnwrapTraits<P5> Bound5UnwrapTraits;
-
- BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
- const P4& p4, const P5& p5)
- : runnable_(runnable),
- p1_(p1),
- p2_(p2),
- p3_(p3),
- p4_(p4),
- p5_(p5) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
- }
+template <typename Runnable,
+ typename R,
+ typename... Args,
+ typename... BoundArgs>
+struct BindState<Runnable, R(Args...), TypeList<BoundArgs...>> final
+ : public BindStateBase {
+ private:
+ using StorageType = BindState<Runnable, R(Args...), TypeList<BoundArgs...>>;
+ using RunnableType = Runnable;
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
+ // true_type if Runnable is a method invocation and the first bound argument
+ // is a WeakPtr.
+ using IsWeakCall =
+ IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
- RunnableType runnable_;
- P1 p1_;
- P2 p2_;
- P3 p3_;
- P4 p4_;
- P5 p5_;
-};
+ using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
+ using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
+ using UnboundForwardArgs = DropTypeListItem<
+ sizeof...(BoundArgs),
+ TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
+ using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
-template <typename Runnable, typename RunType, typename P1, typename P2,
- typename P3, typename P4, typename P5, typename P6>
-struct BindState<Runnable, RunType, void(P1, P2, P3, P4, P5,
- P6)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<6, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
+ using InvokeHelperArgs = ConcatTypeLists<
+ TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>,
+ UnboundForwardArgs>;
+ using InvokeHelperType =
+ InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>;
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
- typedef UnwrapTraits<P2> Bound2UnwrapTraits;
- typedef UnwrapTraits<P3> Bound3UnwrapTraits;
- typedef UnwrapTraits<P4> Bound4UnwrapTraits;
- typedef UnwrapTraits<P5> Bound5UnwrapTraits;
- typedef UnwrapTraits<P6> Bound6UnwrapTraits;
+ using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
- BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
- const P4& p4, const P5& p5, const P6& p6)
- : runnable_(runnable),
- p1_(p1),
- p2_(p2),
- p3_(p3),
- p4_(p4),
- p5_(p5),
- p6_(p6) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
- }
+ public:
+ using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
+ InvokeHelperType, UnboundForwardRunType>;
+ using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
+ BindState(const Runnable& runnable, const BoundArgs&... bound_args)
+ : BindStateBase(&Destroy),
+ runnable_(runnable),
+ ref_(bound_args...),
+ bound_args_(bound_args...) {}
RunnableType runnable_;
- P1 p1_;
- P2 p2_;
- P3 p3_;
- P4 p4_;
- P5 p5_;
- P6 p6_;
-};
-
-template <typename Runnable, typename RunType, typename P1, typename P2,
- typename P3, typename P4, typename P5, typename P6, typename P7>
-struct BindState<Runnable, RunType, void(P1, P2, P3, P4, P5, P6,
- P7)> : public BindStateBase {
- typedef Runnable RunnableType;
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
- typedef Invoker<7, BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
+ MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
+ Tuple<BoundArgs...> bound_args_;
- // Convenience typedefs for bound argument types.
- typedef UnwrapTraits<P1> Bound1UnwrapTraits;
- typedef UnwrapTraits<P2> Bound2UnwrapTraits;
- typedef UnwrapTraits<P3> Bound3UnwrapTraits;
- typedef UnwrapTraits<P4> Bound4UnwrapTraits;
- typedef UnwrapTraits<P5> Bound5UnwrapTraits;
- typedef UnwrapTraits<P6> Bound6UnwrapTraits;
- typedef UnwrapTraits<P7> Bound7UnwrapTraits;
+ private:
+ ~BindState() {}
- BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3,
- const P4& p4, const P5& p5, const P6& p6, const P7& p7)
- : runnable_(runnable),
- p1_(p1),
- p2_(p2),
- p3_(p3),
- p4_(p4),
- p5_(p5),
- p6_(p6),
- p7_(p7) {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
+ static void Destroy(BindStateBase* self) {
+ delete static_cast<BindState*>(self);
}
-
- virtual ~BindState() { MaybeRefcount<HasIsMethodTag<Runnable>::value,
- P1>::Release(p1_); }
-
- RunnableType runnable_;
- P1 p1_;
- P2 p2_;
- P3 p3_;
- P4 p4_;
- P5 p5_;
- P6 p6_;
- P7 p7_;
};
} // namespace internal
diff --git a/chromium/base/bind_internal.h.pump b/chromium/base/bind_internal.h.pump
deleted file mode 100644
index f632b99e556..00000000000
--- a/chromium/base/bind_internal.h.pump
+++ /dev/null
@@ -1,500 +0,0 @@
-$$ This is a pump file for generating file templates. Pump is a python
-$$ script that is part of the Google Test suite of utilities. Description
-$$ can be found here:
-$$
-$$ http://code.google.com/p/googletest/wiki/PumpManual
-$$
-
-$$ See comment for MAX_ARITY in base/bind.h.pump.
-$var MAX_ARITY = 7
-$range ARITY 0..MAX_ARITY
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_BIND_INTERNAL_H_
-#define BASE_BIND_INTERNAL_H_
-
-#include "base/bind_helpers.h"
-#include "base/callback_internal.h"
-#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
-#include "base/memory/weak_ptr.h"
-#include "base/template_util.h"
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include "base/bind_internal_win.h"
-#endif
-
-namespace base {
-namespace internal {
-
-// See base/callback.h for user documentation.
-//
-//
-// CONCEPTS:
-// Runnable -- A type (really a type class) that has a single Run() method
-// and a RunType typedef that corresponds to the type of Run().
-// A Runnable can declare that it should treated like a method
-// call by including a typedef named IsMethod. The value of
-// this typedef is NOT inspected, only the existence. When a
-// Runnable declares itself a method, Bind() will enforce special
-// refcounting + WeakPtr handling semantics for the first
-// parameter which is expected to be an object.
-// Functor -- A copyable type representing something that should be called.
-// All function pointers, Callback<>, and Runnables are functors
-// even if the invocation syntax differs.
-// RunType -- A function type (as opposed to function _pointer_ type) for
-// a Run() function. Usually just a convenience typedef.
-// (Bound)ArgsType -- A function type that is being (ab)used to store the
-// types of set of arguments. The "return" type is always
-// void here. We use this hack so that we do not need
-// a new type name for each arity of type. (eg.,
-// BindState1, BindState2). This makes forward
-// declarations and friending much much easier.
-//
-// Types:
-// RunnableAdapter<> -- Wraps the various "function" pointer types into an
-// object that adheres to the Runnable interface.
-// There are |3*ARITY| RunnableAdapter types.
-// FunctionTraits<> -- Type traits that unwrap a function signature into a
-// a set of easier to use typedefs. Used mainly for
-// compile time asserts.
-// There are |ARITY| FunctionTraits types.
-// ForceVoidReturn<> -- Helper class for translating function signatures to
-// equivalent forms with a "void" return type.
-// There are |ARITY| ForceVoidReturn types.
-// FunctorTraits<> -- Type traits used determine the correct RunType and
-// RunnableType for a Functor. This is where function
-// signature adapters are applied.
-// There are |ARITY| ForceVoidReturn types.
-// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
-// type class that represents the underlying Functor.
-// There are |O(1)| MakeRunnable types.
-// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
-// Handle the differing syntaxes needed for WeakPtr<> support,
-// and for ignoring return values. This is separate from
-// Invoker to avoid creating multiple version of Invoker<>
-// which grows at O(n^2) with the arity.
-// There are |k*ARITY| InvokeHelper types.
-// Invoker<> -- Unwraps the curried parameters and executes the Runnable.
-// There are |(ARITY^2 + ARITY)/2| Invoketypes.
-// BindState<> -- Stores the curried parameters, and is the main entry point
-// into the Bind() system, doing most of the type resolution.
-// There are ARITY BindState types.
-
-// RunnableAdapter<>
-//
-// The RunnableAdapter<> templates provide a uniform interface for invoking
-// a function pointer, method pointer, or const method pointer. The adapter
-// exposes a Run() method with an appropriate signature. Using this wrapper
-// allows for writing code that supports all three pointer types without
-// undue repetition. Without it, a lot of code would need to be repeated 3
-// times.
-//
-// For method pointers and const method pointers the first argument to Run()
-// is considered to be the received of the method. This is similar to STL's
-// mem_fun().
-//
-// This class also exposes a RunType typedef that is the function type of the
-// Run() function.
-//
-// If and only if the wrapper contains a method or const method pointer, an
-// IsMethod typedef is exposed. The existence of this typedef (NOT the value)
-// marks that the wrapper should be considered a method wrapper.
-
-template <typename Functor>
-class RunnableAdapter;
-
-$for ARITY [[
-$range ARG 1..ARITY
-
-// Function: Arity $(ARITY).
-template <typename R[[]]
-$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
-class RunnableAdapter<R(*)($for ARG , [[A$(ARG)]])> {
- public:
- typedef R (RunType)($for ARG , [[A$(ARG)]]);
-
- explicit RunnableAdapter(R(*function)($for ARG , [[A$(ARG)]]))
- : function_(function) {
- }
-
- R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
- return function_($for ARG , [[CallbackForward(a$(ARG))]]);
- }
-
- private:
- R (*function_)($for ARG , [[A$(ARG)]]);
-};
-
-// Method: Arity $(ARITY).
-template <typename R, typename T[[]]
-$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
-class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]])> {
- public:
- typedef R (RunType)(T*[[]]
-$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]))
- : method_(method) {
- }
-
- R Run(T* object[[]]
-$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
- return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]);
- }
-
- private:
- R (T::*method_)($for ARG , [[A$(ARG)]]);
-};
-
-// Const Method: Arity $(ARITY).
-template <typename R, typename T[[]]
-$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
-class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]]) const> {
- public:
- typedef R (RunType)(const T*[[]]
-$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]);
- typedef true_type IsMethod;
-
- explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]) const)
- : method_(method) {
- }
-
- R Run(const T* object[[]]
-$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
- return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]);
- }
-
- private:
- R (T::*method_)($for ARG , [[A$(ARG)]]) const;
-};
-
-]] $$ for ARITY
-
-
-// FunctionTraits<>
-//
-// Breaks a function signature apart into typedefs for easier introspection.
-template <typename Sig>
-struct FunctionTraits;
-
-$for ARITY [[
-$range ARG 1..ARITY
-
-template <typename R[[]]
-$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
-struct FunctionTraits<R($for ARG , [[A$(ARG)]])> {
- typedef R ReturnType;
-$for ARG [[
-
- typedef A$(ARG) A$(ARG)Type;
-]]
-
-};
-
-]]
-
-
-// ForceVoidReturn<>
-//
-// Set of templates that support forcing the function return type to void.
-template <typename Sig>
-struct ForceVoidReturn;
-
-$for ARITY [[
-$range ARG 1..ARITY
-
-template <typename R[[]]
-$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]>
-struct ForceVoidReturn<R($for ARG , [[A$(ARG)]])> {
- typedef void(RunType)($for ARG , [[A$(ARG)]]);
-};
-
-]] $$ for ARITY
-
-
-// FunctorTraits<>
-//
-// See description at top of file.
-template <typename T>
-struct FunctorTraits {
- typedef RunnableAdapter<T> RunnableType;
- typedef typename RunnableType::RunType RunType;
-};
-
-template <typename T>
-struct FunctorTraits<IgnoreResultHelper<T> > {
- typedef typename FunctorTraits<T>::RunnableType RunnableType;
- typedef typename ForceVoidReturn<
- typename RunnableType::RunType>::RunType RunType;
-};
-
-template <typename T>
-struct FunctorTraits<Callback<T> > {
- typedef Callback<T> RunnableType;
- typedef typename Callback<T>::RunType RunType;
-};
-
-
-// MakeRunnable<>
-//
-// Converts a passed in functor to a RunnableType using type inference.
-
-template <typename T>
-typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
- return RunnableAdapter<T>(t);
-}
-
-template <typename T>
-typename FunctorTraits<T>::RunnableType
-MakeRunnable(const IgnoreResultHelper<T>& t) {
- return MakeRunnable(t.functor_);
-}
-
-template <typename T>
-const typename FunctorTraits<Callback<T> >::RunnableType&
-MakeRunnable(const Callback<T>& t) {
- DCHECK(!t.is_null());
- return t;
-}
-
-
-// InvokeHelper<>
-//
-// There are 3 logical InvokeHelper<> specializations: normal, void-return,
-// WeakCalls.
-//
-// The normal type just calls the underlying runnable.
-//
-// We need a InvokeHelper to handle void return types in order to support
-// IgnoreResult(). Normally, if the Runnable's RunType had a void return,
-// the template system would just accept "return functor.Run()" ignoring
-// the fact that a void function is being used with return. This piece of
-// sugar breaks though when the Runnable's RunType is not void. Thus, we
-// need a partial specialization to change the syntax to drop the "return"
-// from the invocation call.
-//
-// WeakCalls similarly need special syntax that is applied to the first
-// argument to check if they should no-op themselves.
-template <bool IsWeakCall, typename ReturnType, typename Runnable,
- typename ArgsType>
-struct InvokeHelper;
-
-$for ARITY [[
-$range ARG 1..ARITY
-$range WEAKCALL_ARG 2..ARITY
-
-template <typename ReturnType, typename Runnable[[]]
-$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]>
-struct InvokeHelper<false, ReturnType, Runnable,
- void($for ARG , [[A$(ARG)]])> {
- static ReturnType MakeItSo(Runnable runnable[[]]
-$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
- return runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]);
- }
-};
-
-template <typename Runnable[[]]
-$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]>
-struct InvokeHelper<false, void, Runnable,
- void($for ARG , [[A$(ARG)]])> {
- static void MakeItSo(Runnable runnable[[]]
-$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) {
- runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]);
- }
-};
-
-$if ARITY > 0 [[
-
-template <typename Runnable[[]], typename BoundWeakPtr
-$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[typename A$(WEAKCALL_ARG)]]>
-struct InvokeHelper<true, void, Runnable,
- void(BoundWeakPtr
-$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[A$(WEAKCALL_ARG)]])> {
- static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr
-$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[A$(WEAKCALL_ARG) a$(WEAKCALL_ARG)]]) {
- if (!weak_ptr.get()) {
- return;
- }
- runnable.Run(weak_ptr.get()
-$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[CallbackForward(a$(WEAKCALL_ARG))]]);
- }
-};
-
-]]
-
-]] $$ for ARITY
-
-#if !defined(_MSC_VER)
-
-template <typename ReturnType, typename Runnable, typename ArgsType>
-struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
- // WeakCalls are only supported for functions with a void return type.
- // Otherwise, the function result would be undefined if the the WeakPtr<>
- // is invalidated.
- COMPILE_ASSERT(is_void<ReturnType>::value,
- weak_ptrs_can_only_bind_to_methods_without_return_values);
-};
-
-#endif
-
-// Invoker<>
-//
-// See description at the top of the file.
-template <int NumBound, typename Storage, typename RunType>
-struct Invoker;
-
-$for ARITY [[
-
-$$ Number of bound arguments.
-$range BOUND 0..ARITY
-$for BOUND [[
-
-$var UNBOUND = ARITY - BOUND
-$range ARG 1..ARITY
-$range BOUND_ARG 1..BOUND
-$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY
-
-// Arity $(ARITY) -> $(UNBOUND).
-template <typename StorageType, typename R[[]]
-$if ARITY > 0 [[,]][[]]
-$for ARG , [[typename X$(ARG)]]>
-struct Invoker<$(BOUND), StorageType, R($for ARG , [[X$(ARG)]])> {
- typedef R(RunType)(BindStateBase*[[]]
-$if UNBOUND != 0 [[, ]]
-$for UNBOUND_ARG , [[typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType]]);
-
- typedef R(UnboundRunType)($for UNBOUND_ARG , [[X$(UNBOUND_ARG)]]);
-
- static R Run(BindStateBase* base[[]]
-$if UNBOUND != 0 [[, ]][[]]
-$for UNBOUND_ARG , [[
-typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)
-]][[]]
-) {
- StorageType* storage = static_cast<StorageType*>(base);
-
- // Local references to make debugger stepping easier. If in a debugger,
- // you really want to warp ahead and step through the
- // InvokeHelper<>::MakeItSo() call below.
-$for BOUND_ARG
-[[
-
- typedef typename StorageType::Bound$(BOUND_ARG)UnwrapTraits Bound$(BOUND_ARG)UnwrapTraits;
-]]
-
-
-$for BOUND_ARG
-[[
-
- typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType x$(BOUND_ARG) =
- Bound$(BOUND_ARG)UnwrapTraits::Unwrap(storage->p$(BOUND_ARG)_);
-]]
-
- return InvokeHelper<StorageType::IsWeakCall::value, R,
- typename StorageType::RunnableType,
- void(
-$for BOUND_ARG , [[
-typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType
-]]
-
-$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]]
-
-$for UNBOUND_ARG , [[
-typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)
-]]
-)>
- ::MakeItSo(storage->runnable_
-$if ARITY > 0[[, ]] $for ARG , [[CallbackForward(x$(ARG))]]);
- }
-};
-
-]] $$ for BOUND
-]] $$ for ARITY
-
-
-// BindState<>
-//
-// This stores all the state passed into Bind() and is also where most
-// of the template resolution magic occurs.
-//
-// Runnable is the functor we are binding arguments to.
-// RunType is type of the Run() function that the Invoker<> should use.
-// Normally, this is the same as the RunType of the Runnable, but it can
-// be different if an adapter like IgnoreResult() has been used.
-//
-// BoundArgsType contains the storage type for all the bound arguments by
-// (ab)using a function type.
-template <typename Runnable, typename RunType, typename BoundArgsType>
-struct BindState;
-
-$for ARITY [[
-$range ARG 1..ARITY
-
-template <typename Runnable, typename RunType[[]]
-$if ARITY > 0[[, ]] $for ARG , [[typename P$(ARG)]]>
-struct BindState<Runnable, RunType, void($for ARG , [[P$(ARG)]])> : public BindStateBase {
- typedef Runnable RunnableType;
-
-$if ARITY > 0 [[
- typedef IsWeakMethod<HasIsMethodTag<Runnable>::value, P1> IsWeakCall;
-]] $else [[
- typedef false_type IsWeakCall;
-]]
-
- typedef Invoker<$(ARITY), BindState, RunType> InvokerType;
- typedef typename InvokerType::UnboundRunType UnboundRunType;
-
-$if ARITY > 0 [[
-
- // Convenience typedefs for bound argument types.
-
-$for ARG [[
- typedef UnwrapTraits<P$(ARG)> Bound$(ARG)UnwrapTraits;
-
-]] $$ for ARG
-
-
-]] $$ if ARITY > 0
-
-$$ The extra [[ ]] is needed to massage spacing. Silly pump.py.
-[[ ]]$if ARITY == 0 [[explicit ]]BindState(const Runnable& runnable
-$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]])
- : runnable_(runnable)[[]]
-$if ARITY == 0 [[
- {
-
-]] $else [[
-, $for ARG , [[
-
- p$(ARG)_(p$(ARG))
-]] {
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_);
-
-]]
- }
-
- virtual ~BindState() {
-$if ARITY > 0 [[
- MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::Release(p1_);
-]]
- }
-
- RunnableType runnable_;
-
-$for ARG [[
- P$(ARG) p$(ARG)_;
-
-]]
-};
-
-]] $$ for ARITY
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_BIND_INTERNAL_H_
diff --git a/chromium/base/bind_unittest.cc b/chromium/base/bind_unittest.cc
index a30b7756704..f885403c92d 100644
--- a/chromium/base/bind_unittest.cc
+++ b/chromium/base/bind_unittest.cc
@@ -778,10 +778,10 @@ TEST_F(BindTest, ArgumentCopies) {
copies = 0;
assigns = 0;
- DerivedCopyCounter dervied(&copies, &assigns);
+ DerivedCopyCounter derived(&copies, &assigns);
Callback<void(CopyCounter)> coerce_cb =
Bind(&VoidPolymorphic1<CopyCounter>);
- coerce_cb.Run(CopyCounter(dervied));
+ coerce_cb.Run(CopyCounter(derived));
EXPECT_GE(2, copies);
EXPECT_EQ(0, assigns);
}
diff --git a/chromium/base/bind_unittest.nc b/chromium/base/bind_unittest.nc
index 4732097d776..259638673a9 100644
--- a/chromium/base/bind_unittest.nc
+++ b/chromium/base/bind_unittest.nc
@@ -167,7 +167,7 @@ void WontCompile() {
method_bound_to_array_cb.Run();
}
-#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed \"p1_is_refcounted_type_and_needs_scoped_refptr\""]
+#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed \"a_parameter_is_refcounted_type_and_needs_scoped_refptr\""]
// Refcounted types should not be bound as a raw pointer.
void WontCompile() {
@@ -190,7 +190,7 @@ void WontCompile() {
weak_ptr_with_non_void_return_type.Run();
}
-#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES) // [r"fatal error: no viable conversion from 'Callback<typename internal::BindState<typename internal::FunctorTraits<void \(\*\)\(int\)>::RunnableType, typename internal::FunctorTraits<void \(\*\)\(int\)>::RunType, void \(\)>::UnboundRunType>' to 'Callback<void \(\)>'"]
+#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES) // [r"fatal error: no viable conversion from 'Callback<typename internal::BindState<typename internal::FunctorTraits<void \(\*\)\(int\)>::RunnableType, typename internal::FunctorTraits<void \(\*\)\(int\)>::RunType, internal::TypeList<> >::UnboundRunType>' to 'Callback<void \(\)>'"]
// Bind result cannot be assigned to Callbacks with a mismatching type.
void WontCompile() {
diff --git a/chromium/base/build_time.h b/chromium/base/build_time.h
index c7df479b622..4f0abc38133 100644
--- a/chromium/base/build_time.h
+++ b/chromium/base/build_time.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_BUILD_TIME_
-#define BASE_BUILD_TIME_
+#ifndef BASE_BUILD_TIME_H_
+#define BASE_BUILD_TIME_H_
#include "base/base_export.h"
#include "base/time/time.h"
@@ -25,4 +25,4 @@ Time BASE_EXPORT GetBuildTime();
} // namespace base
-#endif // BASE_BUILD_TIME_
+#endif // BASE_BUILD_TIME_H_
diff --git a/chromium/base/callback.h b/chromium/base/callback.h
index 364f506139f..00669dd83d1 100644
--- a/chromium/base/callback.h
+++ b/chromium/base/callback.h
@@ -1,8 +1,3 @@
-// This file was GENERATED by command:
-// pump.py callback.h.pump
-// DO NOT EDIT BY HAND!!!
-
-
// Copyright (c) 2012 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.
@@ -367,10 +362,10 @@ template <typename Runnable, typename RunType, typename BoundArgsType>
struct BindState;
} // namespace internal
-template <typename R>
-class Callback<R(void)> : public internal::CallbackBase {
+template <typename R, typename... Args>
+class Callback<R(Args...)> : public internal::CallbackBase {
public:
- typedef R(RunType)();
+ typedef R(RunType)(Args...);
Callback() : CallbackBase(NULL) { }
@@ -380,7 +375,6 @@ class Callback<R(void)> : public internal::CallbackBase {
Callback(internal::BindState<Runnable, BindRunType,
BoundArgsType>* bind_state)
: CallbackBase(bind_state) {
-
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
@@ -394,377 +388,24 @@ class Callback<R(void)> : public internal::CallbackBase {
return CallbackBase::Equals(other);
}
- R Run() const {
+ R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
+ const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- return f(bind_state_.get());
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*);
-
-};
-
-template <typename R, typename A1>
-class Callback<R(A1)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1));
+ return f(bind_state_.get(), internal::CallbackForward(args)...);
}
private:
typedef R(*PolymorphicInvoke)(
internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType);
-
+ typename internal::CallbackParamTraits<Args>::ForwardType...);
};
-template <typename R, typename A1, typename A2>
-class Callback<R(A1, A2)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1, A2);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1),
- internal::CallbackForward(a2));
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType,
- typename internal::CallbackParamTraits<A2>::ForwardType);
-
-};
-
-template <typename R, typename A1, typename A2, typename A3>
-class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1, A2, A3);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1),
- internal::CallbackForward(a2),
- internal::CallbackForward(a3));
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType,
- typename internal::CallbackParamTraits<A2>::ForwardType,
- typename internal::CallbackParamTraits<A3>::ForwardType);
-
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1, A2, A3, A4);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1),
- internal::CallbackForward(a2),
- internal::CallbackForward(a3),
- internal::CallbackForward(a4));
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType,
- typename internal::CallbackParamTraits<A2>::ForwardType,
- typename internal::CallbackParamTraits<A3>::ForwardType,
- typename internal::CallbackParamTraits<A4>::ForwardType);
-
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1, A2, A3, A4, A5);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4,
- typename internal::CallbackParamTraits<A5>::ForwardType a5) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1),
- internal::CallbackForward(a2),
- internal::CallbackForward(a3),
- internal::CallbackForward(a4),
- internal::CallbackForward(a5));
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType,
- typename internal::CallbackParamTraits<A2>::ForwardType,
- typename internal::CallbackParamTraits<A3>::ForwardType,
- typename internal::CallbackParamTraits<A4>::ForwardType,
- typename internal::CallbackParamTraits<A5>::ForwardType);
-
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1, A2, A3, A4, A5, A6);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4,
- typename internal::CallbackParamTraits<A5>::ForwardType a5,
- typename internal::CallbackParamTraits<A6>::ForwardType a6) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1),
- internal::CallbackForward(a2),
- internal::CallbackForward(a3),
- internal::CallbackForward(a4),
- internal::CallbackForward(a5),
- internal::CallbackForward(a6));
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType,
- typename internal::CallbackParamTraits<A2>::ForwardType,
- typename internal::CallbackParamTraits<A3>::ForwardType,
- typename internal::CallbackParamTraits<A4>::ForwardType,
- typename internal::CallbackParamTraits<A5>::ForwardType,
- typename internal::CallbackParamTraits<A6>::ForwardType);
-
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
- public:
- typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4,
- typename internal::CallbackParamTraits<A5>::ForwardType a5,
- typename internal::CallbackParamTraits<A6>::ForwardType a6,
- typename internal::CallbackParamTraits<A7>::ForwardType a7) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get(), internal::CallbackForward(a1),
- internal::CallbackForward(a2),
- internal::CallbackForward(a3),
- internal::CallbackForward(a4),
- internal::CallbackForward(a5),
- internal::CallbackForward(a6),
- internal::CallbackForward(a7));
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<A1>::ForwardType,
- typename internal::CallbackParamTraits<A2>::ForwardType,
- typename internal::CallbackParamTraits<A3>::ForwardType,
- typename internal::CallbackParamTraits<A4>::ForwardType,
- typename internal::CallbackParamTraits<A5>::ForwardType,
- typename internal::CallbackParamTraits<A6>::ForwardType,
- typename internal::CallbackParamTraits<A7>::ForwardType);
-
-};
-
-
// Syntactic sugar to make Callback<void(void)> easier to declare since it
// will be used in a lot of APIs with delayed execution.
typedef Callback<void(void)> Closure;
} // namespace base
-#endif // BASE_CALLBACK_H
+#endif // BASE_CALLBACK_H_
diff --git a/chromium/base/callback.h.pump b/chromium/base/callback.h.pump
deleted file mode 100644
index 686196dae6a..00000000000
--- a/chromium/base/callback.h.pump
+++ /dev/null
@@ -1,436 +0,0 @@
-$$ This is a pump file for generating file templates. Pump is a python
-$$ script that is part of the Google Test suite of utilities. Description
-$$ can be found here:
-$$
-$$ http://code.google.com/p/googletest/wiki/PumpManual
-$$
-
-$$ See comment for MAX_ARITY in base/bind.h.pump.
-$var MAX_ARITY = 7
-
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_CALLBACK_H_
-#define BASE_CALLBACK_H_
-
-#include "base/callback_forward.h"
-#include "base/callback_internal.h"
-#include "base/template_util.h"
-
-// NOTE: Header files that do not require the full definition of Callback or
-// Closure should #include "base/callback_forward.h" instead of this file.
-
-// -----------------------------------------------------------------------------
-// Introduction
-// -----------------------------------------------------------------------------
-//
-// The templated Callback class is a generalized function object. Together
-// with the Bind() function in bind.h, they provide a type-safe method for
-// performing partial application of functions.
-//
-// Partial application (or "currying") is the process of binding a subset of
-// a function's arguments to produce another function that takes fewer
-// arguments. This can be used to pass around a unit of delayed execution,
-// much like lexical closures are used in other languages. For example, it
-// is used in Chromium code to schedule tasks on different MessageLoops.
-//
-// A callback with no unbound input parameters (base::Callback<void(void)>)
-// is called a base::Closure. Note that this is NOT the same as what other
-// languages refer to as a closure -- it does not retain a reference to its
-// enclosing environment.
-//
-// MEMORY MANAGEMENT AND PASSING
-//
-// The Callback objects themselves should be passed by const-reference, and
-// stored by copy. They internally store their state via a refcounted class
-// and thus do not need to be deleted.
-//
-// The reason to pass via a const-reference is to avoid unnecessary
-// AddRef/Release pairs to the internal state.
-//
-//
-// -----------------------------------------------------------------------------
-// Quick reference for basic stuff
-// -----------------------------------------------------------------------------
-//
-// BINDING A BARE FUNCTION
-//
-// int Return5() { return 5; }
-// base::Callback<int(void)> func_cb = base::Bind(&Return5);
-// LOG(INFO) << func_cb.Run(); // Prints 5.
-//
-// BINDING A CLASS METHOD
-//
-// The first argument to bind is the member function to call, the second is
-// the object on which to call it.
-//
-// class Ref : public base::RefCountedThreadSafe<Ref> {
-// public:
-// int Foo() { return 3; }
-// void PrintBye() { LOG(INFO) << "bye."; }
-// };
-// scoped_refptr<Ref> ref = new Ref();
-// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
-// LOG(INFO) << ref_cb.Run(); // Prints out 3.
-//
-// By default the object must support RefCounted or you will get a compiler
-// error. If you're passing between threads, be sure it's
-// RefCountedThreadSafe! See "Advanced binding of member functions" below if
-// you don't want to use reference counting.
-//
-// RUNNING A CALLBACK
-//
-// Callbacks can be run with their "Run" method, which has the same
-// signature as the template argument to the callback.
-//
-// void DoSomething(const base::Callback<void(int, std::string)>& callback) {
-// callback.Run(5, "hello");
-// }
-//
-// Callbacks can be run more than once (they don't get deleted or marked when
-// run). However, this precludes using base::Passed (see below).
-//
-// void DoSomething(const base::Callback<double(double)>& callback) {
-// double myresult = callback.Run(3.14159);
-// myresult += callback.Run(2.71828);
-// }
-//
-// PASSING UNBOUND INPUT PARAMETERS
-//
-// Unbound parameters are specified at the time a callback is Run(). They are
-// specified in the Callback template type:
-//
-// void MyFunc(int i, const std::string& str) {}
-// base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
-// cb.Run(23, "hello, world");
-//
-// PASSING BOUND INPUT PARAMETERS
-//
-// Bound parameters are specified when you create thee callback as arguments
-// to Bind(). They will be passed to the function and the Run()ner of the
-// callback doesn't see those values or even know that the function it's
-// calling.
-//
-// void MyFunc(int i, const std::string& str) {}
-// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
-// cb.Run();
-//
-// A callback with no unbound input parameters (base::Callback<void(void)>)
-// is called a base::Closure. So we could have also written:
-//
-// base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
-//
-// When calling member functions, bound parameters just go after the object
-// pointer.
-//
-// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
-//
-// PARTIAL BINDING OF PARAMETERS
-//
-// You can specify some parameters when you create the callback, and specify
-// the rest when you execute the callback.
-//
-// void MyFunc(int i, const std::string& str) {}
-// base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
-// cb.Run("hello world");
-//
-// When calling a function bound parameters are first, followed by unbound
-// parameters.
-//
-//
-// -----------------------------------------------------------------------------
-// Quick reference for advanced binding
-// -----------------------------------------------------------------------------
-//
-// BINDING A CLASS METHOD WITH WEAK POINTERS
-//
-// base::Bind(&MyClass::Foo, GetWeakPtr());
-//
-// The callback will not be run if the object has already been destroyed.
-// DANGER: weak pointers are not threadsafe, so don't use this
-// when passing between threads!
-//
-// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
-//
-// base::Bind(&MyClass::Foo, base::Unretained(this));
-//
-// This disables all lifetime management on the object. You're responsible
-// for making sure the object is alive at the time of the call. You break it,
-// you own it!
-//
-// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
-//
-// MyClass* myclass = new MyClass;
-// base::Bind(&MyClass::Foo, base::Owned(myclass));
-//
-// The object will be deleted when the callback is destroyed, even if it's
-// not run (like if you post a task during shutdown). Potentially useful for
-// "fire and forget" cases.
-//
-// IGNORING RETURN VALUES
-//
-// Sometimes you want to call a function that returns a value in a callback
-// that doesn't expect a return value.
-//
-// int DoSomething(int arg) { cout << arg << endl; }
-// base::Callback<void<int>) cb =
-// base::Bind(base::IgnoreResult(&DoSomething));
-//
-//
-// -----------------------------------------------------------------------------
-// Quick reference for binding parameters to Bind()
-// -----------------------------------------------------------------------------
-//
-// Bound parameters are specified as arguments to Bind() and are passed to the
-// function. A callback with no parameters or no unbound parameters is called a
-// Closure (base::Callback<void(void)> and base::Closure are the same thing).
-//
-// PASSING PARAMETERS OWNED BY THE CALLBACK
-//
-// void Foo(int* arg) { cout << *arg << endl; }
-// int* pn = new int(1);
-// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
-//
-// The parameter will be deleted when the callback is destroyed, even if it's
-// not run (like if you post a task during shutdown).
-//
-// PASSING PARAMETERS AS A scoped_ptr
-//
-// void TakesOwnership(scoped_ptr<Foo> arg) {}
-// scoped_ptr<Foo> f(new Foo);
-// // f becomes null during the following call.
-// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
-//
-// Ownership of the parameter will be with the callback until the it is run,
-// when ownership is passed to the callback function. This means the callback
-// can only be run once. If the callback is never run, it will delete the
-// object when it's destroyed.
-//
-// PASSING PARAMETERS AS A scoped_refptr
-//
-// void TakesOneRef(scoped_refptr<Foo> arg) {}
-// scoped_refptr<Foo> f(new Foo)
-// base::Closure cb = base::Bind(&TakesOneRef, f);
-//
-// This should "just work." The closure will take a reference as long as it
-// is alive, and another reference will be taken for the called function.
-//
-// PASSING PARAMETERS BY REFERENCE
-//
-// void foo(int arg) { cout << arg << endl }
-// int n = 1;
-// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
-// n = 2;
-// has_ref.Run(); // Prints "2"
-//
-// Normally parameters are copied in the closure. DANGER: ConstRef stores a
-// const reference instead, referencing the original parameter. This means
-// that you must ensure the object outlives the callback!
-//
-//
-// -----------------------------------------------------------------------------
-// Implementation notes
-// -----------------------------------------------------------------------------
-//
-// WHERE IS THIS DESIGN FROM:
-//
-// The design Callback and Bind is heavily influenced by C++'s
-// tr1::function/tr1::bind, and by the "Google Callback" system used inside
-// Google.
-//
-//
-// HOW THE IMPLEMENTATION WORKS:
-//
-// There are three main components to the system:
-// 1) The Callback classes.
-// 2) The Bind() functions.
-// 3) The arguments wrappers (e.g., Unretained() and ConstRef()).
-//
-// The Callback classes represent a generic function pointer. Internally,
-// it stores a refcounted piece of state that represents the target function
-// and all its bound parameters. Each Callback specialization has a templated
-// constructor that takes an BindState<>*. In the context of the constructor,
-// the static type of this BindState<> pointer uniquely identifies the
-// function it is representing, all its bound parameters, and a Run() method
-// that is capable of invoking the target.
-//
-// Callback's constructor takes the BindState<>* that has the full static type
-// and erases the target function type as well as the types of the bound
-// parameters. It does this by storing a pointer to the specific Run()
-// function, and upcasting the state of BindState<>* to a
-// BindStateBase*. This is safe as long as this BindStateBase pointer
-// is only used with the stored Run() pointer.
-//
-// To BindState<> objects are created inside the Bind() functions.
-// These functions, along with a set of internal templates, are responsible for
-//
-// - Unwrapping the function signature into return type, and parameters
-// - Determining the number of parameters that are bound
-// - Creating the BindState storing the bound parameters
-// - Performing compile-time asserts to avoid error-prone behavior
-// - Returning an Callback<> with an arity matching the number of unbound
-// parameters and that knows the correct refcounting semantics for the
-// target object if we are binding a method.
-//
-// The Bind functions do the above using type-inference, and template
-// specializations.
-//
-// By default Bind() will store copies of all bound parameters, and attempt
-// to refcount a target object if the function being bound is a class method.
-// These copies are created even if the function takes parameters as const
-// references. (Binding to non-const references is forbidden, see bind.h.)
-//
-// To change this behavior, we introduce a set of argument wrappers
-// (e.g., Unretained(), and ConstRef()). These are simple container templates
-// that are passed by value, and wrap a pointer to argument. See the
-// file-level comment in base/bind_helpers.h for more info.
-//
-// These types are passed to the Unwrap() functions, and the MaybeRefcount()
-// functions respectively to modify the behavior of Bind(). The Unwrap()
-// and MaybeRefcount() functions change behavior by doing partial
-// specialization based on whether or not a parameter is a wrapper type.
-//
-// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium.
-//
-//
-// WHY NOT TR1 FUNCTION/BIND?
-//
-// Direct use of tr1::function and tr1::bind was considered, but ultimately
-// rejected because of the number of copy constructors invocations involved
-// in the binding of arguments during construction, and the forwarding of
-// arguments during invocation. These copies will no longer be an issue in
-// C++0x because C++0x will support rvalue reference allowing for the compiler
-// to avoid these copies. However, waiting for C++0x is not an option.
-//
-// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
-// tr1::bind call itself will invoke a non-trivial copy constructor three times
-// for each bound parameter. Also, each when passing a tr1::function, each
-// bound argument will be copied again.
-//
-// In addition to the copies taken at binding and invocation, copying a
-// tr1::function causes a copy to be made of all the bound parameters and
-// state.
-//
-// Furthermore, in Chromium, it is desirable for the Callback to take a
-// reference on a target object when representing a class method call. This
-// is not supported by tr1.
-//
-// Lastly, tr1::function and tr1::bind has a more general and flexible API.
-// This includes things like argument reordering by use of
-// tr1::bind::placeholder, support for non-const reference parameters, and some
-// limited amount of subtyping of the tr1::function object (e.g.,
-// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
-//
-// These are not features that are required in Chromium. Some of them, such as
-// allowing for reference parameters, and subtyping of functions, may actually
-// become a source of errors. Removing support for these features actually
-// allows for a simpler implementation, and a terser Currying API.
-//
-//
-// WHY NOT GOOGLE CALLBACKS?
-//
-// The Google callback system also does not support refcounting. Furthermore,
-// its implementation has a number of strange edge cases with respect to type
-// conversion of its arguments. In particular, the argument's constness must
-// at times match exactly the function signature, or the type-inference might
-// break. Given the above, writing a custom solution was easier.
-//
-//
-// MISSING FUNCTIONALITY
-// - Invoking the return of Bind. Bind(&foo).Run() does not work;
-// - Binding arrays to functions that take a non-const pointer.
-// Example:
-// void Foo(const char* ptr);
-// void Bar(char* ptr);
-// Bind(&Foo, "test");
-// Bind(&Bar, "test"); // This fails because ptr is not const.
-
-namespace base {
-
-// First, we forward declare the Callback class template. This informs the
-// compiler that the template only has 1 type parameter which is the function
-// signature that the Callback is representing.
-//
-// After this, create template specializations for 0-$(MAX_ARITY) parameters. Note that
-// even though the template typelist grows, the specialization still
-// only has one type: the function signature.
-//
-// If you are thinking of forward declaring Callback in your own header file,
-// please include "base/callback_forward.h" instead.
-template <typename Sig>
-class Callback;
-
-namespace internal {
-template <typename Runnable, typename RunType, typename BoundArgsType>
-struct BindState;
-} // namespace internal
-
-
-$range ARITY 0..MAX_ARITY
-$for ARITY [[
-$range ARG 1..ARITY
-
-$if ARITY == 0 [[
-template <typename R>
-class Callback<R(void)> : public internal::CallbackBase {
-]] $else [[
-template <typename R, $for ARG , [[typename A$(ARG)]]>
-class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase {
-]]
-
- public:
- typedef R(RunType)($for ARG , [[A$(ARG)]]);
-
- Callback() : CallbackBase(NULL) { }
-
- // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
- // return the exact Callback<> type. See base/bind.h for details.
- template <typename Runnable, typename BindRunType, typename BoundArgsType>
- Callback(internal::BindState<Runnable, BindRunType,
- BoundArgsType>* bind_state)
- : CallbackBase(bind_state) {
-
- // Force the assignment to a local variable of PolymorphicInvoke
- // so the compiler will typecheck that the passed in Run() method has
- // the correct type.
- PolymorphicInvoke invoke_func =
- &internal::BindState<Runnable, BindRunType, BoundArgsType>
- ::InvokerType::Run;
- polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
- }
-
- bool Equals(const Callback& other) const {
- return CallbackBase::Equals(other);
- }
-
- R Run($for ARG ,
- [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const {
- PolymorphicInvoke f =
- reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
-
- return f(bind_state_.get()[[]]
-$if ARITY != 0 [[, ]]
-$for ARG ,
- [[internal::CallbackForward(a$(ARG))]]);
- }
-
- private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*[[]]
-$if ARITY != 0 [[, ]]
-$for ARG , [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType]]);
-
-};
-
-
-]] $$ for ARITY
-
-// Syntactic sugar to make Callback<void(void)> easier to declare since it
-// will be used in a lot of APIs with delayed execution.
-typedef Callback<void(void)> Closure;
-
-} // namespace base
-
-#endif // BASE_CALLBACK_H
diff --git a/chromium/base/callback_forward.h b/chromium/base/callback_forward.h
index 79832481af2..262c3065300 100644
--- a/chromium/base/callback_forward.h
+++ b/chromium/base/callback_forward.h
@@ -14,4 +14,4 @@ typedef Callback<void(void)> Closure;
} // namespace base
-#endif // BASE_CALLBACK_FORWARD_H
+#endif // BASE_CALLBACK_FORWARD_H_
diff --git a/chromium/base/callback_internal.cc b/chromium/base/callback_internal.cc
index ed0fb0dd0cc..2553fe7e1b6 100644
--- a/chromium/base/callback_internal.cc
+++ b/chromium/base/callback_internal.cc
@@ -9,6 +9,18 @@
namespace base {
namespace internal {
+void BindStateBase::AddRef() {
+ AtomicRefCountInc(&ref_count_);
+}
+
+void BindStateBase::Release() {
+ if (!AtomicRefCountDec(&ref_count_))
+ destructor_(this);
+}
+
+CallbackBase::CallbackBase(const CallbackBase& c) = default;
+CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
+
void CallbackBase::Reset() {
polymorphic_invoke_ = NULL;
// NULL the bind_state_ last, since it may be holding the last ref to whatever
@@ -24,7 +36,7 @@ bool CallbackBase::Equals(const CallbackBase& other) const {
CallbackBase::CallbackBase(BindStateBase* bind_state)
: bind_state_(bind_state),
polymorphic_invoke_(NULL) {
- DCHECK(!bind_state_.get() || bind_state_->HasOneRef());
+ DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
}
CallbackBase::~CallbackBase() {
diff --git a/chromium/base/callback_internal.h b/chromium/base/callback_internal.h
index b85973d3815..fefd7a2b201 100644
--- a/chromium/base/callback_internal.h
+++ b/chromium/base/callback_internal.h
@@ -10,15 +10,19 @@
#include <stddef.h>
+#include "base/atomic_ref_count.h"
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/template_util.h"
template <typename T>
class ScopedVector;
namespace base {
namespace internal {
+class CallbackBase;
// BindStateBase is used to provide an opaque handle that the Callback
// class can use to represent a function object with bound arguments. It
@@ -26,16 +30,39 @@ namespace internal {
// DoInvoke function to perform the function execution. This allows
// us to shield the Callback class from the types of the bound argument via
// "type erasure."
-class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
+// At the base level, the only task is to add reference counting data. Don't use
+// RefCountedThreadSafe since it requires the destructor to be a virtual method.
+// Creating a vtable for every BindState template instantiation results in a lot
+// of bloat. Its only task is to call the destructor which can be done with a
+// function pointer.
+class BindStateBase {
protected:
- friend class RefCountedThreadSafe<BindStateBase>;
- virtual ~BindStateBase() {}
+ explicit BindStateBase(void (*destructor)(BindStateBase*))
+ : ref_count_(0), destructor_(destructor) {}
+ ~BindStateBase() = default;
+
+ private:
+ friend class scoped_refptr<BindStateBase>;
+ friend class CallbackBase;
+
+ void AddRef();
+ void Release();
+
+ AtomicRefCount ref_count_;
+
+ // Pointer to a function that will properly destroy |this|.
+ void (*destructor_)(BindStateBase*);
+
+ DISALLOW_COPY_AND_ASSIGN(BindStateBase);
};
// Holds the Callback methods that don't require specialization to reduce
// template bloat.
class BASE_EXPORT CallbackBase {
public:
+ CallbackBase(const CallbackBase& c);
+ CallbackBase& operator=(const CallbackBase& c);
+
// Returns true if Callback is null (doesn't refer to anything).
bool is_null() const { return bind_state_.get() == NULL; }
@@ -81,6 +108,28 @@ template <typename T> struct IsMoveOnlyType {
!is_const<T>::value;
};
+// Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns
+// |Else|.
+template <bool condition, typename Then, typename Else>
+struct SelectType {
+ typedef Then Type;
+};
+
+template <typename Then, typename Else>
+struct SelectType<false, Then, Else> {
+ typedef Else Type;
+};
+
+template <typename>
+struct CallbackParamTraitsForMoveOnlyType;
+
+template <typename>
+struct CallbackParamTraitsForNonMoveOnlyType;
+
+// TODO(tzik): Use a default parameter once MSVS supports variadic templates
+// with default values.
+// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
+//
// This is a typetraits object that's used to take an argument type, and
// extract a suitable type for storing and forwarding arguments.
//
@@ -92,8 +141,15 @@ template <typename T> struct IsMoveOnlyType {
// parameters by const reference. In this case, we end up passing an actual
// array type in the initializer list which C++ does not allow. This will
// break passing of C-string literals.
-template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
-struct CallbackParamTraits {
+template <typename T>
+struct CallbackParamTraits
+ : SelectType<IsMoveOnlyType<T>::value,
+ CallbackParamTraitsForMoveOnlyType<T>,
+ CallbackParamTraitsForNonMoveOnlyType<T> >::Type {
+};
+
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType {
typedef const T& ForwardType;
typedef T StorageType;
};
@@ -104,7 +160,7 @@ struct CallbackParamTraits {
//
// The ForwardType should only be used for unbound arguments.
template <typename T>
-struct CallbackParamTraits<T&, false> {
+struct CallbackParamTraitsForNonMoveOnlyType<T&> {
typedef T& ForwardType;
typedef T StorageType;
};
@@ -115,14 +171,14 @@ struct CallbackParamTraits<T&, false> {
// T[n]" does not seem to match correctly, so we are stuck with this
// restriction.
template <typename T, size_t n>
-struct CallbackParamTraits<T[n], false> {
+struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
-struct CallbackParamTraits<T[], false> {
+struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
@@ -141,7 +197,7 @@ struct CallbackParamTraits<T[], false> {
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
-struct CallbackParamTraits<T, true> {
+struct CallbackParamTraitsForMoveOnlyType {
typedef T ForwardType;
typedef T StorageType;
};
diff --git a/chromium/base/callback_list.h b/chromium/base/callback_list.h
index 5b911fd4867..aeed5f1e221 100644
--- a/chromium/base/callback_list.h
+++ b/chromium/base/callback_list.h
@@ -1,8 +1,3 @@
-// This file was GENERATED by command:
-// pump.py callback_list.h.pump
-// DO NOT EDIT BY HAND!!!
-
-
// Copyright 2013 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.
@@ -208,192 +203,21 @@ class CallbackListBase {
template <typename Sig> class CallbackList;
-template <>
-class CallbackList<void(void)>
- : public internal::CallbackListBase<Callback<void(void)> > {
- public:
- typedef Callback<void(void)> CallbackType;
-
- CallbackList() {}
-
- void Notify() {
- internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run();
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1>
-class CallbackList<void(A1)>
- : public internal::CallbackListBase<Callback<void(A1)> > {
- public:
- typedef Callback<void(A1)> CallbackType;
-
- CallbackList() {}
-
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1) {
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1, typename A2>
-class CallbackList<void(A1, A2)>
- : public internal::CallbackListBase<Callback<void(A1, A2)> > {
- public:
- typedef Callback<void(A1, A2)> CallbackType;
-
- CallbackList() {}
-
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2) {
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1, a2);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1, typename A2, typename A3>
-class CallbackList<void(A1, A2, A3)>
- : public internal::CallbackListBase<Callback<void(A1, A2, A3)> > {
- public:
- typedef Callback<void(A1, A2, A3)> CallbackType;
-
- CallbackList() {}
-
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3) {
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1, a2, a3);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1, typename A2, typename A3, typename A4>
-class CallbackList<void(A1, A2, A3, A4)>
- : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4)> > {
- public:
- typedef Callback<void(A1, A2, A3, A4)> CallbackType;
-
- CallbackList() {}
-
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4) {
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1, a2, a3, a4);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5>
-class CallbackList<void(A1, A2, A3, A4, A5)>
- : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5)> > {
- public:
- typedef Callback<void(A1, A2, A3, A4, A5)> CallbackType;
-
- CallbackList() {}
-
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4,
- typename internal::CallbackParamTraits<A5>::ForwardType a5) {
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1, a2, a3, a4, a5);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6>
-class CallbackList<void(A1, A2, A3, A4, A5, A6)>
- : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5,
- A6)> > {
- public:
- typedef Callback<void(A1, A2, A3, A4, A5, A6)> CallbackType;
-
- CallbackList() {}
-
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4,
- typename internal::CallbackParamTraits<A5>::ForwardType a5,
- typename internal::CallbackParamTraits<A6>::ForwardType a6) {
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1, a2, a3, a4, a5, a6);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7>
-class CallbackList<void(A1, A2, A3, A4, A5, A6, A7)>
- : public internal::CallbackListBase<Callback<void(A1, A2, A3, A4, A5, A6,
- A7)> > {
+template <typename... Args>
+class CallbackList<void(Args...)>
+ : public internal::CallbackListBase<Callback<void(Args...)> > {
public:
- typedef Callback<void(A1, A2, A3, A4, A5, A6, A7)> CallbackType;
+ typedef Callback<void(Args...)> CallbackType;
CallbackList() {}
- void Notify(typename internal::CallbackParamTraits<A1>::ForwardType a1,
- typename internal::CallbackParamTraits<A2>::ForwardType a2,
- typename internal::CallbackParamTraits<A3>::ForwardType a3,
- typename internal::CallbackParamTraits<A4>::ForwardType a4,
- typename internal::CallbackParamTraits<A5>::ForwardType a5,
- typename internal::CallbackParamTraits<A6>::ForwardType a6,
- typename internal::CallbackParamTraits<A7>::ForwardType a7) {
+ void Notify(
+ typename internal::CallbackParamTraits<Args>::ForwardType... args) {
typename internal::CallbackListBase<CallbackType>::Iterator it =
this->GetIterator();
CallbackType* cb;
while ((cb = it.GetNext()) != NULL) {
- cb->Run(a1, a2, a3, a4, a5, a6, a7);
+ cb->Run(args...);
}
}
diff --git a/chromium/base/callback_list.h.pump b/chromium/base/callback_list.h.pump
deleted file mode 100644
index d7f84736c15..00000000000
--- a/chromium/base/callback_list.h.pump
+++ /dev/null
@@ -1,269 +0,0 @@
-$$ This is a pump file for generating file templates. Pump is a python
-$$ script that is part of the Google Test suite of utilities. Description
-$$ can be found here:
-$$
-$$ http://code.google.com/p/googletest/wiki/PumpManual
-$$
-
-$$ See comment for MAX_ARITY in base/bind.h.pump.
-$var MAX_ARITY = 7
-
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_CALLBACK_LIST_H_
-#define BASE_CALLBACK_LIST_H_
-
-#include <list>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/callback_internal.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-
-// OVERVIEW:
-//
-// A container for a list of callbacks. Unlike a normal STL vector or list,
-// this container can be modified during iteration without invalidating the
-// iterator. It safely handles the case of a callback removing itself
-// or another callback from the list while callbacks are being run.
-//
-// TYPICAL USAGE:
-//
-// class MyWidget {
-// public:
-// ...
-//
-// typedef base::Callback<void(const Foo&)> OnFooCallback;
-//
-// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
-// RegisterCallback(const OnFooCallback& cb) {
-// return callback_list_.Add(cb);
-// }
-//
-// private:
-// void NotifyFoo(const Foo& foo) {
-// callback_list_.Notify(foo);
-// }
-//
-// base::CallbackList<void(const Foo&)> callback_list_;
-//
-// DISALLOW_COPY_AND_ASSIGN(MyWidget);
-// };
-//
-//
-// class MyWidgetListener {
-// public:
-// MyWidgetListener::MyWidgetListener() {
-// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
-// base::Bind(&MyWidgetListener::OnFoo, this)));
-// }
-//
-// MyWidgetListener::~MyWidgetListener() {
-// // Subscription gets deleted automatically and will deregister
-// // the callback in the process.
-// }
-//
-// private:
-// void OnFoo(const Foo& foo) {
-// // Do something.
-// }
-//
-// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
-// foo_subscription_;
-//
-// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
-// };
-
-namespace base {
-
-namespace internal {
-
-template <typename CallbackType>
-class CallbackListBase {
- public:
- class Subscription {
- public:
- Subscription(CallbackListBase<CallbackType>* list,
- typename std::list<CallbackType>::iterator iter)
- : list_(list),
- iter_(iter) {
- }
-
- ~Subscription() {
- if (list_->active_iterator_count_) {
- iter_->Reset();
- } else {
- list_->callbacks_.erase(iter_);
- if (!list_->removal_callback_.is_null())
- list_->removal_callback_.Run();
- }
- }
-
- private:
- CallbackListBase<CallbackType>* list_;
- typename std::list<CallbackType>::iterator iter_;
-
- DISALLOW_COPY_AND_ASSIGN(Subscription);
- };
-
- // Add a callback to the list. The callback will remain registered until the
- // returned Subscription is destroyed, which must occur before the
- // CallbackList is destroyed.
- scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
- DCHECK(!cb.is_null());
- return scoped_ptr<Subscription>(
- new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
- }
-
- // Sets a callback which will be run when a subscription list is changed.
- void set_removal_callback(const Closure& callback) {
- removal_callback_ = callback;
- }
-
- // Returns true if there are no subscriptions. This is only valid to call when
- // not looping through the list.
- bool empty() {
- DCHECK_EQ(0, active_iterator_count_);
- return callbacks_.empty();
- }
-
- protected:
- // An iterator class that can be used to access the list of callbacks.
- class Iterator {
- public:
- explicit Iterator(CallbackListBase<CallbackType>* list)
- : list_(list),
- list_iter_(list_->callbacks_.begin()) {
- ++list_->active_iterator_count_;
- }
-
- Iterator(const Iterator& iter)
- : list_(iter.list_),
- list_iter_(iter.list_iter_) {
- ++list_->active_iterator_count_;
- }
-
- ~Iterator() {
- if (list_ && --list_->active_iterator_count_ == 0) {
- list_->Compact();
- }
- }
-
- CallbackType* GetNext() {
- while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
- ++list_iter_;
-
- CallbackType* cb = NULL;
- if (list_iter_ != list_->callbacks_.end()) {
- cb = &(*list_iter_);
- ++list_iter_;
- }
- return cb;
- }
-
- private:
- CallbackListBase<CallbackType>* list_;
- typename std::list<CallbackType>::iterator list_iter_;
- };
-
- CallbackListBase() : active_iterator_count_(0) {}
-
- ~CallbackListBase() {
- DCHECK_EQ(0, active_iterator_count_);
- DCHECK_EQ(0U, callbacks_.size());
- }
-
- // Returns an instance of a CallbackListBase::Iterator which can be used
- // to run callbacks.
- Iterator GetIterator() {
- return Iterator(this);
- }
-
- // Compact the list: remove any entries which were NULLed out during
- // iteration.
- void Compact() {
- typename std::list<CallbackType>::iterator it = callbacks_.begin();
- bool updated = false;
- while (it != callbacks_.end()) {
- if ((*it).is_null()) {
- updated = true;
- it = callbacks_.erase(it);
- } else {
- ++it;
- }
-
- if (updated && !removal_callback_.is_null())
- removal_callback_.Run();
- }
- }
-
- private:
- std::list<CallbackType> callbacks_;
- int active_iterator_count_;
- Closure removal_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
-};
-
-} // namespace internal
-
-template <typename Sig> class CallbackList;
-
-
-$range ARITY 0..MAX_ARITY
-$for ARITY [[
-$range ARG 1..ARITY
-
-$if ARITY == 0 [[
-template <>
-class CallbackList<void(void)>
- : public internal::CallbackListBase<Callback<void(void)> > {
-]] $else [[
-template <$for ARG , [[typename A$(ARG)]]>
-class CallbackList<void($for ARG , [[A$(ARG)]])>
- : public internal::CallbackListBase<Callback<void($for ARG , [[A$(ARG)]])> > {
-]]
-
- public:
-$if ARITY == 0 [[
-
- typedef Callback<void(void)> CallbackType;
-]] $else [[
-
- typedef Callback<void($for ARG , [[A$(ARG)]])> CallbackType;
-]]
-
-
- CallbackList() {}
-
- void Notify($for ARG ,
- [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
-$if ARITY == 0 [[
-
- internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
-]] $else [[
-
- typename internal::CallbackListBase<CallbackType>::Iterator it =
- this->GetIterator();
-]]
-
- CallbackType* cb;
- while ((cb = it.GetNext()) != NULL) {
- cb->Run($for ARG , [[a$(ARG)]]);
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackList);
-};
-
-
-]] $$ for ARITY
-} // namespace base
-
-#endif // BASE_CALLBACK_LIST_H_
diff --git a/chromium/base/callback_unittest.cc b/chromium/base/callback_unittest.cc
index 6103b2e9675..2844aa98a29 100644
--- a/chromium/base/callback_unittest.cc
+++ b/chromium/base/callback_unittest.cc
@@ -35,7 +35,13 @@ template <>
struct BindState<void(void), void(void), void(FakeInvoker)>
: public BindStateBase {
public:
+ BindState() : BindStateBase(&Destroy) {}
typedef FakeInvoker InvokerType;
+ private:
+ ~BindState() {}
+ static void Destroy(BindStateBase* self) {
+ delete static_cast<BindState*>(self);
+ }
};
template <>
@@ -43,7 +49,13 @@ struct BindState<void(void), void(void),
void(FakeInvoker, FakeInvoker)>
: public BindStateBase {
public:
+ BindState() : BindStateBase(&Destroy) {}
typedef FakeInvoker InvokerType;
+ private:
+ ~BindState() {}
+ static void Destroy(BindStateBase* self) {
+ delete static_cast<BindState*>(self);
+ }
};
} // namespace internal
@@ -62,8 +74,7 @@ class CallbackTest : public ::testing::Test {
callback_b_(new FakeBindState2()) {
}
- virtual ~CallbackTest() {
- }
+ ~CallbackTest() override {}
protected:
Callback<void(void)> callback_a_;
diff --git a/chromium/base/cancelable_callback.h b/chromium/base/cancelable_callback.h
index 159100f71bf..2b9d2609464 100644
--- a/chromium/base/cancelable_callback.h
+++ b/chromium/base/cancelable_callback.h
@@ -55,15 +55,14 @@ namespace base {
template <typename Sig>
class CancelableCallback;
-template <>
-class CancelableCallback<void(void)> {
+template <typename... A>
+class CancelableCallback<void(A...)> {
public:
CancelableCallback() : weak_factory_(this) {}
// |callback| must not be null.
- explicit CancelableCallback(const base::Callback<void(void)>& callback)
- : weak_factory_(this),
- callback_(callback) {
+ explicit CancelableCallback(const base::Callback<void(A...)>& callback)
+ : callback_(callback), weak_factory_(this) {
DCHECK(!callback.is_null());
InitializeForwarder();
}
@@ -84,7 +83,7 @@ class CancelableCallback<void(void)> {
// Sets |callback| as the closure that may be cancelled. |callback| may not
// be null. Outstanding and any previously wrapped callbacks are cancelled.
- void Reset(const base::Callback<void(void)>& callback) {
+ void Reset(const base::Callback<void(A...)>& callback) {
DCHECK(!callback.is_null());
// Outstanding tasks (e.g., posted to a message loop) must not be called.
@@ -97,173 +96,34 @@ class CancelableCallback<void(void)> {
}
// Returns a callback that can be disabled by calling Cancel().
- const base::Callback<void(void)>& callback() const {
+ const base::Callback<void(A...)>& callback() const {
return forwarder_;
}
private:
- void Forward() {
- callback_.Run();
+ void Forward(A... args) const {
+ callback_.Run(args...);
}
// Helper method to bind |forwarder_| using a weak pointer from
// |weak_factory_|.
void InitializeForwarder() {
- forwarder_ = base::Bind(&CancelableCallback<void(void)>::Forward,
+ forwarder_ = base::Bind(&CancelableCallback<void(A...)>::Forward,
weak_factory_.GetWeakPtr());
}
- // Used to ensure Forward() is not run when this object is destroyed.
- base::WeakPtrFactory<CancelableCallback<void(void)> > weak_factory_;
-
// The wrapper closure.
- base::Callback<void(void)> forwarder_;
+ base::Callback<void(A...)> forwarder_;
// The stored closure that may be cancelled.
- base::Callback<void(void)> callback_;
-
- DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
-};
-
-template <typename A1>
-class CancelableCallback<void(A1)> {
- public:
- CancelableCallback() : weak_factory_(this) {}
-
- // |callback| must not be null.
- explicit CancelableCallback(const base::Callback<void(A1)>& callback)
- : weak_factory_(this),
- callback_(callback) {
- DCHECK(!callback.is_null());
- InitializeForwarder();
- }
-
- ~CancelableCallback() {}
-
- // Cancels and drops the reference to the wrapped callback.
- void Cancel() {
- weak_factory_.InvalidateWeakPtrs();
- forwarder_.Reset();
- callback_.Reset();
- }
-
- // Returns true if the wrapped callback has been cancelled.
- bool IsCancelled() const {
- return callback_.is_null();
- }
-
- // Sets |callback| as the closure that may be cancelled. |callback| may not
- // be null. Outstanding and any previously wrapped callbacks are cancelled.
- void Reset(const base::Callback<void(A1)>& callback) {
- DCHECK(!callback.is_null());
-
- // Outstanding tasks (e.g., posted to a message loop) must not be called.
- Cancel();
-
- // |forwarder_| is no longer valid after Cancel(), so re-bind.
- InitializeForwarder();
-
- callback_ = callback;
- }
-
- // Returns a callback that can be disabled by calling Cancel().
- const base::Callback<void(A1)>& callback() const {
- return forwarder_;
- }
-
- private:
- void Forward(A1 a1) const {
- callback_.Run(a1);
- }
-
- // Helper method to bind |forwarder_| using a weak pointer from
- // |weak_factory_|.
- void InitializeForwarder() {
- forwarder_ = base::Bind(&CancelableCallback<void(A1)>::Forward,
- weak_factory_.GetWeakPtr());
- }
+ base::Callback<void(A...)> callback_;
// Used to ensure Forward() is not run when this object is destroyed.
- base::WeakPtrFactory<CancelableCallback<void(A1)> > weak_factory_;
-
- // The wrapper closure.
- base::Callback<void(A1)> forwarder_;
-
- // The stored closure that may be cancelled.
- base::Callback<void(A1)> callback_;
+ base::WeakPtrFactory<CancelableCallback<void(A...)>> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
};
-template <typename A1, typename A2>
-class CancelableCallback<void(A1, A2)> {
- public:
- CancelableCallback() : weak_factory_(this) {}
-
- // |callback| must not be null.
- explicit CancelableCallback(const base::Callback<void(A1, A2)>& callback)
- : weak_factory_(this),
- callback_(callback) {
- DCHECK(!callback.is_null());
- InitializeForwarder();
- }
-
- ~CancelableCallback() {}
-
- // Cancels and drops the reference to the wrapped callback.
- void Cancel() {
- weak_factory_.InvalidateWeakPtrs();
- forwarder_.Reset();
- callback_.Reset();
- }
-
- // Returns true if the wrapped callback has been cancelled.
- bool IsCancelled() const {
- return callback_.is_null();
- }
-
- // Sets |callback| as the closure that may be cancelled. |callback| may not
- // be null. Outstanding and any previously wrapped callbacks are cancelled.
- void Reset(const base::Callback<void(A1, A2)>& callback) {
- DCHECK(!callback.is_null());
-
- // Outstanding tasks (e.g., posted to a message loop) must not be called.
- Cancel();
-
- // |forwarder_| is no longer valid after Cancel(), so re-bind.
- InitializeForwarder();
-
- callback_ = callback;
- }
-
- // Returns a callback that can be disabled by calling Cancel().
- const base::Callback<void(A1, A2)>& callback() const {
- return forwarder_;
- }
-
- private:
- void Forward(A1 a1, A2 a2) const {
- callback_.Run(a1, a2);
- }
-
- // Helper method to bind |forwarder_| using a weak pointer from
- // |weak_factory_|.
- void InitializeForwarder() {
- forwarder_ = base::Bind(&CancelableCallback<void(A1, A2)>::Forward,
- weak_factory_.GetWeakPtr());
- }
-
- // The wrapper closure.
- base::Callback<void(A1, A2)> forwarder_;
-
- // The stored closure that may be cancelled.
- base::Callback<void(A1, A2)> callback_;
-
- // Used to ensure Forward() is not run when this object is destroyed.
- base::WeakPtrFactory<CancelableCallback<void(A1, A2)> > weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
-};
-
typedef CancelableCallback<void(void)> CancelableClosure;
} // namespace base
diff --git a/chromium/base/cancelable_callback_unittest.cc b/chromium/base/cancelable_callback_unittest.cc
index fcbe23c1de3..6d0a1144c42 100644
--- a/chromium/base/cancelable_callback_unittest.cc
+++ b/chromium/base/cancelable_callback_unittest.cc
@@ -6,9 +6,11 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -165,12 +167,12 @@ TEST(CancelableCallbackTest, PostTask) {
CancelableClosure cancelable(base::Bind(&Increment,
base::Unretained(&count)));
- MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
RunLoop().RunUntilIdle();
EXPECT_EQ(1, count);
- MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
// Cancel before running the message loop.
cancelable.Cancel();
diff --git a/chromium/base/chromeos/OWNERS b/chromium/base/chromeos/OWNERS
new file mode 100644
index 00000000000..8fda46a1f4e
--- /dev/null
+++ b/chromium/base/chromeos/OWNERS
@@ -0,0 +1,3 @@
+skuhne@chromium.org
+oshima@chromium.org
+
diff --git a/chromium/base/chromeos/memory_pressure_monitor.cc b/chromium/base/chromeos/memory_pressure_monitor.cc
new file mode 100644
index 00000000000..5e8aadfbd81
--- /dev/null
+++ b/chromium/base/chromeos/memory_pressure_monitor.cc
@@ -0,0 +1,272 @@
+// Copyright 2014 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/chromeos/memory_pressure_monitor.h"
+
+#include <fcntl.h>
+#include <sys/select.h>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace chromeos {
+
+namespace {
+
+// The time between memory pressure checks. While under critical pressure, this
+// is also the timer to repeat cleanup attempts.
+const int kMemoryPressureIntervalMs = 1000;
+
+// The time which should pass between two moderate memory pressure calls.
+const int kModerateMemoryPressureCooldownMs = 10000;
+
+// Number of event polls before the next moderate pressure event can be sent.
+const int kModerateMemoryPressureCooldown =
+ kModerateMemoryPressureCooldownMs / kMemoryPressureIntervalMs;
+
+// Threshold constants to emit pressure events.
+const int kNormalMemoryPressureModerateThresholdPercent = 60;
+const int kNormalMemoryPressureCriticalThresholdPercent = 95;
+const int kAggressiveMemoryPressureModerateThresholdPercent = 35;
+const int kAggressiveMemoryPressureCriticalThresholdPercent = 70;
+
+// The possible state for memory pressure level. The values should be in line
+// with values in MemoryPressureListener::MemoryPressureLevel and should be
+// updated if more memory pressure levels are introduced.
+enum MemoryPressureLevelUMA {
+ MEMORY_PRESSURE_LEVEL_NONE = 0,
+ MEMORY_PRESSURE_LEVEL_MODERATE,
+ MEMORY_PRESSURE_LEVEL_CRITICAL,
+ NUM_MEMORY_PRESSURE_LEVELS
+};
+
+// This is the file that will exist if low memory notification is available
+// on the device. Whenever it becomes readable, it signals a low memory
+// condition.
+const char kLowMemFile[] = "/dev/chromeos-low-mem";
+
+// Converts a |MemoryPressureThreshold| value into a used memory percentage for
+// the moderate pressure event.
+int GetModerateMemoryThresholdInPercent(
+ MemoryPressureMonitor::MemoryPressureThresholds thresholds) {
+ return thresholds == MemoryPressureMonitor::
+ THRESHOLD_AGGRESSIVE_CACHE_DISCARD ||
+ thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE
+ ? kAggressiveMemoryPressureModerateThresholdPercent
+ : kNormalMemoryPressureModerateThresholdPercent;
+}
+
+// Converts a |MemoryPressureThreshold| value into a used memory percentage for
+// the critical pressure event.
+int GetCriticalMemoryThresholdInPercent(
+ MemoryPressureMonitor::MemoryPressureThresholds thresholds) {
+ return thresholds == MemoryPressureMonitor::
+ THRESHOLD_AGGRESSIVE_TAB_DISCARD ||
+ thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE
+ ? kAggressiveMemoryPressureCriticalThresholdPercent
+ : kNormalMemoryPressureCriticalThresholdPercent;
+}
+
+// Converts free percent of memory into a memory pressure value.
+MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel(
+ int actual_fill_level,
+ int moderate_threshold,
+ int critical_threshold) {
+ if (actual_fill_level < moderate_threshold)
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+ return actual_fill_level < critical_threshold
+ ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
+ : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+}
+
+// This function will be called less then once a second. It will check if
+// the kernel has detected a low memory situation.
+bool IsLowMemoryCondition(int file_descriptor) {
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO(&fds);
+ FD_SET(file_descriptor, &fds);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ return HANDLE_EINTR(select(file_descriptor + 1, &fds, NULL, NULL, &tv)) > 0;
+}
+
+} // namespace
+
+MemoryPressureMonitor::MemoryPressureMonitor(
+ MemoryPressureThresholds thresholds)
+ : current_memory_pressure_level_(
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+ moderate_pressure_repeat_count_(0),
+ moderate_pressure_threshold_percent_(
+ GetModerateMemoryThresholdInPercent(thresholds)),
+ critical_pressure_threshold_percent_(
+ GetCriticalMemoryThresholdInPercent(thresholds)),
+ low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))),
+ weak_ptr_factory_(this) {
+ StartObserving();
+ LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener";
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+ StopObserving();
+}
+
+void MemoryPressureMonitor::ScheduleEarlyCheck() {
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+ return current_memory_pressure_level_;
+}
+
+// static
+MemoryPressureMonitor* MemoryPressureMonitor::Get() {
+ return static_cast<MemoryPressureMonitor*>(
+ base::MemoryPressureMonitor::Get());
+}
+
+void MemoryPressureMonitor::StartObserving() {
+ timer_.Start(FROM_HERE,
+ TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs),
+ Bind(&MemoryPressureMonitor::
+ CheckMemoryPressureAndRecordStatistics,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MemoryPressureMonitor::StopObserving() {
+ // If StartObserving failed, StopObserving will still get called.
+ timer_.Stop();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
+ CheckMemoryPressure();
+
+ // Record UMA histogram statistics for the current memory pressure level.
+ MemoryPressureLevelUMA memory_pressure_level_uma(MEMORY_PRESSURE_LEVEL_NONE);
+ switch (current_memory_pressure_level_) {
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_NONE;
+ break;
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_MODERATE;
+ break;
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_CRITICAL;
+ break;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel",
+ memory_pressure_level_uma,
+ NUM_MEMORY_PRESSURE_LEVELS);
+}
+
+void MemoryPressureMonitor::CheckMemoryPressure() {
+ MemoryPressureListener::MemoryPressureLevel old_pressure =
+ current_memory_pressure_level_;
+
+ // If we have the kernel low memory observer, we use it's flag instead of our
+ // own computation (for now). Note that in "simulation mode" it can be null.
+ // TODO(skuhne): We need to add code which makes sure that the kernel and this
+ // computation come to similar results and then remove this override again.
+ // TODO(skuhne): Add some testing framework here to see how close the kernel
+ // and the internal functions are.
+ if (low_mem_file_.is_valid() && IsLowMemoryCondition(low_mem_file_.get())) {
+ current_memory_pressure_level_ =
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+ } else {
+ current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel(
+ GetUsedMemoryInPercent(),
+ moderate_pressure_threshold_percent_,
+ critical_pressure_threshold_percent_);
+
+ // When listening to the kernel, we ignore the reported memory pressure
+ // level from our own computation and reduce critical to moderate.
+ if (low_mem_file_.is_valid() &&
+ current_memory_pressure_level_ ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+ current_memory_pressure_level_ =
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+ }
+ }
+
+ // In case there is no memory pressure we do not notify.
+ if (current_memory_pressure_level_ ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
+ return;
+ }
+ if (old_pressure == current_memory_pressure_level_) {
+ // If the memory pressure is still at the same level, we notify again for a
+ // critical level. In case of a moderate level repeat however, we only send
+ // a notification after a certain time has passed.
+ if (current_memory_pressure_level_ ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
+ ++moderate_pressure_repeat_count_ <
+ kModerateMemoryPressureCooldown) {
+ return;
+ }
+ } else if (current_memory_pressure_level_ ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
+ old_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+ // When we reducing the pressure level from critical to moderate, we
+ // restart the timeout and do not send another notification.
+ moderate_pressure_repeat_count_ = 0;
+ return;
+ }
+ moderate_pressure_repeat_count_ = 0;
+ MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+}
+
+// Gets the used ChromeOS memory in percent.
+int MemoryPressureMonitor::GetUsedMemoryInPercent() {
+ base::SystemMemoryInfoKB info;
+ if (!base::GetSystemMemoryInfo(&info)) {
+ VLOG(1) << "Cannot determine the free memory of the system.";
+ return 0;
+ }
+ // TODO(skuhne): Instead of adding the kernel memory pressure calculation
+ // logic here, we should have a kernel mechanism similar to the low memory
+ // notifier in ChromeOS which offers multiple pressure states.
+ // To track this, we have crbug.com/381196.
+
+ // The available memory consists of "real" and virtual (z)ram memory.
+ // Since swappable memory uses a non pre-deterministic compression and
+ // the compression creates its own "dynamic" in the system, it gets
+ // de-emphasized by the |kSwapWeight| factor.
+ const int kSwapWeight = 4;
+
+ // The total memory we have is the "real memory" plus the virtual (z)ram.
+ int total_memory = info.total + info.swap_total / kSwapWeight;
+
+ // The kernel internally uses 50MB.
+ const int kMinFileMemory = 50 * 1024;
+
+ // Most file memory can be easily reclaimed.
+ int file_memory = info.active_file + info.inactive_file;
+ // unless it is dirty or it's a minimal portion which is required.
+ file_memory -= info.dirty + kMinFileMemory;
+
+ // Available memory is the sum of free, swap and easy reclaimable memory.
+ int available_memory =
+ info.free + info.swap_free / kSwapWeight + file_memory;
+
+ DCHECK(available_memory < total_memory);
+ int percentage = ((total_memory - available_memory) * 100) / total_memory;
+ return percentage;
+}
+
+} // namespace chromeos
+} // namespace base
diff --git a/chromium/base/chromeos/memory_pressure_monitor.h b/chromium/base/chromeos/memory_pressure_monitor.h
new file mode 100644
index 00000000000..bed1ec39f6a
--- /dev/null
+++ b/chromium/base/chromeos/memory_pressure_monitor.h
@@ -0,0 +1,119 @@
+// Copyright 2014 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_CHROMEOS_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_CHROMEOS_MEMORY_PRESSURE_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+
+namespace base {
+namespace chromeos {
+
+class TestMemoryPressureMonitor;
+
+////////////////////////////////////////////////////////////////////////////////
+// MemoryPressureMonitor
+//
+// A class to handle the observation of our free memory. It notifies the
+// MemoryPressureListener of memory fill level changes, so that it can take
+// action to reduce memory resources accordingly.
+//
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+ using GetUsedMemoryInPercentCallback = int (*)();
+
+ // There are two memory pressure events:
+ // MODERATE - which will mainly release caches.
+ // CRITICAL - which will discard tabs.
+ // The |MemoryPressureThresholds| enum selects the strategy of firing these
+ // events: A conservative strategy will keep as much content in memory as
+ // possible (causing the system to swap to zram) and an aggressive strategy
+ // will release memory earlier to avoid swapping.
+ enum MemoryPressureThresholds {
+ // Use the system default.
+ THRESHOLD_DEFAULT = 0,
+ // Try to keep as much content in memory as possible.
+ THRESHOLD_CONSERVATIVE = 1,
+ // Discard caches earlier, allowing to keep more tabs in memory.
+ THRESHOLD_AGGRESSIVE_CACHE_DISCARD = 2,
+ // Discard tabs earlier, allowing the system to get faster.
+ THRESHOLD_AGGRESSIVE_TAB_DISCARD = 3,
+ // Discard caches and tabs earlier to allow the system to be faster.
+ THRESHOLD_AGGRESSIVE = 4
+ };
+
+ explicit MemoryPressureMonitor(MemoryPressureThresholds thresholds);
+ ~MemoryPressureMonitor() override;
+
+ // Redo the memory pressure calculation soon and call again if a critical
+ // memory pressure prevails. Note that this call will trigger an asynchronous
+ // action which gives the system time to release memory back into the pool.
+ void ScheduleEarlyCheck();
+
+ // Get the current memory pressure level.
+ MemoryPressureListener::MemoryPressureLevel GetCurrentPressureLevel() const
+ override;
+
+ // Returns a type-casted version of the current memory pressure monitor. A
+ // simple wrapper to base::MemoryPressureMonitor::Get.
+ static MemoryPressureMonitor* Get();
+
+ private:
+ friend TestMemoryPressureMonitor;
+ // Starts observing the memory fill level.
+ // Calls to StartObserving should always be matched with calls to
+ // StopObserving.
+ void StartObserving();
+
+ // Stop observing the memory fill level.
+ // May be safely called if StartObserving has not been called.
+ void StopObserving();
+
+ // The function which gets periodically called to check any changes in the
+ // memory pressure. It will report pressure changes as well as continuous
+ // critical pressure levels.
+ void CheckMemoryPressure();
+
+ // The function periodically checks the memory pressure changes and records
+ // the UMA histogram statistics for the current memory pressure level.
+ void CheckMemoryPressureAndRecordStatistics();
+
+ // Get the memory pressure in percent (virtual for testing).
+ virtual int GetUsedMemoryInPercent();
+
+ // The current memory pressure.
+ base::MemoryPressureListener::MemoryPressureLevel
+ current_memory_pressure_level_;
+
+ // A periodic timer to check for resource pressure changes. This will get
+ // replaced by a kernel triggered event system (see crbug.com/381196).
+ base::RepeatingTimer<MemoryPressureMonitor> timer_;
+
+ // To slow down the amount of moderate pressure event calls, this counter
+ // gets used to count the number of events since the last event occured.
+ int moderate_pressure_repeat_count_;
+
+ // The thresholds for moderate and critical pressure.
+ const int moderate_pressure_threshold_percent_;
+ const int critical_pressure_threshold_percent_;
+
+ // File descriptor used to detect low memory condition.
+ ScopedFD low_mem_file_;
+
+ base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+} // namespace chromeos
+} // namespace base
+
+#endif // BASE_CHROMEOS_MEMORY_PRESSURE_MONITOR_H_
diff --git a/chromium/base/chromeos/memory_pressure_monitor_unittest.cc b/chromium/base/chromeos/memory_pressure_monitor_unittest.cc
new file mode 100644
index 00000000000..4fb83327f4c
--- /dev/null
+++ b/chromium/base/chromeos/memory_pressure_monitor_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2014 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/basictypes.h"
+#include "base/chromeos/memory_pressure_monitor.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace chromeos {
+
+namespace {
+
+// True if the memory notifier got called.
+// Do not read/modify value directly.
+bool on_memory_pressure_called = false;
+
+// If the memory notifier got called, this is the memory pressure reported.
+MemoryPressureListener::MemoryPressureLevel on_memory_pressure_level =
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+// Processes OnMemoryPressure calls.
+void OnMemoryPressure(MemoryPressureListener::MemoryPressureLevel level) {
+ on_memory_pressure_called = true;
+ on_memory_pressure_level = level;
+}
+
+// Resets the indicator for memory pressure.
+void ResetOnMemoryPressureCalled() {
+ on_memory_pressure_called = false;
+}
+
+// Returns true when OnMemoryPressure was called (and resets it).
+bool WasOnMemoryPressureCalled() {
+ bool b = on_memory_pressure_called;
+ ResetOnMemoryPressureCalled();
+ return b;
+}
+
+} // namespace
+
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+ TestMemoryPressureMonitor()
+ : MemoryPressureMonitor(THRESHOLD_DEFAULT),
+ memory_in_percent_override_(0) {
+ // Disable any timers which are going on and set a special memory reporting
+ // function.
+ StopObserving();
+ }
+ ~TestMemoryPressureMonitor() override {}
+
+ void SetMemoryInPercentOverride(int percent) {
+ memory_in_percent_override_ = percent;
+ }
+
+ void CheckMemoryPressureForTest() {
+ CheckMemoryPressure();
+ }
+
+ private:
+ int GetUsedMemoryInPercent() override {
+ return memory_in_percent_override_;
+ }
+
+ int memory_in_percent_override_;
+ DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST(ChromeOSMemoryPressureMonitorTest, CheckMemoryPressure) {
+ base::MessageLoopForUI message_loop;
+ scoped_ptr<TestMemoryPressureMonitor> monitor(
+ new TestMemoryPressureMonitor);
+ scoped_ptr<MemoryPressureListener> listener(
+ new MemoryPressureListener(base::Bind(&OnMemoryPressure)));
+ // Checking the memory pressure while 0% are used should not produce any
+ // events.
+ monitor->SetMemoryInPercentOverride(0);
+ ResetOnMemoryPressureCalled();
+
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_FALSE(WasOnMemoryPressureCalled());
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor->GetCurrentPressureLevel());
+
+ // Setting the memory level to 80% should produce a moderate pressure level.
+ monitor->SetMemoryInPercentOverride(80);
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_TRUE(WasOnMemoryPressureCalled());
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->GetCurrentPressureLevel());
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ on_memory_pressure_level);
+
+ // We need to check that the event gets reposted after a while.
+ int i = 0;
+ for (; i < 100; i++) {
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->GetCurrentPressureLevel());
+ if (WasOnMemoryPressureCalled()) {
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ on_memory_pressure_level);
+ break;
+ }
+ }
+ // Should be more then 5 and less then 100.
+ EXPECT_LE(5, i);
+ EXPECT_GE(99, i);
+
+ // Setting the memory usage to 99% should produce critical levels.
+ monitor->SetMemoryInPercentOverride(99);
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_TRUE(WasOnMemoryPressureCalled());
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ on_memory_pressure_level);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor->GetCurrentPressureLevel());
+
+ // Calling it again should immediately produce a second call.
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_TRUE(WasOnMemoryPressureCalled());
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ on_memory_pressure_level);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor->GetCurrentPressureLevel());
+
+ // When lowering the pressure again we should not get an event, but the
+ // pressure should go back to moderate.
+ monitor->SetMemoryInPercentOverride(80);
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_FALSE(WasOnMemoryPressureCalled());
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->GetCurrentPressureLevel());
+
+ // We should need exactly the same amount of calls as before, before the next
+ // call comes in.
+ int j = 0;
+ for (; j < 100; j++) {
+ monitor->CheckMemoryPressureForTest();
+ message_loop.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->GetCurrentPressureLevel());
+ if (WasOnMemoryPressureCalled()) {
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ on_memory_pressure_level);
+ break;
+ }
+ }
+ // We should have needed exactly the same amount of checks as before.
+ EXPECT_EQ(j, i);
+}
+
+} // namespace chromeos
+} // namespace base
diff --git a/chromium/base/command_line.cc b/chromium/base/command_line.cc
index 1f5edce0fff..61ff5c10c38 100644
--- a/chromium/base/command_line.cc
+++ b/chromium/base/command_line.cc
@@ -70,7 +70,7 @@ bool IsSwitch(const CommandLine::StringType& string,
}
// Append switches and arguments, keeping switches before arguments.
-void AppendSwitchesAndArguments(CommandLine& command_line,
+void AppendSwitchesAndArguments(CommandLine* command_line,
const CommandLine::StringVector& argv) {
bool parse_switches = true;
for (size_t i = 1; i < argv.size(); ++i) {
@@ -82,51 +82,52 @@ void AppendSwitchesAndArguments(CommandLine& command_line,
parse_switches &= (arg != kSwitchTerminator);
if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
#if defined(OS_WIN)
- command_line.AppendSwitchNative(UTF16ToASCII(switch_string),
- switch_value);
+ command_line->AppendSwitchNative(UTF16ToASCII(switch_string),
+ switch_value);
#elif defined(OS_POSIX)
- command_line.AppendSwitchNative(switch_string, switch_value);
+ command_line->AppendSwitchNative(switch_string, switch_value);
#endif
} else {
- command_line.AppendArgNative(arg);
+ command_line->AppendArgNative(arg);
}
}
}
// Lowercase switches for backwards compatiblity *on Windows*.
-std::string LowerASCIIOnWindows(const std::string& string) {
#if defined(OS_WIN)
- return base::StringToLowerASCII(string);
+std::string LowerASCIIOnWindows(const std::string& string) {
+ return StringToLowerASCII(string);
+}
#elif defined(OS_POSIX)
+const std::string& LowerASCIIOnWindows(const std::string& string) {
return string;
-#endif
}
+#endif
#if defined(OS_WIN)
// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
-base::string16 QuoteForCommandLineToArgvW(const base::string16& arg,
- bool quote_placeholders) {
+string16 QuoteForCommandLineToArgvW(const string16& arg,
+ bool quote_placeholders) {
// We follow the quoting rules of CommandLineToArgvW.
// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
- base::string16 quotable_chars(L" \\\"");
+ string16 quotable_chars(L" \\\"");
// We may also be required to quote '%', which is commonly used in a command
// line as a placeholder. (It may be substituted for a string with spaces.)
if (quote_placeholders)
quotable_chars.push_back(L'%');
- if (arg.find_first_of(quotable_chars) == base::string16::npos) {
+ if (arg.find_first_of(quotable_chars) == string16::npos) {
// No quoting necessary.
return arg;
}
- base::string16 out;
+ string16 out;
out.push_back(L'"');
for (size_t i = 0; i < arg.size(); ++i) {
if (arg[i] == '\\') {
// Find the extent of this run of backslashes.
size_t start = i, end = start + 1;
- for (; end < arg.size() && arg[end] == '\\'; ++end)
- /* empty */;
+ for (; end < arg.size() && arg[end] == '\\'; ++end) {}
size_t backslash_count = end - start;
// Backslashes are escapes only if the run is followed by a double quote.
@@ -186,7 +187,7 @@ CommandLine::~CommandLine() {
// static
void CommandLine::set_slash_is_not_a_switch() {
// The last switch prefix should be slash, so adjust the size to skip it.
- DCHECK(wcscmp(kSwitchPrefixes[arraysize(kSwitchPrefixes) - 1], L"/") == 0);
+ DCHECK_EQ(wcscmp(kSwitchPrefixes[arraysize(kSwitchPrefixes) - 1], L"/"), 0);
switch_prefix_count = arraysize(kSwitchPrefixes) - 1;
}
#endif
@@ -230,7 +231,7 @@ bool CommandLine::InitializedForCurrentProcess() {
#if defined(OS_WIN)
// static
-CommandLine CommandLine::FromString(const base::string16& command_line) {
+CommandLine CommandLine::FromString(const string16& command_line) {
CommandLine cmd(NO_PROGRAM);
cmd.ParseFromString(command_line);
return cmd;
@@ -250,7 +251,7 @@ void CommandLine::InitFromArgv(const StringVector& argv) {
switches_.clear();
begin_args_ = 1;
SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
- AppendSwitchesAndArguments(*this, argv);
+ AppendSwitchesAndArguments(this, argv);
}
FilePath CommandLine::GetProgram() const {
@@ -262,7 +263,12 @@ void CommandLine::SetProgram(const FilePath& program) {
}
bool CommandLine::HasSwitch(const std::string& switch_string) const {
- return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end();
+ DCHECK_EQ(StringToLowerASCII(switch_string), switch_string);
+ return switches_.find(switch_string) != switches_.end();
+}
+
+bool CommandLine::HasSwitch(const char string_constant[]) const {
+ return HasSwitch(std::string(string_constant));
}
std::string CommandLine::GetSwitchValueASCII(
@@ -304,7 +310,7 @@ void CommandLine::AppendSwitchNative(const std::string& switch_string,
const CommandLine::StringType& value) {
std::string switch_key(LowerASCIIOnWindows(switch_string));
#if defined(OS_WIN)
- StringType combined_switch_string(ASCIIToWide(switch_key));
+ StringType combined_switch_string(ASCIIToUTF16(switch_key));
#elif defined(OS_POSIX)
StringType combined_switch_string(switch_string);
#endif
@@ -322,7 +328,7 @@ void CommandLine::AppendSwitchNative(const std::string& switch_string,
void CommandLine::AppendSwitchASCII(const std::string& switch_string,
const std::string& value_string) {
#if defined(OS_WIN)
- AppendSwitchNative(switch_string, ASCIIToWide(value_string));
+ AppendSwitchNative(switch_string, ASCIIToUTF16(value_string));
#elif defined(OS_POSIX)
AppendSwitchNative(switch_string, value_string);
#endif
@@ -369,7 +375,7 @@ void CommandLine::AppendArguments(const CommandLine& other,
bool include_program) {
if (include_program)
SetProgram(other.GetProgram());
- AppendSwitchesAndArguments(*this, other.argv());
+ AppendSwitchesAndArguments(this, other.argv());
}
void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
@@ -385,8 +391,8 @@ void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
}
#if defined(OS_WIN)
-void CommandLine::ParseFromString(const base::string16& command_line) {
- base::string16 command_line_string;
+void CommandLine::ParseFromString(const string16& command_line) {
+ string16 command_line_string;
TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
if (command_line_string.empty())
return;
@@ -437,8 +443,7 @@ CommandLine::StringType CommandLine::GetArgumentsStringInternal(
#endif
params.append(kSwitchValueSeparator + switch_value);
}
- }
- else {
+ } else {
#if defined(OS_WIN)
arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
#endif
diff --git a/chromium/base/command_line.h b/chromium/base/command_line.h
index 1829e63e1b5..439921ed6e5 100644
--- a/chromium/base/command_line.h
+++ b/chromium/base/command_line.h
@@ -142,8 +142,11 @@ class BASE_EXPORT CommandLine {
void SetProgram(const FilePath& program);
// Returns true if this command line contains the given switch.
- // (Switch names are case-insensitive).
+ // Switch names should only be lowercase.
+ // The second override provides an optimized version to avoid inlining the
+ // codegen for the string allocation.
bool HasSwitch(const std::string& switch_string) const;
+ bool HasSwitch(const char switch_constant[]) const;
// Returns the value associated with the given switch. If the switch has no
// value or isn't present, this method returns the empty string.
@@ -226,7 +229,4 @@ class BASE_EXPORT CommandLine {
} // namespace base
-// TODO(brettw) remove once all callers specify the namespace properly.
-using base::CommandLine;
-
#endif // BASE_COMMAND_LINE_H_
diff --git a/chromium/base/command_line_unittest.cc b/chromium/base/command_line_unittest.cc
index 8fdd605db79..db1a0b27cb1 100644
--- a/chromium/base/command_line_unittest.cc
+++ b/chromium/base/command_line_unittest.cc
@@ -11,7 +11,7 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-using base::FilePath;
+namespace base {
// To test Windows quoting behavior, we use a string that has some backslashes
// and quotes.
@@ -60,12 +60,13 @@ TEST(CommandLineTest, CommandLineConstructor) {
cl.GetProgram().value());
EXPECT_TRUE(cl.HasSwitch("foo"));
- EXPECT_TRUE(cl.HasSwitch("bAr"));
- EXPECT_TRUE(cl.HasSwitch("baz"));
- EXPECT_TRUE(cl.HasSwitch("spaetzle"));
#if defined(OS_WIN)
- EXPECT_TRUE(cl.HasSwitch("SPAETZLE"));
+ EXPECT_TRUE(cl.HasSwitch("bar"));
+#else
+ EXPECT_FALSE(cl.HasSwitch("bar"));
#endif
+ EXPECT_TRUE(cl.HasSwitch("baz"));
+ EXPECT_TRUE(cl.HasSwitch("spaetzle"));
EXPECT_TRUE(cl.HasSwitch("other-switches"));
EXPECT_TRUE(cl.HasSwitch("input-translation"));
@@ -128,7 +129,6 @@ TEST(CommandLineTest, CommandLineFromString) {
EXPECT_TRUE(cl.HasSwitch("bar"));
EXPECT_TRUE(cl.HasSwitch("baz"));
EXPECT_TRUE(cl.HasSwitch("spaetzle"));
- EXPECT_TRUE(cl.HasSwitch("SPAETZLE"));
EXPECT_TRUE(cl.HasSwitch("other-switches"));
EXPECT_TRUE(cl.HasSwitch("input-translation"));
EXPECT_TRUE(cl.HasSwitch("quotes"));
@@ -200,15 +200,11 @@ TEST(CommandLineTest, GetArgumentsString) {
cl.AppendArg(kFifthArgName);
#if defined(OS_WIN)
- CommandLine::StringType expected_first_arg(
- base::UTF8ToUTF16(kFirstArgName));
- CommandLine::StringType expected_second_arg(
- base::UTF8ToUTF16(kSecondArgName));
- CommandLine::StringType expected_third_arg(
- base::UTF8ToUTF16(kThirdArgName));
- CommandLine::StringType expected_fourth_arg(
- base::UTF8ToUTF16(kFourthArgName));
- CommandLine::StringType expected_fifth_arg(base::UTF8ToUTF16(kFifthArgName));
+ CommandLine::StringType expected_first_arg(UTF8ToUTF16(kFirstArgName));
+ CommandLine::StringType expected_second_arg(UTF8ToUTF16(kSecondArgName));
+ CommandLine::StringType expected_third_arg(UTF8ToUTF16(kThirdArgName));
+ CommandLine::StringType expected_fourth_arg(UTF8ToUTF16(kFourthArgName));
+ CommandLine::StringType expected_fifth_arg(UTF8ToUTF16(kFifthArgName));
#elif defined(OS_POSIX)
CommandLine::StringType expected_first_arg(kFirstArgName);
CommandLine::StringType expected_second_arg(kSecondArgName);
@@ -368,7 +364,7 @@ TEST(CommandLineTest, ProgramQuotes) {
EXPECT_EQ(L"\"Program Path\"", cmd_string);
// Check the optional quoting of placeholders in programs.
- CommandLine cl_quote_placeholder(base::FilePath(L"%1"));
+ CommandLine cl_quote_placeholder(FilePath(L"%1"));
EXPECT_EQ(L"%1", cl_quote_placeholder.GetCommandLineString());
EXPECT_EQ(L"\"%1\"",
cl_quote_placeholder.GetCommandLineStringWithPlaceholders());
@@ -382,3 +378,5 @@ TEST(CommandLineTest, Init) {
CommandLine* current = CommandLine::ForCurrentProcess();
EXPECT_EQ(initial, current);
}
+
+} // namespace base
diff --git a/chromium/base/compiler_specific.h b/chromium/base/compiler_specific.h
index 47ca9778b67..63297dcaf00 100644
--- a/chromium/base/compiler_specific.h
+++ b/chromium/base/compiler_specific.h
@@ -128,13 +128,11 @@
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#endif
-// Return the byte alignment of the given type (available at compile time). Use
-// sizeof(type) prior to checking __alignof to workaround Visual C++ bug:
-// http://goo.gl/isH0C
+// Return the byte alignment of the given type (available at compile time).
// Use like:
// ALIGNOF(int32) // this would be 4
#if defined(COMPILER_MSVC)
-#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
+#define ALIGNOF(type) __alignof(type)
#elif defined(COMPILER_GCC)
#define ALIGNOF(type) __alignof__(type)
#endif
@@ -175,9 +173,17 @@
// Mark a memory region fully initialized.
// Use this to annotate code that deliberately reads uninitialized data, for
// example a GC scavenging root set pointers from the stack.
-#define MSAN_UNPOISON(p, s) __msan_unpoison(p, s)
+#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
+
+// Check a memory region for initializedness, as if it was being used here.
+// If any bits are uninitialized, crash with an MSan report.
+// Use this to sanitize data which MSan won't be able to track, e.g. before
+// passing data to another process via shared memory.
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
+ __msan_check_mem_is_initialized(p, size)
#else // MEMORY_SANITIZER
-#define MSAN_UNPOISON(p, s)
+#define MSAN_UNPOISON(p, size)
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
#endif // MEMORY_SANITIZER
// Macro useful for writing cross-platform function pointers.
diff --git a/chromium/base/containers/hash_tables.h b/chromium/base/containers/hash_tables.h
index 6bf029e4565..d13c46948ed 100644
--- a/chromium/base/containers/hash_tables.h
+++ b/chromium/base/containers/hash_tables.h
@@ -320,7 +320,7 @@ struct hash<std::pair<Type1, Type2> > {
}
};
-}
+} // namespace BASE_HASH_NAMESPACE
#undef DEFINE_PAIR_HASH_FUNCTION_START
#undef DEFINE_PAIR_HASH_FUNCTION_END
diff --git a/chromium/base/containers/mru_cache.h b/chromium/base/containers/mru_cache.h
index 15ea2fccdc4..ed1ad251a2f 100644
--- a/chromium/base/containers/mru_cache.h
+++ b/chromium/base/containers/mru_cache.h
@@ -213,8 +213,7 @@ class MRUCacheBase {
template<class PayloadType>
class MRUCacheNullDeletor {
public:
- void operator()(PayloadType& payload) {
- }
+ void operator()(const PayloadType& payload) {}
};
// A container that does not do anything to free its data. Use this when storing
@@ -244,9 +243,7 @@ class MRUCache : public MRUCacheBase<KeyType,
template<class PayloadType>
class MRUCachePointerDeletor {
public:
- void operator()(PayloadType& payload) {
- delete payload;
- }
+ void operator()(const PayloadType& payload) { delete payload; }
};
// A cache that owns the payload type, which must be a non-const pointer type.
diff --git a/chromium/base/containers/scoped_ptr_hash_map.h b/chromium/base/containers/scoped_ptr_hash_map.h
index dedf21365be..8fe550e7317 100644
--- a/chromium/base/containers/scoped_ptr_hash_map.h
+++ b/chromium/base/containers/scoped_ptr_hash_map.h
@@ -16,12 +16,12 @@
namespace base {
-// This type acts like a hash_map<K, scoped_ptr<V> >, based on top of
+// This type acts like a hash_map<K, scoped_ptr<V, D> >, based on top of
// base::hash_map. The ScopedPtrHashMap has ownership of all values in the data
// structure.
-template <typename Key, typename Value>
+template <typename Key, typename ScopedPtr>
class ScopedPtrHashMap {
- typedef base::hash_map<Key, Value*> Container;
+ typedef base::hash_map<Key, typename ScopedPtr::element_type*> Container;
public:
typedef typename Container::key_type key_type;
@@ -34,15 +34,17 @@ class ScopedPtrHashMap {
~ScopedPtrHashMap() { clear(); }
- void swap(ScopedPtrHashMap<Key, Value>& other) {
+ void swap(ScopedPtrHashMap<Key, ScopedPtr>& other) {
data_.swap(other.data_);
}
// Replaces value but not key if key is already present.
- iterator set(const Key& key, scoped_ptr<Value> data) {
+ iterator set(const Key& key, ScopedPtr data) {
iterator it = find(key);
if (it != end()) {
- delete it->second;
+ // Let ScopedPtr decide how to delete. For example, it may use custom
+ // deleter.
+ ScopedPtr(it->second).reset();
it->second = data.release();
return it;
}
@@ -51,7 +53,7 @@ class ScopedPtrHashMap {
}
// Does nothing if key is already present
- std::pair<iterator, bool> add(const Key& key, scoped_ptr<Value> data) {
+ std::pair<iterator, bool> add(const Key& key, ScopedPtr data) {
std::pair<iterator, bool> result =
data_.insert(std::make_pair(key, data.get()));
if (result.second)
@@ -60,7 +62,8 @@ class ScopedPtrHashMap {
}
void erase(iterator it) {
- delete it->second;
+ // Let ScopedPtr decide how to delete.
+ ScopedPtr(it->second).reset();
data_.erase(it);
}
@@ -72,45 +75,45 @@ class ScopedPtrHashMap {
return 1;
}
- scoped_ptr<Value> take(iterator it) {
+ ScopedPtr take(iterator it) {
DCHECK(it != data_.end());
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
- scoped_ptr<Value> ret(it->second);
+ ScopedPtr ret(it->second);
it->second = NULL;
return ret.Pass();
}
- scoped_ptr<Value> take(const Key& k) {
+ ScopedPtr take(const Key& k) {
iterator it = find(k);
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
return take(it);
}
- scoped_ptr<Value> take_and_erase(iterator it) {
+ ScopedPtr take_and_erase(iterator it) {
DCHECK(it != data_.end());
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
- scoped_ptr<Value> ret(it->second);
+ ScopedPtr ret(it->second);
data_.erase(it);
return ret.Pass();
}
- scoped_ptr<Value> take_and_erase(const Key& k) {
+ ScopedPtr take_and_erase(const Key& k) {
iterator it = find(k);
if (it == data_.end())
- return scoped_ptr<Value>();
+ return ScopedPtr();
return take_and_erase(it);
}
// Returns the element in the hash_map that matches the given key.
// If no such element exists it returns NULL.
- Value* get(const Key& k) const {
+ typename ScopedPtr::element_type* get(const Key& k) const {
const_iterator it = find(k);
if (it == end())
return NULL;
@@ -119,7 +122,19 @@ class ScopedPtrHashMap {
inline bool contains(const Key& k) const { return data_.count(k) > 0; }
- inline void clear() { STLDeleteValues(&data_); }
+ inline void clear() {
+ auto it = data_.begin();
+ while (it != data_.end()) {
+ // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+ // Deleting the value does not always invalidate the iterator, but it may
+ // do so if the key is a pointer into the value object.
+ auto temp = it;
+ ++it;
+ // Let ScopedPtr decide how to delete.
+ ScopedPtr(temp->second).reset();
+ }
+ data_.clear();
+ }
inline const_iterator find(const Key& k) const { return data_.find(k); }
inline iterator find(const Key& k) { return data_.find(k); }
diff --git a/chromium/base/containers/scoped_ptr_hash_map_unittest.cc b/chromium/base/containers/scoped_ptr_hash_map_unittest.cc
new file mode 100644
index 00000000000..88fe41f9a0d
--- /dev/null
+++ b/chromium/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2015 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/containers/scoped_ptr_hash_map.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct DeleteCounter {
+ public:
+ DeleteCounter() {}
+ ~DeleteCounter() { g_delete_count++; }
+
+ static void ResetCounter() { g_delete_count = 0; }
+ static int delete_count() { return g_delete_count; }
+
+ private:
+ static int g_delete_count;
+};
+
+int DeleteCounter::g_delete_count = 0;
+
+struct CountingDeleter {
+ public:
+ inline void operator()(DeleteCounter* ptr) const {
+ g_deleter_call_count++;
+ delete ptr;
+ }
+
+ static int count() { return g_deleter_call_count; }
+ static void ResetCounter() { g_deleter_call_count = 0; }
+
+ private:
+ static int g_deleter_call_count;
+};
+
+int CountingDeleter::g_deleter_call_count = 0;
+
+TEST(ScopedPtrHashMapTest, CustomDeleter) {
+ int key = 123;
+
+ // Test dtor.
+ DeleteCounter::ResetCounter();
+ CountingDeleter::ResetCounter();
+ {
+ ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ }
+ EXPECT_EQ(1, DeleteCounter::delete_count());
+ EXPECT_EQ(1, CountingDeleter::count());
+
+ // Test set and erase.
+ DeleteCounter::ResetCounter();
+ CountingDeleter::ResetCounter();
+ {
+ ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+ map.erase(map.set(
+ key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter)));
+ EXPECT_EQ(1, DeleteCounter::delete_count());
+ EXPECT_EQ(1, CountingDeleter::count());
+ }
+ EXPECT_EQ(1, DeleteCounter::delete_count());
+ EXPECT_EQ(1, CountingDeleter::count());
+
+ // Test set more than once.
+ DeleteCounter::ResetCounter();
+ CountingDeleter::ResetCounter();
+ {
+ ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+ EXPECT_EQ(2, DeleteCounter::delete_count());
+ EXPECT_EQ(2, CountingDeleter::count());
+ }
+ EXPECT_EQ(3, DeleteCounter::delete_count());
+ EXPECT_EQ(3, CountingDeleter::count());
+}
+
+} // namespace
+} // namespace base
diff --git a/chromium/base/containers/stack_container.h b/chromium/base/containers/stack_container.h
index 87fa0369b6a..54090d3cd99 100644
--- a/chromium/base/containers/stack_container.h
+++ b/chromium/base/containers/stack_container.h
@@ -176,6 +176,7 @@ class StackContainer {
Allocator allocator_;
ContainerType container_;
+ private:
DISALLOW_COPY_AND_ASSIGN(StackContainer);
};
diff --git a/chromium/base/critical_closure.h b/chromium/base/critical_closure.h
index ac07911089d..75e37045a77 100644
--- a/chromium/base/critical_closure.h
+++ b/chromium/base/critical_closure.h
@@ -52,7 +52,7 @@ class CriticalClosure {
// returned.
//
// Example:
-// file_message_loop_proxy_->PostTask(
+// file_task_runner_->PostTask(
// FROM_HERE,
// MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
//
diff --git a/chromium/base/debug/BUILD.gn b/chromium/base/debug/BUILD.gn
new file mode 100644
index 00000000000..8ed623b03f9
--- /dev/null
+++ b/chromium/base/debug/BUILD.gn
@@ -0,0 +1,76 @@
+# Copyright (c) 2015 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.
+
+source_set("debug") {
+ sources = [
+ "alias.cc",
+ "alias.h",
+ "asan_invalid_access.cc",
+ "asan_invalid_access.h",
+ "crash_logging.cc",
+ "crash_logging.h",
+ "debugger.cc",
+ "debugger.h",
+ "debugger_posix.cc",
+ "debugger_win.cc",
+ "dump_without_crashing.cc",
+ "dump_without_crashing.h",
+ "gdi_debug_util_win.cc",
+ "gdi_debug_util_win.h",
+
+ # This file depends on files from the "allocator" target,
+ # but this target does not depend on "allocator" (see
+ # allocator.gyp for details).
+ "leak_annotations.h",
+ "leak_tracker.h",
+ "proc_maps_linux.cc",
+ "proc_maps_linux.h",
+ "profiler.cc",
+ "profiler.h",
+ "stack_trace.cc",
+ "stack_trace.h",
+ "stack_trace_android.cc",
+ "stack_trace_posix.cc",
+ "stack_trace_win.cc",
+ "task_annotator.cc",
+ "task_annotator.h",
+ ]
+
+ if (is_android) {
+ # Android uses some Linux sources, put those back.
+ set_sources_assignment_filter([])
+ sources += [ "proc_maps_linux.cc" ]
+ set_sources_assignment_filter(sources_assignment_filter)
+
+ sources -= [ "stack_trace_posix.cc" ]
+ }
+
+ if (is_nacl) {
+ sources -= [
+ "crash_logging.cc",
+ "crash_logging.h",
+ "stack_trace.cc",
+ "stack_trace_posix.cc",
+ ]
+ }
+
+ configs += [ "//base:base_implementation" ]
+
+ deps = [
+ "//base/memory",
+ "//base/process",
+ ]
+
+ if (is_linux) {
+ defines = [ "USE_SYMBOLIZE" ]
+ deps += [ "//base/third_party/symbolize" ]
+ }
+
+ allow_circular_includes_from = [
+ "//base/memory",
+ "//base/process",
+ ]
+
+ visibility = [ "//base/*" ]
+}
diff --git a/chromium/base/debug/crash_logging_unittest.cc b/chromium/base/debug/crash_logging_unittest.cc
index cb11f13f193..4cd9f3e3b09 100644
--- a/chromium/base/debug/crash_logging_unittest.cc
+++ b/chromium/base/debug/crash_logging_unittest.cc
@@ -18,14 +18,14 @@ std::map<std::string, std::string>* key_values_ = NULL;
class CrashLoggingTest : public testing::Test {
public:
- virtual void SetUp() {
+ void SetUp() override {
key_values_ = new std::map<std::string, std::string>;
base::debug::SetCrashKeyReportingFunctions(
&CrashLoggingTest::SetKeyValue,
&CrashLoggingTest::ClearKeyValue);
}
- virtual void TearDown() {
+ void TearDown() override {
base::debug::ResetCrashLoggingForTesting();
delete key_values_;
diff --git a/chromium/base/debug/debugger.h b/chromium/base/debug/debugger.h
index d62ea3f7e17..8680e281ed1 100644
--- a/chromium/base/debug/debugger.h
+++ b/chromium/base/debug/debugger.h
@@ -6,8 +6,8 @@
// debuggers. You should use this to test if you're running under a debugger,
// and if you would like to yield (breakpoint) into the debugger.
-#ifndef BASE_DEBUG_DEBUGGER_H
-#define BASE_DEBUG_DEBUGGER_H
+#ifndef BASE_DEBUG_DEBUGGER_H_
+#define BASE_DEBUG_DEBUGGER_H_
#include "base/base_export.h"
@@ -41,4 +41,4 @@ BASE_EXPORT bool IsDebugUISuppressed();
} // namespace debug
} // namespace base
-#endif // BASE_DEBUG_DEBUGGER_H
+#endif // BASE_DEBUG_DEBUGGER_H_
diff --git a/chromium/base/debug/debugger_unittest.cc b/chromium/base/debug/debugger_unittest.cc
new file mode 100644
index 00000000000..0a5a0390e8a
--- /dev/null
+++ b/chromium/base/debug/debugger_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+void CrashWithBreakDebugger() {
+ base::debug::SetSuppressDebugUI(false);
+ base::debug::BreakDebugger();
+
+#if defined(OS_WIN)
+ // This should not be executed.
+ _exit(125);
+#endif
+}
+#endif // defined(GTEST_HAS_DEATH_TEST)
+
+} // namespace
+
+// Death tests misbehave on Android.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+TEST(Debugger, CrashAtBreakpoint) {
+ EXPECT_DEATH(CrashWithBreakDebugger(), "");
+}
+
+#if defined(OS_WIN)
+TEST(Debugger, DoesntExecuteBeyondBreakpoint) {
+ EXPECT_EXIT(CrashWithBreakDebugger(),
+ ::testing::ExitedWithCode(0x80000003), "");
+}
+#endif // defined(OS_WIN)
+
+#else // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+TEST(Debugger, NoTest) {
+}
+#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
diff --git a/chromium/base/debug/debugger_win.cc b/chromium/base/debug/debugger_win.cc
index ccc9c1604bc..a1d86e4453d 100644
--- a/chromium/base/debug/debugger_win.cc
+++ b/chromium/base/debug/debugger_win.cc
@@ -17,10 +17,8 @@ bool BeingDebugged() {
void BreakDebugger() {
if (IsDebugUISuppressed())
_exit(1);
+
__debugbreak();
-#if defined(NDEBUG)
- _exit(1);
-#endif
}
} // namespace debug
diff --git a/chromium/base/debug/leak_annotations.h b/chromium/base/debug/leak_annotations.h
index 27fe663bddb..ef37959aadc 100644
--- a/chromium/base/debug/leak_annotations.h
+++ b/chromium/base/debug/leak_annotations.h
@@ -21,15 +21,7 @@
#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
-// Public LSan API from <sanitizer/lsan_interface.h>.
-extern "C" {
-void __lsan_disable();
-void __lsan_enable();
-void __lsan_ignore_object(const void *p);
-
-// Invoke leak detection immediately. If leaks are found, the process will exit.
-void __lsan_do_leak_check();
-} // extern "C"
+#include <sanitizer/lsan_interface.h>
class ScopedLeakSanitizerDisabler {
public:
@@ -46,7 +38,6 @@ class ScopedLeakSanitizerDisabler {
#else
-// If neither HeapChecker nor LSan are used, the annotations should be no-ops.
#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
diff --git a/chromium/base/debug/proc_maps_linux_unittest.cc b/chromium/base/debug/proc_maps_linux_unittest.cc
index d5d1b835f4e..cbc0dd036ad 100644
--- a/chromium/base/debug/proc_maps_linux_unittest.cc
+++ b/chromium/base/debug/proc_maps_linux_unittest.cc
@@ -7,6 +7,7 @@
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -180,23 +181,23 @@ TEST(ProcMapsTest, Permissions) {
}
}
-TEST(ProcMapsTest, ReadProcMaps) {
- std::string proc_maps;
- ASSERT_TRUE(ReadProcMaps(&proc_maps));
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
- ASSERT_FALSE(regions.empty());
-
+#if defined(ADDRESS_SANITIZER)
+// AddressSanitizer may move local variables to a dedicated "fake stack" which
+// is outside the stack region listed in /proc/self/maps. We disable ASan
+// instrumentation for this function to force the variable to be local.
+__attribute__((no_sanitize_address))
+#endif
+void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> &regions) {
// We should be able to find both the current executable as well as the stack
- // mapped into memory. Use the address of |proc_maps| as a way of finding the
+ // mapped into memory. Use the address of |exe_path| as a way of finding the
// stack.
FilePath exe_path;
EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path));
- uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps);
+ uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path);
bool found_exe = false;
bool found_stack = false;
bool found_address = false;
+
for (size_t i = 0; i < regions.size(); ++i) {
if (regions[i].path == exe_path.value()) {
// It's OK to find the executable mapped multiple times as there'll be
@@ -204,14 +205,25 @@ TEST(ProcMapsTest, ReadProcMaps) {
found_exe = true;
}
- if (regions[i].path == "[stack]") {
- // Only check if |address| lies within the real stack when not running
- // Valgrind, otherwise |address| will be on a stack that Valgrind creates.
- if (!RunningOnValgrind()) {
- EXPECT_GE(address, regions[i].start);
- EXPECT_LT(address, regions[i].end);
- }
-
+ // Valgrind uses its own allocated stacks instead of the kernel-provided
+ // stack without letting the kernel know via prctl(PR_SET_MM_START_STACK).
+ // Depending on which kernel you're running it'll impact the output of
+ // /proc/self/maps.
+ //
+ // Prior to version 3.4, the kernel completely ignores other stacks and
+ // always prints out the vma lying within mm->start_stack as [stack] even
+ // if the program was currently executing on a different stack.
+ //
+ // Starting in 3.4, the kernel will print out the vma containing the current
+ // stack pointer as [stack:TID] as long as that vma does not lie within
+ // mm->start_stack.
+ //
+ // Because this has gotten too complicated and brittle of a test, completely
+ // ignore checking for the stack and address when running under Valgrind.
+ // See http://crbug.com/431702 for more details.
+ if (!RunningOnValgrind() && regions[i].path == "[stack]") {
+ EXPECT_GE(address, regions[i].start);
+ EXPECT_LT(address, regions[i].end);
EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ);
EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE);
EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE);
@@ -227,8 +239,21 @@ TEST(ProcMapsTest, ReadProcMaps) {
}
EXPECT_TRUE(found_exe);
- EXPECT_TRUE(found_stack);
- EXPECT_TRUE(found_address);
+ if (!RunningOnValgrind()) {
+ EXPECT_TRUE(found_stack);
+ EXPECT_TRUE(found_address);
+ }
+}
+
+TEST(ProcMapsTest, ReadProcMaps) {
+ std::string proc_maps;
+ ASSERT_TRUE(ReadProcMaps(&proc_maps));
+
+ std::vector<MappedMemoryRegion> regions;
+ ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
+ ASSERT_FALSE(regions.empty());
+
+ CheckProcMapsRegions(regions);
}
TEST(ProcMapsTest, ReadProcMapsNonEmptyString) {
diff --git a/chromium/base/debug/profiler.h b/chromium/base/debug/profiler.h
index e1dda897426..2920d8a2fbe 100644
--- a/chromium/base/debug/profiler.h
+++ b/chromium/base/debug/profiler.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEBUG_PROFILER_H
-#define BASE_DEBUG_PROFILER_H
+#ifndef BASE_DEBUG_PROFILER_H_
+#define BASE_DEBUG_PROFILER_H_
#include <string>
@@ -87,4 +87,4 @@ BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
} // namespace debug
} // namespace base
-#endif // BASE_DEBUG_DEBUGGER_H
+#endif // BASE_DEBUG_PROFILER_H_
diff --git a/chromium/base/debug/stack_trace.h b/chromium/base/debug/stack_trace.h
index 572f285beba..fb271b6da4a 100644
--- a/chromium/base/debug/stack_trace.h
+++ b/chromium/base/debug/stack_trace.h
@@ -17,6 +17,7 @@
#if defined(OS_WIN)
struct _EXCEPTION_POINTERS;
+struct _CONTEXT;
#endif
namespace base {
@@ -54,6 +55,7 @@ class BASE_EXPORT StackTrace {
// Note: this function will throw an import not found (StackWalk64) exception
// on system without dbghelp 5.1.
StackTrace(const _EXCEPTION_POINTERS* exception_pointers);
+ StackTrace(const _CONTEXT* context);
#endif
// Copying and assignment are allowed with the default functions.
@@ -76,6 +78,10 @@ class BASE_EXPORT StackTrace {
std::string ToString() const;
private:
+#if defined(OS_WIN)
+ void InitTrace(_CONTEXT* context_record);
+#endif
+
// From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
// the sum of FramesToSkip and FramesToCapture must be less than 63,
// so set it to 62. Even if on POSIX it could be a larger value, it usually
diff --git a/chromium/base/debug/stack_trace_unittest.cc b/chromium/base/debug/stack_trace_unittest.cc
index eb0bd9ad7f3..15c90939a2e 100644
--- a/chromium/base/debug/stack_trace_unittest.cc
+++ b/chromium/base/debug/stack_trace_unittest.cc
@@ -146,9 +146,11 @@ MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) {
// and e.g. mismatched new[]/delete would cause a hang because
// of re-entering malloc.
TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {
- ProcessHandle child = SpawnChild("MismatchedMallocChildProcess");
- ASSERT_NE(kNullProcessHandle, child);
- ASSERT_TRUE(WaitForSingleProcess(child, TestTimeouts::action_timeout()));
+ Process child = SpawnChild("MismatchedMallocChildProcess");
+ ASSERT_TRUE(child.IsValid());
+ int exit_code;
+ ASSERT_TRUE(child.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
+ &exit_code));
}
#endif // !defined(OS_IOS)
diff --git a/chromium/base/debug/stack_trace_win.cc b/chromium/base/debug/stack_trace_win.cc
index 8df6fc6e3e6..55d55624088 100644
--- a/chromium/base/debug/stack_trace_win.cc
+++ b/chromium/base/debug/stack_trace_win.cc
@@ -152,10 +152,6 @@ class SymbolContext {
init_error_ = ERROR_SUCCESS;
- // Work around a mysterious hang on Windows XP.
- if (base::win::GetVersion() < base::win::VERSION_VISTA)
- return;
-
// When transferring the binaries e.g. between bots, path put
// into the executable will get off. To still retrieve symbols correctly,
// add the directory of the executable to symbol search path.
@@ -214,24 +210,35 @@ StackTrace::StackTrace() {
#endif
StackTrace::StackTrace(const EXCEPTION_POINTERS* exception_pointers) {
- // When walking an exception stack, we need to use StackWalk64().
- count_ = 0;
// StackWalk64() may modify context record passed to it, so we will
// use a copy.
CONTEXT context_record = *exception_pointers->ContextRecord;
+ InitTrace(&context_record);
+}
+
+StackTrace::StackTrace(const CONTEXT* context) {
+ // StackWalk64() may modify context record passed to it, so we will
+ // use a copy.
+ CONTEXT context_record = *context;
+ InitTrace(&context_record);
+}
+
+void StackTrace::InitTrace(CONTEXT* context_record) {
+ // When walking an exception stack, we need to use StackWalk64().
+ count_ = 0;
// Initialize stack walking.
STACKFRAME64 stack_frame;
memset(&stack_frame, 0, sizeof(stack_frame));
#if defined(_WIN64)
int machine_type = IMAGE_FILE_MACHINE_AMD64;
- stack_frame.AddrPC.Offset = context_record.Rip;
- stack_frame.AddrFrame.Offset = context_record.Rbp;
- stack_frame.AddrStack.Offset = context_record.Rsp;
+ stack_frame.AddrPC.Offset = context_record->Rip;
+ stack_frame.AddrFrame.Offset = context_record->Rbp;
+ stack_frame.AddrStack.Offset = context_record->Rsp;
#else
int machine_type = IMAGE_FILE_MACHINE_I386;
- stack_frame.AddrPC.Offset = context_record.Eip;
- stack_frame.AddrFrame.Offset = context_record.Ebp;
- stack_frame.AddrStack.Offset = context_record.Esp;
+ stack_frame.AddrPC.Offset = context_record->Eip;
+ stack_frame.AddrFrame.Offset = context_record->Ebp;
+ stack_frame.AddrStack.Offset = context_record->Esp;
#endif
stack_frame.AddrPC.Mode = AddrModeFlat;
stack_frame.AddrFrame.Mode = AddrModeFlat;
@@ -240,7 +247,7 @@ StackTrace::StackTrace(const EXCEPTION_POINTERS* exception_pointers) {
GetCurrentProcess(),
GetCurrentThread(),
&stack_frame,
- &context_record,
+ context_record,
NULL,
&SymFunctionTableAccess64,
&SymGetModuleBase64,
diff --git a/chromium/base/debug/task_annotator.cc b/chromium/base/debug/task_annotator.cc
index ae2d7975c2e..19df8cb39e5 100644
--- a/chromium/base/debug/task_annotator.cc
+++ b/chromium/base/debug/task_annotator.cc
@@ -5,8 +5,8 @@
#include "base/debug/task_annotator.h"
#include "base/debug/alias.h"
-#include "base/debug/trace_event.h"
#include "base/pending_task.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
namespace base {
@@ -28,7 +28,6 @@ void TaskAnnotator::DidQueueTask(const char* queue_function,
void TaskAnnotator::RunTask(const char* queue_function,
const char* run_function,
const PendingTask& pending_task) {
- tracked_objects::ThreadData::PrepareForStartOfRun(pending_task.birth_tally);
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
tracked_objects::Duration queue_duration =
diff --git a/chromium/base/debug/trace_event_unittest.h b/chromium/base/debug/trace_event_unittest.h
deleted file mode 100644
index 599fec7dcd8..00000000000
--- a/chromium/base/debug/trace_event_unittest.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2012 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/time/time.h"
-
-namespace base {
-namespace debug {
-
-// Sleep until HighResNow has advanced by at least |elapsed|.
-void HighResSleepForTraceTest(base::TimeDelta elapsed);
-
-} // namespace debug
-} // namespace base
diff --git a/chromium/base/deferred_sequenced_task_runner.h b/chromium/base/deferred_sequenced_task_runner.h
index bc8db7a9fde..110d988615d 100644
--- a/chromium/base/deferred_sequenced_task_runner.h
+++ b/chromium/base/deferred_sequenced_task_runner.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_
-#define BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_
+#ifndef BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
+#define BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
#include <vector>
@@ -75,4 +75,4 @@ class BASE_EXPORT DeferredSequencedTaskRunner : public SequencedTaskRunner {
} // namespace base
-#endif // BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_
+#endif // BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
diff --git a/chromium/base/deferred_sequenced_task_runner_unittest.cc b/chromium/base/deferred_sequenced_task_runner_unittest.cc
index 81f2a0a00c9..6e17ad93a8f 100644
--- a/chromium/base/deferred_sequenced_task_runner_unittest.cc
+++ b/chromium/base/deferred_sequenced_task_runner_unittest.cc
@@ -7,9 +7,9 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -58,11 +58,9 @@ class DeferredSequencedTaskRunnerTest : public testing::Test,
}
protected:
- DeferredSequencedTaskRunnerTest() :
- loop_(),
- runner_(
- new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) {
- }
+ DeferredSequencedTaskRunnerTest()
+ : loop_(),
+ runner_(new base::DeferredSequencedTaskRunner(loop_.task_runner())) {}
base::MessageLoop loop_;
scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
@@ -126,21 +124,18 @@ TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) {
thread1.Start();
thread2.Start();
for (int i = 0; i < 5; ++i) {
- thread1.message_loop()->PostTask(
+ thread1.task_runner()->PostTask(
FROM_HERE,
base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
- base::Unretained(this),
- 2 * i));
- thread2.message_loop()->PostTask(
+ base::Unretained(this), 2 * i));
+ thread2.task_runner()->PostTask(
FROM_HERE,
base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
- base::Unretained(this),
- 2 * i + 1));
+ base::Unretained(this), 2 * i + 1));
if (i == 2) {
- thread1.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
- base::Unretained(this)));
+ thread1.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
+ base::Unretained(this)));
}
}
}
@@ -154,8 +149,7 @@ TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) {
{
base::Thread thread("DeferredSequencedTaskRunnerTestThread");
thread.Start();
- runner_ =
- new base::DeferredSequencedTaskRunner(thread.message_loop_proxy());
+ runner_ = new base::DeferredSequencedTaskRunner(thread.task_runner());
for (int i = 0; i < 5; ++i) {
{
// Use a block to ensure that no reference to |short_lived_object|
diff --git a/chromium/base/event_recorder.h b/chromium/base/event_recorder.h
deleted file mode 100644
index bff87ed494b..00000000000
--- a/chromium/base/event_recorder.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_EVENT_RECORDER_H_
-#define BASE_EVENT_RECORDER_H_
-
-#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <stdio.h>
-#include <string.h>
-#include <windows.h>
-#endif
-
-namespace base {
-
-class FilePath;
-
-// A class for recording and playing back keyboard and mouse input events.
-//
-// Note - if you record events, and the playback with the windows in
-// different sizes or positions, the playback will fail. When
-// recording and playing, you should move the relevant windows
-// to constant sizes and locations.
-// TODO(mbelshe) For now this is a singleton. I believe that this class
-// could be easily modified to:
-// support two simultaneous recorders
-// be playing back events while already recording events.
-// Why? Imagine if the product had a "record a macro" feature.
-// You might be recording globally, while recording or playing back
-// a macro. I don't think two playbacks make sense.
-class BASE_EXPORT EventRecorder {
- public:
- // Get the singleton EventRecorder.
- // We can only handle one recorder/player at a time.
- static EventRecorder* current() {
- if (!current_)
- current_ = new EventRecorder();
- return current_;
- }
-
- // Starts recording events.
- // Will clobber the file if it already exists.
- // Returns true on success, or false if an error occurred.
- bool StartRecording(const FilePath& filename);
-
- // Stops recording.
- void StopRecording();
-
- // Is the EventRecorder currently recording.
- bool is_recording() const { return is_recording_; }
-
- // Plays events previously recorded.
- // Returns true on success, or false if an error occurred.
- bool StartPlayback(const FilePath& filename);
-
- // Stops playback.
- void StopPlayback();
-
- // Is the EventRecorder currently playing.
- bool is_playing() const { return is_playing_; }
-
-#if defined(OS_WIN)
- // C-style callbacks for the EventRecorder.
- // Used for internal purposes only.
- LRESULT RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam);
- LRESULT PlaybackWndProc(int nCode, WPARAM wParam, LPARAM lParam);
-#endif
-
- private:
- // Create a new EventRecorder. Events are saved to the file filename.
- // If the file already exists, it will be deleted before recording
- // starts.
- EventRecorder()
- : is_recording_(false),
- is_playing_(false),
-#if defined(OS_WIN)
- journal_hook_(NULL),
- file_(NULL),
-#endif
- playback_first_msg_time_(0),
- playback_start_time_(0) {
-#if defined(OS_WIN)
- memset(&playback_msg_, 0, sizeof(playback_msg_));
-#endif
- }
- ~EventRecorder();
-
- static EventRecorder* current_; // Our singleton.
-
- bool is_recording_;
- bool is_playing_;
-#if defined(OS_WIN)
- HHOOK journal_hook_;
- FILE* file_;
- EVENTMSG playback_msg_;
-#endif
- int playback_first_msg_time_;
- int playback_start_time_;
-
- DISALLOW_COPY_AND_ASSIGN(EventRecorder);
-};
-
-} // namespace base
-
-#endif // BASE_EVENT_RECORDER_H_
diff --git a/chromium/base/event_recorder_stubs.cc b/chromium/base/event_recorder_stubs.cc
deleted file mode 100644
index 91f2e072fc9..00000000000
--- a/chromium/base/event_recorder_stubs.cc
+++ /dev/null
@@ -1,28 +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/event_recorder.h"
-
-// This file implements a link stub for EventRecorder that can be used on
-// platforms that don't have a working EventRecorder implementation.
-
-namespace base {
-
-EventRecorder* EventRecorder::current_; // Our singleton.
-
-bool EventRecorder::StartRecording(const FilePath& filename) {
- return true;
-}
-
-void EventRecorder::StopRecording() {
-}
-
-bool EventRecorder::StartPlayback(const FilePath& filename) {
- return false;
-}
-
-void EventRecorder::StopPlayback() {
-}
-
-} // namespace
diff --git a/chromium/base/event_recorder_win.cc b/chromium/base/event_recorder_win.cc
deleted file mode 100644
index b3076a11318..00000000000
--- a/chromium/base/event_recorder_win.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-#include <windows.h>
-#include <mmsystem.h>
-
-#include "base/event_recorder.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-
-// A note about time.
-// For perfect playback of events, you'd like a very accurate timer
-// so that events are played back at exactly the same time that
-// they were recorded. However, windows has a clock which is only
-// granular to ~15ms. We see more consistent event playback when
-// using a higher resolution timer. To do this, we use the
-// timeGetTime API instead of the default GetTickCount() API.
-
-namespace base {
-
-EventRecorder* EventRecorder::current_ = NULL;
-
-LRESULT CALLBACK StaticRecordWndProc(int nCode, WPARAM wParam,
- LPARAM lParam) {
- DCHECK(EventRecorder::current());
- return EventRecorder::current()->RecordWndProc(nCode, wParam, lParam);
-}
-
-LRESULT CALLBACK StaticPlaybackWndProc(int nCode, WPARAM wParam,
- LPARAM lParam) {
- DCHECK(EventRecorder::current());
- return EventRecorder::current()->PlaybackWndProc(nCode, wParam, lParam);
-}
-
-EventRecorder::~EventRecorder() {
- // Try to assert early if the caller deletes the recorder
- // while it is still in use.
- DCHECK(!journal_hook_);
- DCHECK(!is_recording_ && !is_playing_);
-}
-
-bool EventRecorder::StartRecording(const FilePath& filename) {
- if (journal_hook_ != NULL)
- return false;
- if (is_recording_ || is_playing_)
- return false;
-
- // Open the recording file.
- DCHECK(!file_);
- file_ = OpenFile(filename, "wb+");
- if (!file_) {
- DLOG(ERROR) << "EventRecorder could not open log file";
- return false;
- }
-
- // Set the faster clock, if possible.
- ::timeBeginPeriod(1);
-
- // Set the recording hook. JOURNALRECORD can only be used as a global hook.
- journal_hook_ = ::SetWindowsHookEx(WH_JOURNALRECORD, StaticRecordWndProc,
- GetModuleHandle(NULL), 0);
- if (!journal_hook_) {
- DLOG(ERROR) << "EventRecorder Record Hook failed";
- CloseFile(file_);
- return false;
- }
-
- is_recording_ = true;
- return true;
-}
-
-void EventRecorder::StopRecording() {
- if (is_recording_) {
- DCHECK(journal_hook_ != NULL);
-
- if (!::UnhookWindowsHookEx(journal_hook_)) {
- DLOG(ERROR) << "EventRecorder Unhook failed";
- // Nothing else we can really do here.
- return;
- }
-
- ::timeEndPeriod(1);
-
- DCHECK(file_ != NULL);
- CloseFile(file_);
- file_ = NULL;
-
- journal_hook_ = NULL;
- is_recording_ = false;
- }
-}
-
-bool EventRecorder::StartPlayback(const FilePath& filename) {
- if (journal_hook_ != NULL)
- return false;
- if (is_recording_ || is_playing_)
- return false;
-
- // Open the recording file.
- DCHECK(!file_);
- file_ = OpenFile(filename, "rb");
- if (!file_) {
- DLOG(ERROR) << "EventRecorder Playback could not open log file";
- return false;
- }
- // Read the first event from the record.
- if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1) {
- DLOG(ERROR) << "EventRecorder Playback has no records!";
- CloseFile(file_);
- return false;
- }
-
- // Set the faster clock, if possible.
- ::timeBeginPeriod(1);
-
- // Playback time is tricky. When playing back, we read a series of events,
- // each with timeouts. Simply subtracting the delta between two timers will
- // lead to fast playback (about 2x speed). The API has two events, one
- // which advances to the next event (HC_SKIP), and another that requests the
- // event (HC_GETNEXT). The same event will be requested multiple times.
- // Each time the event is requested, we must calculate the new delay.
- // To do this, we track the start time of the playback, and constantly
- // re-compute the delay. I mention this only because I saw two examples
- // of how to use this code on the net, and both were broken :-)
- playback_start_time_ = timeGetTime();
- playback_first_msg_time_ = playback_msg_.time;
-
- // Set the hook. JOURNALPLAYBACK can only be used as a global hook.
- journal_hook_ = ::SetWindowsHookEx(WH_JOURNALPLAYBACK, StaticPlaybackWndProc,
- GetModuleHandle(NULL), 0);
- if (!journal_hook_) {
- DLOG(ERROR) << "EventRecorder Playback Hook failed";
- return false;
- }
-
- is_playing_ = true;
-
- return true;
-}
-
-void EventRecorder::StopPlayback() {
- if (is_playing_) {
- DCHECK(journal_hook_ != NULL);
-
- if (!::UnhookWindowsHookEx(journal_hook_)) {
- DLOG(ERROR) << "EventRecorder Unhook failed";
- // Nothing else we can really do here.
- }
-
- DCHECK(file_ != NULL);
- CloseFile(file_);
- file_ = NULL;
-
- ::timeEndPeriod(1);
-
- journal_hook_ = NULL;
- is_playing_ = false;
- }
-}
-
-// Windows callback hook for the recorder.
-LRESULT EventRecorder::RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
- static bool recording_enabled = true;
- EVENTMSG* msg_ptr = NULL;
-
- // The API says we have to do this.
- // See http://msdn2.microsoft.com/en-us/library/ms644983(VS.85).aspx
- if (nCode < 0)
- return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
-
- // Check for the break key being pressed and stop recording.
- if (::GetKeyState(VK_CANCEL) & 0x8000) {
- StopRecording();
- return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
- }
-
- // The Journal Recorder must stop recording events when system modal
- // dialogs are present. (see msdn link above)
- switch (nCode) {
- case HC_SYSMODALON:
- recording_enabled = false;
- break;
- case HC_SYSMODALOFF:
- recording_enabled = true;
- break;
- }
-
- if (nCode == HC_ACTION && recording_enabled) {
- // Aha - we have an event to record.
- msg_ptr = reinterpret_cast<EVENTMSG*>(lParam);
- msg_ptr->time = timeGetTime();
- fwrite(msg_ptr, sizeof(EVENTMSG), 1, file_);
- fflush(file_);
- }
-
- return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
-}
-
-// Windows callback for the playback mode.
-LRESULT EventRecorder::PlaybackWndProc(int nCode, WPARAM wParam,
- LPARAM lParam) {
- static bool playback_enabled = true;
- int delay = 0;
-
- switch (nCode) {
- // A system modal dialog box is being displayed. Stop playing back
- // messages.
- case HC_SYSMODALON:
- playback_enabled = false;
- break;
-
- // A system modal dialog box is destroyed. We can start playing back
- // messages again.
- case HC_SYSMODALOFF:
- playback_enabled = true;
- break;
-
- // Prepare to copy the next mouse or keyboard event to playback.
- case HC_SKIP:
- if (!playback_enabled)
- break;
-
- // Read the next event from the record.
- if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1)
- this->StopPlayback();
- break;
-
- // Copy the mouse or keyboard event to the EVENTMSG structure in lParam.
- case HC_GETNEXT:
- if (!playback_enabled)
- break;
-
- memcpy(reinterpret_cast<void*>(lParam), &playback_msg_,
- sizeof(playback_msg_));
-
- // The return value is the amount of time (in milliseconds) to wait
- // before playing back the next message in the playback queue. Each
- // time this is called, we recalculate the delay relative to our current
- // wall clock.
- delay = (playback_msg_.time - playback_first_msg_time_) -
- (timeGetTime() - playback_start_time_);
- if (delay < 0)
- delay = 0;
- return delay;
-
- // An application has called PeekMessage with wRemoveMsg set to PM_NOREMOVE
- // indicating that the message is not removed from the message queue after
- // PeekMessage processing.
- case HC_NOREMOVE:
- break;
- }
-
- return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
-}
-
-} // namespace base
diff --git a/chromium/base/event_types.h b/chromium/base/event_types.h
index af586e46ec9..9905800d2e8 100644
--- a/chromium/base/event_types.h
+++ b/chromium/base/event_types.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_EVENT_TYPES_H
-#define BASE_EVENT_TYPES_H
+#ifndef BASE_EVENT_TYPES_H_
+#define BASE_EVENT_TYPES_H_
#include "build/build_config.h"
@@ -34,4 +34,4 @@ typedef void* NativeEvent;
} // namespace base
-#endif // BASE_EVENT_TYPES_H
+#endif // BASE_EVENT_TYPES_H_
diff --git a/chromium/base/file_version_info.h b/chromium/base/file_version_info.h
index e18ba1367f0..57b837c24b0 100644
--- a/chromium/base/file_version_info.h
+++ b/chromium/base/file_version_info.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_FILE_VERSION_INFO_H__
-#define BASE_FILE_VERSION_INFO_H__
+#ifndef BASE_FILE_VERSION_INFO_H_
+#define BASE_FILE_VERSION_INFO_H_
#include "build/build_config.h"
@@ -32,22 +32,21 @@ class FilePath;
// version returns values from the Info.plist as appropriate. TODO(avi): make
// this a less-obvious Windows-ism.
-class FileVersionInfo {
+class BASE_EXPORT FileVersionInfo {
public:
virtual ~FileVersionInfo() {}
#if defined(OS_WIN) || defined(OS_MACOSX)
// Creates a FileVersionInfo for the specified path. Returns NULL if something
// goes wrong (typically the file does not exit or cannot be opened). The
// returned object should be deleted when you are done with it.
- BASE_EXPORT static FileVersionInfo* CreateFileVersionInfo(
+ static FileVersionInfo* CreateFileVersionInfo(
const base::FilePath& file_path);
#endif // OS_WIN || OS_MACOSX
#if defined(OS_WIN)
// Creates a FileVersionInfo for the specified module. Returns NULL in case
// of error. The returned object should be deleted when you are done with it.
- BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForModule(
- HMODULE module);
+ static FileVersionInfo* CreateFileVersionInfoForModule(HMODULE module);
// 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.
@@ -61,7 +60,7 @@ class FileVersionInfo {
#else
// 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.
- BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
+ static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
#endif // OS_WIN
// Accessors to the different version properties.
@@ -84,4 +83,4 @@ class FileVersionInfo {
virtual bool is_official_build() = 0;
};
-#endif // BASE_FILE_VERSION_INFO_H__
+#endif // BASE_FILE_VERSION_INFO_H_
diff --git a/chromium/base/file_version_info_mac.h b/chromium/base/file_version_info_mac.h
index a18dbbdbefb..e67783834df 100644
--- a/chromium/base/file_version_info_mac.h
+++ b/chromium/base/file_version_info_mac.h
@@ -5,16 +5,13 @@
#ifndef BASE_FILE_VERSION_INFO_MAC_H_
#define BASE_FILE_VERSION_INFO_MAC_H_
+#include <CoreFoundation/CoreFoundation.h>
#include <string>
#include "base/file_version_info.h"
#include "base/mac/scoped_nsobject.h"
-#ifdef __OBJC__
@class NSBundle;
-#else
-class NSBundle;
-#endif
class FileVersionInfoMac : public FileVersionInfo {
public:
diff --git a/chromium/base/file_version_info_win.h b/chromium/base/file_version_info_win.h
index 0e0f271a32b..09d8d37cc0c 100644
--- a/chromium/base/file_version_info_win.h
+++ b/chromium/base/file_version_info_win.h
@@ -15,36 +15,36 @@
struct tagVS_FIXEDFILEINFO;
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
-class FileVersionInfoWin : public FileVersionInfo {
+class BASE_EXPORT FileVersionInfoWin : public FileVersionInfo {
public:
- BASE_EXPORT FileVersionInfoWin(void* data, WORD language, WORD code_page);
- BASE_EXPORT ~FileVersionInfoWin();
+ FileVersionInfoWin(void* data, WORD language, WORD code_page);
+ ~FileVersionInfoWin() override;
// Accessors to the different version properties.
// Returns an empty string if the property is not found.
- virtual base::string16 company_name() override;
- virtual base::string16 company_short_name() override;
- virtual base::string16 product_name() override;
- virtual base::string16 product_short_name() override;
- virtual base::string16 internal_name() override;
- virtual base::string16 product_version() override;
- virtual base::string16 private_build() override;
- virtual base::string16 special_build() override;
- virtual base::string16 comments() override;
- virtual base::string16 original_filename() override;
- virtual base::string16 file_description() override;
- virtual base::string16 file_version() override;
- virtual base::string16 legal_copyright() override;
- virtual base::string16 legal_trademarks() override;
- virtual base::string16 last_change() override;
- virtual bool is_official_build() override;
+ base::string16 company_name() override;
+ base::string16 company_short_name() override;
+ base::string16 product_name() override;
+ base::string16 product_short_name() override;
+ base::string16 internal_name() override;
+ base::string16 product_version() override;
+ base::string16 private_build() override;
+ base::string16 special_build() override;
+ base::string16 comments() override;
+ base::string16 original_filename() override;
+ base::string16 file_description() override;
+ base::string16 file_version() override;
+ base::string16 legal_copyright() override;
+ base::string16 legal_trademarks() override;
+ base::string16 last_change() override;
+ bool is_official_build() override;
// Lets you access other properties not covered above.
- BASE_EXPORT bool GetValue(const wchar_t* name, std::wstring* value);
+ bool GetValue(const wchar_t* name, std::wstring* value);
// Similar to GetValue but returns a wstring (empty string if the property
// does not exist).
- BASE_EXPORT std::wstring GetStringValue(const wchar_t* name);
+ std::wstring GetStringValue(const wchar_t* name);
// Get the fixed file info if it exists. Otherwise NULL
VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; }
diff --git a/chromium/base/files/dir_reader_linux.h b/chromium/base/files/dir_reader_linux.h
index cb0cbd38e56..abf259530b3 100644
--- a/chromium/base/files/dir_reader_linux.h
+++ b/chromium/base/files/dir_reader_linux.h
@@ -95,4 +95,4 @@ class DirReaderLinux {
} // namespace base
-#endif // BASE_FILES_DIR_READER_LINUX_H_
+#endif // BASE_FILES_DIR_READER_LINUX_H_
diff --git a/chromium/base/files/dir_reader_posix.h b/chromium/base/files/dir_reader_posix.h
index 6a20ced0223..6a32d9fd480 100644
--- a/chromium/base/files/dir_reader_posix.h
+++ b/chromium/base/files/dir_reader_posix.h
@@ -33,4 +33,4 @@ typedef DirReaderFallback DirReaderPosix;
} // namespace base
-#endif // BASE_FILES_DIR_READER_POSIX_H_
+#endif // BASE_FILES_DIR_READER_POSIX_H_
diff --git a/chromium/base/files/file.cc b/chromium/base/files/file.cc
index ea8dbf27ac1..58f80c52322 100644
--- a/chromium/base/files/file.cc
+++ b/chromium/base/files/file.cc
@@ -4,6 +4,9 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
+#include "base/files/file_tracing.h"
+#include "base/metrics/histogram.h"
+#include "base/timer/elapsed_timer.h"
namespace base {
@@ -23,11 +26,11 @@ File::File()
}
#if !defined(OS_NACL)
-File::File(const FilePath& name, uint32 flags)
+File::File(const FilePath& path, uint32 flags)
: error_details_(FILE_OK),
created_(false),
async_(false) {
- Initialize(name, flags);
+ Initialize(path, flags);
}
#endif
@@ -49,6 +52,7 @@ File::File(Error error_details)
File::File(RValue other)
: file_(other.object->TakePlatformFile()),
+ path_(other.object->path_),
error_details_(other.object->error_details()),
created_(other.object->created()),
async_(other.object->async_) {
@@ -63,6 +67,7 @@ File& File::operator=(RValue other) {
if (this != other.object) {
Close();
SetPlatformFile(other.object->TakePlatformFile());
+ path_ = other.object->path_;
error_details_ = other.object->error_details();
created_ = other.object->created();
async_ = other.object->async_;
@@ -71,12 +76,14 @@ File& File::operator=(RValue other) {
}
#if !defined(OS_NACL)
-void File::Initialize(const FilePath& name, uint32 flags) {
- if (name.ReferencesParent()) {
+void File::Initialize(const FilePath& path, uint32 flags) {
+ if (path.ReferencesParent()) {
error_details_ = FILE_ERROR_ACCESS_DENIED;
return;
}
- InitializeUnsafe(name, flags);
+ path_ = path;
+ SCOPED_FILE_TRACE("Initialize");
+ DoInitialize(flags);
}
#endif
@@ -124,4 +131,12 @@ std::string File::ErrorToString(Error error) {
return "";
}
+bool File::Flush() {
+ ElapsedTimer timer;
+ SCOPED_FILE_TRACE("Flush");
+ bool return_value = DoFlush();
+ UMA_HISTOGRAM_TIMES("PlatformFile.FlushTime", timer.Elapsed());
+ return return_value;
+}
+
} // namespace base
diff --git a/chromium/base/files/file.h b/chromium/base/files/file.h
index 7b6366c1c2e..b21b15972bc 100644
--- a/chromium/base/files/file.h
+++ b/chromium/base/files/file.h
@@ -18,6 +18,8 @@
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/files/file_tracing.h"
#include "base/files/scoped_file.h"
#include "base/gtest_prod_util.h"
#include "base/move.h"
@@ -31,8 +33,6 @@ FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
namespace base {
-class FilePath;
-
#if defined(OS_WIN)
typedef HANDLE PlatformFile;
#elif defined(OS_POSIX)
@@ -128,9 +128,9 @@ class BASE_EXPORT File {
// Used to hold information about a given file.
// If you add more fields to this structure (platform-specific fields are OK),
- // make sure to update all functions that use it in file_util_{win|posix}.cc
- // too, and the ParamTraits<base::PlatformFileInfo> implementation in
- // chrome/common/common_param_traits.cc.
+ // make sure to update all functions that use it in file_util_{win|posix}.cc,
+ // too, and the ParamTraits<base::File::Info> implementation in
+ // ipc/ipc_message_utils.cc.
struct BASE_EXPORT Info {
Info();
~Info();
@@ -145,24 +145,25 @@ class BASE_EXPORT File {
// True if the file corresponds to a directory.
bool is_directory;
- // True if the file corresponds to a symbolic link.
+ // True if the file corresponds to a symbolic link. For Windows currently
+ // not supported and thus always false.
bool is_symbolic_link;
// The last modified time of a file.
- base::Time last_modified;
+ Time last_modified;
// The last accessed time of a file.
- base::Time last_accessed;
+ Time last_accessed;
// The creation time of a file.
- base::Time creation_time;
+ Time creation_time;
};
File();
// Creates or opens the given file. This will fail with 'access denied' if the
- // |name| contains path traversal ('..') components.
- File(const FilePath& name, uint32 flags);
+ // |path| contains path traversal ('..') components.
+ File(const FilePath& path, uint32 flags);
// Takes ownership of |platform_file|.
explicit File(PlatformFile platform_file);
@@ -179,11 +180,7 @@ class BASE_EXPORT File {
File& operator=(RValue other);
// Creates or opens the given file.
- void Initialize(const FilePath& name, uint32 flags);
-
- // Creates or opens the given file, allowing paths with traversal ('..')
- // components. Use only with extreme care.
- void InitializeUnsafe(const FilePath& name, uint32 flags);
+ void Initialize(const FilePath& path, uint32 flags);
bool IsValid() const;
@@ -194,7 +191,7 @@ class BASE_EXPORT File {
// Returns the OS result of opening this file. Note that the way to verify
// the success of the operation is to use IsValid(), not this method:
- // File file(name, flags);
+ // File file(path, flags);
// if (!file.IsValid())
// return;
Error error_details() const { return error_details_; }
@@ -287,6 +284,13 @@ class BASE_EXPORT File {
// Unlock a file previously locked.
Error Unlock();
+ // Returns a new object referencing this file for use within the current
+ // process. Handling of FLAG_DELETE_ON_CLOSE varies by OS. On POSIX, the File
+ // object that was created or initialized with this flag will have unlinked
+ // the underlying file when it was created or opened. On Windows, the
+ // underlying file is deleted when the last handle to it is closed.
+ File Duplicate();
+
bool async() const { return async_; }
#if defined(OS_WIN)
@@ -301,6 +305,8 @@ class BASE_EXPORT File {
private:
FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+ friend class FileTracing::ScopedTrace;
+
#if defined(OS_POSIX)
// Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
// alongside it. This checksum is validated at every access, allowing early
@@ -346,6 +352,14 @@ class BASE_EXPORT File {
};
#endif
+ // Creates or opens the given file. Only called if |path_| has no
+ // traversal ('..') components.
+ void DoInitialize(uint32 flags);
+
+ // TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
+ // cf. issue 473337.
+ bool DoFlush();
+
void SetPlatformFile(PlatformFile file);
#if defined(OS_WIN)
@@ -354,6 +368,12 @@ class BASE_EXPORT File {
MemoryCheckingScopedFD file_;
#endif
+ // Path that |Initialize()| was called with. Only set if safe (i.e. no '..').
+ FilePath path_;
+
+ // Object tied to the lifetime of |this| that enables/disables tracing.
+ FileTracing::ScopedEnabler trace_enabler_;
+
Error error_details_;
bool created_;
bool async_;
diff --git a/chromium/base/files/file_enumerator_win.cc b/chromium/base/files/file_enumerator_win.cc
index 6da1667ed99..931d1549816 100644
--- a/chromium/base/files/file_enumerator_win.cc
+++ b/chromium/base/files/file_enumerator_win.cc
@@ -147,7 +147,8 @@ FilePath FileEnumerator::Next() {
// add it to pending_paths_ so we scan it after we finish scanning this
// directory. However, don't do recursion through reparse points or we
// may end up with an infinite cycle.
- if (!(find_data_.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+ DWORD attributes = GetFileAttributes(cur_file.value().c_str());
+ if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
pending_paths_.push(cur_file);
}
if (file_type_ & FileEnumerator::DIRECTORIES)
diff --git a/chromium/base/files/file_path.cc b/chromium/base/files/file_path.cc
index bf37be615b1..33d5ca1b884 100644
--- a/chromium/base/files/file_path.cc
+++ b/chromium/base/files/file_path.cc
@@ -593,7 +593,7 @@ std::string FilePath::MaybeAsASCII() const {
}
std::string FilePath::AsUTF8Unsafe() const {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
return value();
#else
return WideToUTF8(SysNativeMBToWide(value()));
@@ -601,7 +601,7 @@ std::string FilePath::AsUTF8Unsafe() const {
}
string16 FilePath::AsUTF16Unsafe() const {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
return UTF8ToUTF16(value());
#else
return WideToUTF16(SysNativeMBToWide(value()));
@@ -610,7 +610,7 @@ string16 FilePath::AsUTF16Unsafe() const {
// static
FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
return FilePath(utf8);
#else
return FilePath(SysWideToNativeMB(UTF8ToWide(utf8)));
@@ -619,7 +619,7 @@ FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
// static
FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
return FilePath(UTF16ToUTF8(utf16));
#else
return FilePath(SysWideToNativeMB(UTF16ToWide(utf16)));
diff --git a/chromium/base/files/file_path.h b/chromium/base/files/file_path.h
index ad42b954927..5225b12ffd4 100644
--- a/chromium/base/files/file_path.h
+++ b/chromium/base/files/file_path.h
@@ -53,7 +53,7 @@
// between char[]-based pathnames on POSIX systems and wchar_t[]-based
// pathnames on Windows.
//
-// Paths can't contain NULs as a precaution agaist premature truncation.
+// As a precaution against premature truncation, paths can't contain NULs.
//
// Because a FilePath object should not be instantiated at the global scope,
// instead, use a FilePath::CharType[] and initialize it with
@@ -83,9 +83,9 @@
// in case it ever comes across such a system. FilePath needs this support
// for Windows UNC paths, anyway.
// References:
-// The Open Group Base Specifications Issue 7, sections 3.266 ("Pathname")
+// The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname")
// and 4.12 ("Pathname Resolution"), available at:
-// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_266
+// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12
//
// - Windows treats c:\\ the same way it treats \\. This was intended to
@@ -107,6 +107,7 @@
#include <vector>
#include "base/base_export.h"
+#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h" // For implicit conversions.
@@ -237,7 +238,7 @@ class BASE_EXPORT FilePath {
// ASSERT(new_path == path.value());
// NOTE: this is different from the original file_util implementation which
// returned the extension without a leading "." ("jpg" instead of ".jpg")
- StringType Extension() const;
+ StringType Extension() const WARN_UNUSED_RESULT;
// Returns the path's file extension, as in Extension(), but will
// never return a double extension.
@@ -246,7 +247,7 @@ class BASE_EXPORT FilePath {
// we can rename this to Extension() and the other to something like
// LongExtension(), defaulting to short extensions and leaving the
// long "extensions" to logic like base::GetUniquePathNumber().
- StringType FinalExtension() const;
+ StringType FinalExtension() const WARN_UNUSED_RESULT;
// Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
// NOTE: this is slightly different from the similar file_util implementation
@@ -442,11 +443,9 @@ BASE_EXPORT extern void PrintTo(const base::FilePath& path, std::ostream* out);
#if defined(OS_POSIX)
#define FILE_PATH_LITERAL(x) x
#define PRFilePath "s"
-#define PRFilePathLiteral "%s"
#elif defined(OS_WIN)
#define FILE_PATH_LITERAL(x) L ## x
#define PRFilePath "ls"
-#define PRFilePathLiteral L"%ls"
#endif // OS_WIN
// Provide a hash function so that hash_sets and maps can contain FilePath
diff --git a/chromium/base/files/file_path_unittest.cc b/chromium/base/files/file_path_unittest.cc
index 956faea3218..c16293861ce 100644
--- a/chromium/base/files/file_path_unittest.cc
+++ b/chromium/base/files/file_path_unittest.cc
@@ -48,15 +48,7 @@ struct UTF8TestData {
// file_util winds up using autoreleased objects on the Mac, so this needs
// to be a PlatformTest
-class FilePathTest : public PlatformTest {
- protected:
- virtual void SetUp() override {
- PlatformTest::SetUp();
- }
- virtual void TearDown() override {
- PlatformTest::TearDown();
- }
-};
+typedef PlatformTest FilePathTest;
TEST_F(FilePathTest, DirName) {
const struct UnaryTestData cases[] = {
diff --git a/chromium/base/files/file_path_watcher.cc b/chromium/base/files/file_path_watcher.cc
index b17354197d4..59ae7059caf 100644
--- a/chromium/base/files/file_path_watcher.cc
+++ b/chromium/base/files/file_path_watcher.cc
@@ -32,7 +32,7 @@ bool FilePathWatcher::RecursiveWatchAvailable() {
// FSEvents isn't available on iOS and is broken on OSX 10.6 and earlier.
// See http://crbug.com/54822#c31
return mac::IsOSLionOrLater();
-#elif defined(OS_WIN) || defined(OS_LINUX)
+#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
return true;
#else
return false;
diff --git a/chromium/base/files/file_path_watcher.h b/chromium/base/files/file_path_watcher.h
index d26fa060446..4f132aff78a 100644
--- a/chromium/base/files/file_path_watcher.h
+++ b/chromium/base/files/file_path_watcher.h
@@ -12,7 +12,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
namespace base {
@@ -58,12 +58,13 @@ class BASE_EXPORT FilePathWatcher {
// check |is_cancelled()| to avoid duplicate work.
virtual void CancelOnMessageLoopThread() = 0;
- scoped_refptr<base::MessageLoopProxy> message_loop() const {
- return message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+ return task_runner_;
}
- void set_message_loop(const scoped_refptr<base::MessageLoopProxy>& loop) {
- message_loop_ = loop;
+ void set_task_runner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ task_runner_ = task_runner.Pass();
}
// Must be called before the PlatformDelegate is deleted.
@@ -76,7 +77,7 @@ class BASE_EXPORT FilePathWatcher {
}
private:
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
bool cancelled_;
};
diff --git a/chromium/base/files/file_path_watcher_fsevents.cc b/chromium/base/files/file_path_watcher_fsevents.cc
index f240e33dd6a..da01c431bfe 100644
--- a/chromium/base/files/file_path_watcher_fsevents.cc
+++ b/chromium/base/files/file_path_watcher_fsevents.cc
@@ -13,6 +13,7 @@
#include "base/mac/libdispatch_task_runner.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
namespace base {
@@ -75,11 +76,51 @@ FilePath ResolvePath(const FilePath& path) {
return result;
}
-// The callback passed to FSEventStreamCreate().
-void FSEventsCallback(ConstFSEventStreamRef stream,
- void* event_watcher, size_t num_events,
- void* event_paths, const FSEventStreamEventFlags flags[],
- const FSEventStreamEventId event_ids[]) {
+} // namespace
+
+FilePathWatcherFSEvents::FilePathWatcherFSEvents() : fsevent_stream_(NULL) {
+}
+
+bool FilePathWatcherFSEvents::Watch(const FilePath& path,
+ bool recursive,
+ const FilePathWatcher::Callback& callback) {
+ DCHECK(MessageLoopForIO::current());
+ DCHECK(!callback.is_null());
+ DCHECK(callback_.is_null());
+
+ // This class could support non-recursive watches, but that is currently
+ // left to FilePathWatcherKQueue.
+ if (!recursive)
+ return false;
+
+ set_task_runner(ThreadTaskRunnerHandle::Get());
+ callback_ = callback;
+
+ FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
+ g_task_runner.Get().PostTask(
+ FROM_HERE, Bind(&FilePathWatcherFSEvents::StartEventStream, this,
+ start_event, path));
+ return true;
+}
+
+void FilePathWatcherFSEvents::Cancel() {
+ set_cancelled();
+ callback_.Reset();
+
+ // Switch to the dispatch queue thread to tear down the event stream.
+ g_task_runner.Get().PostTask(
+ FROM_HERE,
+ Bind(&FilePathWatcherFSEvents::CancelOnMessageLoopThread, this));
+}
+
+// static
+void FilePathWatcherFSEvents::FSEventsCallback(
+ ConstFSEventStreamRef stream,
+ void* event_watcher,
+ size_t num_events,
+ void* event_paths,
+ const FSEventStreamEventFlags flags[],
+ const FSEventStreamEventId event_ids[]) {
FilePathWatcherFSEvents* watcher =
reinterpret_cast<FilePathWatcherFSEvents*>(event_watcher);
DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
@@ -111,83 +152,51 @@ void FSEventsCallback(ConstFSEventStreamRef stream,
watcher->OnFilePathsChanged(paths);
}
-} // namespace
-
-FilePathWatcherFSEvents::FilePathWatcherFSEvents() : fsevent_stream_(NULL) {
+FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {
+ // This method may be called on either the libdispatch or task_runner()
+ // thread. Checking callback_ on the libdispatch thread here is safe because
+ // it is executing in a task posted by Cancel() which first reset callback_.
+ // PostTask forms a sufficient memory barrier to ensure that the value is
+ // consistent on the target thread.
+ DCHECK(callback_.is_null())
+ << "Cancel() must be called before FilePathWatcher is destroyed.";
}
void FilePathWatcherFSEvents::OnFilePathsChanged(
const std::vector<FilePath>& paths) {
- if (!message_loop()->BelongsToCurrentThread()) {
- message_loop()->PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::OnFilePathsChanged, this, paths));
- return;
- }
-
- DCHECK(message_loop()->BelongsToCurrentThread());
- if (resolved_target_.empty())
- return;
-
- for (size_t i = 0; i < paths.size(); i++) {
- if (resolved_target_.IsParent(paths[i]) || resolved_target_ == paths[i]) {
- callback_.Run(target_, false);
- return;
- }
- }
+ DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+ DCHECK(!resolved_target_.empty());
+ task_runner()->PostTask(
+ FROM_HERE, Bind(&FilePathWatcherFSEvents::DispatchEvents, this, paths,
+ target_, resolved_target_));
}
-bool FilePathWatcherFSEvents::Watch(const FilePath& path,
- bool recursive,
- const FilePathWatcher::Callback& callback) {
- DCHECK(resolved_target_.empty());
- DCHECK(MessageLoopForIO::current());
- DCHECK(!callback.is_null());
+void FilePathWatcherFSEvents::DispatchEvents(const std::vector<FilePath>& paths,
+ const FilePath& target,
+ const FilePath& resolved_target) {
+ DCHECK(task_runner()->RunsTasksOnCurrentThread());
- // This class could support non-recursive watches, but that is currently
- // left to FilePathWatcherKQueue.
- if (!recursive)
- return false;
-
- set_message_loop(MessageLoopProxy::current());
- callback_ = callback;
- target_ = path;
-
- FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
- g_task_runner.Get().PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::StartEventStream, this, start_event));
- return true;
-}
-
-void FilePathWatcherFSEvents::Cancel() {
- if (callback_.is_null()) {
- // Watch was never called, so exit.
- set_cancelled();
+ // Don't issue callbacks after Cancel() has been called.
+ if (is_cancelled() || callback_.is_null()) {
return;
}
- // Switch to the dispatch queue thread if necessary, so we can tear down
- // the event stream.
- if (!g_task_runner.Get().RunsTasksOnCurrentThread()) {
- g_task_runner.Get().PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::CancelOnMessageLoopThread, this));
- } else {
- CancelOnMessageLoopThread();
+ for (const FilePath& path : paths) {
+ if (resolved_target.IsParent(path) || resolved_target == path) {
+ callback_.Run(target, false);
+ return;
+ }
}
}
void FilePathWatcherFSEvents::CancelOnMessageLoopThread() {
// For all other implementations, the "message loop thread" is the IO thread,
- // as returned by message_loop(). This implementation, however, needs to
- // cancel pending work on the Dipatch Queue thread.
+ // as returned by task_runner(). This implementation, however, needs to
+ // cancel pending work on the Dispatch Queue thread.
DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
- set_cancelled();
if (fsevent_stream_) {
DestroyEventStream();
- callback_.Reset();
target_.clear();
resolved_target_.clear();
}
@@ -199,7 +208,7 @@ void FilePathWatcherFSEvents::UpdateEventStream(
// It can happen that the watcher gets canceled while tasks that call this
// function are still in flight, so abort if this situation is detected.
- if (is_cancelled() || resolved_target_.empty())
+ if (resolved_target_.empty())
return;
if (fsevent_stream_)
@@ -230,8 +239,10 @@ void FilePathWatcherFSEvents::UpdateEventStream(
FSEventStreamSetDispatchQueue(fsevent_stream_,
g_task_runner.Get().GetDispatchQueue());
- if (!FSEventStreamStart(fsevent_stream_))
- message_loop()->PostTask(FROM_HERE, Bind(callback_, target_, true));
+ if (!FSEventStreamStart(fsevent_stream_)) {
+ task_runner()->PostTask(
+ FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+ }
}
bool FilePathWatcherFSEvents::ResolveTargetPath() {
@@ -239,11 +250,20 @@ bool FilePathWatcherFSEvents::ResolveTargetPath() {
FilePath resolved = ResolvePath(target_).StripTrailingSeparators();
bool changed = resolved != resolved_target_;
resolved_target_ = resolved;
- if (resolved_target_.empty())
- message_loop()->PostTask(FROM_HERE, Bind(callback_, target_, true));
+ if (resolved_target_.empty()) {
+ task_runner()->PostTask(
+ FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+ }
return changed;
}
+void FilePathWatcherFSEvents::ReportError(const FilePath& target) {
+ DCHECK(task_runner()->RunsTasksOnCurrentThread());
+ if (!callback_.is_null()) {
+ callback_.Run(target, true);
+ }
+}
+
void FilePathWatcherFSEvents::DestroyEventStream() {
FSEventStreamStop(fsevent_stream_);
FSEventStreamInvalidate(fsevent_stream_);
@@ -251,13 +271,14 @@ void FilePathWatcherFSEvents::DestroyEventStream() {
fsevent_stream_ = NULL;
}
-void FilePathWatcherFSEvents::StartEventStream(
- FSEventStreamEventId start_event) {
+void FilePathWatcherFSEvents::StartEventStream(FSEventStreamEventId start_event,
+ const FilePath& path) {
DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+ DCHECK(resolved_target_.empty());
+
+ target_ = path;
ResolveTargetPath();
UpdateEventStream(start_event);
}
-FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {}
-
} // namespace base
diff --git a/chromium/base/files/file_path_watcher_fsevents.h b/chromium/base/files/file_path_watcher_fsevents.h
index 800c5b43f68..300aa761dfa 100644
--- a/chromium/base/files/file_path_watcher_fsevents.h
+++ b/chromium/base/files/file_path_watcher_fsevents.h
@@ -24,9 +24,35 @@ class FilePathWatcherFSEvents : public FilePathWatcher::PlatformDelegate {
public:
FilePathWatcherFSEvents();
- // Called from the FSEvents callback whenever there is a change to the paths.
+ // FilePathWatcher::PlatformDelegate overrides.
+ bool Watch(const FilePath& path,
+ bool recursive,
+ const FilePathWatcher::Callback& callback) override;
+ void Cancel() override;
+
+ private:
+ static void FSEventsCallback(ConstFSEventStreamRef stream,
+ void* event_watcher,
+ size_t num_events,
+ void* event_paths,
+ const FSEventStreamEventFlags flags[],
+ const FSEventStreamEventId event_ids[]);
+
+ ~FilePathWatcherFSEvents() override;
+
+ // Called from FSEventsCallback whenever there is a change to the paths.
void OnFilePathsChanged(const std::vector<FilePath>& paths);
+ // Called on the message_loop() thread to dispatch path events. Can't access
+ // target_ and resolved_target_ directly as those are modified on the
+ // libdispatch thread.
+ void DispatchEvents(const std::vector<FilePath>& paths,
+ const FilePath& target,
+ const FilePath& resolved_target);
+
+ // Cleans up and stops the event stream.
+ void CancelOnMessageLoopThread() override;
+
// (Re-)Initialize the event stream to start reporting events from
// |start_event|.
void UpdateEventStream(FSEventStreamEventId start_event);
@@ -35,34 +61,29 @@ class FilePathWatcherFSEvents : public FilePathWatcher::PlatformDelegate {
// last time it was done.
bool ResolveTargetPath();
- // FilePathWatcher::PlatformDelegate overrides.
- bool Watch(const FilePath& path,
- bool recursive,
- const FilePathWatcher::Callback& callback) override;
- void Cancel() override;
-
- private:
- ~FilePathWatcherFSEvents() override;
+ // Report an error watching the given target.
+ void ReportError(const FilePath& target);
// Destroy the event stream.
void DestroyEventStream();
// Start watching the FSEventStream.
- void StartEventStream(FSEventStreamEventId start_event);
-
- // Cleans up and stops the event stream.
- void CancelOnMessageLoopThread() override;
+ void StartEventStream(FSEventStreamEventId start_event, const FilePath& path);
// Callback to notify upon changes.
+ // (Only accessed from the message_loop() thread.)
FilePathWatcher::Callback callback_;
// Target path to watch (passed to callback).
+ // (Only accessed from the libdispatch thread.)
FilePath target_;
// Target path with all symbolic links resolved.
+ // (Only accessed from the libdispatch thread.)
FilePath resolved_target_;
// Backend stream we receive event callbacks from (strong reference).
+ // (Only accessed from the libdispatch thread.)
FSEventStreamRef fsevent_stream_;
DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents);
diff --git a/chromium/base/files/file_path_watcher_kqueue.cc b/chromium/base/files/file_path_watcher_kqueue.cc
index 8941d2e419f..e15cba7d341 100644
--- a/chromium/base/files/file_path_watcher_kqueue.cc
+++ b/chromium/base/files/file_path_watcher_kqueue.cc
@@ -11,6 +11,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
// On some platforms these are not defined.
#if !defined(EV_RECEIPT)
@@ -327,7 +328,7 @@ bool FilePathWatcherKQueue::Watch(const FilePath& path,
target_ = path;
MessageLoop::current()->AddDestructionObserver(this);
- io_message_loop_ = base::MessageLoopProxy::current();
+ io_task_runner_ = ThreadTaskRunnerHandle::Get();
kqueue_ = kqueue();
if (kqueue_ == -1) {
@@ -356,14 +357,14 @@ bool FilePathWatcherKQueue::Watch(const FilePath& path,
}
void FilePathWatcherKQueue::Cancel() {
- base::MessageLoopProxy* proxy = io_message_loop_.get();
- if (!proxy) {
+ SingleThreadTaskRunner* task_runner = io_task_runner_.get();
+ if (!task_runner) {
set_cancelled();
return;
}
- if (!proxy->BelongsToCurrentThread()) {
- proxy->PostTask(FROM_HERE,
- base::Bind(&FilePathWatcherKQueue::Cancel, this));
+ if (!task_runner->BelongsToCurrentThread()) {
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&FilePathWatcherKQueue::Cancel, this));
return;
}
CancelOnMessageLoopThread();
@@ -380,7 +381,7 @@ void FilePathWatcherKQueue::CancelOnMessageLoopThread() {
kqueue_ = -1;
std::for_each(events_.begin(), events_.end(), ReleaseEvent);
events_.clear();
- io_message_loop_ = NULL;
+ io_task_runner_ = NULL;
MessageLoop::current()->RemoveDestructionObserver(this);
callback_.Reset();
}
diff --git a/chromium/base/files/file_path_watcher_kqueue.h b/chromium/base/files/file_path_watcher_kqueue.h
index 87af8913e55..69555a30032 100644
--- a/chromium/base/files/file_path_watcher_kqueue.h
+++ b/chromium/base/files/file_path_watcher_kqueue.h
@@ -11,7 +11,7 @@
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
namespace base {
@@ -59,7 +59,7 @@ class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate,
typedef std::vector<struct kevent> EventVector;
- // Can only be called on |io_message_loop_|'s thread.
+ // Can only be called on |io_task_runner_|'s thread.
void CancelOnMessageLoopThread() override;
// Returns true if the kevent values are error free.
@@ -118,7 +118,7 @@ class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate,
}
EventVector events_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
FilePathWatcher::Callback callback_;
FilePath target_;
diff --git a/chromium/base/files/file_path_watcher_linux.cc b/chromium/base/files/file_path_watcher_linux.cc
index 4078920aac9..ba2f1d96c84 100644
--- a/chromium/base/files/file_path_watcher_linux.cc
+++ b/chromium/base/files/file_path_watcher_linux.cc
@@ -19,7 +19,6 @@
#include "base/bind.h"
#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -27,11 +26,12 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
namespace base {
@@ -125,10 +125,13 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
// cleanup thread, in case it quits before Cancel() is called.
void WillDestroyCurrentMessageLoop() override;
- // Inotify watches are installed for all directory components of |target_|. A
- // WatchEntry instance holds the watch descriptor for a component and the
- // subdirectory for that identifies the next component. If a symbolic link
- // is being watched, the target of the link is also kept.
+ // Inotify watches are installed for all directory components of |target_|.
+ // A WatchEntry instance holds:
+ // - |watch|: the watch descriptor for a component.
+ // - |subdir|: the subdirectory that identifies the next component.
+ // - For the last component, there is no next component, so it is empty.
+ // - |linkname|: the target of the symlink.
+ // - Only if the target being watched is a symbolic link.
struct WatchEntry {
explicit WatchEntry(const FilePath::StringType& dirname)
: watch(InotifyReader::kInvalidWatch),
@@ -197,7 +200,7 @@ void InotifyReaderCallback(InotifyReader* reader, int inotify_fd,
CHECK_LE(0, shutdown_fd);
CHECK_GT(FD_SETSIZE, shutdown_fd);
- debug::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
+ trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
while (true) {
fd_set rfds;
@@ -261,7 +264,7 @@ InotifyReader::InotifyReader()
shutdown_pipe_[0] = -1;
shutdown_pipe_[1] = -1;
if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
- thread_.message_loop()->PostTask(
+ thread_.task_runner()->PostTask(
FROM_HERE,
Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0]));
valid_ = true;
@@ -346,12 +349,11 @@ void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
bool created,
bool deleted,
bool is_dir) {
- if (!message_loop()->BelongsToCurrentThread()) {
- // Switch to message_loop() to access |watches_| safely.
- message_loop()->PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
- fired_watch, child, created, deleted, is_dir));
+ if (!task_runner()->BelongsToCurrentThread()) {
+ // Switch to task_runner() to access |watches_| safely.
+ task_runner()->PostTask(FROM_HERE,
+ Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
+ fired_watch, child, created, deleted, is_dir));
return;
}
@@ -381,11 +383,31 @@ void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
(child == watch_entry.subdir);
// Check if the change references |target_| or a direct child of |target_|.
- bool is_watch_for_target = watch_entry.subdir.empty();
- bool target_changed =
- (is_watch_for_target && (child == watch_entry.linkname)) ||
- (is_watch_for_target && watch_entry.linkname.empty()) ||
- (watch_entry.subdir == child && watches_[i + 1].subdir.empty());
+ bool target_changed;
+ if (watch_entry.subdir.empty()) {
+ // The fired watch is for a WatchEntry without a subdir. Thus for a given
+ // |target_| = "/path/to/foo", this is for "foo". Here, check either:
+ // - the target has no symlink: it is the target and it changed.
+ // - the target has a symlink, and it matches |child|.
+ target_changed = (watch_entry.linkname.empty() ||
+ child == watch_entry.linkname);
+ } else {
+ // The fired watch is for a WatchEntry with a subdir. Thus for a given
+ // |target_| = "/path/to/foo", this is for {"/", "/path", "/path/to"}.
+ // So we can safely access the next WatchEntry since we have not reached
+ // the end yet. Check |watch_entry| is for "/path/to", i.e. the next
+ // element is "foo".
+ bool next_watch_may_be_for_target = watches_[i + 1].subdir.empty();
+ if (next_watch_may_be_for_target) {
+ // The current |watch_entry| is for "/path/to", so check if the |child|
+ // that changed is "foo".
+ target_changed = watch_entry.subdir == child;
+ } else {
+ // The current |watch_entry| is not for "/path/to", so the next entry
+ // cannot be "foo". Thus |target_| has not changed.
+ target_changed = false;
+ }
+ }
// Update watches if a directory component of the |target_| path
// (dis)appears. Note that we don't add the additional restriction of
@@ -429,7 +451,7 @@ bool FilePathWatcherImpl::Watch(const FilePath& path,
DCHECK(target_.empty());
DCHECK(MessageLoopForIO::current());
- set_message_loop(MessageLoopProxy::current());
+ set_task_runner(ThreadTaskRunnerHandle::Get());
callback_ = callback;
target_ = path;
recursive_ = recursive;
@@ -453,17 +475,16 @@ void FilePathWatcherImpl::Cancel() {
}
// Switch to the message_loop() if necessary so we can access |watches_|.
- if (!message_loop()->BelongsToCurrentThread()) {
- message_loop()->PostTask(FROM_HERE,
- Bind(&FilePathWatcher::CancelWatch,
- make_scoped_refptr(this)));
+ if (!task_runner()->BelongsToCurrentThread()) {
+ task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+ make_scoped_refptr(this)));
} else {
CancelOnMessageLoopThread();
}
}
void FilePathWatcherImpl::CancelOnMessageLoopThread() {
- DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK(task_runner()->BelongsToCurrentThread());
set_cancelled();
if (!callback_.is_null()) {
@@ -487,7 +508,7 @@ void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
void FilePathWatcherImpl::UpdateWatches() {
// Ensure this runs on the message_loop() exclusively in order to avoid
// concurrency issues.
- DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK(task_runner()->BelongsToCurrentThread());
DCHECK(HasValidWatchVector());
// Walk the list of watches and update them as we go.
diff --git a/chromium/base/files/file_path_watcher_stub.cc b/chromium/base/files/file_path_watcher_stub.cc
index d7ad2066aab..8138692ede1 100644
--- a/chromium/base/files/file_path_watcher_stub.cc
+++ b/chromium/base/files/file_path_watcher_stub.cc
@@ -13,18 +13,18 @@ namespace {
class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
public:
- virtual bool Watch(const FilePath& path,
- bool recursive,
- const FilePathWatcher::Callback& callback) override {
+ bool Watch(const FilePath& path,
+ bool recursive,
+ const FilePathWatcher::Callback& callback) override {
return false;
}
- virtual void Cancel() override {}
+ void Cancel() override {}
- virtual void CancelOnMessageLoopThread() override {}
+ void CancelOnMessageLoopThread() override {}
protected:
- virtual ~FilePathWatcherImpl() {}
+ ~FilePathWatcherImpl() override {}
};
} // namespace
diff --git a/chromium/base/files/file_path_watcher_browsertest.cc b/chromium/base/files/file_path_watcher_unittest.cc
index 0e19b2ed9ae..21e9dd137e2 100644
--- a/chromium/base/files/file_path_watcher_browsertest.cc
+++ b/chromium/base/files/file_path_watcher_unittest.cc
@@ -20,17 +20,22 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_file_util.h"
#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_ANDROID)
+#include "base/android/path_utils.h"
+#endif // defined(OS_ANDROID)
+
namespace base {
namespace {
@@ -42,14 +47,13 @@ class TestDelegate;
class NotificationCollector
: public base::RefCountedThreadSafe<NotificationCollector> {
public:
- NotificationCollector()
- : loop_(base::MessageLoopProxy::current()) {}
+ NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
// Called from the file thread by the delegates.
void OnChange(TestDelegate* delegate) {
- loop_->PostTask(FROM_HERE,
- base::Bind(&NotificationCollector::RecordChange, this,
- base::Unretained(delegate)));
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&NotificationCollector::RecordChange, this,
+ base::Unretained(delegate)));
}
void Register(TestDelegate* delegate) {
@@ -70,13 +74,13 @@ class NotificationCollector
void RecordChange(TestDelegate* delegate) {
// Warning: |delegate| is Unretained. Do not dereference.
- ASSERT_TRUE(loop_->BelongsToCurrentThread());
+ ASSERT_TRUE(task_runner_->BelongsToCurrentThread());
ASSERT_TRUE(delegates_.count(delegate));
signaled_.insert(delegate);
// Check whether all delegates have been signaled.
if (signaled_ == delegates_)
- loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ task_runner_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
}
// Set of registered delegates.
@@ -86,7 +90,7 @@ class NotificationCollector
std::set<TestDelegate*> signaled_;
// The loop we should break after all delegates signaled.
- scoped_refptr<base::MessageLoopProxy> loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
@@ -143,23 +147,31 @@ class FilePathWatcherTest : public testing::Test {
FilePathWatcherTest()
: file_thread_("FilePathWatcherTest") {}
- virtual ~FilePathWatcherTest() {}
+ ~FilePathWatcherTest() override {}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
// Create a separate file thread in order to test proper thread usage.
base::Thread::Options options(MessageLoop::TYPE_IO, 0);
ASSERT_TRUE(file_thread_.StartWithOptions(options));
+#if defined(OS_ANDROID)
+ // Watching files is only permitted when all parent directories are
+ // accessible, which is not the case for the default temp directory
+ // on Android which is under /data/data. Use /sdcard instead.
+ // TODO(pauljensen): Remove this when crbug.com/475568 is fixed.
+ FilePath parent_dir;
+ ASSERT_TRUE(android::GetExternalStorageDirectory(&parent_dir));
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(parent_dir));
+#else // defined(OS_ANDROID)
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+#endif // defined(OS_ANDROID)
collector_ = new NotificationCollector();
}
- virtual void TearDown() override {
- RunLoop().RunUntilIdle();
- }
+ void TearDown() override { RunLoop().RunUntilIdle(); }
void DeleteDelegateOnFileThread(TestDelegate* delegate) {
- file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, delegate);
+ file_thread_.task_runner()->DeleteSoon(FROM_HERE, delegate);
}
FilePath test_file() {
@@ -194,6 +206,7 @@ class FilePathWatcherTest : public testing::Test {
ScopedTempDir temp_dir_;
scoped_refptr<NotificationCollector> collector_;
+ private:
DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest);
};
@@ -203,10 +216,9 @@ bool FilePathWatcherTest::SetupWatch(const FilePath& target,
bool recursive_watch) {
base::WaitableEvent completion(false, false);
bool result;
- file_thread_.message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(SetupWatchCallback, target, watcher, delegate, recursive_watch,
- &result, &completion));
+ file_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(SetupWatchCallback, target, watcher, delegate,
+ recursive_watch, &result, &completion));
completion.Wait();
return result;
}
@@ -276,7 +288,8 @@ class Deleter : public TestDelegateBase {
void OnFileChanged(const FilePath&, bool) override {
watcher_.reset();
- loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ loop_->task_runner()->PostTask(FROM_HERE,
+ MessageLoop::QuitWhenIdleClosure());
}
FilePathWatcher* watcher() const { return watcher_.get(); }
@@ -311,7 +324,7 @@ TEST_F(FilePathWatcherTest, DISABLED_DestroyWithPendingNotification) {
FilePathWatcher* watcher = new FilePathWatcher;
ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
ASSERT_TRUE(WriteFile(test_file(), "content"));
- file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
+ file_thread_.task_runner()->DeleteSoon(FROM_HERE, watcher);
DeleteDelegateOnFileThread(delegate.release());
}
@@ -527,9 +540,16 @@ TEST_F(FilePathWatcherTest, RecursiveWatch) {
ASSERT_TRUE(WriteFile(child_dir_file1, "content"));
ASSERT_TRUE(WaitForEvents());
+// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4". Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#if !defined(OS_ANDROID)
// Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes.
ASSERT_TRUE(base::MakeFileUnreadable(child_dir_file1));
ASSERT_TRUE(WaitForEvents());
+#endif
// Delete "$dir/subdir/subdir_file1".
ASSERT_TRUE(base::DeleteFile(subdir_file1, false));
@@ -542,6 +562,14 @@ TEST_F(FilePathWatcherTest, RecursiveWatch) {
}
#if defined(OS_POSIX)
+#if defined(OS_ANDROID)
+// Apps cannot create symlinks on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4". Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#define RecursiveWithSymLink DISABLED_RecursiveWithSymLink
+#endif // defined(OS_ANDROID)
TEST_F(FilePathWatcherTest, RecursiveWithSymLink) {
if (!FilePathWatcher::RecursiveWatchAvailable())
return;
@@ -611,6 +639,14 @@ TEST_F(FilePathWatcherTest, MoveChild) {
}
// Verify that changing attributes on a file is caught
+#if defined(OS_ANDROID)
+// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4". Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#define FileAttributesChanged DISABLED_FileAttributesChanged
+#endif // defined(OS_ANDROID
TEST_F(FilePathWatcherTest, FileAttributesChanged) {
ASSERT_TRUE(WriteFile(test_file(), "content"));
FilePathWatcher watcher;
diff --git a/chromium/base/files/file_path_watcher_win.cc b/chromium/base/files/file_path_watcher_win.cc
index 73f9cfb332a..081698f8df1 100644
--- a/chromium/base/files/file_path_watcher_win.cc
+++ b/chromium/base/files/file_path_watcher_win.cc
@@ -10,8 +10,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/profiler/scoped_tracker.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/win/object_watcher.h"
@@ -28,21 +27,21 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
recursive_watch_(false) {}
// FilePathWatcher::PlatformDelegate overrides.
- virtual bool Watch(const FilePath& path,
- bool recursive,
- const FilePathWatcher::Callback& callback) override;
- virtual void Cancel() override;
+ bool Watch(const FilePath& path,
+ bool recursive,
+ const FilePathWatcher::Callback& callback) override;
+ void Cancel() override;
// Deletion of the FilePathWatcher will call Cancel() to dispose of this
// object in the right thread. This also observes destruction of the required
// cleanup thread, in case it quits before Cancel() is called.
- virtual void WillDestroyCurrentMessageLoop() override;
+ void WillDestroyCurrentMessageLoop() override;
// Callback from MessageLoopForIO.
- virtual void OnObjectSignaled(HANDLE object) override;
+ void OnObjectSignaled(HANDLE object) override;
private:
- virtual ~FilePathWatcherImpl() {}
+ ~FilePathWatcherImpl() override {}
// Setup a watch handle for directory |dir|. Set |recursive| to true to watch
// the directory sub trees. Returns true if no fatal error occurs. |handle|
@@ -58,7 +57,7 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
// Destroy the watch handle.
void DestroyWatch();
- // Cleans up and stops observing the |message_loop_| thread.
+ // Cleans up and stops observing the |task_runner_| thread.
void CancelOnMessageLoopThread() override;
// Callback to notify upon changes.
@@ -92,7 +91,7 @@ bool FilePathWatcherImpl::Watch(const FilePath& path,
const FilePathWatcher::Callback& callback) {
DCHECK(target_.value().empty()); // Can only watch one path.
- set_message_loop(MessageLoopProxy::current());
+ set_task_runner(ThreadTaskRunnerHandle::Get());
callback_ = callback;
target_ = path;
recursive_watch_ = recursive;
@@ -114,23 +113,22 @@ bool FilePathWatcherImpl::Watch(const FilePath& path,
void FilePathWatcherImpl::Cancel() {
if (callback_.is_null()) {
- // Watch was never called, or the |message_loop_| has already quit.
+ // Watch was never called, or the |task_runner_| has already quit.
set_cancelled();
return;
}
// Switch to the file thread if necessary so we can stop |watcher_|.
- if (!message_loop()->BelongsToCurrentThread()) {
- message_loop()->PostTask(FROM_HERE,
- Bind(&FilePathWatcher::CancelWatch,
- make_scoped_refptr(this)));
+ if (!task_runner()->BelongsToCurrentThread()) {
+ task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+ make_scoped_refptr(this)));
} else {
CancelOnMessageLoopThread();
}
}
void FilePathWatcherImpl::CancelOnMessageLoopThread() {
- DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK(task_runner()->BelongsToCurrentThread());
set_cancelled();
if (handle_ != INVALID_HANDLE_VALUE)
@@ -147,10 +145,6 @@ void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
}
void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("FilePathWatcherImpl_OnObjectSignaled"));
-
DCHECK(object == handle_);
// Make sure we stay alive through the body of this function.
scoped_refptr<FilePathWatcherImpl> keep_alive(this);
diff --git a/chromium/base/files/file_posix.cc b/chromium/base/files/file_posix.cc
index 3d229e4155e..bb49d2dd730 100644
--- a/chromium/base/files/file_posix.cc
+++ b/chromium/base/files/file_posix.cc
@@ -9,7 +9,6 @@
#include <sys/stat.h>
#include <unistd.h>
-#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/sparse_histogram.h"
#include "base/posix/eintr_wrapper.h"
@@ -31,12 +30,12 @@ namespace {
#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
static int CallFstat(int fd, stat_wrapper_t *sb) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
return fstat(fd, sb);
}
#else
static int CallFstat(int fd, stat_wrapper_t *sb) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
return fstat64(fd, sb);
}
#endif
@@ -52,10 +51,6 @@ static int CallFtruncate(PlatformFile file, int64 length) {
return HANDLE_EINTR(ftruncate(file, length));
}
-static int CallFsync(PlatformFile file) {
- return HANDLE_EINTR(fsync(file));
-}
-
static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
#ifdef __USE_XOPEN2K8
// futimens should be available, but futimes might not be
@@ -97,11 +92,6 @@ static int CallFtruncate(PlatformFile file, int64 length) {
return 0;
}
-static int CallFsync(PlatformFile file) {
- NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
- return 0;
-}
-
static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
return 0;
@@ -166,95 +156,6 @@ void File::Info::FromStat(const stat_wrapper_t& stat_info) {
Time::kNanosecondsPerMicrosecond);
}
-// NaCl doesn't implement system calls to open files directly.
-#if !defined(OS_NACL)
-// TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
-void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
- base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(!IsValid());
-
- int open_flags = 0;
- if (flags & FLAG_CREATE)
- open_flags = O_CREAT | O_EXCL;
-
- created_ = false;
-
- if (flags & FLAG_CREATE_ALWAYS) {
- DCHECK(!open_flags);
- DCHECK(flags & FLAG_WRITE);
- open_flags = O_CREAT | O_TRUNC;
- }
-
- if (flags & FLAG_OPEN_TRUNCATED) {
- DCHECK(!open_flags);
- DCHECK(flags & FLAG_WRITE);
- open_flags = O_TRUNC;
- }
-
- if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
- NOTREACHED();
- errno = EOPNOTSUPP;
- error_details_ = FILE_ERROR_FAILED;
- return;
- }
-
- if (flags & FLAG_WRITE && flags & FLAG_READ) {
- open_flags |= O_RDWR;
- } else if (flags & FLAG_WRITE) {
- open_flags |= O_WRONLY;
- } else if (!(flags & FLAG_READ) &&
- !(flags & FLAG_WRITE_ATTRIBUTES) &&
- !(flags & FLAG_APPEND) &&
- !(flags & FLAG_OPEN_ALWAYS)) {
- NOTREACHED();
- }
-
- if (flags & FLAG_TERMINAL_DEVICE)
- open_flags |= O_NOCTTY | O_NDELAY;
-
- if (flags & FLAG_APPEND && flags & FLAG_READ)
- open_flags |= O_APPEND | O_RDWR;
- else if (flags & FLAG_APPEND)
- open_flags |= O_APPEND | O_WRONLY;
-
- COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
-
- int mode = S_IRUSR | S_IWUSR;
-#if defined(OS_CHROMEOS)
- mode |= S_IRGRP | S_IROTH;
-#endif
-
- int descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
-
- if (flags & FLAG_OPEN_ALWAYS) {
- if (descriptor < 0) {
- open_flags |= O_CREAT;
- if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
- open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
-
- descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
- if (descriptor >= 0)
- created_ = true;
- }
- }
-
- if (descriptor < 0) {
- error_details_ = File::OSErrorToFileError(errno);
- return;
- }
-
- if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
- created_ = true;
-
- if (flags & FLAG_DELETE_ON_CLOSE)
- unlink(name.value().c_str());
-
- async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
- error_details_ = FILE_OK;
- file_.reset(descriptor);
-}
-#endif // !defined(OS_NACL)
-
bool File::IsValid() const {
return file_.is_valid();
}
@@ -271,14 +172,17 @@ void File::Close() {
if (!IsValid())
return;
- base::ThreadRestrictions::AssertIOAllowed();
+ SCOPED_FILE_TRACE("Close");
+ ThreadRestrictions::AssertIOAllowed();
file_.reset();
}
int64 File::Seek(Whence whence, int64 offset) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+ SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
+
#if defined(OS_ANDROID)
COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
return lseek64(file_.get(), static_cast<off64_t>(offset),
@@ -291,11 +195,13 @@ int64 File::Seek(Whence whence, int64 offset) {
}
int File::Read(int64 offset, char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
+
int bytes_read = 0;
int rv;
do {
@@ -311,11 +217,13 @@ int File::Read(int64 offset, char* data, int size) {
}
int File::ReadAtCurrentPos(char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
+
int bytes_read = 0;
int rv;
do {
@@ -330,23 +238,24 @@ int File::ReadAtCurrentPos(char* data, int size) {
}
int File::ReadNoBestEffort(int64 offset, char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
-
+ SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
return HANDLE_EINTR(pread(file_.get(), data, size, offset));
}
int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPosNoBestEffort", size);
return HANDLE_EINTR(read(file_.get(), data, size));
}
int File::Write(int64 offset, const char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
if (IsOpenAppend(file_.get()))
return WriteAtCurrentPos(data, size);
@@ -355,6 +264,8 @@ int File::Write(int64 offset, const char* data, int size) {
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
+
int bytes_written = 0;
int rv;
do {
@@ -370,11 +281,13 @@ int File::Write(int64 offset, const char* data, int size) {
}
int File::WriteAtCurrentPos(const char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
+
int bytes_written = 0;
int rv;
do {
@@ -390,17 +303,20 @@ int File::WriteAtCurrentPos(const char* data, int size) {
}
int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPosNoBestEffort", size);
return HANDLE_EINTR(write(file_.get(), data, size));
}
int64 File::GetLength() {
DCHECK(IsValid());
+ SCOPED_FILE_TRACE("GetLength");
+
stat_wrapper_t file_info;
if (CallFstat(file_.get(), &file_info))
return false;
@@ -409,21 +325,19 @@ int64 File::GetLength() {
}
bool File::SetLength(int64 length) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
- return !CallFtruncate(file_.get(), length);
-}
-bool File::Flush() {
- base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(IsValid());
- return !CallFsync(file_.get());
+ SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
+ return !CallFtruncate(file_.get(), length);
}
bool File::SetTimes(Time last_access_time, Time last_modified_time) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+ SCOPED_FILE_TRACE("SetTimes");
+
timeval times[2];
times[0] = last_access_time.ToTimeVal();
times[1] = last_modified_time.ToTimeVal();
@@ -434,6 +348,8 @@ bool File::SetTimes(Time last_access_time, Time last_modified_time) {
bool File::GetInfo(Info* info) {
DCHECK(IsValid());
+ SCOPED_FILE_TRACE("GetInfo");
+
stat_wrapper_t file_info;
if (CallFstat(file_.get(), &file_info))
return false;
@@ -443,13 +359,31 @@ bool File::GetInfo(Info* info) {
}
File::Error File::Lock() {
+ SCOPED_FILE_TRACE("Lock");
return CallFctnlFlock(file_.get(), true);
}
File::Error File::Unlock() {
+ SCOPED_FILE_TRACE("Unlock");
return CallFctnlFlock(file_.get(), false);
}
+File File::Duplicate() {
+ if (!IsValid())
+ return File();
+
+ SCOPED_FILE_TRACE("Duplicate");
+
+ PlatformFile other_fd = dup(GetPlatformFile());
+ if (other_fd == -1)
+ return File(OSErrorToFileError(errno));
+
+ File other(other_fd);
+ if (async())
+ other.async_ = true;
+ return other.Pass();
+}
+
// Static.
File::Error File::OSErrorToFileError(int saved_errno) {
switch (saved_errno) {
@@ -458,12 +392,15 @@ File::Error File::OSErrorToFileError(int saved_errno) {
case EROFS:
case EPERM:
return FILE_ERROR_ACCESS_DENIED;
+ case EBUSY:
#if !defined(OS_NACL) // ETXTBSY not defined by NaCl.
case ETXTBSY:
- return FILE_ERROR_IN_USE;
#endif
+ return FILE_ERROR_IN_USE;
case EEXIST:
return FILE_ERROR_EXISTS;
+ case EIO:
+ return FILE_ERROR_IO;
case ENOENT:
return FILE_ERROR_NOT_FOUND;
case EMFILE:
@@ -526,6 +463,109 @@ void File::MemoryCheckingScopedFD::UpdateChecksum() {
ComputeMemoryChecksum(&file_memory_checksum_);
}
+// NaCl doesn't implement system calls to open files directly.
+#if !defined(OS_NACL)
+// TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
+void File::DoInitialize(uint32 flags) {
+ ThreadRestrictions::AssertIOAllowed();
+ DCHECK(!IsValid());
+
+ int open_flags = 0;
+ if (flags & FLAG_CREATE)
+ open_flags = O_CREAT | O_EXCL;
+
+ created_ = false;
+
+ if (flags & FLAG_CREATE_ALWAYS) {
+ DCHECK(!open_flags);
+ DCHECK(flags & FLAG_WRITE);
+ open_flags = O_CREAT | O_TRUNC;
+ }
+
+ if (flags & FLAG_OPEN_TRUNCATED) {
+ DCHECK(!open_flags);
+ DCHECK(flags & FLAG_WRITE);
+ open_flags = O_TRUNC;
+ }
+
+ if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
+ NOTREACHED();
+ errno = EOPNOTSUPP;
+ error_details_ = FILE_ERROR_FAILED;
+ return;
+ }
+
+ if (flags & FLAG_WRITE && flags & FLAG_READ) {
+ open_flags |= O_RDWR;
+ } else if (flags & FLAG_WRITE) {
+ open_flags |= O_WRONLY;
+ } else if (!(flags & FLAG_READ) &&
+ !(flags & FLAG_WRITE_ATTRIBUTES) &&
+ !(flags & FLAG_APPEND) &&
+ !(flags & FLAG_OPEN_ALWAYS)) {
+ NOTREACHED();
+ }
+
+ if (flags & FLAG_TERMINAL_DEVICE)
+ open_flags |= O_NOCTTY | O_NDELAY;
+
+ if (flags & FLAG_APPEND && flags & FLAG_READ)
+ open_flags |= O_APPEND | O_RDWR;
+ else if (flags & FLAG_APPEND)
+ open_flags |= O_APPEND | O_WRONLY;
+
+ COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+
+ int mode = S_IRUSR | S_IWUSR;
+#if defined(OS_CHROMEOS)
+ mode |= S_IRGRP | S_IROTH;
+#endif
+
+ int descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+
+ if (flags & FLAG_OPEN_ALWAYS) {
+ if (descriptor < 0) {
+ open_flags |= O_CREAT;
+ if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
+ open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
+
+ descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+ if (descriptor >= 0)
+ created_ = true;
+ }
+ }
+
+ if (descriptor < 0) {
+ error_details_ = File::OSErrorToFileError(errno);
+ return;
+ }
+
+ if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
+ created_ = true;
+
+ if (flags & FLAG_DELETE_ON_CLOSE)
+ unlink(path_.value().c_str());
+
+ async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
+ error_details_ = FILE_OK;
+ file_.reset(descriptor);
+}
+#endif // !defined(OS_NACL)
+
+bool File::DoFlush() {
+ ThreadRestrictions::AssertIOAllowed();
+ DCHECK(IsValid());
+
+#if defined(OS_NACL)
+ NOTIMPLEMENTED(); // NaCl doesn't implement fsync.
+ return true;
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+ return !HANDLE_EINTR(fdatasync(file_.get()));
+#else
+ return !HANDLE_EINTR(fsync(file_.get()));
+#endif
+}
+
void File::SetPlatformFile(PlatformFile file) {
DCHECK(!file_.is_valid());
file_.reset(file);
diff --git a/chromium/base/files/file_proxy.cc b/chromium/base/files/file_proxy.cc
index 53b14fef2fd..f995735d5bc 100644
--- a/chromium/base/files/file_proxy.cc
+++ b/chromium/base/files/file_proxy.cc
@@ -9,7 +9,6 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
diff --git a/chromium/base/files/file_proxy_unittest.cc b/chromium/base/files/file_proxy_unittest.cc
index b5ed3950a05..df0bbc869c2 100644
--- a/chromium/base/files/file_proxy_unittest.cc
+++ b/chromium/base/files/file_proxy_unittest.cc
@@ -9,7 +9,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,7 +23,7 @@ class FileProxyTest : public testing::Test {
bytes_written_(-1),
weak_factory_(this) {}
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_TRUE(dir_.CreateUniqueTempDir());
ASSERT_TRUE(file_thread_.Start());
}
@@ -79,7 +78,7 @@ class FileProxyTest : public testing::Test {
}
TaskRunner* file_task_runner() const {
- return file_thread_.message_loop_proxy().get();
+ return file_thread_.task_runner().get();
}
const FilePath& test_dir_path() const { return dir_.path(); }
const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
diff --git a/chromium/base/files/file_tracing.cc b/chromium/base/files/file_tracing.cc
new file mode 100644
index 00000000000..a1919c464bb
--- /dev/null
+++ b/chromium/base/files/file_tracing.cc
@@ -0,0 +1,56 @@
+// Copyright 2015 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/files/file_tracing.h"
+
+#include "base/files/file.h"
+
+namespace base {
+
+namespace {
+FileTracing::Provider* g_provider = nullptr;
+}
+
+// static
+void FileTracing::SetProvider(FileTracing::Provider* provider) {
+ g_provider = provider;
+}
+
+FileTracing::ScopedEnabler::ScopedEnabler() {
+ if (g_provider)
+ g_provider->FileTracingEnable(this);
+}
+
+FileTracing::ScopedEnabler::~ScopedEnabler() {
+ if (g_provider)
+ g_provider->FileTracingDisable(this);
+}
+
+FileTracing::ScopedTrace::ScopedTrace() : initialized_(false) {}
+
+FileTracing::ScopedTrace::~ScopedTrace() {
+ if (initialized_ && g_provider) {
+ g_provider->FileTracingEventEnd(
+ name_, &file_->trace_enabler_, file_->path_, size_);
+ }
+}
+
+bool FileTracing::ScopedTrace::ShouldInitialize() const {
+ return g_provider && g_provider->FileTracingCategoryIsEnabled();
+}
+
+void FileTracing::ScopedTrace::Initialize(
+ const char* name, File* file, int64 size) {
+ file_ = file;
+ name_ = name;
+ size_ = size;
+ initialized_ = true;
+
+ if (g_provider) {
+ g_provider->FileTracingEventBegin(
+ name_, &file_->trace_enabler_, file_->path_, size_);
+ }
+}
+
+} // namespace base
diff --git a/chromium/base/files/file_tracing.h b/chromium/base/files/file_tracing.h
new file mode 100644
index 00000000000..8452037790c
--- /dev/null
+++ b/chromium/base/files/file_tracing.h
@@ -0,0 +1,95 @@
+// Copyright 2015 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_FILES_FILE_TRACING_H_
+#define BASE_FILES_FILE_TRACING_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/macros.h"
+
+#define FILE_TRACING_PREFIX "File"
+
+#define SCOPED_FILE_TRACE_WITH_SIZE(name, size) \
+ FileTracing::ScopedTrace scoped_file_trace; \
+ if (scoped_file_trace.ShouldInitialize()) \
+ scoped_file_trace.Initialize(FILE_TRACING_PREFIX "::" name, this, size)
+
+#define SCOPED_FILE_TRACE(name) SCOPED_FILE_TRACE_WITH_SIZE(name, 0)
+
+namespace base {
+
+class File;
+class FilePath;
+
+class BASE_EXPORT FileTracing {
+ public:
+ class Provider {
+ public:
+ // Whether the file tracing category is currently enabled.
+ virtual bool FileTracingCategoryIsEnabled() const = 0;
+
+ // Enables file tracing for |id|. Must be called before recording events.
+ virtual void FileTracingEnable(void* id) = 0;
+
+ // Disables file tracing for |id|.
+ virtual void FileTracingDisable(void* id) = 0;
+
+ // Begins an event for |id| with |name|. |path| tells where in the directory
+ // structure the event is happening (and may be blank). |size| is reported
+ // if not 0.
+ virtual void FileTracingEventBegin(
+ const char* name, void* id, const FilePath& path, int64 size) = 0;
+
+ // Ends an event for |id| with |name|. |path| tells where in the directory
+ // structure the event is happening (and may be blank). |size| is reported
+ // if not 0.
+ virtual void FileTracingEventEnd(
+ const char* name, void* id, const FilePath& path, int64 size) = 0;
+ };
+
+ // Sets a global file tracing provider to query categories and record events.
+ static void SetProvider(Provider* provider);
+
+ // Enables file tracing while in scope.
+ class ScopedEnabler {
+ public:
+ ScopedEnabler();
+ ~ScopedEnabler();
+ };
+
+ class ScopedTrace {
+ public:
+ ScopedTrace();
+ ~ScopedTrace();
+
+ // Whether this trace should be initialized or not.
+ bool ShouldInitialize() const;
+
+ // Called only if the tracing category is enabled.
+ void Initialize(const char* event, File* file, int64 size);
+
+ private:
+ // True if |Initialize()| has been called. Don't touch |path_|, |event_|,
+ // or |bytes_| if |initialized_| is false.
+ bool initialized_;
+
+ // The event name to trace (e.g. "Read", "Write"). Prefixed with "File".
+ const char* name_;
+
+ // The file being traced. Must outlive this class.
+ File* file_;
+
+ // The size (in bytes) of this trace. Not reported if 0.
+ int64 size_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(FileTracing);
+};
+
+} // namespace base
+
+#endif // BASE_FILES_FILE_TRACING_H_
diff --git a/chromium/base/files/file_unittest.cc b/chromium/base/files/file_unittest.cc
index 3bc2db60f0e..5c594242bc8 100644
--- a/chromium/base/files/file_unittest.cc
+++ b/chromium/base/files/file_unittest.cc
@@ -443,6 +443,49 @@ TEST(FileTest, Seek) {
EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset));
}
+TEST(FileTest, Duplicate) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("file");
+ File file(file_path,(base::File::FLAG_CREATE |
+ base::File::FLAG_READ |
+ base::File::FLAG_WRITE));
+ ASSERT_TRUE(file.IsValid());
+
+ File file2(file.Duplicate());
+ ASSERT_TRUE(file2.IsValid());
+
+ // Write through one handle, close it, read through the other.
+ static const char kData[] = "now is a good time.";
+ static const int kDataLen = sizeof(kData) - 1;
+
+ ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0));
+ ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0));
+ ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
+ ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0));
+ ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0));
+ file.Close();
+ char buf[kDataLen];
+ ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
+ ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
+}
+
+TEST(FileTest, DuplicateDeleteOnClose) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("file");
+ File file(file_path,(base::File::FLAG_CREATE |
+ base::File::FLAG_READ |
+ base::File::FLAG_WRITE |
+ base::File::FLAG_DELETE_ON_CLOSE));
+ ASSERT_TRUE(file.IsValid());
+ File file2(file.Duplicate());
+ ASSERT_TRUE(file2.IsValid());
+ file.Close();
+ file2.Close();
+ ASSERT_FALSE(base::PathExists(file_path));
+}
+
#if defined(OS_WIN)
TEST(FileTest, GetInfoForDirectory) {
base::ScopedTempDir temp_dir;
diff --git a/chromium/base/files/file_util.cc b/chromium/base/files/file_util.cc
index e60dcd9d346..32dab6bd40d 100644
--- a/chromium/base/files/file_util.cc
+++ b/chromium/base/files/file_util.cc
@@ -47,12 +47,6 @@ bool Move(const FilePath& from_path, const FilePath& to_path) {
return internal::MoveUnsafe(from_path, to_path);
}
-bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
- if (from_path.ReferencesParent() || to_path.ReferencesParent())
- return false;
- return internal::CopyFileUnsafe(from_path, to_path);
-}
-
bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
// We open the file in binary format even if they are text files because
// we are just comparing that bytes are exactly same in both files and not
diff --git a/chromium/base/files/file_util.h b/chromium/base/files/file_util.h
index ecc0d581dab..7f169f1c54b 100644
--- a/chromium/base/files/file_util.h
+++ b/chromium/base/files/file_util.h
@@ -421,11 +421,6 @@ namespace internal {
BASE_EXPORT bool MoveUnsafe(const FilePath& from_path,
const FilePath& to_path);
-// Same as CopyFile but allows paths with traversal components.
-// Use only with extreme care.
-BASE_EXPORT bool CopyFileUnsafe(const FilePath& from_path,
- const FilePath& to_path);
-
#if defined(OS_WIN)
// Copy from_path to to_path recursively and then delete from_path recursively.
// Returns true if all operations succeed.
diff --git a/chromium/base/files/file_util_linux.cc b/chromium/base/files/file_util_linux.cc
index 532962f195c..b230fd96484 100644
--- a/chromium/base/files/file_util_linux.cc
+++ b/chromium/base/files/file_util_linux.cc
@@ -10,21 +10,6 @@
#include "base/files/file_path.h"
-// Make sure some of the newer macros from magic.h are defined.
-// TODO(mostynb@opera.com): remove this after 2014.
-#ifndef BTRFS_SUPER_MAGIC
-#define BTRFS_SUPER_MAGIC 0x9123683E
-#endif
-#ifndef HUGETLBFS_MAGIC
-#define HUGETLBFS_MAGIC 0x958458f6
-#endif
-#ifndef RAMFS_MAGIC
-#define RAMFS_MAGIC 0x858458f6
-#endif
-#ifndef TMPFS_MAGIC
-#define TMPFS_MAGIC 0x01021994
-#endif
-
namespace base {
bool GetFileSystemType(const FilePath& path, FileSystemType* type) {
diff --git a/chromium/base/files/file_util_mac.mm b/chromium/base/files/file_util_mac.mm
index 695935a2e31..acac8d738ea 100644
--- a/chromium/base/files/file_util_mac.mm
+++ b/chromium/base/files/file_util_mac.mm
@@ -14,16 +14,15 @@
#include "base/threading/thread_restrictions.h"
namespace base {
-namespace internal {
-bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
ThreadRestrictions::AssertIOAllowed();
+ if (from_path.ReferencesParent() || to_path.ReferencesParent())
+ return false;
return (copyfile(from_path.value().c_str(),
to_path.value().c_str(), NULL, COPYFILE_DATA) == 0);
}
-} // namespace internal
-
bool GetTempDir(base::FilePath* path) {
NSString* tmp = NSTemporaryDirectory();
if (tmp == nil)
diff --git a/chromium/base/files/file_util_posix.cc b/chromium/base/files/file_util_posix.cc
index b8c0eeb94c0..b4a64ba9eee 100644
--- a/chromium/base/files/file_util_posix.cc
+++ b/chromium/base/files/file_util_posix.cc
@@ -28,8 +28,6 @@
#include <glib.h> // for g_get_home_dir()
#endif
-#include <fstream>
-
#include "base/basictypes.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
@@ -59,7 +57,6 @@
namespace base {
-#if !defined(OS_NACL_NONSFI)
namespace {
#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
@@ -82,6 +79,7 @@ static int CallLstat(const char *path, stat_wrapper_t *sb) {
}
#endif // !(defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL))
+#if !defined(OS_NACL_NONSFI)
// Helper for NormalizeFilePath(), defined below.
bool RealPath(const FilePath& path, FilePath* real_path) {
ThreadRestrictions::AssertIOAllowed(); // For realpath().
@@ -184,9 +182,11 @@ bool DetermineDevShmExecutable() {
return result;
}
#endif // defined(OS_LINUX)
+#endif // !defined(OS_NACL_NONSFI)
} // namespace
+#if !defined(OS_NACL_NONSFI)
FilePath MakeAbsoluteFilePath(const FilePath& input) {
ThreadRestrictions::AssertIOAllowed();
char full_path[PATH_MAX];
@@ -365,6 +365,7 @@ bool PathIsWritable(const FilePath& path) {
ThreadRestrictions::AssertIOAllowed();
return access(path.value().c_str(), W_OK) == 0;
}
+#endif // !defined(OS_NACL_NONSFI)
bool DirectoryExists(const FilePath& path) {
ThreadRestrictions::AssertIOAllowed();
@@ -373,7 +374,6 @@ bool DirectoryExists(const FilePath& path) {
return S_ISDIR(file_info.st_mode);
return false;
}
-#endif // !defined(OS_NACL_NONSFI)
bool ReadFromFD(int fd, char* buffer, size_t bytes) {
size_t total_read = 0;
@@ -428,7 +428,7 @@ bool GetPosixFilePermissions(const FilePath& path, int* mode) {
bool SetPosixFilePermissions(const FilePath& path,
int mode) {
ThreadRestrictions::AssertIOAllowed();
- DCHECK((mode & ~FILE_PERMISSION_MASK) == 0);
+ DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0);
// Calls stat() so that we can preserve the higher bits like S_ISGID.
stat_wrapper_t stat_buf;
@@ -847,55 +847,33 @@ bool GetShmemTempDir(bool executable, FilePath* path) {
}
#endif // !defined(OS_ANDROID)
-// -----------------------------------------------------------------------------
-
-namespace internal {
-
-bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
- ThreadRestrictions::AssertIOAllowed();
- // Windows compatibility: if to_path exists, from_path and to_path
- // must be the same type, either both files, or both directories.
- stat_wrapper_t to_file_info;
- if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
- stat_wrapper_t from_file_info;
- if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
- if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
- return false;
- } else {
- return false;
- }
- }
-
- if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
- return true;
-
- if (!CopyDirectory(from_path, to_path, true))
- return false;
-
- DeleteFile(from_path, true);
- return true;
-}
-
#if !defined(OS_MACOSX)
// Mac has its own implementation, this is for all other Posix systems.
-bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
ThreadRestrictions::AssertIOAllowed();
- int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY));
- if (infile < 0)
+ File infile;
+#if defined(OS_ANDROID)
+ if (from_path.IsContentUri()) {
+ infile = OpenContentUriForRead(from_path);
+ } else {
+ infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+ }
+#else
+ infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+#endif
+ if (!infile.IsValid())
return false;
- int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666));
- if (outfile < 0) {
- close(infile);
+ File outfile(to_path, File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
+ if (!outfile.IsValid())
return false;
- }
const size_t kBufferSize = 32768;
std::vector<char> buffer(kBufferSize);
bool result = true;
while (result) {
- ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
+ ssize_t bytes_read = infile.ReadAtCurrentPos(&buffer[0], buffer.size());
if (bytes_read < 0) {
result = false;
break;
@@ -905,10 +883,8 @@ bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
// Allow for partial writes
ssize_t bytes_written_per_read = 0;
do {
- ssize_t bytes_written_partial = HANDLE_EINTR(write(
- outfile,
- &buffer[bytes_written_per_read],
- bytes_read - bytes_written_per_read));
+ ssize_t bytes_written_partial = outfile.WriteAtCurrentPos(
+ &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read);
if (bytes_written_partial < 0) {
result = false;
break;
@@ -917,15 +893,39 @@ bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
} while (bytes_written_per_read < bytes_read);
}
- if (IGNORE_EINTR(close(infile)) < 0)
- result = false;
- if (IGNORE_EINTR(close(outfile)) < 0)
- result = false;
-
return result;
}
#endif // !defined(OS_MACOSX)
+// -----------------------------------------------------------------------------
+
+namespace internal {
+
+bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
+ ThreadRestrictions::AssertIOAllowed();
+ // Windows compatibility: if to_path exists, from_path and to_path
+ // must be the same type, either both files, or both directories.
+ stat_wrapper_t to_file_info;
+ if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
+ stat_wrapper_t from_file_info;
+ if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
+ if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+ if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
+ return true;
+
+ if (!CopyDirectory(from_path, to_path, true))
+ return false;
+
+ DeleteFile(from_path, true);
+ return true;
+}
+
} // namespace internal
#endif // !defined(OS_NACL_NONSFI)
diff --git a/chromium/base/files/file_util_proxy_unittest.cc b/chromium/base/files/file_util_proxy_unittest.cc
index 87ae66a6a0d..74083699f00 100644
--- a/chromium/base/files/file_util_proxy_unittest.cc
+++ b/chromium/base/files/file_util_proxy_unittest.cc
@@ -8,7 +8,6 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,11 +18,9 @@ class FileUtilProxyTest : public testing::Test {
FileUtilProxyTest()
: file_thread_("FileUtilProxyTestFileThread"),
error_(File::FILE_OK),
- created_(false),
- bytes_written_(-1),
weak_factory_(this) {}
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_TRUE(dir_.CreateUniqueTempDir());
ASSERT_TRUE(file_thread_.Start());
}
@@ -42,7 +39,7 @@ class FileUtilProxyTest : public testing::Test {
protected:
TaskRunner* file_task_runner() const {
- return file_thread_.message_loop_proxy().get();
+ return file_thread_.task_runner().get();
}
const FilePath& test_dir_path() const { return dir_.path(); }
const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
@@ -52,11 +49,9 @@ class FileUtilProxyTest : public testing::Test {
ScopedTempDir dir_;
File::Error error_;
- bool created_;
FilePath path_;
File::Info file_info_;
std::vector<char> buffer_;
- int bytes_written_;
WeakPtrFactory<FileUtilProxyTest> weak_factory_;
};
diff --git a/chromium/base/files/file_util_unittest.cc b/chromium/base/files/file_util_unittest.cc
index 08c9587cc06..b107b0f9c89 100644
--- a/chromium/base/files/file_util_unittest.cc
+++ b/chromium/base/files/file_util_unittest.cc
@@ -30,6 +30,7 @@
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_file_util.h"
#include "base/threading/platform_thread.h"
@@ -184,7 +185,7 @@ const int FILES_AND_DIRECTORIES =
// to be a PlatformTest
class FileUtilTest : public PlatformTest {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
PlatformTest::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
@@ -196,9 +197,9 @@ class FileUtilTest : public PlatformTest {
// interface to query whether a given file is present.
class FindResultCollector {
public:
- explicit FindResultCollector(FileEnumerator& enumerator) {
+ explicit FindResultCollector(FileEnumerator* enumerator) {
FilePath cur_file;
- while (!(cur_file = enumerator.Next()).value().empty()) {
+ while (!(cur_file = enumerator->Next()).value().empty()) {
FilePath::StringType path = cur_file.value();
// The file should not be returned twice.
EXPECT_TRUE(files_.end() == files_.find(path))
@@ -326,6 +327,13 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
// |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long)
FilePath base_a = temp_dir_.path().Append(FPL("base_a"));
+#if defined(OS_WIN)
+ // TEMP can have a lower case drive letter.
+ string16 temp_base_a = base_a.value();
+ ASSERT_FALSE(temp_base_a.empty());
+ *temp_base_a.begin() = base::ToUpperASCII(*temp_base_a.begin());
+ base_a = FilePath(temp_base_a);
+#endif
ASSERT_TRUE(CreateDirectory(base_a));
FilePath sub_a = base_a.Append(FPL("sub_a"));
@@ -428,6 +436,7 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
TEST_F(FileUtilTest, DevicePathToDriveLetter) {
// Get a drive letter.
std::wstring real_drive_letter = temp_dir_.path().value().substr(0, 2);
+ StringToUpperASCII(&real_drive_letter);
if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
LOG(ERROR) << "Can't get a drive letter to test with.";
return;
@@ -815,7 +824,7 @@ TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) {
// Make sure the file in the directory can't be enumerated.
FileEnumerator f1(subdir_path, true, FileEnumerator::FILES);
EXPECT_TRUE(PathExists(subdir_path));
- FindResultCollector c1(f1);
+ FindResultCollector c1(&f1);
EXPECT_EQ(0, c1.size());
EXPECT_FALSE(GetPosixFilePermissions(file_name, &mode));
@@ -826,7 +835,7 @@ TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) {
// Make sure the file in the directory can be enumerated.
FileEnumerator f2(subdir_path, true, FileEnumerator::FILES);
- FindResultCollector c2(f2);
+ FindResultCollector c2(&f2);
EXPECT_TRUE(c2.HasFile(file_name));
EXPECT_EQ(1, c2.size());
@@ -1388,19 +1397,15 @@ void SetReadOnly(const FilePath& path, bool read_only) {
path.value().c_str(),
read_only ? (attrs | FILE_ATTRIBUTE_READONLY) :
(attrs & ~FILE_ATTRIBUTE_READONLY)));
- // Files in the temporary directory should not be indexed ever. If this
- // assumption change, fix this unit test accordingly.
- // FILE_ATTRIBUTE_NOT_CONTENT_INDEXED doesn't exist on XP.
+
DWORD expected = read_only ?
((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) |
FILE_ATTRIBUTE_READONLY) :
(attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY));
- // TODO(ripp@yandex-team.ru): this seems out of place here. If we really think
- // it is important to verify that temp files are not indexed there should be
- // a dedicated test for that (create a file, inspect the attributes)
- if (win::GetVersion() >= win::VERSION_VISTA)
- expected |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
- attrs = GetFileAttributes(path.value().c_str());
+
+ // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED if present.
+ attrs = GetFileAttributes(path.value().c_str()) &
+ ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
ASSERT_EQ(expected, attrs);
#else
// On all other platforms, it involves removing/setting the write bit.
@@ -1471,30 +1476,29 @@ TEST_F(FileUtilTest, CopyFile) {
FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt"));
ASSERT_TRUE(CopyFile(file_name_from, dest_file));
- // Copy the file to another location using '..' in the path.
+ // Try to copy the file to another location using '..' in the path.
FilePath dest_file2(dir_name_from);
dest_file2 = dest_file2.AppendASCII("..");
dest_file2 = dest_file2.AppendASCII("DestFile.txt");
ASSERT_FALSE(CopyFile(file_name_from, dest_file2));
- ASSERT_TRUE(internal::CopyFileUnsafe(file_name_from, dest_file2));
FilePath dest_file2_test(dir_name_from);
dest_file2_test = dest_file2_test.DirName();
dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt");
- // Check everything has been copied.
+ // Check expected copy results.
EXPECT_TRUE(PathExists(file_name_from));
EXPECT_TRUE(PathExists(dest_file));
const std::wstring read_contents = ReadTextFile(dest_file);
EXPECT_EQ(file_contents, read_contents);
- EXPECT_TRUE(PathExists(dest_file2_test));
- EXPECT_TRUE(PathExists(dest_file2));
+ EXPECT_FALSE(PathExists(dest_file2_test));
+ EXPECT_FALSE(PathExists(dest_file2));
}
TEST_F(FileUtilTest, CopyFileACL) {
// While FileUtilTest.CopyFile asserts the content is correctly copied over,
// this test case asserts the access control bits are meeting expectations in
- // CopyFileUnsafe().
+ // CopyFile().
FilePath src = temp_dir_.path().Append(FILE_PATH_LITERAL("src.txt"));
const std::wstring file_contents(L"Gooooooooooooooooooooogle");
CreateTextFile(src, file_contents);
@@ -1867,7 +1871,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Only enumerate files.
FileEnumerator f1(temp_dir_.path(), true, FileEnumerator::FILES);
- FindResultCollector c1(f1);
+ FindResultCollector c1(&f1);
EXPECT_TRUE(c1.HasFile(file1));
EXPECT_TRUE(c1.HasFile(file2_abs));
EXPECT_TRUE(c1.HasFile(dir2file));
@@ -1876,7 +1880,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Only enumerate directories.
FileEnumerator f2(temp_dir_.path(), true, FileEnumerator::DIRECTORIES);
- FindResultCollector c2(f2);
+ FindResultCollector c2(&f2);
EXPECT_TRUE(c2.HasFile(dir1));
EXPECT_TRUE(c2.HasFile(dir2));
EXPECT_TRUE(c2.HasFile(dir2inner));
@@ -1885,7 +1889,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Only enumerate directories non-recursively.
FileEnumerator f2_non_recursive(
temp_dir_.path(), false, FileEnumerator::DIRECTORIES);
- FindResultCollector c2_non_recursive(f2_non_recursive);
+ FindResultCollector c2_non_recursive(&f2_non_recursive);
EXPECT_TRUE(c2_non_recursive.HasFile(dir1));
EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
EXPECT_EQ(2, c2_non_recursive.size());
@@ -1894,7 +1898,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
FileEnumerator f2_dotdot(temp_dir_.path(), false,
FileEnumerator::DIRECTORIES |
FileEnumerator::INCLUDE_DOT_DOT);
- FindResultCollector c2_dotdot(f2_dotdot);
+ FindResultCollector c2_dotdot(&f2_dotdot);
EXPECT_TRUE(c2_dotdot.HasFile(dir1));
EXPECT_TRUE(c2_dotdot.HasFile(dir2));
EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.path().Append(FPL(".."))));
@@ -1902,7 +1906,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Enumerate files and directories.
FileEnumerator f3(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
- FindResultCollector c3(f3);
+ FindResultCollector c3(&f3);
EXPECT_TRUE(c3.HasFile(dir1));
EXPECT_TRUE(c3.HasFile(dir2));
EXPECT_TRUE(c3.HasFile(file1));
@@ -1914,7 +1918,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Non-recursive operation.
FileEnumerator f4(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
- FindResultCollector c4(f4);
+ FindResultCollector c4(&f4);
EXPECT_TRUE(c4.HasFile(dir2));
EXPECT_TRUE(c4.HasFile(dir2));
EXPECT_TRUE(c4.HasFile(file1));
@@ -1923,7 +1927,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Enumerate with a pattern.
FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES, FPL("dir*"));
- FindResultCollector c5(f5);
+ FindResultCollector c5(&f5);
EXPECT_TRUE(c5.HasFile(dir1));
EXPECT_TRUE(c5.HasFile(dir2));
EXPECT_TRUE(c5.HasFile(dir2file));
@@ -1942,7 +1946,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// the file system so skip this test for XP.
// Enumerate the reparse point.
FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES);
- FindResultCollector c6(f6);
+ FindResultCollector c6(&f6);
FilePath inner2 = dir1.Append(FPL("inner"));
EXPECT_TRUE(c6.HasFile(inner2));
EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt"))));
@@ -1952,7 +1956,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// No changes for non recursive operation.
FileEnumerator f7(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
- FindResultCollector c7(f7);
+ FindResultCollector c7(&f7);
EXPECT_TRUE(c7.HasFile(dir2));
EXPECT_TRUE(c7.HasFile(dir2));
EXPECT_TRUE(c7.HasFile(file1));
@@ -1961,7 +1965,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Should not enumerate inside dir1 when using recursion.
FileEnumerator f8(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
- FindResultCollector c8(f8);
+ FindResultCollector c8(&f8);
EXPECT_TRUE(c8.HasFile(dir1));
EXPECT_TRUE(c8.HasFile(dir2));
EXPECT_TRUE(c8.HasFile(file1));
@@ -2171,7 +2175,7 @@ TEST_F(FileUtilTest, IsDirectoryEmpty) {
// with a common SetUp() method.
class VerifyPathControlledByUserTest : public FileUtilTest {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
FileUtilTest::SetUp();
// Create a basic structure used by each test.
diff --git a/chromium/base/files/file_util_win.cc b/chromium/base/files/file_util_win.cc
index 733c32c27da..e254232f663 100644
--- a/chromium/base/files/file_util_win.cc
+++ b/chromium/base/files/file_util_win.cc
@@ -210,7 +210,7 @@ bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
<< target_path.value().c_str();
success = false;
}
- } else if (!internal::CopyFileUnsafe(current, target_path)) {
+ } else if (!CopyFile(current, target_path)) {
DLOG(ERROR) << "CopyDirectory() couldn't create file: "
<< target_path.value().c_str();
success = false;
@@ -480,7 +480,7 @@ bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
}
// Move to the next drive letter string, which starts one
// increment after the '\0' that terminates the current string.
- while (*drive_map_ptr++);
+ while (*drive_map_ptr++) {}
}
// No drive matched. The path does not start with a device junction
@@ -496,7 +496,7 @@ bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
// code below to a call to GetFinalPathNameByHandle(). The method this
// function uses is explained in the following msdn article:
// http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
- base::win::ScopedHandle file_handle(
+ win::ScopedHandle file_handle(
::CreateFile(path.value().c_str(),
GENERIC_READ,
kFileShareAll,
@@ -510,7 +510,7 @@ bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
// Create a file mapping object. Can't easily use MemoryMappedFile, because
// we only map the first byte, and need direct access to the handle. You can
// not map an empty file, this call fails in that case.
- base::win::ScopedHandle file_map_handle(
+ win::ScopedHandle file_map_handle(
::CreateFileMapping(file_handle.Get(),
NULL,
PAGE_READONLY,
@@ -575,7 +575,7 @@ bool GetFileInfo(const FilePath& file_path, File::Info* results) {
FILE* OpenFile(const FilePath& filename, const char* mode) {
ThreadRestrictions::AssertIOAllowed();
- std::wstring w_mode = ASCIIToWide(std::string(mode));
+ string16 w_mode = ASCIIToUTF16(mode);
return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
}
@@ -595,13 +595,13 @@ FILE* FileToFILE(File file, const char* mode) {
int ReadFile(const FilePath& filename, char* data, int max_size) {
ThreadRestrictions::AssertIOAllowed();
- base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL));
+ win::ScopedHandle file(CreateFile(filename.value().c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL));
if (!file.IsValid())
return -1;
@@ -614,13 +614,13 @@ int ReadFile(const FilePath& filename, char* data, int max_size) {
int WriteFile(const FilePath& filename, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
- base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- 0,
- NULL));
+ win::ScopedHandle file(CreateFile(filename.value().c_str(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ 0,
+ NULL));
if (!file.IsValid()) {
DPLOG(WARNING) << "CreateFile failed for path "
<< UTF16ToUTF8(filename.value());
@@ -646,13 +646,13 @@ int WriteFile(const FilePath& filename, const char* data, int size) {
bool AppendToFile(const FilePath& filename, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
- base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
- FILE_APPEND_DATA,
- 0,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL));
+ win::ScopedHandle file(CreateFile(filename.value().c_str(),
+ FILE_APPEND_DATA,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL));
if (!file.IsValid()) {
VPLOG(1) << "CreateFile failed for path " << UTF16ToUTF8(filename.value());
return false;
@@ -722,6 +722,37 @@ int GetMaximumPathComponentLength(const FilePath& path) {
return std::min(whole_path_limit, static_cast<int>(max_length));
}
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+ ThreadRestrictions::AssertIOAllowed();
+ if (from_path.ReferencesParent() || to_path.ReferencesParent())
+ return false;
+
+ // NOTE: I suspect we could support longer paths, but that would involve
+ // analyzing all our usage of files.
+ if (from_path.value().length() >= MAX_PATH ||
+ to_path.value().length() >= MAX_PATH) {
+ return false;
+ }
+
+ // Unlike the posix implementation that copies the file manually and discards
+ // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
+ // bits, which is usually not what we want. We can't do much about the
+ // SECURITY_DESCRIPTOR but at least remove the read only bit.
+ const wchar_t* dest = to_path.value().c_str();
+ if (!::CopyFile(from_path.value().c_str(), dest, false)) {
+ // Copy failed.
+ return false;
+ }
+ DWORD attrs = GetFileAttributes(dest);
+ if (attrs == INVALID_FILE_ATTRIBUTES) {
+ return false;
+ }
+ if (attrs & FILE_ATTRIBUTE_READONLY) {
+ SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
+ }
+ return true;
+}
+
// -----------------------------------------------------------------------------
namespace internal {
@@ -760,35 +791,6 @@ bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
return ret;
}
-bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
- ThreadRestrictions::AssertIOAllowed();
-
- // NOTE: I suspect we could support longer paths, but that would involve
- // analyzing all our usage of files.
- if (from_path.value().length() >= MAX_PATH ||
- to_path.value().length() >= MAX_PATH) {
- return false;
- }
-
- // Unlike the posix implementation that copies the file manually and discards
- // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
- // bits, which is usually not what we want. We can't do much about the
- // SECURITY_DESCRIPTOR but at least remove the read only bit.
- const wchar_t* dest = to_path.value().c_str();
- if (!::CopyFile(from_path.value().c_str(), dest, false)) {
- // Copy failed.
- return false;
- }
- DWORD attrs = GetFileAttributes(dest);
- if (attrs == INVALID_FILE_ATTRIBUTES) {
- return false;
- }
- if (attrs & FILE_ATTRIBUTE_READONLY) {
- SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
- }
- return true;
-}
-
bool CopyAndDeleteDirectory(const FilePath& from_path,
const FilePath& to_path) {
ThreadRestrictions::AssertIOAllowed();
diff --git a/chromium/base/files/file_win.cc b/chromium/base/files/file_win.cc
index 727b5ce1dbb..97928522f10 100644
--- a/chromium/base/files/file_win.cc
+++ b/chromium/base/files/file_win.cc
@@ -6,7 +6,6 @@
#include <io.h>
-#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/sparse_histogram.h"
#include "base/threading/thread_restrictions.h"
@@ -18,90 +17,6 @@ COMPILE_ASSERT(File::FROM_BEGIN == FILE_BEGIN &&
File::FROM_CURRENT == FILE_CURRENT &&
File::FROM_END == FILE_END, whence_matches_system);
-void File::InitializeUnsafe(const FilePath& name, uint32 flags) {
- base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(!IsValid());
-
- DWORD disposition = 0;
-
- if (flags & FLAG_OPEN)
- disposition = OPEN_EXISTING;
-
- if (flags & FLAG_CREATE) {
- DCHECK(!disposition);
- disposition = CREATE_NEW;
- }
-
- if (flags & FLAG_OPEN_ALWAYS) {
- DCHECK(!disposition);
- disposition = OPEN_ALWAYS;
- }
-
- if (flags & FLAG_CREATE_ALWAYS) {
- DCHECK(!disposition);
- DCHECK(flags & FLAG_WRITE);
- disposition = CREATE_ALWAYS;
- }
-
- if (flags & FLAG_OPEN_TRUNCATED) {
- DCHECK(!disposition);
- DCHECK(flags & FLAG_WRITE);
- disposition = TRUNCATE_EXISTING;
- }
-
- if (!disposition) {
- NOTREACHED();
- return;
- }
-
- DWORD access = 0;
- if (flags & FLAG_WRITE)
- access = GENERIC_WRITE;
- if (flags & FLAG_APPEND) {
- DCHECK(!access);
- access = FILE_APPEND_DATA;
- }
- if (flags & FLAG_READ)
- access |= GENERIC_READ;
- if (flags & FLAG_WRITE_ATTRIBUTES)
- access |= FILE_WRITE_ATTRIBUTES;
- if (flags & FLAG_EXECUTE)
- access |= GENERIC_EXECUTE;
-
- DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
- if (!(flags & FLAG_EXCLUSIVE_WRITE))
- sharing |= FILE_SHARE_WRITE;
- if (flags & FLAG_SHARE_DELETE)
- sharing |= FILE_SHARE_DELETE;
-
- DWORD create_flags = 0;
- if (flags & FLAG_ASYNC)
- create_flags |= FILE_FLAG_OVERLAPPED;
- if (flags & FLAG_TEMPORARY)
- create_flags |= FILE_ATTRIBUTE_TEMPORARY;
- if (flags & FLAG_HIDDEN)
- create_flags |= FILE_ATTRIBUTE_HIDDEN;
- if (flags & FLAG_DELETE_ON_CLOSE)
- create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
- if (flags & FLAG_BACKUP_SEMANTICS)
- create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
-
- file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
- disposition, create_flags, NULL));
-
- if (file_.IsValid()) {
- error_details_ = FILE_OK;
- async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
-
- if (flags & (FLAG_OPEN_ALWAYS))
- created_ = (ERROR_ALREADY_EXISTS != GetLastError());
- else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
- created_ = true;
- } else {
- error_details_ = OSErrorToFileError(GetLastError());
- }
-}
-
bool File::IsValid() const {
return file_.IsValid();
}
@@ -115,16 +30,20 @@ PlatformFile File::TakePlatformFile() {
}
void File::Close() {
- if (file_.IsValid()) {
- base::ThreadRestrictions::AssertIOAllowed();
- file_.Close();
- }
+ if (!file_.IsValid())
+ return;
+
+ ThreadRestrictions::AssertIOAllowed();
+ SCOPED_FILE_TRACE("Close");
+ file_.Close();
}
int64 File::Seek(Whence whence, int64 offset) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+ SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
+
LARGE_INTEGER distance, res;
distance.QuadPart = offset;
DWORD move_method = static_cast<DWORD>(whence);
@@ -134,12 +53,14 @@ int64 File::Seek(Whence whence, int64 offset) {
}
int File::Read(int64 offset, char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
DCHECK(!async_);
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
+
LARGE_INTEGER offset_li;
offset_li.QuadPart = offset;
@@ -157,12 +78,14 @@ int File::Read(int64 offset, char* data, int size) {
}
int File::ReadAtCurrentPos(char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
DCHECK(!async_);
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
+
DWORD bytes_read;
if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL))
return bytes_read;
@@ -173,18 +96,22 @@ int File::ReadAtCurrentPos(char* data, int size) {
}
int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+ // TODO(dbeam): trace this separately?
return Read(offset, data, size);
}
int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
+ // TODO(dbeam): trace this separately?
return ReadAtCurrentPos(data, size);
}
int File::Write(int64 offset, const char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
DCHECK(!async_);
+ SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
+
LARGE_INTEGER offset_li;
offset_li.QuadPart = offset;
@@ -200,12 +127,14 @@ int File::Write(int64 offset, const char* data, int size) {
}
int File::WriteAtCurrentPos(const char* data, int size) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
DCHECK(!async_);
if (size < 0)
return -1;
+ SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
+
DWORD bytes_written;
if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL))
return bytes_written;
@@ -218,8 +147,11 @@ int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
}
int64 File::GetLength() {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+
+ SCOPED_FILE_TRACE("GetLength");
+
LARGE_INTEGER size;
if (!::GetFileSizeEx(file_.Get(), &size))
return -1;
@@ -228,9 +160,11 @@ int64 File::GetLength() {
}
bool File::SetLength(int64 length) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+ SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
+
// Get the current file pointer.
LARGE_INTEGER file_pointer;
LARGE_INTEGER zero;
@@ -256,16 +190,12 @@ bool File::SetLength(int64 length) {
FALSE));
}
-bool File::Flush() {
- base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(IsValid());
- return ::FlushFileBuffers(file_.Get()) != FALSE;
-}
-
bool File::SetTimes(Time last_access_time, Time last_modified_time) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+ SCOPED_FILE_TRACE("SetTimes");
+
FILETIME last_access_filetime = last_access_time.ToFileTime();
FILETIME last_modified_filetime = last_modified_time.ToFileTime();
return (::SetFileTime(file_.Get(), NULL, &last_access_filetime,
@@ -273,9 +203,11 @@ bool File::SetTimes(Time last_access_time, Time last_modified_time) {
}
bool File::GetInfo(Info* info) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
+ SCOPED_FILE_TRACE("GetInfo");
+
BY_HANDLE_FILE_INFORMATION file_info;
if (!GetFileInformationByHandle(file_.Get(), &file_info))
return false;
@@ -287,14 +219,17 @@ bool File::GetInfo(Info* info) {
info->is_directory =
(file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
info->is_symbolic_link = false; // Windows doesn't have symbolic links.
- info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
- info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
- info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
+ info->last_modified = Time::FromFileTime(file_info.ftLastWriteTime);
+ info->last_accessed = Time::FromFileTime(file_info.ftLastAccessTime);
+ info->creation_time = Time::FromFileTime(file_info.ftCreationTime);
return true;
}
-File::Error base::File::Lock() {
+File::Error File::Lock() {
DCHECK(IsValid());
+
+ SCOPED_FILE_TRACE("Lock");
+
BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
if (!result)
return OSErrorToFileError(GetLastError());
@@ -303,12 +238,39 @@ File::Error base::File::Lock() {
File::Error File::Unlock() {
DCHECK(IsValid());
+
+ SCOPED_FILE_TRACE("Unlock");
+
BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
if (!result)
return OSErrorToFileError(GetLastError());
return FILE_OK;
}
+File File::Duplicate() {
+ if (!IsValid())
+ return File();
+
+ SCOPED_FILE_TRACE("Duplicate");
+
+ HANDLE other_handle = nullptr;
+
+ if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle
+ GetPlatformFile(),
+ GetCurrentProcess(), // hTargetProcessHandle
+ &other_handle,
+ 0, // dwDesiredAccess ignored due to SAME_ACCESS
+ FALSE, // !bInheritHandle
+ DUPLICATE_SAME_ACCESS)) {
+ return File(OSErrorToFileError(GetLastError()));
+ }
+
+ File other(other_handle);
+ if (async())
+ other.async_ = true;
+ return other.Pass();
+}
+
// Static.
File::Error File::OSErrorToFileError(DWORD last_error) {
switch (last_error) {
@@ -346,6 +308,96 @@ File::Error File::OSErrorToFileError(DWORD last_error) {
}
}
+void File::DoInitialize(uint32 flags) {
+ ThreadRestrictions::AssertIOAllowed();
+ DCHECK(!IsValid());
+
+ DWORD disposition = 0;
+
+ if (flags & FLAG_OPEN)
+ disposition = OPEN_EXISTING;
+
+ if (flags & FLAG_CREATE) {
+ DCHECK(!disposition);
+ disposition = CREATE_NEW;
+ }
+
+ if (flags & FLAG_OPEN_ALWAYS) {
+ DCHECK(!disposition);
+ disposition = OPEN_ALWAYS;
+ }
+
+ if (flags & FLAG_CREATE_ALWAYS) {
+ DCHECK(!disposition);
+ DCHECK(flags & FLAG_WRITE);
+ disposition = CREATE_ALWAYS;
+ }
+
+ if (flags & FLAG_OPEN_TRUNCATED) {
+ DCHECK(!disposition);
+ DCHECK(flags & FLAG_WRITE);
+ disposition = TRUNCATE_EXISTING;
+ }
+
+ if (!disposition) {
+ NOTREACHED();
+ return;
+ }
+
+ DWORD access = 0;
+ if (flags & FLAG_WRITE)
+ access = GENERIC_WRITE;
+ if (flags & FLAG_APPEND) {
+ DCHECK(!access);
+ access = FILE_APPEND_DATA;
+ }
+ if (flags & FLAG_READ)
+ access |= GENERIC_READ;
+ if (flags & FLAG_WRITE_ATTRIBUTES)
+ access |= FILE_WRITE_ATTRIBUTES;
+ if (flags & FLAG_EXECUTE)
+ access |= GENERIC_EXECUTE;
+
+ DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
+ if (!(flags & FLAG_EXCLUSIVE_WRITE))
+ sharing |= FILE_SHARE_WRITE;
+ if (flags & FLAG_SHARE_DELETE)
+ sharing |= FILE_SHARE_DELETE;
+
+ DWORD create_flags = 0;
+ if (flags & FLAG_ASYNC)
+ create_flags |= FILE_FLAG_OVERLAPPED;
+ if (flags & FLAG_TEMPORARY)
+ create_flags |= FILE_ATTRIBUTE_TEMPORARY;
+ if (flags & FLAG_HIDDEN)
+ create_flags |= FILE_ATTRIBUTE_HIDDEN;
+ if (flags & FLAG_DELETE_ON_CLOSE)
+ create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
+ if (flags & FLAG_BACKUP_SEMANTICS)
+ create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
+
+ file_.Set(CreateFile(path_.value().c_str(), access, sharing, NULL,
+ disposition, create_flags, NULL));
+
+ if (file_.IsValid()) {
+ error_details_ = FILE_OK;
+ async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
+
+ if (flags & (FLAG_OPEN_ALWAYS))
+ created_ = (ERROR_ALREADY_EXISTS != GetLastError());
+ else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
+ created_ = true;
+ } else {
+ error_details_ = OSErrorToFileError(GetLastError());
+ }
+}
+
+bool File::DoFlush() {
+ ThreadRestrictions::AssertIOAllowed();
+ DCHECK(IsValid());
+ return ::FlushFileBuffers(file_.Get()) != FALSE;
+}
+
void File::SetPlatformFile(PlatformFile file) {
file_.Set(file);
}
diff --git a/chromium/base/files/important_file_writer.cc b/chromium/base/files/important_file_writer.cc
index d7579abb112..814fc7b9add 100644
--- a/chromium/base/files/important_file_writer.cc
+++ b/chromium/base/files/important_file_writer.cc
@@ -10,12 +10,14 @@
#include "base/bind.h"
#include "base/critical_closure.h"
+#include "base/debug/alias.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
@@ -27,10 +29,14 @@ namespace {
const int kDefaultCommitIntervalMs = 10000;
+// This enum is used to define the buckets for an enumerated UMA histogram.
+// Hence,
+// (a) existing enumerated constants should never be deleted or reordered, and
+// (b) new constants should only be appended at the end of the enumeration.
enum TempFileFailure {
FAILED_CREATING,
FAILED_OPENING,
- FAILED_CLOSING,
+ FAILED_CLOSING, // Unused.
FAILED_WRITING,
FAILED_RENAMING,
FAILED_FLUSHING,
@@ -45,11 +51,31 @@ void LogFailure(const FilePath& path, TempFileFailure failure_code,
<< " : " << message;
}
+// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
+bool WriteScopedStringToFileAtomically(const FilePath& path,
+ scoped_ptr<std::string> data) {
+ return ImportantFileWriter::WriteFileAtomically(path, *data);
+}
+
} // namespace
// static
bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
const std::string& data) {
+#if defined(OS_CHROMEOS)
+ // On Chrome OS, chrome gets killed when it cannot finish shutdown quickly,
+ // and this function seems to be one of the slowest shutdown steps.
+ // Include some info to the report for investigation. crbug.com/418627
+ // TODO(hashimoto): Remove this.
+ struct {
+ size_t data_size;
+ char path[128];
+ } file_info;
+ file_info.data_size = data.size();
+ base::strlcpy(file_info.path, path.value().c_str(),
+ arraysize(file_info.path));
+ base::debug::Alias(&file_info);
+#endif
// Write the data to a temp file then rename to avoid data loss if we crash
// while writing the file. Ensure that the temp file is on the same volume
// as target file, so it can be moved in one step, and that the temp file
@@ -104,7 +130,7 @@ ImportantFileWriter::ImportantFileWriter(
commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
weak_factory_(this) {
DCHECK(CalledOnValidThread());
- DCHECK(task_runner_.get());
+ DCHECK(task_runner_);
}
ImportantFileWriter::~ImportantFileWriter() {
@@ -119,9 +145,9 @@ bool ImportantFileWriter::HasPendingWrite() const {
return timer_.IsRunning();
}
-void ImportantFileWriter::WriteNow(const std::string& data) {
+void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
DCHECK(CalledOnValidThread());
- if (data.length() > static_cast<size_t>(kint32max)) {
+ if (data->length() > static_cast<size_t>(kint32max)) {
NOTREACHED();
return;
}
@@ -129,13 +155,14 @@ void ImportantFileWriter::WriteNow(const std::string& data) {
if (HasPendingWrite())
timer_.Stop();
- if (!PostWriteTask(data)) {
+ auto task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data));
+ if (!PostWriteTask(task)) {
// Posting the task to background message loop is not expected
// to fail, but if it does, avoid losing data and just hit the disk
// on the current thread.
NOTREACHED();
- WriteFileAtomically(path_, data);
+ task.Run();
}
}
@@ -153,9 +180,9 @@ void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) {
void ImportantFileWriter::DoScheduledWrite() {
DCHECK(serializer_);
- std::string data;
- if (serializer_->SerializeData(&data)) {
- WriteNow(data);
+ scoped_ptr<std::string> data(new std::string);
+ if (serializer_->SerializeData(data.get())) {
+ WriteNow(data.Pass());
} else {
DLOG(WARNING) << "failed to serialize data to be saved in "
<< path_.value().c_str();
@@ -169,7 +196,7 @@ void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
on_next_successful_write_ = on_next_successful_write;
}
-bool ImportantFileWriter::PostWriteTask(const std::string& data) {
+bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
// TODO(gab): This code could always use PostTaskAndReplyWithResult and let
// ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but
// PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and
@@ -179,16 +206,13 @@ bool ImportantFileWriter::PostWriteTask(const std::string& data) {
return base::PostTaskAndReplyWithResult(
task_runner_.get(),
FROM_HERE,
- MakeCriticalClosure(
- Bind(&ImportantFileWriter::WriteFileAtomically, path_, data)),
+ MakeCriticalClosure(task),
Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
weak_factory_.GetWeakPtr()));
}
return task_runner_->PostTask(
FROM_HERE,
- MakeCriticalClosure(
- Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
- path_, data)));
+ MakeCriticalClosure(base::Bind(IgnoreResult(task))));
}
void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
diff --git a/chromium/base/files/important_file_writer.h b/chromium/base/files/important_file_writer.h
index 9ead9c14bf2..99f1a7c6814 100644
--- a/chromium/base/files/important_file_writer.h
+++ b/chromium/base/files/important_file_writer.h
@@ -78,7 +78,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
// Save |data| to target filename. Does not block. If there is a pending write
// scheduled by ScheduleWrite, it is cancelled.
- void WriteNow(const std::string& data);
+ void WriteNow(scoped_ptr<std::string> data);
// Schedule a save to target filename. Data will be serialized and saved
// to disk after the commit interval. If another ScheduleWrite is issued
@@ -106,7 +106,7 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
private:
// Helper method for WriteNow().
- bool PostWriteTask(const std::string& data);
+ bool PostWriteTask(const Callback<bool()>& task);
// If |result| is true and |on_next_successful_write_| is set, invokes
// |on_successful_write_| and then resets it; no-ops otherwise.
diff --git a/chromium/base/files/important_file_writer_unittest.cc b/chromium/base/files/important_file_writer_unittest.cc
index 96d0d059bb8..d376cdc35ab 100644
--- a/chromium/base/files/important_file_writer_unittest.cc
+++ b/chromium/base/files/important_file_writer_unittest.cc
@@ -9,9 +9,11 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -82,7 +84,7 @@ bool SuccessfulWriteObserver::GetAndResetObservationState() {
class ImportantFileWriterTest : public testing::Test {
public:
ImportantFileWriterTest() { }
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_ = temp_dir_.path().AppendASCII("test-file");
}
@@ -97,10 +99,10 @@ class ImportantFileWriterTest : public testing::Test {
};
TEST_F(ImportantFileWriterTest, Basic) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
EXPECT_FALSE(PathExists(writer.path()));
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
- writer.WriteNow("foo");
+ writer.WriteNow(make_scoped_ptr(new std::string("foo")));
RunLoop().RunUntilIdle();
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
@@ -109,11 +111,11 @@ TEST_F(ImportantFileWriterTest, Basic) {
}
TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
EXPECT_FALSE(PathExists(writer.path()));
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
- writer.WriteNow("foo");
+ writer.WriteNow(make_scoped_ptr(new std::string("foo")));
RunLoop().RunUntilIdle();
// Confirm that the observer is invoked.
@@ -124,7 +126,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
// Confirm that re-installing the observer works for another write.
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
- writer.WriteNow("bar");
+ writer.WriteNow(make_scoped_ptr(new std::string("bar")));
RunLoop().RunUntilIdle();
EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
@@ -134,7 +136,7 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
// Confirm that writing again without re-installing the observer doesn't
// result in a notification.
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
- writer.WriteNow("baz");
+ writer.WriteNow(make_scoped_ptr(new std::string("baz")));
RunLoop().RunUntilIdle();
EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
@@ -143,15 +145,14 @@ TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
}
TEST_F(ImportantFileWriterTest, ScheduleWrite) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
EXPECT_FALSE(writer.HasPendingWrite());
DataSerializer serializer("foo");
writer.ScheduleWrite(&serializer);
EXPECT_TRUE(writer.HasPendingWrite());
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- MessageLoop::QuitWhenIdleClosure(),
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(100));
MessageLoop::current()->Run();
EXPECT_FALSE(writer.HasPendingWrite());
@@ -160,15 +161,14 @@ TEST_F(ImportantFileWriterTest, ScheduleWrite) {
}
TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
EXPECT_FALSE(writer.HasPendingWrite());
DataSerializer serializer("foo");
writer.ScheduleWrite(&serializer);
EXPECT_TRUE(writer.HasPendingWrite());
writer.DoScheduledWrite();
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- MessageLoop::QuitWhenIdleClosure(),
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(100));
MessageLoop::current()->Run();
EXPECT_FALSE(writer.HasPendingWrite());
@@ -177,15 +177,14 @@ TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
}
TEST_F(ImportantFileWriterTest, BatchingWrites) {
- ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
+ ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
DataSerializer foo("foo"), bar("bar"), baz("baz");
writer.ScheduleWrite(&foo);
writer.ScheduleWrite(&bar);
writer.ScheduleWrite(&baz);
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- MessageLoop::QuitWhenIdleClosure(),
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(100));
MessageLoop::current()->Run();
ASSERT_TRUE(PathExists(writer.path()));
diff --git a/chromium/base/files/memory_mapped_file.cc b/chromium/base/files/memory_mapped_file.cc
index 745a5ff1f45..891fcffc4cb 100644
--- a/chromium/base/files/memory_mapped_file.cc
+++ b/chromium/base/files/memory_mapped_file.cc
@@ -31,6 +31,7 @@ MemoryMappedFile::~MemoryMappedFile() {
CloseHandles();
}
+#if !defined(OS_NACL)
bool MemoryMappedFile::Initialize(const FilePath& file_name) {
if (IsValid())
return false;
@@ -85,5 +86,6 @@ void MemoryMappedFile::CalculateVMAlignedBoundaries(int64 start,
*aligned_start = start & ~mask;
*aligned_size = (size + *offset + mask) & ~mask;
}
+#endif
} // namespace base
diff --git a/chromium/base/files/memory_mapped_file_posix.cc b/chromium/base/files/memory_mapped_file_posix.cc
index ebf38779f03..168da923d46 100644
--- a/chromium/base/files/memory_mapped_file_posix.cc
+++ b/chromium/base/files/memory_mapped_file_posix.cc
@@ -16,6 +16,7 @@ namespace base {
MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
}
+#if !defined(OS_NACL)
bool MemoryMappedFile::MapFileRegionToMemory(
const MemoryMappedFile::Region& region) {
ThreadRestrictions::AssertIOAllowed();
@@ -74,6 +75,7 @@ bool MemoryMappedFile::MapFileRegionToMemory(
data_ += data_offset;
return true;
}
+#endif
void MemoryMappedFile::CloseHandles() {
ThreadRestrictions::AssertIOAllowed();
diff --git a/chromium/base/files/memory_mapped_file_unittest.cc b/chromium/base/files/memory_mapped_file_unittest.cc
index 36999bfba92..d0833b5cc9a 100644
--- a/chromium/base/files/memory_mapped_file_unittest.cc
+++ b/chromium/base/files/memory_mapped_file_unittest.cc
@@ -29,12 +29,12 @@ bool CheckBufferContents(const uint8* data, size_t size, size_t offset) {
class MemoryMappedFileTest : public PlatformTest {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
PlatformTest::SetUp();
CreateTemporaryFile(&temp_file_path_);
}
- virtual void TearDown() { EXPECT_TRUE(DeleteFile(temp_file_path_, false)); }
+ void TearDown() override { EXPECT_TRUE(DeleteFile(temp_file_path_, false)); }
void CreateTemporaryTestFile(size_t size) {
File file(temp_file_path_,
diff --git a/chromium/base/float_util.h b/chromium/base/float_util.h
deleted file mode 100644
index 90273106cd6..00000000000
--- a/chromium/base/float_util.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 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_FLOAT_UTIL_H_
-#define BASE_FLOAT_UTIL_H_
-
-#include "build/build_config.h"
-
-#include <float.h>
-
-#include <cmath>
-
-namespace base {
-
-template <typename Float>
-inline bool IsFinite(const Float& number) {
-#if defined(OS_POSIX)
- return std::isfinite(number) != 0;
-#elif defined(OS_WIN)
- return _finite(number) != 0;
-#endif
-}
-
-template <typename Float>
-inline bool IsNaN(const Float& number) {
-#if defined(OS_POSIX)
- return std::isnan(number) != 0;
-#elif defined(OS_WIN)
- return _isnan(number) != 0;
-#endif
-}
-
-} // namespace base
-
-#endif // BASE_FLOAT_UTIL_H_
diff --git a/chromium/base/format_macros.h b/chromium/base/format_macros.h
index 4d90c593a61..d58658d2b91 100644
--- a/chromium/base/format_macros.h
+++ b/chromium/base/format_macros.h
@@ -23,19 +23,20 @@
#include "build/build_config.h"
-#if defined(OS_POSIX)
-
-#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
+#if defined(OS_POSIX) && (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \
+ !defined(PRId64)
#error "inttypes.h has already been included before this header file, but "
#error "without __STDC_FORMAT_MACROS defined."
#endif
-#if !defined(__STDC_FORMAT_MACROS)
+#if defined(OS_POSIX) && !defined(__STDC_FORMAT_MACROS)
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
+#if defined(OS_POSIX)
+
// GCC will concatenate wide and narrow strings correctly, so nothing needs to
// be done here.
#define WidePRId64 PRId64
@@ -76,16 +77,8 @@
#else // OS_WIN
-#if !defined(PRId64)
-#define PRId64 "I64d"
-#endif
-
-#if !defined(PRIu64)
-#define PRIu64 "I64u"
-#endif
-
-#if !defined(PRIx64)
-#define PRIx64 "I64x"
+#if !defined(PRId64) || !defined(PRIu64) || !defined(PRIx64)
+#error "inttypes.h provided by win toolchain should define these."
#endif
#define WidePRId64 L"I64d"
diff --git a/chromium/base/guid_posix.cc b/chromium/base/guid_posix.cc
index 9681b084fa3..f0fedc27e57 100644
--- a/chromium/base/guid_posix.cc
+++ b/chromium/base/guid_posix.cc
@@ -39,4 +39,4 @@ std::string RandomDataToGUIDString(const uint64 bytes[2]) {
bytes[1] & 0x0000ffffffffffffULL);
}
-} // namespace guid
+} // namespace base
diff --git a/chromium/base/guid_win.cc b/chromium/base/guid_win.cc
index cdb860a0b9f..da3453dc73c 100644
--- a/chromium/base/guid_win.cc
+++ b/chromium/base/guid_win.cc
@@ -35,4 +35,4 @@ std::string GenerateGUID() {
return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
}
-} // namespace guid
+} // namespace base
diff --git a/chromium/base/i18n/break_iterator.cc b/chromium/base/i18n/break_iterator.cc
index e3aaa2b5b0b..e2ed667572f 100644
--- a/chromium/base/i18n/break_iterator.cc
+++ b/chromium/base/i18n/break_iterator.cc
@@ -74,7 +74,8 @@ bool BreakIterator::Init() {
static_cast<int32_t>(string_.size()),
&status);
if (U_FAILURE(status)) {
- NOTREACHED() << "ubrk_open failed";
+ NOTREACHED() << "ubrk_open failed for type " << break_type
+ << " with error " << status;
}
}
diff --git a/chromium/base/i18n/build_utf8_validator_tables.cc b/chromium/base/i18n/build_utf8_validator_tables.cc
index 45fc6cbf92b..ae5b1a71e9d 100644
--- a/chromium/base/i18n/build_utf8_validator_tables.cc
+++ b/chromium/base/i18n/build_utf8_validator_tables.cc
@@ -248,7 +248,7 @@ void MoveAllCharsToSets(PairVector* pairs) {
for (int i = 0; i < 4; ++i) {
MoveRightMostCharToSet(pairs);
}
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
for (PairVector::const_iterator it = pairs->begin(); it != pairs->end();
++it) {
DCHECK(it->character.empty());
@@ -425,16 +425,16 @@ void PrintStates(const std::vector<State>& states, FILE* stream) {
} // namespace
int main(int argc, char* argv[]) {
- CommandLine::Init(argc, argv);
+ base::CommandLine::Init(argc, argv);
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
logging::InitLogging(settings);
- if (CommandLine::ForCurrentProcess()->HasSwitch("help")) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch("help")) {
fwrite(kHelpText, 1, arraysize(kHelpText), stdout);
exit(EXIT_SUCCESS);
}
base::FilePath filename =
- CommandLine::ForCurrentProcess()->GetSwitchValuePath("output");
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath("output");
FILE* output = stdout;
if (!filename.empty()) {
diff --git a/chromium/base/i18n/char_iterator.h b/chromium/base/i18n/char_iterator.h
index 46928b37d0b..8174ef48f22 100644
--- a/chromium/base/i18n/char_iterator.h
+++ b/chromium/base/i18n/char_iterator.h
@@ -15,7 +15,7 @@
// UTF16 strings. Example usage:
//
// UTF8CharIterator iter(&str);
-// while (!iter.End()) {
+// while (!iter.end()) {
// VLOG(1) << iter.get();
// iter.Advance();
// }
diff --git a/chromium/base/i18n/file_util_icu.cc b/chromium/base/i18n/file_util_icu.cc
index b5c0b9d8f5f..f6e2c2956f4 100644
--- a/chromium/base/i18n/file_util_icu.cc
+++ b/chromium/base/i18n/file_util_icu.cc
@@ -30,12 +30,19 @@ class IllegalCharacters {
return Singleton<IllegalCharacters>::get();
}
- bool contains(UChar32 ucs4) {
- return !!set->contains(ucs4);
+ bool DisallowedEverywhere(UChar32 ucs4) {
+ return !!illegal_anywhere_->contains(ucs4);
}
- bool containsNone(const string16 &s) {
- return !!set->containsNone(icu::UnicodeString(s.c_str(), s.size()));
+ bool DisallowedLeadingOrTrailing(UChar32 ucs4) {
+ return !!illegal_at_ends_->contains(ucs4);
+ }
+
+ bool IsAllowedName(const string16& s) {
+ return s.empty() || (!!illegal_anywhere_->containsNone(
+ icu::UnicodeString(s.c_str(), s.size())) &&
+ !illegal_at_ends_->contains(*s.begin()) &&
+ !illegal_at_ends_->contains(*s.rbegin()));
}
private:
@@ -45,60 +52,61 @@ class IllegalCharacters {
IllegalCharacters();
~IllegalCharacters() { }
- scoped_ptr<icu::UnicodeSet> set;
+ // set of characters considered invalid anywhere inside a filename.
+ scoped_ptr<icu::UnicodeSet> illegal_anywhere_;
+
+ // set of characters considered invalid at either end of a filename.
+ scoped_ptr<icu::UnicodeSet> illegal_at_ends_;
DISALLOW_COPY_AND_ASSIGN(IllegalCharacters);
};
IllegalCharacters::IllegalCharacters() {
- UErrorCode status = U_ZERO_ERROR;
- // Control characters, formatting characters, non-characters, and
- // some printable ASCII characters regarded as dangerous ('"*/:<>?\\').
+ UErrorCode everywhere_status = U_ZERO_ERROR;
+ UErrorCode ends_status = U_ZERO_ERROR;
+ // Control characters, formatting characters, non-characters, path separators,
+ // and some printable ASCII characters regarded as dangerous ('"*/:<>?\\').
// See http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx
// and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx
- // TODO(jungshik): Revisit the set. ZWJ and ZWNJ are excluded because they
- // are legitimate in Arabic and some S/SE Asian scripts. However, when used
- // elsewhere, they can be confusing/problematic.
- // Also, consider wrapping the set with our Singleton class to create and
- // freeze it only once. Note that there's a trade-off between memory and
- // speed.
-#if defined(WCHAR_T_IS_UTF16)
- set.reset(new icu::UnicodeSet(icu::UnicodeString(
- L"[[\"*/:<>?\\\\|][:Cc:][:Cf:] - [\u200c\u200d]]"), status));
-#else
- set.reset(new icu::UnicodeSet(UNICODE_STRING_SIMPLE(
- "[[\"*/:<>?\\\\|][:Cc:][:Cf:] - [\\u200c\\u200d]]").unescape(),
- status));
-#endif
- DCHECK(U_SUCCESS(status));
+ // Note that code points in the "Other, Format" (Cf) category are ignored on
+ // HFS+ despite the ZERO_WIDTH_JOINER and ZERO_WIDTH_NON-JOINER being
+ // legitimate in Arabic and some S/SE Asian scripts. In addition tilde (~) is
+ // also excluded due to the possibility of interacting poorly with short
+ // filenames on VFAT. (Related to CVE-2014-9390)
+ illegal_anywhere_.reset(new icu::UnicodeSet(
+ UNICODE_STRING_SIMPLE("[[\"~*/:<>?\\\\|][:Cc:][:Cf:]]"),
+ everywhere_status));
+ illegal_at_ends_.reset(new icu::UnicodeSet(
+ UNICODE_STRING_SIMPLE("[[:WSpace:][.]]"), ends_status));
+ DCHECK(U_SUCCESS(everywhere_status));
+ DCHECK(U_SUCCESS(ends_status));
+
// Add non-characters. If this becomes a performance bottleneck by
// any chance, do not add these to |set| and change IsFilenameLegal()
// to check |ucs4 & 0xFFFEu == 0xFFFEu|, in addiition to calling
- // containsNone().
- set->add(0xFDD0, 0xFDEF);
+ // IsAllowedName().
+ illegal_anywhere_->add(0xFDD0, 0xFDEF);
for (int i = 0; i <= 0x10; ++i) {
int plane_base = 0x10000 * i;
- set->add(plane_base + 0xFFFE, plane_base + 0xFFFF);
+ illegal_anywhere_->add(plane_base + 0xFFFE, plane_base + 0xFFFF);
}
- set->freeze();
+ illegal_anywhere_->freeze();
+ illegal_at_ends_->freeze();
}
} // namespace
bool IsFilenameLegal(const string16& file_name) {
- return IllegalCharacters::GetInstance()->containsNone(file_name);
+ return IllegalCharacters::GetInstance()->IsAllowedName(file_name);
}
void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
char replace_char) {
- DCHECK(file_name);
-
- DCHECK(!(IllegalCharacters::GetInstance()->contains(replace_char)));
+ IllegalCharacters* illegal = IllegalCharacters::GetInstance();
- // Remove leading and trailing whitespace.
- TrimWhitespace(*file_name, TRIM_ALL, file_name);
+ DCHECK(!(illegal->DisallowedEverywhere(replace_char)));
+ DCHECK(!(illegal->DisallowedLeadingOrTrailing(replace_char)));
- 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;
@@ -122,7 +130,9 @@ void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
NOTREACHED();
#endif
- if (illegal->contains(code_point)) {
+ if (illegal->DisallowedEverywhere(code_point) ||
+ ((char_begin == 0 || cursor == static_cast<int>(file_name->length())) &&
+ illegal->DisallowedLeadingOrTrailing(code_point))) {
file_name->replace(char_begin, cursor - char_begin, 1, replace_char);
// We just made the potentially multi-byte/word char into one that only
// takes one byte/word, so need to adjust the cursor to point to the next
@@ -142,16 +152,15 @@ bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
collator->setStrength(icu::Collator::TERTIARY);
#if defined(OS_WIN)
- return CompareString16WithCollator(collator.get(),
- WideToUTF16(a.value()), WideToUTF16(b.value())) == UCOL_LESS;
+ return CompareString16WithCollator(*collator, WideToUTF16(a.value()),
+ WideToUTF16(b.value())) == UCOL_LESS;
#elif defined(OS_POSIX)
// On linux, the file system encoding is not defined. We assume
// SysNativeMBToWide takes care of it.
return CompareString16WithCollator(
- collator.get(),
- WideToUTF16(SysNativeMBToWide(a.value().c_str())),
- WideToUTF16(SysNativeMBToWide(b.value().c_str()))) == UCOL_LESS;
+ *collator, WideToUTF16(SysNativeMBToWide(a.value().c_str())),
+ WideToUTF16(SysNativeMBToWide(b.value().c_str()))) == UCOL_LESS;
#else
#error Not implemented on your system
#endif
diff --git a/chromium/base/i18n/file_util_icu.h b/chromium/base/i18n/file_util_icu.h
index 7dd94cd9b06..6d7f2ec6000 100644
--- a/chromium/base/i18n/file_util_icu.h
+++ b/chromium/base/i18n/file_util_icu.h
@@ -18,13 +18,23 @@ namespace i18n {
// param has the same restriction as that for ReplaceIllegalCharacters.
BASE_I18N_EXPORT bool IsFilenameLegal(const string16& file_name);
-// Replaces characters in 'file_name' that are illegal for file names with
-// 'replace_char'. 'file_name' must not be a full or relative path, but just the
+// Replaces characters in |file_name| that are illegal for file names with
+// |replace_char|. |file_name| must not be a full or relative path, but just the
// file name component (since slashes are considered illegal). Any leading or
-// trailing whitespace in 'file_name' is removed.
+// trailing whitespace or periods in |file_name| is also replaced with the
+// |replace_char|.
+//
// Example:
-// file_name == "bad:file*name?.txt", changed to: "bad-file-name-.txt" when
-// 'replace_char' is '-'.
+// "bad:file*name?.txt" will be turned into "bad_file_name_.txt" when
+// |replace_char| is '_'.
+//
+// Warning: Do not use this function as the sole means of sanitizing a filename.
+// While the resulting filename itself would be legal, it doesn't necessarily
+// mean that the file will behave safely. On Windows, certain reserved names
+// refer to devices rather than files (E.g. LPT1), and some filenames could be
+// interpreted as shell namespace extensions (E.g. Foo.{<GUID>}).
+//
+// TODO(asanka): Move full filename sanitization logic here.
BASE_I18N_EXPORT void ReplaceIllegalCharactersInPath(
FilePath::StringType* file_name,
char replace_char);
diff --git a/chromium/base/i18n/file_util_icu_unittest.cc b/chromium/base/i18n/file_util_icu_unittest.cc
index 369345b6add..8fa7f6a261d 100644
--- a/chromium/base/i18n/file_util_icu_unittest.cc
+++ b/chromium/base/i18n/file_util_icu_unittest.cc
@@ -20,24 +20,28 @@ class FileUtilICUTest : public PlatformTest {
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// Linux disallows some evil ASCII characters, but passes all non-ASCII.
-static const struct goodbad_pair {
+static const struct GoodBadPairLinux {
const char* bad_name;
const char* good_name;
-} kIllegalCharacterCases[] = {
- {"bad*file:name?.jpg", "bad-file-name-.jpg"},
+} kLinuxIllegalCharacterCases[] = {
+ {"bad*\\/file:name?.jpg", "bad---file-name-.jpg"},
{"**********::::.txt", "--------------.txt"},
{"\xe9\xf0zzzz.\xff", "\xe9\xf0zzzz.\xff"},
+ {" _ ", "-_-"},
+ {".", "-"},
+ {" .( ). ", "-.( ).-"},
+ {" ", "- -"},
};
TEST_F(FileUtilICUTest, ReplaceIllegalCharacersInPathLinuxTest) {
- for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
- std::string bad_name(kIllegalCharacterCases[i].bad_name);
+ for (size_t i = 0; i < arraysize(kLinuxIllegalCharacterCases); ++i) {
+ std::string bad_name(kLinuxIllegalCharacterCases[i].bad_name);
ReplaceIllegalCharactersInPath(&bad_name, '-');
- EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name);
+ EXPECT_EQ(kLinuxIllegalCharacterCases[i].good_name, bad_name);
}
}
-#else
+#endif
// For Mac & Windows, which both do Unicode validation on filenames. These
// characters are given as wide strings since its more convenient to specify
@@ -46,29 +50,36 @@ static const struct goodbad_pair {
const wchar_t* bad_name;
const wchar_t* good_name;
} kIllegalCharacterCases[] = {
- {L"bad*file:name?.jpg", L"bad-file-name-.jpg"},
- {L"**********::::.txt", L"--------------.txt"},
- // We can't use UCNs (universal character names) for C0/C1 characters and
- // U+007F, but \x escape is interpreted by MSVC and gcc as we intend.
- {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"},
-#if defined(OS_WIN)
- {L"bad*file\\name.jpg", L"bad-file-name.jpg"},
- {L"\t bad*file\\name/.jpg ", L"bad-file-name-.jpg"},
-#elif defined(OS_MACOSX)
- {L"bad*file?name.jpg", L"bad-file-name.jpg"},
- {L"\t bad*file?name/.jpg ", L"bad-file-name-.jpg"},
-#endif
- {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"},
- {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"},
- {L"\u0635\u200C\u0644.mp3", L"\u0635\u200C\u0644.mp3"},
- {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"},
- // Unassigned codepoints are ok.
- {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"},
- // Non-characters are not allowed.
- {L"bad\uFFFFfile\U0010FFFEname.jpg ", L"bad-file-name.jpg"},
- {L"bad\uFDD0file\uFDEFname.jpg ", L"bad-file-name.jpg"},
+ {L"bad*file:name?.jpg", L"bad-file-name-.jpg"},
+ {L"**********::::.txt", L"--------------.txt"},
+ // We can't use UCNs (universal character names) for C0/C1 characters and
+ // U+007F, but \x escape is interpreted by MSVC and gcc as we intend.
+ {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"},
+ {L"bad*file\\?name.jpg", L"bad-file--name.jpg"},
+ {L"\t bad*file\\name/.jpg", L"- bad-file-name-.jpg"},
+ {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"},
+ {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"},
+ {L"\u0635\u200C\u0644.mp3", L"\u0635-\u0644.mp3"},
+ {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"},
+ // Unassigned codepoints are ok.
+ {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"},
+ // Non-characters are not allowed.
+ {L"bad\uFFFFfile\U0010FFFEname.jpg", L"bad-file-name.jpg"},
+ {L"bad\uFDD0file\uFDEFname.jpg", L"bad-file-name.jpg"},
+ // CVE-2014-9390
+ {L"(\u200C.\u200D.\u200E.\u200F.\u202A.\u202B.\u202C.\u202D.\u202E.\u206A."
+ L"\u206B.\u206C.\u206D.\u206F.\uFEFF)",
+ L"(-.-.-.-.-.-.-.-.-.-.-.-.-.-.-)"},
+ {L"config~1", L"config-1"},
+ {L" _ ", L"-_-"},
+ {L" ", L"-"},
+ {L"\u2008.(\u2007).\u3000", L"-.(\u2007).-"},
+ {L" ", L"- -"},
+ {L". ", L"- -"}
};
+#if defined(OS_WIN) || defined(OS_MACOSX)
+
TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) {
for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
#if defined(OS_WIN)
@@ -85,6 +96,19 @@ TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) {
#endif
+TEST_F(FileUtilICUTest, IsFilenameLegalTest) {
+ EXPECT_TRUE(IsFilenameLegal(string16()));
+
+ for (const auto& test_case : kIllegalCharacterCases) {
+ string16 bad_name = WideToUTF16(test_case.bad_name);
+ string16 good_name = WideToUTF16(test_case.good_name);
+
+ EXPECT_TRUE(IsFilenameLegal(good_name)) << good_name;
+ if (good_name != bad_name)
+ EXPECT_FALSE(IsFilenameLegal(bad_name)) << bad_name;
+ }
+}
+
#if defined(OS_CHROMEOS)
static const struct normalize_name_encoding_test_cases {
const char* original_path;
diff --git a/chromium/base/i18n/i18n_constants.cc b/chromium/base/i18n/i18n_constants.cc
index 9b8c571564f..7d2f5fc0538 100644
--- a/chromium/base/i18n/i18n_constants.cc
+++ b/chromium/base/i18n/i18n_constants.cc
@@ -8,8 +8,6 @@ namespace base {
const char kCodepageLatin1[] = "ISO-8859-1";
const char kCodepageUTF8[] = "UTF-8";
-const char kCodepageUTF16BE[] = "UTF-16BE";
-const char kCodepageUTF16LE[] = "UTF-16LE";
} // namespace base
diff --git a/chromium/base/i18n/i18n_constants.h b/chromium/base/i18n/i18n_constants.h
index c2de842da1d..c1bd87dc485 100644
--- a/chromium/base/i18n/i18n_constants.h
+++ b/chromium/base/i18n/i18n_constants.h
@@ -12,8 +12,9 @@ namespace base {
// Names of codepages (charsets) understood by icu.
BASE_I18N_EXPORT extern const char kCodepageLatin1[]; // a.k.a. ISO 8859-1
BASE_I18N_EXPORT extern const char kCodepageUTF8[];
-BASE_I18N_EXPORT extern const char kCodepageUTF16BE[];
-BASE_I18N_EXPORT extern const char kCodepageUTF16LE[];
+
+// The other possible options are UTF-16BE and UTF-16LE, but they are unused in
+// Chromium as of this writing.
} // namespace base
diff --git a/chromium/base/i18n/icu_string_conversions.cc b/chromium/base/i18n/icu_string_conversions.cc
index 1530117f1e4..edb31c3525f 100644
--- a/chromium/base/i18n/icu_string_conversions.cc
+++ b/chromium/base/i18n/icu_string_conversions.cc
@@ -134,14 +134,6 @@ void SetUpErrorHandlerForToUChars(OnStringConversionError::Type on_error,
}
}
-inline UConverterType utf32_platform_endian() {
-#if U_IS_BIG_ENDIAN
- return UCNV_UTF32_BigEndian;
-#else
- return UCNV_UTF32_LittleEndian;
-#endif
-}
-
} // namespace
// Codepage <-> Wide/UTF-16 ---------------------------------------------------
@@ -197,74 +189,6 @@ bool CodepageToUTF16(const std::string& encoded,
return true;
}
-bool WideToCodepage(const std::wstring& wide,
- const char* codepage_name,
- OnStringConversionError::Type on_error,
- std::string* encoded) {
-#if defined(WCHAR_T_IS_UTF16)
- return UTF16ToCodepage(wide, codepage_name, on_error, encoded);
-#elif defined(WCHAR_T_IS_UTF32)
- encoded->clear();
-
- UErrorCode status = U_ZERO_ERROR;
- UConverter* converter = ucnv_open(codepage_name, &status);
- if (!U_SUCCESS(status))
- return false;
-
- int utf16_len;
- // When wchar_t is wider than UChar (16 bits), transform |wide| into a
- // UChar* string. Size the UChar* buffer to be large enough to hold twice
- // as many UTF-16 code units (UChar's) as there are Unicode code points,
- // in case each code points translates to a UTF-16 surrogate pair,
- // and leave room for a NUL terminator.
- std::vector<UChar> utf16(wide.length() * 2 + 1);
- u_strFromUTF32(&utf16[0], utf16.size(), &utf16_len,
- reinterpret_cast<const UChar32*>(wide.c_str()),
- wide.length(), &status);
- DCHECK(U_SUCCESS(status)) << "failed to convert wstring to UChar*";
-
- return ConvertFromUTF16(converter, &utf16[0], utf16_len, on_error, encoded);
-#endif // defined(WCHAR_T_IS_UTF32)
-}
-
-bool CodepageToWide(const std::string& encoded,
- const char* codepage_name,
- OnStringConversionError::Type on_error,
- std::wstring* wide) {
-#if defined(WCHAR_T_IS_UTF16)
- return CodepageToUTF16(encoded, codepage_name, on_error, wide);
-#elif defined(WCHAR_T_IS_UTF32)
- wide->clear();
-
- UErrorCode status = U_ZERO_ERROR;
- UConverter* converter = ucnv_open(codepage_name, &status);
- if (!U_SUCCESS(status))
- return false;
-
- // The maximum length in 4 byte unit of UTF-32 output would be
- // at most the same as the number of bytes in input. In the worst
- // case of GB18030 (excluding escaped-based encodings like ISO-2022-JP),
- // this can be 4 times larger than actually needed.
- size_t wchar_max_length = encoded.length() + 1;
-
- SetUpErrorHandlerForToUChars(on_error, converter, &status);
- scoped_ptr<wchar_t[]> buffer(new wchar_t[wchar_max_length]);
- int actual_size = ucnv_toAlgorithmic(utf32_platform_endian(), converter,
- reinterpret_cast<char*>(buffer.get()),
- static_cast<int>(wchar_max_length) * sizeof(wchar_t), encoded.data(),
- static_cast<int>(encoded.length()), &status);
- ucnv_close(converter);
- if (!U_SUCCESS(status)) {
- wide->clear(); // Make sure the output is empty on error.
- return false;
- }
-
- // actual_size is # of bytes.
- wide->assign(buffer.get(), actual_size / sizeof(wchar_t));
- return true;
-#endif // defined(WCHAR_T_IS_UTF32)
-}
-
bool ConvertToUtf8AndNormalize(const std::string& text,
const std::string& charset,
std::string* result) {
diff --git a/chromium/base/i18n/icu_string_conversions.h b/chromium/base/i18n/icu_string_conversions.h
index fd2ae46c529..9135da86a21 100644
--- a/chromium/base/i18n/icu_string_conversions.h
+++ b/chromium/base/i18n/icu_string_conversions.h
@@ -13,8 +13,7 @@
namespace base {
-// Defines the error handling modes of UTF16ToCodepage, CodepageToUTF16,
-// WideToCodepage and CodepageToWide.
+// Defines the error handling modes of UTF16ToCodepage and CodepageToUTF16.
class OnStringConversionError {
public:
enum Type {
@@ -47,18 +46,6 @@ BASE_I18N_EXPORT bool CodepageToUTF16(const std::string& encoded,
OnStringConversionError::Type on_error,
string16* utf16);
-// Converts between wide strings and the encoding specified. If the
-// encoding doesn't exist or the encoding fails (when on_error is FAIL),
-// returns false.
-BASE_I18N_EXPORT bool WideToCodepage(const std::wstring& wide,
- const char* codepage_name,
- OnStringConversionError::Type on_error,
- std::string* encoded);
-BASE_I18N_EXPORT bool CodepageToWide(const std::string& encoded,
- const char* codepage_name,
- OnStringConversionError::Type on_error,
- std::wstring* wide);
-
// Converts from any codepage to UTF-8 and ensures the resulting UTF-8 is
// normalized.
BASE_I18N_EXPORT bool ConvertToUtf8AndNormalize(const std::string& text,
diff --git a/chromium/base/i18n/icu_string_conversions_unittest.cc b/chromium/base/i18n/icu_string_conversions_unittest.cc
index d4d32518575..821529ddcee 100644
--- a/chromium/base/i18n/icu_string_conversions_unittest.cc
+++ b/chromium/base/i18n/icu_string_conversions_unittest.cc
@@ -42,49 +42,8 @@ string16 BuildString16(const wchar_t* s) {
#endif
}
-const wchar_t* const kConvertRoundtripCases[] = {
- L"Google Video",
- // "网页 图片 资讯更多 »"
- L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
- // "Παγκόσμιος Ιστός"
- L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
- L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
- // "Поиск страниц на русском"
- L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
- L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
- L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
- // "전체서비스"
- L"\xc804\xccb4\xc11c\xbe44\xc2a4",
-
- // Test characters that take more than 16 bits. This will depend on whether
- // wchar_t is 16 or 32 bits.
-#if defined(WCHAR_T_IS_UTF16)
- L"\xd800\xdf00",
- // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
- L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
-#elif defined(WCHAR_T_IS_UTF32)
- L"\x10300",
- // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
- L"\x11d40\x11d41\x11d42\x11d43\x11d44",
-#endif
-};
-
} // namespace
-TEST(ICUStringConversionsTest, ConvertCodepageUTF8) {
- // Make sure WideToCodepage works like WideToUTF8.
- for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
- SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %ls",
- i, kConvertRoundtripCases[i]));
-
- std::string expected(WideToUTF8(kConvertRoundtripCases[i]));
- std::string utf8;
- EXPECT_TRUE(WideToCodepage(kConvertRoundtripCases[i], kCodepageUTF8,
- OnStringConversionError::SKIP, &utf8));
- EXPECT_EQ(expected, utf8);
- }
-}
-
// kConverterCodepageCases is not comprehensive. There are a number of cases
// to add if we really want to have a comprehensive coverage of various
// codepages and their 'idiosyncrasies'. Currently, the only implementation
@@ -233,73 +192,6 @@ static const struct {
NULL},
};
-TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndWide) {
- for (size_t i = 0; i < arraysize(kConvertCodepageCases); ++i) {
- SCOPED_TRACE(base::StringPrintf(
- "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
- kConvertCodepageCases[i].encoded,
- kConvertCodepageCases[i].codepage_name));
-
- std::wstring wide;
- bool success = CodepageToWide(kConvertCodepageCases[i].encoded,
- kConvertCodepageCases[i].codepage_name,
- kConvertCodepageCases[i].on_error,
- &wide);
- EXPECT_EQ(kConvertCodepageCases[i].success, success);
- EXPECT_EQ(kConvertCodepageCases[i].wide, wide);
-
- // When decoding was successful and nothing was skipped, we also check the
- // reverse conversion. Not all conversions are round-trippable, but
- // kConverterCodepageCases does not have any one-way conversion at the
- // moment.
- if (success &&
- kConvertCodepageCases[i].on_error ==
- OnStringConversionError::FAIL) {
- std::string encoded;
- success = WideToCodepage(wide, kConvertCodepageCases[i].codepage_name,
- kConvertCodepageCases[i].on_error, &encoded);
- EXPECT_EQ(kConvertCodepageCases[i].success, success);
- EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded);
- }
- }
-
- // The above cases handled codepage->wide errors, but not wide->codepage.
- // Test that here.
- std::string encoded("Temp data"); // Make sure the string gets cleared.
-
- // First test going to an encoding that can not represent that character.
- EXPECT_FALSE(WideToCodepage(L"Chinese\xff27", "iso-8859-1",
- OnStringConversionError::FAIL, &encoded));
- EXPECT_TRUE(encoded.empty());
- EXPECT_TRUE(WideToCodepage(L"Chinese\xff27", "iso-8859-1",
- OnStringConversionError::SKIP, &encoded));
- EXPECT_STREQ("Chinese", encoded.c_str());
- // From Unicode, SUBSTITUTE is the same as SKIP for now.
- EXPECT_TRUE(WideToCodepage(L"Chinese\xff27", "iso-8859-1",
- OnStringConversionError::SUBSTITUTE,
- &encoded));
- EXPECT_STREQ("Chinese", encoded.c_str());
-
-#if defined(WCHAR_T_IS_UTF16)
- // When we're in UTF-16 mode, test an invalid UTF-16 character in the input.
- EXPECT_FALSE(WideToCodepage(L"a\xd800z", "iso-8859-1",
- OnStringConversionError::FAIL, &encoded));
- EXPECT_TRUE(encoded.empty());
- EXPECT_TRUE(WideToCodepage(L"a\xd800z", "iso-8859-1",
- OnStringConversionError::SKIP, &encoded));
- EXPECT_STREQ("az", encoded.c_str());
-#endif // WCHAR_T_IS_UTF16
-
- // Invalid characters should fail.
- EXPECT_TRUE(WideToCodepage(L"a\xffffz", "iso-8859-1",
- OnStringConversionError::SKIP, &encoded));
- EXPECT_STREQ("az", encoded.c_str());
-
- // Invalid codepages should fail.
- EXPECT_FALSE(WideToCodepage(L"Hello, world", "awesome-8571-2",
- OnStringConversionError::SKIP, &encoded));
-}
-
TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) {
for (size_t i = 0; i < arraysize(kConvertCodepageCases); ++i) {
SCOPED_TRACE(base::StringPrintf(
diff --git a/chromium/base/i18n/icu_util.cc b/chromium/base/i18n/icu_util.cc
index e0bd62cc50b..a9f0b129633 100644
--- a/chromium/base/i18n/icu_util.cc
+++ b/chromium/base/i18n/icu_util.cc
@@ -10,6 +10,7 @@
#include <string>
+#include "base/debug/alias.h"
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
@@ -18,6 +19,9 @@
#include "base/strings/sys_string_conversions.h"
#include "third_party/icu/source/common/unicode/putil.h"
#include "third_party/icu/source/common/unicode/udata.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
#if defined(OS_MACOSX)
#include "base/mac/foundation_util.h"
@@ -27,35 +31,38 @@
#define ICU_UTIL_DATA_SHARED 1
#define ICU_UTIL_DATA_STATIC 2
-#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+namespace base {
+namespace i18n {
+
// Use an unversioned file name to simplify a icu version update down the road.
// No need to change the filename in multiple places (gyp files, windows
// build pkg configurations, etc). 'l' stands for Little Endian.
-#define ICU_UTIL_DATA_FILE_NAME "icudtl.dat"
-#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
+// This variable is exported through the header file.
+const char kIcuDataFileName[] = "icudtl.dat";
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
#if defined(OS_WIN)
#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll"
#endif
#endif
-namespace base {
-namespace i18n {
-
namespace {
#if !defined(NDEBUG)
// Assert that we are not called more than once. Even though calling this
// function isn't harmful (ICU can handle it), being called twice probably
// indicates a programming error.
+#if !defined(OS_NACL)
bool g_called_once = false;
+#endif
bool g_check_called_once = true;
#endif
}
-
-#if defined(OS_ANDROID)
-bool InitializeICUWithFileDescriptor(int data_fd) {
+#if !defined(OS_NACL)
+bool InitializeICUWithFileDescriptor(
+ PlatformFile data_fd,
+ MemoryMappedFile::Region data_region) {
#if !defined(NDEBUG)
DCHECK(!g_check_called_once || !g_called_once);
g_called_once = true;
@@ -65,9 +72,9 @@ bool InitializeICUWithFileDescriptor(int data_fd) {
// The ICU data is statically linked.
return true;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
- CR_DEFINE_STATIC_LOCAL(base::MemoryMappedFile, mapped_file, ());
+ CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
if (!mapped_file.IsValid()) {
- if (!mapped_file.Initialize(base::File(data_fd))) {
+ if (!mapped_file.Initialize(File(data_fd), data_region)) {
LOG(ERROR) << "Couldn't mmap icu data file";
return false;
}
@@ -77,7 +84,6 @@ bool InitializeICUWithFileDescriptor(int data_fd) {
return err == U_ZERO_ERROR;
#endif // ICU_UTIL_DATA_FILE
}
-#endif
bool InitializeICU() {
@@ -86,10 +92,11 @@ bool InitializeICU() {
g_called_once = true;
#endif
+ bool result;
#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
// We expect to find the ICU data module alongside the current module.
FilePath data_path;
- PathService::Get(base::DIR_MODULE, &data_path);
+ PathService::Get(DIR_MODULE, &data_path);
data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME);
HMODULE module = LoadLibrary(data_path.value().c_str());
@@ -107,10 +114,10 @@ bool InitializeICU() {
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(reinterpret_cast<void*>(addr), &err);
- return err == U_ZERO_ERROR;
+ result = (err == U_ZERO_ERROR);
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
// The ICU data is statically linked.
- return true;
+ result = true;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
// If the ICU data directory is set, ICU won't actually load the data until
// it is needed. This can fail if the process is sandboxed at that time.
@@ -119,42 +126,74 @@ bool InitializeICU() {
// Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
// be released.
- CR_DEFINE_STATIC_LOCAL(base::MemoryMappedFile, mapped_file, ());
+ CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
if (!mapped_file.IsValid()) {
#if !defined(OS_MACOSX)
FilePath data_path;
#if defined(OS_WIN)
// The data file will be in the same directory as the current module.
- bool path_ok = PathService::Get(base::DIR_MODULE, &data_path);
+ bool path_ok = PathService::Get(DIR_MODULE, &data_path);
+ wchar_t tmp_buffer[_MAX_PATH] = {0};
+ wcscpy_s(tmp_buffer, data_path.value().c_str());
+ debug::Alias(tmp_buffer);
+ CHECK(path_ok); // TODO(scottmg): http://crbug.com/445616
#elif defined(OS_ANDROID)
- bool path_ok = PathService::Get(base::DIR_ANDROID_APP_DATA, &data_path);
+ bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
#else
// For now, expect the data file to be alongside the executable.
// This is sufficient while we work on unit tests, but will eventually
// likely live in a data directory.
- bool path_ok = PathService::Get(base::DIR_EXE, &data_path);
+ bool path_ok = PathService::Get(DIR_EXE, &data_path);
#endif
DCHECK(path_ok);
- data_path = data_path.AppendASCII(ICU_UTIL_DATA_FILE_NAME);
+ data_path = data_path.AppendASCII(kIcuDataFileName);
+
+#if defined(OS_WIN)
+ // TODO(scottmg): http://crbug.com/445616
+ wchar_t tmp_buffer2[_MAX_PATH] = {0};
+ wcscpy_s(tmp_buffer2, data_path.value().c_str());
+ debug::Alias(tmp_buffer2);
+#endif
+
#else
// Assume it is in the framework bundle's Resources directory.
+ ScopedCFTypeRef<CFStringRef> data_file_name(
+ SysUTF8ToCFStringRef(kIcuDataFileName));
FilePath data_path =
- base::mac::PathForFrameworkBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME));
+ mac::PathForFrameworkBundleResource(data_file_name);
if (data_path.empty()) {
- LOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle";
+ LOG(ERROR) << kIcuDataFileName << " not found in bundle";
return false;
}
#endif // OS check
if (!mapped_file.Initialize(data_path)) {
+#if defined(OS_WIN)
+ CHECK(false); // TODO(scottmg): http://crbug.com/445616
+#endif
LOG(ERROR) << "Couldn't mmap " << data_path.AsUTF8Unsafe();
return false;
}
}
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
- return err == U_ZERO_ERROR;
+ result = (err == U_ZERO_ERROR);
+#if defined(OS_WIN)
+ CHECK(result); // TODO(scottmg): http://crbug.com/445616
+#endif
#endif
+
+// To respond to the timezone change properly, the default timezone
+// cache in ICU has to be populated on starting up.
+// TODO(jungshik): Some callers do not care about tz at all. If necessary,
+// add a boolean argument to this function to init'd the default tz only
+// when requested.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (result)
+ scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+ return result;
}
+#endif
void AllowMultipleInitializeCallsForTesting() {
#if !defined(NDEBUG)
diff --git a/chromium/base/i18n/icu_util.h b/chromium/base/i18n/icu_util.h
index b0a5dbcce6d..65de0ad7e21 100644
--- a/chromium/base/i18n/icu_util.h
+++ b/chromium/base/i18n/icu_util.h
@@ -5,20 +5,25 @@
#ifndef BASE_I18N_ICU_UTIL_H_
#define BASE_I18N_ICU_UTIL_H_
-#include "build/build_config.h"
+#include "base/files/memory_mapped_file.h"
#include "base/i18n/base_i18n_export.h"
+#include "build/build_config.h"
namespace base {
namespace i18n {
+BASE_I18N_EXPORT extern const char kIcuDataFileName[];
+
+#if !defined(OS_NACL)
// Call this function to load ICU's data tables for the current process. This
// function should be called before ICU is used.
BASE_I18N_EXPORT bool InitializeICU();
-#if defined(OS_ANDROID)
-// Android uses a file descriptor passed by browser process to initialize ICU
-// in render processes.
-BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(int data_fd);
+// Android and html_viewer use a file descriptor passed by browser process to
+// initialize ICU in render processes.
+BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
+ PlatformFile data_fd,
+ MemoryMappedFile::Region data_region);
#endif
// In a test binary, the call above might occur twice.
diff --git a/chromium/base/i18n/rtl.cc b/chromium/base/i18n/rtl.cc
index 392cb13bdb7..1cccae28937 100644
--- a/chromium/base/i18n/rtl.cc
+++ b/chromium/base/i18n/rtl.cc
@@ -74,8 +74,8 @@ std::string GetConfiguredLocale() {
}
// Convert the ICU canonicalized locale to a string.
-std::string GetCanonicalLocale(const char* locale) {
- return GetLocaleString(icu::Locale::createCanonical(locale));
+std::string GetCanonicalLocale(const std::string& locale) {
+ return GetLocaleString(icu::Locale::createCanonical(locale.c_str()));
}
// Convert Chrome locale name to ICU locale name
diff --git a/chromium/base/i18n/rtl.h b/chromium/base/i18n/rtl.h
index aa5f6810a9b..9b9a0dcd31c 100644
--- a/chromium/base/i18n/rtl.h
+++ b/chromium/base/i18n/rtl.h
@@ -40,7 +40,7 @@ enum TextDirection {
BASE_I18N_EXPORT std::string GetConfiguredLocale();
// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name.
-BASE_I18N_EXPORT std::string GetCanonicalLocale(const char* locale);
+BASE_I18N_EXPORT std::string GetCanonicalLocale(const std::string& locale);
// Sets the default locale of ICU.
// Once the application locale of Chrome in GetApplicationLocale is determined,
diff --git a/chromium/base/i18n/streaming_utf8_validator_perftest.cc b/chromium/base/i18n/streaming_utf8_validator_perftest.cc
index ac2eb0820ba..6b8c17b654b 100644
--- a/chromium/base/i18n/streaming_utf8_validator_perftest.cc
+++ b/chromium/base/i18n/streaming_utf8_validator_perftest.cc
@@ -134,6 +134,10 @@ struct TestFunctionDescription {
const char* function_name;
};
+bool IsStringUTF8(const std::string& str) {
+ return base::IsStringUTF8(base::StringPiece(str));
+}
+
// IsString7Bit is intentionally placed last so it can be excluded easily.
const TestFunctionDescription kTestFunctions[] = {
{&StreamingUtf8Validator::Validate, "StreamingUtf8Validator"},
diff --git a/chromium/base/i18n/string_compare.cc b/chromium/base/i18n/string_compare.cc
index 1ac7284359c..2851e7d2dce 100644
--- a/chromium/base/i18n/string_compare.cc
+++ b/chromium/base/i18n/string_compare.cc
@@ -12,12 +12,11 @@ namespace i18n {
// Compares the character data stored in two different string16 strings by
// specified Collator instance.
-UCollationResult CompareString16WithCollator(const icu::Collator* collator,
+UCollationResult CompareString16WithCollator(const icu::Collator& collator,
const string16& lhs,
const string16& rhs) {
- DCHECK(collator);
UErrorCode error = U_ZERO_ERROR;
- UCollationResult result = collator->compare(
+ UCollationResult result = collator.compare(
static_cast<const UChar*>(lhs.c_str()), static_cast<int>(lhs.length()),
static_cast<const UChar*>(rhs.c_str()), static_cast<int>(rhs.length()),
error);
diff --git a/chromium/base/i18n/string_compare.h b/chromium/base/i18n/string_compare.h
index f0f3e297f09..5fcc5feaede 100644
--- a/chromium/base/i18n/string_compare.h
+++ b/chromium/base/i18n/string_compare.h
@@ -17,12 +17,12 @@ namespace base {
namespace i18n {
// Compares the two strings using the specified collator.
-BASE_I18N_EXPORT UCollationResult CompareString16WithCollator(
- const icu::Collator* collator,
- const string16& lhs,
- const string16& rhs);
+BASE_I18N_EXPORT UCollationResult
+CompareString16WithCollator(const icu::Collator& collator,
+ const string16& lhs,
+ const string16& rhs);
} // namespace i18n
} // namespace base
-#endif // BASE_I18N_STRING_COMPARATOR_H_
+#endif // BASE_I18N_STRING_COMPARE_H_
diff --git a/chromium/base/i18n/time_formatting.cc b/chromium/base/i18n/time_formatting.cc
index 917ba43b9ec..15b34a31f91 100644
--- a/chromium/base/i18n/time_formatting.cc
+++ b/chromium/base/i18n/time_formatting.cc
@@ -106,6 +106,12 @@ string16 TimeFormatShortDateAndTime(const Time& time) {
return TimeFormat(formatter.get(), time);
}
+string16 TimeFormatShortDateAndTimeWithTimeZone(const Time& time) {
+ scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateTimeInstance(
+ icu::DateFormat::kShort, icu::DateFormat::kLong));
+ return TimeFormat(formatter.get(), time);
+}
+
string16 TimeFormatFriendlyDateAndTime(const Time& time) {
scoped_ptr<icu::DateFormat> formatter(
icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull));
diff --git a/chromium/base/i18n/time_formatting.h b/chromium/base/i18n/time_formatting.h
index 226d1a91a22..2053c0b47da 100644
--- a/chromium/base/i18n/time_formatting.h
+++ b/chromium/base/i18n/time_formatting.h
@@ -48,6 +48,11 @@ BASE_I18N_EXPORT string16 TimeFormatShortDateNumeric(const Time& time);
// Returns a numeric date and time such as "12/13/52 2:44:30 PM".
BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time);
+// Returns a numeric date and time with time zone such as
+// "12/13/52 2:44:30 PM PST".
+BASE_I18N_EXPORT string16
+TimeFormatShortDateAndTimeWithTimeZone(const Time& time);
+
// Formats a time in a friendly sentence format, e.g.
// "Monday, March 6, 2008 2:44:30 PM".
BASE_I18N_EXPORT string16 TimeFormatFriendlyDateAndTime(const Time& time);
diff --git a/chromium/base/i18n/time_formatting_unittest.cc b/chromium/base/i18n/time_formatting_unittest.cc
index 03a3aa3ec77..df0c1ed5ea1 100644
--- a/chromium/base/i18n/time_formatting_unittest.cc
+++ b/chromium/base/i18n/time_formatting_unittest.cc
@@ -5,10 +5,13 @@
#include "base/i18n/time_formatting.h"
#include "base/i18n/rtl.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/icu/source/common/unicode/uversion.h"
+#include "third_party/icu/source/i18n/unicode/calendar.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
namespace base {
namespace {
@@ -18,6 +21,13 @@ const Time::Exploded kTestDateTimeExploded = {
15, 42, 7, 0 // 15:42:07.000
};
+base::string16 GetShortTimeZone() {
+ scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+ icu::UnicodeString name;
+ zone->getDisplayName(true, icu::TimeZone::SHORT, name);
+ return base::string16(name.getBuffer(), name.length());
+}
+
TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault12h) {
// Test for a locale defaulted to 12h clock.
// As an instance, we use third_party/icu/source/data/locales/en.txt.
@@ -58,12 +68,7 @@ TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault24h) {
Time time(Time::FromLocalExploded(kTestDateTimeExploded));
string16 clock24h(ASCIIToUTF16("15:42"));
-#if U_ICU_VERSION_MAJOR_NUM >= 50
string16 clock12h_pm(ASCIIToUTF16("3:42 pm"));
-#else
- // TODO(phajdan.jr): Clean up after bundled ICU gets updated to 50.
- string16 clock12h_pm(ASCIIToUTF16("3:42 PM"));
-#endif
string16 clock12h(ASCIIToUTF16("3:42"));
// The default is 24h clock.
@@ -132,23 +137,13 @@ TEST(TimeFormattingTest, TimeFormatDateUS) {
EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatShortDate(time));
EXPECT_EQ(ASCIIToUTF16("4/30/11"), TimeFormatShortDateNumeric(time));
-#if U_ICU_VERSION_MAJOR_NUM >= 50
EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"),
TimeFormatShortDateAndTime(time));
-#else
- // TODO(phajdan.jr): Clean up after bundled ICU gets updated to 50.
- EXPECT_EQ(ASCIIToUTF16("4/30/11 3:42:07 PM"),
- TimeFormatShortDateAndTime(time));
-#endif
+ EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(),
+ TimeFormatShortDateAndTimeWithTimeZone(time));
-#if U_ICU_VERSION_MAJOR_NUM >= 50
EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"),
TimeFormatFriendlyDateAndTime(time));
-#else
- // TODO(phajdan.jr): Clean up after bundled ICU gets updated to 50.
- EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 3:42:07 PM"),
- TimeFormatFriendlyDateAndTime(time));
-#endif
EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011"),
TimeFormatFriendlyDate(time));
@@ -163,9 +158,11 @@ TEST(TimeFormattingTest, TimeFormatDateGB) {
EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time));
EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time));
- EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07"),
+ EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07"),
TimeFormatShortDateAndTime(time));
- EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 15:42:07"),
+ EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(),
+ TimeFormatShortDateAndTimeWithTimeZone(time));
+ EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
TimeFormatFriendlyDateAndTime(time));
EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"),
TimeFormatFriendlyDate(time));
diff --git a/chromium/base/i18n/timezone.h b/chromium/base/i18n/timezone.h
index b7275f7b00b..f7fda941188 100644
--- a/chromium/base/i18n/timezone.h
+++ b/chromium/base/i18n/timezone.h
@@ -18,4 +18,4 @@ BASE_I18N_EXPORT std::string CountryCodeForCurrentTimezone();
} // namespace base
-#endif // BASE_TIME_TIMEZONE_H_
+#endif // BASE_I18N_TIMEZONE_H_
diff --git a/chromium/base/id_map.h b/chromium/base/id_map.h
index 9cbc1f8978f..852c1380471 100644
--- a/chromium/base/id_map.h
+++ b/chromium/base/id_map.h
@@ -53,13 +53,14 @@ class IDMap : public base::NonThreadSafe {
Releaser<OS, 0>::release_all(&data_);
}
- // Sets whether Add should CHECK if passed in NULL data. Default is false.
+ // Sets whether Add and Replace should DCHECK if passed in NULL data.
+ // Default is false.
void set_check_on_null_data(bool value) { check_on_null_data_ = value; }
// Adds a view with an automatically generated unique ID. See AddWithID.
KeyType Add(T* data) {
DCHECK(CalledOnValidThread());
- CHECK(!check_on_null_data_ || data);
+ DCHECK(!check_on_null_data_ || data);
KeyType this_id = next_id_;
DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
data_[this_id] = data;
@@ -73,7 +74,7 @@ class IDMap : public base::NonThreadSafe {
// two methods may not be mixed, or duplicate IDs may be generated
void AddWithID(T* data, KeyType id) {
DCHECK(CalledOnValidThread());
- CHECK(!check_on_null_data_ || data);
+ DCHECK(!check_on_null_data_ || data);
DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
data_[id] = data;
}
@@ -94,6 +95,25 @@ class IDMap : public base::NonThreadSafe {
}
}
+ // Replaces the value for |id| with |new_data| and returns a pointer to the
+ // existing value. If there is no entry for |id|, the map is not altered and
+ // nullptr is returned. The OwnershipSemantics of the map have no effect on
+ // how the existing value is treated, the IDMap does not delete the existing
+ // value being replaced.
+ T* Replace(KeyType id, T* new_data) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!check_on_null_data_ || new_data);
+ typename HashTable::iterator i = data_.find(id);
+ if (i == data_.end()) {
+ NOTREACHED() << "Attempting to replace an item not in the list";
+ return nullptr;
+ }
+
+ T* temp = i->second;
+ i->second = new_data;
+ return temp;
+ }
+
void Clear() {
DCHECK(CalledOnValidThread());
if (iteration_depth_ == 0) {
diff --git a/chromium/base/id_map_unittest.cc b/chromium/base/id_map_unittest.cc
index c005a690578..a9fb2b9decd 100644
--- a/chromium/base/id_map_unittest.cc
+++ b/chromium/base/id_map_unittest.cc
@@ -53,6 +53,9 @@ TEST(IDMapTest, Basic) {
EXPECT_EQ(&obj1, map.Lookup(1));
EXPECT_EQ(&obj2, map.Lookup(2));
+ EXPECT_EQ(&obj2, map.Replace(2, &obj1));
+ EXPECT_EQ(&obj1, map.Lookup(2));
+
EXPECT_EQ(0, map.iteration_depth());
}
diff --git a/chromium/base/ios/block_types.h b/chromium/base/ios/block_types.h
new file mode 100644
index 00000000000..e4dde798aa4
--- /dev/null
+++ b/chromium/base/ios/block_types.h
@@ -0,0 +1,14 @@
+// Copyright 2013 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_IOS_BLOCK_TYPES_H_
+#define BASE_IOS_BLOCK_TYPES_H_
+
+// A generic procedural block type that takes no arguments and returns nothing.
+typedef void (^ProceduralBlock)(void);
+
+// A block that takes no arguments and returns a bool.
+typedef bool (^ConditionBlock)(void);
+
+#endif // BASE_IOS_BLOCK_TYPES_H_
diff --git a/chromium/base/ios/crb_protocol_observers.h b/chromium/base/ios/crb_protocol_observers.h
new file mode 100644
index 00000000000..15d16569ff8
--- /dev/null
+++ b/chromium/base/ios/crb_protocol_observers.h
@@ -0,0 +1,36 @@
+// Copyright 2014 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_IOS_CRB_PROTOCOL_OBSERVERS_H_
+#define BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
+
+#import <Foundation/Foundation.h>
+
+typedef void (^ExecutionWithObserverBlock)(id);
+
+// Implements a container for observers that implement a specific Objective-C
+// protocol. The container forwards method invocations to its contained
+// observers, so that sending a message to all the observers is as simple as
+// sending the message to the container.
+@interface CRBProtocolObservers : NSObject
+
+// The Objective-C protocol that the observers in this container conform to.
+@property(nonatomic, readonly) Protocol* protocol;
+
+// Returns a CRBProtocolObservers container for observers that conform to
+// |protocol|.
++ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol;
+
+// Adds |observer| to this container.
+- (void)addObserver:(id)observer;
+
+// Remove |observer| from this container.
+- (void)removeObserver:(id)observer;
+
+// Executes callback on every observer. |callback| cannot be nil.
+- (void)executeOnObservers:(ExecutionWithObserverBlock)callback;
+
+@end
+
+#endif // BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
diff --git a/chromium/base/ios/crb_protocol_observers.mm b/chromium/base/ios/crb_protocol_observers.mm
new file mode 100644
index 00000000000..ee9e23fcb4e
--- /dev/null
+++ b/chromium/base/ios/crb_protocol_observers.mm
@@ -0,0 +1,99 @@
+// Copyright 2014 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 "base/ios/crb_protocol_observers.h"
+
+#include <objc/runtime.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+@interface CRBProtocolObservers ()
+
+// Designated initializer.
+- (id)initWithProtocol:(Protocol*)protocol;
+
+@end
+
+@implementation CRBProtocolObservers {
+ base::scoped_nsobject<Protocol> _protocol;
+ base::scoped_nsobject<NSHashTable> _observers;
+}
+
++ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol {
+ return [[[self alloc] initWithProtocol:protocol] autorelease];
+}
+
+- (id)init {
+ NOTREACHED();
+ return nil;
+}
+
+- (id)initWithProtocol:(Protocol*)protocol {
+ self = [super init];
+ if (self) {
+ _protocol.reset([protocol retain]);
+ _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
+ }
+ return self;
+}
+
+- (Protocol*)protocol {
+ return _protocol.get();
+}
+
+- (void)addObserver:(id)observer {
+ DCHECK([observer conformsToProtocol:self.protocol]);
+ [_observers addObject:observer];
+}
+
+- (void)removeObserver:(id)observer {
+ [_observers removeObject:observer];
+}
+
+#pragma mark - NSObject
+
+- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
+ NSMethodSignature* signature = [super methodSignatureForSelector:selector];
+ if (signature)
+ return signature;
+
+ // Look for a required method in the protocol. protocol_getMethodDescription
+ // returns a struct whose fields are null if a method for the selector was
+ // not found.
+ struct objc_method_description description =
+ protocol_getMethodDescription(self.protocol, selector, YES, YES);
+ if (description.types)
+ return [NSMethodSignature signatureWithObjCTypes:description.types];
+
+ // Look for an optional method in the protocol.
+ description = protocol_getMethodDescription(self.protocol, selector, NO, YES);
+ if (description.types)
+ return [NSMethodSignature signatureWithObjCTypes:description.types];
+
+ // There is neither a required nor optional method with this selector in the
+ // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
+ // NSInvalidArgumentException.
+ [self doesNotRecognizeSelector:selector];
+ return nil;
+}
+
+- (void)forwardInvocation:(NSInvocation*)invocation {
+ SEL selector = [invocation selector];
+ base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
+ for (id observer in observers.get()) {
+ if ([observer respondsToSelector:selector])
+ [invocation invokeWithTarget:observer];
+ }
+}
+
+- (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
+ DCHECK(callback);
+ base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
+ for (id observer in observers.get()) {
+ callback(observer);
+ }
+}
+
+@end
diff --git a/chromium/base/ios/crb_protocol_observers_unittest.mm b/chromium/base/ios/crb_protocol_observers_unittest.mm
new file mode 100644
index 00000000000..d235c98b21f
--- /dev/null
+++ b/chromium/base/ios/crb_protocol_observers_unittest.mm
@@ -0,0 +1,159 @@
+// Copyright 2014 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 "base/ios/crb_protocol_observers.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+@protocol TestObserver
+
+@required
+- (void)requiredMethod;
+- (void)reset;
+
+@optional
+- (void)optionalMethod;
+
+@end
+
+// Implements only the required methods in the TestObserver protocol.
+@interface TestPartialObserver : NSObject<TestObserver>
+@property(nonatomic, readonly) BOOL requiredMethodInvoked;
+@end
+
+// Implements all the methods in the TestObserver protocol.
+@interface TestCompleteObserver : TestPartialObserver<TestObserver>
+@property(nonatomic, readonly) BOOL optionalMethodInvoked;
+@end
+
+namespace {
+
+class CRBProtocolObserversTest : public PlatformTest {
+ public:
+ CRBProtocolObserversTest() {}
+
+ protected:
+ void SetUp() override {
+ PlatformTest::SetUp();
+
+ observers_.reset([[CRBProtocolObservers observersWithProtocol:
+ @protocol(TestObserver)] retain]);
+
+ partial_observer_.reset([[TestPartialObserver alloc] init]);
+ EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+ complete_observer_.reset([[TestCompleteObserver alloc] init]);
+ EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
+ EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
+ }
+
+ base::scoped_nsobject<id> observers_;
+ base::scoped_nsobject<TestPartialObserver> partial_observer_;
+ base::scoped_nsobject<TestCompleteObserver> complete_observer_;
+};
+
+// Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
+// -[CRBProtocolObservers removeObserver:].
+TEST_F(CRBProtocolObserversTest, AddRemoveObserver) {
+ // Add an observer and verify that the CRBProtocolObservers instance forwards
+ // an invocation to it.
+ [observers_ addObserver:partial_observer_];
+ [observers_ requiredMethod];
+ EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+ [partial_observer_ reset];
+ EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+ // Remove the observer and verify that the CRBProtocolObservers instance no
+ // longer forwards an invocation to it.
+ [observers_ removeObserver:partial_observer_];
+ [observers_ requiredMethod];
+ EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers correctly forwards the invocation of a
+// required method in the protocol.
+TEST_F(CRBProtocolObserversTest, RequiredMethods) {
+ [observers_ addObserver:partial_observer_];
+ [observers_ addObserver:complete_observer_];
+ [observers_ requiredMethod];
+ EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+ EXPECT_TRUE([complete_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers correctly forwards the invocation of an
+// optional method in the protocol.
+TEST_F(CRBProtocolObserversTest, OptionalMethods) {
+ [observers_ addObserver:partial_observer_];
+ [observers_ addObserver:complete_observer_];
+ [observers_ optionalMethod];
+ EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+ EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
+ EXPECT_TRUE([complete_observer_ optionalMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers only holds a weak reference to an
+// observer.
+TEST_F(CRBProtocolObserversTest, WeakReference) {
+ base::WeakNSObject<TestPartialObserver> weak_observer(
+ partial_observer_);
+ EXPECT_TRUE(weak_observer);
+
+ [observers_ addObserver:partial_observer_];
+
+ {
+ // Need an autorelease pool here, because
+ // -[CRBProtocolObservers forwardInvocation:] creates a temporary
+ // autoreleased array that holds all the observers.
+ base::mac::ScopedNSAutoreleasePool pool;
+ [observers_ requiredMethod];
+ EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+ }
+
+ partial_observer_.reset();
+ EXPECT_FALSE(weak_observer.get());
+}
+
+} // namespace
+
+@implementation TestPartialObserver {
+ BOOL _requiredMethodInvoked;
+}
+
+- (BOOL)requiredMethodInvoked {
+ return _requiredMethodInvoked;
+}
+
+- (void)requiredMethod {
+ _requiredMethodInvoked = YES;
+}
+
+- (void)reset {
+ _requiredMethodInvoked = NO;
+}
+
+@end
+
+@implementation TestCompleteObserver {
+ BOOL _optionalMethodInvoked;
+}
+
+- (BOOL)optionalMethodInvoked {
+ return _optionalMethodInvoked;
+}
+
+- (void)optionalMethod {
+ _optionalMethodInvoked = YES;
+}
+
+- (void)reset {
+ [super reset];
+ _optionalMethodInvoked = NO;
+}
+
+@end
diff --git a/chromium/base/ios/device_util.mm b/chromium/base/ios/device_util.mm
index ff7be36875c..1234562944d 100644
--- a/chromium/base/ios/device_util.mm
+++ b/chromium/base/ios/device_util.mm
@@ -13,7 +13,6 @@
#include <sys/socket.h>
#include <sys/sysctl.h>
-#include "base/ios/ios_util.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/scoped_ptr.h"
diff --git a/chromium/base/ios/device_util_unittest.mm b/chromium/base/ios/device_util_unittest.mm
index 3494e00a73e..82d421723de 100644
--- a/chromium/base/ios/device_util_unittest.mm
+++ b/chromium/base/ios/device_util_unittest.mm
@@ -5,7 +5,6 @@
#import <UIKit/UIKit.h>
#include "base/ios/device_util.h"
-#include "base/ios/ios_util.h"
#include "base/strings/sys_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
diff --git a/chromium/base/ios/ios_util.h b/chromium/base/ios/ios_util.h
index fca9a509f1c..d9d7e193dd5 100644
--- a/chromium/base/ios/ios_util.h
+++ b/chromium/base/ios/ios_util.h
@@ -11,9 +11,6 @@
namespace base {
namespace ios {
-// Returns whether the operating system is iOS 7 or later.
-BASE_EXPORT bool IsRunningOnIOS7OrLater();
-
// Returns whether the operating system is iOS 8 or later.
BASE_EXPORT bool IsRunningOnIOS8OrLater();
diff --git a/chromium/base/ios/ios_util.mm b/chromium/base/ios/ios_util.mm
index 91fce0cc273..ca0a24d2a52 100644
--- a/chromium/base/ios/ios_util.mm
+++ b/chromium/base/ios/ios_util.mm
@@ -20,10 +20,6 @@ const int32* OSVersionAsArray() {
namespace base {
namespace ios {
-bool IsRunningOnIOS7OrLater() {
- return IsRunningOnOrLater(7, 0, 0);
-}
-
bool IsRunningOnIOS8OrLater() {
return IsRunningOnOrLater(8, 0, 0);
}
diff --git a/chromium/base/ios/weak_nsobject.h b/chromium/base/ios/weak_nsobject.h
new file mode 100644
index 00000000000..fc3a7c38dc4
--- /dev/null
+++ b/chromium/base/ios/weak_nsobject.h
@@ -0,0 +1,189 @@
+// Copyright 2013 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_IOS_WEAK_NSOBJECT_H_
+#define BASE_IOS_WEAK_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread_checker.h"
+
+// WeakNSObject<> is patterned after scoped_nsobject<>, but instead of
+// maintaining ownership of an NSObject subclass object, it will nil itself out
+// when the object is deallocated.
+//
+// WeakNSProtocol<> has the same behavior as WeakNSObject, but can be used
+// with protocols.
+//
+// Example usage (base::WeakNSObject<T>):
+// scoped_nsobject<Foo> foo([[Foo alloc] init]);
+// WeakNSObject<Foo> weak_foo; // No pointer
+// weak_foo.reset(foo) // Now a weak reference is kept.
+// [weak_foo description]; // Returns [foo description].
+// foo.reset(); // The reference is released.
+// [weak_foo description]; // Returns nil, as weak_foo is pointing to nil.
+//
+//
+// Implementation wise a WeakNSObject keeps a reference to a refcounted
+// WeakContainer. There is one unique instance of a WeakContainer per watched
+// NSObject, this relationship is maintained via the ObjectiveC associated
+// object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class.
+//
+// Threading restrictions:
+// - Several WeakNSObject pointing to the same underlying object must all be
+// created and dereferenced on the same thread;
+// - thread safety is enforced by the implementation, except in two cases:
+// (1) it is allowed to copy a WeakNSObject on a different thread. However,
+// that copy must return to the original thread before being dereferenced,
+// (2) it is allowed to destroy a WeakNSObject on any thread;
+// - the implementation assumes that the tracked object will be released on the
+// same thread that the WeakNSObject is created on.
+namespace base {
+
+// WeakContainer keeps a weak pointer to an object and clears it when it
+// receives nullify() from the object's sentinel.
+class WeakContainer : public base::RefCountedThreadSafe<WeakContainer> {
+ public:
+ explicit WeakContainer(id object) : object_(object) {}
+
+ id object() {
+ DCHECK(checker_.CalledOnValidThread());
+ return object_;
+ }
+
+ void nullify() {
+ DCHECK(checker_.CalledOnValidThread());
+ object_ = nil;
+ }
+
+ private:
+ friend base::RefCountedThreadSafe<WeakContainer>;
+ ~WeakContainer() {}
+ base::ThreadChecker checker_;
+ id object_;
+};
+
+} // namespace base
+
+// Sentinel for observing the object contained in the weak pointer. The object
+// will be deleted when the weak object is deleted and will notify its
+// container.
+@interface CRBWeakNSProtocolSentinel : NSObject
+// Return the only associated container for this object. There can be only one.
+// Will return null if object is nil .
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object;
+@end
+
+namespace base {
+
+// Base class for all WeakNSObject derivatives.
+template <typename NST>
+class WeakNSProtocol {
+ public:
+ explicit WeakNSProtocol(NST object = nil) {
+ container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+ }
+
+ WeakNSProtocol(const WeakNSProtocol<NST>& that) {
+ // A WeakNSProtocol object can be copied on one thread and used on
+ // another.
+ checker_.DetachFromThread();
+ container_ = that.container_;
+ }
+
+ ~WeakNSProtocol() {
+ // A WeakNSProtocol object can be used on one thread and released on
+ // another. This is not the case for the contained object.
+ checker_.DetachFromThread();
+ }
+
+ void reset(NST object = nil) {
+ DCHECK(checker_.CalledOnValidThread());
+ container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+ }
+
+ NST get() const {
+ DCHECK(checker_.CalledOnValidThread());
+ if (!container_.get())
+ return nil;
+ return container_->object();
+ }
+
+ WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) {
+ // A WeakNSProtocol object can be copied on one thread and used on
+ // another.
+ checker_.DetachFromThread();
+ container_ = that.container_;
+ return *this;
+ }
+
+ bool operator==(NST that) const {
+ DCHECK(checker_.CalledOnValidThread());
+ return get() == that;
+ }
+
+ bool operator!=(NST that) const {
+ DCHECK(checker_.CalledOnValidThread());
+ return get() != that;
+ }
+
+ operator NST() const {
+ DCHECK(checker_.CalledOnValidThread());
+ return get();
+ }
+
+ private:
+ // Refecounted reference to the container tracking the ObjectiveC object this
+ // class encapsulates.
+ scoped_refptr<base::WeakContainer> container_;
+ base::ThreadChecker checker_;
+};
+
+// Free functions
+template <class NST>
+bool operator==(NST p1, const WeakNSProtocol<NST>& p2) {
+ return p1 == p2.get();
+}
+
+template <class NST>
+bool operator!=(NST p1, const WeakNSProtocol<NST>& p2) {
+ return p1 != p2.get();
+}
+
+template <typename NST>
+class WeakNSObject : public WeakNSProtocol<NST*> {
+ public:
+ explicit WeakNSObject(NST* object = nil) : WeakNSProtocol<NST*>(object) {}
+
+ WeakNSObject(const WeakNSObject<NST>& that) : WeakNSProtocol<NST*>(that) {}
+
+ WeakNSObject& operator=(const WeakNSObject<NST>& that) {
+ WeakNSProtocol<NST*>::operator=(that);
+ return *this;
+ }
+};
+
+// Specialization to make WeakNSObject<id> work.
+template <>
+class WeakNSObject<id> : public WeakNSProtocol<id> {
+ public:
+ explicit WeakNSObject(id object = nil) : WeakNSProtocol<id>(object) {}
+
+ WeakNSObject(const WeakNSObject<id>& that) : WeakNSProtocol<id>(that) {}
+
+ WeakNSObject& operator=(const WeakNSObject<id>& that) {
+ WeakNSProtocol<id>::operator=(that);
+ return *this;
+ }
+};
+
+} // namespace base
+
+#endif // BASE_IOS_WEAK_NSOBJECT_H_
diff --git a/chromium/base/ios/weak_nsobject.mm b/chromium/base/ios/weak_nsobject.mm
new file mode 100644
index 00000000000..36f9d3ea7cd
--- /dev/null
+++ b/chromium/base/ios/weak_nsobject.mm
@@ -0,0 +1,61 @@
+// Copyright 2013 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/ios/weak_nsobject.h"
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace {
+// The key needed by objc_setAssociatedObject.
+char sentinelObserverKey_;
+}
+
+@interface CRBWeakNSProtocolSentinel ()
+// Container to notify on dealloc.
+@property(readonly, assign) scoped_refptr<base::WeakContainer> container;
+// Designed initializer.
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container;
+@end
+
+@implementation CRBWeakNSProtocolSentinel
+
+@synthesize container = container_;
+
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object {
+ if (object == nil)
+ return nullptr;
+ // The autoreleasePool is needed here as the call to objc_getAssociatedObject
+ // returns an autoreleased object which is better released sooner than later.
+ base::mac::ScopedNSAutoreleasePool pool;
+ CRBWeakNSProtocolSentinel* sentinel =
+ objc_getAssociatedObject(object, &sentinelObserverKey_);
+ if (!sentinel) {
+ base::scoped_nsobject<CRBWeakNSProtocolSentinel> newSentinel(
+ [[CRBWeakNSProtocolSentinel alloc]
+ initWithContainer:new base::WeakContainer(object)]);
+ sentinel = newSentinel;
+ objc_setAssociatedObject(object, &sentinelObserverKey_, sentinel,
+ OBJC_ASSOCIATION_RETAIN);
+ // The retain count is 2. One retain is due to the alloc, the other to the
+ // association with the weak object.
+ DCHECK_EQ(2u, [sentinel retainCount]);
+ }
+ return [sentinel container];
+}
+
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container {
+ DCHECK(container.get());
+ self = [super init];
+ if (self)
+ container_ = container;
+ return self;
+}
+
+- (void)dealloc {
+ self.container->nullify();
+ [super dealloc];
+}
+
+@end
diff --git a/chromium/base/ios/weak_nsobject_unittest.mm b/chromium/base/ios/weak_nsobject_unittest.mm
new file mode 100644
index 00000000000..81de993cf25
--- /dev/null
+++ b/chromium/base/ios/weak_nsobject_unittest.mm
@@ -0,0 +1,140 @@
+// Copyright 2013 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/basictypes.h"
+#include "base/bind.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(WeakNSObjectTest, WeakNSObject) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1(p1);
+ EXPECT_TRUE(w1);
+ p1.reset();
+ EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, MultipleWeakNSObject) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1(p1);
+ WeakNSObject<NSObject> w2(w1);
+ EXPECT_TRUE(w1);
+ EXPECT_TRUE(w2);
+ EXPECT_TRUE(w1.get() == w2.get());
+ p1.reset();
+ EXPECT_FALSE(w1);
+ EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectDies) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ {
+ WeakNSObject<NSObject> w1(p1);
+ EXPECT_TRUE(w1);
+ }
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectReset) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1(p1);
+ EXPECT_TRUE(w1);
+ w1.reset();
+ EXPECT_FALSE(w1);
+ EXPECT_TRUE(p1);
+ EXPECT_TRUE([p1 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectResetWithObject) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ scoped_nsobject<NSObject> p2([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1(p1);
+ EXPECT_TRUE(w1);
+ w1.reset(p2);
+ EXPECT_TRUE(w1);
+ EXPECT_TRUE([p1 description]);
+ EXPECT_TRUE([p2 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectEmpty) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1;
+ EXPECT_FALSE(w1);
+ w1.reset(p1);
+ EXPECT_TRUE(w1);
+ p1.reset();
+ EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectCopy) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1(p1);
+ WeakNSObject<NSObject> w2(w1);
+ EXPECT_TRUE(w1);
+ EXPECT_TRUE(w2);
+ p1.reset();
+ EXPECT_FALSE(w1);
+ EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectAssignment) {
+ scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ WeakNSObject<NSObject> w1(p1);
+ WeakNSObject<NSObject> w2;
+ EXPECT_FALSE(w2);
+ w2 = w1;
+ EXPECT_TRUE(w1);
+ EXPECT_TRUE(w2);
+ p1.reset();
+ EXPECT_FALSE(w1);
+ EXPECT_FALSE(w2);
+}
+
+// Touches |weak_data| by increasing its length by 1. Used to check that the
+// weak object can be dereferenced.
+void TouchWeakData(const WeakNSObject<NSMutableData>& weak_data) {
+ if (!weak_data)
+ return;
+ [weak_data increaseLengthBy:1];
+}
+
+// Makes a copy of |weak_object| on the current thread and posts a task to touch
+// the weak object on its original thread.
+void CopyWeakNSObjectAndPost(const WeakNSObject<NSMutableData>& weak_object,
+ scoped_refptr<SingleThreadTaskRunner> runner) {
+ // Copy using constructor.
+ WeakNSObject<NSMutableData> weak_copy1(weak_object);
+ runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy1));
+ // Copy using assignment operator.
+ WeakNSObject<NSMutableData> weak_copy2 = weak_object;
+ runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy2));
+}
+
+// Tests that the weak object can be copied on a different thread.
+TEST(WeakNSObjectTest, WeakNSObjectCopyOnOtherThread) {
+ MessageLoop loop;
+ Thread other_thread("WeakNSObjectCopyOnOtherThread");
+ other_thread.Start();
+
+ scoped_nsobject<NSMutableData> data([[NSMutableData alloc] init]);
+ WeakNSObject<NSMutableData> weak(data);
+
+ scoped_refptr<SingleThreadTaskRunner> runner = loop.task_runner();
+ other_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&CopyWeakNSObjectAndPost, weak, runner));
+ other_thread.Stop();
+ loop.RunUntilIdle();
+
+ // Check that TouchWeakData was called and the object touched twice.
+ EXPECT_EQ(2u, [data length]);
+}
+
+} // namespace
+} // namespace base
diff --git a/chromium/base/json/BUILD.gn b/chromium/base/json/BUILD.gn
new file mode 100644
index 00000000000..70830c15e55
--- /dev/null
+++ b/chromium/base/json/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 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.
+
+source_set("json") {
+ sources = [
+ "json_file_value_serializer.cc",
+ "json_file_value_serializer.h",
+ "json_parser.cc",
+ "json_parser.h",
+ "json_reader.cc",
+ "json_reader.h",
+ "json_string_value_serializer.cc",
+ "json_string_value_serializer.h",
+ "json_value_converter.cc",
+ "json_value_converter.h",
+ "json_writer.cc",
+ "json_writer.h",
+ "string_escape.cc",
+ "string_escape.h",
+ ]
+
+ if (is_nacl) {
+ sources -= [
+ "json_file_value_serializer.cc",
+ "json_file_value_serializer.h",
+ ]
+ }
+
+ configs += [ "//base:base_implementation" ]
+
+ deps = [
+ "//base/memory",
+ ]
+
+ visibility = [ "//base/*" ]
+}
diff --git a/chromium/base/json/json_file_value_serializer.cc b/chromium/base/json/json_file_value_serializer.cc
index d60f800cfcf..72a09700161 100644
--- a/chromium/base/json/json_file_value_serializer.cc
+++ b/chromium/base/json/json_file_value_serializer.cc
@@ -10,10 +10,18 @@
using base::FilePath;
-const char JSONFileValueSerializer::kAccessDenied[] = "Access denied.";
-const char JSONFileValueSerializer::kCannotReadFile[] = "Can't read file.";
-const char JSONFileValueSerializer::kFileLocked[] = "File locked.";
-const char JSONFileValueSerializer::kNoSuchFile[] = "File doesn't exist.";
+const char JSONFileValueDeserializer::kAccessDenied[] = "Access denied.";
+const char JSONFileValueDeserializer::kCannotReadFile[] = "Can't read file.";
+const char JSONFileValueDeserializer::kFileLocked[] = "File locked.";
+const char JSONFileValueDeserializer::kNoSuchFile[] = "File doesn't exist.";
+
+JSONFileValueSerializer::JSONFileValueSerializer(
+ const base::FilePath& json_file_path)
+ : json_file_path_(json_file_path) {
+}
+
+JSONFileValueSerializer::~JSONFileValueSerializer() {
+}
bool JSONFileValueSerializer::Serialize(const base::Value& root) {
return SerializeInternal(root, false);
@@ -43,7 +51,17 @@ bool JSONFileValueSerializer::SerializeInternal(const base::Value& root,
return true;
}
-int JSONFileValueSerializer::ReadFileToString(std::string* json_string) {
+JSONFileValueDeserializer::JSONFileValueDeserializer(
+ const base::FilePath& json_file_path)
+ : json_file_path_(json_file_path),
+ allow_trailing_comma_(false),
+ last_read_size_(0U) {
+}
+
+JSONFileValueDeserializer::~JSONFileValueDeserializer() {
+}
+
+int JSONFileValueDeserializer::ReadFileToString(std::string* json_string) {
DCHECK(json_string);
if (!base::ReadFileToString(json_file_path_, json_string)) {
#if defined(OS_WIN)
@@ -59,10 +77,12 @@ int JSONFileValueSerializer::ReadFileToString(std::string* json_string) {
else
return JSON_CANNOT_READ_FILE;
}
+
+ last_read_size_ = json_string->size();
return JSON_NO_ERROR;
}
-const char* JSONFileValueSerializer::GetErrorMessageForCode(int error_code) {
+const char* JSONFileValueDeserializer::GetErrorMessageForCode(int error_code) {
switch (error_code) {
case JSON_NO_ERROR:
return "";
@@ -80,8 +100,8 @@ const char* JSONFileValueSerializer::GetErrorMessageForCode(int error_code) {
}
}
-base::Value* JSONFileValueSerializer::Deserialize(int* error_code,
- std::string* error_str) {
+base::Value* JSONFileValueDeserializer::Deserialize(int* error_code,
+ std::string* error_str) {
std::string json_string;
int error = ReadFileToString(&json_string);
if (error != JSON_NO_ERROR) {
@@ -92,7 +112,7 @@ base::Value* JSONFileValueSerializer::Deserialize(int* error_code,
return NULL;
}
- JSONStringValueSerializer serializer(json_string);
- serializer.set_allow_trailing_comma(allow_trailing_comma_);
- return serializer.Deserialize(error_code, error_str);
+ JSONStringValueDeserializer deserializer(json_string);
+ deserializer.set_allow_trailing_comma(allow_trailing_comma_);
+ return deserializer.Deserialize(error_code, error_str);
}
diff --git a/chromium/base/json/json_file_value_serializer.h b/chromium/base/json/json_file_value_serializer.h
index f0f556c2dc6..aab47eec2dc 100644
--- a/chromium/base/json/json_file_value_serializer.h
+++ b/chromium/base/json/json_file_value_serializer.h
@@ -14,15 +14,12 @@
class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
public:
- // json_file_patch is the path of a file that will be source of the
- // deserialization or the destination of the serialization.
- // When deserializing, the file should exist, but when serializing, the
- // serializer will attempt to create the file at the specified location.
- explicit JSONFileValueSerializer(const base::FilePath& json_file_path)
- : json_file_path_(json_file_path),
- allow_trailing_comma_(false) {}
+ // |json_file_path_| is the path of a file that will be destination of the
+ // serialization. The serializer will attempt to create the file at the
+ // specified location.
+ explicit JSONFileValueSerializer(const base::FilePath& json_file_path);
- ~JSONFileValueSerializer() override {}
+ ~JSONFileValueSerializer() override;
// DO NOT USE except in unit tests to verify the file was written properly.
// We should never serialize directly to a file since this will block the
@@ -38,6 +35,22 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
// output.
bool SerializeAndOmitBinaryValues(const base::Value& root);
+ private:
+ bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+ const base::FilePath json_file_path_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
+};
+
+class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
+ public:
+ // |json_file_path_| is the path of a file that will be source of the
+ // deserialization.
+ explicit JSONFileValueDeserializer(const base::FilePath& json_file_path);
+
+ ~JSONFileValueDeserializer() override;
+
// Attempt to deserialize the data structure encoded in the file passed
// in to the constructor into a structure of Value objects. If the return
// value is NULL, and if |error_code| is non-null, |error_code| will
@@ -71,17 +84,20 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
allow_trailing_comma_ = new_value;
}
- private:
- bool SerializeInternal(const base::Value& root, bool omit_binary_values);
-
- base::FilePath json_file_path_;
- bool allow_trailing_comma_;
+ // Returns the size (in bytes) of JSON string read from disk in the last
+ // successful |Deserialize()| call.
+ size_t get_last_read_size() const { return last_read_size_; }
+ private:
// A wrapper for ReadFileToString which returns a non-zero JsonFileError if
// there were file errors.
int ReadFileToString(std::string* json_string);
- DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
+ const base::FilePath json_file_path_;
+ bool allow_trailing_comma_;
+ size_t last_read_size_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueDeserializer);
};
#endif // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
diff --git a/chromium/base/json/json_parser.cc b/chromium/base/json/json_parser.cc
index 6a25bc7b481..4d79be36194 100644
--- a/chromium/base/json/json_parser.cc
+++ b/chromium/base/json/json_parser.cc
@@ -4,7 +4,8 @@
#include "base/json/json_parser.h"
-#include "base/float_util.h"
+#include <cmath>
+
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
@@ -428,7 +429,7 @@ bool JSONParser::EatComment() {
if (next_char == '/') {
// Single line comment, read to newline.
while (CanConsume(1)) {
- char next_char = *NextChar();
+ next_char = *NextChar();
if (next_char == '\n' || next_char == '\r')
return true;
}
@@ -872,7 +873,7 @@ Value* JSONParser::ConsumeNumber() {
double num_double;
if (base::StringToDouble(num_string.as_string(), &num_double) &&
- IsFinite(num_double)) {
+ std::isfinite(num_double)) {
return new FundamentalValue(num_double);
}
@@ -931,7 +932,7 @@ Value* JSONParser::ConsumeLiteral() {
return NULL;
}
NextNChars(kNullLen - 1);
- return Value::CreateNullValue();
+ return Value::CreateNullValue().release();
}
default:
ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
diff --git a/chromium/base/json/json_string_value_serializer.cc b/chromium/base/json/json_string_value_serializer.cc
index 59f030dff2f..debf9f088d1 100644
--- a/chromium/base/json/json_string_value_serializer.cc
+++ b/chromium/base/json/json_string_value_serializer.cc
@@ -10,6 +10,11 @@
using base::Value;
+JSONStringValueSerializer::JSONStringValueSerializer(std::string* json_string)
+ : json_string_(json_string),
+ pretty_print_(false) {
+}
+
JSONStringValueSerializer::~JSONStringValueSerializer() {}
bool JSONStringValueSerializer::Serialize(const Value& root) {
@@ -23,7 +28,7 @@ bool JSONStringValueSerializer::SerializeAndOmitBinaryValues(
bool JSONStringValueSerializer::SerializeInternal(const Value& root,
bool omit_binary_values) {
- if (!json_string_ || initialized_with_const_string_)
+ if (!json_string_)
return false;
int options = 0;
@@ -35,12 +40,17 @@ bool JSONStringValueSerializer::SerializeInternal(const Value& root,
return base::JSONWriter::WriteWithOptions(&root, options, json_string_);
}
-Value* JSONStringValueSerializer::Deserialize(int* error_code,
- std::string* error_str) {
- if (!json_string_)
- return NULL;
+JSONStringValueDeserializer::JSONStringValueDeserializer(
+ const base::StringPiece& json_string)
+ : json_string_(json_string),
+ allow_trailing_comma_(false) {
+}
+
+JSONStringValueDeserializer::~JSONStringValueDeserializer() {}
- return base::JSONReader::ReadAndReturnError(*json_string_,
+Value* JSONStringValueDeserializer::Deserialize(int* error_code,
+ std::string* error_str) {
+ return base::JSONReader::ReadAndReturnError(json_string_,
allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS :
base::JSON_PARSE_RFC,
error_code, error_str);
diff --git a/chromium/base/json/json_string_value_serializer.h b/chromium/base/json/json_string_value_serializer.h
index 6435051aa19..bc0e66d127f 100644
--- a/chromium/base/json/json_string_value_serializer.h
+++ b/chromium/base/json/json_string_value_serializer.h
@@ -10,28 +10,15 @@
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/strings/string_piece.h"
#include "base/values.h"
class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
public:
- // json_string is the string that will be source of the deserialization
- // or the destination of the serialization. The caller of the constructor
- // retains ownership of the string.
- explicit JSONStringValueSerializer(std::string* json_string)
- : json_string_(json_string),
- initialized_with_const_string_(false),
- pretty_print_(false),
- allow_trailing_comma_(false) {
- }
-
- // This version allows initialization with a const string reference for
- // deserialization only.
- explicit JSONStringValueSerializer(const std::string& json_string)
- : json_string_(&const_cast<std::string&>(json_string)),
- initialized_with_const_string_(true),
- pretty_print_(false),
- allow_trailing_comma_(false) {
- }
+ // |json_string| is the string that will be the destination of the
+ // serialization. The caller of the constructor retains ownership of the
+ // string. |json_string| must not be null.
+ explicit JSONStringValueSerializer(std::string* json_string);
~JSONStringValueSerializer() override;
@@ -44,9 +31,30 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
// output.
bool SerializeAndOmitBinaryValues(const base::Value& root);
+ void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
+ bool pretty_print() { return pretty_print_; }
+
+ private:
+ bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+ // Owned by the caller of the constructor.
+ std::string* json_string_;
+ bool pretty_print_; // If true, serialization will span multiple lines.
+
+ DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer);
+};
+
+class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer {
+ public:
+ // This retains a reference to the contents of |json_string|, so the data
+ // must outlive the JSONStringValueDeserializer.
+ explicit JSONStringValueDeserializer(const base::StringPiece& json_string);
+
+ ~JSONStringValueDeserializer() override;
+
// Attempt to deserialize the data structure encoded in the string passed
// in to the constructor into a structure of Value objects. If the return
- // value is NULL, and if |error_code| is non-null, |error_code| will
+ // value is null, and if |error_code| is non-null, |error_code| will
// contain an integer error code (a JsonParseError in this case).
// If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate.
@@ -54,24 +62,17 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
base::Value* Deserialize(int* error_code,
std::string* error_message) override;
- void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
- bool pretty_print() { return pretty_print_; }
-
void set_allow_trailing_comma(bool new_value) {
allow_trailing_comma_ = new_value;
}
private:
- bool SerializeInternal(const base::Value& root, bool omit_binary_values);
-
- std::string* json_string_;
- bool initialized_with_const_string_;
- bool pretty_print_; // If true, serialization will span multiple lines.
+ // Data is owned by the caller of the constructor.
+ base::StringPiece json_string_;
// If true, deserialization will allow trailing commas.
bool allow_trailing_comma_;
- DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer);
+ DISALLOW_COPY_AND_ASSIGN(JSONStringValueDeserializer);
};
#endif // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
-
diff --git a/chromium/base/json/json_value_converter.cc b/chromium/base/json/json_value_converter.cc
new file mode 100644
index 00000000000..6f772f366b8
--- /dev/null
+++ b/chromium/base/json/json_value_converter.cc
@@ -0,0 +1,37 @@
+// Copyright 2014 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/json/json_value_converter.h"
+
+namespace base {
+namespace internal {
+
+bool BasicValueConverter<int>::Convert(
+ const base::Value& value, int* field) const {
+ return value.GetAsInteger(field);
+}
+
+bool BasicValueConverter<std::string>::Convert(
+ const base::Value& value, std::string* field) const {
+ return value.GetAsString(field);
+}
+
+bool BasicValueConverter<string16>::Convert(
+ const base::Value& value, string16* field) const {
+ return value.GetAsString(field);
+}
+
+bool BasicValueConverter<double>::Convert(
+ const base::Value& value, double* field) const {
+ return value.GetAsDouble(field);
+}
+
+bool BasicValueConverter<bool>::Convert(
+ const base::Value& value, bool* field) const {
+ return value.GetAsBoolean(field);
+}
+
+} // namespace internal
+} // namespace base
+
diff --git a/chromium/base/json/json_value_converter.h b/chromium/base/json/json_value_converter.h
index f049d9a8588..f94d46e3ccf 100644
--- a/chromium/base/json/json_value_converter.h
+++ b/chromium/base/json/json_value_converter.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -122,8 +123,7 @@ class FieldConverter : public FieldConverterBase<StructType> {
value_converter_(converter) {
}
- virtual bool ConvertField(
- const base::Value& value, StructType* dst) const override {
+ bool ConvertField(const base::Value& value, StructType* dst) const override {
return value_converter_->Convert(value, &(dst->*field_pointer_));
}
@@ -137,67 +137,57 @@ template <typename FieldType>
class BasicValueConverter;
template <>
-class BasicValueConverter<int> : public ValueConverter<int> {
+class BASE_EXPORT BasicValueConverter<int> : public ValueConverter<int> {
public:
BasicValueConverter() {}
- virtual bool Convert(const base::Value& value, int* field) const override {
- return value.GetAsInteger(field);
- }
+ bool Convert(const base::Value& value, int* field) const override;
private:
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
};
template <>
-class BasicValueConverter<std::string> : public ValueConverter<std::string> {
+class BASE_EXPORT BasicValueConverter<std::string>
+ : public ValueConverter<std::string> {
public:
BasicValueConverter() {}
- virtual bool Convert(
- const base::Value& value, std::string* field) const override {
- return value.GetAsString(field);
- }
+ bool Convert(const base::Value& value, std::string* field) const override;
private:
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
};
template <>
-class BasicValueConverter<string16> : public ValueConverter<string16> {
+class BASE_EXPORT BasicValueConverter<string16>
+ : public ValueConverter<string16> {
public:
BasicValueConverter() {}
- virtual bool Convert(
- const base::Value& value, string16* field) const override {
- return value.GetAsString(field);
- }
+ bool Convert(const base::Value& value, string16* field) const override;
private:
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
};
template <>
-class BasicValueConverter<double> : public ValueConverter<double> {
+class BASE_EXPORT BasicValueConverter<double> : public ValueConverter<double> {
public:
BasicValueConverter() {}
- virtual bool Convert(const base::Value& value, double* field) const override {
- return value.GetAsDouble(field);
- }
+ bool Convert(const base::Value& value, double* field) const override;
private:
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
};
template <>
-class BasicValueConverter<bool> : public ValueConverter<bool> {
+class BASE_EXPORT BasicValueConverter<bool> : public ValueConverter<bool> {
public:
BasicValueConverter() {}
- virtual bool Convert(const base::Value& value, bool* field) const override {
- return value.GetAsBoolean(field);
- }
+ bool Convert(const base::Value& value, bool* field) const override;
private:
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
@@ -211,8 +201,7 @@ class ValueFieldConverter : public ValueConverter<FieldType> {
ValueFieldConverter(ConvertFunc convert_func)
: convert_func_(convert_func) {}
- virtual bool Convert(const base::Value& value,
- FieldType* field) const override {
+ bool Convert(const base::Value& value, FieldType* field) const override {
return convert_func_(&value, field);
}
@@ -230,8 +219,7 @@ class CustomFieldConverter : public ValueConverter<FieldType> {
CustomFieldConverter(ConvertFunc convert_func)
: convert_func_(convert_func) {}
- virtual bool Convert(const base::Value& value,
- FieldType* field) const override {
+ bool Convert(const base::Value& value, FieldType* field) const override {
std::string string_value;
return value.GetAsString(&string_value) &&
convert_func_(string_value, field);
@@ -248,8 +236,7 @@ class NestedValueConverter : public ValueConverter<NestedType> {
public:
NestedValueConverter() {}
- virtual bool Convert(
- const base::Value& value, NestedType* field) const override {
+ bool Convert(const base::Value& value, NestedType* field) const override {
return converter_.Convert(value, field);
}
@@ -263,8 +250,8 @@ class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > {
public:
RepeatedValueConverter() {}
- virtual bool Convert(
- const base::Value& value, ScopedVector<Element>* field) const override {
+ bool Convert(const base::Value& value,
+ ScopedVector<Element>* field) const override {
const base::ListValue* list = NULL;
if (!value.GetAsList(&list)) {
// The field is not a list.
@@ -299,8 +286,8 @@ class RepeatedMessageConverter
public:
RepeatedMessageConverter() {}
- virtual bool Convert(const base::Value& value,
- ScopedVector<NestedType>* field) const override {
+ bool Convert(const base::Value& value,
+ ScopedVector<NestedType>* field) const override {
const base::ListValue* list = NULL;
if (!value.GetAsList(&list))
return false;
@@ -336,8 +323,8 @@ class RepeatedCustomValueConverter
RepeatedCustomValueConverter(ConvertFunc convert_func)
: convert_func_(convert_func) {}
- virtual bool Convert(const base::Value& value,
- ScopedVector<NestedType>* field) const override {
+ bool Convert(const base::Value& value,
+ ScopedVector<NestedType>* field) const override {
const base::ListValue* list = NULL;
if (!value.GetAsList(&list))
return false;
diff --git a/chromium/base/json/json_value_serializer_unittest.cc b/chromium/base/json/json_value_serializer_unittest.cc
index dc436937a33..b8aebe0656d 100644
--- a/chromium/base/json/json_value_serializer_unittest.cc
+++ b/chromium/base/json/json_value_serializer_unittest.cc
@@ -12,6 +12,7 @@
#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
@@ -42,11 +43,25 @@ const char kProperJSONWithCommas[] =
"\t\"compound\": { \"a\": 1, \"b\": 2, },\n"
"}\n";
+// kProperJSON with a few misc characters at the begin and end.
+const char kProperJSONPadded[] =
+ ")]}'\n"
+ "{\n"
+ " \"compound\": {\n"
+ " \"a\": 1,\n"
+ " \"b\": 2\n"
+ " },\n"
+ " \"some_String\": \"1337\",\n"
+ " \"some_int\": 42,\n"
+ " \"the_list\": [ \"val1\", \"val2\" ]\n"
+ "}\n"
+ "?!ab\n";
+
const char kWinLineEnds[] = "\r\n";
const char kLinuxLineEnds[] = "\n";
// Verifies the generated JSON against the expected output.
-void CheckJSONIsStillTheSame(Value& value) {
+void CheckJSONIsStillTheSame(const Value& value) {
// Serialize back the output.
std::string serialized_json;
JSONStringValueSerializer str_serializer(&serialized_json);
@@ -71,11 +86,29 @@ void ValidateJsonList(const std::string& json) {
ASSERT_EQ(1, value);
}
-// Test proper JSON [de]serialization from string is working.
-TEST(JSONValueSerializerTest, ReadProperJSONFromString) {
+// Test proper JSON deserialization from string is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromString) {
// Try to deserialize it through the serializer.
- std::string proper_json(kProperJSON);
- JSONStringValueSerializer str_deserializer(proper_json);
+ JSONStringValueDeserializer str_deserializer(kProperJSON);
+
+ int error_code = 0;
+ std::string error_message;
+ scoped_ptr<Value> value(
+ str_deserializer.Deserialize(&error_code, &error_message));
+ ASSERT_TRUE(value.get());
+ ASSERT_EQ(0, error_code);
+ ASSERT_TRUE(error_message.empty());
+ // Verify if the same JSON is still there.
+ CheckJSONIsStillTheSame(*value);
+}
+
+// Test proper JSON deserialization from a StringPiece substring.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) {
+ // Create a StringPiece for the substring of kProperJSONPadded that matches
+ // kProperJSON.
+ base::StringPiece proper_json(kProperJSONPadded);
+ proper_json = proper_json.substr(5, proper_json.length() - 10);
+ JSONStringValueDeserializer str_deserializer(proper_json);
int error_code = 0;
std::string error_message;
@@ -90,10 +123,9 @@ TEST(JSONValueSerializerTest, ReadProperJSONFromString) {
// Test that trialing commas are only properly deserialized from string when
// the proper flag for that is set.
-TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) {
+TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) {
// Try to deserialize it through the serializer.
- std::string proper_json(kProperJSONWithCommas);
- JSONStringValueSerializer str_deserializer(proper_json);
+ JSONStringValueDeserializer str_deserializer(kProperJSONWithCommas);
int error_code = 0;
std::string error_message;
@@ -111,8 +143,8 @@ TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) {
CheckJSONIsStillTheSame(*value);
}
-// Test proper JSON [de]serialization from file is working.
-TEST(JSONValueSerializerTest, ReadProperJSONFromFile) {
+// Test proper JSON deserialization from file is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromFile) {
ScopedTempDir tempdir;
ASSERT_TRUE(tempdir.CreateUniqueTempDir());
// Write it down in the file.
@@ -121,7 +153,7 @@ TEST(JSONValueSerializerTest, ReadProperJSONFromFile) {
WriteFile(temp_file, kProperJSON, strlen(kProperJSON)));
// Try to deserialize it through the serializer.
- JSONFileValueSerializer file_deserializer(temp_file);
+ JSONFileValueDeserializer file_deserializer(temp_file);
int error_code = 0;
std::string error_message;
@@ -136,7 +168,7 @@ TEST(JSONValueSerializerTest, ReadProperJSONFromFile) {
// Test that trialing commas are only properly deserialized from file when
// the proper flag for that is set.
-TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) {
+TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) {
ScopedTempDir tempdir;
ASSERT_TRUE(tempdir.CreateUniqueTempDir());
// Write it down in the file.
@@ -146,7 +178,7 @@ TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) {
strlen(kProperJSONWithCommas)));
// Try to deserialize it through the serializer.
- JSONFileValueSerializer file_deserializer(temp_file);
+ JSONFileValueDeserializer file_deserializer(temp_file);
// This must fail without the proper flag.
int error_code = 0;
std::string error_message;
@@ -164,11 +196,27 @@ TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) {
CheckJSONIsStillTheSame(*value);
}
+TEST(JSONValueDeserializerTest, AllowTrailingComma) {
+ scoped_ptr<Value> root;
+ scoped_ptr<Value> root_expected;
+ static const char kTestWithCommas[] = "{\"key\": [true,],}";
+ static const char kTestNoCommas[] = "{\"key\": [true]}";
+
+ JSONStringValueDeserializer deserializer(kTestWithCommas);
+ deserializer.set_allow_trailing_comma(true);
+ JSONStringValueDeserializer deserializer_expected(kTestNoCommas);
+ root.reset(deserializer.Deserialize(NULL, NULL));
+ ASSERT_TRUE(root.get());
+ root_expected.reset(deserializer_expected.Deserialize(NULL, NULL));
+ ASSERT_TRUE(root_expected.get());
+ ASSERT_TRUE(root->Equals(root_expected.get()));
+}
+
TEST(JSONValueSerializerTest, Roundtrip) {
- const std::string original_serialization =
+ static const char kOriginalSerialization[] =
"{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
- JSONStringValueSerializer serializer(original_serialization);
- scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));
+ JSONStringValueDeserializer deserializer(kOriginalSerialization);
+ scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
@@ -191,14 +239,10 @@ TEST(JSONValueSerializerTest, Roundtrip) {
ASSERT_TRUE(root_dict->GetDouble("double", &double_value));
ASSERT_DOUBLE_EQ(3.14, double_value);
- // We shouldn't be able to write using this serializer, since it was
- // initialized with a const string.
- ASSERT_FALSE(serializer.Serialize(*root_dict));
-
std::string test_serialization;
JSONStringValueSerializer mutable_serializer(&test_serialization);
ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
- ASSERT_EQ(original_serialization, test_serialization);
+ ASSERT_EQ(kOriginalSerialization, test_serialization);
mutable_serializer.set_pretty_print(true);
ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
@@ -273,15 +317,15 @@ TEST(JSONValueSerializerTest, UnicodeStrings) {
string16 test(WideToUTF16(L"\x7F51\x9875"));
root.SetString("web", test);
- std::string expected = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
+ static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
std::string actual;
JSONStringValueSerializer serializer(&actual);
ASSERT_TRUE(serializer.Serialize(root));
- ASSERT_EQ(expected, actual);
+ ASSERT_EQ(kExpected, actual);
// escaped ascii text -> json
- JSONStringValueSerializer deserializer(expected);
+ JSONStringValueDeserializer deserializer(kExpected);
scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
@@ -297,15 +341,15 @@ TEST(JSONValueSerializerTest, HexStrings) {
string16 test(WideToUTF16(L"\x01\x02"));
root.SetString("test", test);
- std::string expected = "{\"test\":\"\\u0001\\u0002\"}";
+ static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}";
std::string actual;
JSONStringValueSerializer serializer(&actual);
ASSERT_TRUE(serializer.Serialize(root));
- ASSERT_EQ(expected, actual);
+ ASSERT_EQ(kExpected, actual);
// escaped ascii text -> json
- JSONStringValueSerializer deserializer(expected);
+ JSONStringValueDeserializer deserializer(kExpected);
scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
@@ -315,8 +359,8 @@ TEST(JSONValueSerializerTest, HexStrings) {
ASSERT_EQ(test, test_value);
// Test converting escaped regular chars
- std::string escaped_chars = "{\"test\":\"\\u0067\\u006f\"}";
- JSONStringValueSerializer deserializer2(escaped_chars);
+ static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
+ JSONStringValueDeserializer deserializer2(kEscapedChars);
deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
dict_root = static_cast<DictionaryValue*>(deserial_root.get());
@@ -324,22 +368,6 @@ TEST(JSONValueSerializerTest, HexStrings) {
ASSERT_EQ(ASCIIToUTF16("go"), test_value);
}
-TEST(JSONValueSerializerTest, AllowTrailingComma) {
- scoped_ptr<Value> root;
- scoped_ptr<Value> root_expected;
- std::string test_with_commas("{\"key\": [true,],}");
- std::string test_no_commas("{\"key\": [true]}");
-
- JSONStringValueSerializer serializer(test_with_commas);
- serializer.set_allow_trailing_comma(true);
- JSONStringValueSerializer serializer_expected(test_no_commas);
- root.reset(serializer.Deserialize(NULL, NULL));
- ASSERT_TRUE(root.get());
- root_expected.reset(serializer_expected.Deserialize(NULL, NULL));
- ASSERT_TRUE(root_expected.get());
- ASSERT_TRUE(root->Equals(root_expected.get()));
-}
-
TEST(JSONValueSerializerTest, JSONReaderComments) {
ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]");
ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]");
@@ -372,9 +400,7 @@ TEST(JSONValueSerializerTest, JSONReaderComments) {
class JSONFileValueSerializerTest : public testing::Test {
protected:
- virtual void SetUp() override {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- }
+ void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
base::ScopedTempDir temp_dir_;
};
@@ -387,7 +413,7 @@ TEST_F(JSONFileValueSerializerTest, Roundtrip) {
ASSERT_TRUE(PathExists(original_file_path));
- JSONFileValueSerializer deserializer(original_file_path);
+ JSONFileValueDeserializer deserializer(original_file_path);
scoped_ptr<Value> root;
root.reset(deserializer.Deserialize(NULL, NULL));
@@ -435,7 +461,7 @@ TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
ASSERT_TRUE(PathExists(original_file_path));
- JSONFileValueSerializer deserializer(original_file_path);
+ JSONFileValueDeserializer deserializer(original_file_path);
scoped_ptr<Value> root;
root.reset(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
@@ -460,9 +486,9 @@ TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
source_file_path = source_file_path.Append(
FILE_PATH_LITERAL("serializer_test_nowhitespace.json"));
ASSERT_TRUE(PathExists(source_file_path));
- JSONFileValueSerializer serializer(source_file_path);
+ JSONFileValueDeserializer deserializer(source_file_path);
scoped_ptr<Value> root;
- root.reset(serializer.Deserialize(NULL, NULL));
+ root.reset(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
}
diff --git a/chromium/base/json/json_writer_unittest.cc b/chromium/base/json/json_writer_unittest.cc
index ae46800dde6..5ac2590a0d8 100644
--- a/chromium/base/json/json_writer_unittest.cc
+++ b/chromium/base/json/json_writer_unittest.cc
@@ -12,75 +12,63 @@ TEST(JSONWriterTest, BasicTypes) {
std::string output_js;
// Test null.
- Value* root = Value::CreateNullValue();
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ EXPECT_TRUE(JSONWriter::Write(Value::CreateNullValue().get(), &output_js));
EXPECT_EQ("null", output_js);
- delete root;
// Test empty dict.
- root = new DictionaryValue;
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ DictionaryValue dict;
+ EXPECT_TRUE(JSONWriter::Write(&dict, &output_js));
EXPECT_EQ("{}", output_js);
- delete root;
// Test empty list.
- root = new ListValue;
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ ListValue list;
+ EXPECT_TRUE(JSONWriter::Write(&list, &output_js));
EXPECT_EQ("[]", output_js);
- delete root;
// Test integer values.
- root = new FundamentalValue(42);
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ FundamentalValue int_value(42);
+ EXPECT_TRUE(JSONWriter::Write(&int_value, &output_js));
EXPECT_EQ("42", output_js);
- delete root;
// Test boolean values.
- root = new FundamentalValue(true);
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ FundamentalValue bool_value(true);
+ EXPECT_TRUE(JSONWriter::Write(&bool_value, &output_js));
EXPECT_EQ("true", output_js);
- delete root;
// Test Real values should always have a decimal or an 'e'.
- root = new FundamentalValue(1.0);
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ FundamentalValue double_value(1.0);
+ EXPECT_TRUE(JSONWriter::Write(&double_value, &output_js));
EXPECT_EQ("1.0", output_js);
- delete root;
// Test Real values in the the range (-1, 1) must have leading zeros
- root = new FundamentalValue(0.2);
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ FundamentalValue double_value2(0.2);
+ EXPECT_TRUE(JSONWriter::Write(&double_value2, &output_js));
EXPECT_EQ("0.2", output_js);
- delete root;
// Test Real values in the the range (-1, 1) must have leading zeros
- root = new FundamentalValue(-0.8);
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ FundamentalValue double_value3(-0.8);
+ EXPECT_TRUE(JSONWriter::Write(&double_value3, &output_js));
EXPECT_EQ("-0.8", output_js);
- delete root;
// Test String values.
- root = new StringValue("foo");
- EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+ StringValue string_value("foo");
+ EXPECT_TRUE(JSONWriter::Write(&string_value, &output_js));
EXPECT_EQ("\"foo\"", output_js);
- delete root;
}
-
TEST(JSONWriterTest, NestedTypes) {
std::string output_js;
// Writer unittests like empty list/dict nesting,
// list list nesting, etc.
DictionaryValue root_dict;
- ListValue* list = new ListValue;
- root_dict.Set("list", list);
- DictionaryValue* inner_dict = new DictionaryValue;
- list->Append(inner_dict);
+ scoped_ptr<ListValue> list(new ListValue());
+ scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue());
inner_dict->SetInteger("inner int", 10);
- ListValue* inner_list = new ListValue;
- list->Append(inner_list);
- list->Append(new FundamentalValue(true));
+ list->Append(inner_dict.Pass());
+ list->Append(make_scoped_ptr(new ListValue()));
+ list->AppendBoolean(true);
+ root_dict.Set("list", list.Pass());
// Test the pretty-printer.
EXPECT_TRUE(JSONWriter::Write(&root_dict, &output_js));
@@ -109,17 +97,17 @@ TEST(JSONWriterTest, KeysWithPeriods) {
std::string output_js;
DictionaryValue period_dict;
- period_dict.SetWithoutPathExpansion("a.b", new FundamentalValue(3));
- period_dict.SetWithoutPathExpansion("c", new FundamentalValue(2));
- DictionaryValue* period_dict2 = new DictionaryValue;
- period_dict2->SetWithoutPathExpansion("g.h.i.j", new FundamentalValue(1));
- period_dict.SetWithoutPathExpansion("d.e.f", period_dict2);
+ period_dict.SetIntegerWithoutPathExpansion("a.b", 3);
+ period_dict.SetIntegerWithoutPathExpansion("c", 2);
+ scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue());
+ period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1);
+ period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass());
EXPECT_TRUE(JSONWriter::Write(&period_dict, &output_js));
EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
DictionaryValue period_dict3;
- period_dict3.Set("a.b", new FundamentalValue(2));
- period_dict3.SetWithoutPathExpansion("a.b", new FundamentalValue(1));
+ period_dict3.SetInteger("a.b", 2);
+ period_dict3.SetIntegerWithoutPathExpansion("a.b", 1);
EXPECT_TRUE(JSONWriter::Write(&period_dict3, &output_js));
EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
}
@@ -129,18 +117,17 @@ TEST(JSONWriterTest, BinaryValues) {
// Binary values should return errors unless suppressed via the
// OPTIONS_OMIT_BINARY_VALUES flag.
- Value* root = BinaryValue::CreateWithCopiedBuffer("asdf", 4);
- EXPECT_FALSE(JSONWriter::Write(root, &output_js));
+ scoped_ptr<Value> root(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+ EXPECT_FALSE(JSONWriter::Write(root.get(), &output_js));
EXPECT_TRUE(JSONWriter::WriteWithOptions(
- root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+ root.get(), JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
EXPECT_TRUE(output_js.empty());
- delete root;
ListValue binary_list;
binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
- binary_list.Append(new FundamentalValue(5));
+ binary_list.Append(make_scoped_ptr(new FundamentalValue(5)));
binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
- binary_list.Append(new FundamentalValue(2));
+ binary_list.Append(make_scoped_ptr(new FundamentalValue(2)));
binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
EXPECT_FALSE(JSONWriter::Write(&binary_list, &output_js));
EXPECT_TRUE(JSONWriter::WriteWithOptions(
@@ -148,11 +135,14 @@ TEST(JSONWriterTest, BinaryValues) {
EXPECT_EQ("[5,2]", output_js);
DictionaryValue binary_dict;
- binary_dict.Set("a", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
- binary_dict.Set("b", new FundamentalValue(5));
- binary_dict.Set("c", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
- binary_dict.Set("d", new FundamentalValue(2));
- binary_dict.Set("e", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+ binary_dict.Set(
+ "a", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+ binary_dict.SetInteger("b", 5);
+ binary_dict.Set(
+ "c", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+ binary_dict.SetInteger("d", 2);
+ binary_dict.Set(
+ "e", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
EXPECT_FALSE(JSONWriter::Write(&binary_dict, &output_js));
EXPECT_TRUE(JSONWriter::WriteWithOptions(
&binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
diff --git a/chromium/base/json/string_escape_unittest.cc b/chromium/base/json/string_escape_unittest.cc
index 3eb4e8e5d55..100373fccd3 100644
--- a/chromium/base/json/string_escape_unittest.cc
+++ b/chromium/base/json/string_escape_unittest.cc
@@ -159,7 +159,7 @@ TEST(JSONStringEscapeTest, EscapeBytes) {
const char* escaped;
} cases[] = {
{"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
- {"\xe5\xc4\x4f\x05\xb6\xfd\0", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
+ {"\xe5\xc4\x4f\x05\xb6\xfd", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
diff --git a/chromium/base/location.cc b/chromium/base/location.cc
index 8b32b9785ba..1333e6ec453 100644
--- a/chromium/base/location.cc
+++ b/chromium/base/location.cc
@@ -31,6 +31,13 @@ Location::Location()
program_counter_(NULL) {
}
+Location::Location(const Location& other)
+ : function_name_(other.function_name_),
+ file_name_(other.file_name_),
+ line_number_(other.line_number_),
+ program_counter_(other.program_counter_) {
+}
+
std::string Location::ToString() const {
return std::string(function_name_) + "@" + file_name_ + ":" +
base::IntToString(line_number_);
diff --git a/chromium/base/location.h b/chromium/base/location.h
index 05a4f661090..477dc022273 100644
--- a/chromium/base/location.h
+++ b/chromium/base/location.h
@@ -5,10 +5,12 @@
#ifndef BASE_LOCATION_H_
#define BASE_LOCATION_H_
+#include <cassert>
#include <string>
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
namespace tracked_objects {
@@ -27,18 +29,15 @@ class BASE_EXPORT Location {
// Provide a default constructor for easy of debugging.
Location();
- // Comparison operator for insertion into a std::map<> hash tables.
- // All we need is *some* (any) hashing distinction. Strings should already
- // be unique, so we don't bother with strcmp or such.
- // Use line number as the primary key (because it is fast, and usually gets us
- // a difference), and then pointers as secondary keys (just to get some
- // distinctions).
- bool operator < (const Location& other) const {
- if (line_number_ != other.line_number_)
- return line_number_ < other.line_number_;
- if (file_name_ != other.file_name_)
- return file_name_ < other.file_name_;
- return function_name_ < other.function_name_;
+ // Copy constructor.
+ Location(const Location& other);
+
+ // Comparator for hash map insertion.
+ // No need to use |function_name_| since the other two fields uniquely
+ // identify this location.
+ bool operator==(const Location& other) const {
+ return line_number_ == other.line_number_ &&
+ file_name_ == other.file_name_;
}
const char* function_name() const { return function_name_; }
@@ -48,6 +47,26 @@ class BASE_EXPORT Location {
std::string ToString() const;
+ // Hash operator for hash maps.
+ struct Hash {
+ size_t operator()(const Location& location) const {
+ // Compute the hash value using file name pointer and line number.
+ // No need to use |function_name_| since the other two fields uniquely
+ // identify this location.
+
+ // The file name will always be uniquely identified by its pointer since
+ // it comes from __FILE__, so no need to check the contents of the string.
+ // See the definition of FROM_HERE in location.h, and how it is used
+ // elsewhere.
+
+ // Due to inconsistent definitions of uint64_t and uintptr_t, casting the
+ // file name pointer to a uintptr_t causes a compiler error for some
+ // platforms. The solution is to explicitly cast it to a uint64_t.
+ return base::HashPair(reinterpret_cast<uint64_t>(location.file_name()),
+ location.line_number());
+ }
+ };
+
// Translate the some of the state in this instance into a human readable
// string with HTML characters in the function names escaped, and append that
// string to |output|. Inclusion of the file_name_ and function_name_ are
diff --git a/chromium/base/logging.cc b/chromium/base/logging.cc
index 150a40815c5..c7a8881456d 100644
--- a/chromium/base/logging.cc
+++ b/chromium/base/logging.cc
@@ -19,7 +19,7 @@ typedef HANDLE MutexHandle;
#include <mach-o/dyld.h>
#elif defined(OS_POSIX)
#if defined(OS_NACL)
-#include <sys/time.h> // timespec doesn't seem to be in <time.h>
+#include <sys/time.h> // timespec doesn't seem to be in <time.h>
#else
#include <sys/syscall.h>
#endif
@@ -76,8 +76,7 @@ VlogInfo* g_vlog_info_prev = NULL;
const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
"INFO", "WARNING", "ERROR", "FATAL" };
-const char* log_severity_name(int severity)
-{
+const char* log_severity_name(int severity) {
if (severity >= 0 && severity < LOG_NUM_SEVERITIES)
return log_severity_names[severity];
return "UNKNOWN";
@@ -152,7 +151,7 @@ uint64 TickCount() {
void DeleteFilePath(const PathString& log_name) {
#if defined(OS_WIN)
DeleteFile(log_name.c_str());
-#elif defined (OS_NACL)
+#elif defined(OS_NACL)
// Do nothing; unlink() isn't supported on NaCl.
#else
unlink(log_name.c_str());
@@ -165,13 +164,12 @@ PathString GetDefaultLogFile() {
wchar_t module_name[MAX_PATH];
GetModuleFileName(NULL, module_name, MAX_PATH);
- PathString log_file = module_name;
- PathString::size_type last_backslash =
- log_file.rfind('\\', log_file.size());
+ PathString log_name = module_name;
+ PathString::size_type last_backslash = log_name.rfind('\\', log_name.size());
if (last_backslash != PathString::npos)
- log_file.erase(last_backslash + 1);
- log_file += L"debug.log";
- return log_file;
+ log_name.erase(last_backslash + 1);
+ log_name += L"debug.log";
+ return log_name;
#elif defined(OS_POSIX)
// On other platforms we just use the current directory.
return PathString("debug.log");
@@ -359,7 +357,7 @@ bool BaseInitLoggingImpl(const LoggingSettings& settings) {
// Can log only to the system debug log.
CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
#endif
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// Don't bother initializing g_vlog_info unless we use one of the
// vlog switches.
if (command_line->HasSwitch(switches::kV) ||
@@ -660,7 +658,7 @@ void LogMessage::Init(const char* file, int line) {
if (log_timestamp) {
time_t t = time(NULL);
struct tm local_time = {0};
-#if _MSC_VER >= 1400
+#ifdef _MSC_VER
localtime_s(&local_time, &t);
#else
localtime_r(&t, &local_time);
@@ -706,8 +704,8 @@ SystemErrorCode GetLastSystemErrorCode() {
#if defined(OS_WIN)
BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
- const int error_message_buffer_size = 256;
- char msgbuf[error_message_buffer_size];
+ const int kErrorMessageBufferSize = 256;
+ char msgbuf[kErrorMessageBufferSize];
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
DWORD len = FormatMessageA(flags, NULL, error_code, 0, msgbuf,
arraysize(msgbuf), NULL);
@@ -808,5 +806,5 @@ std::wstring GetLogFileFullPath() {
} // namespace logging
std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
- return out << base::WideToUTF8(std::wstring(wstr));
+ return out << base::WideToUTF8(wstr);
}
diff --git a/chromium/base/logging.h b/chromium/base/logging.h
index 6a1df765895..cc0a5aa11bc 100644
--- a/chromium/base/logging.h
+++ b/chromium/base/logging.h
@@ -350,7 +350,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
// Helper macro which avoids evaluating the arguments to a stream if
-// the condition doesn't hold.
+// the condition doesn't hold. Condition is evaluated once and only once.
#define LAZY_STREAM(stream, condition) \
!(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
@@ -560,9 +560,9 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#endif
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
-#define DCHECK_IS_ON 0
+#define DCHECK_IS_ON() 0
#else
-#define DCHECK_IS_ON 1
+#define DCHECK_IS_ON() 1
#endif
// Definitions for DLOG et al.
@@ -616,14 +616,14 @@ enum { DEBUG_MODE = ENABLE_DLOG };
// Definitions for DCHECK et al.
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
const LogSeverity LOG_DCHECK = LOG_FATAL;
-#else // DCHECK_IS_ON
+#else // DCHECK_IS_ON()
// These are just dummy values.
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
@@ -631,7 +631,7 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
const LogSeverity LOG_DCHECK = LOG_INFO;
-#endif // DCHECK_IS_ON
+#endif // DCHECK_IS_ON()
// DCHECK et al. make sure to reference |condition| regardless of
// whether DCHECKs are enabled; this is so that we don't get unused
@@ -653,26 +653,24 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
#else // _PREFAST_
-#define DCHECK(condition) \
- LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \
- << "Check failed: " #condition ". "
+#define DCHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+ << "Check failed: " #condition ". "
-#define DPCHECK(condition) \
- LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \
- << "Check failed: " #condition ". "
+#define DPCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+ << "Check failed: " #condition ". "
#endif // _PREFAST_
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
-#define DCHECK_OP(name, op, val1, val2) \
- if (DCHECK_IS_ON) \
- if (std::string* _result = \
- logging::Check##name##Impl((val1), (val2), \
- #val1 " " #op " " #val2)) \
- logging::LogMessage( \
- __FILE__, __LINE__, ::logging::LOG_DCHECK, \
- _result).stream()
+#define DCHECK_OP(name, op, val1, val2) \
+ if (DCHECK_IS_ON()) \
+ if (std::string* _result = logging::Check##name##Impl( \
+ (val1), (val2), #val1 " " #op " " #val2)) \
+ logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \
+ .stream()
// Equality/Inequality checks - compare two values, and log a
// LOG_DCHECK message including the two values when the result is not
@@ -701,7 +699,7 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
#define DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2))
-#if !DCHECK_IS_ON && defined(OS_CHROMEOS)
+#if !DCHECK_IS_ON() && defined(OS_CHROMEOS)
#define NOTREACHED() LOG(ERROR) << "NOTREACHED() hit in " << \
__FUNCTION__ << ". "
#else
diff --git a/chromium/base/logging_unittest.cc b/chromium/base/logging_unittest.cc
index 95a16f2e4bb..8b9701a545f 100644
--- a/chromium/base/logging_unittest.cc
+++ b/chromium/base/logging_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -186,7 +187,7 @@ TEST_F(LoggingTest, DebugLoggingReleaseBehavior) {
TEST_F(LoggingTest, DcheckStreamsAreLazy) {
MockLogSource mock_log_source;
EXPECT_CALL(mock_log_source, Log()).Times(0);
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(true) << mock_log_source.Log();
DCHECK_EQ(0, 0) << mock_log_source.Log();
#else
@@ -201,27 +202,27 @@ TEST_F(LoggingTest, DcheckStreamsAreLazy) {
TEST_F(LoggingTest, Dcheck) {
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
// Release build.
- EXPECT_FALSE(DCHECK_IS_ON);
+ EXPECT_FALSE(DCHECK_IS_ON());
EXPECT_FALSE(DLOG_IS_ON(DCHECK));
#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
// Release build with real DCHECKS.
SetLogAssertHandler(&LogSink);
- EXPECT_TRUE(DCHECK_IS_ON);
+ EXPECT_TRUE(DCHECK_IS_ON());
EXPECT_FALSE(DLOG_IS_ON(DCHECK));
#else
// Debug build.
SetLogAssertHandler(&LogSink);
- EXPECT_TRUE(DCHECK_IS_ON);
+ EXPECT_TRUE(DCHECK_IS_ON());
EXPECT_TRUE(DLOG_IS_ON(DCHECK));
#endif
EXPECT_EQ(0, log_sink_call_count);
DCHECK(false);
- EXPECT_EQ(DCHECK_IS_ON ? 1 : 0, log_sink_call_count);
+ EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count);
DPCHECK(false);
- EXPECT_EQ(DCHECK_IS_ON ? 2 : 0, log_sink_call_count);
+ EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count);
DCHECK_EQ(0, 1);
- EXPECT_EQ(DCHECK_IS_ON ? 3 : 0, log_sink_call_count);
+ EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count);
}
TEST_F(LoggingTest, DcheckReleaseBehavior) {
diff --git a/chromium/base/logging_win.h b/chromium/base/logging_win.h
index 38508a32466..aa48e22e76d 100644
--- a/chromium/base/logging_win.h
+++ b/chromium/base/logging_win.h
@@ -61,8 +61,8 @@ class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider {
protected:
// Overridden to manipulate the log level on ETW control callbacks.
- virtual void OnEventsEnabled();
- virtual void OnEventsDisabled();
+ void OnEventsEnabled() override;
+ void OnEventsDisabled() override;
private:
LogEventProvider();
diff --git a/chromium/base/mac/authorization_util.mm b/chromium/base/mac/authorization_util.mm
index 6cb8de3f73b..1dfd5a019f2 100644
--- a/chromium/base/mac/authorization_util.mm
+++ b/chromium/base/mac/authorization_util.mm
@@ -12,8 +12,8 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
#include "base/mac/mac_logging.h"
-#import "base/mac/mac_util.h"
#include "base/mac/scoped_authorizationref.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"
@@ -28,10 +28,9 @@ AuthorizationRef GetAuthorizationRightsWithPrompt(
AuthorizationFlags extraFlags) {
// Create an empty AuthorizationRef.
ScopedAuthorizationRef authorization;
- OSStatus status = AuthorizationCreate(NULL,
- kAuthorizationEmptyEnvironment,
+ OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
- &authorization);
+ authorization.get_pointer());
if (status != errAuthorizationSuccess) {
OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate";
return NULL;
diff --git a/chromium/base/mac/close_nocancel.cc b/chromium/base/mac/close_nocancel.cc
index 134f7ac25cc..8971e731c98 100644
--- a/chromium/base/mac/close_nocancel.cc
+++ b/chromium/base/mac/close_nocancel.cc
@@ -28,12 +28,14 @@
//
// This file operates by providing a close function with the non-$NOCANCEL
// symbol name expected for the compilation environment as set by <unistd.h>
-// and <sys/cdefs.h> (the DARWIN_ALIAS_C macro). That function calls the
-// $NOCANCEL variant, which is resolved from libsyscall. By linking with this
-// version of close prior to the libsyscall version, close's implementation is
-// overridden.
+// and <sys/cdefs.h> (the DARWIN_ALIAS_C macro). That name is set by an asm
+// label on the declaration of the close function, so the definition of that
+// function receives that name. The function calls the $NOCANCEL variant, which
+// is resolved from libsyscall. By linking with this version of close prior to
+// the libsyscall version, close's implementation is overridden.
#include <sys/cdefs.h>
+#include <unistd.h>
// If the non-cancelable variants of all system calls have already been
// chosen, do nothing.
@@ -41,37 +43,26 @@
extern "C" {
-#if __DARWIN_UNIX03 && !__DARWIN_ONLY_UNIX_CONFORMANCE
+#if !__DARWIN_ONLY_UNIX_CONFORMANCE
-// When there's a choice between UNIX2003 and pre-UNIX2003 and UNIX2003 has
-// been chosen:
-#define close_interface close$UNIX2003
-#define close_implementation close$NOCANCEL$UNIX2003
-
-#elif !__DARWIN_UNIX03 && !__DARWIN_ONLY_UNIX_CONFORMANCE
-
-// When there's a choice between UNIX2003 and pre-UNIX2003 and pre-UNIX2003
-// has been chosen. There's no close$NOCANCEL symbol in this case, so use
-// close$NOCANCEL$UNIX2003 as the implementation. It does the same thing
-// that close$NOCANCEL would do.
-#define close_interface close
+// When there's a choice between UNIX2003 and pre-UNIX2003. There's no
+// close$NOCANCEL symbol in this case, so use close$NOCANCEL$UNIX2003 as the
+// implementation. It does the same thing that close$NOCANCEL would do.
#define close_implementation close$NOCANCEL$UNIX2003
#else // __DARWIN_ONLY_UNIX_CONFORMANCE
// When only UNIX2003 is supported:
-#define close_interface close
#define close_implementation close$NOCANCEL
#endif
int close_implementation(int fd);
-int close_interface(int fd) {
+int close(int fd) {
return close_implementation(fd);
}
-#undef close_interface
#undef close_implementation
} // extern "C"
diff --git a/chromium/base/mac/cocoa_protocols.h b/chromium/base/mac/cocoa_protocols.h
index e10001f6be0..a28795c3a4d 100644
--- a/chromium/base/mac/cocoa_protocols.h
+++ b/chromium/base/mac/cocoa_protocols.h
@@ -2,15 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_COCOA_PROTOCOLS_MAC_H_
-#define BASE_COCOA_PROTOCOLS_MAC_H_
+#ifndef BASE_MAC_COCOA_PROTOCOLS_H_
+#define BASE_MAC_COCOA_PROTOCOLS_H_
#import <Cocoa/Cocoa.h>
-// GTM also maintains a list of empty protocols, but only the ones the library
-// requires. Augment that below.
-#import "third_party/google_toolbox_for_mac/src/GTMDefines.h"
-
// New Mac OS X SDKs introduce new protocols used for delegates. These
// protocol defintions aren't not present in earlier releases of the Mac OS X
// SDK. In order to support building against the new SDK, which requires
@@ -32,4 +28,4 @@ DEFINE_EMPTY_PROTOCOL(ICCameraDeviceDownloadDelegate)
#undef DEFINE_EMPTY_PROTOCOL
-#endif // BASE_COCOA_PROTOCOLS_MAC_H_
+#endif // BASE_MAC_COCOA_PROTOCOLS_H_
diff --git a/chromium/base/mac/dispatch_source_mach.cc b/chromium/base/mac/dispatch_source_mach.cc
new file mode 100644
index 00000000000..745c9dec7d1
--- /dev/null
+++ b/chromium/base/mac/dispatch_source_mach.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/dispatch_source_mach.h"
+
+namespace base {
+
+DispatchSourceMach::DispatchSourceMach(const char* name,
+ mach_port_t port,
+ void (^event_handler)())
+ // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL
+ // means the same thing but is not symbolically clear.
+ : DispatchSourceMach(dispatch_queue_create(name, NULL),
+ port,
+ event_handler) {
+ // Since the queue was created above in the delegated constructor, and it was
+ // subsequently retained, release it here.
+ dispatch_release(queue_);
+}
+
+DispatchSourceMach::DispatchSourceMach(dispatch_queue_t queue,
+ mach_port_t port,
+ void (^event_handler)())
+ : queue_(queue),
+ source_(dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
+ port, 0, queue_)),
+ source_canceled_(dispatch_semaphore_create(0)) {
+ dispatch_retain(queue);
+
+ dispatch_source_set_event_handler(source_, event_handler);
+ dispatch_source_set_cancel_handler(source_, ^{
+ dispatch_semaphore_signal(source_canceled_);
+ });
+}
+
+DispatchSourceMach::~DispatchSourceMach() {
+ Cancel();
+}
+
+void DispatchSourceMach::Resume() {
+ dispatch_resume(source_);
+}
+
+void DispatchSourceMach::Cancel() {
+ if (source_) {
+ dispatch_source_cancel(source_);
+ dispatch_release(source_);
+ source_ = NULL;
+
+ dispatch_semaphore_wait(source_canceled_, DISPATCH_TIME_FOREVER);
+ dispatch_release(source_canceled_);
+ source_canceled_ = NULL;
+ }
+
+ if (queue_) {
+ dispatch_release(queue_);
+ queue_ = NULL;
+ }
+}
+
+} // namespace base
diff --git a/chromium/base/mac/dispatch_source_mach.h b/chromium/base/mac/dispatch_source_mach.h
new file mode 100644
index 00000000000..e7d5cb2fbb4
--- /dev/null
+++ b/chromium/base/mac/dispatch_source_mach.h
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_DISPATCH_SOURCE_MACH_H_
+#define BASE_MAC_DISPATCH_SOURCE_MACH_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+
+// This class encapsulates a MACH_RECV dispatch source. When this object is
+// destroyed, the source will be cancelled and it will wait for the source
+// to stop executing work. The source can run on either a user-supplied queue,
+// or it can create its own for the source.
+class BASE_EXPORT DispatchSourceMach {
+ public:
+ // Creates a new dispatch source for the |port| and schedules it on a new
+ // queue that will be created with |name|. When a Mach message is received,
+ // the |event_handler| will be called.
+ DispatchSourceMach(const char* name,
+ mach_port_t port,
+ void (^event_handler)());
+
+ // Creates a new dispatch source with the same semantics as above, but rather
+ // than creating a new queue, it schedules the source on |queue|.
+ DispatchSourceMach(dispatch_queue_t queue,
+ mach_port_t port,
+ void (^event_handler)());
+
+ // Cancels the source and waits for it to become fully cancelled before
+ // releasing the source.
+ ~DispatchSourceMach();
+
+ // Resumes the source. This must be called before any Mach messages will
+ // be received.
+ void Resume();
+
+ private:
+ // Cancels the source, after which this class will no longer receive Mach
+ // messages. Calling this more than once is a no-op.
+ void Cancel();
+
+ // The dispatch queue used to service the source_.
+ dispatch_queue_t queue_;
+
+ // A MACH_RECV dispatch source.
+ dispatch_source_t source_;
+
+ // Semaphore used to wait on the |source_|'s cancellation in the destructor.
+ dispatch_semaphore_t source_canceled_;
+
+ DISALLOW_COPY_AND_ASSIGN(DispatchSourceMach);
+};
+
+} // namespace base
+
+#endif // BASE_MAC_DISPATCH_SOURCE_MACH_H_
diff --git a/chromium/base/mac/dispatch_source_mach_unittest.cc b/chromium/base/mac/dispatch_source_mach_unittest.cc
new file mode 100644
index 00000000000..82dc13643c4
--- /dev/null
+++ b/chromium/base/mac/dispatch_source_mach_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/dispatch_source_mach.h"
+
+#include <mach/mach.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class DispatchSourceMachTest : public testing::Test {
+ public:
+ void SetUp() override {
+ mach_port_t port = MACH_PORT_NULL;
+ ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE, &port));
+ receive_right_.reset(port);
+
+ ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(mach_task_self(), port,
+ port, MACH_MSG_TYPE_MAKE_SEND));
+ send_right_.reset(port);
+ }
+
+ mach_port_t GetPort() { return receive_right_.get(); }
+
+ void WaitForSemaphore(dispatch_semaphore_t semaphore) {
+ dispatch_semaphore_wait(semaphore, dispatch_time(
+ DISPATCH_TIME_NOW,
+ TestTimeouts::action_timeout().InSeconds() * NSEC_PER_SEC));
+ }
+
+ private:
+ base::mac::ScopedMachReceiveRight receive_right_;
+ base::mac::ScopedMachSendRight send_right_;
+};
+
+TEST_F(DispatchSourceMachTest, ReceiveAfterResume) {
+ dispatch_semaphore_t signal = dispatch_semaphore_create(0);
+ mach_port_t port = GetPort();
+
+ bool __block did_receive = false;
+ DispatchSourceMach source("org.chromium.base.test.ReceiveAfterResume",
+ port, ^{
+ mach_msg_empty_rcv_t msg = {{0}};
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_local_port = port;
+ mach_msg_receive(&msg.header);
+ did_receive = true;
+
+ dispatch_semaphore_signal(signal);
+ });
+
+ mach_msg_empty_send_t msg = {{0}};
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_remote_port = port;
+ msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+ ASSERT_EQ(KERN_SUCCESS, mach_msg_send(&msg.header));
+
+ EXPECT_FALSE(did_receive);
+
+ source.Resume();
+
+ WaitForSemaphore(signal);
+ dispatch_release(signal);
+
+ EXPECT_TRUE(did_receive);
+}
+
+TEST_F(DispatchSourceMachTest, NoMessagesAfterDestruction) {
+ mach_port_t port = GetPort();
+
+ scoped_ptr<int> count(new int(0));
+ int* __block count_ptr = count.get();
+
+ scoped_ptr<DispatchSourceMach> source(new DispatchSourceMach(
+ "org.chromium.base.test.NoMessagesAfterDestruction",
+ port, ^{
+ mach_msg_empty_rcv_t msg = {{0}};
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_local_port = port;
+ mach_msg_receive(&msg.header);
+ LOG(INFO) << "Receieve " << *count_ptr;
+ ++(*count_ptr);
+ }));
+ source->Resume();
+
+ dispatch_queue_t queue =
+ dispatch_queue_create("org.chromium.base.test.MessageSend", NULL);
+ dispatch_semaphore_t signal = dispatch_semaphore_create(0);
+ for (int i = 0; i < 30; ++i) {
+ dispatch_async(queue, ^{
+ mach_msg_empty_send_t msg = {{0}};
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_remote_port = port;
+ msg.header.msgh_bits =
+ MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+ mach_msg_send(&msg.header);
+ });
+
+ // After sending five messages, shut down the source and taint the
+ // pointer the handler dereferences. The test will crash if |count_ptr|
+ // is being used after "free".
+ if (i == 5) {
+ scoped_ptr<DispatchSourceMach>* source_ptr = &source;
+ dispatch_async(queue, ^{
+ source_ptr->reset();
+ count_ptr = reinterpret_cast<int*>(0xdeaddead);
+ dispatch_semaphore_signal(signal);
+ });
+ }
+ }
+
+ WaitForSemaphore(signal);
+ dispatch_release(signal);
+
+ dispatch_release(queue);
+}
+
+} // namespace base
diff --git a/chromium/base/mac/foundation_util.h b/chromium/base/mac/foundation_util.h
index 46ea3c324c3..353ed7c6318 100644
--- a/chromium/base/mac/foundation_util.h
+++ b/chromium/base/mac/foundation_util.h
@@ -64,6 +64,15 @@ namespace mac {
BASE_EXPORT bool AmIBundled();
BASE_EXPORT void SetOverrideAmIBundled(bool value);
+#if defined(UNIT_TEST)
+// This is required because instantiating some tests requires checking the
+// directory structure, which sets the AmIBundled cache state. Individual tests
+// may or may not be bundled, and this would trip them up if the cache weren't
+// cleared. This should not be called from individual tests, just from test
+// instantiation code that gets a path from PathService.
+BASE_EXPORT void ClearAmIBundledCache();
+#endif
+
// Returns true if this process is marked as a "Background only process".
BASE_EXPORT bool IsBackgroundOnlyProcess();
@@ -287,6 +296,7 @@ CF_CAST_DECL(CFUUID);
CF_CAST_DECL(CGColor);
CF_CAST_DECL(CTFont);
+CF_CAST_DECL(CTFontDescriptor);
CF_CAST_DECL(CTRun);
CF_CAST_DECL(SecACL);
diff --git a/chromium/base/mac/foundation_util.mm b/chromium/base/mac/foundation_util.mm
index 4e9b2248874..27d6e7c4653 100644
--- a/chromium/base/mac/foundation_util.mm
+++ b/chromium/base/mac/foundation_util.mm
@@ -26,6 +26,8 @@ namespace mac {
namespace {
+bool g_cached_am_i_bundled_called = false;
+bool g_cached_am_i_bundled_value = false;
bool g_override_am_i_bundled = false;
bool g_override_am_i_bundled_value = false;
@@ -48,12 +50,15 @@ bool AmIBundled() {
// If the return value is not cached, this function will return different
// values depending on when it's called. This confuses some client code, see
// http://crbug.com/63183 .
- static bool result = UncachedAmIBundled();
- DCHECK_EQ(result, UncachedAmIBundled())
+ if (!g_cached_am_i_bundled_called) {
+ g_cached_am_i_bundled_called = true;
+ g_cached_am_i_bundled_value = UncachedAmIBundled();
+ }
+ DCHECK_EQ(g_cached_am_i_bundled_value, UncachedAmIBundled())
<< "The return value of AmIBundled() changed. This will confuse tests. "
<< "Call SetAmIBundled() override manually if your test binary "
<< "delay-loads the framework.";
- return result;
+ return g_cached_am_i_bundled_value;
}
void SetOverrideAmIBundled(bool value) {
@@ -66,6 +71,10 @@ void SetOverrideAmIBundled(bool value) {
g_override_am_i_bundled_value = value;
}
+BASE_EXPORT void ClearAmIBundledCache() {
+ g_cached_am_i_bundled_called = false;
+}
+
bool IsBackgroundOnlyProcess() {
// This function really does want to examine NSBundle's idea of the main
// bundle dictionary. It needs to look at the actual running .app's
@@ -353,6 +362,7 @@ CF_CAST_DEFN(CFUUID);
CF_CAST_DEFN(CGColor);
+CF_CAST_DEFN(CTFontDescriptor);
CF_CAST_DEFN(CTRun);
#if defined(OS_IOS)
diff --git a/chromium/base/mac/launch_services_util.cc b/chromium/base/mac/launch_services_util.cc
index 61210814040..4c3b417095f 100644
--- a/chromium/base/mac/launch_services_util.cc
+++ b/chromium/base/mac/launch_services_util.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
namespace base {
diff --git a/chromium/base/mac/launch_services_util.h b/chromium/base/mac/launch_services_util.h
index 0c52ca94c52..0e64316052b 100644
--- a/chromium/base/mac/launch_services_util.h
+++ b/chromium/base/mac/launch_services_util.h
@@ -5,7 +5,7 @@
#ifndef BASE_MAC_LAUNCH_SERVICES_UTIL_H_
#define BASE_MAC_LAUNCH_SERVICES_UTIL_H_
-#include <ApplicationServices/ApplicationServices.h>
+#include <CoreServices/CoreServices.h>
#include "base/base_export.h"
#include "base/command_line.h"
diff --git a/chromium/base/mac/libdispatch_task_runner.h b/chromium/base/mac/libdispatch_task_runner.h
index f5fd866006e..b479bc7aa2b 100644
--- a/chromium/base/mac/libdispatch_task_runner.h
+++ b/chromium/base/mac/libdispatch_task_runner.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_
-#define BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_
+#ifndef BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
+#define BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
#include <dispatch/dispatch.h>
@@ -77,4 +77,4 @@ class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner {
} // namespace mac
} // namespace base
-#endif // BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_
+#endif // BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
diff --git a/chromium/base/mac/libdispatch_task_runner_unittest.cc b/chromium/base/mac/libdispatch_task_runner_unittest.cc
index cad0efaa48e..49b0c9ae9d7 100644
--- a/chromium/base/mac/libdispatch_task_runner_unittest.cc
+++ b/chromium/base/mac/libdispatch_task_runner_unittest.cc
@@ -12,7 +12,7 @@
class LibDispatchTaskRunnerTest : public testing::Test {
public:
- virtual void SetUp() override {
+ void SetUp() override {
task_runner_ = new base::mac::LibDispatchTaskRunner(
"org.chromium.LibDispatchTaskRunnerTest");
}
diff --git a/chromium/base/mac/mac_logging.h b/chromium/base/mac/mac_logging.h
index 1081490ec4a..5192b208f1c 100644
--- a/chromium/base/mac/mac_logging.h
+++ b/chromium/base/mac/mac_logging.h
@@ -87,9 +87,9 @@ class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage {
LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
MAC_DVLOG_IS_ON(verbose_level) && (condition))
-#define OSSTATUS_DCHECK(condition, status) \
- LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \
- DCHECK_IS_ON && !(condition)) \
- << "Check failed: " # condition << ". "
+#define OSSTATUS_DCHECK(condition, status) \
+ LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \
+ DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition << ". "
#endif // BASE_MAC_MAC_LOGGING_H_
diff --git a/chromium/base/mac/mac_util.h b/chromium/base/mac/mac_util.h
index d93b49508dd..f8ffa97545d 100644
--- a/chromium/base/mac/mac_util.h
+++ b/chromium/base/mac/mac_util.h
@@ -12,9 +12,6 @@
#include "base/base_export.h"
#include "base/logging.h"
-// TODO(rohitrao): Clean up sites that include mac_util.h and remove this line.
-#include "base/mac/foundation_util.h"
-
#if defined(__OBJC__)
#import <Foundation/Foundation.h>
#else // __OBJC__
diff --git a/chromium/base/mac/mac_util_unittest.mm b/chromium/base/mac/mac_util_unittest.mm
index 3b23e53571b..3982ab00dfc 100644
--- a/chromium/base/mac/mac_util_unittest.mm
+++ b/chromium/base/mac/mac_util_unittest.mm
@@ -100,7 +100,8 @@ TEST_F(MacUtilTest, TestGetAppBundlePath) {
}
}
-TEST_F(MacUtilTest, TestExcludeFileFromBackups) {
+// http://crbug.com/425745
+TEST_F(MacUtilTest, DISABLED_TestExcludeFileFromBackups) {
// The file must already exist in order to set its exclusion property.
ScopedTempDir temp_dir_;
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
diff --git a/chromium/base/mac/mach_logging.h b/chromium/base/mac/mach_logging.h
index a9b3b65d648..b12e274ea80 100644
--- a/chromium/base/mac/mach_logging.h
+++ b/chromium/base/mac/mach_logging.h
@@ -91,10 +91,10 @@ class BASE_EXPORT MachLogMessage : public logging::LogMessage {
LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
MACH_DVLOG_IS_ON(verbose_level) && (condition))
-#define MACH_DCHECK(condition, mach_err) \
- LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), \
- DCHECK_IS_ON && !(condition)) \
- << "Check failed: " # condition << ". "
+#define MACH_DCHECK(condition, mach_err) \
+ LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), \
+ DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition << ". "
#if !defined(OS_IOS)
@@ -157,10 +157,10 @@ class BASE_EXPORT BootstrapLogMessage : public logging::LogMessage {
LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
BOOTSTRAP_DVLOG_IS_ON(verbose_level) && (condition))
-#define BOOTSTRAP_DCHECK(condition, bootstrap_err) \
- LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), \
- DCHECK_IS_ON && !(condition)) \
- << "Check failed: " # condition << ". "
+#define BOOTSTRAP_DCHECK(condition, bootstrap_err) \
+ LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), \
+ DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition << ". "
#endif // !OS_IOS
diff --git a/chromium/base/mac/memory_pressure_monitor.cc b/chromium/base/mac/memory_pressure_monitor.cc
new file mode 100644
index 00000000000..5667aa6661c
--- /dev/null
+++ b/chromium/base/mac/memory_pressure_monitor.cc
@@ -0,0 +1,78 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/memory_pressure_monitor.h"
+
+#include <dlfcn.h>
+#include <sys/sysctl.h>
+
+#include "base/mac/mac_util.h"
+
+namespace base {
+namespace mac {
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure(
+ int mac_memory_pressure) {
+ switch (mac_memory_pressure) {
+ case DISPATCH_MEMORYPRESSURE_NORMAL:
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+ case DISPATCH_MEMORYPRESSURE_WARN:
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+ case DISPATCH_MEMORYPRESSURE_CRITICAL:
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+ }
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void MemoryPressureMonitor::NotifyMemoryPressureChanged(
+ dispatch_source_s* event_source) {
+ int mac_memory_pressure = dispatch_source_get_data(event_source);
+ MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
+ MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+ MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
+MemoryPressureMonitor::MemoryPressureMonitor()
+ : memory_level_event_source_(nullptr) {
+ // _dispatch_source_type_memorypressure is not available prior to 10.9.
+ dispatch_source_type_t dispatch_source_memorypressure =
+ static_cast<dispatch_source_type_t>
+ (dlsym(RTLD_NEXT, "_dispatch_source_type_memorypressure"));
+ if (dispatch_source_memorypressure) {
+ // The MemoryPressureListener doesn't want to know about transitions to
+ // MEMORY_PRESSURE_LEVEL_NONE so don't watch for
+ // DISPATCH_MEMORYPRESSURE_NORMAL notifications.
+ memory_level_event_source_.reset(
+ dispatch_source_create(dispatch_source_memorypressure, 0,
+ DISPATCH_MEMORYPRESSURE_WARN |
+ DISPATCH_MEMORYPRESSURE_CRITICAL,
+ dispatch_get_global_queue(
+ DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
+
+ dispatch_source_set_event_handler(memory_level_event_source_.get(), ^{
+ NotifyMemoryPressureChanged(memory_level_event_source_.get());
+ });
+ dispatch_retain(memory_level_event_source_.get());
+ dispatch_resume(memory_level_event_source_.get());
+ }
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+ if (base::mac::IsOSMountainLionOrEarlier()) {
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+ }
+ int mac_memory_pressure;
+ size_t length = sizeof(int);
+ sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure,
+ &length, nullptr, 0);
+ return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+}
+
+} // namespace mac
+} // namespace base
diff --git a/chromium/base/mac/memory_pressure_monitor.h b/chromium/base/mac/memory_pressure_monitor.h
new file mode 100644
index 00000000000..afaec274715
--- /dev/null
+++ b/chromium/base/mac/memory_pressure_monitor.h
@@ -0,0 +1,63 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_MAC_MEMORY_PRESSURE_MONITOR_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+
+// The following was added to <dispatch/source.h> after 10.8.
+// TODO(shrike): Remove the DISPATCH_MEMORYPRESSURE_NORMAL ifndef once builders
+// reach 10.9 or higher.
+#ifndef DISPATCH_MEMORYPRESSURE_NORMAL
+
+#define DISPATCH_MEMORYPRESSURE_NORMAL 0x01
+#define DISPATCH_MEMORYPRESSURE_WARN 0x02
+#define DISPATCH_MEMORYPRESSURE_CRITICAL 0x04
+
+#endif // DISPATCH_MEMORYPRESSURE_NORMAL
+
+namespace base {
+namespace mac {
+
+class TestMemoryPressureMonitor;
+
+struct DispatchSourceSDeleter {
+ void operator()(dispatch_source_s* ptr) {
+ dispatch_source_cancel(ptr);
+ dispatch_release(ptr);
+ }
+};
+
+// Declares the interface for the Mac MemoryPressureMonitor, which reports
+// memory pressure events and status.
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+ MemoryPressureMonitor();
+ ~MemoryPressureMonitor() override;
+
+ // Returns the currently-observed memory pressure.
+ MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+ private:
+ friend TestMemoryPressureMonitor;
+
+ static MemoryPressureLevel
+ MemoryPressureLevelForMacMemoryPressure(int mac_memory_pressure);
+ static void NotifyMemoryPressureChanged(dispatch_source_s* event_source);
+
+ scoped_ptr<dispatch_source_s, DispatchSourceSDeleter>
+ memory_level_event_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+} // namespace mac
+} // namespace base
+
+#endif // BASE_MAC_MEMORY_PRESSURE_MONITOR_H_
diff --git a/chromium/base/mac/memory_pressure_monitor_unittest.cc b/chromium/base/mac/memory_pressure_monitor_unittest.cc
new file mode 100644
index 00000000000..acb366609ef
--- /dev/null
+++ b/chromium/base/mac/memory_pressure_monitor_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/memory_pressure_monitor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace mac {
+
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+ using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure;
+
+ TestMemoryPressureMonitor() { }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+TEST(MacMemoryPressureMonitorTest, MemoryPressureFromMacMemoryPressure) {
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(
+ DISPATCH_MEMORYPRESSURE_NORMAL));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(
+ DISPATCH_MEMORYPRESSURE_WARN));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(
+ DISPATCH_MEMORYPRESSURE_CRITICAL));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(0));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(3));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(5));
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ TestMemoryPressureMonitor::
+ MemoryPressureLevelForMacMemoryPressure(-1));
+}
+
+TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) {
+ TestMemoryPressureMonitor monitor;
+ MemoryPressureListener::MemoryPressureLevel memory_pressure =
+ monitor.GetCurrentPressureLevel();
+ EXPECT_TRUE(memory_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE ||
+ memory_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE ||
+ memory_pressure ==
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
+} // namespace mac
+} // namespace base
diff --git a/chromium/base/mac/scoped_authorizationref.h b/chromium/base/mac/scoped_authorizationref.h
index 6413f2e4164..18114883800 100644
--- a/chromium/base/mac/scoped_authorizationref.h
+++ b/chromium/base/mac/scoped_authorizationref.h
@@ -49,9 +49,7 @@ class ScopedAuthorizationRef {
return authorization_;
}
- AuthorizationRef* operator&() {
- return &authorization_;
- }
+ AuthorizationRef* get_pointer() { return &authorization_; }
AuthorizationRef get() const {
return authorization_;
diff --git a/chromium/base/mac/scoped_mach_port.cc b/chromium/base/mac/scoped_mach_port.cc
index de94602e36e..13307f2c9d2 100644
--- a/chromium/base/mac/scoped_mach_port.cc
+++ b/chromium/base/mac/scoped_mach_port.cc
@@ -25,6 +25,14 @@ void ReceiveRightTraits::Free(mach_port_t port) {
<< "ScopedMachReceiveRight mach_port_mod_refs";
}
+// static
+void PortSetTraits::Free(mach_port_t port) {
+ kern_return_t kr =
+ mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, -1);
+ MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+ << "ScopedMachPortSet mach_port_mod_refs";
+}
+
} // namespace internal
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_mach_port.h b/chromium/base/mac/scoped_mach_port.h
index 36087c9bdec..beb62b03213 100644
--- a/chromium/base/mac/scoped_mach_port.h
+++ b/chromium/base/mac/scoped_mach_port.h
@@ -20,7 +20,7 @@ struct BASE_EXPORT SendRightTraits {
return MACH_PORT_NULL;
}
- static void Free(mach_port_t port);
+ BASE_EXPORT static void Free(mach_port_t port);
};
struct BASE_EXPORT ReceiveRightTraits {
@@ -28,7 +28,15 @@ struct BASE_EXPORT ReceiveRightTraits {
return MACH_PORT_NULL;
}
- static void Free(mach_port_t port);
+ BASE_EXPORT static void Free(mach_port_t port);
+};
+
+struct PortSetTraits {
+ static mach_port_t InvalidValue() {
+ return MACH_PORT_NULL;
+ }
+
+ BASE_EXPORT static void Free(mach_port_t port);
};
} // namespace internal
@@ -59,6 +67,19 @@ class BASE_EXPORT ScopedMachReceiveRight :
operator mach_port_t() const { return get(); }
};
+// A scoper for handling a Mach port set. A port set can have only one
+// reference. This takes ownership of that single reference on construction and
+// destroys the port set on destruction. Destroying a port set does not destroy
+// the receive rights that are members of the port set.
+class BASE_EXPORT ScopedMachPortSet :
+ public ScopedGeneric<mach_port_t, internal::PortSetTraits> {
+ public:
+ explicit ScopedMachPortSet(mach_port_t port = traits_type::InvalidValue())
+ : ScopedGeneric(port) {}
+
+ operator mach_port_t() const { return get(); }
+};
+
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_mach_vm.cc b/chromium/base/mac/scoped_mach_vm.cc
index 1c28d9c7c42..d52c77f6398 100644
--- a/chromium/base/mac/scoped_mach_vm.cc
+++ b/chromium/base/mac/scoped_mach_vm.cc
@@ -8,8 +8,8 @@ namespace base {
namespace mac {
void ScopedMachVM::reset(vm_address_t address, vm_size_t size) {
- DCHECK(address % PAGE_SIZE == 0);
- DCHECK(size % PAGE_SIZE == 0);
+ DCHECK_EQ(address % PAGE_SIZE, 0u);
+ DCHECK_EQ(size % PAGE_SIZE, 0u);
if (size_) {
if (address_ < address) {
diff --git a/chromium/base/mac/scoped_mach_vm.h b/chromium/base/mac/scoped_mach_vm.h
index b130a79fb63..ffc00d5a5d2 100644
--- a/chromium/base/mac/scoped_mach_vm.h
+++ b/chromium/base/mac/scoped_mach_vm.h
@@ -48,10 +48,9 @@ namespace mac {
class BASE_EXPORT ScopedMachVM {
public:
explicit ScopedMachVM(vm_address_t address = 0, vm_size_t size = 0)
- : address_(address),
- size_(size) {
- DCHECK(address % PAGE_SIZE == 0);
- DCHECK(size % PAGE_SIZE == 0);
+ : address_(address), size_(size) {
+ DCHECK_EQ(address % PAGE_SIZE, 0u);
+ DCHECK_EQ(size % PAGE_SIZE, 0u);
}
~ScopedMachVM() {
diff --git a/chromium/base/mac/scoped_nsobject.h b/chromium/base/mac/scoped_nsobject.h
index 8d7bd4a27bd..836bdcc3507 100644
--- a/chromium/base/mac/scoped_nsobject.h
+++ b/chromium/base/mac/scoped_nsobject.h
@@ -5,10 +5,16 @@
#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
#define BASE_MAC_SCOPED_NSOBJECT_H_
-#import <Foundation/Foundation.h>
+// Include NSObject.h directly because Foundation.h pulls in many dependencies.
+// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
+// singled out because it is most typically included from other header files.
+#import <Foundation/NSObject.h>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+@class NSAutoreleasePool;
+
namespace base {
// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
@@ -40,6 +46,11 @@ class scoped_nsprotocol {
: object_([that.object_ retain]) {
}
+ template <typename NSU>
+ scoped_nsprotocol(const scoped_nsprotocol<NSU>& that)
+ : object_([that.get() retain]) {
+ }
+
~scoped_nsprotocol() {
[object_ release];
}
@@ -119,6 +130,11 @@ class scoped_nsobject : public scoped_nsprotocol<NST*> {
: scoped_nsprotocol<NST*>(that) {
}
+ template<typename NSU>
+ scoped_nsobject(const scoped_nsobject<NSU>& that)
+ : scoped_nsprotocol<NST*>(that) {
+ }
+
scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
scoped_nsprotocol<NST*>::operator=(that);
return *this;
@@ -135,6 +151,11 @@ class scoped_nsobject<id> : public scoped_nsprotocol<id> {
: scoped_nsprotocol<id>(that) {
}
+ template<typename NSU>
+ scoped_nsobject(const scoped_nsobject<NSU>& that)
+ : scoped_nsprotocol<id>(that) {
+ }
+
scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
scoped_nsprotocol<id>::operator=(that);
return *this;
diff --git a/chromium/base/mac/scoped_sending_event_unittest.mm b/chromium/base/mac/scoped_sending_event_unittest.mm
index 95f6eba16ab..02ef2dbe292 100644
--- a/chromium/base/mac/scoped_sending_event_unittest.mm
+++ b/chromium/base/mac/scoped_sending_event_unittest.mm
@@ -27,9 +27,7 @@ class ScopedSendingEventTest : public testing::Test {
ScopedSendingEventTest() : app_([[ScopedSendingEventTestCrApp alloc] init]) {
NSApp = app_.get();
}
- virtual ~ScopedSendingEventTest() {
- NSApp = nil;
- }
+ ~ScopedSendingEventTest() override { NSApp = nil; }
private:
base::scoped_nsobject<ScopedSendingEventTestCrApp> app_;
diff --git a/chromium/base/mac/sdk_forward_declarations.h b/chromium/base/mac/sdk_forward_declarations.h
index fde0fcc744a..d70a6aa7deb 100644
--- a/chromium/base/mac/sdk_forward_declarations.h
+++ b/chromium/base/mac/sdk_forward_declarations.h
@@ -18,16 +18,91 @@
#include "base/base_export.h"
+// ----------------------------------------------------------------------------
+// Either define or forward declare classes only available in OSX 10.7+.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface CWChannel : NSObject
+@end
+
+@interface CBPeripheral : NSObject
+@end
+
+@interface CBCentralManager : NSObject
+@end
+
+@interface CBUUID : NSObject
+@end
+
+#else
+
+@class CWChannel;
+@class CBPeripheral;
+@class CBCentralManager;
+@class CBUUID;
+
+#endif // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+@interface NSUUID : NSObject
+@end
+
+#else
+
+@class NSUUID;
+
+#endif // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+// NSProgress is public API in 10.9, but a version of it exists and is usable
+// in 10.8.
+@interface NSProgress : NSObject
+@end
+
+@interface NSAppearance : NSObject
+@end
+
+#else
+
+@class NSProgress;
+@class NSAppearance;
+
+#endif // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity : NSObject
+@end
+
+#else
+
+@class NSUserActivity;
+
+#endif // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Define typedefs, enums, and protocols not available in the version of the
+// OSX SDK being compiled against.
+// ----------------------------------------------------------------------------
+
#if !defined(MAC_OS_X_VERSION_10_7) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
enum {
- NSEventPhaseNone = 0, // event not associated with a phase.
- NSEventPhaseBegan = 0x1 << 0,
- NSEventPhaseStationary = 0x1 << 1,
- NSEventPhaseChanged = 0x1 << 2,
- NSEventPhaseEnded = 0x1 << 3,
- NSEventPhaseCancelled = 0x1 << 4
+ NSEventPhaseNone = 0, // event not associated with a phase.
+ NSEventPhaseBegan = 0x1 << 0,
+ NSEventPhaseStationary = 0x1 << 1,
+ NSEventPhaseChanged = 0x1 << 2,
+ NSEventPhaseEnded = 0x1 << 3,
+ NSEventPhaseCancelled = 0x1 << 4
};
typedef NSUInteger NSEventPhase;
@@ -65,9 +140,141 @@ enum {
};
typedef NSUInteger NSWindowButton;
+enum CWChannelBand {
+ kCWChannelBandUnknown = 0,
+ kCWChannelBand2GHz = 1,
+ kCWChannelBand5GHz = 2,
+};
+
+enum {
+ kCWSecurityNone = 0,
+ kCWSecurityWEP = 1,
+ kCWSecurityWPAPersonal = 2,
+ kCWSecurityWPAPersonalMixed = 3,
+ kCWSecurityWPA2Personal = 4,
+ kCWSecurityPersonal = 5,
+ kCWSecurityDynamicWEP = 6,
+ kCWSecurityWPAEnterprise = 7,
+ kCWSecurityWPAEnterpriseMixed = 8,
+ kCWSecurityWPA2Enterprise = 9,
+ kCWSecurityEnterprise = 10,
+ kCWSecurityUnknown = NSIntegerMax,
+};
+
+typedef NSInteger CWSecurity;
+
+enum {
+ kBluetoothFeatureLESupportedController = (1 << 6L),
+};
+
+@protocol IOBluetoothDeviceInquiryDelegate
+- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
+- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
+ device:(IOBluetoothDevice*)device;
+- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
+ error:(IOReturn)error
+ aborted:(BOOL)aborted;
+@end
+
+@protocol NSWindowDelegateFullScreenAdditions
+- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
+- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
+@end
+
+enum {
+ CBPeripheralStateDisconnected = 0,
+ CBPeripheralStateConnecting,
+ CBPeripheralStateConnected,
+};
+typedef NSInteger CBPeripheralState;
+
+enum {
+ CBCentralManagerStateUnknown = 0,
+ CBCentralManagerStateResetting,
+ CBCentralManagerStateUnsupported,
+ CBCentralManagerStateUnauthorized,
+ CBCentralManagerStatePoweredOff,
+ CBCentralManagerStatePoweredOn,
+};
+typedef NSInteger CBCentralManagerState;
+
+@protocol CBCentralManagerDelegate;
+
+@protocol CBCentralManagerDelegate<NSObject>
+- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
+- (void)centralManager:(CBCentralManager*)central
+ didDiscoverPeripheral:(CBPeripheral*)peripheral
+ advertisementData:(NSDictionary*)advertisementData
+ RSSI:(NSNumber*)RSSI;
+@end
+
+#endif // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+enum { NSEventPhaseMayBegin = 0x1 << 5 };
+
+#endif // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+enum {
+ NSWindowOcclusionStateVisible = 1UL << 1,
+};
+typedef NSUInteger NSWindowOcclusionState;
+
+enum { NSWorkspaceLaunchWithErrorPresentation = 0x00000040 };
+
+#endif // MAC_OS_X_VERSION_10_9
+
+// ----------------------------------------------------------------------------
+// Define NSStrings only available in newer versions of the OSX SDK to force
+// them to be statically linked.
+// ----------------------------------------------------------------------------
+
+extern "C" {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+BASE_EXPORT extern NSString* const NSWindowWillEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowWillExitFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidExitFullScreenNotification;
+BASE_EXPORT extern NSString* const
+ NSWindowDidChangeBackingPropertiesNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataServiceDataKey;
+BASE_EXPORT extern NSString* const
+ NSPreferredScrollerStyleDidChangeNotification;
+#endif // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern NSString* const NSWindowDidChangeOcclusionStateNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataIsConnectable;
+#endif // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+BASE_EXPORT extern NSString* const NSUserActivityTypeBrowsingWeb;
+BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
+#endif // MAC_OS_X_VERSION_10_10
+} // extern "C"
+
+// ----------------------------------------------------------------------------
+// If compiling against an older version of the OSX SDK, declare functions that
+// are available in newer versions of the OSX SDK. If compiling against a newer
+// version of the OSX SDK, redeclare those same functions to suppress
+// -Wpartial-availability warnings.
+// ----------------------------------------------------------------------------
+
+// Once Chrome no longer supports OSX 10.6, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+
@interface NSEvent (LionSDK)
+ (BOOL)isSwipeTrackingFromScrollEventsEnabled;
-
- (NSEventPhase)momentumPhase;
- (NSEventPhase)phase;
- (BOOL)hasPreciseScrollingDeltas;
@@ -79,10 +286,8 @@ typedef NSUInteger NSWindowButton;
usingHandler:(void (^)(CGFloat gestureAmount,
NSEventPhase phase,
BOOL isComplete,
- BOOL *stop))trackingHandler;
-
+ BOOL* stop))trackingHandler;
- (BOOL)isDirectionInvertedFromDevice;
-
@end
@interface NSApplication (LionSDK)
@@ -105,6 +310,7 @@ typedef NSUInteger NSWindowButton;
- (void)setAnimationBehavior:(NSWindowAnimationBehavior)newAnimationBehavior;
- (void)toggleFullScreen:(id)sender;
- (void)setRestorable:(BOOL)flag;
+- (NSRect)convertRectFromScreen:(NSRect)aRect;
@end
@interface NSCursor (LionSDKDeclarations)
@@ -112,9 +318,9 @@ typedef NSUInteger NSWindowButton;
@end
@interface NSAnimationContext (LionSDK)
-+ (void)runAnimationGroup:(void (^)(NSAnimationContext *context))changes
++ (void)runAnimationGroup:(void (^)(NSAnimationContext* context))changes
completionHandler:(void (^)(void))completionHandler;
-@property(copy) void(^completionHandler)(void);
+@property(copy) void (^completionHandler)(void);
@end
@interface NSView (LionSDK)
@@ -138,37 +344,13 @@ typedef NSUInteger NSWindowButton;
- (BOOL)associateToNetwork:(CWNetwork*)network
password:(NSString*)password
error:(NSError**)error;
-- (NSSet*)scanForNetworksWithName:(NSString*)networkName
- error:(NSError**)error;
+- (NSSet*)scanForNetworksWithName:(NSString*)networkName error:(NSError**)error;
@end
-enum CWChannelBand {
- kCWChannelBandUnknown = 0,
- kCWChannelBand2GHz = 1,
- kCWChannelBand5GHz = 2,
-};
-
-@interface CWChannel : NSObject
+@interface CWChannel (LionSDK)
@property(readonly) CWChannelBand channelBand;
@end
-enum {
- kCWSecurityNone = 0,
- kCWSecurityWEP = 1,
- kCWSecurityWPAPersonal = 2,
- kCWSecurityWPAPersonalMixed = 3,
- kCWSecurityWPA2Personal = 4,
- kCWSecurityPersonal = 5,
- kCWSecurityDynamicWEP = 6,
- kCWSecurityWPAEnterprise = 7,
- kCWSecurityWPAEnterpriseMixed = 8,
- kCWSecurityWPA2Enterprise = 9,
- kCWSecurityEnterprise = 10,
- kCWSecurityUnknown = NSIntegerMax,
-};
-
-typedef NSInteger CWSecurity;
-
@interface CWNetwork (LionSDK)
@property(readonly) CWChannel* wlanChannel;
@property(readonly) NSInteger rssiValue;
@@ -180,19 +362,6 @@ typedef NSInteger CWSecurity;
- (BluetoothHCIPowerState)powerState;
@end
-enum {
- kBluetoothFeatureLESupportedController = (1 << 6L),
-};
-
-@protocol IOBluetoothDeviceInquiryDelegate
-- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
-- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
- device:(IOBluetoothDevice*)device;
-- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
- error:(IOReturn)error
- aborted:(BOOL)aborted;
-@end
-
@interface IOBluetoothL2CAPChannel (LionSDK)
@property(readonly) BluetoothL2CAPMTU outgoingMTU;
@end
@@ -206,63 +375,75 @@ enum {
- (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids;
@end
-BASE_EXPORT extern "C" NSString* const NSWindowWillEnterFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowWillExitFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowDidEnterFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const NSWindowDidExitFullScreenNotification;
-BASE_EXPORT extern "C" NSString* const
- NSWindowDidChangeBackingPropertiesNotification;
+@interface CBPeripheral (LionSDK)
+@property(readonly, nonatomic) CFUUIDRef UUID;
+@property(retain, readonly) NSString* name;
+@property(readonly) BOOL isConnected;
+@end
-@protocol NSWindowDelegateFullScreenAdditions
-- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
-- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
+@interface CBCentralManager (LionSDK)
+@property(readonly) CBCentralManagerState state;
+- (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate
+ queue:(dispatch_queue_t)queue;
+- (void)scanForPeripheralsWithServices:(NSArray*)serviceUUIDs
+ options:(NSDictionary*)options;
+- (void)stopScan;
+@end
+
+@interface CBUUID (LionSDK)
+@property(nonatomic, readonly) NSData* data;
++ (CBUUID*)UUIDWithString:(NSString*)theString;
@end
#endif // MAC_OS_X_VERSION_10_7
+// Once Chrome no longer supports OSX 10.7, everything within this preprocessor
+// block can be removed.
#if !defined(MAC_OS_X_VERSION_10_8) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
-
-enum {
- NSEventPhaseMayBegin = 0x1 << 5
-};
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
@interface NSColor (MountainLionSDK)
- (CGColorRef)CGColor;
@end
-#endif // MAC_OS_X_VERSION_10_8
+@interface NSUUID (MountainLionSDK)
+- (NSString*)UUIDString;
+@end
+@interface NSControl (MountainLionSDK)
+@property BOOL allowsExpansionToolTips;
+@end
-#if !defined(MAC_OS_X_VERSION_10_9) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+#endif // MAC_OS_X_VERSION_10_8
-// NSProgress is public API in 10.9, but a version of it exists and is usable
-// in 10.8.
+// Once Chrome no longer supports OSX 10.8, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
-@interface NSProgress : NSObject
+@interface NSProgress (MavericksSDK)
- (instancetype)initWithParent:(NSProgress*)parentProgressOrNil
userInfo:(NSDictionary*)userInfoOrNil;
-@property (copy) NSString* kind;
+@property(copy) NSString* kind;
@property int64_t totalUnitCount;
@property int64_t completedUnitCount;
-@property (getter=isCancellable) BOOL cancellable;
-@property (getter=isPausable) BOOL pausable;
-@property (readonly, getter=isCancelled) BOOL cancelled;
-@property (readonly, getter=isPaused) BOOL paused;
-@property (copy) void (^cancellationHandler)(void);
-@property (copy) void (^pausingHandler)(void);
+@property(getter=isCancellable) BOOL cancellable;
+@property(getter=isPausable) BOOL pausable;
+@property(readonly, getter=isCancelled) BOOL cancelled;
+@property(readonly, getter=isPaused) BOOL paused;
+@property(copy) void (^cancellationHandler)(void);
+@property(copy) void (^pausingHandler)(void);
- (void)cancel;
- (void)pause;
- (void)setUserInfoObject:(id)objectOrNil forKey:(NSString*)key;
- (NSDictionary*)userInfo;
-@property (readonly, getter=isIndeterminate) BOOL indeterminate;
-@property (readonly) double fractionCompleted;
+@property(readonly, getter=isIndeterminate) BOOL indeterminate;
+@property(readonly) double fractionCompleted;
- (void)publish;
- (void)unpublish;
@@ -273,73 +454,84 @@ enum {
+ (BOOL)screensHaveSeparateSpaces;
@end
-// NSAppearance is a new class in the 10.9 SDK. New classes cannot be
-// forward-declared because they also require an @implementation, which would
-// produce conflicting linkage. Instead, just declare the necessary pieces of
-// the interface as a protocol, and treat objects of this type as id.
-@protocol CrNSAppearance<NSObject>
-+ (id<NSObject>)appearanceNamed:(NSString*)name;
-@end
-
@interface NSView (MavericksSDK)
- (void)setCanDrawSubviewsIntoLayer:(BOOL)flag;
-- (id<CrNSAppearance>)effectiveAppearance;
+- (NSAppearance*)effectiveAppearance;
@end
-enum {
- NSWindowOcclusionStateVisible = 1UL << 1,
-};
-typedef NSUInteger NSWindowOcclusionState;
-
@interface NSWindow (MavericksSDK)
- (NSWindowOcclusionState)occlusionState;
@end
-
-BASE_EXPORT extern "C" NSString* const
- NSWindowDidChangeOcclusionStateNotification;
-
-enum {
- NSWorkspaceLaunchWithErrorPresentation = 0x00000040
-};
-
-#else // !MAC_OS_X_VERSION_10_9
-
-typedef enum {
- kCWSecurityModeOpen = 0,
- kCWSecurityModeWEP,
- kCWSecurityModeWPA_PSK,
- kCWSecurityModeWPA2_PSK,
- kCWSecurityModeWPA_Enterprise,
- kCWSecurityModeWPA2_Enterprise,
- kCWSecurityModeWPS,
- kCWSecurityModeDynamicWEP
-} CWSecurityMode;
-
-@interface CWNetwork (SnowLeopardSDK)
-@property(readonly) NSNumber* rssi;
-@property(readonly) NSNumber* securityMode;
+@interface NSAppearance (MavericksSDK)
++ (id<NSObject>)appearanceNamed:(NSString*)name;
@end
-BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
+@interface CBPeripheral (MavericksSDK)
+@property(readonly, nonatomic) NSUUID* identifier;
+@end
#endif // MAC_OS_X_VERSION_10_9
+// Once Chrome no longer supports OSX 10.9, everything within this preprocessor
+// block can be removed.
#if !defined(MAC_OS_X_VERSION_10_10) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
-@interface NSUserActivity : NSObject
+@interface NSUserActivity (YosemiteSDK)
-@property (readonly, copy) NSString* activityType;
-@property (copy) NSDictionary* userInfo;
-@property (copy) NSURL* webPageURL;
+@property(readonly, copy) NSString* activityType;
+@property(copy) NSDictionary* userInfo;
+@property(copy) NSURL* webpageURL;
-@end
+- (instancetype)initWithActivityType:(NSString*)activityType;
+- (void)becomeCurrent;
+- (void)invalidate;
-BASE_EXPORT extern "C" NSString* const NSUserActivityTypeBrowsingWeb;
+@end
-BASE_EXPORT extern "C" NSString* const NSAppearanceNameVibrantDark;
+@interface CBUUID (YosemiteSDK)
+- (NSString*)UUIDString;
+@end
#endif // MAC_OS_X_VERSION_10_10
+// ----------------------------------------------------------------------------
+// Chrome uses -[CWNetwork securityMode] and -[CWNetwork rssi] on OSX 10.6. The
+// former method relies on the enum CWSecurityMode which was removed in the OSX
+// 10.9 SDK. In order for Chrome to compile against an OSX 10.9+ SDK, Chrome
+// must define this enum. Chrome must also declare these methods.
+//
+// These declarations and definitions will not be necessary once Chrome no
+// longer runs on OSX 10.6.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6
+typedef enum {
+ kCWSecurityModeOpen = 0,
+ kCWSecurityModeWEP,
+ kCWSecurityModeWPA_PSK,
+ kCWSecurityModeWPA2_PSK,
+ kCWSecurityModeWPA_Enterprise,
+ kCWSecurityModeWPA2_Enterprise,
+ kCWSecurityModeWPS,
+ kCWSecurityModeDynamicWEP
+} CWSecurityMode;
+
+@interface CWNetwork (SnowLeopardSDK)
+@property(readonly) NSNumber* rssi;
+@property(readonly) NSNumber* securityMode;
+@end
+#endif
+
+// ----------------------------------------------------------------------------
+// The symbol for kCWSSIDDidChangeNotification is available in the
+// CoreWLAN.framework for OSX versions 10.6 through 10.10. The symbol is not
+// declared in the OSX 10.9+ SDK, so when compiling against an OSX 10.9+ SDK,
+// declare the symbol.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
+#endif
#endif // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
diff --git a/chromium/base/mac/sdk_forward_declarations.mm b/chromium/base/mac/sdk_forward_declarations.mm
index 7a5703228f1..2e4b2d98457 100644
--- a/chromium/base/mac/sdk_forward_declarations.mm
+++ b/chromium/base/mac/sdk_forward_declarations.mm
@@ -4,10 +4,8 @@
#include "base/mac/sdk_forward_declarations.h"
-// Replicate specific 10.7 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
NSString* const NSWindowWillEnterFullScreenNotification =
@"NSWindowWillEnterFullScreenNotification";
@@ -23,24 +21,24 @@ NSString* const NSWindowDidExitFullScreenNotification =
NSString* const NSWindowDidChangeBackingPropertiesNotification =
@"NSWindowDidChangeBackingPropertiesNotification";
+NSString* const CBAdvertisementDataServiceDataKey = @"kCBAdvDataServiceData";
+
+NSString* const NSPreferredScrollerStyleDidChangeNotification =
+ @"NSPreferredScrollerStyleDidChangeNotification";
#endif // MAC_OS_X_VERSION_10_7
-// Replicate specific 10.9 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_9) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
-
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
NSString* const NSWindowDidChangeOcclusionStateNotification =
@"NSWindowDidChangeOcclusionStateNotification";
+NSString* const CBAdvertisementDataIsConnectable = @"kCBAdvDataIsConnectable";
#endif // MAC_OS_X_VERSION_10_9
-// Replicate specific 10.10 SDK declarations for building with prior SDKs.
#if !defined(MAC_OS_X_VERSION_10_10) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
-
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
NSString* const NSUserActivityTypeBrowsingWeb =
@"NSUserActivityTypeBrowsingWeb";
NSString* const NSAppearanceNameVibrantDark = @"NSAppearanceNameVibrantDark";
-
#endif // MAC_OS_X_VERSION_10_10
diff --git a/chromium/base/macros.h b/chromium/base/macros.h
index b6240da2bee..d9043281cf5 100644
--- a/chromium/base/macros.h
+++ b/chromium/base/macros.h
@@ -13,8 +13,6 @@
#include <stddef.h> // For size_t.
#include <string.h> // For memcpy.
-#include "base/compiler_specific.h" // For ALLOW_UNUSED.
-
// Put this in the private: declarations for a class to be uncopyable.
#define DISALLOW_COPY(TypeName) \
TypeName(const TypeName&)
@@ -54,17 +52,7 @@
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-
-// That gcc wants both of these prototypes seems mysterious. VC, for
-// its part, can't decide which to use (another mystery). Matching of
-// template overloads: the final frontier.
-#ifndef _MSC_VER
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-#endif
-
+template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
diff --git a/chromium/base/md5.cc b/chromium/base/md5.cc
index 6227ee66042..72c774d3554 100644
--- a/chromium/base/md5.cc
+++ b/chromium/base/md5.cc
@@ -23,27 +23,28 @@
#include "base/md5.h"
-#include "base/basictypes.h"
+#include <stddef.h>
namespace {
struct Context {
- uint32 buf[4];
- uint32 bits[2];
- unsigned char in[64];
+ uint32_t buf[4];
+ uint32_t bits[2];
+ uint8_t in[64];
};
/*
* Note: this code is harmless on little-endian machines.
*/
-void byteReverse(unsigned char *buf, unsigned longs) {
- uint32 t;
- do {
- t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
- ((unsigned)buf[1]<<8 | buf[0]);
- *(uint32 *)buf = t;
- buf += 4;
- } while (--longs);
+void byteReverse(uint8_t* buf, unsigned longs) {
+ do {
+ uint32_t temp = static_cast<uint32_t>(
+ static_cast<unsigned>(buf[3]) << 8 |
+ buf[2]) << 16 |
+ (static_cast<unsigned>(buf[1]) << 8 | buf[0]);
+ *reinterpret_cast<uint32_t*>(buf) = temp;
+ buf += 4;
+ } while (--longs);
}
/* The four core functions - F1 is optimized somewhat */
@@ -56,93 +57,93 @@ void byteReverse(unsigned char *buf, unsigned longs) {
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+ (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
-void MD5Transform(uint32 buf[4], const uint32 in[16]) {
- register uint32 a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
+void MD5Transform(uint32_t buf[4], const uint32_t in[16]) {
+ uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
}
} // namespace
@@ -154,13 +155,13 @@ namespace base {
* initialization constants.
*/
void MD5Init(MD5Context* context) {
- struct Context *ctx = (struct Context *)context;
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
+ struct Context* ctx = reinterpret_cast<struct Context*>(context);
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
}
/*
@@ -168,51 +169,49 @@ void MD5Init(MD5Context* context) {
* of bytes.
*/
void MD5Update(MD5Context* context, const StringPiece& data) {
- const unsigned char* inbuf = (const unsigned char*)data.data();
- size_t len = data.size();
- struct Context *ctx = (struct Context *)context;
- const unsigned char* buf = (const unsigned char*)inbuf;
- uint32 t;
-
- /* Update bitcount */
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
- ctx->bits[1]++; /* Carry from low to high */
- ctx->bits[1] += static_cast<uint32>(len >> 29);
-
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
-
- /* Handle any leading odd-sized chunks */
-
- if (t) {
- unsigned char *p = (unsigned char *)ctx->in + t;
-
- t = 64-t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
- buf += t;
- len -= t;
- }
-
- /* Process data in 64-byte chunks */
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
- buf += 64;
- len -= 64;
- }
-
- /* Handle any remaining bytes of data. */
-
- memcpy(ctx->in, buf, len);
+ struct Context* ctx = reinterpret_cast<struct Context*>(context);
+ const uint8_t* buf = reinterpret_cast<const uint8_t*>(data.data());
+ size_t len = data.size();
+
+ /* Update bitcount */
+
+ uint32_t t = ctx->bits[0];
+ if ((ctx->bits[0] = t + (static_cast<uint32_t>(len) << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += static_cast<uint32_t>(len >> 29);
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ uint8_t* p = static_cast<uint8_t*>(ctx->in + t);
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
}
/*
@@ -220,48 +219,46 @@ void MD5Update(MD5Context* context, const StringPiece& data) {
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(MD5Digest* digest, MD5Context* context) {
- struct Context *ctx = (struct Context *)context;
- unsigned count;
- unsigned char *p;
-
- /* Compute number of bytes mod 64 */
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- p = ctx->in + count;
- *p++ = 0x80;
-
- /* Bytes of padding needed to make 64 bytes */
- count = 64 - 1 - count;
-
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
-
- /* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
- } else {
- /* Pad block to 56 bytes */
- memset(p, 0, count-8);
- }
- byteReverse(ctx->in, 14);
-
- /* Append length in bits and transform */
- memcpy(&ctx->in[14 * sizeof(ctx->bits[0])],
- &ctx->bits[0],
- sizeof(ctx->bits[0]));
- memcpy(&ctx->in[15 * sizeof(ctx->bits[1])],
- &ctx->bits[1],
- sizeof(ctx->bits[1]));
-
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
- byteReverse((unsigned char *)ctx->buf, 4);
- memcpy(digest->a, ctx->buf, 16);
- memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+ struct Context* ctx = reinterpret_cast<struct Context*>(context);
+ unsigned count;
+ uint8_t* p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ memcpy(&ctx->in[14 * sizeof(ctx->bits[0])], &ctx->bits[0],
+ sizeof(ctx->bits[0]));
+ memcpy(&ctx->in[15 * sizeof(ctx->bits[1])], &ctx->bits[1],
+ sizeof(ctx->bits[1]));
+
+ MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+ byteReverse(reinterpret_cast<uint8_t*>(ctx->buf), 4);
+ memcpy(digest->a, ctx->buf, 16);
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
void MD5IntermediateFinal(MD5Digest* digest, const MD5Context* context) {
@@ -278,11 +275,10 @@ std::string MD5DigestToBase16(const MD5Digest& digest) {
std::string ret;
ret.resize(32);
- int j = 0;
- for (int i = 0; i < 16; i ++) {
- int a = digest.a[i];
- ret[j++] = zEncode[(a>>4)&0xf];
- ret[j++] = zEncode[a & 0xf];
+ for (int i = 0, j = 0; i < 16; i++, j += 2) {
+ uint8_t a = digest.a[i];
+ ret[j] = zEncode[(a >> 4) & 0xf];
+ ret[j + 1] = zEncode[a & 0xf];
}
return ret;
}
@@ -290,8 +286,7 @@ std::string MD5DigestToBase16(const MD5Digest& digest) {
void MD5Sum(const void* data, size_t length, MD5Digest* digest) {
MD5Context ctx;
MD5Init(&ctx);
- MD5Update(&ctx,
- StringPiece(reinterpret_cast<const char*>(data), length));
+ MD5Update(&ctx, StringPiece(reinterpret_cast<const char*>(data), length));
MD5Final(digest, &ctx);
}
diff --git a/chromium/base/md5.h b/chromium/base/md5.h
index 0a87fcf7c4a..0b4cbcef3a8 100644
--- a/chromium/base/md5.h
+++ b/chromium/base/md5.h
@@ -5,6 +5,8 @@
#ifndef BASE_MD5_H_
#define BASE_MD5_H_
+#include <stdint.h>
+
#include "base/base_export.h"
#include "base/strings/string_piece.h"
@@ -35,17 +37,13 @@ namespace base {
// The output of an MD5 operation.
struct MD5Digest {
- unsigned char a[16];
+ uint8_t a[16];
};
// Used for storing intermediate data during an MD5 computation. Callers
// should not access the data.
typedef char MD5Context[88];
-// Computes the MD5 sum of the given data buffer with the given length.
-// The given 'digest' structure will be filled with the result data.
-BASE_EXPORT void MD5Sum(const void* data, size_t length, MD5Digest* digest);
-
// Initializes the given MD5 context structure for subsequent calls to
// MD5Update().
BASE_EXPORT void MD5Init(MD5Context* context);
@@ -67,6 +65,10 @@ BASE_EXPORT void MD5IntermediateFinal(MD5Digest* digest,
// Converts a digest into human-readable hexadecimal.
BASE_EXPORT std::string MD5DigestToBase16(const MD5Digest& digest);
+// Computes the MD5 sum of the given data buffer with the given length.
+// The given 'digest' structure will be filled with the result data.
+BASE_EXPORT void MD5Sum(const void* data, size_t length, MD5Digest* digest);
+
// Returns the MD5 (in hexadecimal) of a string.
BASE_EXPORT std::string MD5String(const StringPiece& str);
diff --git a/chromium/base/md5_unittest.cc b/chromium/base/md5_unittest.cc
index 8d817e9a8e0..08c99f19049 100644
--- a/chromium/base/md5_unittest.cc
+++ b/chromium/base/md5_unittest.cc
@@ -246,7 +246,7 @@ TEST(MD5, IntermediateFinal) {
EXPECT_TRUE(!memcmp(&header_digest, &check_header_digest,
sizeof(header_digest)));
EXPECT_TRUE(!memcmp(&digest, &check_full_digest, sizeof(digest)));
- EXPECT_FALSE(!memcmp(&digest, &header_digest, sizeof(digest)));
+ EXPECT_TRUE(memcmp(&digest, &header_digest, sizeof(digest)));
}
} // namespace base
diff --git a/chromium/base/memory/BUILD.gn b/chromium/base/memory/BUILD.gn
new file mode 100644
index 00000000000..bd864caa245
--- /dev/null
+++ b/chromium/base/memory/BUILD.gn
@@ -0,0 +1,58 @@
+# Copyright (c) 2015 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.
+
+source_set("memory") {
+ sources = [
+ "aligned_memory.cc",
+ "aligned_memory.h",
+ "discardable_memory.cc",
+ "discardable_memory.h",
+ "discardable_memory_allocator.cc",
+ "discardable_memory_allocator.h",
+ "discardable_shared_memory.cc",
+ "discardable_shared_memory.h",
+ "linked_ptr.h",
+ "manual_constructor.h",
+ "memory_pressure_listener.cc",
+ "memory_pressure_listener.h",
+ "memory_pressure_monitor.cc",
+ "memory_pressure_monitor.h",
+ "raw_scoped_refptr_mismatch_checker.h",
+ "ref_counted.cc",
+ "ref_counted.h",
+ "ref_counted_delete_on_message_loop.h",
+ "ref_counted_memory.cc",
+ "ref_counted_memory.h",
+ "scoped_policy.h",
+ "scoped_ptr.h",
+ "scoped_vector.h",
+ "shared_memory.h",
+ "shared_memory_android.cc",
+ "shared_memory_nacl.cc",
+ "shared_memory_posix.cc",
+ "shared_memory_win.cc",
+ "singleton.cc",
+ "singleton.h",
+ "weak_ptr.cc",
+ "weak_ptr.h",
+ ]
+
+ if (is_nacl) {
+ sources -= [
+ "discardable_memory.cc",
+ "discardable_memory.h",
+ "discardable_memory_allocator.cc",
+ "discardable_memory_allocator.h",
+ "discardable_shared_memory.cc",
+ "discardable_shared_memory.h",
+ "shared_memory_posix.cc",
+ ]
+ } else {
+ sources -= [ "shared_memory_nacl.cc" ]
+ }
+
+ configs += [ "//base:base_implementation" ]
+
+ visibility = [ "//base/*" ]
+}
diff --git a/chromium/base/memory/discardable_memory.cc b/chromium/base/memory/discardable_memory.cc
index 3d82f91d78f..d50f1853e19 100644
--- a/chromium/base/memory/discardable_memory.cc
+++ b/chromium/base/memory/discardable_memory.cc
@@ -4,83 +4,12 @@
#include "base/memory/discardable_memory.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-
namespace base {
-namespace {
-
-const struct TypeNamePair {
- DiscardableMemoryType type;
- const char* name;
-} kTypeNamePairs[] = {
- { DISCARDABLE_MEMORY_TYPE_ASHMEM, "ashmem" },
- { DISCARDABLE_MEMORY_TYPE_MACH, "mach" },
- { DISCARDABLE_MEMORY_TYPE_EMULATED, "emulated" },
- { DISCARDABLE_MEMORY_TYPE_SHMEM, "shmem" }
-};
-
-DiscardableMemoryType g_preferred_type = DISCARDABLE_MEMORY_TYPE_NONE;
-
-struct DefaultPreferredType {
- DefaultPreferredType() : value(DISCARDABLE_MEMORY_TYPE_NONE) {
- std::vector<DiscardableMemoryType> supported_types;
- DiscardableMemory::GetSupportedTypes(&supported_types);
- DCHECK(!supported_types.empty());
- value = supported_types[0];
- }
- DiscardableMemoryType value;
-};
-LazyInstance<DefaultPreferredType>::Leaky g_default_preferred_type =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-// static
-DiscardableMemoryType DiscardableMemory::GetNamedType(
- const std::string& name) {
- for (size_t i = 0; i < arraysize(kTypeNamePairs); ++i) {
- if (name == kTypeNamePairs[i].name)
- return kTypeNamePairs[i].type;
- }
-
- return DISCARDABLE_MEMORY_TYPE_NONE;
-}
-
-// static
-const char* DiscardableMemory::GetTypeName(DiscardableMemoryType type) {
- for (size_t i = 0; i < arraysize(kTypeNamePairs); ++i) {
- if (type == kTypeNamePairs[i].type)
- return kTypeNamePairs[i].name;
- }
-
- return "unknown";
-}
-
-// static
-void DiscardableMemory::SetPreferredType(DiscardableMemoryType type) {
- // NONE is a reserved value and not a valid default type.
- DCHECK_NE(DISCARDABLE_MEMORY_TYPE_NONE, type);
-
- // Make sure this function is only called once before the first call
- // to GetPreferredType().
- DCHECK_EQ(DISCARDABLE_MEMORY_TYPE_NONE, g_preferred_type);
-
- g_preferred_type = type;
-}
-
-// static
-DiscardableMemoryType DiscardableMemory::GetPreferredType() {
- if (g_preferred_type == DISCARDABLE_MEMORY_TYPE_NONE)
- g_preferred_type = g_default_preferred_type.Get().value;
- return g_preferred_type;
+DiscardableMemory::DiscardableMemory() {
}
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
- size_t size) {
- return CreateLockedMemoryWithType(GetPreferredType(), size);
+DiscardableMemory::~DiscardableMemory() {
}
} // namespace base
diff --git a/chromium/base/memory/discardable_memory.h b/chromium/base/memory/discardable_memory.h
index d8b7a58fbbb..fc189e74634 100644
--- a/chromium/base/memory/discardable_memory.h
+++ b/chromium/base/memory/discardable_memory.h
@@ -5,40 +5,24 @@
#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_H_
#define BASE_MEMORY_DISCARDABLE_MEMORY_H_
-#include <string>
-#include <vector>
-
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
namespace base {
-enum DiscardableMemoryType {
- DISCARDABLE_MEMORY_TYPE_NONE,
- DISCARDABLE_MEMORY_TYPE_ASHMEM,
- DISCARDABLE_MEMORY_TYPE_MACH,
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
-};
-
-enum DiscardableMemoryLockStatus {
- DISCARDABLE_MEMORY_LOCK_STATUS_FAILED,
- DISCARDABLE_MEMORY_LOCK_STATUS_PURGED,
- DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS
-};
-
-// Platform abstraction for discardable memory. DiscardableMemory is used to
-// cache large objects without worrying about blowing out memory, both on mobile
-// devices where there is no swap, and desktop devices where unused free memory
-// should be used to help the user experience. This is preferable to releasing
-// memory in response to an OOM signal because it is simpler, though it has less
-// flexibility as to which objects get discarded.
+// Discardable memory is used to cache large objects without worrying about
+// blowing out memory, both on mobile devices where there is no swap, and
+// desktop devices where unused free memory should be used to help the user
+// experience. This is preferable to releasing memory in response to an OOM
+// signal because it is simpler and provides system-wide management of
+// purgable memory, though it has less flexibility as to which objects get
+// discarded.
//
// Discardable memory has two states: locked and unlocked. While the memory is
-// locked, it will not be discarded. Unlocking the memory allows the OS to
-// reclaim it if needed. Locks do not nest.
+// locked, it will not be discarded. Unlocking the memory allows the
+// discardable memory system and the OS to reclaim it if needed. Locks do not
+// nest.
//
// Notes:
// - The paging behavior of memory while it is locked is not specified. While
@@ -53,77 +37,28 @@ enum DiscardableMemoryLockStatus {
// responsibility of users of discardable memory to ensure there are no
// races.
//
-// References:
-// - Linux: http://lwn.net/Articles/452035/
-// - Mac: http://trac.webkit.org/browser/trunk/Source/WebCore/platform/mac/PurgeableBufferMac.cpp
-// the comment starting with "vm_object_purgable_control" at
-// http://www.opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/vm/vm_object.c
-//
-// Thread-safety: DiscardableMemory instances are not thread-safe.
class BASE_EXPORT DiscardableMemory {
public:
- virtual ~DiscardableMemory() {}
-
- // Gets the discardable memory type with a given name.
- static DiscardableMemoryType GetNamedType(const std::string& name);
-
- // Gets the name of a discardable memory type.
- static const char* GetTypeName(DiscardableMemoryType type);
-
- // Gets system supported discardable memory types. Default preferred type
- // at the front of vector.
- static void GetSupportedTypes(std::vector<DiscardableMemoryType>* types);
-
- // Sets the preferred discardable memory type. This overrides the default
- // preferred type. Can only be called once prior to GetPreferredType()
- // or CreateLockedMemory(). Caller is responsible for correct ordering.
- static void SetPreferredType(DiscardableMemoryType type);
-
- // Gets the preferred discardable memory type.
- static DiscardableMemoryType GetPreferredType();
-
- // Create a DiscardableMemory instance with specified |type| and |size|.
- static scoped_ptr<DiscardableMemory> CreateLockedMemoryWithType(
- DiscardableMemoryType type, size_t size);
-
- // Create a DiscardableMemory instance with preferred type and |size|.
- static scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size);
-
- // Discardable memory implementations might use this to release memory
- // or resources assigned to instances that have been purged.
- static void ReleaseFreeMemory();
-
- // Discardable memory implementations might allow an elevated usage level
- // while in frequent use. Call this to have the usage reduced to the base
- // level. Returns true if there's no need to call this again until
- // memory instances have been used. This indicates that all discardable
- // memory implementations have reduced usage to the base level or below.
- // Note: calling this too often or while discardable memory is in frequent
- // use can hurt performance, whereas calling it too infrequently can result
- // in memory bloat.
- static bool ReduceMemoryUsage();
+ DiscardableMemory();
+ virtual ~DiscardableMemory();
// Locks the memory so that it will not be purged by the system. Returns
- // DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS on success. If the return value is
- // DISCARDABLE_MEMORY_LOCK_STATUS_FAILED then this object should be
- // discarded and a new one should be created. If the return value is
- // DISCARDABLE_MEMORY_LOCK_STATUS_PURGED then the memory is present but any
- // data that was in it is gone.
- virtual DiscardableMemoryLockStatus Lock() WARN_UNUSED_RESULT = 0;
+ // true on success. If the return value is false then this object should be
+ // discarded and a new one should be created.
+ virtual bool Lock() WARN_UNUSED_RESULT = 0;
// Unlocks the memory so that it can be purged by the system. Must be called
// after every successful lock call.
virtual void Unlock() = 0;
// Returns the memory address held by this object. The object must be locked
- // before calling this. Otherwise, this will cause a DCHECK error.
- virtual void* Memory() const = 0;
-
- // Testing utility calls.
+ // before calling this.
+ virtual void* data() const = 0;
- // Purge all discardable memory in the system. This call has global effects
- // across all running processes, so it should only be used for testing!
- static void PurgeForTesting();
+ // Handy method to simplify calling data() with a reinterpret_cast.
+ template<typename T> T* data_as() const {
+ return reinterpret_cast<T*>(data());
+ }
};
} // namespace base
diff --git a/chromium/base/memory/discardable_memory_allocator.cc b/chromium/base/memory/discardable_memory_allocator.cc
new file mode 100644
index 00000000000..002a3ba5e47
--- /dev/null
+++ b/chromium/base/memory/discardable_memory_allocator.cc
@@ -0,0 +1,34 @@
+// Copyright 2015 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/memory/discardable_memory_allocator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+DiscardableMemoryAllocator* g_allocator = nullptr;
+
+} // namespace
+
+// static
+void DiscardableMemoryAllocator::SetInstance(
+ DiscardableMemoryAllocator* allocator) {
+ DCHECK(allocator);
+
+ // Make sure this function is only called once before the first call
+ // to GetInstance().
+ DCHECK(!g_allocator);
+
+ g_allocator = allocator;
+}
+
+// static
+DiscardableMemoryAllocator* DiscardableMemoryAllocator::GetInstance() {
+ DCHECK(g_allocator);
+ return g_allocator;
+}
+
+} // namespace base
diff --git a/chromium/base/memory/discardable_memory_allocator.h b/chromium/base/memory/discardable_memory_allocator.h
new file mode 100644
index 00000000000..400f87aeee0
--- /dev/null
+++ b/chromium/base/memory/discardable_memory_allocator.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DiscardableMemory;
+
+class BASE_EXPORT DiscardableMemoryAllocator {
+ public:
+ // Returns the allocator instance.
+ static DiscardableMemoryAllocator* GetInstance();
+
+ // Sets the allocator instance. Can only be called once, e.g. on startup.
+ // Ownership of |instance| remains with the caller.
+ static void SetInstance(DiscardableMemoryAllocator* allocator);
+
+ virtual scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+ size_t size) = 0;
+
+ protected:
+ virtual ~DiscardableMemoryAllocator() {}
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/chromium/base/memory/discardable_memory_android.cc b/chromium/base/memory/discardable_memory_android.cc
deleted file mode 100644
index de7112457de..00000000000
--- a/chromium/base/memory/discardable_memory_android.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2013 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/memory/discardable_memory.h"
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/discardable_memory_ashmem.h"
-#include "base/memory/discardable_memory_ashmem_allocator.h"
-#include "base/memory/discardable_memory_emulated.h"
-#include "base/memory/discardable_memory_shmem.h"
-#include "base/sys_info.h"
-
-namespace base {
-namespace {
-
-const char kAshmemAllocatorName[] = "DiscardableMemoryAshmemAllocator";
-
-// For Ashmem, have the DiscardableMemoryManager trigger userspace eviction
-// when address space usage gets too high (e.g. 512 MBytes).
-const size_t kAshmemMemoryLimit = 512 * 1024 * 1024;
-
-size_t GetOptimalAshmemRegionSizeForAllocator() {
- // Note that this may do some I/O (without hitting the disk though) so it
- // should not be called on the critical path.
- return base::SysInfo::AmountOfPhysicalMemory() / 8;
-}
-
-// Holds the shared state used for allocations.
-struct SharedState {
- SharedState()
- : manager(kAshmemMemoryLimit, kAshmemMemoryLimit, TimeDelta::Max()),
- allocator(kAshmemAllocatorName,
- GetOptimalAshmemRegionSizeForAllocator()) {}
-
- internal::DiscardableMemoryManager manager;
- internal::DiscardableMemoryAshmemAllocator allocator;
-};
-LazyInstance<SharedState>::Leaky g_shared_state = LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-// static
-void DiscardableMemory::ReleaseFreeMemory() {
- internal::DiscardableMemoryShmem::ReleaseFreeMemory();
-}
-
-// static
-bool DiscardableMemory::ReduceMemoryUsage() {
- return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
-}
-
-// static
-void DiscardableMemory::GetSupportedTypes(
- std::vector<DiscardableMemoryType>* types) {
- const DiscardableMemoryType supported_types[] = {
- DISCARDABLE_MEMORY_TYPE_ASHMEM,
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
- };
- types->assign(supported_types, supported_types + arraysize(supported_types));
-}
-
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
- DiscardableMemoryType type, size_t size) {
- switch (type) {
- case DISCARDABLE_MEMORY_TYPE_ASHMEM: {
- SharedState* const shared_state = g_shared_state.Pointer();
- scoped_ptr<internal::DiscardableMemoryAshmem> memory(
- new internal::DiscardableMemoryAshmem(
- size, &shared_state->allocator, &shared_state->manager));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_EMULATED: {
- scoped_ptr<internal::DiscardableMemoryEmulated> memory(
- new internal::DiscardableMemoryEmulated(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_SHMEM: {
- scoped_ptr<internal::DiscardableMemoryShmem> memory(
- new internal::DiscardableMemoryShmem(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_NONE:
- case DISCARDABLE_MEMORY_TYPE_MACH:
- NOTREACHED();
- return nullptr;
- }
-
- NOTREACHED();
- return nullptr;
-}
-
-// static
-void DiscardableMemory::PurgeForTesting() {
- g_shared_state.Pointer()->manager.PurgeAll();
- internal::DiscardableMemoryEmulated::PurgeForTesting();
- internal::DiscardableMemoryShmem::PurgeForTesting();
-}
-
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_ashmem.cc b/chromium/base/memory/discardable_memory_ashmem.cc
deleted file mode 100644
index df0697c9ae9..00000000000
--- a/chromium/base/memory/discardable_memory_ashmem.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_ashmem.h"
-
-#include "base/memory/discardable_memory_ashmem_allocator.h"
-
-namespace base {
-namespace internal {
-
-DiscardableMemoryAshmem::DiscardableMemoryAshmem(
- size_t bytes,
- DiscardableMemoryAshmemAllocator* allocator,
- DiscardableMemoryManager* manager)
- : bytes_(bytes),
- allocator_(allocator),
- manager_(manager),
- is_locked_(false) {
- manager_->Register(this, bytes_);
-}
-
-DiscardableMemoryAshmem::~DiscardableMemoryAshmem() {
- if (is_locked_)
- Unlock();
-
- manager_->Unregister(this);
-}
-
-bool DiscardableMemoryAshmem::Initialize() {
- return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-}
-
-DiscardableMemoryLockStatus DiscardableMemoryAshmem::Lock() {
- DCHECK(!is_locked_);
-
- bool purged = false;
- if (!manager_->AcquireLock(this, &purged))
- return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-
- is_locked_ = true;
- return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
- : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
-}
-
-void DiscardableMemoryAshmem::Unlock() {
- DCHECK(is_locked_);
- manager_->ReleaseLock(this);
- is_locked_ = false;
-}
-
-void* DiscardableMemoryAshmem::Memory() const {
- DCHECK(is_locked_);
- DCHECK(ashmem_chunk_);
- return ashmem_chunk_->Memory();
-}
-
-bool DiscardableMemoryAshmem::AllocateAndAcquireLock() {
- if (ashmem_chunk_)
- return ashmem_chunk_->Lock();
-
- ashmem_chunk_ = allocator_->Allocate(bytes_);
- return false;
-}
-
-void DiscardableMemoryAshmem::ReleaseLock() {
- ashmem_chunk_->Unlock();
-}
-
-void DiscardableMemoryAshmem::Purge() {
- ashmem_chunk_.reset();
-}
-
-bool DiscardableMemoryAshmem::IsMemoryResident() const {
- return true;
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_ashmem.h b/chromium/base/memory/discardable_memory_ashmem.h
deleted file mode 100644
index c1cc077657a..00000000000
--- a/chromium/base/memory/discardable_memory_ashmem.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 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_MEMORY_DISCARDABLE_MEMORY_ASHMEM_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_ASHMEM_H_
-
-#include "base/memory/discardable_memory.h"
-
-#include "base/macros.h"
-#include "base/memory/discardable_memory_manager.h"
-
-namespace base {
-namespace internal {
-
-class DiscardableAshmemChunk;
-class DiscardableMemoryAshmemAllocator;
-class DiscardableMemoryManager;
-
-class DiscardableMemoryAshmem
- : public DiscardableMemory,
- public internal::DiscardableMemoryManagerAllocation {
- public:
- explicit DiscardableMemoryAshmem(size_t bytes,
- DiscardableMemoryAshmemAllocator* allocator,
- DiscardableMemoryManager* manager);
-
- virtual ~DiscardableMemoryAshmem();
-
- bool Initialize();
-
- // Overridden from DiscardableMemory:
- virtual DiscardableMemoryLockStatus Lock() override;
- virtual void Unlock() override;
- virtual void* Memory() const override;
-
- // Overridden from internal::DiscardableMemoryManagerAllocation:
- virtual bool AllocateAndAcquireLock() override;
- virtual void ReleaseLock() override;
- virtual void Purge() override;
- virtual bool IsMemoryResident() const override;
-
- private:
- const size_t bytes_;
- DiscardableMemoryAshmemAllocator* const allocator_;
- DiscardableMemoryManager* const manager_;
- bool is_locked_;
- scoped_ptr<DiscardableAshmemChunk> ashmem_chunk_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryAshmem);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_ASHMEM_H_
diff --git a/chromium/base/memory/discardable_memory_ashmem_allocator.cc b/chromium/base/memory/discardable_memory_ashmem_allocator.cc
deleted file mode 100644
index 3d4af925af3..00000000000
--- a/chromium/base/memory/discardable_memory_ashmem_allocator.cc
+++ /dev/null
@@ -1,528 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_ashmem_allocator.h"
-
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <cmath>
-#include <limits>
-#include <set>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/memory/scoped_vector.h"
-#include "third_party/ashmem/ashmem.h"
-
-// The allocator consists of three parts (classes):
-// - DiscardableMemoryAshmemAllocator: entry point of all allocations (through
-// its Allocate() method) that are dispatched to the AshmemRegion instances
-// (which it owns).
-// - AshmemRegion: manages allocations and destructions inside a single large
-// (e.g. 32 MBytes) ashmem region.
-// - DiscardableAshmemChunk: class mimicking the DiscardableMemory interface
-// whose instances are returned to the client.
-
-namespace base {
-namespace {
-
-// Only tolerate fragmentation in used chunks *caused by the client* (as opposed
-// to the allocator when a free chunk is reused). The client can cause such
-// fragmentation by e.g. requesting 4097 bytes. This size would be rounded up to
-// 8192 by the allocator which would cause 4095 bytes of fragmentation (which is
-// currently the maximum allowed). If the client requests 4096 bytes and a free
-// chunk of 8192 bytes is available then the free chunk gets splitted into two
-// pieces to minimize fragmentation (since 8192 - 4096 = 4096 which is greater
-// than 4095).
-// TODO(pliard): tune this if splitting chunks too often leads to performance
-// issues.
-const size_t kMaxChunkFragmentationBytes = 4096 - 1;
-
-const size_t kMinAshmemRegionSize = 32 * 1024 * 1024;
-
-// Returns 0 if the provided size is too high to be aligned.
-size_t AlignToNextPage(size_t size) {
- const size_t kPageSize = 4096;
- DCHECK_EQ(static_cast<int>(kPageSize), getpagesize());
- if (size > std::numeric_limits<size_t>::max() - kPageSize + 1)
- return 0;
- const size_t mask = ~(kPageSize - 1);
- return (size + kPageSize - 1) & mask;
-}
-
-bool CreateAshmemRegion(const char* name,
- size_t size,
- int* out_fd,
- uintptr_t* out_address) {
- base::ScopedFD fd(ashmem_create_region(name, size));
- if (!fd.is_valid()) {
- DLOG(ERROR) << "ashmem_create_region() failed";
- return false;
- }
-
- const int err = ashmem_set_prot_region(fd.get(), PROT_READ | PROT_WRITE);
- if (err < 0) {
- DLOG(ERROR) << "Error " << err << " when setting protection of ashmem";
- return false;
- }
-
- // There is a problem using MAP_PRIVATE here. As we are constantly calling
- // Lock() and Unlock(), data could get lost if they are not written to the
- // underlying file when Unlock() gets called.
- void* const address = mmap(
- NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
- if (address == MAP_FAILED) {
- DPLOG(ERROR) << "Failed to map memory.";
- return false;
- }
-
- *out_fd = fd.release();
- *out_address = reinterpret_cast<uintptr_t>(address);
- return true;
-}
-
-bool CloseAshmemRegion(int fd, size_t size, void* address) {
- if (munmap(address, size) == -1) {
- DPLOG(ERROR) << "Failed to unmap memory.";
- close(fd);
- return false;
- }
- return close(fd) == 0;
-}
-
-bool LockAshmemRegion(int fd, size_t off, size_t size) {
- return ashmem_pin_region(fd, off, size) != ASHMEM_WAS_PURGED;
-}
-
-bool UnlockAshmemRegion(int fd, size_t off, size_t size) {
- const int failed = ashmem_unpin_region(fd, off, size);
- if (failed)
- DLOG(ERROR) << "Failed to unpin memory.";
- return !failed;
-}
-
-} // namespace
-
-namespace internal {
-
-class AshmemRegion {
- public:
- // Note that |allocator| must outlive |this|.
- static scoped_ptr<AshmemRegion> Create(
- size_t size,
- const std::string& name,
- DiscardableMemoryAshmemAllocator* allocator) {
- DCHECK_EQ(size, AlignToNextPage(size));
- int fd;
- uintptr_t base;
- if (!CreateAshmemRegion(name.c_str(), size, &fd, &base))
- return scoped_ptr<AshmemRegion>();
- return make_scoped_ptr(new AshmemRegion(fd, size, base, allocator));
- }
-
- ~AshmemRegion() {
- const bool result = CloseAshmemRegion(
- fd_, size_, reinterpret_cast<void*>(base_));
- DCHECK(result);
- DCHECK(!highest_allocated_chunk_);
- }
-
- // Returns a new instance of DiscardableAshmemChunk whose size is greater or
- // equal than |actual_size| (which is expected to be greater or equal than
- // |client_requested_size|).
- // Allocation works as follows:
- // 1) Reuse a previously freed chunk and return it if it succeeded. See
- // ReuseFreeChunk_Locked() below for more information.
- // 2) If no free chunk could be reused and the region is not big enough for
- // the requested size then NULL is returned.
- // 3) If there is enough room in the ashmem region then a new chunk is
- // returned. This new chunk starts at |offset_| which is the end of the
- // previously highest chunk in the region.
- scoped_ptr<DiscardableAshmemChunk> Allocate_Locked(
- size_t client_requested_size,
- size_t actual_size) {
- DCHECK_LE(client_requested_size, actual_size);
- allocator_->lock_.AssertAcquired();
-
- // Check that the |highest_allocated_chunk_| field doesn't contain a stale
- // pointer. It should point to either a free chunk or a used chunk.
- DCHECK(!highest_allocated_chunk_ ||
- address_to_free_chunk_map_.find(highest_allocated_chunk_) !=
- address_to_free_chunk_map_.end() ||
- used_to_previous_chunk_map_.find(highest_allocated_chunk_) !=
- used_to_previous_chunk_map_.end());
-
- scoped_ptr<DiscardableAshmemChunk> memory = ReuseFreeChunk_Locked(
- client_requested_size, actual_size);
- if (memory)
- return memory.Pass();
-
- if (size_ - offset_ < actual_size) {
- // This region does not have enough space left to hold the requested size.
- return scoped_ptr<DiscardableAshmemChunk>();
- }
-
- uintptr_t const address = base_ + offset_;
- memory.reset(
- new DiscardableAshmemChunk(this, fd_, reinterpret_cast<void*>(address),
- offset_, actual_size));
-
- used_to_previous_chunk_map_.insert(
- std::make_pair(address, highest_allocated_chunk_));
- highest_allocated_chunk_ = reinterpret_cast<uintptr_t>(address);
- offset_ += actual_size;
- DCHECK_LE(offset_, size_);
- return memory.Pass();
- }
-
- void OnChunkDeletion(uintptr_t chunk, size_t size) {
- AutoLock auto_lock(allocator_->lock_);
- MergeAndAddFreeChunk_Locked(chunk, size);
- // Note that |this| might be deleted beyond this point.
- }
-
- private:
- struct FreeChunk {
- FreeChunk() : previous_chunk(0), start(0), size(0) {}
-
- explicit FreeChunk(size_t size)
- : previous_chunk(0),
- start(0),
- size(size) {
- }
-
- FreeChunk(uintptr_t previous_chunk, uintptr_t start, size_t size)
- : previous_chunk(previous_chunk),
- start(start),
- size(size) {
- DCHECK_LT(previous_chunk, start);
- }
-
- uintptr_t const previous_chunk;
- uintptr_t const start;
- const size_t size;
-
- bool is_null() const { return !start; }
-
- bool operator<(const FreeChunk& other) const {
- return size < other.size;
- }
- };
-
- // Note that |allocator| must outlive |this|.
- AshmemRegion(int fd,
- size_t size,
- uintptr_t base,
- DiscardableMemoryAshmemAllocator* allocator)
- : fd_(fd),
- size_(size),
- base_(base),
- allocator_(allocator),
- highest_allocated_chunk_(0),
- offset_(0) {
- DCHECK_GE(fd_, 0);
- DCHECK_GE(size, kMinAshmemRegionSize);
- DCHECK(base);
- DCHECK(allocator);
- }
-
- // Tries to reuse a previously freed chunk by doing a closest size match.
- scoped_ptr<DiscardableAshmemChunk> ReuseFreeChunk_Locked(
- size_t client_requested_size,
- size_t actual_size) {
- allocator_->lock_.AssertAcquired();
- const FreeChunk reused_chunk = RemoveFreeChunkFromIterator_Locked(
- free_chunks_.lower_bound(FreeChunk(actual_size)));
- if (reused_chunk.is_null())
- return scoped_ptr<DiscardableAshmemChunk>();
-
- used_to_previous_chunk_map_.insert(
- std::make_pair(reused_chunk.start, reused_chunk.previous_chunk));
- size_t reused_chunk_size = reused_chunk.size;
- // |client_requested_size| is used below rather than |actual_size| to
- // reflect the amount of bytes that would not be usable by the client (i.e.
- // wasted). Using |actual_size| instead would not allow us to detect
- // fragmentation caused by the client if he did misaligned allocations.
- DCHECK_GE(reused_chunk.size, client_requested_size);
- const size_t fragmentation_bytes =
- reused_chunk.size - client_requested_size;
-
- if (fragmentation_bytes > kMaxChunkFragmentationBytes) {
- // Split the free chunk being recycled so that its unused tail doesn't get
- // reused (i.e. locked) which would prevent it from being evicted under
- // memory pressure.
- reused_chunk_size = actual_size;
- uintptr_t const new_chunk_start = reused_chunk.start + actual_size;
- if (reused_chunk.start == highest_allocated_chunk_) {
- // We also need to update the pointer to the highest allocated chunk in
- // case we are splitting the highest chunk.
- highest_allocated_chunk_ = new_chunk_start;
- }
- DCHECK_GT(reused_chunk.size, actual_size);
- const size_t new_chunk_size = reused_chunk.size - actual_size;
- // Note that merging is not needed here since there can't be contiguous
- // free chunks at this point.
- AddFreeChunk_Locked(
- FreeChunk(reused_chunk.start, new_chunk_start, new_chunk_size));
- }
-
- const size_t offset = reused_chunk.start - base_;
- LockAshmemRegion(fd_, offset, reused_chunk_size);
- scoped_ptr<DiscardableAshmemChunk> memory(
- new DiscardableAshmemChunk(this, fd_,
- reinterpret_cast<void*>(reused_chunk.start),
- offset, reused_chunk_size));
- return memory.Pass();
- }
-
- // Makes the chunk identified with the provided arguments free and possibly
- // merges this chunk with the previous and next contiguous ones.
- // If the provided chunk is the only one used (and going to be freed) in the
- // region then the internal ashmem region is closed so that the underlying
- // physical pages are immediately released.
- // Note that free chunks are unlocked therefore they can be reclaimed by the
- // kernel if needed (under memory pressure) but they are not immediately
- // released unfortunately since madvise(MADV_REMOVE) and
- // fallocate(FALLOC_FL_PUNCH_HOLE) don't seem to work on ashmem. This might
- // change in versions of kernel >=3.5 though. The fact that free chunks are
- // not immediately released is the reason why we are trying to minimize
- // fragmentation in order not to cause "artificial" memory pressure.
- void MergeAndAddFreeChunk_Locked(uintptr_t chunk, size_t size) {
- allocator_->lock_.AssertAcquired();
- size_t new_free_chunk_size = size;
- // Merge with the previous chunk.
- uintptr_t first_free_chunk = chunk;
- DCHECK(!used_to_previous_chunk_map_.empty());
- const hash_map<uintptr_t, uintptr_t>::iterator previous_chunk_it =
- used_to_previous_chunk_map_.find(chunk);
- DCHECK(previous_chunk_it != used_to_previous_chunk_map_.end());
- uintptr_t previous_chunk = previous_chunk_it->second;
- used_to_previous_chunk_map_.erase(previous_chunk_it);
-
- if (previous_chunk) {
- const FreeChunk free_chunk = RemoveFreeChunk_Locked(previous_chunk);
- if (!free_chunk.is_null()) {
- new_free_chunk_size += free_chunk.size;
- first_free_chunk = previous_chunk;
- if (chunk == highest_allocated_chunk_)
- highest_allocated_chunk_ = previous_chunk;
-
- // There should not be more contiguous previous free chunks.
- previous_chunk = free_chunk.previous_chunk;
- DCHECK(!address_to_free_chunk_map_.count(previous_chunk));
- }
- }
-
- // Merge with the next chunk if free and present.
- uintptr_t next_chunk = chunk + size;
- const FreeChunk next_free_chunk = RemoveFreeChunk_Locked(next_chunk);
- if (!next_free_chunk.is_null()) {
- new_free_chunk_size += next_free_chunk.size;
- if (next_free_chunk.start == highest_allocated_chunk_)
- highest_allocated_chunk_ = first_free_chunk;
-
- // Same as above.
- DCHECK(
- !address_to_free_chunk_map_.count(next_chunk + next_free_chunk.size));
- }
-
- const bool whole_ashmem_region_is_free =
- used_to_previous_chunk_map_.empty();
- if (!whole_ashmem_region_is_free) {
- AddFreeChunk_Locked(
- FreeChunk(previous_chunk, first_free_chunk, new_free_chunk_size));
- return;
- }
-
- // The whole ashmem region is free thus it can be deleted.
- DCHECK_EQ(base_, first_free_chunk);
- DCHECK_EQ(base_, highest_allocated_chunk_);
- DCHECK(free_chunks_.empty());
- DCHECK(address_to_free_chunk_map_.empty());
- DCHECK(used_to_previous_chunk_map_.empty());
- highest_allocated_chunk_ = 0;
- allocator_->DeleteAshmemRegion_Locked(this); // Deletes |this|.
- }
-
- void AddFreeChunk_Locked(const FreeChunk& free_chunk) {
- allocator_->lock_.AssertAcquired();
- const std::multiset<FreeChunk>::iterator it = free_chunks_.insert(
- free_chunk);
- address_to_free_chunk_map_.insert(std::make_pair(free_chunk.start, it));
- // Update the next used contiguous chunk, if any, since its previous chunk
- // may have changed due to free chunks merging/splitting.
- uintptr_t const next_used_contiguous_chunk =
- free_chunk.start + free_chunk.size;
- hash_map<uintptr_t, uintptr_t>::iterator previous_it =
- used_to_previous_chunk_map_.find(next_used_contiguous_chunk);
- if (previous_it != used_to_previous_chunk_map_.end())
- previous_it->second = free_chunk.start;
- }
-
- // Finds and removes the free chunk, if any, whose start address is
- // |chunk_start|. Returns a copy of the unlinked free chunk or a free chunk
- // whose content is null if it was not found.
- FreeChunk RemoveFreeChunk_Locked(uintptr_t chunk_start) {
- allocator_->lock_.AssertAcquired();
- const hash_map<
- uintptr_t, std::multiset<FreeChunk>::iterator>::iterator it =
- address_to_free_chunk_map_.find(chunk_start);
- if (it == address_to_free_chunk_map_.end())
- return FreeChunk();
- return RemoveFreeChunkFromIterator_Locked(it->second);
- }
-
- // Same as above but takes an iterator in.
- FreeChunk RemoveFreeChunkFromIterator_Locked(
- std::multiset<FreeChunk>::iterator free_chunk_it) {
- allocator_->lock_.AssertAcquired();
- if (free_chunk_it == free_chunks_.end())
- return FreeChunk();
- DCHECK(free_chunk_it != free_chunks_.end());
- const FreeChunk free_chunk(*free_chunk_it);
- address_to_free_chunk_map_.erase(free_chunk_it->start);
- free_chunks_.erase(free_chunk_it);
- return free_chunk;
- }
-
- const int fd_;
- const size_t size_;
- uintptr_t const base_;
- DiscardableMemoryAshmemAllocator* const allocator_;
- // Points to the chunk with the highest address in the region. This pointer
- // needs to be carefully updated when chunks are merged/split.
- uintptr_t highest_allocated_chunk_;
- // Points to the end of |highest_allocated_chunk_|.
- size_t offset_;
- // Allows free chunks recycling (lookup, insertion and removal) in O(log N).
- // Note that FreeChunk values are indexed by their size and also note that
- // multiple free chunks can have the same size (which is why multiset<> is
- // used instead of e.g. set<>).
- std::multiset<FreeChunk> free_chunks_;
- // Used while merging free contiguous chunks to erase free chunks (from their
- // start address) in constant time. Note that multiset<>::{insert,erase}()
- // don't invalidate iterators (except the one for the element being removed
- // obviously).
- hash_map<
- uintptr_t, std::multiset<FreeChunk>::iterator> address_to_free_chunk_map_;
- // Maps the address of *used* chunks to the address of their previous
- // contiguous chunk.
- hash_map<uintptr_t, uintptr_t> used_to_previous_chunk_map_;
-
- DISALLOW_COPY_AND_ASSIGN(AshmemRegion);
-};
-
-DiscardableAshmemChunk::~DiscardableAshmemChunk() {
- if (locked_)
- UnlockAshmemRegion(fd_, offset_, size_);
- ashmem_region_->OnChunkDeletion(reinterpret_cast<uintptr_t>(address_), size_);
-}
-
-bool DiscardableAshmemChunk::Lock() {
- DCHECK(!locked_);
- locked_ = true;
- return LockAshmemRegion(fd_, offset_, size_);
-}
-
-void DiscardableAshmemChunk::Unlock() {
- DCHECK(locked_);
- locked_ = false;
- UnlockAshmemRegion(fd_, offset_, size_);
-}
-
-void* DiscardableAshmemChunk::Memory() const {
- return address_;
-}
-
-// Note that |ashmem_region| must outlive |this|.
-DiscardableAshmemChunk::DiscardableAshmemChunk(AshmemRegion* ashmem_region,
- int fd,
- void* address,
- size_t offset,
- size_t size)
- : ashmem_region_(ashmem_region),
- fd_(fd),
- address_(address),
- offset_(offset),
- size_(size),
- locked_(true) {
-}
-
-DiscardableMemoryAshmemAllocator::DiscardableMemoryAshmemAllocator(
- const std::string& name,
- size_t ashmem_region_size)
- : name_(name),
- ashmem_region_size_(
- std::max(kMinAshmemRegionSize, AlignToNextPage(ashmem_region_size))),
- last_ashmem_region_size_(0) {
- DCHECK_GE(ashmem_region_size_, kMinAshmemRegionSize);
-}
-
-DiscardableMemoryAshmemAllocator::~DiscardableMemoryAshmemAllocator() {
- DCHECK(ashmem_regions_.empty());
-}
-
-scoped_ptr<DiscardableAshmemChunk> DiscardableMemoryAshmemAllocator::Allocate(
- size_t size) {
- const size_t aligned_size = AlignToNextPage(size);
- if (!aligned_size)
- return scoped_ptr<DiscardableAshmemChunk>();
- // TODO(pliard): make this function less naive by e.g. moving the free chunks
- // multiset to the allocator itself in order to decrease even more
- // fragmentation/speedup allocation. Note that there should not be more than a
- // couple (=5) of AshmemRegion instances in practice though.
- AutoLock auto_lock(lock_);
- DCHECK_LE(ashmem_regions_.size(), 5U);
- for (ScopedVector<AshmemRegion>::iterator it = ashmem_regions_.begin();
- it != ashmem_regions_.end(); ++it) {
- scoped_ptr<DiscardableAshmemChunk> memory(
- (*it)->Allocate_Locked(size, aligned_size));
- if (memory)
- return memory.Pass();
- }
- // The creation of the (large) ashmem region might fail if the address space
- // is too fragmented. In case creation fails the allocator retries by
- // repetitively dividing the size by 2.
- const size_t min_region_size = std::max(kMinAshmemRegionSize, aligned_size);
- for (size_t region_size = std::max(ashmem_region_size_, aligned_size);
- region_size >= min_region_size;
- region_size = AlignToNextPage(region_size / 2)) {
- scoped_ptr<AshmemRegion> new_region(
- AshmemRegion::Create(region_size, name_.c_str(), this));
- if (!new_region)
- continue;
- last_ashmem_region_size_ = region_size;
- ashmem_regions_.push_back(new_region.release());
- return ashmem_regions_.back()->Allocate_Locked(size, aligned_size);
- }
- // TODO(pliard): consider adding an histogram to see how often this happens.
- return scoped_ptr<DiscardableAshmemChunk>();
-}
-
-size_t DiscardableMemoryAshmemAllocator::last_ashmem_region_size() const {
- AutoLock auto_lock(lock_);
- return last_ashmem_region_size_;
-}
-
-void DiscardableMemoryAshmemAllocator::DeleteAshmemRegion_Locked(
- AshmemRegion* region) {
- lock_.AssertAcquired();
- // Note that there should not be more than a couple of ashmem region instances
- // in |ashmem_regions_|.
- DCHECK_LE(ashmem_regions_.size(), 5U);
- const ScopedVector<AshmemRegion>::iterator it = std::find(
- ashmem_regions_.begin(), ashmem_regions_.end(), region);
- DCHECK(ashmem_regions_.end() != it);
- std::swap(*it, ashmem_regions_.back());
- ashmem_regions_.pop_back();
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_ashmem_allocator.h b/chromium/base/memory/discardable_memory_ashmem_allocator.h
deleted file mode 100644
index 996dde92496..00000000000
--- a/chromium/base/memory/discardable_memory_ashmem_allocator.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2014 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_MEMORY_DISCARDABLE_MEMORY_ASHMEM_ALLOCATOR_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_ASHMEM_ALLOCATOR_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/synchronization/lock.h"
-
-namespace base {
-namespace internal {
-
-class AshmemRegion;
-
-// Internal class, whose instances are returned to the client of the allocator
-// (e.g. DiscardableMemoryAshmem), that mimicks the DiscardableMemory interface.
-class BASE_EXPORT_PRIVATE DiscardableAshmemChunk {
- public:
- ~DiscardableAshmemChunk();
-
- // Returns whether the memory is still resident.
- bool Lock();
-
- void Unlock();
-
- void* Memory() const;
-
- private:
- friend class AshmemRegion;
-
- DiscardableAshmemChunk(AshmemRegion* ashmem_region,
- int fd,
- void* address,
- size_t offset,
- size_t size);
-
- AshmemRegion* const ashmem_region_;
- const int fd_;
- void* const address_;
- const size_t offset_;
- const size_t size_;
- bool locked_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableAshmemChunk);
-};
-
-// Ashmem regions are backed by a file (descriptor) therefore they are a limited
-// resource. This allocator minimizes the problem by allocating large ashmem
-// regions internally and returning smaller chunks to the client.
-// Allocated chunks are systematically aligned on a page boundary therefore this
-// allocator should not be used for small allocations.
-class BASE_EXPORT_PRIVATE DiscardableMemoryAshmemAllocator {
- public:
- // Note that |name| is only used for debugging/measurement purposes.
- // |ashmem_region_size| is the size that will be used to create the underlying
- // ashmem regions and is expected to be greater or equal than 32 MBytes.
- DiscardableMemoryAshmemAllocator(const std::string& name,
- size_t ashmem_region_size);
-
- ~DiscardableMemoryAshmemAllocator();
-
- // Note that the allocator must outlive the returned DiscardableAshmemChunk
- // instance.
- scoped_ptr<DiscardableAshmemChunk> Allocate(size_t size);
-
- // Returns the size of the last ashmem region which was created. This is used
- // for testing only.
- size_t last_ashmem_region_size() const;
-
- private:
- friend class AshmemRegion;
-
- void DeleteAshmemRegion_Locked(AshmemRegion* region);
-
- const std::string name_;
- const size_t ashmem_region_size_;
- mutable Lock lock_;
- size_t last_ashmem_region_size_;
- ScopedVector<AshmemRegion> ashmem_regions_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryAshmemAllocator);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_ASHMEM_ALLOCATOR_H_
diff --git a/chromium/base/memory/discardable_memory_ashmem_allocator_unittest.cc b/chromium/base/memory/discardable_memory_ashmem_allocator_unittest.cc
deleted file mode 100644
index e9f63ba3439..00000000000
--- a/chromium/base/memory/discardable_memory_ashmem_allocator_unittest.cc
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_ashmem_allocator.h"
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "base/memory/discardable_memory.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace internal {
-
-const char kAllocatorName[] = "allocator-for-testing";
-
-const size_t kAshmemRegionSizeForTesting = 32 * 1024 * 1024;
-const size_t kPageSize = 4096;
-
-const size_t kMaxAllowedAllocationSize =
- std::numeric_limits<size_t>::max() - kPageSize + 1;
-
-class DiscardableMemoryAshmemAllocatorTest : public testing::Test {
- protected:
- DiscardableMemoryAshmemAllocatorTest()
- : allocator_(kAllocatorName, kAshmemRegionSizeForTesting) {
- }
-
- DiscardableMemoryAshmemAllocator allocator_;
-};
-
-void WriteToDiscardableAshmemChunk(DiscardableAshmemChunk* memory,
- size_t size) {
- // Write to the first and the last pages only to avoid paging in up to 64
- // MBytes.
- static_cast<char*>(memory->Memory())[0] = 'a';
- static_cast<char*>(memory->Memory())[size - 1] = 'a';
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, Basic) {
- const size_t size = 128;
- scoped_ptr<DiscardableAshmemChunk> memory(allocator_.Allocate(size));
- ASSERT_TRUE(memory);
- WriteToDiscardableAshmemChunk(memory.get(), size);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, ZeroAllocationIsNotSupported) {
- scoped_ptr<DiscardableAshmemChunk> memory(allocator_.Allocate(0));
- ASSERT_FALSE(memory);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, TooLargeAllocationFails) {
- scoped_ptr<DiscardableAshmemChunk> memory(
- allocator_.Allocate(kMaxAllowedAllocationSize + 1));
- // Page-alignment would have caused an overflow resulting in a small
- // allocation if the input size wasn't checked correctly.
- ASSERT_FALSE(memory);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest,
- AshmemRegionsAreNotSmallerThanRequestedSize) {
- // The creation of the underlying ashmem region is expected to fail since
- // there should not be enough room in the address space. When ashmem creation
- // fails, the allocator repetitively retries by dividing the size by 2. This
- // size should not be smaller than the size the user requested so the
- // allocation here should just fail (and not succeed with the minimum ashmem
- // region size).
- scoped_ptr<DiscardableAshmemChunk> memory(
- allocator_.Allocate(kMaxAllowedAllocationSize));
- ASSERT_FALSE(memory);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest,
- AshmemRegionsAreAlwaysPageAligned) {
- // Use a separate allocator here so that we can override the ashmem region
- // size.
- DiscardableMemoryAshmemAllocator allocator(
- kAllocatorName, kMaxAllowedAllocationSize);
- scoped_ptr<DiscardableAshmemChunk> memory(allocator.Allocate(kPageSize));
- ASSERT_TRUE(memory);
- EXPECT_GT(kMaxAllowedAllocationSize, allocator.last_ashmem_region_size());
- ASSERT_TRUE(allocator.last_ashmem_region_size() % kPageSize == 0);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, LargeAllocation) {
- const size_t size = 64 * 1024 * 1024;
- scoped_ptr<DiscardableAshmemChunk> memory(allocator_.Allocate(size));
- ASSERT_TRUE(memory);
- WriteToDiscardableAshmemChunk(memory.get(), size);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, ChunksArePageAligned) {
- scoped_ptr<DiscardableAshmemChunk> memory(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory);
- EXPECT_EQ(0U, reinterpret_cast<uint64_t>(memory->Memory()) % kPageSize);
- WriteToDiscardableAshmemChunk(memory.get(), kPageSize);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, AllocateFreeAllocate) {
- scoped_ptr<DiscardableAshmemChunk> memory(allocator_.Allocate(kPageSize));
- // Extra allocation that prevents the region from being deleted when |memory|
- // gets deleted.
- scoped_ptr<DiscardableAshmemChunk> memory_lock(
- allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory);
- void* const address = memory->Memory();
- memory->Unlock(); // Tests that the reused chunk is being locked correctly.
- memory.reset();
- memory = allocator_.Allocate(kPageSize);
- ASSERT_TRUE(memory);
- // The previously freed chunk should be reused.
- EXPECT_EQ(address, memory->Memory());
- WriteToDiscardableAshmemChunk(memory.get(), kPageSize);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest,
- FreeingWholeAshmemRegionClosesAshmem) {
- scoped_ptr<DiscardableAshmemChunk> memory(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory);
- const int kMagic = 0xdeadbeef;
- *static_cast<int*>(memory->Memory()) = kMagic;
- memory.reset();
- // The previous ashmem region should have been closed thus it should not be
- // reused.
- memory = allocator_.Allocate(kPageSize);
- ASSERT_TRUE(memory);
- EXPECT_NE(kMagic, *static_cast<const int*>(memory->Memory()));
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, AllocateUsesBestFitAlgorithm) {
- scoped_ptr<DiscardableAshmemChunk> memory1(
- allocator_.Allocate(3 * kPageSize));
- ASSERT_TRUE(memory1);
- scoped_ptr<DiscardableAshmemChunk> memory2(
- allocator_.Allocate(2 * kPageSize));
- ASSERT_TRUE(memory2);
- scoped_ptr<DiscardableAshmemChunk> memory3(
- allocator_.Allocate(1 * kPageSize));
- ASSERT_TRUE(memory3);
- void* const address_3 = memory3->Memory();
- memory1.reset();
- // Don't free |memory2| to avoid merging the 3 blocks together.
- memory3.reset();
- memory1 = allocator_.Allocate(1 * kPageSize);
- ASSERT_TRUE(memory1);
- // The chunk whose size is closest to the requested size should be reused.
- EXPECT_EQ(address_3, memory1->Memory());
- WriteToDiscardableAshmemChunk(memory1.get(), kPageSize);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, MergeFreeChunks) {
- scoped_ptr<DiscardableAshmemChunk> memory1(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory1);
- scoped_ptr<DiscardableAshmemChunk> memory2(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory2);
- scoped_ptr<DiscardableAshmemChunk> memory3(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory3);
- scoped_ptr<DiscardableAshmemChunk> memory4(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory4);
- void* const memory1_address = memory1->Memory();
- memory1.reset();
- memory3.reset();
- // Freeing |memory2| (located between memory1 and memory3) should merge the
- // three free blocks together.
- memory2.reset();
- memory1 = allocator_.Allocate(3 * kPageSize);
- EXPECT_EQ(memory1_address, memory1->Memory());
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, MergeFreeChunksAdvanced) {
- scoped_ptr<DiscardableAshmemChunk> memory1(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory1);
- scoped_ptr<DiscardableAshmemChunk> memory2(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory2);
- void* const memory1_address = memory1->Memory();
- memory1.reset();
- memory1 = allocator_.Allocate(2 * kPageSize);
- memory2.reset();
- // At this point, the region should be in this state:
- // 8 KBytes (used), 24 KBytes (free).
- memory2 = allocator_.Allocate(6 * kPageSize);
- EXPECT_EQ(
- static_cast<const char*>(memory2->Memory()),
- static_cast<const char*>(memory1_address) + 2 * kPageSize);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, MergeFreeChunksAdvanced2) {
- scoped_ptr<DiscardableAshmemChunk> memory1(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory1);
- scoped_ptr<DiscardableAshmemChunk> memory2(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory2);
- void* const memory1_address = memory1->Memory();
- memory1.reset();
- memory1 = allocator_.Allocate(2 * kPageSize);
- scoped_ptr<DiscardableAshmemChunk> memory3(
- allocator_.Allocate(2 * kPageSize));
- // At this point, the region should be in this state:
- // 8 KBytes (used), 8 KBytes (used), 16 KBytes (used).
- memory3.reset();
- memory2.reset();
- // At this point, the region should be in this state:
- // 8 KBytes (used), 24 KBytes (free).
- memory2 = allocator_.Allocate(6 * kPageSize);
- EXPECT_EQ(
- static_cast<const char*>(memory2->Memory()),
- static_cast<const char*>(memory1_address) + 2 * kPageSize);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest,
- MergeFreeChunksAndDeleteAshmemRegion) {
- scoped_ptr<DiscardableAshmemChunk> memory1(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory1);
- scoped_ptr<DiscardableAshmemChunk> memory2(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory2);
- memory1.reset();
- memory1 = allocator_.Allocate(2 * kPageSize);
- scoped_ptr<DiscardableAshmemChunk> memory3(
- allocator_.Allocate(2 * kPageSize));
- // At this point, the region should be in this state:
- // 8 KBytes (used), 8 KBytes (used), 16 KBytes (used).
- memory1.reset();
- memory3.reset();
- // At this point, the region should be in this state:
- // 8 KBytes (free), 8 KBytes (used), 8 KBytes (free).
- const int kMagic = 0xdeadbeef;
- *static_cast<int*>(memory2->Memory()) = kMagic;
- memory2.reset();
- // The whole region should have been deleted.
- memory2 = allocator_.Allocate(2 * kPageSize);
- EXPECT_NE(kMagic, *static_cast<int*>(memory2->Memory()));
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest,
- TooLargeFreeChunksDontCauseTooMuchFragmentationWhenRecycled) {
- // Keep |memory_1| below allocated so that the ashmem region doesn't get
- // closed when |memory_2| is deleted.
- scoped_ptr<DiscardableAshmemChunk> memory_1(allocator_.Allocate(64 * 1024));
- ASSERT_TRUE(memory_1);
- scoped_ptr<DiscardableAshmemChunk> memory_2(allocator_.Allocate(32 * 1024));
- ASSERT_TRUE(memory_2);
- void* const address = memory_2->Memory();
- memory_2.reset();
- const size_t size = 16 * 1024;
- memory_2 = allocator_.Allocate(size);
- ASSERT_TRUE(memory_2);
- EXPECT_EQ(address, memory_2->Memory());
- WriteToDiscardableAshmemChunk(memory_2.get(), size);
- scoped_ptr<DiscardableAshmemChunk> memory_3(allocator_.Allocate(size));
- // The unused tail (16 KBytes large) of the previously freed chunk should be
- // reused.
- EXPECT_EQ(static_cast<char*>(address) + size, memory_3->Memory());
- WriteToDiscardableAshmemChunk(memory_3.get(), size);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest, UseMultipleAshmemRegions) {
- // Leave one page untouched at the end of the ashmem region.
- const size_t size = kAshmemRegionSizeForTesting - kPageSize;
- scoped_ptr<DiscardableAshmemChunk> memory1(allocator_.Allocate(size));
- ASSERT_TRUE(memory1);
- WriteToDiscardableAshmemChunk(memory1.get(), size);
-
- scoped_ptr<DiscardableAshmemChunk> memory2(
- allocator_.Allocate(kAshmemRegionSizeForTesting));
- ASSERT_TRUE(memory2);
- WriteToDiscardableAshmemChunk(memory2.get(), kAshmemRegionSizeForTesting);
- // The last page of the first ashmem region should be used for this
- // allocation.
- scoped_ptr<DiscardableAshmemChunk> memory3(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory3);
- WriteToDiscardableAshmemChunk(memory3.get(), kPageSize);
- EXPECT_EQ(memory3->Memory(), static_cast<char*>(memory1->Memory()) + size);
-}
-
-TEST_F(DiscardableMemoryAshmemAllocatorTest,
- HighestAllocatedChunkPointerIsUpdatedWhenHighestChunkGetsSplit) {
- // Prevents the ashmem region from getting closed when |memory2| gets freed.
- scoped_ptr<DiscardableAshmemChunk> memory1(allocator_.Allocate(kPageSize));
- ASSERT_TRUE(memory1);
-
- scoped_ptr<DiscardableAshmemChunk> memory2(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory2);
-
- memory2.reset();
- memory2 = allocator_.Allocate(kPageSize);
- // There should now be a free chunk of size 3 * |kPageSize| starting at offset
- // 2 * |kPageSize| and the pointer to the highest allocated chunk should have
- // also been updated to |base_| + 2 * |kPageSize|. This pointer is used to
- // maintain the container mapping a chunk address to its previous chunk and
- // this map is in turn used while merging previous contiguous chunks.
-
- // Allocate more than 3 * |kPageSize| so that the free chunk of size 3 *
- // |kPageSize| is not reused and |highest_allocated_chunk_| gets used instead.
- scoped_ptr<DiscardableAshmemChunk> memory3(
- allocator_.Allocate(4 * kPageSize));
- ASSERT_TRUE(memory3);
-
- // Deleting |memory3| (whose size is 4 * |kPageSize|) should result in a merge
- // with its previous chunk which is the free chunk of size |3 * kPageSize|.
- memory3.reset();
- memory3 = allocator_.Allocate((3 + 4) * kPageSize);
- EXPECT_EQ(memory3->Memory(),
- static_cast<const char*>(memory2->Memory()) + kPageSize);
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_emulated.cc b/chromium/base/memory/discardable_memory_emulated.cc
deleted file mode 100644
index 43034006319..00000000000
--- a/chromium/base/memory/discardable_memory_emulated.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2013 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/memory/discardable_memory_emulated.h"
-
-#include "base/lazy_instance.h"
-#include "base/memory/discardable_memory_manager.h"
-
-namespace base {
-namespace {
-
-// This is admittedly pretty magical.
-const size_t kEmulatedMemoryLimit = 512 * 1024 * 1024;
-const size_t kEmulatedSoftMemoryLimit = 32 * 1024 * 1024;
-const size_t kEmulatedHardMemoryLimitExpirationTimeMs = 1000;
-
-// internal::DiscardableMemoryManager has an explicit constructor that takes
-// a number of memory limit parameters. The LeakyLazyInstanceTraits doesn't
-// handle the case. Thus, we need our own class here.
-struct DiscardableMemoryManagerLazyInstanceTraits {
- // Leaky as discardable memory clients can use this after the exit handler
- // has been called.
- static const bool kRegisterOnExit = false;
-#ifndef NDEBUG
- static const bool kAllowedToAccessOnNonjoinableThread = true;
-#endif
-
- static internal::DiscardableMemoryManager* New(void* instance) {
- return new (instance) internal::DiscardableMemoryManager(
- kEmulatedMemoryLimit,
- kEmulatedSoftMemoryLimit,
- TimeDelta::FromMilliseconds(kEmulatedHardMemoryLimitExpirationTimeMs));
- }
- static void Delete(internal::DiscardableMemoryManager* instance) {
- instance->~DiscardableMemoryManager();
- }
-};
-
-LazyInstance<internal::DiscardableMemoryManager,
- DiscardableMemoryManagerLazyInstanceTraits>
- g_manager = LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-namespace internal {
-
-DiscardableMemoryEmulated::DiscardableMemoryEmulated(size_t bytes)
- : bytes_(bytes),
- is_locked_(false) {
- g_manager.Pointer()->Register(this, bytes);
-}
-
-DiscardableMemoryEmulated::~DiscardableMemoryEmulated() {
- if (is_locked_)
- Unlock();
- g_manager.Pointer()->Unregister(this);
-}
-
-// static
-bool DiscardableMemoryEmulated::ReduceMemoryUsage() {
- return g_manager.Pointer()->ReduceMemoryUsage();
-}
-
-// static
-void DiscardableMemoryEmulated::ReduceMemoryUsageUntilWithinLimit(
- size_t bytes) {
- g_manager.Pointer()->ReduceMemoryUsageUntilWithinLimit(bytes);
-}
-
-// static
-void DiscardableMemoryEmulated::PurgeForTesting() {
- g_manager.Pointer()->PurgeAll();
-}
-
-bool DiscardableMemoryEmulated::Initialize() {
- return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-}
-
-DiscardableMemoryLockStatus DiscardableMemoryEmulated::Lock() {
- DCHECK(!is_locked_);
-
- bool purged = false;
- if (!g_manager.Pointer()->AcquireLock(this, &purged))
- return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-
- is_locked_ = true;
- return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
- : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
-}
-
-void DiscardableMemoryEmulated::Unlock() {
- DCHECK(is_locked_);
- g_manager.Pointer()->ReleaseLock(this);
- is_locked_ = false;
-}
-
-void* DiscardableMemoryEmulated::Memory() const {
- DCHECK(is_locked_);
- DCHECK(memory_);
- return memory_.get();
-}
-
-bool DiscardableMemoryEmulated::AllocateAndAcquireLock() {
- if (memory_)
- return true;
-
- memory_.reset(new uint8[bytes_]);
- return false;
-}
-
-void DiscardableMemoryEmulated::Purge() {
- memory_.reset();
-}
-
-bool DiscardableMemoryEmulated::IsMemoryResident() const {
- return true;
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_emulated.h b/chromium/base/memory/discardable_memory_emulated.h
deleted file mode 100644
index 150c1ab5669..00000000000
--- a/chromium/base/memory/discardable_memory_emulated.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 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_MEMORY_DISCARDABLE_MEMORY_EMULATED_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_EMULATED_H_
-
-#include "base/memory/discardable_memory.h"
-
-#include "base/memory/discardable_memory_manager.h"
-
-namespace base {
-namespace internal {
-
-class DiscardableMemoryEmulated
- : public DiscardableMemory,
- public internal::DiscardableMemoryManagerAllocation {
- public:
- explicit DiscardableMemoryEmulated(size_t bytes);
- ~DiscardableMemoryEmulated() override;
-
- static bool ReduceMemoryUsage();
-
- // TODO(reveman): Remove this as it is breaking the discardable memory design
- // principle that implementations should not rely on information this is
- // unavailable in kernel space. crbug.com/400423
- BASE_EXPORT static void ReduceMemoryUsageUntilWithinLimit(size_t bytes);
-
- static void PurgeForTesting();
-
- bool Initialize();
-
- // Overridden from DiscardableMemory:
- DiscardableMemoryLockStatus Lock() override;
- void Unlock() override;
- void* Memory() const override;
-
- // Overridden from internal::DiscardableMemoryManagerAllocation:
- bool AllocateAndAcquireLock() override;
- void ReleaseLock() override {}
- void Purge() override;
- bool IsMemoryResident() const override;
-
- private:
- const size_t bytes_;
- scoped_ptr<uint8[]> memory_;
- bool is_locked_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryEmulated);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_EMULATED_H_
diff --git a/chromium/base/memory/discardable_memory_linux.cc b/chromium/base/memory/discardable_memory_linux.cc
deleted file mode 100644
index 9b4e9401ce4..00000000000
--- a/chromium/base/memory/discardable_memory_linux.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 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/memory/discardable_memory.h"
-
-#include "base/logging.h"
-#include "base/memory/discardable_memory_emulated.h"
-#include "base/memory/discardable_memory_shmem.h"
-
-namespace base {
-
-// static
-void DiscardableMemory::ReleaseFreeMemory() {
- internal::DiscardableMemoryShmem::ReleaseFreeMemory();
-}
-
-// static
-bool DiscardableMemory::ReduceMemoryUsage() {
- return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
-}
-
-// static
-void DiscardableMemory::GetSupportedTypes(
- std::vector<DiscardableMemoryType>* types) {
- const DiscardableMemoryType supported_types[] = {
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
- };
- types->assign(supported_types, supported_types + arraysize(supported_types));
-}
-
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
- DiscardableMemoryType type, size_t size) {
- switch (type) {
- case DISCARDABLE_MEMORY_TYPE_EMULATED: {
- scoped_ptr<internal::DiscardableMemoryEmulated> memory(
- new internal::DiscardableMemoryEmulated(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_SHMEM: {
- scoped_ptr<internal::DiscardableMemoryShmem> memory(
- new internal::DiscardableMemoryShmem(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_NONE:
- case DISCARDABLE_MEMORY_TYPE_ASHMEM:
- case DISCARDABLE_MEMORY_TYPE_MACH:
- NOTREACHED();
- return nullptr;
- }
-
- NOTREACHED();
- return nullptr;
-}
-
-// static
-void DiscardableMemory::PurgeForTesting() {
- internal::DiscardableMemoryEmulated::PurgeForTesting();
- internal::DiscardableMemoryShmem::PurgeForTesting();
-}
-
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_mac.cc b/chromium/base/memory/discardable_memory_mac.cc
deleted file mode 100644
index 18cf80ac4aa..00000000000
--- a/chromium/base/memory/discardable_memory_mac.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2013 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/memory/discardable_memory.h"
-
-#include "base/logging.h"
-#include "base/memory/discardable_memory_emulated.h"
-#include "base/memory/discardable_memory_mach.h"
-#include "base/memory/discardable_memory_manager.h"
-#include "base/memory/discardable_memory_shmem.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace base {
-
-// static
-void DiscardableMemory::ReleaseFreeMemory() {
- internal::DiscardableMemoryShmem::ReleaseFreeMemory();
-}
-
-// static
-bool DiscardableMemory::ReduceMemoryUsage() {
- return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
-}
-
-// static
-void DiscardableMemory::GetSupportedTypes(
- std::vector<DiscardableMemoryType>* types) {
- const DiscardableMemoryType supported_types[] = {
- DISCARDABLE_MEMORY_TYPE_MACH,
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
- };
- types->assign(supported_types, supported_types + arraysize(supported_types));
-}
-
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
- DiscardableMemoryType type, size_t size) {
- switch (type) {
- case DISCARDABLE_MEMORY_TYPE_MACH: {
- scoped_ptr<internal::DiscardableMemoryMach> memory(
- new internal::DiscardableMemoryMach(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_EMULATED: {
- scoped_ptr<internal::DiscardableMemoryEmulated> memory(
- new internal::DiscardableMemoryEmulated(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_SHMEM: {
- scoped_ptr<internal::DiscardableMemoryShmem> memory(
- new internal::DiscardableMemoryShmem(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_NONE:
- case DISCARDABLE_MEMORY_TYPE_ASHMEM:
- NOTREACHED();
- return nullptr;
- }
-
- NOTREACHED();
- return nullptr;
-}
-
-// static
-void DiscardableMemory::PurgeForTesting() {
- internal::DiscardableMemoryMach::PurgeForTesting();
- internal::DiscardableMemoryEmulated::PurgeForTesting();
- internal::DiscardableMemoryShmem::PurgeForTesting();
-}
-
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_mach.cc b/chromium/base/memory/discardable_memory_mach.cc
deleted file mode 100644
index 5fc43f2a7d8..00000000000
--- a/chromium/base/memory/discardable_memory_mach.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_mach.h"
-
-#include <mach/mach.h>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/mac/mach_logging.h"
-
-namespace base {
-namespace {
-
-// For Mach, have the DiscardableMemoryManager trigger userspace eviction when
-// address space usage gets too high (e.g. 512 MBytes).
-const size_t kMachMemoryLimit = 512 * 1024 * 1024;
-
-// internal::DiscardableMemoryManager has an explicit constructor that takes
-// a number of memory limit parameters. The LeakyLazyInstanceTraits doesn't
-// handle the case. Thus, we need our own class here.
-struct DiscardableMemoryManagerLazyInstanceTraits {
- // Leaky as discardable memory clients can use this after the exit handler
- // has been called.
- static const bool kRegisterOnExit = false;
-#ifndef NDEBUG
- static const bool kAllowedToAccessOnNonjoinableThread = true;
-#endif
-
- static internal::DiscardableMemoryManager* New(void* instance) {
- return new (instance) internal::DiscardableMemoryManager(
- kMachMemoryLimit, kMachMemoryLimit, TimeDelta::Max());
- }
- static void Delete(internal::DiscardableMemoryManager* instance) {
- instance->~DiscardableMemoryManager();
- }
-};
-
-LazyInstance<internal::DiscardableMemoryManager,
- DiscardableMemoryManagerLazyInstanceTraits>
- g_manager = LAZY_INSTANCE_INITIALIZER;
-
-// The VM subsystem allows tagging of memory and 240-255 is reserved for
-// application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic
-// weight of ~52).
-const int kDiscardableMemoryTag = VM_MAKE_TAG(252);
-
-} // namespace
-
-namespace internal {
-
-DiscardableMemoryMach::DiscardableMemoryMach(size_t bytes)
- : memory_(0, 0), bytes_(mach_vm_round_page(bytes)), is_locked_(false) {
- g_manager.Pointer()->Register(this, bytes);
-}
-
-DiscardableMemoryMach::~DiscardableMemoryMach() {
- if (is_locked_)
- Unlock();
- g_manager.Pointer()->Unregister(this);
-}
-
-// static
-void DiscardableMemoryMach::PurgeForTesting() {
- int state = 0;
- vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state);
-}
-
-bool DiscardableMemoryMach::Initialize() {
- return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-}
-
-DiscardableMemoryLockStatus DiscardableMemoryMach::Lock() {
- DCHECK(!is_locked_);
-
- bool purged = false;
- if (!g_manager.Pointer()->AcquireLock(this, &purged))
- return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-
- is_locked_ = true;
- return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
- : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
-}
-
-void DiscardableMemoryMach::Unlock() {
- DCHECK(is_locked_);
- g_manager.Pointer()->ReleaseLock(this);
- is_locked_ = false;
-}
-
-void* DiscardableMemoryMach::Memory() const {
- DCHECK(is_locked_);
- return reinterpret_cast<void*>(memory_.address());
-}
-
-bool DiscardableMemoryMach::AllocateAndAcquireLock() {
- kern_return_t ret;
- bool persistent;
- if (!memory_.size()) {
- vm_address_t address = 0;
- ret = vm_allocate(
- mach_task_self(),
- &address,
- bytes_,
- VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE | kDiscardableMemoryTag);
- MACH_CHECK(ret == KERN_SUCCESS, ret) << "vm_allocate";
- memory_.reset(address, bytes_);
-
- // When making a fresh allocation, it's impossible for |persistent| to
- // be true.
- persistent = false;
- } else {
- // |persistent| will be reset to false below if appropriate, but when
- // reusing an existing allocation, it's possible for it to be true.
- persistent = true;
-
-#if !defined(NDEBUG)
- ret = vm_protect(mach_task_self(),
- memory_.address(),
- memory_.size(),
- FALSE,
- VM_PROT_DEFAULT);
- MACH_DCHECK(ret == KERN_SUCCESS, ret) << "vm_protect";
-#endif
- }
-
- int state = VM_PURGABLE_NONVOLATILE;
- ret = vm_purgable_control(
- mach_task_self(), memory_.address(), VM_PURGABLE_SET_STATE, &state);
- MACH_CHECK(ret == KERN_SUCCESS, ret) << "vm_purgable_control";
- if (state & VM_PURGABLE_EMPTY)
- persistent = false;
-
- return persistent;
-}
-
-void DiscardableMemoryMach::ReleaseLock() {
- int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT;
- kern_return_t ret = vm_purgable_control(
- mach_task_self(), memory_.address(), VM_PURGABLE_SET_STATE, &state);
- MACH_CHECK(ret == KERN_SUCCESS, ret) << "vm_purgable_control";
-
-#if !defined(NDEBUG)
- ret = vm_protect(
- mach_task_self(), memory_.address(), memory_.size(), FALSE, VM_PROT_NONE);
- MACH_DCHECK(ret == KERN_SUCCESS, ret) << "vm_protect";
-#endif
-}
-
-void DiscardableMemoryMach::Purge() {
- memory_.reset();
-}
-
-bool DiscardableMemoryMach::IsMemoryResident() const {
- return true;
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_mach.h b/chromium/base/memory/discardable_memory_mach.h
deleted file mode 100644
index af2191f338c..00000000000
--- a/chromium/base/memory/discardable_memory_mach.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 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_MEMORY_DISCARDABLE_MEMORY_MACH_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_MACH_H_
-
-#include "base/memory/discardable_memory.h"
-
-#include "base/mac/scoped_mach_vm.h"
-#include "base/memory/discardable_memory_manager.h"
-
-namespace base {
-namespace internal {
-
-class DiscardableMemoryMach
- : public DiscardableMemory,
- public internal::DiscardableMemoryManagerAllocation {
- public:
- explicit DiscardableMemoryMach(size_t bytes);
- ~DiscardableMemoryMach() override;
-
- static void PurgeForTesting();
-
- bool Initialize();
-
- // Overridden from DiscardableMemory:
- DiscardableMemoryLockStatus Lock() override;
- void Unlock() override;
- void* Memory() const override;
-
- // Overridden from internal::DiscardableMemoryManagerAllocation:
- bool AllocateAndAcquireLock() override;
- void ReleaseLock() override;
- void Purge() override;
- bool IsMemoryResident() const override;
-
- private:
- mac::ScopedMachVM memory_;
- const size_t bytes_;
- bool is_locked_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryMach);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_MACH_H_
diff --git a/chromium/base/memory/discardable_memory_manager.cc b/chromium/base/memory/discardable_memory_manager.cc
deleted file mode 100644
index faf583b485f..00000000000
--- a/chromium/base/memory/discardable_memory_manager.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_manager.h"
-
-#include "base/bind.h"
-#include "base/containers/adapters.h"
-#include "base/containers/hash_tables.h"
-#include "base/containers/mru_cache.h"
-#include "base/debug/crash_logging.h"
-#include "base/debug/trace_event.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/synchronization/lock.h"
-
-namespace base {
-namespace internal {
-
-DiscardableMemoryManager::DiscardableMemoryManager(
- size_t memory_limit,
- size_t soft_memory_limit,
- TimeDelta hard_memory_limit_expiration_time)
- : allocations_(AllocationMap::NO_AUTO_EVICT),
- bytes_allocated_(0u),
- memory_limit_(memory_limit),
- soft_memory_limit_(soft_memory_limit),
- hard_memory_limit_expiration_time_(hard_memory_limit_expiration_time) {
- BytesAllocatedChanged(bytes_allocated_);
-}
-
-DiscardableMemoryManager::~DiscardableMemoryManager() {
- DCHECK(allocations_.empty());
- DCHECK_EQ(0u, bytes_allocated_);
-}
-
-void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
- AutoLock lock(lock_);
- memory_limit_ = bytes;
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
- Now(), memory_limit_);
-}
-
-void DiscardableMemoryManager::SetSoftMemoryLimit(size_t bytes) {
- AutoLock lock(lock_);
- soft_memory_limit_ = bytes;
-}
-
-void DiscardableMemoryManager::SetHardMemoryLimitExpirationTime(
- TimeDelta hard_memory_limit_expiration_time) {
- AutoLock lock(lock_);
- hard_memory_limit_expiration_time_ = hard_memory_limit_expiration_time;
-}
-
-void DiscardableMemoryManager::ReleaseFreeMemory() {
- TRACE_EVENT0("base", "DiscardableMemoryManager::ReleaseFreeMemory");
-
- AutoLock lock(lock_);
- size_t bytes_allocated_before_releasing_memory = bytes_allocated_;
- for (auto& entry : allocations_) {
- Allocation* allocation = entry.first;
- AllocationInfo* info = &entry.second;
-
- if (!info->purgable)
- continue;
-
- // Skip if memory is still resident, otherwise purge and adjust
- // |bytes_allocated_|.
- if (allocation->IsMemoryResident())
- continue;
-
- size_t bytes_purgable = info->bytes;
- DCHECK_LE(bytes_purgable, bytes_allocated_);
- bytes_allocated_ -= bytes_purgable;
- info->purgable = false;
- allocation->Purge();
- }
-
- if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
- BytesAllocatedChanged(bytes_allocated_);
-}
-
-bool DiscardableMemoryManager::ReduceMemoryUsage() {
- return PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
-}
-
-void DiscardableMemoryManager::ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
- AutoLock lock(lock_);
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(),
- bytes);
-}
-
-void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) {
- AutoLock lock(lock_);
- DCHECK(allocations_.Peek(allocation) == allocations_.end());
- allocations_.Put(allocation, AllocationInfo(bytes));
-}
-
-void DiscardableMemoryManager::Unregister(Allocation* allocation) {
- AutoLock lock(lock_);
- AllocationMap::iterator it = allocations_.Peek(allocation);
- DCHECK(it != allocations_.end());
- const AllocationInfo& info = it->second;
-
- if (info.purgable) {
- size_t bytes_purgable = info.bytes;
- DCHECK_LE(bytes_purgable, bytes_allocated_);
- bytes_allocated_ -= bytes_purgable;
- BytesAllocatedChanged(bytes_allocated_);
- }
- allocations_.Erase(it);
-}
-
-bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
- bool* purged) {
- AutoLock lock(lock_);
- // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
- // cache.
- AllocationMap::iterator it = allocations_.Get(allocation);
- DCHECK(it != allocations_.end());
- AllocationInfo* info = &it->second;
-
- if (!info->bytes)
- return false;
-
- TimeTicks now = Now();
- size_t bytes_required = info->purgable ? 0u : info->bytes;
-
- if (memory_limit_) {
- size_t limit = 0;
- if (bytes_required < memory_limit_)
- limit = memory_limit_ - bytes_required;
-
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(now,
- limit);
- }
-
- // Check for overflow.
- if (std::numeric_limits<size_t>::max() - bytes_required < bytes_allocated_)
- return false;
-
- *purged = !allocation->AllocateAndAcquireLock();
- info->purgable = false;
- info->last_usage = now;
- if (bytes_required) {
- bytes_allocated_ += bytes_required;
- BytesAllocatedChanged(bytes_allocated_);
- }
- return true;
-}
-
-void DiscardableMemoryManager::ReleaseLock(Allocation* allocation) {
- AutoLock lock(lock_);
- // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
- // cache.
- AllocationMap::iterator it = allocations_.Get(allocation);
- DCHECK(it != allocations_.end());
- AllocationInfo* info = &it->second;
-
- TimeTicks now = Now();
- allocation->ReleaseLock();
- info->purgable = true;
- info->last_usage = now;
-
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
- now, memory_limit_);
-}
-
-void DiscardableMemoryManager::PurgeAll() {
- AutoLock lock(lock_);
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(), 0);
-}
-
-bool DiscardableMemoryManager::IsRegisteredForTest(
- Allocation* allocation) const {
- AutoLock lock(lock_);
- AllocationMap::const_iterator it = allocations_.Peek(allocation);
- return it != allocations_.end();
-}
-
-bool DiscardableMemoryManager::CanBePurgedForTest(
- Allocation* allocation) const {
- AutoLock lock(lock_);
- AllocationMap::const_iterator it = allocations_.Peek(allocation);
- return it != allocations_.end() && it->second.purgable;
-}
-
-size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
- AutoLock lock(lock_);
- return bytes_allocated_;
-}
-
-bool DiscardableMemoryManager::
- PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit() {
- AutoLock lock(lock_);
-
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
- Now() - hard_memory_limit_expiration_time_, soft_memory_limit_);
-
- return bytes_allocated_ <= soft_memory_limit_;
-}
-
-void DiscardableMemoryManager::
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
- TimeTicks timestamp,
- size_t limit) {
- lock_.AssertAcquired();
-
- size_t bytes_allocated_before_purging = bytes_allocated_;
- for (auto& entry : base::Reversed(allocations_)) {
- Allocation* allocation = entry.first;
- AllocationInfo* info = &entry.second;
-
- if (bytes_allocated_ <= limit)
- break;
-
- bool purgable = info->purgable && info->last_usage <= timestamp;
- if (!purgable)
- continue;
-
- size_t bytes_purgable = info->bytes;
- DCHECK_LE(bytes_purgable, bytes_allocated_);
- bytes_allocated_ -= bytes_purgable;
- info->purgable = false;
- allocation->Purge();
- }
-
- if (bytes_allocated_ != bytes_allocated_before_purging)
- BytesAllocatedChanged(bytes_allocated_);
-}
-
-void DiscardableMemoryManager::BytesAllocatedChanged(
- size_t new_bytes_allocated) const {
- TRACE_COUNTER_ID1(
- "base", "DiscardableMemoryUsage", this, new_bytes_allocated);
-
- static const char kDiscardableMemoryUsageKey[] = "dm-usage";
- base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey,
- Uint64ToString(new_bytes_allocated));
-}
-
-TimeTicks DiscardableMemoryManager::Now() const {
- return TimeTicks::Now();
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_manager.h b/chromium/base/memory/discardable_memory_manager.h
deleted file mode 100644
index 8bf92891a3e..00000000000
--- a/chromium/base/memory/discardable_memory_manager.h
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2014 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_MEMORY_DISCARDABLE_MEMORY_MANAGER_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_MANAGER_H_
-
-#include "base/base_export.h"
-#include "base/containers/hash_tables.h"
-#include "base/containers/mru_cache.h"
-#include "base/synchronization/lock.h"
-#include "base/time/time.h"
-
-namespace base {
-namespace internal {
-
-// This interface is used by the DiscardableMemoryManager class to provide some
-// level of userspace control over discardable memory allocations.
-class DiscardableMemoryManagerAllocation {
- public:
- // Allocate and acquire a lock that prevents the allocation from being purged
- // by the system. Returns true if memory was previously allocated and is still
- // resident.
- virtual bool AllocateAndAcquireLock() = 0;
-
- // Release a previously acquired lock on the allocation so that it can be
- // purged by the system.
- virtual void ReleaseLock() = 0;
-
- // Explicitly purge this allocation. It is illegal to call this while a lock
- // is acquired on the allocation.
- virtual void Purge() = 0;
-
- // Check if allocated memory is still resident. It is illegal to call this
- // while a lock is acquired on the allocation.
- virtual bool IsMemoryResident() const = 0;
-
- protected:
- virtual ~DiscardableMemoryManagerAllocation() {}
-};
-
-} // namespace internal
-} // namespace base
-
-namespace base {
-namespace internal {
-
-// The DiscardableMemoryManager manages a collection of
-// DiscardableMemoryManagerAllocation instances. It is used on platforms that
-// need some level of userspace control over discardable memory. It keeps track
-// of all allocation instances (in case they need to be purged), and the total
-// amount of allocated memory (in case this forces a purge). When memory usage
-// reaches the limit, the manager purges the LRU memory.
-class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
- public:
- typedef DiscardableMemoryManagerAllocation Allocation;
-
- DiscardableMemoryManager(size_t memory_limit,
- size_t soft_memory_limit,
- TimeDelta hard_memory_limit_expiration_time);
- virtual ~DiscardableMemoryManager();
-
- // The maximum number of bytes of memory that may be allocated before we force
- // a purge.
- void SetMemoryLimit(size_t bytes);
-
- // The number of bytes of memory that may be allocated but unused for the hard
- // limit expiration time without getting purged.
- void SetSoftMemoryLimit(size_t bytes);
-
- // Sets the memory usage cutoff time for hard memory limit.
- void SetHardMemoryLimitExpirationTime(
- TimeDelta hard_memory_limit_expiration_time);
-
- // This will make sure that all purged memory is released to the OS.
- void ReleaseFreeMemory();
-
- // This will attempt to reduce memory footprint until within soft memory
- // limit. Returns true if there's no need to call this again until allocations
- // have been used.
- bool ReduceMemoryUsage();
-
- // This can be called to attempt to reduce memory footprint until within
- // limit for bytes to keep under moderate pressure.
- void ReduceMemoryUsageUntilWithinLimit(size_t bytes);
-
- // Adds the given allocation to the manager's collection.
- void Register(Allocation* allocation, size_t bytes);
-
- // Removes the given allocation from the manager's collection.
- void Unregister(Allocation* allocation);
-
- // Returns false if an error occurred. Otherwise, returns true and sets
- // |purged| to indicate whether or not allocation has been purged since last
- // use.
- bool AcquireLock(Allocation* allocation, bool* purged);
-
- // Release a previously acquired lock on allocation. This allows the manager
- // to purge it if necessary.
- void ReleaseLock(Allocation* allocation);
-
- // Purges all discardable memory.
- void PurgeAll();
-
- // Returns true if allocation has been added to the manager's collection. This
- // should only be used by tests.
- bool IsRegisteredForTest(Allocation* allocation) const;
-
- // Returns true if allocation can be purged. This should only be used by
- // tests.
- bool CanBePurgedForTest(Allocation* allocation) const;
-
- // Returns total amount of allocated discardable memory. This should only be
- // used by tests.
- size_t GetBytesAllocatedForTest() const;
-
- private:
- struct AllocationInfo {
- explicit AllocationInfo(size_t bytes) : bytes(bytes), purgable(false) {}
-
- const size_t bytes;
- bool purgable;
- TimeTicks last_usage;
- };
- typedef HashingMRUCache<Allocation*, AllocationInfo> AllocationMap;
-
- // Purges memory not used since |hard_memory_limit_expiration_time_| before
- // "right now" until usage is less or equal to |soft_memory_limit_|.
- // Returns true if total amount of memory is less or equal to soft memory
- // limit.
- bool PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
-
- // Purges memory that has not been used since |timestamp| until usage is less
- // or equal to |limit|.
- // Caller must acquire |lock_| prior to calling this function.
- void PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
- TimeTicks timestamp,
- size_t limit);
-
- // Called when a change to |bytes_allocated_| has been made.
- void BytesAllocatedChanged(size_t new_bytes_allocated) const;
-
- // Virtual for tests.
- virtual TimeTicks Now() const;
-
- // Needs to be held when accessing members.
- mutable Lock lock_;
-
- // A MRU cache of all allocated bits of memory. Used for purging.
- AllocationMap allocations_;
-
- // The total amount of allocated memory.
- size_t bytes_allocated_;
-
- // The maximum number of bytes of memory that may be allocated.
- size_t memory_limit_;
-
- // The number of bytes of memory that may be allocated but not used for
- // |hard_memory_limit_expiration_time_| amount of time when receiving an idle
- // notification.
- size_t soft_memory_limit_;
-
- // Amount of time it takes for an allocation to become affected by
- // |soft_memory_limit_|.
- TimeDelta hard_memory_limit_expiration_time_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryManager);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_MANAGER_H_
diff --git a/chromium/base/memory/discardable_memory_manager_unittest.cc b/chromium/base/memory/discardable_memory_manager_unittest.cc
deleted file mode 100644
index 12f7f0816a5..00000000000
--- a/chromium/base/memory/discardable_memory_manager_unittest.cc
+++ /dev/null
@@ -1,494 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_manager.h"
-
-#include "base/bind.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace {
-
-class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation {
- public:
- TestAllocationImpl() : is_allocated_(false), is_locked_(false) {}
- ~TestAllocationImpl() override { DCHECK(!is_locked_); }
-
- // Overridden from internal::DiscardableMemoryManagerAllocation:
- bool AllocateAndAcquireLock() override {
- bool was_allocated = is_allocated_;
- is_allocated_ = true;
- DCHECK(!is_locked_);
- is_locked_ = true;
- return was_allocated;
- }
- void ReleaseLock() override {
- DCHECK(is_locked_);
- is_locked_ = false;
- }
- void Purge() override {
- DCHECK(is_allocated_);
- is_allocated_ = false;
- }
- virtual bool IsMemoryResident() const override {
- DCHECK(is_allocated_);
- return true;
- }
-
- bool is_locked() const { return is_locked_; }
-
- private:
- bool is_allocated_;
- bool is_locked_;
-};
-
-// Tests can assume that the default limit is at least 1024. Tests that rely on
-// something else needs to explicit set the limit.
-const size_t kDefaultMemoryLimit = 1024;
-const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit;
-
-class TestDiscardableMemoryManagerImpl
- : public internal::DiscardableMemoryManager {
- public:
- TestDiscardableMemoryManagerImpl()
- : DiscardableMemoryManager(kDefaultMemoryLimit,
- kDefaultSoftMemoryLimit,
- TimeDelta::Max()) {}
-
- void SetNow(TimeTicks now) { now_ = now; }
-
- private:
- // Overriden from internal::DiscardableMemoryManager:
- TimeTicks Now() const override { return now_; }
-
- TimeTicks now_;
-};
-
-class DiscardableMemoryManagerTestBase {
- public:
- DiscardableMemoryManagerTestBase() {}
-
- protected:
- enum LockStatus {
- LOCK_STATUS_FAILED,
- LOCK_STATUS_PURGED,
- LOCK_STATUS_SUCCESS
- };
-
- size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); }
-
- void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); }
-
- void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); }
-
- void SetHardMemoryLimitExpirationTime(TimeDelta time) {
- manager_.SetHardMemoryLimitExpirationTime(time);
- }
-
- void Register(TestAllocationImpl* allocation, size_t bytes) {
- manager_.Register(allocation, bytes);
- }
-
- void Unregister(TestAllocationImpl* allocation) {
- manager_.Unregister(allocation);
- }
-
- bool IsRegistered(TestAllocationImpl* allocation) const {
- return manager_.IsRegisteredForTest(allocation);
- }
-
- LockStatus Lock(TestAllocationImpl* allocation) {
- bool purged;
- if (!manager_.AcquireLock(allocation, &purged))
- return LOCK_STATUS_FAILED;
- return purged ? LOCK_STATUS_PURGED : LOCK_STATUS_SUCCESS;
- }
-
- void Unlock(TestAllocationImpl* allocation) {
- manager_.ReleaseLock(allocation);
- }
-
- LockStatus RegisterAndLock(TestAllocationImpl* allocation, size_t bytes) {
- manager_.Register(allocation, bytes);
- return Lock(allocation);
- }
-
- bool CanBePurged(TestAllocationImpl* allocation) const {
- return manager_.CanBePurgedForTest(allocation);
- }
-
- void SetNow(TimeTicks now) { manager_.SetNow(now); }
-
- void PurgeAll() { return manager_.PurgeAll(); }
-
- bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); }
-
- void ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
- manager_.ReduceMemoryUsageUntilWithinLimit(bytes);
- }
-
- private:
- TestDiscardableMemoryManagerImpl manager_;
-};
-
-class DiscardableMemoryManagerTest : public DiscardableMemoryManagerTestBase,
- public testing::Test {
- public:
- DiscardableMemoryManagerTest() {}
-};
-
-TEST_F(DiscardableMemoryManagerTest, CreateAndLock) {
- size_t size = 1024;
- TestAllocationImpl allocation;
- Register(&allocation, size);
- EXPECT_TRUE(IsRegistered(&allocation));
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
- EXPECT_TRUE(allocation.is_locked());
- EXPECT_EQ(1024u, BytesAllocated());
- EXPECT_FALSE(CanBePurged(&allocation));
- Unlock(&allocation);
- Unregister(&allocation);
-}
-
-TEST_F(DiscardableMemoryManagerTest, CreateZeroSize) {
- size_t size = 0;
- TestAllocationImpl allocation;
- Register(&allocation, size);
- EXPECT_TRUE(IsRegistered(&allocation));
- EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&allocation));
- EXPECT_EQ(0u, BytesAllocated());
- Unregister(&allocation);
-}
-
-TEST_F(DiscardableMemoryManagerTest, LockAfterUnlock) {
- size_t size = 1024;
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- EXPECT_EQ(1024u, BytesAllocated());
- EXPECT_FALSE(CanBePurged(&allocation));
-
- // Now unlock so we can lock later.
- Unlock(&allocation);
- EXPECT_TRUE(CanBePurged(&allocation));
-
- EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(&allocation));
- EXPECT_FALSE(CanBePurged(&allocation));
- Unlock(&allocation);
- Unregister(&allocation);
-}
-
-TEST_F(DiscardableMemoryManagerTest, LockAfterPurge) {
- size_t size = 1024;
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- EXPECT_EQ(1024u, BytesAllocated());
- EXPECT_FALSE(CanBePurged(&allocation));
-
- // Now unlock so we can lock later.
- Unlock(&allocation);
- EXPECT_TRUE(CanBePurged(&allocation));
-
- // Force the system to purge.
- PurgeAll();
-
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
- EXPECT_FALSE(CanBePurged(&allocation));
-
- Unlock(&allocation);
- Unregister(&allocation);
-}
-
-TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) {
- size_t size = 1024;
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- EXPECT_EQ(1024u, BytesAllocated());
- EXPECT_FALSE(CanBePurged(&allocation));
-
- // Now unlock so we can lock later.
- Unlock(&allocation);
- EXPECT_TRUE(CanBePurged(&allocation));
-
- // Set max allowed allocation to 1 byte. This will cause the memory to be
- // purged.
- SetMemoryLimit(1);
-
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
- EXPECT_FALSE(CanBePurged(&allocation));
-
- Unlock(&allocation);
- Unregister(&allocation);
-}
-
-TEST_F(DiscardableMemoryManagerTest, Overflow) {
- size_t size = 1024;
- {
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- EXPECT_EQ(1024u, BytesAllocated());
-
- size_t massive_size = std::numeric_limits<size_t>::max();
- TestAllocationImpl massive_allocation;
- Register(&massive_allocation, massive_size);
- EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&massive_allocation));
- EXPECT_EQ(1024u, BytesAllocated());
-
- Unlock(&allocation);
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&massive_allocation));
- Unlock(&massive_allocation);
- Unregister(&massive_allocation);
- Unregister(&allocation);
- }
- EXPECT_EQ(0u, BytesAllocated());
-}
-
-class PermutationTestData {
- public:
- PermutationTestData(unsigned d0, unsigned d1, unsigned d2) {
- ordering_[0] = d0;
- ordering_[1] = d1;
- ordering_[2] = d2;
- }
-
- const unsigned* ordering() const { return ordering_; }
-
- private:
- unsigned ordering_[3];
-};
-
-class DiscardableMemoryManagerPermutationTest
- : public DiscardableMemoryManagerTestBase,
- public testing::TestWithParam<PermutationTestData> {
- public:
- DiscardableMemoryManagerPermutationTest() {}
-
- protected:
- // Use memory in order specified by ordering parameter.
- void RegisterAndUseAllocations() {
- for (int i = 0; i < 3; ++i) {
- RegisterAndLock(&allocation_[i], 1024);
- Unlock(&allocation_[i]);
- }
- for (int i = 0; i < 3; ++i) {
- int index = GetParam().ordering()[i];
- EXPECT_NE(LOCK_STATUS_FAILED, Lock(&allocation_[index]));
- // Leave i == 0 locked.
- if (i > 0)
- Unlock(&allocation_[index]);
- }
- }
-
- TestAllocationImpl* allocation(unsigned position) {
- return &allocation_[GetParam().ordering()[position]];
- }
-
- void UnlockAndUnregisterAllocations() {
- for (int i = 0; i < 3; ++i) {
- if (allocation_[i].is_locked())
- Unlock(&allocation_[i]);
- Unregister(&allocation_[i]);
- }
- }
-
- private:
- TestAllocationImpl allocation_[3];
-};
-
-// Verify that memory was discarded in the correct order after reducing usage to
-// limit.
-TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscarded) {
- RegisterAndUseAllocations();
-
- SetMemoryLimit(2048);
-
- ReduceMemoryUsageUntilWithinLimit(1024);
-
- EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
- // 0 should still be locked.
- EXPECT_TRUE(allocation(0)->is_locked());
-
- UnlockAndUnregisterAllocations();
-}
-
-// Verify that memory was discarded in the correct order after changing
-// memory limit.
-TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
- RegisterAndUseAllocations();
-
- SetMemoryLimit(2048);
-
- EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
- // 0 should still be locked.
- EXPECT_TRUE(allocation(0)->is_locked());
-
- UnlockAndUnregisterAllocations();
-}
-
-// Verify that no more memory than necessary was discarded after changing
-// memory limit.
-TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
- SetMemoryLimit(4096);
-
- RegisterAndUseAllocations();
-
- SetMemoryLimit(2048);
-
- EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(allocation(2)));
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
- // 0 should still be locked.
- EXPECT_TRUE(allocation(0)->is_locked());
-
- UnlockAndUnregisterAllocations();
-}
-
-TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) {
- RegisterAndUseAllocations();
-
- PurgeAll();
-
- for (int i = 0; i < 3; ++i) {
- if (i == 0)
- EXPECT_TRUE(allocation(i)->is_locked());
- else
- EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(i)));
- }
-
- UnlockAndUnregisterAllocations();
-}
-
-INSTANTIATE_TEST_CASE_P(DiscardableMemoryManagerPermutationTests,
- DiscardableMemoryManagerPermutationTest,
- ::testing::Values(PermutationTestData(0, 1, 2),
- PermutationTestData(0, 2, 1),
- PermutationTestData(1, 0, 2),
- PermutationTestData(1, 2, 0),
- PermutationTestData(2, 0, 1),
- PermutationTestData(2, 1, 0)));
-
-TEST_F(DiscardableMemoryManagerTest, NormalDestruction) {
- {
- size_t size = 1024;
- TestAllocationImpl allocation;
- Register(&allocation, size);
- Unregister(&allocation);
- }
- EXPECT_EQ(0u, BytesAllocated());
-}
-
-TEST_F(DiscardableMemoryManagerTest, DestructionAfterLocked) {
- {
- size_t size = 1024;
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- EXPECT_EQ(1024u, BytesAllocated());
- EXPECT_FALSE(CanBePurged(&allocation));
- Unlock(&allocation);
- Unregister(&allocation);
- }
- EXPECT_EQ(0u, BytesAllocated());
-}
-
-TEST_F(DiscardableMemoryManagerTest, DestructionAfterPurged) {
- {
- size_t size = 1024;
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- EXPECT_EQ(1024u, BytesAllocated());
- Unlock(&allocation);
- EXPECT_TRUE(CanBePurged(&allocation));
- SetMemoryLimit(0);
- EXPECT_EQ(0u, BytesAllocated());
- Unregister(&allocation);
- }
- EXPECT_EQ(0u, BytesAllocated());
-}
-
-TEST_F(DiscardableMemoryManagerTest, ReduceMemoryUsage) {
- SetMemoryLimit(3072);
- SetSoftMemoryLimit(1024);
- SetHardMemoryLimitExpirationTime(TimeDelta::FromInternalValue(1));
-
- size_t size = 1024;
- TestAllocationImpl allocation[3];
- RegisterAndLock(&allocation[0], size);
- RegisterAndLock(&allocation[1], size);
- RegisterAndLock(&allocation[2], size);
- EXPECT_EQ(3072u, BytesAllocated());
-
- // Above soft limit but nothing that can be purged.
- EXPECT_FALSE(ReduceMemoryUsage());
-
- SetNow(TimeTicks::FromInternalValue(0));
- Unlock(&allocation[0]);
-
- // Above soft limit but still nothing that can be purged as all unlocked
- // allocations are within the hard limit cutoff time.
- EXPECT_FALSE(ReduceMemoryUsage());
-
- SetNow(TimeTicks::FromInternalValue(1));
- Unlock(&allocation[1]);
-
- // One unlocked allocation is no longer within the hard limit cutoff time. It
- // should be purged and ReduceMemoryUsage() should return false as we're not
- // yet within the soft memory limit.
- EXPECT_FALSE(ReduceMemoryUsage());
- EXPECT_EQ(2048u, BytesAllocated());
-
- // One more unlocked allocation is no longer within the hard limit cutoff
- // time. It should be purged and ReduceMemoryUsage() should return true as
- // we're now within the soft memory limit.
- SetNow(TimeTicks::FromInternalValue(2));
- EXPECT_TRUE(ReduceMemoryUsage());
- EXPECT_EQ(1024u, BytesAllocated());
-
- Unlock(&allocation[2]);
-
- Unregister(&allocation[0]);
- Unregister(&allocation[1]);
- Unregister(&allocation[2]);
-}
-
-class ThreadedDiscardableMemoryManagerTest
- : public DiscardableMemoryManagerTest {
- public:
- ThreadedDiscardableMemoryManagerTest()
- : memory_usage_thread_("memory_usage_thread"),
- thread_sync_(true, false) {}
-
- virtual void SetUp() override { memory_usage_thread_.Start(); }
-
- virtual void TearDown() override { memory_usage_thread_.Stop(); }
-
- void UseMemoryHelper() {
- size_t size = 1024;
- TestAllocationImpl allocation;
- RegisterAndLock(&allocation, size);
- Unlock(&allocation);
- Unregister(&allocation);
- }
-
- void SignalHelper() { thread_sync_.Signal(); }
-
- Thread memory_usage_thread_;
- WaitableEvent thread_sync_;
-};
-
-TEST_F(ThreadedDiscardableMemoryManagerTest, UseMemoryOnThread) {
- memory_usage_thread_.message_loop()->PostTask(
- FROM_HERE,
- Bind(&ThreadedDiscardableMemoryManagerTest::UseMemoryHelper,
- Unretained(this)));
- memory_usage_thread_.message_loop()->PostTask(
- FROM_HERE,
- Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper,
- Unretained(this)));
- thread_sync_.Wait();
-}
-
-} // namespace
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_shmem.cc b/chromium/base/memory/discardable_memory_shmem.cc
deleted file mode 100644
index 77699f0739f..00000000000
--- a/chromium/base/memory/discardable_memory_shmem.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_shmem.h"
-
-#include "base/lazy_instance.h"
-#include "base/memory/discardable_memory_shmem_allocator.h"
-#include "base/memory/discardable_shared_memory.h"
-
-namespace base {
-namespace {
-
-// Have the DiscardableMemoryManager trigger in-process eviction
-// when address space usage gets too high (e.g. 512 MBytes).
-const size_t kMemoryLimit = 512 * 1024 * 1024;
-
-// internal::DiscardableMemoryManager has an explicit constructor that takes
-// a number of memory limit parameters. The LeakyLazyInstanceTraits doesn't
-// handle the case. Thus, we need our own class here.
-struct DiscardableMemoryManagerLazyInstanceTraits {
- // Leaky as discardable memory clients can use this after the exit handler
- // has been called.
- static const bool kRegisterOnExit = false;
-#ifndef NDEBUG
- static const bool kAllowedToAccessOnNonjoinableThread = true;
-#endif
-
- static internal::DiscardableMemoryManager* New(void* instance) {
- return new (instance) internal::DiscardableMemoryManager(
- kMemoryLimit, kMemoryLimit, TimeDelta::Max());
- }
- static void Delete(internal::DiscardableMemoryManager* instance) {
- instance->~DiscardableMemoryManager();
- }
-};
-
-LazyInstance<internal::DiscardableMemoryManager,
- DiscardableMemoryManagerLazyInstanceTraits> g_manager =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-namespace internal {
-
-DiscardableMemoryShmem::DiscardableMemoryShmem(size_t bytes)
- : bytes_(bytes), is_locked_(false) {
- g_manager.Pointer()->Register(this, bytes);
-}
-
-DiscardableMemoryShmem::~DiscardableMemoryShmem() {
- if (is_locked_)
- Unlock();
- g_manager.Pointer()->Unregister(this);
-}
-
-// static
-void DiscardableMemoryShmem::ReleaseFreeMemory() {
- g_manager.Pointer()->ReleaseFreeMemory();
-}
-
-// static
-void DiscardableMemoryShmem::PurgeForTesting() {
- g_manager.Pointer()->PurgeAll();
-}
-
-bool DiscardableMemoryShmem::Initialize() {
- return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-}
-
-DiscardableMemoryLockStatus DiscardableMemoryShmem::Lock() {
- DCHECK(!is_locked_);
-
- bool purged = false;
- if (!g_manager.Pointer()->AcquireLock(this, &purged))
- return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
-
- is_locked_ = true;
- return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
- : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
-}
-
-void DiscardableMemoryShmem::Unlock() {
- DCHECK(is_locked_);
- g_manager.Pointer()->ReleaseLock(this);
- is_locked_ = false;
-}
-
-void* DiscardableMemoryShmem::Memory() const {
- DCHECK(is_locked_);
- DCHECK(shared_memory_);
- return shared_memory_->memory();
-}
-
-bool DiscardableMemoryShmem::AllocateAndAcquireLock() {
- if (shared_memory_ && shared_memory_->Lock())
- return true;
-
- // TODO(reveman): Allocate fixed size memory segments and use a free list to
- // improve performance and limit the number of file descriptors used.
- shared_memory_ = DiscardableMemoryShmemAllocator::GetInstance()
- ->AllocateLockedDiscardableSharedMemory(bytes_);
- DCHECK(shared_memory_);
- return false;
-}
-
-void DiscardableMemoryShmem::ReleaseLock() {
- shared_memory_->Unlock();
-}
-
-void DiscardableMemoryShmem::Purge() {
- shared_memory_->Purge(Time());
- shared_memory_.reset();
-}
-
-bool DiscardableMemoryShmem::IsMemoryResident() const {
- return shared_memory_->IsMemoryResident();
-}
-
-} // namespace internal
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_shmem.h b/chromium/base/memory/discardable_memory_shmem.h
deleted file mode 100644
index d25f84cb46d..00000000000
--- a/chromium/base/memory/discardable_memory_shmem.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 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_MEMORY_DISCARDABLE_MEMORY_SHMEM_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_H_
-
-#include "base/memory/discardable_memory.h"
-
-#include "base/memory/discardable_memory_manager.h"
-
-namespace base {
-class DiscardableSharedMemory;
-
-namespace internal {
-
-class DiscardableMemoryShmem
- : public DiscardableMemory,
- public internal::DiscardableMemoryManagerAllocation {
- public:
- explicit DiscardableMemoryShmem(size_t bytes);
- virtual ~DiscardableMemoryShmem();
-
- static void ReleaseFreeMemory();
-
- static void PurgeForTesting();
-
- bool Initialize();
-
- // Overridden from DiscardableMemory:
- virtual DiscardableMemoryLockStatus Lock() override;
- virtual void Unlock() override;
- virtual void* Memory() const override;
-
- // Overridden from internal::DiscardableMemoryManagerAllocation:
- virtual bool AllocateAndAcquireLock() override;
- virtual void ReleaseLock() override;
- virtual void Purge() override;
- virtual bool IsMemoryResident() const override;
-
- private:
- const size_t bytes_;
- scoped_ptr<DiscardableSharedMemory> shared_memory_;
- bool is_locked_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmem);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_H_
diff --git a/chromium/base/memory/discardable_memory_shmem_allocator.cc b/chromium/base/memory/discardable_memory_shmem_allocator.cc
deleted file mode 100644
index 78d15c1031e..00000000000
--- a/chromium/base/memory/discardable_memory_shmem_allocator.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 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/memory/discardable_memory_shmem_allocator.h"
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/discardable_shared_memory.h"
-
-namespace base {
-namespace {
-
-// Default allocator implementation that allocates in-process
-// DiscardableSharedMemory instances.
-class DiscardableMemoryShmemAllocatorImpl
- : public DiscardableMemoryShmemAllocator {
- public:
- // Overridden from DiscardableMemoryShmemAllocator:
- virtual scoped_ptr<DiscardableSharedMemory>
- AllocateLockedDiscardableSharedMemory(size_t size) override {
- scoped_ptr<DiscardableSharedMemory> memory(new DiscardableSharedMemory);
- if (!memory->CreateAndMap(size))
- return scoped_ptr<DiscardableSharedMemory>();
-
- return memory.Pass();
- }
-};
-
-LazyInstance<DiscardableMemoryShmemAllocatorImpl>::Leaky g_default_allocator =
- LAZY_INSTANCE_INITIALIZER;
-
-DiscardableMemoryShmemAllocator* g_allocator = nullptr;
-
-} // namespace
-
-// static
-void DiscardableMemoryShmemAllocator::SetInstance(
- DiscardableMemoryShmemAllocator* allocator) {
- DCHECK(allocator);
-
- // Make sure this function is only called once before the first call
- // to GetInstance().
- DCHECK(!g_allocator);
-
- g_allocator = allocator;
-}
-
-// static
-DiscardableMemoryShmemAllocator*
-DiscardableMemoryShmemAllocator::GetInstance() {
- if (!g_allocator)
- g_allocator = g_default_allocator.Pointer();
-
- return g_allocator;
-}
-
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_shmem_allocator.h b/chromium/base/memory/discardable_memory_shmem_allocator.h
deleted file mode 100644
index 68624b3960b..00000000000
--- a/chromium/base/memory/discardable_memory_shmem_allocator.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 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_MEMORY_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
-
-#include "base/base_export.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace base {
-class DiscardableSharedMemory;
-
-class BASE_EXPORT DiscardableMemoryShmemAllocator {
- public:
- // Returns the allocator instance.
- static DiscardableMemoryShmemAllocator* GetInstance();
-
- // Sets the allocator instance. Can only be called once, e.g. on startup.
- // Ownership of |instance| remains with the caller.
- static void SetInstance(DiscardableMemoryShmemAllocator* allocator);
-
- virtual scoped_ptr<DiscardableSharedMemory>
- AllocateLockedDiscardableSharedMemory(size_t size) = 0;
-
- protected:
- virtual ~DiscardableMemoryShmemAllocator() {}
-};
-
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
diff --git a/chromium/base/memory/discardable_memory_unittest.cc b/chromium/base/memory/discardable_memory_unittest.cc
deleted file mode 100644
index 600475ee06b..00000000000
--- a/chromium/base/memory/discardable_memory_unittest.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 2013 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/memory/discardable_memory.h"
-
-#include <algorithm>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_ANDROID)
-#include <limits>
-#endif
-
-namespace base {
-namespace {
-
-class DiscardableMemoryTest
- : public testing::TestWithParam<DiscardableMemoryType> {
- public:
- DiscardableMemoryTest() {}
- virtual ~DiscardableMemoryTest() {
- }
-
- protected:
- scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size) {
- return DiscardableMemory::CreateLockedMemoryWithType(
- GetParam(), size).Pass();
- }
-};
-
-const size_t kSize = 1024;
-
-TEST_P(DiscardableMemoryTest, IsNamed) {
- std::string type_name(DiscardableMemory::GetTypeName(GetParam()));
- EXPECT_NE("unknown", type_name);
- EXPECT_EQ(GetParam(), DiscardableMemory::GetNamedType(type_name));
-}
-
-bool IsNativeType(DiscardableMemoryType type) {
- return type == DISCARDABLE_MEMORY_TYPE_ASHMEM ||
- type == DISCARDABLE_MEMORY_TYPE_MACH;
-}
-
-TEST_P(DiscardableMemoryTest, SupportedNatively) {
- std::vector<DiscardableMemoryType> supported_types;
- DiscardableMemory::GetSupportedTypes(&supported_types);
-#if defined(DISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY)
- EXPECT_NE(0, std::count_if(supported_types.begin(),
- supported_types.end(),
- IsNativeType));
-#else
- // If we ever have a platform that decides at runtime if it can support
- // discardable memory natively, then we'll have to add a 'never supported
- // natively' define for this case. At present, if it's not always supported
- // natively, it's never supported.
- EXPECT_EQ(0, std::count_if(supported_types.begin(),
- supported_types.end(),
- IsNativeType));
-#endif
-}
-
-// Test Lock() and Unlock() functionalities.
-TEST_P(DiscardableMemoryTest, LockAndUnLock) {
- const scoped_ptr<DiscardableMemory> memory(CreateLockedMemory(kSize));
- ASSERT_TRUE(memory);
- void* addr = memory->Memory();
- ASSERT_NE(nullptr, addr);
-
- memory->Unlock();
-
- EXPECT_NE(DISCARDABLE_MEMORY_LOCK_STATUS_FAILED, memory->Lock());
- addr = memory->Memory();
- ASSERT_NE(nullptr, addr);
-
- memory->Unlock();
-}
-
-// Test delete a discardable memory while it is locked.
-TEST_P(DiscardableMemoryTest, DeleteWhileLocked) {
- const scoped_ptr<DiscardableMemory> memory(CreateLockedMemory(kSize));
- ASSERT_TRUE(memory);
-}
-
-// Test forced purging.
-TEST_P(DiscardableMemoryTest, Purge) {
- const scoped_ptr<DiscardableMemory> memory(CreateLockedMemory(kSize));
- ASSERT_TRUE(memory);
- memory->Unlock();
-
- DiscardableMemory::PurgeForTesting();
- EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_PURGED, memory->Lock());
-}
-
-#if !defined(NDEBUG) && !defined(OS_ANDROID)
-// Death tests are not supported with Android APKs.
-TEST_P(DiscardableMemoryTest, UnlockedMemoryAccessCrashesInDebugMode) {
- const scoped_ptr<DiscardableMemory> memory(CreateLockedMemory(kSize));
- ASSERT_TRUE(memory);
- memory->Unlock();
- ASSERT_DEATH_IF_SUPPORTED(
- { *static_cast<int*>(memory->Memory()) = 0xdeadbeef; }, ".*");
-}
-#endif
-
-// Test behavior when creating enough instances that could use up a 32-bit
-// address space.
-TEST_P(DiscardableMemoryTest, AddressSpace) {
- const size_t kLargeSize = 4 * 1024 * 1024; // 4MiB.
- const size_t kNumberOfInstances = 1024 + 1; // >4GiB total.
-
- scoped_ptr<DiscardableMemory> instances[kNumberOfInstances];
- for (auto& memory : instances) {
- memory = CreateLockedMemory(kLargeSize);
- ASSERT_TRUE(memory);
- void* addr = memory->Memory();
- ASSERT_NE(nullptr, addr);
- memory->Unlock();
- }
-}
-
-std::vector<DiscardableMemoryType> GetSupportedDiscardableMemoryTypes() {
- std::vector<DiscardableMemoryType> supported_types;
- DiscardableMemory::GetSupportedTypes(&supported_types);
- return supported_types;
-}
-
-INSTANTIATE_TEST_CASE_P(
- DiscardableMemoryTests,
- DiscardableMemoryTest,
- ::testing::ValuesIn(GetSupportedDiscardableMemoryTypes()));
-
-} // namespace
-} // namespace base
diff --git a/chromium/base/memory/discardable_memory_win.cc b/chromium/base/memory/discardable_memory_win.cc
deleted file mode 100644
index 9b4e9401ce4..00000000000
--- a/chromium/base/memory/discardable_memory_win.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 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/memory/discardable_memory.h"
-
-#include "base/logging.h"
-#include "base/memory/discardable_memory_emulated.h"
-#include "base/memory/discardable_memory_shmem.h"
-
-namespace base {
-
-// static
-void DiscardableMemory::ReleaseFreeMemory() {
- internal::DiscardableMemoryShmem::ReleaseFreeMemory();
-}
-
-// static
-bool DiscardableMemory::ReduceMemoryUsage() {
- return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
-}
-
-// static
-void DiscardableMemory::GetSupportedTypes(
- std::vector<DiscardableMemoryType>* types) {
- const DiscardableMemoryType supported_types[] = {
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
- };
- types->assign(supported_types, supported_types + arraysize(supported_types));
-}
-
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
- DiscardableMemoryType type, size_t size) {
- switch (type) {
- case DISCARDABLE_MEMORY_TYPE_EMULATED: {
- scoped_ptr<internal::DiscardableMemoryEmulated> memory(
- new internal::DiscardableMemoryEmulated(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_SHMEM: {
- scoped_ptr<internal::DiscardableMemoryShmem> memory(
- new internal::DiscardableMemoryShmem(size));
- if (!memory->Initialize())
- return nullptr;
-
- return memory.Pass();
- }
- case DISCARDABLE_MEMORY_TYPE_NONE:
- case DISCARDABLE_MEMORY_TYPE_ASHMEM:
- case DISCARDABLE_MEMORY_TYPE_MACH:
- NOTREACHED();
- return nullptr;
- }
-
- NOTREACHED();
- return nullptr;
-}
-
-// static
-void DiscardableMemory::PurgeForTesting() {
- internal::DiscardableMemoryEmulated::PurgeForTesting();
- internal::DiscardableMemoryShmem::PurgeForTesting();
-}
-
-} // namespace base
diff --git a/chromium/base/memory/discardable_shared_memory.cc b/chromium/base/memory/discardable_shared_memory.cc
index 653304806ec..f8248e942cb 100644
--- a/chromium/base/memory/discardable_shared_memory.cc
+++ b/chromium/base/memory/discardable_shared_memory.cc
@@ -13,6 +13,11 @@
#include "base/atomicops.h"
#include "base/logging.h"
#include "base/numerics/safe_math.h"
+#include "base/process/process_metrics.h"
+
+#if defined(OS_ANDROID)
+#include "third_party/ashmem/ashmem.h"
+#endif
namespace base {
namespace {
@@ -59,7 +64,7 @@ struct SharedState {
SharedState(LockState lock_state, Time timestamp) {
int64 wire_timestamp = TimeToWireFormat<sizeof(AtomicType)>(timestamp);
DCHECK_GE(wire_timestamp, 0);
- DCHECK((lock_state & ~1) == 0);
+ DCHECK_EQ(lock_state & ~1, 0);
value.u = (static_cast<UAtomicType>(wire_timestamp) << 1) | lock_state;
}
@@ -84,14 +89,28 @@ SharedState* SharedStateFromSharedMemory(const SharedMemory& shared_memory) {
return static_cast<SharedState*>(shared_memory.memory());
}
+// Round up |size| to a multiple of alignment, which must be a power of two.
+size_t Align(size_t alignment, size_t size) {
+ DCHECK_EQ(alignment & (alignment - 1), 0u);
+ return (size + alignment - 1) & ~(alignment - 1);
+}
+
+// Round up |size| to a multiple of page size.
+size_t AlignToPageSize(size_t size) {
+ return Align(base::GetPageSize(), size);
+}
+
} // namespace
-DiscardableSharedMemory::DiscardableSharedMemory() {
+DiscardableSharedMemory::DiscardableSharedMemory()
+ : mapped_size_(0), locked_page_count_(0) {
}
DiscardableSharedMemory::DiscardableSharedMemory(
SharedMemoryHandle shared_memory_handle)
- : shared_memory_(shared_memory_handle, false) {
+ : shared_memory_(shared_memory_handle, false),
+ mapped_size_(0),
+ locked_page_count_(0) {
}
DiscardableSharedMemory::~DiscardableSharedMemory() {
@@ -99,13 +118,22 @@ DiscardableSharedMemory::~DiscardableSharedMemory() {
bool DiscardableSharedMemory::CreateAndMap(size_t size) {
CheckedNumeric<size_t> checked_size = size;
- checked_size += sizeof(SharedState);
+ checked_size += AlignToPageSize(sizeof(SharedState));
if (!checked_size.IsValid())
return false;
if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
return false;
+ mapped_size_ =
+ shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
+
+ locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
+#if DCHECK_IS_ON()
+ for (size_t page = 0; page < locked_page_count_; ++page)
+ locked_pages_.insert(page);
+#endif
+
DCHECK(last_known_usage_.is_null());
SharedState new_state(SharedState::LOCKED, Time());
subtle::Release_Store(&SharedStateFromSharedMemory(shared_memory_)->value.i,
@@ -114,35 +142,141 @@ bool DiscardableSharedMemory::CreateAndMap(size_t size) {
}
bool DiscardableSharedMemory::Map(size_t size) {
- return shared_memory_.Map(sizeof(SharedState) + size);
+ if (!shared_memory_.Map(AlignToPageSize(sizeof(SharedState)) + size))
+ return false;
+
+ mapped_size_ =
+ shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
+
+ locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
+#if DCHECK_IS_ON()
+ for (size_t page = 0; page < locked_page_count_; ++page)
+ locked_pages_.insert(page);
+#endif
+
+ return true;
+}
+
+bool DiscardableSharedMemory::Unmap() {
+ if (!shared_memory_.Unmap())
+ return false;
+
+ mapped_size_ = 0;
+ return true;
}
-bool DiscardableSharedMemory::Lock() {
+DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
+ size_t offset, size_t length) {
+ DCHECK_EQ(AlignToPageSize(offset), offset);
+ DCHECK_EQ(AlignToPageSize(length), length);
+
+ // Calls to this function must be synchronized properly.
+ DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
DCHECK(shared_memory_.memory());
- // Return false when instance has been purged or not initialized properly by
- // checking if |last_known_usage_| is NULL.
- if (last_known_usage_.is_null())
- return false;
+ // We need to successfully acquire the platform independent lock before
+ // individual pages can be locked.
+ if (!locked_page_count_) {
+ // Return false when instance has been purged or not initialized properly
+ // by checking if |last_known_usage_| is NULL.
+ if (last_known_usage_.is_null())
+ return FAILED;
+
+ SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
+ SharedState new_state(SharedState::LOCKED, Time());
+ SharedState result(subtle::Acquire_CompareAndSwap(
+ &SharedStateFromSharedMemory(shared_memory_)->value.i,
+ old_state.value.i,
+ new_state.value.i));
+ if (result.value.u != old_state.value.u) {
+ // Update |last_known_usage_| in case the above CAS failed because of
+ // an incorrect timestamp.
+ last_known_usage_ = result.GetTimestamp();
+ return FAILED;
+ }
+ }
- SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
- SharedState new_state(SharedState::LOCKED, Time());
- SharedState result(subtle::Acquire_CompareAndSwap(
- &SharedStateFromSharedMemory(shared_memory_)->value.i,
- old_state.value.i,
- new_state.value.i));
- if (result.value.u == old_state.value.u)
- return true;
+ // Zero for length means "everything onward".
+ if (!length)
+ length = AlignToPageSize(mapped_size_) - offset;
+
+ size_t start = offset / base::GetPageSize();
+ size_t end = start + length / base::GetPageSize();
+ DCHECK_LT(start, end);
+ DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
+
+ // Add pages to |locked_page_count_|.
+ // Note: Locking a page that is already locked is an error.
+ locked_page_count_ += end - start;
+#if DCHECK_IS_ON()
+ // Detect incorrect usage by keeping track of exactly what pages are locked.
+ for (auto page = start; page < end; ++page) {
+ auto result = locked_pages_.insert(page);
+ DCHECK(result.second);
+ }
+ DCHECK_EQ(locked_pages_.size(), locked_page_count_);
+#endif
+
+#if defined(OS_ANDROID)
+ SharedMemoryHandle handle = shared_memory_.handle();
+ if (SharedMemory::IsHandleValid(handle)) {
+ if (ashmem_pin_region(
+ handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+ return PURGED;
+ }
+ }
+#endif
- // Update |last_known_usage_| in case the above CAS failed because of
- // an incorrect timestamp.
- last_known_usage_ = result.GetTimestamp();
- return false;
+ return SUCCESS;
}
-void DiscardableSharedMemory::Unlock() {
+void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
+ DCHECK_EQ(AlignToPageSize(offset), offset);
+ DCHECK_EQ(AlignToPageSize(length), length);
+
+ // Calls to this function must be synchronized properly.
+ DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+ // Zero for length means "everything onward".
+ if (!length)
+ length = AlignToPageSize(mapped_size_) - offset;
+
DCHECK(shared_memory_.memory());
+#if defined(OS_ANDROID)
+ SharedMemoryHandle handle = shared_memory_.handle();
+ if (SharedMemory::IsHandleValid(handle)) {
+ if (ashmem_unpin_region(
+ handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+ DPLOG(ERROR) << "ashmem_unpin_region() failed";
+ }
+ }
+#endif
+
+ size_t start = offset / base::GetPageSize();
+ size_t end = start + length / base::GetPageSize();
+ DCHECK_LT(start, end);
+ DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
+
+ // Remove pages from |locked_page_count_|.
+ // Note: Unlocking a page that is not locked is an error.
+ DCHECK_GE(locked_page_count_, end - start);
+ locked_page_count_ -= end - start;
+#if DCHECK_IS_ON()
+ // Detect incorrect usage by keeping track of exactly what pages are locked.
+ for (auto page = start; page < end; ++page) {
+ auto erased_count = locked_pages_.erase(page);
+ DCHECK_EQ(1u, erased_count);
+ }
+ DCHECK_EQ(locked_pages_.size(), locked_page_count_);
+#endif
+
+ // Early out and avoid releasing the platform independent lock if some pages
+ // are still locked.
+ if (locked_page_count_)
+ return;
+
Time current_time = Now();
DCHECK(!current_time.is_null());
@@ -151,7 +285,7 @@ void DiscardableSharedMemory::Unlock() {
// Note: timestamp cannot be NULL as that is a unique value used when
// locked or purged.
DCHECK(!new_state.GetTimestamp().is_null());
- // Timestamps precision should at least be accurate to the second.
+ // Timestamp precision should at least be accurate to the second.
DCHECK_EQ((new_state.GetTimestamp() - Time::UnixEpoch()).InSeconds(),
(current_time - Time::UnixEpoch()).InSeconds());
SharedState result(subtle::Release_CompareAndSwap(
@@ -165,10 +299,14 @@ void DiscardableSharedMemory::Unlock() {
}
void* DiscardableSharedMemory::memory() const {
- return SharedStateFromSharedMemory(shared_memory_) + 1;
+ return reinterpret_cast<uint8*>(shared_memory_.memory()) +
+ AlignToPageSize(sizeof(SharedState));
}
bool DiscardableSharedMemory::Purge(Time current_time) {
+ // Calls to this function must be synchronized properly.
+ DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
// Early out if not mapped. This can happen if the segment was previously
// unmapped using a call to Close().
if (!shared_memory_.memory())
@@ -197,22 +335,6 @@ bool DiscardableSharedMemory::Purge(Time current_time) {
return true;
}
-bool DiscardableSharedMemory::PurgeAndTruncate(Time current_time) {
- if (!Purge(current_time))
- return false;
-
-#if defined(OS_POSIX)
- // Truncate shared memory to size of SharedState.
- SharedMemoryHandle handle = shared_memory_.handle();
- if (SharedMemory::IsHandleValid(handle)) {
- if (HANDLE_EINTR(ftruncate(handle.fd, sizeof(SharedState))) != 0)
- DPLOG(ERROR) << "ftruncate() failed";
- }
-#endif
-
- return true;
-}
-
bool DiscardableSharedMemory::IsMemoryResident() const {
DCHECK(shared_memory_.memory());
@@ -227,6 +349,26 @@ void DiscardableSharedMemory::Close() {
shared_memory_.Close();
}
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+void DiscardableSharedMemory::Shrink() {
+#if defined(OS_POSIX)
+ SharedMemoryHandle handle = shared_memory_.handle();
+ if (!SharedMemory::IsHandleValid(handle))
+ return;
+
+ // Truncate shared memory to size of SharedState.
+ if (HANDLE_EINTR(
+ ftruncate(handle.fd, AlignToPageSize(sizeof(SharedState)))) != 0) {
+ DPLOG(ERROR) << "ftruncate() failed";
+ return;
+ }
+ mapped_size_ = 0;
+#else
+ NOTIMPLEMENTED();
+#endif
+}
+#endif
+
Time DiscardableSharedMemory::Now() const {
return Time::Now();
}
diff --git a/chromium/base/memory/discardable_shared_memory.h b/chromium/base/memory/discardable_shared_memory.h
index ca2accf1a2e..74bbe8e95f4 100644
--- a/chromium/base/memory/discardable_shared_memory.h
+++ b/chromium/base/memory/discardable_shared_memory.h
@@ -6,18 +6,35 @@
#define BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
#include "base/base_export.h"
+#include "base/logging.h"
#include "base/memory/shared_memory.h"
+#include "base/threading/thread_collision_warner.h"
#include "base/time/time.h"
+#if DCHECK_IS_ON()
+#include <set>
+#endif
+
+// Define DISCARDABLE_SHARED_MEMORY_SHRINKING if platform supports shrinking
+// of discardable shared memory segments.
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#define DISCARDABLE_SHARED_MEMORY_SHRINKING
+#endif
+
namespace base {
// Platform abstraction for discardable shared memory.
+//
+// This class is not thread-safe. Clients are responsible for synchronizing
+// access to an instance of this class.
class BASE_EXPORT DiscardableSharedMemory {
public:
+ enum LockResult { SUCCESS, PURGED, FAILED };
+
DiscardableSharedMemory();
// Create a new DiscardableSharedMemory object from an existing, open shared
- // memory file.
+ // memory file. Memory must be locked.
explicit DiscardableSharedMemory(SharedMemoryHandle handle);
// Closes any open files.
@@ -27,32 +44,48 @@ class BASE_EXPORT DiscardableSharedMemory {
// Returns true on success and false on failure.
bool CreateAndMap(size_t size);
- // Maps the discardable memory into the caller's address space.
+ // Maps the locked discardable memory into the caller's address space.
// Returns true on success, false otherwise.
bool Map(size_t size);
+ // Unmaps the discardable shared memory from the caller's address space.
+ // Returns true if successful; returns false on error or if the memory is
+ // not mapped.
+ bool Unmap();
+
// The actual size of the mapped memory (may be larger than requested).
- size_t mapped_size() const { return shared_memory_.mapped_size(); }
+ size_t mapped_size() const { return mapped_size_; }
// Returns a shared memory handle for this DiscardableSharedMemory object.
SharedMemoryHandle handle() const { return shared_memory_.handle(); }
- // Locks the memory so that it will not be purged by the system. Returns
- // true if successful and the memory is still resident. Locking can fail
- // for three reasons; object might have been purged, our last known usage
- // timestamp might be out of date or memory might already be locked. Last
- // know usage time is updated to the actual last usage timestamp if memory
- // is still resident or 0 if not.
- bool Lock();
-
- // Unlock previously successfully locked memory.
- void Unlock();
+ // Locks a range of memory so that it will not be purged by the system.
+ // The range of memory must be unlocked. The result of trying to lock an
+ // already locked range is undefined. |offset| and |length| must both be
+ // a multiple of the page size as returned by GetPageSize().
+ // Passing 0 for |length| means "everything onward".
+ // Returns SUCCESS if range was successfully locked and the memory is still
+ // resident, PURGED if range was successfully locked but has been purged
+ // since last time it was locked and FAILED if range could not be locked.
+ // Locking can fail for two reasons; object might have been purged, our
+ // last known usage timestamp might be out of date. Last known usage time
+ // is updated to the actual last usage timestamp if memory is still resident
+ // or 0 if not.
+ LockResult Lock(size_t offset, size_t length);
+
+ // Unlock a previously successfully locked range of memory. The range of
+ // memory must be locked. The result of trying to unlock a not
+ // previously locked range is undefined.
+ // |offset| and |length| must both be a multiple of the page size as returned
+ // by GetPageSize().
+ // Passing 0 for |length| means "everything onward".
+ void Unlock(size_t offset, size_t length);
// Gets a pointer to the opened discardable memory space. Discardable memory
// must have been mapped via Map().
void* memory() const;
- // Returns the last know usage time for DiscardableSharedMemory object. This
+ // Returns the last known usage time for DiscardableSharedMemory object. This
// may be earlier than the "true" usage time when memory has been used by a
// different process. Returns NULL time if purged.
Time last_known_usage() const { return last_known_usage_; }
@@ -62,7 +95,7 @@ class BASE_EXPORT DiscardableSharedMemory {
// for two reasons; object might be locked or our last known usage timestamp
// might be out of date. Last known usage time is updated to |current_time|
// if locked or the actual last usage timestamp if unlocked. It is often
- // neccesary to call this function twice for the object to successfully be
+ // necessary to call this function twice for the object to successfully be
// purged. First call, updates |last_known_usage_|. Second call, successfully
// purges the object using the updated |last_known_usage_|.
// Note: there is no guarantee that multiple calls to this function will
@@ -71,12 +104,6 @@ class BASE_EXPORT DiscardableSharedMemory {
// each call.
bool Purge(Time current_time);
- // Purge and release as much memory as possible to the OS.
- // Note: The amount of memory that can be released to the OS is platform
- // specific. Best case, all but one page is released. Worst case, nothing
- // is released.
- bool PurgeAndTruncate(Time current_time);
-
// Returns true if memory is still resident.
bool IsMemoryResident() const;
@@ -94,11 +121,25 @@ class BASE_EXPORT DiscardableSharedMemory {
return shared_memory_.ShareToProcess(process_handle, new_handle);
}
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+ // Release as much memory as possible to the OS. The change in size will
+ // be reflected by the return value of mapped_size().
+ void Shrink();
+#endif
+
private:
// Virtual for tests.
virtual Time Now() const;
SharedMemory shared_memory_;
+ size_t mapped_size_;
+ size_t locked_page_count_;
+#if DCHECK_IS_ON()
+ std::set<size_t> locked_pages_;
+#endif
+ // Implementation is not thread-safe but still usable if clients are
+ // synchronized somehow. Use a collision warner to detect incorrect usage.
+ DFAKE_MUTEX(thread_collision_warner_);
Time last_known_usage_;
DISALLOW_COPY_AND_ASSIGN(DiscardableSharedMemory);
diff --git a/chromium/base/memory/discardable_shared_memory_unittest.cc b/chromium/base/memory/discardable_shared_memory_unittest.cc
index e5174298bfd..91b0b68523a 100644
--- a/chromium/base/memory/discardable_shared_memory_unittest.cc
+++ b/chromium/base/memory/discardable_shared_memory_unittest.cc
@@ -4,6 +4,7 @@
#include "base/basictypes.h"
#include "base/memory/discardable_shared_memory.h"
+#include "base/process/process_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -20,7 +21,7 @@ class TestDiscardableSharedMemory : public DiscardableSharedMemory {
private:
// Overriden from DiscardableSharedMemory:
- virtual Time Now() const override { return now_; }
+ Time Now() const override { return now_; }
Time now_;
};
@@ -60,13 +61,17 @@ TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
// Memory is initially locked. Unlock it.
memory1.SetNow(Time::FromDoubleT(1));
- memory1.Unlock();
+ memory1.Unlock(0, 0);
// Lock and unlock memory.
- rv = memory1.Lock();
- EXPECT_TRUE(rv);
+ auto lock_rv = memory1.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
memory1.SetNow(Time::FromDoubleT(2));
- memory1.Unlock();
+ memory1.Unlock(0, 0);
+
+ // Lock again before duplicating and passing ownership to new instance.
+ lock_rv = memory1.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
SharedMemoryHandle shared_handle;
ASSERT_TRUE(
@@ -77,35 +82,21 @@ TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
- // Lock first instance again.
- rv = memory1.Lock();
- EXPECT_TRUE(rv);
-
// Unlock second instance.
memory2.SetNow(Time::FromDoubleT(3));
- memory2.Unlock();
-
- // Lock and unlock second instance.
- rv = memory2.Lock();
- EXPECT_TRUE(rv);
- memory2.SetNow(Time::FromDoubleT(4));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
- // Try to lock first instance again. Should fail as first instance has an
- // incorrect last know usage time.
- rv = memory1.Lock();
- EXPECT_FALSE(rv);
+ // Lock second instance before passing ownership back to first instance.
+ lock_rv = memory2.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
// Memory should still be resident.
rv = memory1.IsMemoryResident();
EXPECT_TRUE(rv);
- // Second attempt to lock first instance should succeed as last known usage
- // time is now correct.
- rv = memory1.Lock();
- EXPECT_TRUE(rv);
- memory1.SetNow(Time::FromDoubleT(5));
- memory1.Unlock();
+ // Unlock first instance.
+ memory1.SetNow(Time::FromDoubleT(4));
+ memory1.Unlock(0, 0);
}
TEST(DiscardableSharedMemoryTest, Purge) {
@@ -129,7 +120,7 @@ TEST(DiscardableSharedMemoryTest, Purge) {
EXPECT_FALSE(rv);
memory2.SetNow(Time::FromDoubleT(2));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
ASSERT_TRUE(memory2.IsMemoryResident());
@@ -144,8 +135,8 @@ TEST(DiscardableSharedMemoryTest, Purge) {
EXPECT_TRUE(rv);
// Lock should fail as memory has been purged.
- rv = memory2.Lock();
- EXPECT_FALSE(rv);
+ auto lock_rv = memory2.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
ASSERT_FALSE(memory2.IsMemoryResident());
}
@@ -167,12 +158,12 @@ TEST(DiscardableSharedMemoryTest, LastUsed) {
ASSERT_TRUE(rv);
memory2.SetNow(Time::FromDoubleT(1));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1));
- rv = memory2.Lock();
- EXPECT_TRUE(rv);
+ auto lock_rv = memory2.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
// This should fail as memory is locked.
rv = memory1.Purge(Time::FromDoubleT(2));
@@ -182,7 +173,7 @@ TEST(DiscardableSharedMemoryTest, LastUsed) {
EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
memory2.SetNow(Time::FromDoubleT(3));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
// Usage time should be correct for |memory2| instance.
EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(3));
@@ -235,17 +226,129 @@ TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
ASSERT_TRUE(rv);
memory2.SetNow(Time::FromDoubleT(1));
- memory2.Unlock();
+ memory2.Unlock(0, 0);
rv = memory2.Purge(Time::FromDoubleT(2));
EXPECT_TRUE(rv);
// Lock should fail as memory has been purged.
- rv = memory2.Lock();
+ auto lock_rv = memory2.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
+ const uint32 kDataSize = 32;
+
+ uint32 data_size_in_bytes = kDataSize * base::GetPageSize();
+
+ TestDiscardableSharedMemory memory1;
+ bool rv = memory1.CreateAndMap(data_size_in_bytes);
+ ASSERT_TRUE(rv);
+
+ SharedMemoryHandle shared_handle;
+ ASSERT_TRUE(
+ memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+ ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+ TestDiscardableSharedMemory memory2(shared_handle);
+ rv = memory2.Map(data_size_in_bytes);
+ ASSERT_TRUE(rv);
+
+ // Unlock first page.
+ memory2.SetNow(Time::FromDoubleT(1));
+ memory2.Unlock(0, base::GetPageSize());
+
+ rv = memory1.Purge(Time::FromDoubleT(2));
+ EXPECT_FALSE(rv);
+
+ // Lock first page again.
+ memory2.SetNow(Time::FromDoubleT(3));
+ auto lock_rv = memory2.Lock(0, base::GetPageSize());
+ EXPECT_NE(DiscardableSharedMemory::FAILED, lock_rv);
+
+ // Unlock first page.
+ memory2.SetNow(Time::FromDoubleT(4));
+ memory2.Unlock(0, base::GetPageSize());
+
+ rv = memory1.Purge(Time::FromDoubleT(5));
+ EXPECT_FALSE(rv);
+
+ // Unlock second page.
+ memory2.SetNow(Time::FromDoubleT(6));
+ memory2.Unlock(base::GetPageSize(), base::GetPageSize());
+
+ rv = memory1.Purge(Time::FromDoubleT(7));
EXPECT_FALSE(rv);
- rv = memory1.Lock();
+
+ // Unlock anything onwards.
+ memory2.SetNow(Time::FromDoubleT(8));
+ memory2.Unlock(2 * base::GetPageSize(), 0);
+
+ // Memory is unlocked, but our usage timestamp is incorrect.
+ rv = memory1.Purge(Time::FromDoubleT(9));
EXPECT_FALSE(rv);
+
+ // The failed purge attempt should have updated usage time to the correct
+ // value.
+ EXPECT_EQ(Time::FromDoubleT(8), memory1.last_known_usage());
+
+ // Purge should now succeed.
+ rv = memory1.Purge(Time::FromDoubleT(10));
+ EXPECT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, MappedSize) {
+ const uint32 kDataSize = 1024;
+
+ TestDiscardableSharedMemory memory;
+ bool rv = memory.CreateAndMap(kDataSize);
+ ASSERT_TRUE(rv);
+
+ EXPECT_LE(kDataSize, memory.mapped_size());
+
+ // Mapped size should be 0 after memory segment has been unmapped.
+ rv = memory.Unmap();
+ EXPECT_TRUE(rv);
+ EXPECT_EQ(0u, memory.mapped_size());
+}
+
+TEST(DiscardableSharedMemoryTest, Close) {
+ const uint32 kDataSize = 1024;
+
+ TestDiscardableSharedMemory memory;
+ bool rv = memory.CreateAndMap(kDataSize);
+ ASSERT_TRUE(rv);
+
+ // Mapped size should be unchanged after memory segment has been closed.
+ memory.Close();
+ EXPECT_LE(kDataSize, memory.mapped_size());
+
+ // Memory is initially locked. Unlock it.
+ memory.SetNow(Time::FromDoubleT(1));
+ memory.Unlock(0, 0);
+
+ // Lock and unlock memory.
+ auto lock_rv = memory.Lock(0, 0);
+ EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+ memory.SetNow(Time::FromDoubleT(2));
+ memory.Unlock(0, 0);
+}
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+TEST(DiscardableSharedMemoryTest, Shrink) {
+ const uint32 kDataSize = 1024;
+
+ TestDiscardableSharedMemory memory;
+ bool rv = memory.CreateAndMap(kDataSize);
+ ASSERT_TRUE(rv);
+
+ EXPECT_NE(0u, memory.mapped_size());
+
+ // Mapped size should be 0 after shrinking memory segment.
+ memory.Shrink();
+ EXPECT_EQ(0u, memory.mapped_size());
}
+#endif
} // namespace
} // namespace base
diff --git a/chromium/base/memory/manual_constructor.h b/chromium/base/memory/manual_constructor.h
index 9275f73b83b..56081a1d3bc 100644
--- a/chromium/base/memory/manual_constructor.h
+++ b/chromium/base/memory/manual_constructor.h
@@ -18,6 +18,7 @@
#include <stddef.h>
+#include "base/compiler_specific.h"
#include "base/memory/aligned_memory.h"
namespace base {
@@ -33,11 +34,7 @@ class ManualConstructor {
// Support users creating arrays of ManualConstructor<>s. This ensures that
// the array itself has the correct alignment.
static void* operator new[](size_t size) {
-#if defined(COMPILER_MSVC)
- return AlignedAlloc(size, __alignof(Type));
-#else
- return AlignedAlloc(size, __alignof__(Type));
-#endif
+ return AlignedAlloc(size, ALIGNOF(Type));
}
static void operator delete[](void* mem) {
AlignedFree(mem);
@@ -56,56 +53,9 @@ class ManualConstructor {
inline Type& operator*() { return *get(); }
inline const Type& operator*() const { return *get(); }
- // You can pass up to eight constructor arguments as arguments of Init().
- inline void Init() {
- new(space_.void_data()) Type;
- }
-
- template <typename T1>
- inline void Init(const T1& p1) {
- new(space_.void_data()) Type(p1);
- }
-
- template <typename T1, typename T2>
- inline void Init(const T1& p1, const T2& p2) {
- new(space_.void_data()) Type(p1, p2);
- }
-
- template <typename T1, typename T2, typename T3>
- inline void Init(const T1& p1, const T2& p2, const T3& p3) {
- new(space_.void_data()) Type(p1, p2, p3);
- }
-
- template <typename T1, typename T2, typename T3, typename T4>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
- new(space_.void_data()) Type(p1, p2, p3, p4);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5) {
- new(space_.void_data()) Type(p1, p2, p3, p4, p5);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6) {
- new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7) {
- new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6, p7);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
- new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
+ template <typename... Ts>
+ inline void Init(const Ts&... params) {
+ new(space_.void_data()) Type(params...);
}
inline void Destroy() {
@@ -113,11 +63,7 @@ class ManualConstructor {
}
private:
-#if defined(COMPILER_MSVC)
- AlignedMemory<sizeof(Type), __alignof(Type)> space_;
-#else
- AlignedMemory<sizeof(Type), __alignof__(Type)> space_;
-#endif
+ AlignedMemory<sizeof(Type), ALIGNOF(Type)> space_;
};
} // namespace base
diff --git a/chromium/base/memory/memory_pressure_listener.cc b/chromium/base/memory/memory_pressure_listener.cc
index 745c9859a08..6a8ed210a7d 100644
--- a/chromium/base/memory/memory_pressure_listener.cc
+++ b/chromium/base/memory/memory_pressure_listener.cc
@@ -4,9 +4,9 @@
#include "base/memory/memory_pressure_listener.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/observer_list_threadsafe.h"
+#include "base/trace_event/trace_event.h"
namespace {
@@ -51,9 +51,10 @@ void MemoryPressureListener::Notify(MemoryPressureLevel memory_pressure_level) {
// static
void MemoryPressureListener::NotifyMemoryPressure(
MemoryPressureLevel memory_pressure_level) {
+ DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
TRACE_EVENT1("memory", "MemoryPressureListener::NotifyMemoryPressure",
"level", memory_pressure_level);
- g_observers.Get().Notify(&MemoryPressureListener::Notify,
+ g_observers.Get().Notify(FROM_HERE, &MemoryPressureListener::Notify,
memory_pressure_level);
}
diff --git a/chromium/base/memory/memory_pressure_listener.h b/chromium/base/memory/memory_pressure_listener.h
index f586209c5bc..6adaeeed7fd 100644
--- a/chromium/base/memory/memory_pressure_listener.h
+++ b/chromium/base/memory/memory_pressure_listener.h
@@ -3,15 +3,12 @@
// found in the LICENSE file.
// MemoryPressure provides static APIs for handling memory pressure on
-// platforms that have such signals, such as Android.
+// platforms that have such signals, such as Android and ChromeOS.
// The app will try to discard buffers that aren't deemed essential (individual
// modules will implement their own policy).
-//
-// Refer to memory_pressure_level_list.h for information about what sorts of
-// signals can be sent under what conditions.
-#ifndef BASE_MEMORY_PRESSURE_LISTENER_H_
-#define BASE_MEMORY_PRESSURE_LISTENER_H_
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
#include "base/base_export.h"
#include "base/basictypes.h"
@@ -26,12 +23,11 @@ namespace base {
// the listener.
// Note that even on the same thread, the callback is not guaranteed to be
// called synchronously within the system memory pressure broadcast.
-// Please see notes on memory_pressure_level_list.h: some levels are absolutely
-// critical, and if not enough memory is returned to the system, it'll
-// potentially kill the app, and then later the app will have to be
+// Please see notes in MemoryPressureLevel enum below: some levels are
+// absolutely critical, and if not enough memory is returned to the system,
+// it'll potentially kill the app, and then later the app will have to be
// cold-started.
//
-//
// Example:
//
// void OnMemoryPressure(MemoryPressureLevel memory_pressure_level) {
@@ -52,6 +48,11 @@ class BASE_EXPORT MemoryPressureListener {
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
enum MemoryPressureLevel {
+ // No problems, there is enough memory to use. This event is not sent via
+ // callback, but the enum is used in other places to find out the current
+ // state of the system.
+ MEMORY_PRESSURE_LEVEL_NONE = -1,
+
// Modules are advised to free buffers that are cheap to re-allocate and not
// immediately needed.
MEMORY_PRESSURE_LEVEL_MODERATE = 0,
@@ -81,4 +82,4 @@ class BASE_EXPORT MemoryPressureListener {
} // namespace base
-#endif // BASE_MEMORY_PRESSURE_LISTENER_H_
+#endif // BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
diff --git a/chromium/base/memory/memory_pressure_monitor.cc b/chromium/base/memory/memory_pressure_monitor.cc
new file mode 100644
index 00000000000..00633f1dd61
--- /dev/null
+++ b/chromium/base/memory/memory_pressure_monitor.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 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/memory/memory_pressure_monitor.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+MemoryPressureMonitor* g_monitor = nullptr;
+
+} // namespace
+
+MemoryPressureMonitor::MemoryPressureMonitor() {
+ DCHECK(!g_monitor);
+ g_monitor = this;
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+ DCHECK(g_monitor);
+ g_monitor = nullptr;
+}
+
+// static
+MemoryPressureMonitor* MemoryPressureMonitor::Get() {
+ return g_monitor;
+}
+
+} // namespace base
diff --git a/chromium/base/memory/memory_pressure_monitor.h b/chromium/base/memory/memory_pressure_monitor.h
new file mode 100644
index 00000000000..90c94209653
--- /dev/null
+++ b/chromium/base/memory/memory_pressure_monitor.h
@@ -0,0 +1,43 @@
+// Copyright 2015 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_MEMORY_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+
+namespace base {
+
+// TODO(chrisha): Make this a concrete class with per-OS implementations rather
+// than an abstract base class.
+
+// Declares the interface for a MemoryPressureMonitor. There are multiple
+// OS specific implementations of this class. An instance of the memory
+// pressure observer is created at the process level, tracks memory usage, and
+// pushes memory state change notifications to the static function
+// base::MemoryPressureListener::NotifyMemoryPressure. This is turn notifies
+// all MemoryPressureListener instances via a callback.
+class BASE_EXPORT MemoryPressureMonitor {
+ public:
+ using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
+ virtual ~MemoryPressureMonitor();
+
+ // Return the singleton MemoryPressureMonitor.
+ static MemoryPressureMonitor* Get();
+
+ // Returns the currently observed memory pressure.
+ virtual MemoryPressureLevel GetCurrentPressureLevel() const = 0;
+
+ protected:
+ MemoryPressureMonitor();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
diff --git a/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h b/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
index 7974f3047b2..01905588058 100644
--- a/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -47,30 +47,30 @@ struct ParamsUseScopedRefptrCorrectly {
};
template <>
-struct ParamsUseScopedRefptrCorrectly<Tuple0> {
+struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
enum { value = 1 };
};
template <typename A>
-struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A>> {
enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
};
template <typename A, typename B>
-struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value) };
};
template <typename A, typename B, typename C>
-struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
NeedsScopedRefptrButGetsRawPtr<C>::value) };
};
template <typename A, typename B, typename C, typename D>
-struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
@@ -78,7 +78,7 @@ struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > {
};
template <typename A, typename B, typename C, typename D, typename E>
-struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
@@ -88,7 +88,7 @@ struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > {
template <typename A, typename B, typename C, typename D, typename E,
typename F>
-struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
@@ -99,7 +99,7 @@ struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > {
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> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
@@ -111,7 +111,7 @@ struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > {
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> > {
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G, H>> {
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
diff --git a/chromium/base/memory/ref_counted.h b/chromium/base/memory/ref_counted.h
index 7869e72d111..5f94b4c37ae 100644
--- a/chromium/base/memory/ref_counted.h
+++ b/chromium/base/memory/ref_counted.h
@@ -14,13 +14,10 @@
#ifndef NDEBUG
#include "base/logging.h"
#endif
+#include "base/move.h"
#include "base/threading/thread_collision_warner.h"
#include "build/build_config.h"
-#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_ANDROID)
-#define DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR
-#endif
-
namespace base {
namespace subtle {
@@ -268,6 +265,7 @@ class RefCountedData
//
template <class T>
class scoped_refptr {
+ TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
public:
typedef T element_type;
@@ -290,6 +288,11 @@ class scoped_refptr {
AddRef(ptr_);
}
+ template <typename U>
+ scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
+ r.ptr_ = nullptr;
+ }
+
~scoped_refptr() {
if (ptr_)
Release(ptr_);
@@ -297,12 +300,6 @@ class scoped_refptr {
T* get() const { return ptr_; }
-#if !defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
- // Allow scoped_refptr<C> to be used in boolean expression
- // and comparison operations.
- operator T*() const { return ptr_; }
-#endif
-
T& operator*() const {
assert(ptr_ != NULL);
return *ptr_;
@@ -333,6 +330,17 @@ class scoped_refptr {
return *this = r.get();
}
+ scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
+ scoped_refptr<T>(r.Pass()).swap(*this);
+ return *this;
+ }
+
+ template <typename U>
+ scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
+ scoped_refptr<T>(r.Pass()).swap(*this);
+ return *this;
+ }
+
void swap(T** pp) {
T* p = ptr_;
ptr_ = *pp;
@@ -343,7 +351,21 @@ class scoped_refptr {
swap(&r.ptr_);
}
-#if defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
+ private:
+ template <typename U> friend class scoped_refptr;
+
+ // Allow scoped_refptr<T> to be used in boolean expressions, but not
+ // implicitly convertible to a real bool (which is dangerous).
+ //
+ // Note that this trick is only safe when the == and != operators
+ // are declared explicitly, as otherwise "refptr1 == refptr2"
+ // will compile but do the wrong thing (i.e., convert to Testable
+ // and then do the comparison).
+ typedef T* scoped_refptr::*Testable;
+
+ public:
+ operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
+
template <typename U>
bool operator==(const scoped_refptr<U>& rhs) const {
return ptr_ == rhs.get();
@@ -358,7 +380,6 @@ class scoped_refptr {
bool operator<(const scoped_refptr<U>& rhs) const {
return ptr_ < rhs.get();
}
-#endif
protected:
T* ptr_;
@@ -389,8 +410,8 @@ scoped_refptr<T> make_scoped_refptr(T* t) {
return scoped_refptr<T>(t);
}
-#if defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
-// Temporary operator overloads to facilitate the transition...
+// Temporary operator overloads to facilitate the transition. See
+// https://crbug.com/110610.
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
return lhs.get() == rhs;
@@ -415,6 +436,5 @@ template <typename T>
std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
return out << p.get();
}
-#endif // defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
#endif // BASE_MEMORY_REF_COUNTED_H_
diff --git a/chromium/base/memory/ref_counted_delete_on_message_loop.h b/chromium/base/memory/ref_counted_delete_on_message_loop.h
index 7b898ac00dd..6a109e81e00 100644
--- a/chromium/base/memory/ref_counted_delete_on_message_loop.h
+++ b/chromium/base/memory/ref_counted_delete_on_message_loop.h
@@ -8,7 +8,9 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+// TODO(ricea): Remove the following include once all callers have been fixed.
#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
namespace base {
@@ -18,7 +20,7 @@ namespace base {
// Sample usage:
// class Foo : public RefCountedDeleteOnMessageLoop<Foo> {
//
-// Foo(const scoped_refptr<MessageLoopProxy>& loop)
+// Foo(const scoped_refptr<SingleThreadTaskRunner>& loop)
// : RefCountedDeleteOnMessageLoop<Foo>(loop) {
// ...
// }
@@ -30,12 +32,18 @@ namespace base {
// ~Foo();
// };
+// TODO(skyostil): Rename this to RefCountedDeleteOnTaskRunner.
template <class T>
class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
public:
+ // This constructor will accept a MessageL00pProxy object, but new code should
+ // prefer a SingleThreadTaskRunner. A SingleThreadTaskRunner for the
+ // MessageLoop on the current thread can be acquired by calling
+ // MessageLoop::current()->task_runner().
RefCountedDeleteOnMessageLoop(
- const scoped_refptr<MessageLoopProxy>& proxy) : proxy_(proxy) {
- DCHECK(proxy_.get());
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+ : task_runner_(task_runner) {
+ DCHECK(task_runner_);
}
void AddRef() const {
@@ -53,13 +61,13 @@ class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
void DestructOnMessageLoop() const {
const T* t = static_cast<const T*>(this);
- if (proxy_->BelongsToCurrentThread())
+ if (task_runner_->BelongsToCurrentThread())
delete t;
else
- proxy_->DeleteSoon(FROM_HERE, t);
+ task_runner_->DeleteSoon(FROM_HERE, t);
}
- scoped_refptr<MessageLoopProxy> proxy_;
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
private:
DISALLOW_COPY_AND_ASSIGN(RefCountedDeleteOnMessageLoop);
diff --git a/chromium/base/memory/ref_counted_unittest.cc b/chromium/base/memory/ref_counted_unittest.cc
index 7e73bde1155..6f8e599cbdc 100644
--- a/chromium/base/memory/ref_counted_unittest.cc
+++ b/chromium/base/memory/ref_counted_unittest.cc
@@ -10,9 +10,19 @@
namespace {
class SelfAssign : public base::RefCounted<SelfAssign> {
+ protected:
+ virtual ~SelfAssign() {}
+
+ private:
friend class base::RefCounted<SelfAssign>;
+};
+
+class Derived : public SelfAssign {
+ protected:
+ ~Derived() override {}
- ~SelfAssign() {}
+ private:
+ friend class base::RefCounted<Derived>;
};
class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
@@ -30,19 +40,71 @@ class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> {
static bool was_destroyed() { return was_destroyed_; }
- void SelfDestruct() { self_ptr_ = NULL; }
+ static void reset_was_destroyed() { was_destroyed_ = false; }
+
+ scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
private:
friend class base::RefCounted<ScopedRefPtrToSelf>;
~ScopedRefPtrToSelf() { was_destroyed_ = true; }
static bool was_destroyed_;
-
- scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
};
bool ScopedRefPtrToSelf::was_destroyed_ = false;
+class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> {
+ public:
+ ScopedRefPtrCountBase() { ++constructor_count_; }
+
+ static int constructor_count() { return constructor_count_; }
+
+ static int destructor_count() { return destructor_count_; }
+
+ static void reset_count() {
+ constructor_count_ = 0;
+ destructor_count_ = 0;
+ }
+
+ protected:
+ virtual ~ScopedRefPtrCountBase() { ++destructor_count_; }
+
+ private:
+ friend class base::RefCounted<ScopedRefPtrCountBase>;
+
+ static int constructor_count_;
+ static int destructor_count_;
+};
+
+int ScopedRefPtrCountBase::constructor_count_ = 0;
+int ScopedRefPtrCountBase::destructor_count_ = 0;
+
+class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase {
+ public:
+ ScopedRefPtrCountDerived() { ++constructor_count_; }
+
+ static int constructor_count() { return constructor_count_; }
+
+ static int destructor_count() { return destructor_count_; }
+
+ static void reset_count() {
+ constructor_count_ = 0;
+ destructor_count_ = 0;
+ }
+
+ protected:
+ ~ScopedRefPtrCountDerived() override { ++destructor_count_; }
+
+ private:
+ friend class base::RefCounted<ScopedRefPtrCountDerived>;
+
+ static int constructor_count_;
+ static int destructor_count_;
+};
+
+int ScopedRefPtrCountDerived::constructor_count_ = 0;
+int ScopedRefPtrCountDerived::destructor_count_ = 0;
+
} // end namespace
TEST(RefCountedUnitTest, TestSelfAssignment) {
@@ -56,10 +118,24 @@ TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) {
CheckDerivedMemberAccess check;
}
-TEST(RefCountedUnitTest, ScopedRefPtrToSelf) {
+TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) {
+ ScopedRefPtrToSelf::reset_was_destroyed();
+
ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
- check->SelfDestruct();
+ check->self_ptr_ = nullptr;
+ EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) {
+ ScopedRefPtrToSelf::reset_was_destroyed();
+
+ ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
+ EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
+ // Releasing |check->self_ptr_| will delete |check|.
+ // The move assignment operator must assign |check->self_ptr_| first then
+ // release |check->self_ptr_|.
+ check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>();
EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
}
@@ -72,3 +148,315 @@ TEST(RefCountedUnitTest, ScopedRefPtrToOpaque) {
base::TestOpaqueRefCounted(p);
base::TestOpaqueRefCounted(q);
}
+
+TEST(RefCountedUnitTest, BooleanTesting) {
+ scoped_refptr<SelfAssign> p;
+ EXPECT_FALSE(p);
+ p = new SelfAssign;
+ EXPECT_TRUE(p);
+}
+
+TEST(RefCountedUnitTest, Equality) {
+ scoped_refptr<SelfAssign> p1(new SelfAssign);
+ scoped_refptr<SelfAssign> p2(new SelfAssign);
+
+ EXPECT_EQ(p1, p1);
+ EXPECT_EQ(p2, p2);
+
+ EXPECT_NE(p1, p2);
+ EXPECT_NE(p2, p1);
+}
+
+TEST(RefCountedUnitTest, ConvertibleEquality) {
+ scoped_refptr<Derived> p1(new Derived);
+ scoped_refptr<SelfAssign> p2;
+
+ EXPECT_NE(p1, p2);
+ EXPECT_NE(p2, p1);
+
+ p2 = p1;
+
+ EXPECT_EQ(p1, p2);
+ EXPECT_EQ(p2, p1);
+}
+
+TEST(RefCountedUnitTest, SelfMoveAssignment) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p(raw);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ p = p.Pass();
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(raw, p.get());
+
+ // p goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignment1) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ {
+ scoped_refptr<ScopedRefPtrCountBase> p2;
+
+ p2 = p1.Pass();
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(raw, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignment2) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1;
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ {
+ scoped_refptr<ScopedRefPtrCountBase> p2(raw);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ p1 = p2.Pass();
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(raw, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ {
+ scoped_refptr<ScopedRefPtrCountBase> p2(p1);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ p1 = p2.Pass();
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(raw, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ {
+ scoped_refptr<ScopedRefPtrCountBase> p2(p1);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ p2 = p1.Pass();
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(raw, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ {
+ ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p2(raw2);
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ p1 = p2.Pass();
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(raw2, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentDerived) {
+ ScopedRefPtrCountBase::reset_count();
+ ScopedRefPtrCountDerived::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+ {
+ ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived();
+ scoped_refptr<ScopedRefPtrCountDerived> p2(raw2);
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+ p1 = p2.Pass();
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+ EXPECT_EQ(raw2, p1.get());
+ EXPECT_EQ(nullptr, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveConstructor) {
+ ScopedRefPtrCountBase::reset_count();
+
+ {
+ ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+ scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+ {
+ scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(raw, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveConstructorDerived) {
+ ScopedRefPtrCountBase::reset_count();
+ ScopedRefPtrCountDerived::reset_count();
+
+ {
+ ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived();
+ scoped_refptr<ScopedRefPtrCountDerived> p1(raw1);
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+ {
+ scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+ EXPECT_EQ(nullptr, p1.get());
+ EXPECT_EQ(raw1, p2.get());
+
+ // p2 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+
+ // p1 goes out of scope.
+ }
+ EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+ EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+}
+
diff --git a/chromium/base/memory/scoped_open_process.h b/chromium/base/memory/scoped_open_process.h
deleted file mode 100644
index 8bb19e241ec..00000000000
--- a/chromium/base/memory/scoped_open_process.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_MEMORY_SCOPED_OPEN_PROCESS_H_
-#define BASE_MEMORY_SCOPED_OPEN_PROCESS_H_
-
-#include "base/process/process_handle.h"
-
-namespace base {
-
-// A class that opens a process from its process id and closes it when the
-// instance goes out of scope.
-class ScopedOpenProcess {
- public:
- ScopedOpenProcess() : handle_(kNullProcessHandle) {
- }
-
- // Automatically close the process.
- ~ScopedOpenProcess() {
- Close();
- }
-
- // Open a new process by pid. Closes any previously opened process (even if
- // opening the new one fails).
- bool Open(ProcessId pid) {
- Close();
- return OpenProcessHandle(pid, &handle_);
- }
-
- // Close the previously opened process.
- void Close() {
- if (handle_ == kNullProcessHandle)
- return;
-
- CloseProcessHandle(handle_);
- handle_ = kNullProcessHandle;
- }
-
- ProcessHandle handle() const { return handle_; }
-
- private:
- ProcessHandle handle_;
- DISALLOW_COPY_AND_ASSIGN(ScopedOpenProcess);
-};
-} // namespace base
-
-#endif // BASE_MEMORY_SCOPED_OPEN_PROCESS_H_
diff --git a/chromium/base/memory/scoped_ptr.h b/chromium/base/memory/scoped_ptr.h
index ae9eb0fee8b..987ccfa804e 100644
--- a/chromium/base/memory/scoped_ptr.h
+++ b/chromium/base/memory/scoped_ptr.h
@@ -85,6 +85,7 @@
#include <stdlib.h>
#include <algorithm> // For std::swap().
+#include <iosfwd>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
@@ -585,4 +586,9 @@ scoped_ptr<T> make_scoped_ptr(T* ptr) {
return scoped_ptr<T>(ptr);
}
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) {
+ return out << p.get();
+}
+
#endif // BASE_MEMORY_SCOPED_PTR_H_
diff --git a/chromium/base/memory/scoped_ptr_unittest.cc b/chromium/base/memory/scoped_ptr_unittest.cc
index 3f169a7fa2a..766f4444001 100644
--- a/chromium/base/memory/scoped_ptr_unittest.cc
+++ b/chromium/base/memory/scoped_ptr_unittest.cc
@@ -4,6 +4,8 @@
#include "base/memory/scoped_ptr.h"
+#include <sstream>
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
@@ -669,10 +671,25 @@ TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) {
TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
// A custom deleter should be able to opt out of self-reset abort behavior.
struct NoOpDeleter {
+#if !defined(NDEBUG)
typedef void AllowSelfReset;
+#endif
inline void operator()(int*) {}
};
scoped_ptr<int> owner(new int);
scoped_ptr<int, NoOpDeleter> x(owner.get());
x.reset(x.get());
}
+
+// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean
+// value first.
+TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
+ scoped_ptr<int> x(new int);
+ std::stringstream s1;
+ s1 << x;
+
+ std::stringstream s2;
+ s2 << x.get();
+
+ EXPECT_EQ(s2.str(), s1.str());
+}
diff --git a/chromium/base/memory/scoped_vector.h b/chromium/base/memory/scoped_vector.h
index 1b30f635ca1..173ea5a1d63 100644
--- a/chromium/base/memory/scoped_vector.h
+++ b/chromium/base/memory/scoped_vector.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/move.h"
#include "base/stl_util.h"
@@ -64,6 +65,7 @@ class ScopedVector {
reference back() { return v_.back(); }
void push_back(T* elem) { v_.push_back(elem); }
+ void push_back(scoped_ptr<T> elem) { v_.push_back(elem.release()); }
void pop_back() {
DCHECK(!empty());
diff --git a/chromium/base/memory/scoped_vector_unittest.cc b/chromium/base/memory/scoped_vector_unittest.cc
index b60ca14ab5c..220cfb04687 100644
--- a/chromium/base/memory/scoped_vector_unittest.cc
+++ b/chromium/base/memory/scoped_vector_unittest.cc
@@ -308,4 +308,17 @@ TEST(ScopedVectorTest, InsertRange) {
EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
}
+// Assertions for push_back(scoped_ptr).
+TEST(ScopedVectorTest, PushBackScopedPtr) {
+ int delete_counter = 0;
+ scoped_ptr<DeleteCounter> elem(new DeleteCounter(&delete_counter));
+ EXPECT_EQ(0, delete_counter);
+ {
+ ScopedVector<DeleteCounter> v;
+ v.push_back(elem.Pass());
+ EXPECT_EQ(0, delete_counter);
+ }
+ EXPECT_EQ(1, delete_counter);
+}
+
} // namespace
diff --git a/chromium/base/memory/shared_memory.h b/chromium/base/memory/shared_memory.h
index 7254950feb0..d76e01c6e57 100644
--- a/chromium/base/memory/shared_memory.h
+++ b/chromium/base/memory/shared_memory.h
@@ -200,7 +200,8 @@ class BASE_EXPORT SharedMemory {
SharedMemoryId id() const { return inode_; }
#endif
- // Closes the open shared memory segment.
+ // Closes the open shared memory segment. The memory will remain mapped if
+ // it was previously mapped.
// It is safe to call Close repeatedly.
void Close();
diff --git a/chromium/base/memory/shared_memory_nacl.cc b/chromium/base/memory/shared_memory_nacl.cc
index 39625ee65b5..8435b2ba295 100644
--- a/chromium/base/memory/shared_memory_nacl.cc
+++ b/chromium/base/memory/shared_memory_nacl.cc
@@ -46,6 +46,7 @@ SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
}
SharedMemory::~SharedMemory() {
+ Unmap();
Close();
}
@@ -125,7 +126,6 @@ SharedMemoryHandle SharedMemory::handle() const {
}
void SharedMemory::Close() {
- Unmap();
if (mapped_file_ > 0) {
if (close(mapped_file_) < 0)
DPLOG(ERROR) << "close";
@@ -159,8 +159,10 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
new_handle->fd = new_fd;
new_handle->auto_close = true;
- if (close_self)
+ if (close_self) {
+ Unmap();
Close();
+ }
return true;
}
diff --git a/chromium/base/memory/shared_memory_posix.cc b/chromium/base/memory/shared_memory_posix.cc
index 0358e63e338..d6c290fa016 100644
--- a/chromium/base/memory/shared_memory_posix.cc
+++ b/chromium/base/memory/shared_memory_posix.cc
@@ -16,6 +16,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/process/process_metrics.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/safe_strerror_posix.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
@@ -80,6 +81,7 @@ SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
}
SharedMemory::~SharedMemory() {
+ Unmap();
Close();
}
@@ -117,6 +119,11 @@ bool SharedMemory::CreateAndMapAnonymous(size_t size) {
// In case we want to delete it later, it may be useful to save the value
// of mem_filename after FilePathForMemoryName().
bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466437 SharedMemory::Create::Start"));
DCHECK_EQ(-1, mapped_file_);
if (options.size == 0) return false;
@@ -139,11 +146,22 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
// Q: Why not use the shm_open() etc. APIs?
// A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU
FilePath directory;
- if (GetShmemTempDir(options.executable, &directory))
+ if (GetShmemTempDir(options.executable, &directory)) {
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466437 SharedMemory::Create::OpenTemporaryFile"));
fp.reset(CreateAndOpenTemporaryFileInDir(directory, &path));
+ }
if (fp) {
if (options.share_read_only) {
+ // TODO(erikchen): Remove ScopedTracker below once
+ // http://crbug.com/466437 is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466437 SharedMemory::Create::OpenReadonly"));
// Also open as readonly so that we can ShareReadOnlyToProcess.
readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
if (!readonly_fd.is_valid()) {
@@ -152,6 +170,12 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
return false;
}
}
+
+ // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "466437 SharedMemory::Create::Unlink"));
// Deleting the file prevents anyone else from mapping it in (making it
// private), and prevents the need for cleanup (once the last fd is
// closed, it is truly freed).
@@ -331,8 +355,6 @@ SharedMemoryHandle SharedMemory::handle() const {
}
void SharedMemory::Close() {
- Unmap();
-
if (mapped_file_ > 0) {
if (close(mapped_file_) < 0)
PLOG(ERROR) << "close";
@@ -454,7 +476,7 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
case SHARE_READONLY:
// We could imagine re-opening the file from /dev/fd, but that can't make
// it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
- CHECK(readonly_mapped_file_ >= 0);
+ CHECK_GE(readonly_mapped_file_, 0);
handle_to_dup = readonly_mapped_file_;
break;
}
@@ -468,8 +490,10 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
new_handle->fd = new_fd;
new_handle->auto_close = true;
- if (close_self)
+ if (close_self) {
+ Unmap();
Close();
+ }
return true;
}
diff --git a/chromium/base/memory/shared_memory_unittest.cc b/chromium/base/memory/shared_memory_unittest.cc
index 0b3fd7b1dd7..6fe57060e6f 100644
--- a/chromium/base/memory/shared_memory_unittest.cc
+++ b/chromium/base/memory/shared_memory_unittest.cc
@@ -101,10 +101,10 @@ const char* const MultipleThreadMain::s_test_name_ =
class MultipleLockThread : public PlatformThread::Delegate {
public:
explicit MultipleLockThread(int id) : id_(id) {}
- virtual ~MultipleLockThread() {}
+ ~MultipleLockThread() override {}
// PlatformThread::Delegate interface.
- virtual void ThreadMain() override {
+ void ThreadMain() override {
const uint32 kDataSize = sizeof(int);
SharedMemoryHandle handle = NULL;
{
@@ -260,6 +260,29 @@ TEST(SharedMemoryTest, OpenExclusive) {
}
#endif
+// Check that memory is still mapped after its closed.
+TEST(SharedMemoryTest, CloseNoUnmap) {
+ const size_t kDataSize = 4096;
+
+ SharedMemory memory;
+ ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+ char* ptr = static_cast<char*>(memory.memory());
+ ASSERT_NE(ptr, static_cast<void*>(NULL));
+ memset(ptr, 'G', kDataSize);
+
+ memory.Close();
+
+ EXPECT_EQ(ptr, memory.memory());
+ EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle());
+
+ for (size_t i = 0; i < kDataSize; i++) {
+ EXPECT_EQ('G', ptr[i]);
+ }
+
+ memory.Unmap();
+ EXPECT_EQ(nullptr, memory.memory());
+}
+
// Create a set of N threads to each open a shared memory segment and write to
// it. Verify that they are always reading/writing consistent data.
TEST(SharedMemoryTest, MultipleThreads) {
@@ -676,15 +699,15 @@ const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
TEST_F(SharedMemoryProcessTest, Tasks) {
SharedMemoryProcessTest::CleanUp();
- ProcessHandle handles[kNumTasks];
+ Process processes[kNumTasks];
for (int index = 0; index < kNumTasks; ++index) {
- handles[index] = SpawnChild("SharedMemoryTestMain");
- ASSERT_TRUE(handles[index]);
+ processes[index] = SpawnChild("SharedMemoryTestMain");
+ ASSERT_TRUE(processes[index].IsValid());
}
int exit_code = 0;
for (int index = 0; index < kNumTasks; ++index) {
- EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code));
+ EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
EXPECT_EQ(0, exit_code);
}
diff --git a/chromium/base/memory/shared_memory_win.cc b/chromium/base/memory/shared_memory_win.cc
index eef7f037752..7e0cf0bf23e 100644
--- a/chromium/base/memory/shared_memory_win.cc
+++ b/chromium/base/memory/shared_memory_win.cc
@@ -71,6 +71,7 @@ SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
}
SharedMemory::~SharedMemory() {
+ Unmap();
Close();
if (lock_ != NULL)
CloseHandle(lock_);
@@ -118,8 +119,8 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
return false;
size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
- name_ = ASCIIToWide(options.name_deprecated == NULL ? "" :
- *options.name_deprecated);
+ name_ = options.name_deprecated ?
+ ASCIIToUTF16(*options.name_deprecated) : L"";
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
SECURITY_DESCRIPTOR sd;
ACL dacl;
@@ -137,13 +138,14 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
// Windows ignores DACLs on certain unnamed objects (like shared sections).
// So, we generate a random name when we need to enforce read-only.
uint64_t rand_values[4];
- base::RandBytes(&rand_values, sizeof(rand_values));
- name_ = base::StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
- rand_values[0], rand_values[1],
- rand_values[2], rand_values[3]);
+ RandBytes(&rand_values, sizeof(rand_values));
+ name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
+ rand_values[0], rand_values[1],
+ rand_values[2], rand_values[3]);
}
mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
- PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size), name_.c_str());
+ PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
+ name_.empty() ? nullptr : name_.c_str());
if (!mapped_file_)
return false;
@@ -171,7 +173,7 @@ bool SharedMemory::Delete(const std::string& name) {
bool SharedMemory::Open(const std::string& name, bool read_only) {
DCHECK(!mapped_file_);
- name_ = ASCIIToWide(name);
+ name_ = ASCIIToUTF16(name);
read_only_ = read_only;
mapped_file_ = OpenFileMapping(
read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
@@ -218,7 +220,7 @@ bool SharedMemory::Unmap() {
}
bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
- SharedMemoryHandle *new_handle,
+ SharedMemoryHandle* new_handle,
bool close_self,
ShareMode share_mode) {
*new_handle = 0;
@@ -249,11 +251,6 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
void SharedMemory::Close() {
- if (memory_ != NULL) {
- UnmapViewOfFile(memory_);
- memory_ = NULL;
- }
-
if (mapped_file_ != NULL) {
CloseHandle(mapped_file_);
mapped_file_ = NULL;
diff --git a/chromium/base/memory/singleton.h b/chromium/base/memory/singleton.h
index e5e2e3efed0..e50bdc05f34 100644
--- a/chromium/base/memory/singleton.h
+++ b/chromium/base/memory/singleton.h
@@ -23,7 +23,6 @@
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/memory/aligned_memory.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_restrictions.h"
namespace base {
@@ -237,8 +236,6 @@ class Singleton {
// instance_ pointer must acquire visibility over the singleton data.
base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
if (value != 0 && value != base::internal::kBeingCreatedMarker) {
- // See the corresponding HAPPENS_BEFORE below.
- ANNOTATE_HAPPENS_AFTER(&instance_);
return reinterpret_cast<Type*>(value);
}
@@ -250,10 +247,6 @@ class Singleton {
// stop right after we do this store.
Type* newval = Traits::New();
- // This annotation helps race detectors recognize correct lock-less
- // synchronization between different threads calling get().
- // See the corresponding HAPPENS_AFTER below and above.
- ANNOTATE_HAPPENS_BEFORE(&instance_);
// Releases the visibility over instance_ to the readers.
base::subtle::Release_Store(
&instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
@@ -267,8 +260,6 @@ class Singleton {
// We hit a race. Wait for the other thread to complete it.
value = base::internal::WaitForInstance(&instance_);
- // See the corresponding HAPPENS_BEFORE above.
- ANNOTATE_HAPPENS_AFTER(&instance_);
return reinterpret_cast<Type*>(value);
}
diff --git a/chromium/base/memory/singleton_unittest.cc b/chromium/base/memory/singleton_unittest.cc
index 0e9ecdc03aa..dbff007ada7 100644
--- a/chromium/base/memory/singleton_unittest.cc
+++ b/chromium/base/memory/singleton_unittest.cc
@@ -153,7 +153,7 @@ class SingletonTest : public testing::Test {
public:
SingletonTest() {}
- virtual void SetUp() override {
+ void SetUp() override {
non_leak_called_ = false;
leaky_called_ = false;
static_called_ = false;
diff --git a/chromium/base/memory/weak_ptr_unittest.cc b/chromium/base/memory/weak_ptr_unittest.cc
index d89a5c6bbda..20e5c7b05c2 100644
--- a/chromium/base/memory/weak_ptr_unittest.cc
+++ b/chromium/base/memory/weak_ptr_unittest.cc
@@ -8,8 +8,9 @@
#include "base/bind.h"
#include "base/debug/leak_annotations.h"
+#include "base/location.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,9 +26,8 @@ class OffThreadObjectCreator {
{
Thread creator_thread("creator_thread");
creator_thread.Start();
- creator_thread.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(OffThreadObjectCreator::CreateObject, &result));
+ creator_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(OffThreadObjectCreator::CreateObject, &result));
}
DCHECK(result); // We synchronized on thread destruction above.
return result;
@@ -66,25 +66,23 @@ class BackgroundThread : public Thread {
void CreateArrowFromTarget(Arrow** arrow, Target* target) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
- arrow, target, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
+ target, &completion));
completion.Wait();
}
void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
- arrow, other, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
+ other, &completion));
completion.Wait();
}
void DeleteTarget(Target* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
completion.Wait();
@@ -92,25 +90,23 @@ class BackgroundThread : public Thread {
void CopyAndAssignArrow(Arrow* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCopyAndAssignArrow,
- object, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
+ &completion));
completion.Wait();
}
void CopyAndAssignArrowBase(Arrow* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
- object, &completion));
+ task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
+ object, &completion));
completion.Wait();
}
void DeleteArrow(Arrow* object) {
WaitableEvent completion(true, false);
- message_loop()->PostTask(
+ task_runner()->PostTask(
FROM_HERE,
base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
completion.Wait();
@@ -119,9 +115,8 @@ class BackgroundThread : public Thread {
Target* DeRef(const Arrow* arrow) {
WaitableEvent completion(true, false);
Target* result = NULL;
- message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion));
+ task_runner()->PostTask(FROM_HERE, base::Bind(&BackgroundThread::DoDeRef,
+ arrow, &result, &completion));
completion.Wait();
return result;
}
diff --git a/chromium/base/message_loop/incoming_task_queue.cc b/chromium/base/message_loop/incoming_task_queue.cc
index 2ca32d6254b..c1ce939b0c4 100644
--- a/chromium/base/message_loop/incoming_task_queue.cc
+++ b/chromium/base/message_loop/incoming_task_queue.cc
@@ -4,18 +4,47 @@
#include "base/message_loop/incoming_task_queue.h"
+#include <limits>
+
#include "base/location.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
namespace base {
namespace internal {
+namespace {
+
+#ifndef NDEBUG
+// Delays larger than this are often bogus, and a warning should be emitted in
+// debug builds to warn developers. http://crbug.com/450045
+const int kTaskDelayWarningThresholdInSeconds =
+ 14 * 24 * 60 * 60; // 14 days.
+#endif
+
+// Returns true if MessagePump::ScheduleWork() must be called one
+// time for every task that is added to the MessageLoop incoming queue.
+bool AlwaysNotifyPump(MessageLoop::Type type) {
+#if defined(OS_ANDROID)
+ // The Android UI message loop needs to get notified each time a task is
+ // added
+ // to the incoming queue.
+ return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
+#else
+ return false;
+#endif
+}
+
+} // namespace
+
IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
: high_res_task_count_(0),
message_loop_(message_loop),
- next_sequence_num_(0) {
+ next_sequence_num_(0),
+ message_loop_scheduled_(false),
+ always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {
}
bool IncomingTaskQueue::AddToIncomingQueue(
@@ -23,6 +52,11 @@ bool IncomingTaskQueue::AddToIncomingQueue(
const Closure& task,
TimeDelta delay,
bool nestable) {
+ DLOG_IF(WARNING,
+ delay.InSeconds() > kTaskDelayWarningThresholdInSeconds)
+ << "Requesting super-long task delay period of " << delay.InSeconds()
+ << " seconds from here: " << from_here.ToString();
+
AutoLock locked(incoming_queue_lock_);
PendingTask pending_task(
from_here, task, CalculateDelayedRuntime(delay), nestable);
@@ -56,9 +90,14 @@ int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
// Acquire all we can from the inter-thread queue with one lock acquisition.
AutoLock lock(incoming_queue_lock_);
- if (!incoming_queue_.empty())
+ if (incoming_queue_.empty()) {
+ // If the loop attempts to reload but there are no tasks in the incoming
+ // queue, that means it will go to sleep waiting for more work. If the
+ // incoming queue becomes nonempty we need to schedule it again.
+ message_loop_scheduled_ = false;
+ } else {
incoming_queue_.Swap(work_queue);
-
+ }
// Reset the count of high resolution tasks since our queue is now empty.
int high_res_tasks = high_res_task_count_;
high_res_task_count_ = 0;
@@ -109,8 +148,16 @@ bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
incoming_queue_.push(*pending_task);
pending_task->task.Reset();
- // Wake up the pump.
- message_loop_->ScheduleWork(was_empty);
+ if (always_schedule_work_ || (!message_loop_scheduled_ && was_empty)) {
+ // Wake up the message loop.
+ message_loop_->ScheduleWork();
+ // After we've scheduled the message loop, we do not need to do so again
+ // until we know it has processed all of the work in our queue and is
+ // waiting for more work again. The message loop will always attempt to
+ // reload from the incoming queue before waiting again so we clear this flag
+ // in ReloadWorkQueue().
+ message_loop_scheduled_ = true;
+ }
return true;
}
diff --git a/chromium/base/message_loop/incoming_task_queue.h b/chromium/base/message_loop/incoming_task_queue.h
index 30f26033a2d..72e1f302829 100644
--- a/chromium/base/message_loop/incoming_task_queue.h
+++ b/chromium/base/message_loop/incoming_task_queue.h
@@ -84,6 +84,14 @@ class BASE_EXPORT IncomingTaskQueue
// The next sequence number to use for delayed tasks.
int next_sequence_num_;
+ // True if our message loop has already been scheduled and does not need to be
+ // scheduled again until an empty reload occurs.
+ bool message_loop_scheduled_;
+
+ // True if we always need to call ScheduleWork when receiving a new task, even
+ // if the incoming queue was not empty.
+ const bool always_schedule_work_;
+
DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
};
diff --git a/chromium/base/message_loop/message_loop.cc b/chromium/base/message_loop/message_loop.cc
index 01402d070e3..eb0f9688494 100644
--- a/chromium/base/message_loop/message_loop.cc
+++ b/chromium/base/message_loop/message_loop.cc
@@ -86,18 +86,6 @@ bool enable_histogrammer_ = false;
MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
-// Returns true if MessagePump::ScheduleWork() must be called one
-// time for every task that is added to the MessageLoop incoming queue.
-bool AlwaysNotifyPump(MessageLoop::Type type) {
-#if defined(OS_ANDROID)
- // The Android UI message loop needs to get notified each time a task is added
- // to the incoming queue.
- return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
-#else
- return false;
-#endif
-}
-
#if defined(OS_IOS)
typedef MessagePumpIOSForIO MessagePumpForIO;
#elif defined(OS_NACL_SFI)
@@ -106,9 +94,11 @@ typedef MessagePumpDefault MessagePumpForIO;
typedef MessagePumpLibevent MessagePumpForIO;
#endif
+#if !defined(OS_NACL_SFI)
MessagePumpForIO* ToPumpIO(MessagePump* pump) {
return static_cast<MessagePumpForIO*>(pump);
}
+#endif // !defined(OS_NACL_SFI)
} // namespace
@@ -127,8 +117,10 @@ MessageLoop::DestructionObserver::~DestructionObserver() {
MessageLoop::MessageLoop(Type type)
: type_(type),
+#if defined(OS_WIN)
pending_high_res_tasks_(0),
in_high_res_mode_(false),
+#endif
nestable_tasks_allowed_(true),
#if defined(OS_WIN)
os_modal_loop_(false),
@@ -143,8 +135,10 @@ MessageLoop::MessageLoop(Type type)
MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
: pump_(pump.Pass()),
type_(TYPE_CUSTOM),
+#if defined(OS_WIN)
pending_high_res_tasks_(0),
in_high_res_mode_(false),
+#endif
nestable_tasks_allowed_(true),
#if defined(OS_WIN)
os_modal_loop_(false),
@@ -158,7 +152,12 @@ MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
MessageLoop::~MessageLoop() {
DCHECK_EQ(this, current());
+ // iOS just attaches to the loop, it doesn't Run it.
+ // TODO(stuartmorgan): Consider wiring up a Detach().
+#if !defined(OS_IOS)
DCHECK(!run_loop_);
+#endif
+
#if defined(OS_WIN)
if (in_high_res_mode_)
Time::ActivateHighResolutionTimer(false);
@@ -276,31 +275,27 @@ void MessageLoop::RemoveDestructionObserver(
void MessageLoop::PostTask(
const tracked_objects::Location& from_here,
const Closure& task) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true);
+ message_loop_proxy_->PostTask(from_here, task);
}
void MessageLoop::PostDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true);
+ message_loop_proxy_->PostDelayedTask(from_here, task, delay);
}
void MessageLoop::PostNonNestableTask(
const tracked_objects::Location& from_here,
const Closure& task) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false);
+ message_loop_proxy_->PostNonNestableTask(from_here, task);
}
void MessageLoop::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false);
+ message_loop_proxy_->PostNonNestableDelayedTask(from_here, task, delay);
}
void MessageLoop::Run() {
@@ -432,10 +427,13 @@ bool MessageLoop::ProcessNextDelayedNonNestableTask() {
void MessageLoop::RunTask(const PendingTask& pending_task) {
DCHECK(nestable_tasks_allowed_);
+#if defined(OS_WIN)
if (pending_task.is_high_res) {
pending_high_res_tasks_--;
- CHECK(pending_high_res_tasks_ >= 0);
+ CHECK_GE(pending_high_res_tasks_, 0);
}
+#endif
+
// Execute the task and assume the worst: It is probably not reentrant.
nestable_tasks_allowed_ = false;
@@ -505,14 +503,17 @@ void MessageLoop::ReloadWorkQueue() {
// load. That reduces the number of locks-per-task significantly when our
// queues get large.
if (work_queue_.empty()) {
+#if defined(OS_WIN)
pending_high_res_tasks_ +=
incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+#else
+ incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+#endif
}
}
-void MessageLoop::ScheduleWork(bool was_empty) {
- if (was_empty || AlwaysNotifyPump(type_))
- pump_->ScheduleWork();
+void MessageLoop::ScheduleWork() {
+ pump_->ScheduleWork();
}
//------------------------------------------------------------------------------
@@ -703,8 +704,8 @@ bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
bool MessageLoopForIO::WatchFileDescriptor(int fd,
bool persistent,
Mode mode,
- FileDescriptorWatcher *controller,
- Watcher *delegate) {
+ FileDescriptorWatcher* controller,
+ Watcher* delegate) {
return ToPumpIO(pump_.get())->WatchFileDescriptor(
fd,
persistent,
diff --git a/chromium/base/message_loop/message_loop.h b/chromium/base/message_loop/message_loop.h
index 47df69a921b..fd7596a7920 100644
--- a/chromium/base/message_loop/message_loop.h
+++ b/chromium/base/message_loop/message_loop.h
@@ -106,7 +106,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
TYPE_IO,
#if defined(OS_ANDROID)
TYPE_JAVA,
-#endif // defined(OS_ANDROID)
+#endif // defined(OS_ANDROID)
};
// Normally, it is not necessary to instantiate a MessageLoop. Instead, it
@@ -155,6 +155,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// DestructionObserver is receiving a notification callback.
void RemoveDestructionObserver(DestructionObserver* destruction_observer);
+ // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces.
+ // TODO(skyostil): Remove these functions (crbug.com/465354).
+ //
// The "PostTask" family of methods call the task's Run method asynchronously
// from within a message loop at some point in the future.
//
@@ -300,6 +303,8 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
}
// Gets the TaskRunner associated with this message loop.
+ // TODO(skyostil): Change this to return a const reference to a refptr
+ // once the internal type matches what is being returned (crbug.com/465354).
scoped_refptr<SingleThreadTaskRunner> task_runner() {
return message_loop_proxy_;
}
@@ -391,7 +396,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// Wakes up the message pump. Can be called on any thread. The caller is
// responsible for synchronizing ScheduleWork() calls.
- void ScheduleWork(bool was_empty);
+ void ScheduleWork();
// Returns the TaskAnnotator which is used to add debug information to posted
// tasks.
@@ -452,6 +457,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// this queue is only accessed (push/pop) by our current thread.
TaskQueue work_queue_;
+#if defined(OS_WIN)
// How many high resolution tasks are in the pending task queue. This value
// increases by N every time we call ReloadWorkQueue() and decreases by 1
// every time we call RunTask() if the task needs a high resolution timer.
@@ -459,6 +465,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// Tracks if we have requested high resolution timers. Its only use is to
// turn off the high resolution timer upon loop destruction.
bool in_high_res_mode_;
+#endif
// Contains delayed tasks, sorted by their 'delayed_run_time' property.
DelayedTaskQueue delayed_work_queue_;
@@ -639,8 +646,8 @@ class BASE_EXPORT MessageLoopForIO : public MessageLoop {
bool WatchFileDescriptor(int fd,
bool persistent,
Mode mode,
- FileDescriptorWatcher *controller,
- Watcher *delegate);
+ FileDescriptorWatcher* controller,
+ Watcher* delegate);
#endif // defined(OS_IOS) || defined(OS_POSIX)
#endif // !defined(OS_NACL_SFI)
};
diff --git a/chromium/base/message_loop/message_loop_proxy.h b/chromium/base/message_loop/message_loop_proxy.h
index 88eeac4ee6d..d5ecc041b6f 100644
--- a/chromium/base/message_loop/message_loop_proxy.h
+++ b/chromium/base/message_loop/message_loop_proxy.h
@@ -10,6 +10,18 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
+// MessageLoopProxy is deprecated. Code should prefer to depend on TaskRunner
+// (or the various specializations) for passing task runners around, and should
+// use ThreadTaskRunnerHandle::Get() to get the thread's associated task runner.
+//
+// See http://crbug.com/391045 for more details.
+// Example for these changes:
+//
+// base::MessageLoopProxy::current() -> base::ThreadTaskRunnerHandle::Get()
+// scoped_refptr<base::MessageLoopProxy> ->
+// scoped_refptr<base::SingleThreadTaskRunner>
+// base::MessageLoopProxy -> base::SingleThreadTaskRunner
+
namespace base {
// This class provides a thread-safe refcounted interface to the Post* methods
diff --git a/chromium/base/message_loop/message_loop_proxy_impl_unittest.cc b/chromium/base/message_loop/message_loop_proxy_impl_unittest.cc
index 5f31140303f..fa253717654 100644
--- a/chromium/base/message_loop/message_loop_proxy_impl_unittest.cc
+++ b/chromium/base/message_loop/message_loop_proxy_impl_unittest.cc
@@ -38,14 +38,14 @@ class MessageLoopProxyImplTest : public testing::Test {
}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
io_thread_.reset(new Thread("MessageLoopProxyImplTest_IO"));
file_thread_.reset(new Thread("MessageLoopProxyImplTest_File"));
io_thread_->Start();
file_thread_->Start();
}
- virtual void TearDown() override {
+ void TearDown() override {
io_thread_->Stop();
file_thread_->Stop();
}
diff --git a/chromium/base/message_loop/message_loop_proxy_unittest.cc b/chromium/base/message_loop/message_loop_proxy_unittest.cc
index 673ed884001..0b0d9f8ad00 100644
--- a/chromium/base/message_loop/message_loop_proxy_unittest.cc
+++ b/chromium/base/message_loop/message_loop_proxy_unittest.cc
@@ -31,7 +31,7 @@ class MessageLoopProxyTest : public testing::Test {
}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
// Use SetUp() instead of the constructor to avoid posting a task to a
// partialy constructed object.
task_thread_.Start();
@@ -42,7 +42,7 @@ class MessageLoopProxyTest : public testing::Test {
Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
}
- virtual void TearDown() override {
+ void TearDown() override {
// Make sure the |task_thread_| is not blocked, and stop the thread
// fully before destuction because its tasks may still depend on the
// |thread_sync_| event.
diff --git a/chromium/base/message_loop/message_loop_unittest.cc b/chromium/base/message_loop/message_loop_unittest.cc
index 733f5e5b510..ddde6bb170d 100644
--- a/chromium/base/message_loop/message_loop_unittest.cc
+++ b/chromium/base/message_loop/message_loop_unittest.cc
@@ -425,7 +425,7 @@ class DispatcherImpl : public MessagePumpDispatcher {
public:
DispatcherImpl() : dispatch_count_(0) {}
- virtual uint32_t Dispatch(const NativeEvent& msg) override {
+ uint32_t Dispatch(const NativeEvent& msg) override {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
// Do not count WM_TIMER since it is not what we post and it will cause
@@ -489,8 +489,9 @@ class TestIOHandler : public MessageLoopForIO::IOHandler {
public:
TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
- virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered, DWORD error);
+ void OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered,
+ DWORD error) override;
void Init();
void WaitForIO();
@@ -668,14 +669,12 @@ class DummyTaskObserver : public MessageLoop::TaskObserver {
void WillProcessTask(const PendingTask& pending_task) override {
num_tasks_started_++;
- EXPECT_TRUE(pending_task.time_posted != TimeTicks());
EXPECT_LE(num_tasks_started_, num_tasks_);
EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
}
void DidProcessTask(const PendingTask& pending_task) override {
num_tasks_processed_++;
- EXPECT_TRUE(pending_task.time_posted != TimeTicks());
EXPECT_LE(num_tasks_started_, num_tasks_);
EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
}
diff --git a/chromium/base/message_loop/message_pump_android.h b/chromium/base/message_loop/message_pump_android.h
index 9b4540f6ff9..d48050d21d1 100644
--- a/chromium/base/message_loop/message_pump_android.h
+++ b/chromium/base/message_loop/message_pump_android.h
@@ -22,12 +22,12 @@ class TimeTicks;
class BASE_EXPORT MessagePumpForUI : public MessagePump {
public:
MessagePumpForUI();
- virtual ~MessagePumpForUI();
+ ~MessagePumpForUI() override;
- virtual void Run(Delegate* delegate) override;
- virtual void Quit() override;
- virtual void ScheduleWork() override;
- virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+ void Run(Delegate* delegate) override;
+ void Quit() override;
+ void ScheduleWork() override;
+ void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
virtual void Start(Delegate* delegate);
diff --git a/chromium/base/message_loop/message_pump_default.cc b/chromium/base/message_loop/message_pump_default.cc
index 27c19e0227b..bb9d8ce9ffc 100644
--- a/chromium/base/message_loop/message_pump_default.cc
+++ b/chromium/base/message_loop/message_pump_default.cc
@@ -52,7 +52,8 @@ void MessagePumpDefault::Run(Delegate* delegate) {
event_.Wait();
} else {
TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
- if (delay > TimeDelta()) {
+ // If the delay is under 1 ms we need to execute the task right away.
+ if (delay.InMilliseconds() >= 1) {
event_.TimedWait(delay);
} else {
// It looks like delayed_work_time_ indicates a time in the past, so we
diff --git a/chromium/base/message_loop/message_pump_default.h b/chromium/base/message_loop/message_pump_default.h
index d63e8101a93..8aeaa62fcd2 100644
--- a/chromium/base/message_loop/message_pump_default.h
+++ b/chromium/base/message_loop/message_pump_default.h
@@ -38,4 +38,4 @@ class BASE_EXPORT MessagePumpDefault : public MessagePump {
} // namespace base
-#endif // BASE__MESSAGE_LOOPMESSAGE_PUMP_DEFAULT_H_
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
diff --git a/chromium/base/message_loop/message_pump_dispatcher.h b/chromium/base/message_loop/message_pump_dispatcher.h
index 0dea22662f9..5b1bd55b5e7 100644
--- a/chromium/base/message_loop/message_pump_dispatcher.h
+++ b/chromium/base/message_loop/message_pump_dispatcher.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H
-#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
#include <stdint.h>
@@ -40,4 +40,4 @@ class BASE_EXPORT MessagePumpDispatcher {
} // namespace base
-#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H
+#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
diff --git a/chromium/base/message_loop/message_pump_glib_unittest.cc b/chromium/base/message_loop/message_pump_glib_unittest.cc
index ae4fefe2e75..7ddd4f08a04 100644
--- a/chromium/base/message_loop/message_pump_glib_unittest.cc
+++ b/chromium/base/message_loop/message_pump_glib_unittest.cc
@@ -161,11 +161,11 @@ class MessagePumpGLibTest : public testing::Test {
MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { }
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
loop_ = new MessageLoop(MessageLoop::TYPE_UI);
injector_ = new EventInjector();
}
- virtual void TearDown() override {
+ void TearDown() override {
delete injector_;
injector_ = NULL;
delete loop_;
diff --git a/chromium/base/message_loop/message_pump_io_ios.h b/chromium/base/message_loop/message_pump_io_ios.h
index 18af4a8fe33..317a59c5d9a 100644
--- a/chromium/base/message_loop/message_pump_io_ios.h
+++ b/chromium/base/message_loop/message_pump_io_ios.h
@@ -97,7 +97,7 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop {
};
MessagePumpIOSForIO();
- virtual ~MessagePumpIOSForIO();
+ ~MessagePumpIOSForIO() override;
// Have the current thread's message loop watch for a a situation in which
// reading/writing to the FD can be performed without blocking.
diff --git a/chromium/base/message_loop/message_pump_io_ios_unittest.cc b/chromium/base/message_loop/message_pump_io_ios_unittest.cc
index 0bf8c082f36..ba96f83bbf0 100644
--- a/chromium/base/message_loop/message_pump_io_ios_unittest.cc
+++ b/chromium/base/message_loop/message_pump_io_ios_unittest.cc
@@ -18,9 +18,9 @@ class MessagePumpIOSForIOTest : public testing::Test {
MessagePumpIOSForIOTest()
: ui_loop_(MessageLoop::TYPE_UI),
io_thread_("MessagePumpIOSForIOTestIOThread") {}
- virtual ~MessagePumpIOSForIOTest() {}
+ ~MessagePumpIOSForIOTest() override {}
- virtual void SetUp() override {
+ void SetUp() override {
Thread::Options options(MessageLoop::TYPE_IO, 0);
ASSERT_TRUE(io_thread_.StartWithOptions(options));
ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
@@ -30,7 +30,7 @@ class MessagePumpIOSForIOTest : public testing::Test {
ASSERT_EQ(0, ret);
}
- virtual void TearDown() override {
+ void TearDown() override {
if (IGNORE_EINTR(close(pipefds_[0])) < 0)
PLOG(ERROR) << "close";
if (IGNORE_EINTR(close(pipefds_[1])) < 0)
@@ -64,11 +64,11 @@ namespace {
// nothing useful.
class StupidWatcher : public MessagePumpIOSForIO::Watcher {
public:
- virtual ~StupidWatcher() {}
+ ~StupidWatcher() override {}
// base:MessagePumpIOSForIO::Watcher interface
- virtual void OnFileCanReadWithoutBlocking(int fd) override {}
- virtual void OnFileCanWriteWithoutBlocking(int fd) override {}
+ void OnFileCanReadWithoutBlocking(int fd) override {}
+ void OnFileCanWriteWithoutBlocking(int fd) override {}
};
#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
@@ -93,16 +93,12 @@ class BaseWatcher : public MessagePumpIOSForIO::Watcher {
: controller_(controller) {
DCHECK(controller_);
}
- virtual ~BaseWatcher() {}
+ ~BaseWatcher() override {}
// MessagePumpIOSForIO::Watcher interface
- virtual void OnFileCanReadWithoutBlocking(int /* fd */) override {
- NOTREACHED();
- }
+ void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
- virtual void OnFileCanWriteWithoutBlocking(int /* fd */) override {
- NOTREACHED();
- }
+ void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
protected:
MessagePumpIOSForIO::FileDescriptorWatcher* controller_;
@@ -114,11 +110,9 @@ class DeleteWatcher : public BaseWatcher {
MessagePumpIOSForIO::FileDescriptorWatcher* controller)
: BaseWatcher(controller) {}
- virtual ~DeleteWatcher() {
- DCHECK(!controller_);
- }
+ ~DeleteWatcher() override { DCHECK(!controller_); }
- virtual void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+ void OnFileCanWriteWithoutBlocking(int /* fd */) override {
DCHECK(controller_);
delete controller_;
controller_ = NULL;
@@ -146,9 +140,9 @@ class StopWatcher : public BaseWatcher {
pump_(pump),
fd_to_start_watching_(fd_to_start_watching) {}
- virtual ~StopWatcher() {}
+ ~StopWatcher() override {}
- virtual void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+ void OnFileCanWriteWithoutBlocking(int /* fd */) override {
controller_->StopWatchingFileDescriptor();
if (fd_to_start_watching_ >= 0) {
pump_->WatchFileDescriptor(fd_to_start_watching_,
diff --git a/chromium/base/message_loop/message_pump_libevent.cc b/chromium/base/message_loop/message_pump_libevent.cc
index d52025a1990..b5b1fb7e81e 100644
--- a/chromium/base/message_loop/message_pump_libevent.cc
+++ b/chromium/base/message_loop/message_pump_libevent.cc
@@ -15,6 +15,7 @@
#include "base/observer_list.h"
#include "base/posix/eintr_wrapper.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "third_party/libevent/event.h"
#if defined(OS_MACOSX)
@@ -274,6 +275,9 @@ void MessagePumpLibevent::Run(Delegate* delegate) {
delayed_work_time_ = TimeTicks();
}
}
+
+ if (!keep_running_)
+ break;
}
}
@@ -341,6 +345,8 @@ void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
WeakPtr<FileDescriptorWatcher> controller =
static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
DCHECK(controller.get());
+ TRACE_EVENT1("toplevel", "MessagePumpLibevent::OnLibeventNotification",
+ "fd", fd);
MessagePumpLibevent* pump = controller->pump();
pump->processed_io_events_ = true;
diff --git a/chromium/base/message_loop/message_pump_libevent_unittest.cc b/chromium/base/message_loop/message_pump_libevent_unittest.cc
index f9b89c4230b..65d72172728 100644
--- a/chromium/base/message_loop/message_pump_libevent_unittest.cc
+++ b/chromium/base/message_loop/message_pump_libevent_unittest.cc
@@ -7,9 +7,14 @@
#include <unistd.h>
#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/waitable_event_watcher.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libevent/event.h"
@@ -19,11 +24,11 @@ namespace base {
class MessagePumpLibeventTest : public testing::Test {
protected:
MessagePumpLibeventTest()
- : ui_loop_(MessageLoop::TYPE_UI),
+ : ui_loop_(new MessageLoop(MessageLoop::TYPE_UI)),
io_thread_("MessagePumpLibeventTestIOThread") {}
- virtual ~MessagePumpLibeventTest() {}
+ ~MessagePumpLibeventTest() override {}
- virtual void SetUp() override {
+ void SetUp() override {
Thread::Options options(MessageLoop::TYPE_IO, 0);
ASSERT_TRUE(io_thread_.StartWithOptions(options));
ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
@@ -31,14 +36,13 @@ class MessagePumpLibeventTest : public testing::Test {
ASSERT_EQ(0, ret);
}
- virtual void TearDown() override {
+ void TearDown() override {
if (IGNORE_EINTR(close(pipefds_[0])) < 0)
PLOG(ERROR) << "close";
if (IGNORE_EINTR(close(pipefds_[1])) < 0)
PLOG(ERROR) << "close";
}
- MessageLoop* ui_loop() { return &ui_loop_; }
MessageLoopForIO* io_loop() const {
return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
}
@@ -50,9 +54,9 @@ class MessagePumpLibeventTest : public testing::Test {
}
int pipefds_[2];
+ scoped_ptr<MessageLoop> ui_loop_;
private:
- MessageLoop ui_loop_;
Thread io_thread_;
};
@@ -194,6 +198,69 @@ TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) {
OnLibeventNotification(pump.get(), &watcher);
}
+void FatalClosure() {
+ FAIL() << "Reached fatal closure.";
+}
+
+class QuitWatcher : public BaseWatcher {
+ public:
+ QuitWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller,
+ RunLoop* run_loop)
+ : BaseWatcher(controller), run_loop_(run_loop) {}
+ ~QuitWatcher() override {}
+
+ void OnFileCanReadWithoutBlocking(int /* fd */) override {
+ // Post a fatal closure to the MessageLoop before we quit it.
+ MessageLoop::current()->PostTask(FROM_HERE, Bind(&FatalClosure));
+
+ // Now quit the MessageLoop.
+ run_loop_->Quit();
+ }
+
+ private:
+ RunLoop* run_loop_; // weak
+};
+
+void WriteFDWrapper(const int fd,
+ const char* buf,
+ int size,
+ WaitableEvent* event) {
+ ASSERT_TRUE(WriteFileDescriptor(fd, buf, size));
+}
+
+// Tests that MessagePumpLibevent quits immediately when it is quit from
+// libevent's event_base_loop().
+TEST_F(MessagePumpLibeventTest, QuitWatcher) {
+ // Delete the old MessageLoop so that we can manage our own one here.
+ ui_loop_.reset();
+
+ MessagePumpLibevent* pump = new MessagePumpLibevent; // owned by |loop|.
+ MessageLoop loop(make_scoped_ptr(pump));
+ RunLoop run_loop;
+ MessagePumpLibevent::FileDescriptorWatcher controller;
+ QuitWatcher delegate(&controller, &run_loop);
+ WaitableEvent event(false /* manual_reset */, false /* initially_signaled */);
+ WaitableEventWatcher watcher;
+
+ // Tell the pump to watch the pipe.
+ pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpLibevent::WATCH_READ,
+ &controller, &delegate);
+
+ // Make the IO thread wait for |event| before writing to pipefds[1].
+ const char buf = 0;
+ const WaitableEventWatcher::EventCallback write_fd_task =
+ Bind(&WriteFDWrapper, pipefds_[1], &buf, 1);
+ io_loop()->PostTask(FROM_HERE,
+ Bind(IgnoreResult(&WaitableEventWatcher::StartWatching),
+ Unretained(&watcher), &event, write_fd_task));
+
+ // Queue |event| to signal on |loop|.
+ loop.PostTask(FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
+
+ // Now run the MessageLoop.
+ run_loop.Run();
+}
+
} // namespace
} // namespace base
diff --git a/chromium/base/message_loop/message_pump_mac.h b/chromium/base/message_loop/message_pump_mac.h
index 55ab2c674d4..c8532020847 100644
--- a/chromium/base/message_loop/message_pump_mac.h
+++ b/chromium/base/message_loop/message_pump_mac.h
@@ -263,9 +263,9 @@ class BASE_EXPORT MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
class MessagePumpUIApplication : public MessagePumpCFRunLoopBase {
public:
MessagePumpUIApplication();
- virtual ~MessagePumpUIApplication();
- virtual void DoRun(Delegate* delegate) override;
- virtual void Quit() override;
+ ~MessagePumpUIApplication() override;
+ void DoRun(Delegate* delegate) override;
+ void Quit() override;
// This message pump can not spin the main message loop directly. Instead,
// call |Attach()| to set up a delegate. It is an error to call |Run()|.
diff --git a/chromium/base/message_loop/message_pump_perftest.cc b/chromium/base/message_loop/message_pump_perftest.cc
index 9fca4653dbe..b3e5604c813 100644
--- a/chromium/base/message_loop/message_pump_perftest.cc
+++ b/chromium/base/message_loop/message_pump_perftest.cc
@@ -29,7 +29,7 @@ class ScheduleWorkTest : public testing::Test {
void Increment(uint64_t amount) { counter_ += amount; }
void Schedule(int index) {
- base::TimeTicks start = base::TimeTicks::HighResNow();
+ base::TimeTicks start = base::TimeTicks::Now();
base::TimeTicks thread_start;
if (TimeTicks::IsThreadNowSupported())
thread_start = base::TimeTicks::ThreadNow();
@@ -39,10 +39,10 @@ class ScheduleWorkTest : public testing::Test {
uint64_t schedule_calls = 0u;
do {
for (size_t i = 0; i < kBatchSize; ++i) {
- target_message_loop()->ScheduleWork(true);
+ target_message_loop()->ScheduleWork();
schedule_calls++;
}
- now = base::TimeTicks::HighResNow();
+ now = base::TimeTicks::Now();
base::TimeDelta laptime = now - lastnow;
lastnow = now;
minimum = std::min(minimum, laptime);
@@ -242,7 +242,7 @@ class FakeMessagePump : public MessagePump {
class PostTaskTest : public testing::Test {
public:
void Run(int batch_size, int tasks_per_reload) {
- base::TimeTicks start = base::TimeTicks::HighResNow();
+ base::TimeTicks start = base::TimeTicks::Now();
base::TimeTicks now;
MessageLoop loop(scoped_ptr<MessagePump>(new FakeMessagePump));
scoped_refptr<internal::IncomingTaskQueue> queue(
@@ -264,7 +264,7 @@ class PostTaskTest : public testing::Test {
}
}
- now = base::TimeTicks::HighResNow();
+ now = base::TimeTicks::Now();
} while (now - start < base::TimeDelta::FromSeconds(5));
std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
perf_test::PrintResult(
diff --git a/chromium/base/message_loop/message_pump_win.cc b/chromium/base/message_loop/message_pump_win.cc
index ad89b7f6384..27b47e1a0f8 100644
--- a/chromium/base/message_loop/message_pump_win.cc
+++ b/chromium/base/message_loop/message_pump_win.cc
@@ -4,13 +4,15 @@
#include "base/message_loop/message_pump_win.h"
+#include <limits>
#include <math.h>
-#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/wrapped_window_proc.h"
namespace base {
@@ -51,6 +53,10 @@ void MessagePumpWin::RunWithDispatcher(
state_ = previous_state;
}
+void MessagePumpWin::Run(Delegate* delegate) {
+ RunWithDispatcher(delegate, NULL);
+}
+
void MessagePumpWin::Quit() {
DCHECK(state_);
state_->should_quit = true;
@@ -69,12 +75,13 @@ int MessagePumpWin::GetCurrentDelay() const {
double timeout =
ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
- // If this value is negative, then we need to run delayed work soon.
- int delay = static_cast<int>(timeout);
- if (delay < 0)
- delay = 0;
-
- return delay;
+ // Range check the |timeout| while converting to an integer. If the |timeout|
+ // is negative, then we need to run delayed work soon. If the |timeout| is
+ // "overflowingly" large, that means a delayed task was posted with a
+ // super-long delay.
+ return timeout < 0 ? 0 :
+ (timeout > std::numeric_limits<int>::max() ?
+ std::numeric_limits<int>::max() : static_cast<int>(timeout));
}
//-----------------------------------------------------------------------------
@@ -161,6 +168,11 @@ void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
// static
LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::WndProcThunk1"));
+
switch (message) {
case kMsgHaveWork:
reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
@@ -169,6 +181,12 @@ LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
break;
}
+
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::WndProcThunk2"));
+
return DefWindowProc(hwnd, message, wparam, lparam);
}
@@ -319,6 +337,11 @@ void MessagePumpForUI::HandleTimerMessage() {
}
bool MessagePumpForUI::ProcessNextWindowsMessage() {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessNextWindowsMessage1"));
+
// If there are sent messages in the queue then PeekMessage internally
// dispatches the message and returns false. We return true in this
// case to ensure that the message loop peeks again instead of calling
@@ -328,6 +351,11 @@ bool MessagePumpForUI::ProcessNextWindowsMessage() {
if (HIWORD(queue_status) & QS_SENDMESSAGE)
sent_messages_in_queue = true;
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessNextWindowsMessage2"));
+
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE)
return ProcessMessageHelper(msg);
@@ -336,6 +364,11 @@ bool MessagePumpForUI::ProcessNextWindowsMessage() {
}
bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessMessageHelper1"));
+
TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
"message", msg.message);
if (WM_QUIT == msg.message) {
@@ -350,16 +383,43 @@ bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
return ProcessPumpReplacementMessage();
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessMessageHelper2"));
+
if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
return true;
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessMessageHelper3"));
+
uint32_t action = MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT;
- if (state_->dispatcher)
+ if (state_->dispatcher) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessMessageHelper4"));
+
action = state_->dispatcher->Dispatch(msg);
+ }
if (action & MessagePumpDispatcher::POST_DISPATCH_QUIT_LOOP)
state_->should_quit = true;
if (action & MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile5(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessMessageHelper5"));
+
TranslateMessage(&msg);
+
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 MessagePumpForUI::ProcessMessageHelper6"));
+
DispatchMessage(&msg);
}
@@ -416,6 +476,9 @@ MessagePumpForIO::MessagePumpForIO() {
DCHECK(port_.IsValid());
}
+MessagePumpForIO::~MessagePumpForIO() {
+}
+
void MessagePumpForIO::ScheduleWork() {
if (InterlockedExchange(&have_work_, 1))
return; // Someone else continued the pumping.
@@ -617,7 +680,7 @@ ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler,
// |IOHandler| is at least pointer-size aligned, so the lowest two bits are
// always cleared. We use the lowest bit to distinguish completion keys with
// and without the associated |IOContext|.
- DCHECK((key & 1) == 0);
+ DCHECK_EQ(key & 1, 0u);
// Mark the completion key as context-less.
if (!has_valid_io_context)
diff --git a/chromium/base/message_loop/message_pump_win.h b/chromium/base/message_loop/message_pump_win.h
index b2573174228..00f1287ce43 100644
--- a/chromium/base/message_loop/message_pump_win.h
+++ b/chromium/base/message_loop/message_pump_win.h
@@ -25,14 +25,13 @@ namespace base {
class BASE_EXPORT MessagePumpWin : public MessagePump {
public:
MessagePumpWin() : have_work_(0), state_(NULL) {}
- virtual ~MessagePumpWin() {}
// Like MessagePump::Run, but MSG objects are routed through dispatcher.
void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher);
// MessagePump methods:
- virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
- virtual void Quit();
+ void Run(Delegate* delegate) override;
+ void Quit() override;
protected:
struct RunState {
@@ -115,18 +114,18 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
static const int kMessageFilterCode = 0x5001;
MessagePumpForUI();
- virtual ~MessagePumpForUI();
+ ~MessagePumpForUI() override;
// MessagePump methods:
- virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+ void ScheduleWork() override;
+ void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
private:
static LRESULT CALLBACK WndProcThunk(HWND window_handle,
UINT message,
WPARAM wparam,
LPARAM lparam);
- virtual void DoRunLoop();
+ void DoRunLoop() override;
void InitMessageWnd();
void WaitForWork();
void HandleWorkMessage();
@@ -267,11 +266,11 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
};
MessagePumpForIO();
- virtual ~MessagePumpForIO() {}
+ ~MessagePumpForIO() override;
// MessagePump methods:
- virtual void ScheduleWork();
- virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+ void ScheduleWork() override;
+ void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
// Register the handler to be used when asynchronous IO for the given file
// completes. The registration persists as long as |file_handle| is valid, so
@@ -311,7 +310,7 @@ class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
bool has_valid_io_context;
};
- virtual void DoRunLoop();
+ void DoRunLoop() override;
void WaitForWork();
bool MatchCompletedIOItem(IOHandler* filter, IOItem* item);
bool GetIOItem(DWORD timeout, IOItem* item);
diff --git a/chromium/base/metrics/BUILD.gn b/chromium/base/metrics/BUILD.gn
new file mode 100644
index 00000000000..845ac4f79c8
--- /dev/null
+++ b/chromium/base/metrics/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright (c) 2015 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.
+
+source_set("metrics") {
+ sources = [
+ "bucket_ranges.cc",
+ "bucket_ranges.h",
+ "field_trial.cc",
+ "field_trial.h",
+ "histogram.cc",
+ "histogram.h",
+ "histogram_base.cc",
+ "histogram_base.h",
+ "histogram_delta_serialization.cc",
+ "histogram_delta_serialization.h",
+ "histogram_flattener.h",
+ "histogram_macros.h",
+ "histogram_samples.cc",
+ "histogram_samples.h",
+ "histogram_snapshot_manager.cc",
+ "histogram_snapshot_manager.h",
+ "sample_map.cc",
+ "sample_map.h",
+ "sample_vector.cc",
+ "sample_vector.h",
+ "sparse_histogram.cc",
+ "sparse_histogram.h",
+ "statistics_recorder.cc",
+ "statistics_recorder.h",
+ "user_metrics.cc",
+ "user_metrics.h",
+ "user_metrics_action.h",
+ ]
+
+ if (is_nacl) {
+ sources -= [ "field_trial.cc" ]
+ }
+
+ configs += [ "//base:base_implementation" ]
+
+ deps = [
+ "//base/debug",
+ "//base/json",
+ "//base/memory",
+ ]
+
+ visibility = [ "//base/*" ]
+}
diff --git a/chromium/base/metrics/field_trial.cc b/chromium/base/metrics/field_trial.cc
index 7efca7a3ef5..639f6d38e24 100644
--- a/chromium/base/metrics/field_trial.cc
+++ b/chromium/base/metrics/field_trial.cc
@@ -223,6 +223,20 @@ bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
return true;
}
+bool FieldTrial::GetState(FieldTrialState* field_trial_state) const {
+ if (!enable_field_trial_)
+ return false;
+ field_trial_state->trial_name = trial_name_;
+ // If the group name is empty (hasn't been finalized yet), use the default
+ // group name instead.
+ if (!group_name_.empty())
+ field_trial_state->group_name = group_name_;
+ else
+ field_trial_state->group_name = default_group_name_;
+ field_trial_state->activated = group_reported_;
+ return true;
+}
+
//------------------------------------------------------------------------------
// FieldTrialList methods and members.
@@ -387,6 +401,29 @@ void FieldTrialList::StatesToString(std::string* output) {
}
// static
+void FieldTrialList::AllStatesToString(std::string* output) {
+ if (!global_)
+ return;
+ AutoLock auto_lock(global_->lock_);
+
+ for (const auto& registered : global_->registered_) {
+ FieldTrial::FieldTrialState trial;
+ if (!registered.second->GetState(&trial))
+ continue;
+ DCHECK_EQ(std::string::npos,
+ trial.trial_name.find(kPersistentStringSeparator));
+ DCHECK_EQ(std::string::npos,
+ trial.group_name.find(kPersistentStringSeparator));
+ if (trial.activated)
+ output->append(1, kActivationMarker);
+ output->append(trial.trial_name);
+ output->append(1, kPersistentStringSeparator);
+ output->append(trial.group_name);
+ output->append(1, kPersistentStringSeparator);
+ }
+}
+
+// static
void FieldTrialList::GetActiveFieldTrialGroups(
FieldTrial::ActiveGroups* active_groups) {
DCHECK(active_groups->empty());
@@ -510,9 +547,8 @@ void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
return;
global_->observer_list_->Notify(
- &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
- field_trial->trial_name(),
- field_trial->group_name_internal());
+ FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
+ field_trial->trial_name(), field_trial->group_name_internal());
}
// static
diff --git a/chromium/base/metrics/field_trial.h b/chromium/base/metrics/field_trial.h
index e2e543947a1..26257ab4a89 100644
--- a/chromium/base/metrics/field_trial.h
+++ b/chromium/base/metrics/field_trial.h
@@ -106,6 +106,14 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
std::string group_name;
};
+ // A triplet representing a FieldTrial, its selected group and whether it's
+ // active.
+ struct FieldTrialState {
+ std::string trial_name;
+ std::string group_name;
+ bool activated;
+ };
+
typedef std::vector<ActiveGroup> ActiveGroups;
// A return value to indicate that a given instance has not yet had a group
@@ -180,8 +188,10 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
+ FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
+ FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
@@ -230,6 +240,13 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// untouched.
bool GetActiveGroup(ActiveGroup* active_group) const;
+ // Returns the trial name and selected group name for this field trial via
+ // the output parameter |field_trial_state|, but only if the trial has not
+ // been disabled. In that case, true is returned and |field_trial_state| is
+ // filled in; otherwise, the result is false and |field_trial_state| is left
+ // untouched.
+ bool GetState(FieldTrialState* field_trial_state) const;
+
// Returns the group_name. A winner need not have been chosen.
std::string group_name_internal() const { return group_name_; }
@@ -404,6 +421,16 @@ class BASE_EXPORT FieldTrialList {
// by |CreateTrialsFromString()|.
static void StatesToString(std::string* output);
+ // Creates a persistent representation of all FieldTrial instances for
+ // resurrection in another process. This allows randomization to be done in
+ // one process, and secondary processes can be synchronized on the result.
+ // The resulting string contains the name and group name pairs of all
+ // registered FieldTrials which have not been disabled, with "/" used
+ // to separate all names and to terminate the string. All activated trials
+ // have their name prefixed with "*". This string is parsed by
+ // |CreateTrialsFromString()|.
+ static void AllStatesToString(std::string* output);
+
// Fills in the supplied vector |active_groups| (which must be empty when
// called) with a snapshot of all registered FieldTrials for which the group
// has been chosen and externally observed (via |group()|) and which have
diff --git a/chromium/base/metrics/field_trial_unittest.cc b/chromium/base/metrics/field_trial_unittest.cc
index ce95c2ae15b..f1a10425852 100644
--- a/chromium/base/metrics/field_trial_unittest.cc
+++ b/chromium/base/metrics/field_trial_unittest.cc
@@ -311,6 +311,36 @@ TEST_F(FieldTrialTest, ActiveGroups) {
}
}
+TEST_F(FieldTrialTest, AllGroups) {
+ FieldTrial::FieldTrialState field_trial_state;
+ std::string one_winner("One Winner");
+ scoped_refptr<FieldTrial> trial =
+ CreateFieldTrial(one_winner, 10, "Default", NULL);
+ std::string winner("Winner");
+ trial->AppendGroup(winner, 10);
+ EXPECT_TRUE(trial->GetState(&field_trial_state));
+ EXPECT_EQ(one_winner, field_trial_state.trial_name);
+ EXPECT_EQ(winner, field_trial_state.group_name);
+ trial->group();
+ EXPECT_TRUE(trial->GetState(&field_trial_state));
+ EXPECT_EQ(one_winner, field_trial_state.trial_name);
+ EXPECT_EQ(winner, field_trial_state.group_name);
+
+ std::string multi_group("MultiGroup");
+ scoped_refptr<FieldTrial> multi_group_trial =
+ CreateFieldTrial(multi_group, 9, "Default", NULL);
+
+ multi_group_trial->AppendGroup("Me", 3);
+ multi_group_trial->AppendGroup("You", 3);
+ multi_group_trial->AppendGroup("Them", 3);
+ EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
+ // Finalize the group selection by accessing the selected group.
+ multi_group_trial->group();
+ EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
+ EXPECT_EQ(multi_group, field_trial_state.trial_name);
+ EXPECT_EQ(multi_group_trial->group_name(), field_trial_state.group_name);
+}
+
TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
const char kTrialName[] = "TestTrial";
const char kSecondaryGroupName[] = "SecondaryGroup";
@@ -388,6 +418,44 @@ TEST_F(FieldTrialTest, Save) {
EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string);
}
+TEST_F(FieldTrialTest, SaveAll) {
+ std::string save_string;
+
+ scoped_refptr<FieldTrial> trial =
+ CreateFieldTrial("Some name", 10, "Default some name", NULL);
+ EXPECT_EQ("", trial->group_name_internal());
+ FieldTrialList::AllStatesToString(&save_string);
+ EXPECT_EQ("Some name/Default some name/", save_string);
+ save_string.clear();
+
+ // Create a winning group.
+ trial->AppendGroup("Winner", 10);
+ // Finalize the group selection by accessing the selected group.
+ trial->group();
+ FieldTrialList::AllStatesToString(&save_string);
+ EXPECT_EQ("*Some name/Winner/", save_string);
+ save_string.clear();
+
+ // Create a second trial and winning group.
+ scoped_refptr<FieldTrial> trial2 =
+ CreateFieldTrial("xxx", 10, "Default xxx", NULL);
+ trial2->AppendGroup("yyyy", 10);
+ // Finalize the group selection by accessing the selected group.
+ trial2->group();
+
+ FieldTrialList::AllStatesToString(&save_string);
+ // We assume names are alphabetized... though this is not critical.
+ EXPECT_EQ("*Some name/Winner/*xxx/yyyy/", save_string);
+ save_string.clear();
+
+ // Create a third trial with only the default group.
+ scoped_refptr<FieldTrial> trial3 =
+ CreateFieldTrial("zzz", 10, "default", NULL);
+
+ FieldTrialList::AllStatesToString(&save_string);
+ EXPECT_EQ("*Some name/Winner/*xxx/yyyy/zzz/default/", save_string);
+}
+
TEST_F(FieldTrialTest, Restore) {
ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
@@ -1014,6 +1082,43 @@ TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
}
}
+TEST(FieldTrialTestWithoutList, StatesStringFormat) {
+ std::string save_string;
+
+ // Scoping the first FieldTrialList, as we need another one to test the
+ // importing function.
+ {
+ FieldTrialList field_trial_list(NULL);
+ scoped_refptr<FieldTrial> trial =
+ CreateFieldTrial("Abc", 10, "Default some name", NULL);
+ trial->AppendGroup("cba", 10);
+ trial->group();
+ scoped_refptr<FieldTrial> trial2 =
+ CreateFieldTrial("Xyz", 10, "Default xxx", NULL);
+ trial2->AppendGroup("zyx", 10);
+ trial2->group();
+ scoped_refptr<FieldTrial> trial3 =
+ CreateFieldTrial("zzz", 10, "default", NULL);
+
+ FieldTrialList::AllStatesToString(&save_string);
+ }
+
+ // Starting with a new blank FieldTrialList.
+ FieldTrialList field_trial_list(NULL);
+ ASSERT_TRUE(field_trial_list.CreateTrialsFromString(
+ save_string, FieldTrialList::DONT_ACTIVATE_TRIALS,
+ std::set<std::string>()));
+
+ FieldTrial::ActiveGroups active_groups;
+ field_trial_list.GetActiveFieldTrialGroups(&active_groups);
+ ASSERT_EQ(2U, active_groups.size());
+ EXPECT_EQ("Abc", active_groups[0].trial_name);
+ EXPECT_EQ("cba", active_groups[0].group_name);
+ EXPECT_EQ("Xyz", active_groups[1].trial_name);
+ EXPECT_EQ("zyx", active_groups[1].group_name);
+ EXPECT_TRUE(field_trial_list.TrialExists("zzz"));
+}
+
#if GTEST_HAS_DEATH_TEST
TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) {
// Trying to instantiate a one-time randomized field trial before the
diff --git a/chromium/base/metrics/histogram.cc b/chromium/base/metrics/histogram.cc
index fe5b6e6117c..42ced3d0abc 100644
--- a/chromium/base/metrics/histogram.cc
+++ b/chromium/base/metrics/histogram.cc
@@ -369,7 +369,7 @@ HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
samples->Add(*samples_);
- return samples;
+ return samples.Pass();
}
void Histogram::WriteAsciiImpl(bool graph_it,
@@ -495,13 +495,13 @@ void Histogram::GetCountAndBucketData(Count* count,
*sum = snapshot->sum();
size_t index = 0;
for (size_t i = 0; i < bucket_count(); ++i) {
- Sample count = snapshot->GetCountAtIndex(i);
- if (count > 0) {
+ Sample count_at_index = snapshot->GetCountAtIndex(i);
+ if (count_at_index > 0) {
scoped_ptr<DictionaryValue> bucket_value(new DictionaryValue());
bucket_value->SetInteger("low", ranges(i));
if (i != bucket_count() - 1)
bucket_value->SetInteger("high", ranges(i + 1));
- bucket_value->SetInteger("count", count);
+ bucket_value->SetInteger("count", count_at_index);
buckets->Set(index, bucket_value.release());
++index;
}
diff --git a/chromium/base/metrics/histogram.h b/chromium/base/metrics/histogram.h
index 5ed9d9eb9d6..9ee172e6cda 100644
--- a/chromium/base/metrics/histogram.h
+++ b/chromium/base/metrics/histogram.h
@@ -50,9 +50,12 @@
// at the low end of the histogram scale, but allows the histogram to cover a
// gigantic range with the addition of very few buckets.
-// Usually we use macros to define and use a histogram. These macros use a
-// pattern involving a function static variable, that is a pointer to a
-// histogram. This static is explicitly initialized on any thread
+// Usually we use macros to define and use a histogram, which are defined in
+// base/metrics/histogram_macros.h. Note: Callers should include that header
+// directly if they only access the histogram APIs through macros.
+//
+// Macros use a pattern involving a function static variable, that is a pointer
+// to a histogram. This static is explicitly initialized on any thread
// that detects a uninitialized (NULL) pointer. The potentially racy
// initialization is not a problem as it is always set to point to the same
// value (i.e., the FactoryGet always returns the same value). FactoryGet
@@ -67,7 +70,6 @@
#include <string>
#include <vector>
-#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
@@ -76,6 +78,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_base.h"
+// TODO(asvitkine): Migrate callers to to include this directly and remove this.
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/histogram_samples.h"
#include "base/time/time.h"
@@ -84,234 +88,11 @@ class PickleIterator;
namespace base {
-class Lock;
-//------------------------------------------------------------------------------
-// Histograms are often put in areas where they are called many many times, and
-// performance is critical. As a result, they are designed to have a very low
-// recurring cost of executing (adding additional samples). Toward that end,
-// the macros declare a static pointer to the histogram in question, and only
-// take a "slow path" to construct (or find) the histogram on the first run
-// through the macro. We leak the histograms at shutdown time so that we don't
-// have to validate using the pointers at any time during the running of the
-// process.
-
-// The following code is generally what a thread-safe static pointer
-// initialization looks like for a histogram (after a macro is expanded). This
-// sample is an expansion (with comments) of the code for
-// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
-
-/*
- do {
- // The pointer's presence indicates the initialization is complete.
- // Initialization is idempotent, so it can safely be atomically repeated.
- static base::subtle::AtomicWord atomic_histogram_pointer = 0;
-
- // Acquire_Load() ensures that we acquire visibility to the pointed-to data
- // in the histogram.
- base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
- base::subtle::Acquire_Load(&atomic_histogram_pointer)));
-
- if (!histogram_pointer) {
- // This is the slow path, which will construct OR find the matching
- // histogram. FactoryGet includes locks on a global histogram name map
- // and is completely thread safe.
- histogram_pointer = base::Histogram::FactoryGet(
- name, min, max, bucket_count, base::HistogramBase::kNoFlags);
-
- // Use Release_Store to ensure that the histogram data is made available
- // globally before we make the pointer visible.
- // Several threads may perform this store, but the same value will be
- // stored in all cases (for a given named/spec'ed histogram).
- // We could do this without any barrier, since FactoryGet entered and
- // exited a lock after construction, but this barrier makes things clear.
- base::subtle::Release_Store(&atomic_histogram_pointer,
- reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
- }
-
- // Ensure calling contract is upheld, and the name does NOT vary.
- DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
-
- histogram_pointer->Add(sample);
- } while (0);
-*/
-
-// The above pattern is repeated in several macros. The only elements that
-// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
-// of which FactoryGet method to use. The different FactoryGet methods have
-// various argument lists, so the function with its argument list is provided as
-// a macro argument here. The name is only used in a DCHECK, to assure that
-// callers don't try to vary the name of the histogram (which would tend to be
-// ignored by the one-time initialization of the histogtram_pointer).
-#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
- histogram_add_method_invocation, \
- histogram_factory_get_invocation) \
- do { \
- static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
- base::HistogramBase* histogram_pointer( \
- reinterpret_cast<base::HistogramBase*>( \
- base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
- if (!histogram_pointer) { \
- histogram_pointer = histogram_factory_get_invocation; \
- base::subtle::Release_Store(&atomic_histogram_pointer, \
- reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
- } \
- if (DCHECK_IS_ON) \
- histogram_pointer->CheckName(constant_histogram_name); \
- histogram_pointer->histogram_add_method_invocation; \
- } while (0)
-
-
-//------------------------------------------------------------------------------
-// Provide easy general purpose histogram in a macro, just like stats counters.
-// The first four macros use 50 buckets.
-
-#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromSeconds(10), 50)
-
-// For folks that need real specific times, use this to select a precise range
-// of times you want plotted, and the number of buckets you want used.
-#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
- base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
- base::HistogramBase::kNoFlags))
-
-#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 1000000, 50)
-
-#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
- LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
-
-#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
- LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
-
-#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::Histogram::FactoryGet(name, min, max, bucket_count, \
- base::HistogramBase::kNoFlags))
-
-// This is a helper macro used by other macros and shouldn't be used directly.
-#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
- flag))
-
-#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
- LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
-
-#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
- base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
-
-// Support histograming of an enumerated value. The samples should always be
-// strictly less than |boundary_value| -- this prevents you from running into
-// problems down the line if you add additional buckets to the histogram. Note
-// also that, despite explicitly setting the minimum bucket value to |1| below,
-// it is fine for enumerated histograms to be 0-indexed -- this is because
-// enumerated histograms should never have underflow.
-#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
- boundary_value + 1, base::HistogramBase::kNoFlags))
-
-// Support histograming of an enumerated value. Samples should be one of the
-// std::vector<int> list provided via |custom_ranges|. See comments above
-// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
-// You can use the helper function CustomHistogram::ArrayToCustomRanges to
-// transform a C-style array of valid sample values to a std::vector<int>.
-#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::CustomHistogram::FactoryGet(name, custom_ranges, \
- base::HistogramBase::kNoFlags))
-
-#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1000, 500000, 50)
-
-//------------------------------------------------------------------------------
-// The following macros provide typical usage scenarios for callers that wish
-// to record histogram data, and have the data submitted/uploaded via UMA.
-// Not all systems support such UMA, but if they do, the following macros
-// should work with the service.
-
-#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromSeconds(10), 50)
-
-#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(10), \
- base::TimeDelta::FromMinutes(3), 50)
-
-// Use this macro when times can routinely be much longer than 10 seconds.
-#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromHours(1), 50)
-
-// Use this macro when times can routinely be much longer than 10 seconds and
-// you want 100 buckets.
-#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromHours(1), 100)
-
-#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
- base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 1000000, 50)
-
-#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 100, 50)
-
-#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 10000, 50)
-
-#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::Histogram::FactoryGet(name, min, max, bucket_count, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1000, 500000, 50)
-
-#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 1000, 50)
-
-#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
- UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
-
-#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
- base::BooleanHistogram::FactoryGet(name, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-// The samples should always be strictly less than |boundary_value|. For more
-// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above.
-#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
- HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
- base::HistogramBase::kUmaTargetedHistogramFlag)
-
-// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
-// histograms. Use this if recording a histogram that should be part of the
-// initial stability log.
-#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
- HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
- base::HistogramBase::kUmaStabilityHistogramFlag)
-
-#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::CustomHistogram::FactoryGet(name, custom_ranges, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-//------------------------------------------------------------------------------
-
-class BucketRanges;
-class SampleVector;
-
class BooleanHistogram;
class CustomHistogram;
class Histogram;
class LinearHistogram;
+class SampleVector;
class BASE_EXPORT Histogram : public HistogramBase {
public:
diff --git a/chromium/base/metrics/histogram_base.cc b/chromium/base/metrics/histogram_base.cc
index f09c84e20d0..de34c79d4b4 100644
--- a/chromium/base/metrics/histogram_base.cc
+++ b/chromium/base/metrics/histogram_base.cc
@@ -111,8 +111,8 @@ void HistogramBase::WriteJSON(std::string* output) const {
root.SetInteger("count", count);
root.SetDouble("sum", static_cast<double>(sum));
root.SetInteger("flags", flags());
- root.Set("params", parameters.release());
- root.Set("buckets", buckets.release());
+ root.Set("params", parameters.Pass());
+ root.Set("buckets", buckets.Pass());
root.SetInteger("pid", GetCurrentProcId());
serializer.Serialize(root);
}
diff --git a/chromium/base/metrics/histogram_base_unittest.cc b/chromium/base/metrics/histogram_base_unittest.cc
index 4a2963aa6c4..2d6b6df0288 100644
--- a/chromium/base/metrics/histogram_base_unittest.cc
+++ b/chromium/base/metrics/histogram_base_unittest.cc
@@ -22,9 +22,7 @@ class HistogramBaseTest : public testing::Test {
ResetStatisticsRecorder();
}
- virtual ~HistogramBaseTest() {
- delete statistics_recorder_;
- }
+ ~HistogramBaseTest() override { delete statistics_recorder_; }
void ResetStatisticsRecorder() {
delete statistics_recorder_;
diff --git a/chromium/base/metrics/histogram_macros.h b/chromium/base/metrics/histogram_macros.h
new file mode 100644
index 00000000000..2aee1a5de44
--- /dev/null
+++ b/chromium/base/metrics/histogram_macros.h
@@ -0,0 +1,264 @@
+// Copyright 2014 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_METRICS_HISTOGRAM_MACROS_H_
+#define BASE_METRICS_HISTOGRAM_MACROS_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+//------------------------------------------------------------------------------
+// Histograms are often put in areas where they are called many many times, and
+// performance is critical. As a result, they are designed to have a very low
+// recurring cost of executing (adding additional samples). Toward that end,
+// the macros declare a static pointer to the histogram in question, and only
+// take a "slow path" to construct (or find) the histogram on the first run
+// through the macro. We leak the histograms at shutdown time so that we don't
+// have to validate using the pointers at any time during the running of the
+// process.
+
+// The following code is generally what a thread-safe static pointer
+// initialization looks like for a histogram (after a macro is expanded). This
+// sample is an expansion (with comments) of the code for
+// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
+
+/*
+ do {
+ // The pointer's presence indicates the initialization is complete.
+ // Initialization is idempotent, so it can safely be atomically repeated.
+ static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+
+ // Acquire_Load() ensures that we acquire visibility to the pointed-to data
+ // in the histogram.
+ base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
+ base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+
+ if (!histogram_pointer) {
+ // This is the slow path, which will construct OR find the matching
+ // histogram. FactoryGet includes locks on a global histogram name map
+ // and is completely thread safe.
+ histogram_pointer = base::Histogram::FactoryGet(
+ name, min, max, bucket_count, base::HistogramBase::kNoFlags);
+
+ // Use Release_Store to ensure that the histogram data is made available
+ // globally before we make the pointer visible.
+ // Several threads may perform this store, but the same value will be
+ // stored in all cases (for a given named/spec'ed histogram).
+ // We could do this without any barrier, since FactoryGet entered and
+ // exited a lock after construction, but this barrier makes things clear.
+ base::subtle::Release_Store(&atomic_histogram_pointer,
+ reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+ }
+
+ // Ensure calling contract is upheld, and the name does NOT vary.
+ DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
+
+ histogram_pointer->Add(sample);
+ } while (0);
+*/
+
+// The above pattern is repeated in several macros. The only elements that
+// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
+// of which FactoryGet method to use. The different FactoryGet methods have
+// various argument lists, so the function with its argument list is provided as
+// a macro argument here. The name is only used in a DCHECK, to assure that
+// callers don't try to vary the name of the histogram (which would tend to be
+// ignored by the one-time initialization of the histogtram_pointer).
+#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
+ histogram_add_method_invocation, \
+ histogram_factory_get_invocation) \
+ do { \
+ static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
+ base::HistogramBase* histogram_pointer( \
+ reinterpret_cast<base::HistogramBase*>( \
+ base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
+ if (!histogram_pointer) { \
+ histogram_pointer = histogram_factory_get_invocation; \
+ base::subtle::Release_Store( \
+ &atomic_histogram_pointer, \
+ reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
+ } \
+ if (DCHECK_IS_ON()) \
+ histogram_pointer->CheckName(constant_histogram_name); \
+ histogram_pointer->histogram_add_method_invocation; \
+ } while (0)
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// The first four macros use 50 buckets.
+
+#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromSeconds(10), 50)
+
+// For folks that need real specific times, use this to select a precise range
+// of times you want plotted, and the number of buckets you want used.
+#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+ base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+ base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000000, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
+ LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
+ LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
+#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::Histogram::FactoryGet(name, min, max, bucket_count, \
+ base::HistogramBase::kNoFlags))
+
+// This is a helper macro used by other macros and shouldn't be used directly.
+#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
+ flag))
+
+#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+ LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+ base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
+
+// Support histograming of an enumerated value. The samples should always be
+// strictly less than |boundary_value| -- this prevents you from running into
+// problems down the line if you add additional buckets to the histogram. Note
+// also that, despite explicitly setting the minimum bucket value to |1| below,
+// it is fine for enumerated histograms to be 0-indexed -- this is because
+// enumerated histograms should never have underflow.
+#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+ boundary_value + 1, base::HistogramBase::kNoFlags))
+
+// Support histograming of an enumerated value. Samples should be one of the
+// std::vector<int> list provided via |custom_ranges|. See comments above
+// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
+// You can use the helper function CustomHistogram::ArrayToCustomRanges to
+// transform a C-style array of valid sample values to a std::vector<int>.
+#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::CustomHistogram::FactoryGet(name, custom_ranges, \
+ base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1000, 500000, 50)
+
+//------------------------------------------------------------------------------
+// The following macros provide typical usage scenarios for callers that wish
+// to record histogram data, and have the data submitted/uploaded via UMA.
+// Not all systems support such UMA, but if they do, the following macros
+// should work with the service.
+
+#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromSeconds(10), 50)
+
+#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(10), \
+ base::TimeDelta::FromMinutes(3), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds.
+#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromHours(1), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds and
+// you want 100 buckets.
+#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromHours(1), 100)
+
+#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+ base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000000, 50)
+
+#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 100, 50)
+
+#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 10000, 50)
+
+#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::Histogram::FactoryGet(name, min, max, bucket_count, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1000, 500000, 50)
+
+#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000, 50)
+
+#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+ UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+ base::BooleanHistogram::FactoryGet(name, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// The samples should always be strictly less than |boundary_value|. For more
+// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
+#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+
+// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
+// histograms. Use this if recording a histogram that should be part of the
+// initial stability log.
+#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+ base::HistogramBase::kUmaStabilityHistogramFlag)
+
+#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::CustomHistogram::FactoryGet(name, custom_ranges, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// Scoped class which logs its time on this earth as a UMA statistic. This is
+// recommended for when you want a histogram which measures the time it takes
+// for a method to execute. This measures up to 10 seconds.
+#define SCOPED_UMA_HISTOGRAM_TIMER(name) \
+ SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, false, __COUNTER__)
+
+// Similar scoped histogram timer, but this uses UMA_HISTOGRAM_LONG_TIMES_100,
+// which measures up to an hour, and uses 100 buckets. This is more expensive
+// to store, so only use if this often takes >10 seconds.
+#define SCOPED_UMA_HISTOGRAM_LONG_TIMER(name) \
+ SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, true, __COUNTER__)
+
+// This nested macro is necessary to expand __COUNTER__ to an actual value.
+#define SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, is_long, key) \
+ SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(name, is_long, key)
+
+#define SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \
+ class ScopedHistogramTimer##key { \
+ public: \
+ ScopedHistogramTimer##key() : constructed_(base::TimeTicks::Now()) {} \
+ ~ScopedHistogramTimer##key() { \
+ base::TimeDelta elapsed = base::TimeTicks::Now() - constructed_; \
+ if (is_long) { \
+ UMA_HISTOGRAM_LONG_TIMES_100(name, elapsed); \
+ } else { \
+ UMA_HISTOGRAM_TIMES(name, elapsed); \
+ } \
+ } \
+ private: \
+ base::TimeTicks constructed_; \
+ } scoped_histogram_timer_##key
+
+#endif // BASE_METRICS_HISTOGRAM_MACROS_H_
diff --git a/chromium/base/metrics/histogram_macros_unittest.cc b/chromium/base/metrics/histogram_macros_unittest.cc
new file mode 100644
index 00000000000..c5991619a0f
--- /dev/null
+++ b/chromium/base/metrics/histogram_macros_unittest.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 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/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedHistogramTimer, TwoTimersOneScope) {
+ SCOPED_UMA_HISTOGRAM_TIMER("TestTimer0");
+ SCOPED_UMA_HISTOGRAM_TIMER("TestTimer1");
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer0");
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer1");
+}
+
+} // namespace base
diff --git a/chromium/base/metrics/histogram_snapshot_manager_unittest.cc b/chromium/base/metrics/histogram_snapshot_manager_unittest.cc
index 5dd72a7f1ce..3a1fd4044b2 100644
--- a/chromium/base/metrics/histogram_snapshot_manager_unittest.cc
+++ b/chromium/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -51,7 +51,7 @@ class HistogramSnapshotManagerTest : public testing::Test {
HistogramSnapshotManagerTest()
: histogram_snapshot_manager_(&histogram_flattener_delta_recorder_) {}
- virtual ~HistogramSnapshotManagerTest() {}
+ ~HistogramSnapshotManagerTest() override {}
StatisticsRecorder statistics_recorder_;
HistogramFlattenerDeltaRecorder histogram_flattener_delta_recorder_;
diff --git a/chromium/base/metrics/histogram_unittest.cc b/chromium/base/metrics/histogram_unittest.cc
index 41e36faa3c5..df43e65fdef 100644
--- a/chromium/base/metrics/histogram_unittest.cc
+++ b/chromium/base/metrics/histogram_unittest.cc
@@ -24,15 +24,13 @@ namespace base {
class HistogramTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
// Each test will have a clean state (no Histogram / BucketRanges
// registered).
InitializeStatisticsRecorder();
}
- virtual void TearDown() {
- UninitializeStatisticsRecorder();
- }
+ void TearDown() override { UninitializeStatisticsRecorder(); }
void InitializeStatisticsRecorder() {
statistics_recorder_ = new StatisticsRecorder();
diff --git a/chromium/base/metrics/sparse_histogram_unittest.cc b/chromium/base/metrics/sparse_histogram_unittest.cc
index 6a0efa4e12b..c29dd5e2254 100644
--- a/chromium/base/metrics/sparse_histogram_unittest.cc
+++ b/chromium/base/metrics/sparse_histogram_unittest.cc
@@ -18,15 +18,13 @@ namespace base {
class SparseHistogramTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
// Each test will have a clean state (no Histogram / BucketRanges
// registered).
InitializeStatisticsRecorder();
}
- virtual void TearDown() {
- UninitializeStatisticsRecorder();
- }
+ void TearDown() override { UninitializeStatisticsRecorder(); }
void InitializeStatisticsRecorder() {
statistics_recorder_ = new StatisticsRecorder();
diff --git a/chromium/base/metrics/statistics_recorder.cc b/chromium/base/metrics/statistics_recorder.cc
index 62617c5d804..fb069a5cdac 100644
--- a/chromium/base/metrics/statistics_recorder.cc
+++ b/chromium/base/metrics/statistics_recorder.cc
@@ -31,7 +31,6 @@ void StatisticsRecorder::Initialize() {
g_statistics_recorder_.Get();
}
-
// static
bool StatisticsRecorder::IsActive() {
if (lock_ == NULL)
@@ -287,11 +286,8 @@ StatisticsRecorder::StatisticsRecorder() {
// static
void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
- DCHECK(VLOG_IS_ON(1));
-
- StatisticsRecorder* me = reinterpret_cast<StatisticsRecorder*>(instance);
string output;
- me->WriteGraph(std::string(), &output);
+ StatisticsRecorder::WriteGraph(std::string(), &output);
VLOG(1) << output;
}
diff --git a/chromium/base/metrics/statistics_recorder.h b/chromium/base/metrics/statistics_recorder.h
index 3bef622b76f..b5230575963 100644
--- a/chromium/base/metrics/statistics_recorder.h
+++ b/chromium/base/metrics/statistics_recorder.h
@@ -88,6 +88,7 @@ class BASE_EXPORT StatisticsRecorder {
friend class HistogramBaseTest;
friend class HistogramSnapshotManagerTest;
friend class HistogramTest;
+ friend class JsonPrefStoreTest;
friend class SparseHistogramTest;
friend class StatisticsRecorderTest;
FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
diff --git a/chromium/base/metrics/statistics_recorder_unittest.cc b/chromium/base/metrics/statistics_recorder_unittest.cc
index cabeb714e5b..e653bf30dfe 100644
--- a/chromium/base/metrics/statistics_recorder_unittest.cc
+++ b/chromium/base/metrics/statistics_recorder_unittest.cc
@@ -15,15 +15,13 @@ namespace base {
class StatisticsRecorderTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
// Each test will have a clean state (no Histogram / BucketRanges
// registered).
InitializeStatisticsRecorder();
}
- virtual void TearDown() {
- UninitializeStatisticsRecorder();
- }
+ void TearDown() override { UninitializeStatisticsRecorder(); }
void InitializeStatisticsRecorder() {
statistics_recorder_ = new StatisticsRecorder();
diff --git a/chromium/base/metrics/stats_counters.cc b/chromium/base/metrics/stats_counters.cc
deleted file mode 100644
index 12416d9f0f5..00000000000
--- a/chromium/base/metrics/stats_counters.cc
+++ /dev/null
@@ -1,125 +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/metrics/stats_counters.h"
-
-namespace base {
-
-StatsCounter::StatsCounter(const std::string& name)
- : counter_id_(-1) {
- // We prepend the name with 'c:' to indicate that it is a counter.
- if (StatsTable::current()) {
- // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
- // static.
- name_ = "c:";
- name_.append(name);
- }
-}
-
-StatsCounter::~StatsCounter() {
-}
-
-void StatsCounter::Set(int value) {
- int* loc = GetPtr();
- if (loc)
- *loc = value;
-}
-
-void StatsCounter::Add(int value) {
- int* loc = GetPtr();
- if (loc)
- (*loc) += value;
-}
-
-StatsCounter::StatsCounter()
- : counter_id_(-1) {
-}
-
-int* StatsCounter::GetPtr() {
- StatsTable* table = StatsTable::current();
- if (!table)
- return NULL;
-
- // If counter_id_ is -1, then we haven't looked it up yet.
- if (counter_id_ == -1) {
- counter_id_ = table->FindCounter(name_);
- if (table->GetSlot() == 0) {
- if (!table->RegisterThread(std::string())) {
- // There is no room for this thread. This thread
- // cannot use counters.
- counter_id_ = 0;
- return NULL;
- }
- }
- }
-
- // If counter_id_ is > 0, then we have a valid counter.
- if (counter_id_ > 0)
- return table->GetLocation(counter_id_, table->GetSlot());
-
- // counter_id_ was zero, which means the table is full.
- return NULL;
-}
-
-
-StatsCounterTimer::StatsCounterTimer(const std::string& name) {
- // we prepend the name with 't:' to indicate that it is a timer.
- if (StatsTable::current()) {
- // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
- // static.
- name_ = "t:";
- name_.append(name);
- }
-}
-
-StatsCounterTimer::~StatsCounterTimer() {
-}
-
-void StatsCounterTimer::Start() {
- if (!Enabled())
- return;
- start_time_ = TimeTicks::Now();
- stop_time_ = TimeTicks();
-}
-
-// Stop the timer and record the results.
-void StatsCounterTimer::Stop() {
- if (!Enabled() || !Running())
- return;
- stop_time_ = TimeTicks::Now();
- Record();
-}
-
-// Returns true if the timer is running.
-bool StatsCounterTimer::Running() {
- return Enabled() && !start_time_.is_null() && stop_time_.is_null();
-}
-
-// Accept a TimeDelta to increment.
-void StatsCounterTimer::AddTime(TimeDelta time) {
- Add(static_cast<int>(time.InMilliseconds()));
-}
-
-void StatsCounterTimer::Record() {
- AddTime(stop_time_ - start_time_);
-}
-
-
-StatsRate::StatsRate(const std::string& name)
- : StatsCounterTimer(name),
- counter_(name),
- largest_add_(std::string(" ").append(name).append("MAX")) {
-}
-
-StatsRate::~StatsRate() {
-}
-
-void StatsRate::Add(int value) {
- counter_.Increment();
- StatsCounterTimer::Add(value);
- if (value > largest_add_.value())
- largest_add_.Set(value);
-}
-
-} // namespace base
diff --git a/chromium/base/metrics/stats_counters.h b/chromium/base/metrics/stats_counters.h
deleted file mode 100644
index 0f8354f26a4..00000000000
--- a/chromium/base/metrics/stats_counters.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_METRICS_STATS_COUNTERS_H_
-#define BASE_METRICS_STATS_COUNTERS_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/compiler_specific.h"
-#include "base/metrics/stats_table.h"
-#include "base/time/time.h"
-
-namespace base {
-
-// StatsCounters are dynamically created values which can be tracked in
-// the StatsTable. They are designed to be lightweight to create and
-// easy to use.
-//
-// Since StatsCounters can be created dynamically by name, there is
-// a hash table lookup to find the counter in the table. A StatsCounter
-// object can be created once and used across multiple threads safely.
-//
-// Example usage:
-// {
-// StatsCounter request_count("RequestCount");
-// request_count.Increment();
-// }
-//
-// Note that creating counters on the stack does work, however creating
-// the counter object requires a hash table lookup. For inner loops, it
-// may be better to create the counter either as a member of another object
-// (or otherwise outside of the loop) for maximum performance.
-//
-// Internally, a counter represents a value in a row of a StatsTable.
-// The row has a 32bit value for each process/thread in the table and also
-// a name (stored in the table metadata).
-//
-// NOTE: In order to make stats_counters usable in lots of different code,
-// avoid any dependencies inside this header file.
-//
-
-//------------------------------------------------------------------------------
-// Define macros for ease of use. They also allow us to change definitions
-// as the implementation varies, or depending on compile options.
-//------------------------------------------------------------------------------
-// First provide generic macros, which exist in production as well as debug.
-#define STATS_COUNTER(name, delta) do { \
- base::StatsCounter counter(name); \
- counter.Add(delta); \
-} while (0)
-
-#define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1)
-
-#define RATE_COUNTER(name, duration) do { \
- base::StatsRate hit_count(name); \
- hit_count.AddTime(duration); \
-} while (0)
-
-// Define Debug vs non-debug flavors of macros.
-#ifndef NDEBUG
-
-#define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta)
-#define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name)
-#define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration)
-
-#else // NDEBUG
-
-#define DSTATS_COUNTER(name, delta) do {} while (0)
-#define DSIMPLE_STATS_COUNTER(name) do {} while (0)
-#define DRATE_COUNTER(name, duration) do {} while (0)
-
-#endif // NDEBUG
-
-//------------------------------------------------------------------------------
-// StatsCounter represents a counter in the StatsTable class.
-class BASE_EXPORT StatsCounter {
- public:
- // Create a StatsCounter object.
- explicit StatsCounter(const std::string& name);
- virtual ~StatsCounter();
-
- // Sets the counter to a specific value.
- void Set(int value);
-
- // Increments the counter.
- void Increment() {
- Add(1);
- }
-
- virtual void Add(int value);
-
- // Decrements the counter.
- void Decrement() {
- Add(-1);
- }
-
- void Subtract(int value) {
- Add(-value);
- }
-
- // Is this counter enabled?
- // Returns false if table is full.
- bool Enabled() {
- return GetPtr() != NULL;
- }
-
- int value() {
- int* loc = GetPtr();
- if (loc) return *loc;
- return 0;
- }
-
- protected:
- StatsCounter();
-
- // Returns the cached address of this counter location.
- int* GetPtr();
-
- std::string name_;
- // The counter id in the table. We initialize to -1 (an invalid value)
- // and then cache it once it has been looked up. The counter_id is
- // valid across all threads and processes.
- int32 counter_id_;
-};
-
-
-// A StatsCounterTimer is a StatsCounter which keeps a timer during
-// the scope of the StatsCounterTimer. On destruction, it will record
-// its time measurement.
-class BASE_EXPORT StatsCounterTimer : protected StatsCounter {
- public:
- // Constructs and starts the timer.
- explicit StatsCounterTimer(const std::string& name);
- ~StatsCounterTimer() override;
-
- // Start the timer.
- void Start();
-
- // Stop the timer and record the results.
- void Stop();
-
- // Returns true if the timer is running.
- bool Running();
-
- // Accept a TimeDelta to increment.
- virtual void AddTime(TimeDelta time);
-
- protected:
- // Compute the delta between start and stop, in milliseconds.
- void Record();
-
- TimeTicks start_time_;
- TimeTicks stop_time_;
-};
-
-// A StatsRate is a timer that keeps a count of the number of intervals added so
-// that several statistics can be produced:
-// min, max, avg, count, total
-class BASE_EXPORT StatsRate : public StatsCounterTimer {
- public:
- // Constructs and starts the timer.
- explicit StatsRate(const std::string& name);
- ~StatsRate() override;
-
- void Add(int value) override;
-
- private:
- StatsCounter counter_;
- StatsCounter largest_add_;
-};
-
-
-// Helper class for scoping a timer or rate.
-template<class T> class StatsScope {
- public:
- explicit StatsScope<T>(T& timer)
- : timer_(timer) {
- timer_.Start();
- }
-
- ~StatsScope() {
- timer_.Stop();
- }
-
- void Stop() {
- timer_.Stop();
- }
-
- private:
- T& timer_;
-};
-
-} // namespace base
-
-#endif // BASE_METRICS_STATS_COUNTERS_H_
diff --git a/chromium/base/metrics/stats_table.cc b/chromium/base/metrics/stats_table.cc
deleted file mode 100644
index 0986395dd98..00000000000
--- a/chromium/base/metrics/stats_table.cc
+++ /dev/null
@@ -1,617 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/metrics/stats_table.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process_handle.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_local_storage.h"
-
-namespace base {
-
-// The StatsTable uses a shared memory segment that is laid out as follows
-//
-// +-------------------------------------------+
-// | Version | Size | MaxCounters | MaxThreads |
-// +-------------------------------------------+
-// | Thread names table |
-// +-------------------------------------------+
-// | Thread TID table |
-// +-------------------------------------------+
-// | Thread PID table |
-// +-------------------------------------------+
-// | Counter names table |
-// +-------------------------------------------+
-// | Data |
-// +-------------------------------------------+
-//
-// The data layout is a grid, where the columns are the thread_ids and the
-// rows are the counter_ids.
-//
-// If the first character of the thread_name is '\0', then that column is
-// empty.
-// If the first character of the counter_name is '\0', then that row is
-// empty.
-//
-// About Locking:
-// This class is designed to be both multi-thread and multi-process safe.
-// Aside from initialization, this is done by partitioning the data which
-// each thread uses so that no locking is required. However, to allocate
-// the rows and columns of the table to particular threads, locking is
-// required.
-//
-// At the shared-memory level, we have a lock. This lock protects the
-// shared-memory table only, and is used when we create new counters (e.g.
-// use rows) or when we register new threads (e.g. use columns). Reading
-// data from the table does not require any locking at the shared memory
-// level.
-//
-// Each process which accesses the table will create a StatsTable object.
-// The StatsTable maintains a hash table of the existing counters in the
-// table for faster lookup. Since the hash table is process specific,
-// each process maintains its own cache. We avoid complexity here by never
-// de-allocating from the hash table. (Counters are dynamically added,
-// but not dynamically removed).
-
-// In order for external viewers to be able to read our shared memory,
-// we all need to use the same size ints.
-COMPILE_ASSERT(sizeof(int)==4, expect_4_byte_ints);
-
-namespace {
-
-// An internal version in case we ever change the format of this
-// file, and so that we can identify our table.
-const int kTableVersion = 0x13131313;
-
-// The name for un-named counters and threads in the table.
-const char kUnknownName[] = "<unknown>";
-
-// Calculates delta to align an offset to the size of an int
-inline int AlignOffset(int offset) {
- return (sizeof(int) - (offset % sizeof(int))) % sizeof(int);
-}
-
-inline int AlignedSize(int size) {
- return size + AlignOffset(size);
-}
-
-} // namespace
-
-// The StatsTable::Internal maintains convenience pointers into the
-// shared memory segment. Use this class to keep the data structure
-// clean and accessible.
-class StatsTable::Internal {
- public:
- // Various header information contained in the memory mapped segment.
- struct TableHeader {
- int version;
- int size;
- int max_counters;
- int max_threads;
- };
-
- // Construct a new Internal based on expected size parameters, or
- // return NULL on failure.
- static Internal* New(const StatsTable::TableIdentifier& table,
- int size,
- int max_threads,
- int max_counters);
-
- SharedMemory* shared_memory() { return shared_memory_.get(); }
-
- // Accessors for our header pointers
- TableHeader* table_header() const { return table_header_; }
- int version() const { return table_header_->version; }
- int size() const { return table_header_->size; }
- int max_counters() const { return table_header_->max_counters; }
- int max_threads() const { return table_header_->max_threads; }
-
- // Accessors for our tables
- char* thread_name(int slot_id) const {
- return &thread_names_table_[
- (slot_id-1) * (StatsTable::kMaxThreadNameLength)];
- }
- PlatformThreadId* thread_tid(int slot_id) const {
- return &(thread_tid_table_[slot_id-1]);
- }
- int* thread_pid(int slot_id) const {
- return &(thread_pid_table_[slot_id-1]);
- }
- char* counter_name(int counter_id) const {
- return &counter_names_table_[
- (counter_id-1) * (StatsTable::kMaxCounterNameLength)];
- }
- int* row(int counter_id) const {
- return &data_table_[(counter_id-1) * max_threads()];
- }
-
- private:
- // Constructor is private because you should use New() instead.
- explicit Internal(SharedMemory* shared_memory)
- : shared_memory_(shared_memory),
- table_header_(NULL),
- thread_names_table_(NULL),
- thread_tid_table_(NULL),
- thread_pid_table_(NULL),
- counter_names_table_(NULL),
- data_table_(NULL) {
- }
-
- // Create or open the SharedMemory used by the stats table.
- static SharedMemory* CreateSharedMemory(
- const StatsTable::TableIdentifier& table,
- int size);
-
- // Initializes the table on first access. Sets header values
- // appropriately and zeroes all counters.
- void InitializeTable(void* memory, int size, int max_counters,
- int max_threads);
-
- // Initializes our in-memory pointers into a pre-created StatsTable.
- void ComputeMappedPointers(void* memory);
-
- scoped_ptr<SharedMemory> shared_memory_;
- TableHeader* table_header_;
- char* thread_names_table_;
- PlatformThreadId* thread_tid_table_;
- int* thread_pid_table_;
- char* counter_names_table_;
- int* data_table_;
-
- DISALLOW_COPY_AND_ASSIGN(Internal);
-};
-
-// static
-StatsTable::Internal* StatsTable::Internal::New(
- const StatsTable::TableIdentifier& table,
- int size,
- int max_threads,
- int max_counters) {
- scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(table, size));
- if (!shared_memory.get())
- return NULL;
- if (!shared_memory->Map(size))
- return NULL;
- void* memory = shared_memory->memory();
-
- scoped_ptr<Internal> internal(new Internal(shared_memory.release()));
- TableHeader* header = static_cast<TableHeader*>(memory);
-
- // If the version does not match, then assume the table needs
- // to be initialized.
- if (header->version != kTableVersion)
- internal->InitializeTable(memory, size, max_counters, max_threads);
-
- // We have a valid table, so compute our pointers.
- internal->ComputeMappedPointers(memory);
-
- return internal.release();
-}
-
-// static
-SharedMemory* StatsTable::Internal::CreateSharedMemory(
- const StatsTable::TableIdentifier& table,
- int size) {
-#if defined(OS_POSIX)
- // Check for existing table.
- if (table.fd != -1)
- return new SharedMemory(table, false);
-
- // Otherwise we need to create it.
- scoped_ptr<SharedMemory> shared_memory(new SharedMemory());
- if (!shared_memory->CreateAnonymous(size))
- return NULL;
- return shared_memory.release();
-#elif defined(OS_WIN)
- scoped_ptr<SharedMemory> shared_memory(new SharedMemory());
- if (table.empty()) {
- // Create an anonymous table.
- if (!shared_memory->CreateAnonymous(size))
- return NULL;
- } else {
- // Create a named table for sharing between processes.
- if (!shared_memory->CreateNamedDeprecated(table, true, size))
- return NULL;
- }
- return shared_memory.release();
-#endif
-}
-
-void StatsTable::Internal::InitializeTable(void* memory, int size,
- int max_counters,
- int max_threads) {
- // Zero everything.
- memset(memory, 0, size);
-
- // Initialize the header.
- TableHeader* header = static_cast<TableHeader*>(memory);
- header->version = kTableVersion;
- header->size = size;
- header->max_counters = max_counters;
- header->max_threads = max_threads;
-}
-
-void StatsTable::Internal::ComputeMappedPointers(void* memory) {
- char* data = static_cast<char*>(memory);
- int offset = 0;
-
- table_header_ = reinterpret_cast<TableHeader*>(data);
- offset += sizeof(*table_header_);
- offset += AlignOffset(offset);
-
- // Verify we're looking at a valid StatsTable.
- DCHECK_EQ(table_header_->version, kTableVersion);
-
- thread_names_table_ = reinterpret_cast<char*>(data + offset);
- offset += sizeof(char) *
- max_threads() * StatsTable::kMaxThreadNameLength;
- offset += AlignOffset(offset);
-
- thread_tid_table_ = reinterpret_cast<PlatformThreadId*>(data + offset);
- offset += sizeof(int) * max_threads();
- offset += AlignOffset(offset);
-
- thread_pid_table_ = reinterpret_cast<int*>(data + offset);
- offset += sizeof(int) * max_threads();
- offset += AlignOffset(offset);
-
- counter_names_table_ = reinterpret_cast<char*>(data + offset);
- offset += sizeof(char) *
- max_counters() * StatsTable::kMaxCounterNameLength;
- offset += AlignOffset(offset);
-
- data_table_ = reinterpret_cast<int*>(data + offset);
- offset += sizeof(int) * max_threads() * max_counters();
-
- DCHECK_EQ(offset, size());
-}
-
-// TLSData carries the data stored in the TLS slots for the
-// StatsTable. This is used so that we can properly cleanup when the
-// thread exits and return the table slot.
-//
-// Each thread that calls RegisterThread in the StatsTable will have
-// a TLSData stored in its TLS.
-struct StatsTable::TLSData {
- StatsTable* table;
- int slot;
-};
-
-// We keep a singleton table which can be easily accessed.
-StatsTable* global_table = NULL;
-
-StatsTable::StatsTable(const TableIdentifier& table,
- int max_threads,
- int max_counters)
- : internal_(NULL),
- tls_index_(SlotReturnFunction) {
- int table_size =
- AlignedSize(sizeof(Internal::TableHeader)) +
- AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) +
- AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) +
- AlignedSize(max_threads * sizeof(int)) +
- AlignedSize(max_threads * sizeof(int)) +
- AlignedSize((sizeof(int) * (max_counters * max_threads)));
-
- internal_ = Internal::New(table, table_size, max_threads, max_counters);
-
- if (!internal_)
- DPLOG(ERROR) << "StatsTable did not initialize";
-}
-
-StatsTable::~StatsTable() {
- // Before we tear down our copy of the table, be sure to
- // unregister our thread.
- UnregisterThread();
-
- // Return ThreadLocalStorage. At this point, if any registered threads
- // still exist, they cannot Unregister.
- tls_index_.Free();
-
- // Cleanup our shared memory.
- delete internal_;
-
- // If we are the global table, unregister ourselves.
- if (global_table == this)
- global_table = NULL;
-}
-
-StatsTable* StatsTable::current() {
- return global_table;
-}
-
-void StatsTable::set_current(StatsTable* value) {
- global_table = value;
-}
-
-int StatsTable::GetSlot() const {
- TLSData* data = GetTLSData();
- if (!data)
- return 0;
- return data->slot;
-}
-
-int StatsTable::RegisterThread(const std::string& name) {
- int slot = 0;
- if (!internal_)
- return 0;
-
- // Registering a thread requires that we lock the shared memory
- // so that two threads don't grab the same slot. Fortunately,
- // thread creation shouldn't happen in inner loops.
- // TODO(viettrungluu): crbug.com/345734: Use a different locking mechanism.
- {
- SharedMemoryAutoLockDeprecated lock(internal_->shared_memory());
- slot = FindEmptyThread();
- if (!slot) {
- return 0;
- }
-
- // We have space, so consume a column in the table.
- std::string thread_name = name;
- if (name.empty())
- thread_name = kUnknownName;
- strlcpy(internal_->thread_name(slot), thread_name.c_str(),
- kMaxThreadNameLength);
- *(internal_->thread_tid(slot)) = PlatformThread::CurrentId();
- *(internal_->thread_pid(slot)) = GetCurrentProcId();
- }
-
- // Set our thread local storage.
- TLSData* data = new TLSData;
- data->table = this;
- data->slot = slot;
- tls_index_.Set(data);
- return slot;
-}
-
-int StatsTable::CountThreadsRegistered() const {
- if (!internal_)
- return 0;
-
- // Loop through the shared memory and count the threads that are active.
- // We intentionally do not lock the table during the operation.
- int count = 0;
- for (int index = 1; index <= internal_->max_threads(); index++) {
- char* name = internal_->thread_name(index);
- if (*name != '\0')
- count++;
- }
- return count;
-}
-
-int StatsTable::FindCounter(const std::string& name) {
- // Note: the API returns counters numbered from 1..N, although
- // internally, the array is 0..N-1. This is so that we can return
- // zero as "not found".
- if (!internal_)
- return 0;
-
- // Create a scope for our auto-lock.
- {
- AutoLock scoped_lock(counters_lock_);
-
- // Attempt to find the counter.
- CountersMap::const_iterator iter;
- iter = counters_.find(name);
- if (iter != counters_.end())
- return iter->second;
- }
-
- // Counter does not exist, so add it.
- return AddCounter(name);
-}
-
-int* StatsTable::GetLocation(int counter_id, int slot_id) const {
- if (!internal_)
- return NULL;
- if (slot_id > internal_->max_threads())
- return NULL;
-
- int* row = internal_->row(counter_id);
- return &(row[slot_id-1]);
-}
-
-const char* StatsTable::GetRowName(int index) const {
- if (!internal_)
- return NULL;
-
- return internal_->counter_name(index);
-}
-
-int StatsTable::GetRowValue(int index) const {
- return GetRowValue(index, 0);
-}
-
-int StatsTable::GetRowValue(int index, int pid) const {
- if (!internal_)
- return 0;
-
- int rv = 0;
- int* row = internal_->row(index);
- for (int slot_id = 1; slot_id <= internal_->max_threads(); slot_id++) {
- if (pid == 0 || *internal_->thread_pid(slot_id) == pid)
- rv += row[slot_id-1];
- }
- return rv;
-}
-
-int StatsTable::GetCounterValue(const std::string& name) {
- return GetCounterValue(name, 0);
-}
-
-int StatsTable::GetCounterValue(const std::string& name, int pid) {
- if (!internal_)
- return 0;
-
- int row = FindCounter(name);
- if (!row)
- return 0;
- return GetRowValue(row, pid);
-}
-
-int StatsTable::GetMaxCounters() const {
- if (!internal_)
- return 0;
- return internal_->max_counters();
-}
-
-int StatsTable::GetMaxThreads() const {
- if (!internal_)
- return 0;
- return internal_->max_threads();
-}
-
-int* StatsTable::FindLocation(const char* name) {
- // Get the static StatsTable
- StatsTable *table = StatsTable::current();
- if (!table)
- return NULL;
-
- // Get the slot for this thread. Try to register
- // it if none exists.
- int slot = table->GetSlot();
- if (!slot)
- slot = table->RegisterThread(std::string());
- if (!slot)
- return NULL;
-
- // Find the counter id for the counter.
- std::string str_name(name);
- int counter = table->FindCounter(str_name);
-
- // Now we can find the location in the table.
- return table->GetLocation(counter, slot);
-}
-
-void StatsTable::UnregisterThread() {
- UnregisterThread(GetTLSData());
-}
-
-void StatsTable::UnregisterThread(TLSData* data) {
- if (!data)
- return;
- DCHECK(internal_);
-
- // Mark the slot free by zeroing out the thread name.
- char* name = internal_->thread_name(data->slot);
- *name = '\0';
-
- // Remove the calling thread's TLS so that it cannot use the slot.
- tls_index_.Set(NULL);
- delete data;
-}
-
-void StatsTable::SlotReturnFunction(void* data) {
- // This is called by the TLS destructor, which on some platforms has
- // already cleared the TLS info, so use the tls_data argument
- // rather than trying to fetch it ourselves.
- TLSData* tls_data = static_cast<TLSData*>(data);
- if (tls_data) {
- DCHECK(tls_data->table);
- tls_data->table->UnregisterThread(tls_data);
- }
-}
-
-int StatsTable::FindEmptyThread() const {
- // Note: the API returns slots numbered from 1..N, although
- // internally, the array is 0..N-1. This is so that we can return
- // zero as "not found".
- //
- // The reason for doing this is because the thread 'slot' is stored
- // in TLS, which is always initialized to zero, not -1. If 0 were
- // returned as a valid slot number, it would be confused with the
- // uninitialized state.
- if (!internal_)
- return 0;
-
- int index = 1;
- for (; index <= internal_->max_threads(); index++) {
- char* name = internal_->thread_name(index);
- if (!*name)
- break;
- }
- if (index > internal_->max_threads())
- return 0; // The table is full.
- return index;
-}
-
-int StatsTable::FindCounterOrEmptyRow(const std::string& name) const {
- // Note: the API returns slots numbered from 1..N, although
- // internally, the array is 0..N-1. This is so that we can return
- // zero as "not found".
- //
- // There isn't much reason for this other than to be consistent
- // with the way we track columns for thread slots. (See comments
- // in FindEmptyThread for why it is done this way).
- if (!internal_)
- return 0;
-
- int free_slot = 0;
- for (int index = 1; index <= internal_->max_counters(); index++) {
- char* row_name = internal_->counter_name(index);
- if (!*row_name && !free_slot)
- free_slot = index; // save that we found a free slot
- else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength))
- return index;
- }
- return free_slot;
-}
-
-int StatsTable::AddCounter(const std::string& name) {
- if (!internal_)
- return 0;
-
- int counter_id = 0;
- {
- // To add a counter to the shared memory, we need the
- // shared memory lock.
- SharedMemoryAutoLockDeprecated lock(internal_->shared_memory());
-
- // We have space, so create a new counter.
- counter_id = FindCounterOrEmptyRow(name);
- if (!counter_id)
- return 0;
-
- std::string counter_name = name;
- if (name.empty())
- counter_name = kUnknownName;
- strlcpy(internal_->counter_name(counter_id), counter_name.c_str(),
- kMaxCounterNameLength);
- }
-
- // now add to our in-memory cache
- {
- AutoLock lock(counters_lock_);
- counters_[name] = counter_id;
- }
- return counter_id;
-}
-
-StatsTable::TLSData* StatsTable::GetTLSData() const {
- TLSData* data =
- static_cast<TLSData*>(tls_index_.Get());
- if (!data)
- return NULL;
-
- DCHECK(data->slot);
- DCHECK_EQ(data->table, this);
- return data;
-}
-
-#if defined(OS_POSIX)
-SharedMemoryHandle StatsTable::GetSharedMemoryHandle() const {
- if (!internal_)
- return SharedMemory::NULLHandle();
- return internal_->shared_memory()->handle();
-}
-#endif
-
-} // namespace base
diff --git a/chromium/base/metrics/stats_table.h b/chromium/base/metrics/stats_table.h
deleted file mode 100644
index 719e6304813..00000000000
--- a/chromium/base/metrics/stats_table.h
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// A StatsTable is a table of statistics. It can be used across multiple
-// processes and threads, maintaining cheap statistics counters without
-// locking.
-//
-// The goal is to make it very cheap and easy for developers to add
-// counters to code, without having to build one-off utilities or mechanisms
-// to track the counters, and also to allow a single "view" to display
-// the contents of all counters.
-//
-// To achieve this, StatsTable creates a shared memory segment to store
-// the data for the counters. Upon creation, it has a specific size
-// which governs the maximum number of counters and concurrent
-// threads/processes which can use it.
-//
-
-#ifndef BASE_METRICS_STATS_TABLE_H_
-#define BASE_METRICS_STATS_TABLE_H_
-
-#include <string>
-
-#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/shared_memory.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_local_storage.h"
-#include "build/build_config.h"
-
-#if defined(OS_POSIX)
-#include "base/file_descriptor_posix.h"
-#endif
-
-namespace base {
-
-class BASE_EXPORT StatsTable {
- public:
- // Identifies a StatsTable. We often want to share these between processes.
- //
- // On Windows, we use a named shared memory segment so the table identifier
- // should be a relatively unique string identifying the table to use. An
- // empty string can be used to use an anonymous shared memory segment for
- // cases where the table does not need to be shared between processes.
- //
- // Posix does not support named memory so we explicitly share file
- // descriptors. On Posix, pass a default-constructed file descriptor if a
- // handle doesn't already exist, and a new one will be created.
- //
- // If a table doesn't already exist with the given identifier, a new one will
- // be created with zeroed counters.
-#if defined(OS_POSIX)
- typedef FileDescriptor TableIdentifier;
-#elif defined(OS_WIN)
- typedef std::string TableIdentifier;
-#endif
-
- // Create a new StatsTable.
- //
- // max_threads is the maximum number of threads the table will support.
- // If the StatsTable already exists, this number is ignored.
- //
- // max_counters is the maximum number of counters the table will support.
- // If the StatsTable already exists, this number is ignored.
- StatsTable(const TableIdentifier& table,
- int max_threads,
- int max_counters);
-
- // Destroys the StatsTable. When the last StatsTable is destroyed
- // (across all processes), the StatsTable is removed from disk.
- ~StatsTable();
-
- // For convenience, we create a static table. This is generally
- // used automatically by the counters.
- static StatsTable* current();
-
- // Set the global table for use in this process.
- static void set_current(StatsTable* value);
-
- // Get the slot id for the calling thread. Returns 0 if no
- // slot is assigned.
- int GetSlot() const;
-
- // All threads that contribute data to the table must register with the
- // table first. This function will set thread local storage for the
- // thread containing the location in the table where this thread will
- // write its counter data.
- //
- // name is just a debugging tag to label the thread, and it does not
- // need to be unique. It will be truncated to kMaxThreadNameLength-1
- // characters.
- //
- // On success, returns the slot id for this thread. On failure,
- // returns 0.
- int RegisterThread(const std::string& name);
-
- // Returns the number of threads currently registered. This is really not
- // useful except for diagnostics and debugging.
- int CountThreadsRegistered() const;
-
- // Find a counter in the StatsTable.
- //
- // Returns an id for the counter which can be used to call GetLocation().
- // If the counter does not exist, attempts to create a row for the new
- // counter. If there is no space in the table for the new counter,
- // returns 0.
- int FindCounter(const std::string& name);
-
- // TODO(mbelshe): implement RemoveCounter.
-
- // Gets the location of a particular value in the table based on
- // the counter id and slot id.
- int* GetLocation(int counter_id, int slot_id) const;
-
- // Gets the counter name at a particular row. If the row is empty,
- // returns NULL.
- const char* GetRowName(int index) const;
-
- // Gets the sum of the values for a particular row.
- int GetRowValue(int index) const;
-
- // Gets the sum of the values for a particular row for a given pid.
- int GetRowValue(int index, int pid) const;
-
- // Gets the sum of the values for a particular counter. If the counter
- // does not exist, creates the counter.
- int GetCounterValue(const std::string& name);
-
- // Gets the sum of the values for a particular counter for a given pid.
- // If the counter does not exist, creates the counter.
- int GetCounterValue(const std::string& name, int pid);
-
- // The maxinum number of counters/rows in the table.
- int GetMaxCounters() const;
-
- // The maxinum number of threads/columns in the table.
- int GetMaxThreads() const;
-
-#if defined(OS_POSIX)
- // Get the underlying shared memory handle for the table.
- base::SharedMemoryHandle GetSharedMemoryHandle() const;
-#endif
-
- // The maximum length (in characters) of a Thread's name including
- // null terminator, as stored in the shared memory.
- static const int kMaxThreadNameLength = 32;
-
- // The maximum length (in characters) of a Counter's name including
- // null terminator, as stored in the shared memory.
- static const int kMaxCounterNameLength = 64;
-
- // Convenience function to lookup a counter location for a
- // counter by name for the calling thread. Will register
- // the thread if it is not already registered.
- static int* FindLocation(const char *name);
-
- private:
- class Internal;
- struct TLSData;
- typedef hash_map<std::string, int> CountersMap;
-
- // Returns the space occupied by a thread in the table. Generally used
- // if a thread terminates but the process continues. This function
- // does not zero out the thread's counters.
- // Cannot be used inside a posix tls destructor.
- void UnregisterThread();
-
- // This variant expects the tls data to be passed in, so it is safe to
- // call from inside a posix tls destructor (see doc for pthread_key_create).
- void UnregisterThread(TLSData* tls_data);
-
- // The SlotReturnFunction is called at thread exit for each thread
- // which used the StatsTable.
- static void SlotReturnFunction(void* data);
-
- // Locates a free slot in the table. Returns a number > 0 on success,
- // or 0 on failure. The caller must hold the shared_memory lock when
- // calling this function.
- int FindEmptyThread() const;
-
- // Locates a counter in the table or finds an empty row. Returns a
- // number > 0 on success, or 0 on failure. The caller must hold the
- // shared_memory_lock when calling this function.
- int FindCounterOrEmptyRow(const std::string& name) const;
-
- // Internal function to add a counter to the StatsTable. Assumes that
- // the counter does not already exist in the table.
- //
- // name is a unique identifier for this counter, and will be truncated
- // to kMaxCounterNameLength-1 characters.
- //
- // On success, returns the counter_id for the newly added counter.
- // On failure, returns 0.
- int AddCounter(const std::string& name);
-
- // Get the TLS data for the calling thread. Returns NULL if none is
- // initialized.
- TLSData* GetTLSData() const;
-
- Internal* internal_;
-
- // The counters_lock_ protects the counters_ hash table.
- base::Lock counters_lock_;
-
- // The counters_ hash map is an in-memory hash of the counters.
- // It is used for quick lookup of counters, but is cannot be used
- // as a substitute for what is in the shared memory. Even though
- // we don't have a counter in our hash table, another process may
- // have created it.
- CountersMap counters_;
- ThreadLocalStorage::Slot tls_index_;
-
- DISALLOW_COPY_AND_ASSIGN(StatsTable);
-};
-
-} // namespace base
-
-#endif // BASE_METRICS_STATS_TABLE_H_
diff --git a/chromium/base/metrics/stats_table_unittest.cc b/chromium/base/metrics/stats_table_unittest.cc
deleted file mode 100644
index 45b0a4397bc..00000000000
--- a/chromium/base/metrics/stats_table_unittest.cc
+++ /dev/null
@@ -1,402 +0,0 @@
-// Copyright (c) 2012 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/memory/shared_memory.h"
-#include "base/metrics/stats_counters.h"
-#include "base/metrics/stats_table.h"
-#include "base/process/kill.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/multiprocess_test.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/simple_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/multiprocess_func_list.h"
-
-namespace base {
-
-class StatsTableTest : public MultiProcessTest {
-};
-
-// Open a StatsTable and verify that we can write to each of the
-// locations in the table.
-TEST_F(StatsTableTest, VerifySlots) {
- const int kMaxThreads = 1;
- const int kMaxCounter = 5;
- StatsTable table(StatsTable::TableIdentifier(), kMaxThreads, kMaxCounter);
-
- // Register a single thread.
- std::string thread_name = "mainThread";
- int slot_id = table.RegisterThread(thread_name);
- EXPECT_NE(slot_id, 0);
-
- // Fill up the table with counters.
- std::string counter_base_name = "counter";
- for (int index = 0; index < kMaxCounter; index++) {
- std::string counter_name = counter_base_name;
- base::StringAppendF(&counter_name, "counter.ctr%d", index);
- int counter_id = table.FindCounter(counter_name);
- EXPECT_GT(counter_id, 0);
- }
-
- // Try to allocate an additional thread. Verify it fails.
- slot_id = table.RegisterThread("too many threads");
- EXPECT_EQ(slot_id, 0);
-
- // Try to allocate an additional counter. Verify it fails.
- int counter_id = table.FindCounter(counter_base_name);
- EXPECT_EQ(counter_id, 0);
-}
-
-// CounterZero will continually be set to 0.
-const std::string kCounterZero = "CounterZero";
-// Counter1313 will continually be set to 1313.
-const std::string kCounter1313 = "Counter1313";
-// CounterIncrement will be incremented each time.
-const std::string kCounterIncrement = "CounterIncrement";
-// CounterDecrement will be decremented each time.
-const std::string kCounterDecrement = "CounterDecrement";
-// CounterMixed will be incremented by odd numbered threads and
-// decremented by even threads.
-const std::string kCounterMixed = "CounterMixed";
-// The number of thread loops that we will do.
-const int kThreadLoops = 100;
-
-class StatsTableThread : public SimpleThread {
- public:
- StatsTableThread(std::string name, int id)
- : SimpleThread(name),
- id_(id) {}
-
- void Run() override;
-
- private:
- int id_;
-};
-
-void StatsTableThread::Run() {
- // Each thread will open the shared memory and set counters
- // concurrently in a loop. We'll use some pauses to
- // mixup the thread scheduling.
-
- StatsCounter zero_counter(kCounterZero);
- StatsCounter lucky13_counter(kCounter1313);
- StatsCounter increment_counter(kCounterIncrement);
- StatsCounter decrement_counter(kCounterDecrement);
- for (int index = 0; index < kThreadLoops; index++) {
- StatsCounter mixed_counter(kCounterMixed); // create this one in the loop
- zero_counter.Set(0);
- lucky13_counter.Set(1313);
- increment_counter.Increment();
- decrement_counter.Decrement();
- if (id_ % 2)
- mixed_counter.Decrement();
- else
- mixed_counter.Increment();
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
- }
-}
-
-// Create a few threads and have them poke on their counters.
-// See http://crbug.com/10611 for more information.
-// It is disabled on Win x64 incremental linking pending resolution of
-// http://crbug.com/251251.
-#if defined(OS_MACOSX) || defined(THREAD_SANITIZER) || \
- (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && \
- defined(INCREMENTAL_LINKING))
-#define MAYBE_MultipleThreads DISABLED_MultipleThreads
-#else
-#define MAYBE_MultipleThreads MultipleThreads
-#endif
-TEST_F(StatsTableTest, MAYBE_MultipleThreads) {
- // Create a stats table.
- const int kMaxThreads = 20;
- const int kMaxCounter = 5;
- StatsTable table(StatsTable::TableIdentifier(), kMaxThreads, kMaxCounter);
- StatsTable::set_current(&table);
-
- EXPECT_EQ(0, table.CountThreadsRegistered());
-
- // Spin up a set of threads to go bang on the various counters.
- // After we join the threads, we'll make sure the counters
- // contain the values we expected.
- StatsTableThread* threads[kMaxThreads];
-
- // Spawn the threads.
- for (int index = 0; index < kMaxThreads; index++) {
- threads[index] = new StatsTableThread("MultipleThreadsTest", index);
- threads[index]->Start();
- }
-
- // Wait for the threads to finish.
- for (int index = 0; index < kMaxThreads; index++) {
- threads[index]->Join();
- delete threads[index];
- }
-
- StatsCounter zero_counter(kCounterZero);
- StatsCounter lucky13_counter(kCounter1313);
- StatsCounter increment_counter(kCounterIncrement);
- StatsCounter decrement_counter(kCounterDecrement);
- StatsCounter mixed_counter(kCounterMixed);
-
- // Verify the various counters are correct.
- std::string name;
- name = "c:" + kCounterZero;
- EXPECT_EQ(0, table.GetCounterValue(name));
- name = "c:" + kCounter1313;
- EXPECT_EQ(1313 * kMaxThreads,
- table.GetCounterValue(name));
- name = "c:" + kCounterIncrement;
- EXPECT_EQ(kMaxThreads * kThreadLoops,
- table.GetCounterValue(name));
- name = "c:" + kCounterDecrement;
- EXPECT_EQ(-kMaxThreads * kThreadLoops,
- table.GetCounterValue(name));
- name = "c:" + kCounterMixed;
- EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
- table.GetCounterValue(name));
- EXPECT_EQ(0, table.CountThreadsRegistered());
-}
-
-// This multiprocess test only runs on Windows. On Posix, the shared memory
-// handle is not sent between the processes properly.
-#if defined(OS_WIN)
-const std::string kMPTableName = "MultipleProcessStatTable";
-
-MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
- // Each process will open the shared memory and set counters
- // concurrently in a loop. We'll use some pauses to
- // mixup the scheduling.
-
- StatsTable table(kMPTableName, 0, 0);
- StatsTable::set_current(&table);
- StatsCounter zero_counter(kCounterZero);
- StatsCounter lucky13_counter(kCounter1313);
- StatsCounter increment_counter(kCounterIncrement);
- StatsCounter decrement_counter(kCounterDecrement);
- for (int index = 0; index < kThreadLoops; index++) {
- zero_counter.Set(0);
- lucky13_counter.Set(1313);
- increment_counter.Increment();
- decrement_counter.Decrement();
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
- }
- return 0;
-}
-
-// Create a few processes and have them poke on their counters.
-// This test is slow and flaky http://crbug.com/10611
-TEST_F(StatsTableTest, DISABLED_MultipleProcesses) {
- // Create a stats table.
- const int kMaxProcs = 20;
- const int kMaxCounter = 5;
- StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
- StatsTable::set_current(&table);
- EXPECT_EQ(0, table.CountThreadsRegistered());
-
- // Spin up a set of processes to go bang on the various counters.
- // After we join the processes, we'll make sure the counters
- // contain the values we expected.
- ProcessHandle procs[kMaxProcs];
-
- // Spawn the processes.
- for (int16 index = 0; index < kMaxProcs; index++) {
- procs[index] = SpawnChild("StatsTableMultipleProcessMain");
- EXPECT_NE(kNullProcessHandle, procs[index]);
- }
-
- // Wait for the processes to finish.
- for (int index = 0; index < kMaxProcs; index++) {
- EXPECT_TRUE(WaitForSingleProcess(
- procs[index], base::TimeDelta::FromMinutes(1)));
- CloseProcessHandle(procs[index]);
- }
-
- StatsCounter zero_counter(kCounterZero);
- StatsCounter lucky13_counter(kCounter1313);
- StatsCounter increment_counter(kCounterIncrement);
- StatsCounter decrement_counter(kCounterDecrement);
-
- // Verify the various counters are correct.
- std::string name;
- name = "c:" + kCounterZero;
- EXPECT_EQ(0, table.GetCounterValue(name));
- name = "c:" + kCounter1313;
- EXPECT_EQ(1313 * kMaxProcs,
- table.GetCounterValue(name));
- name = "c:" + kCounterIncrement;
- EXPECT_EQ(kMaxProcs * kThreadLoops,
- table.GetCounterValue(name));
- name = "c:" + kCounterDecrement;
- EXPECT_EQ(-kMaxProcs * kThreadLoops,
- table.GetCounterValue(name));
- EXPECT_EQ(0, table.CountThreadsRegistered());
-}
-#endif
-
-class MockStatsCounter : public StatsCounter {
- public:
- explicit MockStatsCounter(const std::string& name)
- : StatsCounter(name) {}
- int* Pointer() { return GetPtr(); }
-};
-
-// Test some basic StatsCounter operations
-TEST_F(StatsTableTest, StatsCounter) {
- // Create a stats table.
- const int kMaxThreads = 20;
- const int kMaxCounter = 5;
- StatsTable table(StatsTable::TableIdentifier(), kMaxThreads, kMaxCounter);
- StatsTable::set_current(&table);
-
- MockStatsCounter foo("foo");
-
- // Test initial state.
- EXPECT_TRUE(foo.Enabled());
- ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
- EXPECT_EQ(0, *(foo.Pointer()));
- EXPECT_EQ(0, table.GetCounterValue("c:foo"));
-
- // Test Increment.
- while (*(foo.Pointer()) < 123) foo.Increment();
- EXPECT_EQ(123, table.GetCounterValue("c:foo"));
- foo.Add(0);
- EXPECT_EQ(123, table.GetCounterValue("c:foo"));
- foo.Add(-1);
- EXPECT_EQ(122, table.GetCounterValue("c:foo"));
-
- // Test Set.
- foo.Set(0);
- EXPECT_EQ(0, table.GetCounterValue("c:foo"));
- foo.Set(100);
- EXPECT_EQ(100, table.GetCounterValue("c:foo"));
- foo.Set(-1);
- EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
- foo.Set(0);
- EXPECT_EQ(0, table.GetCounterValue("c:foo"));
-
- // Test Decrement.
- foo.Subtract(1);
- EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
- foo.Subtract(0);
- EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
- foo.Subtract(-1);
- EXPECT_EQ(0, table.GetCounterValue("c:foo"));
-}
-
-class MockStatsCounterTimer : public StatsCounterTimer {
- public:
- explicit MockStatsCounterTimer(const std::string& name)
- : StatsCounterTimer(name) {}
-
- TimeTicks start_time() { return start_time_; }
- TimeTicks stop_time() { return stop_time_; }
-};
-
-// Test some basic StatsCounterTimer operations
-TEST_F(StatsTableTest, StatsCounterTimer) {
- // Create a stats table.
- const int kMaxThreads = 20;
- const int kMaxCounter = 5;
- StatsTable table(StatsTable::TableIdentifier(), kMaxThreads, kMaxCounter);
- StatsTable::set_current(&table);
-
- MockStatsCounterTimer bar("bar");
-
- // Test initial state.
- EXPECT_FALSE(bar.Running());
- EXPECT_TRUE(bar.start_time().is_null());
- EXPECT_TRUE(bar.stop_time().is_null());
-
- const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
-
- // Do some timing.
- bar.Start();
- PlatformThread::Sleep(kDuration);
- bar.Stop();
- EXPECT_GT(table.GetCounterValue("t:bar"), 0);
- EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
-
- // Verify that timing again is additive.
- bar.Start();
- PlatformThread::Sleep(kDuration);
- bar.Stop();
- EXPECT_GT(table.GetCounterValue("t:bar"), 0);
- EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
-}
-
-// Test some basic StatsRate operations
-TEST_F(StatsTableTest, StatsRate) {
- // Create a stats table.
- const int kMaxThreads = 20;
- const int kMaxCounter = 5;
- StatsTable table(StatsTable::TableIdentifier(), kMaxThreads, kMaxCounter);
- StatsTable::set_current(&table);
-
- StatsRate baz("baz");
-
- // Test initial state.
- EXPECT_FALSE(baz.Running());
- EXPECT_EQ(0, table.GetCounterValue("c:baz"));
- EXPECT_EQ(0, table.GetCounterValue("t:baz"));
-
- const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
-
- // Do some timing.
- baz.Start();
- PlatformThread::Sleep(kDuration);
- baz.Stop();
- EXPECT_EQ(1, table.GetCounterValue("c:baz"));
- EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:baz"));
-
- // Verify that timing again is additive.
- baz.Start();
- PlatformThread::Sleep(kDuration);
- baz.Stop();
- EXPECT_EQ(2, table.GetCounterValue("c:baz"));
- EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:baz"));
-}
-
-// Test some basic StatsScope operations
-TEST_F(StatsTableTest, StatsScope) {
- // Create a stats table.
- const int kMaxThreads = 20;
- const int kMaxCounter = 5;
- StatsTable table(StatsTable::TableIdentifier(), kMaxThreads, kMaxCounter);
- StatsTable::set_current(&table);
-
- StatsCounterTimer foo("foo");
- StatsRate bar("bar");
-
- // Test initial state.
- EXPECT_EQ(0, table.GetCounterValue("t:foo"));
- EXPECT_EQ(0, table.GetCounterValue("t:bar"));
- EXPECT_EQ(0, table.GetCounterValue("c:bar"));
-
- const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);
-
- // Try a scope.
- {
- StatsScope<StatsCounterTimer> timer(foo);
- StatsScope<StatsRate> timer2(bar);
- PlatformThread::Sleep(kDuration);
- }
- EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:foo"));
- EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
- EXPECT_EQ(1, table.GetCounterValue("c:bar"));
-
- // Try a second scope.
- {
- StatsScope<StatsCounterTimer> timer(foo);
- StatsScope<StatsRate> timer2(bar);
- PlatformThread::Sleep(kDuration);
- }
- EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:foo"));
- EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
- EXPECT_EQ(2, table.GetCounterValue("c:bar"));
-}
-
-} // namespace base
diff --git a/chromium/base/move.h b/chromium/base/move.h
index 06f3f323723..87dc52d16c5 100644
--- a/chromium/base/move.h
+++ b/chromium/base/move.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/compiler_specific.h"
-
#ifndef BASE_MOVE_H_
#define BASE_MOVE_H_
+#include "base/compiler_specific.h"
+
// Macro with the boilerplate that makes a type move-only in C++03.
//
// USAGE
@@ -219,11 +219,16 @@
#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
private: \
- type(type&); \
- void operator=(type&); \
+ type(const type&); \
+ void operator=(const type&); \
public: \
type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
typedef void MoveOnlyTypeForCPP03; \
private:
+#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
+ public: \
+ type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+ private:
+
#endif // BASE_MOVE_H_
diff --git a/chromium/base/move_unittest.cc b/chromium/base/move_unittest.cc
new file mode 100644
index 00000000000..1f4ce84cb6a
--- /dev/null
+++ b/chromium/base/move_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2015 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/move.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MoveOnly {
+ MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(MoveOnly)
+
+ public:
+ MoveOnly() {}
+
+ MoveOnly(MoveOnly&& other) {}
+ MoveOnly& operator=(MoveOnly&& other) { return *this; }
+};
+
+class Container {
+ public:
+ Container() = default;
+ Container(const Container& other) = default;
+ Container& operator=(const Container& other) = default;
+
+ Container(Container&& other) { value_ = other.value_.Pass(); }
+
+ Container& operator=(Container&& other) {
+ value_ = other.value_.Pass();
+ return *this;
+ }
+
+ private:
+ MoveOnly value_;
+};
+
+Container GetContainerRvalue() {
+ Container x;
+ return x;
+}
+
+TEST(MoveTest, CopyableContainerCanBeMoved) {
+ // Container should be move-constructible and move-assignable.
+ Container y = GetContainerRvalue();
+ y = GetContainerRvalue();
+}
+
+} // namespace
diff --git a/chromium/base/native_library_ios.mm b/chromium/base/native_library_ios.mm
new file mode 100644
index 00000000000..030c171eceb
--- /dev/null
+++ b/chromium/base/native_library_ios.mm
@@ -0,0 +1,40 @@
+// Copyright (c) 2015 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/native_library.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+std::string NativeLibraryLoadError::ToString() const {
+ return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
+ NativeLibraryLoadError* error) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+ NOTIMPLEMENTED();
+ DCHECK(!library);
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+ const char* name) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+ return name;
+}
+
+} // namespace base
diff --git a/chromium/base/nix/xdg_util.cc b/chromium/base/nix/xdg_util.cc
index e2a48d4b938..ef045617761 100644
--- a/chromium/base/nix/xdg_util.cc
+++ b/chromium/base/nix/xdg_util.cc
@@ -33,7 +33,7 @@ FilePath GetXDGDirectory(Environment* env, const char* env_name,
if (env->GetVar(env_name, &env_value) && !env_value.empty()) {
path = FilePath(env_value);
} else {
- PathService::Get(base::DIR_HOME, &path);
+ PathService::Get(DIR_HOME, &path);
path = path.Append(fallback_dir);
}
return path.StripTrailingSeparators();
@@ -46,7 +46,7 @@ FilePath GetXDGUserDirectory(const char* dir_name, const char* fallback_dir) {
path = FilePath(xdg_dir);
free(xdg_dir);
} else {
- PathService::Get(base::DIR_HOME, &path);
+ PathService::Get(DIR_HOME, &path);
path = path.Append(fallback_dir);
}
return path.StripTrailingSeparators();
@@ -68,15 +68,17 @@ DesktopEnvironment GetDesktopEnvironment(Environment* env) {
return DESKTOP_ENVIRONMENT_UNITY;
} else if (xdg_current_desktop == "GNOME") {
return DESKTOP_ENVIRONMENT_GNOME;
+ } else if (xdg_current_desktop == "KDE") {
+ return DESKTOP_ENVIRONMENT_KDE4;
}
}
// DESKTOP_SESSION was what everyone used in 2010.
std::string desktop_session;
if (env->GetVar("DESKTOP_SESSION", &desktop_session)) {
- if (desktop_session == "gnome") {
+ if (desktop_session == "gnome" || desktop_session =="mate") {
return DESKTOP_ENVIRONMENT_GNOME;
- } else if (desktop_session == "kde4") {
+ } else if (desktop_session == "kde4" || desktop_session == "kde-plasma") {
return DESKTOP_ENVIRONMENT_KDE4;
} else if (desktop_session == "kde") {
// This may mean KDE4 on newer systems, so we have to check.
diff --git a/chromium/base/nix/xdg_util_unittest.cc b/chromium/base/nix/xdg_util_unittest.cc
index 6d10d3e3f00..136eb5d745d 100644
--- a/chromium/base/nix/xdg_util_unittest.cc
+++ b/chromium/base/nix/xdg_util_unittest.cc
@@ -25,51 +25,104 @@ class MockEnvironment : public Environment {
MOCK_METHOD1(UnSetVar, bool(const char*));
};
-const char* const kGnome = "gnome";
-const char* const kKDE4 = "kde4";
-const char* const kKDE = "kde";
-const char* const kXFCE = "xfce";
+// Needs to be const char* to make gmock happy.
+const char* const kDesktopGnome = "gnome";
+const char* const kDesktopGnomeFallback = "gnome-fallback";
+const char* const kDesktopMATE = "mate";
+const char* const kDesktopKDE4 = "kde4";
+const char* const kDesktopKDE = "kde";
+const char* const kDesktopXFCE = "xfce";
+const char* const kXdgDesktopGNOME = "GNOME";
+const char* const kXdgDesktopKDE = "KDE";
+const char* const kXdgDesktopUnity = "Unity";
+
+const char kDesktopSession[] = "DESKTOP_SESSION";
+const char kXdgDesktop[] = "XDG_CURRENT_DESKTOP";
} // namespace
TEST(XDGUtilTest, GetDesktopEnvironmentGnome) {
MockEnvironment getter;
EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
- .WillOnce(DoAll(SetArgumentPointee<1>(kGnome), Return(true)));
+ EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopGnome), Return(true)));
- EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME,
- GetDesktopEnvironment(&getter));
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentMATE) {
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopMATE), Return(true)));
+
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
}
TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) {
MockEnvironment getter;
EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
- .WillOnce(DoAll(SetArgumentPointee<1>(kKDE4), Return(true)));
+ EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopKDE4), Return(true)));
- EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4,
- GetDesktopEnvironment(&getter));
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter));
}
TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) {
MockEnvironment getter;
EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
- .WillOnce(DoAll(SetArgumentPointee<1>(kKDE), Return(true)));
+ EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopKDE), Return(true)));
- EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3,
- GetDesktopEnvironment(&getter));
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3, GetDesktopEnvironment(&getter));
}
TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) {
MockEnvironment getter;
EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
- .WillOnce(DoAll(SetArgumentPointee<1>(kXFCE), Return(true)));
+ EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopXFCE), Return(true)));
+
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopGnome) {
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopGNOME), Return(true)));
+
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopGnomeFallback) {
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopUnity), Return(true)));
+ EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopGnomeFallback),
+ Return(true)));
+
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopKDE4) {
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopKDE), Return(true)));
+
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopUnity) {
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopUnity), Return(true)));
- EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE,
- GetDesktopEnvironment(&getter));
+ EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter));
}
} // namespace nix
diff --git a/chromium/base/numerics/safe_conversions.h b/chromium/base/numerics/safe_conversions.h
index fe85fc6f52d..d9b77f76d50 100644
--- a/chromium/base/numerics/safe_conversions.h
+++ b/chromium/base/numerics/safe_conversions.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_SAFE_CONVERSIONS_H_
-#define BASE_SAFE_CONVERSIONS_H_
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
#include <limits>
@@ -60,5 +60,4 @@ inline Dst saturated_cast(Src value) {
} // namespace base
-#endif // BASE_SAFE_CONVERSIONS_H_
-
+#endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/chromium/base/numerics/safe_conversions_impl.h b/chromium/base/numerics/safe_conversions_impl.h
index c26757a4b3c..504ce7ef297 100644
--- a/chromium/base/numerics/safe_conversions_impl.h
+++ b/chromium/base/numerics/safe_conversions_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_SAFE_CONVERSIONS_IMPL_H_
-#define BASE_SAFE_CONVERSIONS_IMPL_H_
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#include <limits>
@@ -212,5 +212,4 @@ inline RangeConstraint DstRangeRelationToSrcRange(Src value) {
} // namespace internal
} // namespace base
-#endif // BASE_SAFE_CONVERSIONS_IMPL_H_
-
+#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/chromium/base/numerics/safe_math.h b/chromium/base/numerics/safe_math.h
index ccda1c873e6..1309446e195 100644
--- a/chromium/base/numerics/safe_math.h
+++ b/chromium/base/numerics/safe_math.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_SAFE_MATH_H_
-#define BASE_SAFE_MATH_H_
+#ifndef BASE_NUMERICS_SAFE_MATH_H_
+#define BASE_NUMERICS_SAFE_MATH_H_
#include "base/numerics/safe_math_impl.h"
@@ -269,4 +269,4 @@ using internal::CheckedNumeric;
} // namespace base
-#endif // BASE_SAFE_MATH_H_
+#endif // BASE_NUMERICS_SAFE_MATH_H_
diff --git a/chromium/base/numerics/safe_math_impl.h b/chromium/base/numerics/safe_math_impl.h
index 663f393665d..08f2e88345f 100644
--- a/chromium/base/numerics/safe_math_impl.h
+++ b/chromium/base/numerics/safe_math_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SAFE_MATH_IMPL_H_
-#define SAFE_MATH_IMPL_H_
+#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_IMPL_H_
#include <stdint.h>
@@ -176,8 +176,8 @@ typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits<
T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)),
T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
- // if either side is zero then the result will be zero.
- if (!(x || y)) {
+ // If either side is zero then the result will be zero.
+ if (!x || !y) {
return RANGE_VALID;
} else if (x > 0) {
@@ -498,4 +498,4 @@ struct IsIntegerArithmeticSafe {
} // namespace internal
} // namespace base
-#endif // SAFE_MATH_IMPL_H_
+#endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
diff --git a/chromium/base/numerics/safe_numerics_unittest.cc b/chromium/base/numerics/safe_numerics_unittest.cc
index 0402cef200a..3185b06faf0 100644
--- a/chromium/base/numerics/safe_numerics_unittest.cc
+++ b/chromium/base/numerics/safe_numerics_unittest.cc
@@ -26,14 +26,6 @@ using base::internal::RANGE_OVERFLOW;
using base::internal::RANGE_UNDERFLOW;
using base::enable_if;
-// MSVS 2013 ia32 may not reset the FPU between calculations, and the test
-// framework masks the exceptions. So we just force a manual reset after NaN.
-inline void ResetFloatingPointUnit() {
-#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
- _mm_empty();
-#endif
-}
-
// These tests deliberately cause arithmetic overflows. If the compiler is
// aggressive enough, it can const fold these overflows. Disable warnings about
// overflows for const expressions.
@@ -247,6 +239,9 @@ static void TestArithmetic(const char* dst, int line) {
TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1));
TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1));
TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2));
+ TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0));
+ TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0));
+ TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1));
TEST_EXPECTED_VALIDITY(
RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max());
@@ -341,7 +336,6 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> {
TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
- ResetFloatingPointUnit();
} else if (numeric_limits<Src>::is_signed) {
TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
@@ -373,7 +367,6 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> {
TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
- ResetFloatingPointUnit();
} else if (SrcLimits::is_signed) {
TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
@@ -432,7 +425,6 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> {
TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
- ResetFloatingPointUnit();
} else {
TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
}
diff --git a/chromium/base/observer_list.h b/chromium/base/observer_list.h
index c77ec15b1db..fb6f0262dfd 100644
--- a/chromium/base/observer_list.h
+++ b/chromium/base/observer_list.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_OBSERVER_LIST_H__
-#define BASE_OBSERVER_LIST_H__
+#ifndef BASE_OBSERVER_LIST_H_
+#define BASE_OBSERVER_LIST_H_
#include <algorithm>
#include <limits>
@@ -79,7 +79,7 @@ class ObserverListBase
// also the FOR_EACH_OBSERVER macro defined below.
class Iterator {
public:
- Iterator(ObserverListBase<ObserverType>& list);
+ explicit Iterator(ObserverListBase<ObserverType>* list);
~Iterator();
ObserverType* GetNext();
@@ -100,7 +100,8 @@ class ObserverListBase
// Remove an observer from the list if it is in the list.
void RemoveObserver(ObserverType* obs);
- bool HasObserver(ObserverType* observer) const;
+ // Determine whether a particular observer is in the list.
+ bool HasObserver(const ObserverType* observer) const;
void Clear();
@@ -125,12 +126,11 @@ class ObserverListBase
template <class ObserverType>
ObserverListBase<ObserverType>::Iterator::Iterator(
- ObserverListBase<ObserverType>& list)
- : list_(list.AsWeakPtr()),
+ ObserverListBase<ObserverType>* list)
+ : list_(list->AsWeakPtr()),
index_(0),
- max_index_(list.type_ == NOTIFY_ALL ?
- std::numeric_limits<size_t>::max() :
- list.observers_.size()) {
+ max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
+ : list->observers_.size()) {
++list_->notify_depth_;
}
@@ -143,17 +143,18 @@ ObserverListBase<ObserverType>::Iterator::~Iterator() {
template <class ObserverType>
ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
if (!list_.get())
- return NULL;
+ return nullptr;
ListType& observers = list_->observers_;
// Advance if the current element is null
size_t max_index = std::min(max_index_, observers.size());
while (index_ < max_index && !observers[index_])
++index_;
- return index_ < max_index ? observers[index_++] : NULL;
+ return index_ < max_index ? observers[index_++] : nullptr;
}
template <class ObserverType>
void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
+ DCHECK(obs);
if (std::find(observers_.begin(), observers_.end(), obs)
!= observers_.end()) {
NOTREACHED() << "Observers can only be added once!";
@@ -164,11 +165,12 @@ void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
template <class ObserverType>
void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
+ DCHECK(obs);
typename ListType::iterator it =
std::find(observers_.begin(), observers_.end(), obs);
if (it != observers_.end()) {
if (notify_depth_) {
- *it = 0;
+ *it = nullptr;
} else {
observers_.erase(it);
}
@@ -176,7 +178,8 @@ void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
}
template <class ObserverType>
-bool ObserverListBase<ObserverType>::HasObserver(ObserverType* observer) const {
+bool ObserverListBase<ObserverType>::HasObserver(
+ const ObserverType* observer) const {
for (size_t i = 0; i < observers_.size(); ++i) {
if (observers_[i] == observer)
return true;
@@ -189,7 +192,7 @@ void ObserverListBase<ObserverType>::Clear() {
if (notify_depth_) {
for (typename ListType::iterator it = observers_.begin();
it != observers_.end(); ++it) {
- *it = 0;
+ *it = nullptr;
}
} else {
observers_.clear();
@@ -199,8 +202,8 @@ void ObserverListBase<ObserverType>::Clear() {
template <class ObserverType>
void ObserverListBase<ObserverType>::Compact() {
observers_.erase(
- std::remove(observers_.begin(), observers_.end(),
- static_cast<ObserverType*>(NULL)), observers_.end());
+ std::remove(observers_.begin(), observers_.end(), nullptr),
+ observers_.end());
}
template <class ObserverType, bool check_empty = false>
@@ -226,15 +229,15 @@ class ObserverList : public ObserverListBase<ObserverType> {
}
};
-#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
- do { \
- if ((observer_list).might_have_observers()) { \
- ObserverListBase<ObserverType>::Iterator \
- it_inside_observer_macro(observer_list); \
- ObserverType* obs; \
- while ((obs = it_inside_observer_macro.GetNext()) != NULL) \
- obs->func; \
- } \
+#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
+ do { \
+ if ((observer_list).might_have_observers()) { \
+ ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \
+ &observer_list); \
+ ObserverType* obs; \
+ while ((obs = it_inside_observer_macro.GetNext()) != nullptr) \
+ obs->func; \
+ } \
} while (0)
-#endif // BASE_OBSERVER_LIST_H__
+#endif // BASE_OBSERVER_LIST_H_
diff --git a/chromium/base/observer_list_threadsafe.h b/chromium/base/observer_list_threadsafe.h
index 70b4f11ffa6..e0ce0daa90f 100644
--- a/chromium/base/observer_list_threadsafe.h
+++ b/chromium/base/observer_list_threadsafe.h
@@ -14,9 +14,10 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
///////////////////////////////////////////////////////////////////////////////
@@ -111,7 +112,7 @@ class ObserverListThreadSafe
if (!base::MessageLoop::current())
return;
- ObserverList<ObserverType>* list = NULL;
+ ObserverList<ObserverType>* list = nullptr;
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
{
base::AutoLock lock(list_lock_);
@@ -128,8 +129,8 @@ class ObserverListThreadSafe
// If the observer to be removed is in the list, RemoveObserver MUST
// be called from the same thread which called AddObserver.
void RemoveObserver(ObserverType* obs) {
- ObserverListContext* context = NULL;
- ObserverList<ObserverType>* list = NULL;
+ ObserverListContext* context = nullptr;
+ ObserverList<ObserverType>* list = nullptr;
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
{
base::AutoLock lock(list_lock_);
@@ -167,54 +168,37 @@ class ObserverListThreadSafe
// Note, these calls are effectively asynchronous. You cannot assume
// that at the completion of the Notify call that all Observers have
// been Notified. The notification may still be pending delivery.
- template <class Method>
- void Notify(Method m) {
- UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
- Notify<Method, Tuple0>(method);
- }
-
- template <class Method, class A>
- void Notify(Method m, const A& a) {
- UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
- Notify<Method, Tuple1<A> >(method);
- }
-
- template <class Method, class A, class B>
- void Notify(Method m, const A& a, const B& b) {
- UnboundMethod<ObserverType, Method, Tuple2<A, B> > method(
- m, MakeTuple(a, b));
- Notify<Method, Tuple2<A, B> >(method);
- }
+ template <class Method, class... Params>
+ void Notify(const tracked_objects::Location& from_here,
+ Method m,
+ const Params&... params) {
+ UnboundMethod<ObserverType, Method, Tuple<Params...>> method(
+ m, MakeTuple(params...));
- template <class Method, class A, class B, class C>
- void Notify(Method m, const A& a, const B& b, const C& c) {
- UnboundMethod<ObserverType, Method, Tuple3<A, B, C> > method(
- m, MakeTuple(a, b, c));
- Notify<Method, Tuple3<A, B, C> >(method);
- }
-
- template <class Method, class A, class B, class C, class D>
- void Notify(Method m, const A& a, const B& b, const C& c, const D& d) {
- UnboundMethod<ObserverType, Method, Tuple4<A, B, C, D> > method(
- m, MakeTuple(a, b, c, d));
- Notify<Method, Tuple4<A, B, C, D> >(method);
+ base::AutoLock lock(list_lock_);
+ for (const auto& entry : observer_lists_) {
+ ObserverListContext* context = entry.second;
+ context->task_runner->PostTask(
+ from_here,
+ base::Bind(
+ &ObserverListThreadSafe<ObserverType>::template NotifyWrapper<
+ Method, Tuple<Params...>>,
+ this, context, method));
+ }
}
- // TODO(mbelshe): Add more wrappers for Notify() with more arguments.
-
private:
// See comment above ObserverListThreadSafeTraits' definition.
friend struct ObserverListThreadSafeTraits<ObserverType>;
struct ObserverListContext {
explicit ObserverListContext(NotificationType type)
- : loop(base::MessageLoopProxy::current()),
- list(type) {
- }
+ : task_runner(base::ThreadTaskRunnerHandle::Get()), list(type) {}
- scoped_refptr<base::MessageLoopProxy> loop;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner;
ObserverList<ObserverType> list;
+ private:
DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
};
@@ -222,26 +206,12 @@ class ObserverListThreadSafe
STLDeleteValues(&observer_lists_);
}
- template <class Method, class Params>
- void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
- base::AutoLock lock(list_lock_);
- typename ObserversListMap::iterator it;
- for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
- ObserverListContext* context = (*it).second;
- context->loop->PostTask(
- FROM_HERE,
- base::Bind(&ObserverListThreadSafe<ObserverType>::
- template NotifyWrapper<Method, Params>, this, context, method));
- }
- }
-
// Wrapper which is called to fire the notifications for each thread's
// ObserverList. This function MUST be called on the thread which owns
// the unsafe ObserverList.
template <class Method, class Params>
void NotifyWrapper(ObserverListContext* context,
const UnboundMethod<ObserverType, Method, Params>& method) {
-
// Check that this list still needs notifications.
{
base::AutoLock lock(list_lock_);
@@ -257,9 +227,9 @@ class ObserverListThreadSafe
}
{
- typename ObserverList<ObserverType>::Iterator it(context->list);
+ typename ObserverList<ObserverType>::Iterator it(&context->list);
ObserverType* obs;
- while ((obs = it.GetNext()) != NULL)
+ while ((obs = it.GetNext()) != nullptr)
method.Run(obs);
}
diff --git a/chromium/base/observer_list_unittest.cc b/chromium/base/observer_list_unittest.cc
index 11f59be5065..2e51e455216 100644
--- a/chromium/base/observer_list_unittest.cc
+++ b/chromium/base/observer_list_unittest.cc
@@ -8,9 +8,10 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/location.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -71,7 +72,7 @@ class AddInObserve : public Foo {
adder(1) {
}
- virtual void Observe(int x) override {
+ void Observe(int x) override {
if (!added) {
added = true;
observer_list->AddObserver(&adder);
@@ -94,7 +95,7 @@ class AddRemoveThread : public PlatformThread::Delegate,
public:
AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
: list_(list),
- loop_(NULL),
+ loop_(nullptr),
in_list_(false),
start_(Time::Now()),
count_observes_(0),
@@ -107,7 +108,7 @@ class AddRemoveThread : public PlatformThread::Delegate,
void ThreadMain() override {
loop_ = new MessageLoop(); // Fire up a message loop.
- loop_->PostTask(
+ loop_->task_runner()->PostTask(
FROM_HERE,
base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
loop_->Run();
@@ -134,16 +135,17 @@ class AddRemoveThread : public PlatformThread::Delegate,
}
if (do_notifies_) {
- list_->Notify(&Foo::Observe, 10);
+ list_->Notify(FROM_HERE, &Foo::Observe, 10);
}
- loop_->PostTask(
+ loop_->task_runner()->PostTask(
FROM_HERE,
base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
}
void Quit() {
- loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+ loop_->task_runner()->PostTask(FROM_HERE,
+ MessageLoop::QuitWhenIdleClosure());
}
void Observe(int x) override {
@@ -182,6 +184,9 @@ TEST(ObserverListTest, BasicTest) {
observer_list.AddObserver(&a);
observer_list.AddObserver(&b);
+ EXPECT_TRUE(observer_list.HasObserver(&a));
+ EXPECT_FALSE(observer_list.HasObserver(&c));
+
FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
observer_list.AddObserver(&evil);
@@ -214,14 +219,14 @@ TEST(ObserverListThreadSafeTest, BasicTest) {
observer_list->AddObserver(&a);
observer_list->AddObserver(&b);
- observer_list->Notify(&Foo::Observe, 10);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
RunLoop().RunUntilIdle();
observer_list->AddObserver(&evil);
observer_list->AddObserver(&c);
observer_list->AddObserver(&d);
- observer_list->Notify(&Foo::Observe, 10);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
RunLoop().RunUntilIdle();
EXPECT_EQ(20, a.total);
@@ -244,7 +249,7 @@ TEST(ObserverListThreadSafeTest, RemoveObserver) {
observer_list->RemoveObserver(&a);
observer_list->RemoveObserver(&b);
- observer_list->Notify(&Foo::Observe, 10);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
RunLoop().RunUntilIdle();
EXPECT_EQ(0, a.total);
@@ -255,7 +260,7 @@ TEST(ObserverListThreadSafeTest, RemoveObserver) {
// Should also do nothing.
observer_list->RemoveObserver(&b);
- observer_list->Notify(&Foo::Observe, 10);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
RunLoop().RunUntilIdle();
EXPECT_EQ(10, a.total);
@@ -277,7 +282,7 @@ TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
MessageLoop loop;
observer_list->AddObserver(&c);
- observer_list->Notify(&Foo::Observe, 10);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
RunLoop().RunUntilIdle();
EXPECT_EQ(0, a.total);
@@ -291,7 +296,7 @@ TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
observer_list->RemoveObserver(&c);
// Notify again.
- observer_list->Notify(&Foo::Observe, 20);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 20);
RunLoop().RunUntilIdle();
EXPECT_EQ(20, a.total);
@@ -305,7 +310,7 @@ TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
// Notifying should not fail but should also be a no-op.
MessageLoop loop;
observer_list->AddObserver(&b);
- observer_list->Notify(&Foo::Observe, 30);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 30);
RunLoop().RunUntilIdle();
EXPECT_EQ(20, a.total);
@@ -350,7 +355,7 @@ TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
a.AddFooToRemove(&a);
a.AddFooToRemove(&b);
- observer_list->Notify(&Foo::Observe, 1);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
RunLoop().RunUntilIdle();
}
@@ -389,7 +394,7 @@ static void ThreadSafeObserverHarness(int num_threads,
if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
break;
- observer_list->Notify(&Foo::Observe, 10);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
RunLoop().RunUntilIdle();
}
@@ -421,7 +426,7 @@ TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) {
observer_list->AddObserver(&a);
delete loop;
// Test passes if we don't crash here.
- observer_list->Notify(&Foo::Observe, 1);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
}
TEST(ObserverListTest, Existing) {
@@ -455,7 +460,7 @@ TEST(ObserverListThreadSafeTest, Existing) {
observer_list->AddObserver(&a);
observer_list->AddObserver(&b);
- observer_list->Notify(&Foo::Observe, 1);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
RunLoop().RunUntilIdle();
EXPECT_TRUE(b.added);
@@ -464,7 +469,7 @@ TEST(ObserverListThreadSafeTest, Existing) {
EXPECT_EQ(0, b.adder.total);
// Notify again to make sure b's adder is notified.
- observer_list->Notify(&Foo::Observe, 1);
+ observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
RunLoop().RunUntilIdle();
EXPECT_EQ(1, b.adder.total);
}
diff --git a/chromium/base/path_service.cc b/chromium/base/path_service.cc
index ce4966ed709..3c437ee7493 100644
--- a/chromium/base/path_service.cc
+++ b/chromium/base/path_service.cc
@@ -33,7 +33,7 @@ namespace base {
// Mac and Android.
bool PathProviderPosix(int key, FilePath* result);
#endif
-}
+} // namespace base
namespace {
diff --git a/chromium/base/path_service.h b/chromium/base/path_service.h
index 554eb9e3464..025550f2ad1 100644
--- a/chromium/base/path_service.h
+++ b/chromium/base/path_service.h
@@ -15,7 +15,7 @@
namespace base {
class FilePath;
class ScopedPathOverride;
-} // namespace
+} // namespace base
// The path service is a global table mapping keys to file system paths. It is
// OK to use this service from multiple threads.
diff --git a/chromium/base/path_service_unittest.cc b/chromium/base/path_service_unittest.cc
index 543deb60a70..7551d676416 100644
--- a/chromium/base/path_service_unittest.cc
+++ b/chromium/base/path_service_unittest.cc
@@ -220,3 +220,55 @@ TEST_F(PathServiceTest, RemoveOverride) {
EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
EXPECT_EQ(original_user_data_dir, new_user_data_dir);
}
+
+#if defined(OS_WIN)
+TEST_F(PathServiceTest, GetProgramFiles) {
+ base::FilePath programfiles_dir;
+#if defined(_WIN64)
+ // 64-bit on 64-bit.
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files"));
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files"));
+#else
+ if (base::win::OSInfo::GetInstance()->wow64_status() ==
+ base::win::OSInfo::WOW64_ENABLED) {
+ // 32-bit on 64-bit.
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files"));
+ } else {
+ // 32-bit on 32-bit.
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files"));
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files"));
+ EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+ &programfiles_dir));
+ EXPECT_EQ(programfiles_dir.value(),
+ FILE_PATH_LITERAL("C:\\Program Files"));
+ }
+#endif
+}
+#endif
diff --git a/chromium/base/pending_task.h b/chromium/base/pending_task.h
index a2edc6947d0..fddfc868fe7 100644
--- a/chromium/base/pending_task.h
+++ b/chromium/base/pending_task.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PENDING_TASK_H_
-#define PENDING_TASK_H_
+#ifndef BASE_PENDING_TASK_H_
+#define BASE_PENDING_TASK_H_
#include <queue>
@@ -57,4 +57,4 @@ typedef std::priority_queue<base::PendingTask> DelayedTaskQueue;
} // namespace base
-#endif // PENDING_TASK_H_
+#endif // BASE_PENDING_TASK_H_
diff --git a/chromium/base/pickle.cc b/chromium/base/pickle.cc
index d461f413dfd..112ddc33e7b 100644
--- a/chromium/base/pickle.cc
+++ b/chromium/base/pickle.cc
@@ -152,15 +152,15 @@ bool PickleIterator::ReadString(std::string* result) {
return true;
}
-bool PickleIterator::ReadWString(std::wstring* result) {
+bool PickleIterator::ReadStringPiece(base::StringPiece* result) {
int len;
if (!ReadInt(&len))
return false;
- const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t));
+ const char* read_from = GetReadPointerAndAdvance(len);
if (!read_from)
return false;
- result->assign(reinterpret_cast<const wchar_t*>(read_from), len);
+ *result = base::StringPiece(read_from, len);
return true;
}
@@ -176,6 +176,19 @@ bool PickleIterator::ReadString16(string16* result) {
return true;
}
+bool PickleIterator::ReadStringPiece16(base::StringPiece16* result) {
+ int len;
+ if (!ReadInt(&len))
+ return false;
+ const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
+ if (!read_from)
+ return false;
+
+ *result = base::StringPiece16(reinterpret_cast<const char16*>(read_from),
+ len);
+ return true;
+}
+
bool PickleIterator::ReadData(const char** data, int* length) {
*length = 0;
*data = 0;
@@ -271,22 +284,14 @@ Pickle& Pickle::operator=(const Pickle& other) {
return *this;
}
-bool Pickle::WriteString(const std::string& value) {
+bool Pickle::WriteString(const base::StringPiece& value) {
if (!WriteInt(static_cast<int>(value.size())))
return false;
return WriteBytes(value.data(), static_cast<int>(value.size()));
}
-bool Pickle::WriteWString(const std::wstring& value) {
- if (!WriteInt(static_cast<int>(value.size())))
- return false;
-
- return WriteBytes(value.data(),
- static_cast<int>(value.size() * sizeof(wchar_t)));
-}
-
-bool Pickle::WriteString16(const string16& value) {
+bool Pickle::WriteString16(const base::StringPiece16& value) {
if (!WriteInt(static_cast<int>(value.size())))
return false;
@@ -353,6 +358,7 @@ template void Pickle::WriteBytesStatic<8>(const void* data);
inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
<< "oops: pickle is readonly";
+ MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
size_t data_len = AlignInt(length, sizeof(uint32));
DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
diff --git a/chromium/base/pickle.h b/chromium/base/pickle.h
index 11cf4841f67..9589e2aadad 100644
--- a/chromium/base/pickle.h
+++ b/chromium/base/pickle.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_PICKLE_H__
-#define BASE_PICKLE_H__
+#ifndef BASE_PICKLE_H_
+#define BASE_PICKLE_H_
#include <string>
@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
class Pickle;
@@ -26,7 +27,7 @@ class BASE_EXPORT PickleIterator {
// Methods for reading the payload of the Pickle. To read from the start of
// the Pickle, create a PickleIterator from a Pickle. If successful, these
// methods return true. Otherwise, false is returned to indicate that the
- // result could not be extracted. It is not possible to read from iterator
+ // result could not be extracted. It is not possible to read from the iterator
// after that.
bool ReadBool(bool* result) WARN_UNUSED_RESULT;
bool ReadInt(int* result) WARN_UNUSED_RESULT;
@@ -39,12 +40,26 @@ class BASE_EXPORT PickleIterator {
bool ReadFloat(float* result) WARN_UNUSED_RESULT;
bool ReadDouble(double* result) WARN_UNUSED_RESULT;
bool ReadString(std::string* result) WARN_UNUSED_RESULT;
- bool ReadWString(std::wstring* result) WARN_UNUSED_RESULT;
+ // The StringPiece data will only be valid for the lifetime of the message.
+ bool ReadStringPiece(base::StringPiece* result) WARN_UNUSED_RESULT;
bool ReadString16(base::string16* result) WARN_UNUSED_RESULT;
+ // The StringPiece16 data will only be valid for the lifetime of the message.
+ bool ReadStringPiece16(base::StringPiece16* result) WARN_UNUSED_RESULT;
+
+ // A pointer to the data will be placed in |*data|, and the length will be
+ // placed in |*length|. The pointer placed into |*data| points into the
+ // message's buffer so it will be scoped to the lifetime of the message (or
+ // until the message data is mutated). Do not keep the pointer around!
bool ReadData(const char** data, int* length) WARN_UNUSED_RESULT;
+
+ // A pointer to the data will be placed in |*data|. The caller specifies the
+ // number of bytes to read, and ReadBytes will validate this length. The
+ // pointer placed into |*data| points into the message's buffer so it will be
+ // scoped to the lifetime of the message (or until the message data is
+ // mutated). Do not keep the pointer around!
bool ReadBytes(const char** data, int length) WARN_UNUSED_RESULT;
- // Safer version of ReadInt() checks for the result not being negative.
+ // A safer version of ReadInt() that checks for the result not being negative.
// Use it for reading the object sizes.
bool ReadLength(int* result) WARN_UNUSED_RESULT {
return ReadInt(result) && *result >= 0;
@@ -57,7 +72,7 @@ class BASE_EXPORT PickleIterator {
}
private:
- // Aligns 'i' by rounding it up to the next multiple of 'alignment'
+ // Aligns 'i' by rounding it up to the next multiple of 'alignment'.
static size_t AlignInt(size_t i, int alignment) {
return i + (alignment - (i % alignment)) % alignment;
}
@@ -142,91 +157,11 @@ class BASE_EXPORT Pickle {
// Returns the data for this Pickle.
const void* data() const { return header_; }
- // For compatibility, these older style read methods pass through to the
- // PickleIterator methods.
- // TODO(jbates) Remove these methods.
- bool ReadBool(PickleIterator* iter,
- bool* result) const WARN_UNUSED_RESULT {
- return iter->ReadBool(result);
- }
- bool ReadInt(PickleIterator* iter,
- int* result) const WARN_UNUSED_RESULT {
- return iter->ReadInt(result);
- }
- bool ReadLong(PickleIterator* iter,
- long* result) const WARN_UNUSED_RESULT {
- return iter->ReadLong(result);
- }
- bool ReadUInt16(PickleIterator* iter,
- uint16* result) const WARN_UNUSED_RESULT {
- return iter->ReadUInt16(result);
- }
- bool ReadUInt32(PickleIterator* iter,
- uint32* result) const WARN_UNUSED_RESULT {
- return iter->ReadUInt32(result);
- }
- bool ReadInt64(PickleIterator* iter,
- int64* result) const WARN_UNUSED_RESULT {
- return iter->ReadInt64(result);
- }
- bool ReadUInt64(PickleIterator* iter,
- uint64* result) const WARN_UNUSED_RESULT {
- return iter->ReadUInt64(result);
- }
- bool ReadSizeT(PickleIterator* iter,
- size_t* result) const WARN_UNUSED_RESULT {
- return iter->ReadSizeT(result);
- }
- bool ReadFloat(PickleIterator* iter,
- float* result) const WARN_UNUSED_RESULT {
- return iter->ReadFloat(result);
- }
- bool ReadDouble(PickleIterator* iter,
- double* result) const WARN_UNUSED_RESULT {
- return iter->ReadDouble(result);
- }
- bool ReadString(PickleIterator* iter,
- std::string* result) const WARN_UNUSED_RESULT {
- return iter->ReadString(result);
- }
- bool ReadWString(PickleIterator* iter,
- std::wstring* result) const WARN_UNUSED_RESULT {
- return iter->ReadWString(result);
- }
- bool ReadString16(PickleIterator* iter,
- base::string16* result) const WARN_UNUSED_RESULT {
- return iter->ReadString16(result);
- }
- // A pointer to the data will be placed in *data, and the length will be
- // placed in *length. This buffer will be into the message's buffer so will
- // be scoped to the lifetime of the message (or until the message data is
- // mutated).
- bool ReadData(PickleIterator* iter,
- const char** data,
- int* length) const WARN_UNUSED_RESULT {
- return iter->ReadData(data, length);
- }
- // A pointer to the data will be placed in *data. The caller specifies the
- // number of bytes to read, and ReadBytes will validate this length. The
- // returned buffer will be into the message's buffer so will be scoped to the
- // lifetime of the message (or until the message data is mutated).
- bool ReadBytes(PickleIterator* iter,
- const char** data,
- int length) const WARN_UNUSED_RESULT {
- return iter->ReadBytes(data, length);
- }
-
- // Safer version of ReadInt() checks for the result not being negative.
- // Use it for reading the object sizes.
- bool ReadLength(PickleIterator* iter,
- int* result) const WARN_UNUSED_RESULT {
- return iter->ReadLength(result);
- }
-
// Methods for adding to the payload of the Pickle. These values are
// appended to the end of the Pickle's payload. When reading values from a
// Pickle, it is important to read them in the order in which they were added
// to the Pickle.
+
bool WriteBool(bool value) {
return WriteInt(value ? 1 : 0);
}
@@ -264,9 +199,8 @@ class BASE_EXPORT Pickle {
bool WriteDouble(double value) {
return WritePOD(value);
}
- bool WriteString(const std::string& value);
- bool WriteWString(const std::wstring& value);
- bool WriteString16(const base::string16& value);
+ bool WriteString(const base::StringPiece& value);
+ bool WriteString16(const base::StringPiece16& value);
// "Data" is a blob with a length. When you read it out you will be given the
// length. See also WriteBytes.
bool WriteData(const char* data, int length);
@@ -370,4 +304,4 @@ class BASE_EXPORT Pickle {
FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextOverflow);
};
-#endif // BASE_PICKLE_H__
+#endif // BASE_PICKLE_H_
diff --git a/chromium/base/pickle_unittest.cc b/chromium/base/pickle_unittest.cc
index 20a8d674c1f..a2c405ce918 100644
--- a/chromium/base/pickle_unittest.cc
+++ b/chromium/base/pickle_unittest.cc
@@ -30,75 +30,82 @@ const double testdouble = 2.71828182845904523;
const std::string teststring("Hello world"); // note non-aligned string length
const std::wstring testwstring(L"Hello, world");
const base::string16 teststring16(base::ASCIIToUTF16("Hello, world"));
+const char testrawstring[] = "Hello new world"; // Test raw string writing
+// Test raw char16 writing, assumes UTF16 encoding is ANSI for alpha chars.
+const base::char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0};
const char testdata[] = "AAA\0BBB\0";
const int testdatalen = arraysize(testdata) - 1;
-// checks that the result
+// checks that the results can be read correctly from the Pickle
void VerifyResult(const Pickle& pickle) {
PickleIterator iter(pickle);
bool outbool;
- EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
+ EXPECT_TRUE(iter.ReadBool(&outbool));
EXPECT_FALSE(outbool);
- EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
+ EXPECT_TRUE(iter.ReadBool(&outbool));
EXPECT_TRUE(outbool);
int outint;
- EXPECT_TRUE(pickle.ReadInt(&iter, &outint));
+ EXPECT_TRUE(iter.ReadInt(&outint));
EXPECT_EQ(testint, outint);
long outlong;
- EXPECT_TRUE(pickle.ReadLong(&iter, &outlong));
+ EXPECT_TRUE(iter.ReadLong(&outlong));
EXPECT_EQ(testlong, outlong);
uint16 outuint16;
- EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16));
+ EXPECT_TRUE(iter.ReadUInt16(&outuint16));
EXPECT_EQ(testuint16, outuint16);
uint32 outuint32;
- EXPECT_TRUE(pickle.ReadUInt32(&iter, &outuint32));
+ EXPECT_TRUE(iter.ReadUInt32(&outuint32));
EXPECT_EQ(testuint32, outuint32);
int64 outint64;
- EXPECT_TRUE(pickle.ReadInt64(&iter, &outint64));
+ EXPECT_TRUE(iter.ReadInt64(&outint64));
EXPECT_EQ(testint64, outint64);
uint64 outuint64;
- EXPECT_TRUE(pickle.ReadUInt64(&iter, &outuint64));
+ EXPECT_TRUE(iter.ReadUInt64(&outuint64));
EXPECT_EQ(testuint64, outuint64);
size_t outsizet;
- EXPECT_TRUE(pickle.ReadSizeT(&iter, &outsizet));
+ EXPECT_TRUE(iter.ReadSizeT(&outsizet));
EXPECT_EQ(testsizet, outsizet);
float outfloat;
- EXPECT_TRUE(pickle.ReadFloat(&iter, &outfloat));
+ EXPECT_TRUE(iter.ReadFloat(&outfloat));
EXPECT_EQ(testfloat, outfloat);
double outdouble;
- EXPECT_TRUE(pickle.ReadDouble(&iter, &outdouble));
+ EXPECT_TRUE(iter.ReadDouble(&outdouble));
EXPECT_EQ(testdouble, outdouble);
std::string outstring;
- EXPECT_TRUE(pickle.ReadString(&iter, &outstring));
+ EXPECT_TRUE(iter.ReadString(&outstring));
EXPECT_EQ(teststring, outstring);
- std::wstring outwstring;
- EXPECT_TRUE(pickle.ReadWString(&iter, &outwstring));
- EXPECT_EQ(testwstring, outwstring);
-
base::string16 outstring16;
- EXPECT_TRUE(pickle.ReadString16(&iter, &outstring16));
+ EXPECT_TRUE(iter.ReadString16(&outstring16));
EXPECT_EQ(teststring16, outstring16);
+ base::StringPiece outstringpiece;
+ EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece));
+ EXPECT_EQ(testrawstring, outstringpiece);
+
+ base::StringPiece16 outstringpiece16;
+ EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16));
+ EXPECT_EQ(testrawstring16, outstringpiece16);
+
const char* outdata;
int outdatalen;
- EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
+ EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen));
EXPECT_EQ(testdatalen, outdatalen);
EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
// reads past the end should fail
- EXPECT_FALSE(pickle.ReadInt(&iter, &outint));
+ EXPECT_FALSE(iter.ReadInt(&outint));
}
} // namespace
@@ -119,8 +126,9 @@ TEST(PickleTest, EncodeDecode) {
EXPECT_TRUE(pickle.WriteFloat(testfloat));
EXPECT_TRUE(pickle.WriteDouble(testdouble));
EXPECT_TRUE(pickle.WriteString(teststring));
- EXPECT_TRUE(pickle.WriteWString(testwstring));
EXPECT_TRUE(pickle.WriteString16(teststring16));
+ EXPECT_TRUE(pickle.WriteString(testrawstring));
+ EXPECT_TRUE(pickle.WriteString16(testrawstring16));
EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
VerifyResult(pickle);
@@ -148,9 +156,9 @@ TEST(PickleTest, SizeTFrom64Bit) {
if (sizeof(size_t) < sizeof(uint64)) {
// ReadSizeT() should return false when the original written value can't be
// represented as a size_t.
- EXPECT_FALSE(pickle.ReadSizeT(&iter, &outsizet));
+ EXPECT_FALSE(iter.ReadSizeT(&outsizet));
} else {
- EXPECT_TRUE(pickle.ReadSizeT(&iter, &outsizet));
+ EXPECT_TRUE(iter.ReadSizeT(&outsizet));
EXPECT_EQ(testuint64, outsizet);
}
}
@@ -164,7 +172,7 @@ TEST(PickleTest, SmallBuffer) {
PickleIterator iter(pickle);
int data;
- EXPECT_FALSE(pickle.ReadInt(&iter, &data));
+ EXPECT_FALSE(iter.ReadInt(&data));
}
// Tests that we can handle improper headers.
@@ -175,7 +183,7 @@ TEST(PickleTest, BigSize) {
PickleIterator iter(pickle);
int data;
- EXPECT_FALSE(pickle.ReadInt(&iter, &data));
+ EXPECT_FALSE(iter.ReadInt(&data));
}
TEST(PickleTest, UnalignedSize) {
@@ -185,7 +193,7 @@ TEST(PickleTest, UnalignedSize) {
PickleIterator iter(pickle);
int data;
- EXPECT_FALSE(pickle.ReadInt(&iter, &data));
+ EXPECT_FALSE(iter.ReadInt(&data));
}
TEST(PickleTest, ZeroLenStr) {
@@ -194,17 +202,17 @@ TEST(PickleTest, ZeroLenStr) {
PickleIterator iter(pickle);
std::string outstr;
- EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
+ EXPECT_TRUE(iter.ReadString(&outstr));
EXPECT_EQ("", outstr);
}
-TEST(PickleTest, ZeroLenWStr) {
+TEST(PickleTest, ZeroLenStr16) {
Pickle pickle;
- EXPECT_TRUE(pickle.WriteWString(std::wstring()));
+ EXPECT_TRUE(pickle.WriteString16(base::string16()));
PickleIterator iter(pickle);
std::string outstr;
- EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
+ EXPECT_TRUE(iter.ReadString(&outstr));
EXPECT_EQ("", outstr);
}
@@ -214,16 +222,16 @@ TEST(PickleTest, BadLenStr) {
PickleIterator iter(pickle);
std::string outstr;
- EXPECT_FALSE(pickle.ReadString(&iter, &outstr));
+ EXPECT_FALSE(iter.ReadString(&outstr));
}
-TEST(PickleTest, BadLenWStr) {
+TEST(PickleTest, BadLenStr16) {
Pickle pickle;
EXPECT_TRUE(pickle.WriteInt(-1));
PickleIterator iter(pickle);
- std::wstring woutstr;
- EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr));
+ base::string16 outstr;
+ EXPECT_FALSE(iter.ReadString16(&outstr));
}
TEST(PickleTest, FindNext) {
@@ -351,7 +359,7 @@ TEST(PickleTest, HeaderPadding) {
PickleIterator iter(pickle);
int result;
- ASSERT_TRUE(pickle.ReadInt(&iter, &result));
+ ASSERT_TRUE(iter.ReadInt(&result));
EXPECT_EQ(static_cast<uint32>(result), kMagic);
}
@@ -375,14 +383,14 @@ TEST(PickleTest, EvilLengths) {
// to out-of-bounds reading.
PickleIterator iter(source);
string16 str16;
- EXPECT_FALSE(source.ReadString16(&iter, &str16));
+ EXPECT_FALSE(iter.ReadString16(&str16));
// And check we didn't break ReadString16.
str16 = (wchar_t) 'A';
Pickle str16_pickle;
EXPECT_TRUE(str16_pickle.WriteString16(str16));
iter = PickleIterator(str16_pickle);
- EXPECT_TRUE(str16_pickle.ReadString16(&iter, &str16));
+ EXPECT_TRUE(iter.ReadString16(&str16));
EXPECT_EQ(1U, str16.length());
// Check we don't fail in a length check with invalid String16 size.
@@ -390,14 +398,7 @@ TEST(PickleTest, EvilLengths) {
Pickle bad_len;
EXPECT_TRUE(bad_len.WriteInt(1 << 31));
iter = PickleIterator(bad_len);
- EXPECT_FALSE(bad_len.ReadString16(&iter, &str16));
-
- // Check we don't fail in a length check with large WStrings.
- Pickle big_len;
- EXPECT_TRUE(big_len.WriteInt(1 << 30));
- iter = PickleIterator(big_len);
- std::wstring wstr;
- EXPECT_FALSE(big_len.ReadWString(&iter, &wstr));
+ EXPECT_FALSE(iter.ReadString16(&str16));
}
// Check we can write zero bytes of data and 'data' can be NULL.
@@ -408,7 +409,7 @@ TEST(PickleTest, ZeroLength) {
PickleIterator iter(pickle);
const char* outdata;
int outdatalen;
- EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
+ EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen));
EXPECT_EQ(0, outdatalen);
// We can't assert that outdata is NULL.
}
@@ -421,7 +422,7 @@ TEST(PickleTest, ReadBytes) {
PickleIterator iter(pickle);
const char* outdata_char = NULL;
- EXPECT_TRUE(pickle.ReadBytes(&iter, &outdata_char, sizeof(data)));
+ EXPECT_TRUE(iter.ReadBytes(&outdata_char, sizeof(data)));
int outdata;
memcpy(&outdata, outdata_char, sizeof(outdata));
diff --git a/chromium/base/port.h b/chromium/base/port.h
index 0a04d55f0f6..56c4d4e109f 100644
--- a/chromium/base/port.h
+++ b/chromium/base/port.h
@@ -26,18 +26,6 @@
#define GG_INT64_C(x) GG_LONGLONG(x)
#define GG_UINT64_C(x) GG_ULONGLONG(x)
-// It's possible for functions that use a va_list, such as StringPrintf, to
-// invalidate the data in it upon use. The fix is to make a copy of the
-// structure before using it and use that copy instead. va_copy is provided
-// for this purpose. MSVC does not provide va_copy, so define an
-// implementation here. It is not guaranteed that assignment is a copy, so the
-// StringUtil.VariableArgsFunc unit test tests this capability.
-#if defined(COMPILER_GCC)
-#define GG_VA_COPY(a, b) (va_copy(a, b))
-#elif defined(COMPILER_MSVC)
-#define GG_VA_COPY(a, b) (a = b)
-#endif
-
// Define an OS-neutral wrapper for shared library entry points
#if defined(OS_WIN)
#define API_CALL __stdcall
diff --git a/chromium/base/posix/global_descriptors.cc b/chromium/base/posix/global_descriptors.cc
index bcca443acc1..6c187838ad6 100644
--- a/chromium/base/posix/global_descriptors.cc
+++ b/chromium/base/posix/global_descriptors.cc
@@ -11,6 +11,16 @@
namespace base {
+GlobalDescriptors::Descriptor::Descriptor(Key key, int fd)
+ : key(key), fd(fd), region(base::MemoryMappedFile::Region::kWholeFile) {
+}
+
+GlobalDescriptors::Descriptor::Descriptor(Key key,
+ int fd,
+ base::MemoryMappedFile::Region region)
+ : key(key), fd(fd), region(region) {
+}
+
// static
GlobalDescriptors* GlobalDescriptors::GetInstance() {
typedef Singleton<base::GlobalDescriptors,
@@ -30,23 +40,38 @@ int GlobalDescriptors::Get(Key key) const {
int GlobalDescriptors::MaybeGet(Key key) const {
for (Mapping::const_iterator
i = descriptors_.begin(); i != descriptors_.end(); ++i) {
- if (i->first == key)
- return i->second;
+ if (i->key == key)
+ return i->fd;
}
return -1;
}
void GlobalDescriptors::Set(Key key, int fd) {
- for (Mapping::iterator
- i = descriptors_.begin(); i != descriptors_.end(); ++i) {
- if (i->first == key) {
- i->second = fd;
+ Set(key, fd, base::MemoryMappedFile::Region::kWholeFile);
+}
+
+void GlobalDescriptors::Set(Key key,
+ int fd,
+ base::MemoryMappedFile::Region region) {
+ for (auto& i : descriptors_) {
+ if (i.key == key) {
+ i.fd = fd;
+ i.region = region;
return;
}
}
- descriptors_.push_back(std::make_pair(key, fd));
+ descriptors_.push_back(Descriptor(key, fd, region));
+}
+
+base::MemoryMappedFile::Region GlobalDescriptors::GetRegion(Key key) const {
+ for (const auto& i : descriptors_) {
+ if (i.key == key)
+ return i.region;
+ }
+ DLOG(FATAL) << "Unknown global descriptor: " << key;
+ return base::MemoryMappedFile::Region::kWholeFile;
}
void GlobalDescriptors::Reset(const Mapping& mapping) {
diff --git a/chromium/base/posix/global_descriptors.h b/chromium/base/posix/global_descriptors.h
index 3d7369c3174..c774634f59b 100644
--- a/chromium/base/posix/global_descriptors.h
+++ b/chromium/base/posix/global_descriptors.h
@@ -12,6 +12,7 @@
#include <stdint.h>
+#include "base/files/memory_mapped_file.h"
#include "base/memory/singleton.h"
namespace base {
@@ -36,8 +37,18 @@ namespace base {
class BASE_EXPORT GlobalDescriptors {
public:
typedef uint32_t Key;
- typedef std::pair<Key, int> KeyFDPair;
- typedef std::vector<KeyFDPair> Mapping;
+ struct Descriptor {
+ Descriptor(Key key, int fd);
+ Descriptor(Key key, int fd, base::MemoryMappedFile::Region region);
+
+ // Globally unique key.
+ Key key;
+ // Actual FD.
+ int fd;
+ // Optional region, defaults to kWholeFile.
+ base::MemoryMappedFile::Region region;
+ };
+ typedef std::vector<Descriptor> Mapping;
// Often we want a canonical descriptor for a given Key. In this case, we add
// the following constant to the key value:
@@ -53,12 +64,19 @@ class BASE_EXPORT GlobalDescriptors {
// 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.
+ // Get a descriptor given a key. Returns -1 on error.
int MaybeGet(Key key) const;
- // Set the descriptor for the given key.
+ // Get a region given a key. It is a fatal error if the key is not known.
+ base::MemoryMappedFile::Region GetRegion(Key key) const;
+
+ // Set the descriptor for the given |key|. This sets the region associated
+ // with |key| to kWholeFile.
void Set(Key key, int fd);
+ // Set the descriptor and |region| for the given |key|.
+ void Set(Key key, int fd, base::MemoryMappedFile::Region region);
+
void Reset(const Mapping& mapping);
private:
diff --git a/chromium/base/posix/unix_domain_socket_linux.cc b/chromium/base/posix/unix_domain_socket_linux.cc
index 203285b9626..16d8eaad241 100644
--- a/chromium/base/posix/unix_domain_socket_linux.cc
+++ b/chromium/base/posix/unix_domain_socket_linux.cc
@@ -136,8 +136,8 @@ ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
- DCHECK(payload_len % sizeof(int) == 0);
- DCHECK(wire_fds == NULL);
+ DCHECK_EQ(payload_len % sizeof(int), 0u);
+ DCHECK_EQ(wire_fds, static_cast<void*>(nullptr));
wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
wire_fds_len = payload_len / sizeof(int);
}
@@ -146,8 +146,8 @@ ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
// SCM_CREDENTIALS.
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS) {
- DCHECK(payload_len == sizeof(struct ucred));
- DCHECK(pid == -1);
+ DCHECK_EQ(payload_len, sizeof(struct ucred));
+ DCHECK_EQ(pid, -1);
pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid;
}
#endif
diff --git a/chromium/base/posix/unix_domain_socket_linux_unittest.cc b/chromium/base/posix/unix_domain_socket_linux_unittest.cc
index 60b2bb8a470..c05141cdcf1 100644
--- a/chromium/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/chromium/base/posix/unix_domain_socket_linux_unittest.cc
@@ -10,9 +10,11 @@
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
+#include "base/location.h"
#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/unix_domain_socket_linux.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,11 +34,10 @@ TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
// Have the thread send a synchronous message via the socket.
Pickle request;
- message_thread.message_loop()->PostTask(
+ message_thread.task_runner()->PostTask(
FROM_HERE,
- Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg),
- fds[1], static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL),
- request));
+ Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1],
+ static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
// Receive the message.
ScopedVector<base::ScopedFD> message_fds;
@@ -51,9 +52,8 @@ TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
// Check that the thread didn't get blocked.
WaitableEvent event(false, false);
- message_thread.message_loop()->PostTask(
- FROM_HERE,
- Bind(&WaitableEvent::Signal, Unretained(&event)));
+ message_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000)));
}
diff --git a/chromium/base/power_monitor/power_monitor.cc b/chromium/base/power_monitor/power_monitor.cc
index 14dc4b51783..98c9c68c1df 100644
--- a/chromium/base/power_monitor/power_monitor.cc
+++ b/chromium/base/power_monitor/power_monitor.cc
@@ -45,17 +45,18 @@ bool PowerMonitor::IsOnBatteryPower() {
void PowerMonitor::NotifyPowerStateChange(bool battery_in_use) {
DVLOG(1) << "PowerStateChange: " << (battery_in_use ? "On" : "Off")
<< " battery";
- observers_->Notify(&PowerObserver::OnPowerStateChange, battery_in_use);
+ observers_->Notify(FROM_HERE, &PowerObserver::OnPowerStateChange,
+ battery_in_use);
}
void PowerMonitor::NotifySuspend() {
DVLOG(1) << "Power Suspending";
- observers_->Notify(&PowerObserver::OnSuspend);
+ observers_->Notify(FROM_HERE, &PowerObserver::OnSuspend);
}
void PowerMonitor::NotifyResume() {
DVLOG(1) << "Power Resuming";
- observers_->Notify(&PowerObserver::OnResume);
+ observers_->Notify(FROM_HERE, &PowerObserver::OnResume);
}
} // namespace base
diff --git a/chromium/base/power_monitor/power_monitor_device_source_win.cc b/chromium/base/power_monitor/power_monitor_device_source_win.cc
index b8b16e1d344..0e199dcddbb 100644
--- a/chromium/base/power_monitor/power_monitor_device_source_win.cc
+++ b/chromium/base/power_monitor/power_monitor_device_source_win.cc
@@ -5,6 +5,7 @@
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/power_monitor/power_monitor_source.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/win/wrapped_window_proc.h"
namespace base {
@@ -98,6 +99,11 @@ LRESULT CALLBACK PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk(
UINT message,
WPARAM wparam,
LPARAM lparam) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "440919 PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk"));
+
switch (message) {
case WM_POWERBROADCAST:
ProcessWmPowerBroadcastMessage(wparam);
diff --git a/chromium/base/power_monitor/power_monitor_unittest.cc b/chromium/base/power_monitor/power_monitor_unittest.cc
index 5f7b531206f..2df82618f4c 100644
--- a/chromium/base/power_monitor/power_monitor_unittest.cc
+++ b/chromium/base/power_monitor/power_monitor_unittest.cc
@@ -15,7 +15,7 @@ class PowerMonitorTest : public testing::Test {
power_monitor_.reset(new PowerMonitor(
scoped_ptr<PowerMonitorSource>(power_monitor_source_)));
}
- virtual ~PowerMonitorTest() {};
+ ~PowerMonitorTest() override{};
PowerMonitorTestSource* source() { return power_monitor_source_; }
PowerMonitor* monitor() { return power_monitor_.get(); }
diff --git a/chromium/base/prefs/json_pref_store.cc b/chromium/base/prefs/json_pref_store.cc
index d4714037c01..da545b8634c 100644
--- a/chromium/base/prefs/json_pref_store.cc
+++ b/chromium/base/prefs/json_pref_store.cc
@@ -16,9 +16,11 @@
#include "base/metrics/histogram.h"
#include "base/prefs/pref_filter.h"
#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "base/time/default_clock.h"
#include "base/values.h"
// Result returned from internal read tasks.
@@ -56,16 +58,16 @@ PersistentPrefStore::PrefReadError HandleReadErrors(
DVLOG(1) << "Error while loading JSON file: " << error_msg
<< ", file: " << path.value();
switch (error_code) {
- case JSONFileValueSerializer::JSON_ACCESS_DENIED:
+ case JSONFileValueDeserializer::JSON_ACCESS_DENIED:
return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
break;
- case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
+ case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE:
return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
break;
- case JSONFileValueSerializer::JSON_FILE_LOCKED:
+ case JSONFileValueDeserializer::JSON_FILE_LOCKED:
return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
break;
- case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
+ case JSONFileValueDeserializer::JSON_NO_SUCH_FILE:
return PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
break;
default:
@@ -91,6 +93,22 @@ PersistentPrefStore::PrefReadError HandleReadErrors(
return PersistentPrefStore::PREF_READ_ERROR_NONE;
}
+// Records a sample for |size| in the Settings.JsonDataReadSizeKilobytes
+// histogram suffixed with the base name of the JSON file under |path|.
+void RecordJsonDataSizeHistogram(const base::FilePath& path, size_t size) {
+ std::string spaceless_basename;
+ base::ReplaceChars(path.BaseName().MaybeAsASCII(), " ", "_",
+ &spaceless_basename);
+
+ // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+ // macro adapted to allow for a dynamically suffixed histogram name.
+ // Note: The factory creates and owns the histogram.
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ "Settings.JsonDataReadSizeKilobytes." + spaceless_basename, 1, 10000, 50,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(static_cast<int>(size) / 1024);
+}
+
scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
const base::FilePath& path,
const base::FilePath& alternate_path) {
@@ -103,11 +121,15 @@ scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
std::string error_msg;
scoped_ptr<JsonPrefStore::ReadResult> read_result(
new JsonPrefStore::ReadResult);
- JSONFileValueSerializer serializer(path);
- read_result->value.reset(serializer.Deserialize(&error_code, &error_msg));
+ JSONFileValueDeserializer deserializer(path);
+ read_result->value.reset(deserializer.Deserialize(&error_code, &error_msg));
read_result->error =
HandleReadErrors(read_result->value.get(), path, error_code, error_msg);
read_result->no_dir = !base::PathExists(path.DirName());
+
+ if (read_result->error == PersistentPrefStore::PREF_READ_ERROR_NONE)
+ RecordJsonDataSizeHistogram(path, deserializer.get_last_read_size());
+
return read_result.Pass();
}
@@ -128,15 +150,10 @@ JsonPrefStore::JsonPrefStore(
const base::FilePath& filename,
const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
scoped_ptr<PrefFilter> pref_filter)
- : path_(filename),
- sequenced_task_runner_(sequenced_task_runner),
- prefs_(new base::DictionaryValue()),
- read_only_(false),
- writer_(filename, sequenced_task_runner),
- pref_filter_(pref_filter.Pass()),
- initialized_(false),
- filtering_in_progress_(false),
- read_error_(PREF_READ_ERROR_NONE) {
+ : JsonPrefStore(filename,
+ base::FilePath(),
+ sequenced_task_runner,
+ pref_filter.Pass()) {
}
JsonPrefStore::JsonPrefStore(
@@ -153,7 +170,10 @@ JsonPrefStore::JsonPrefStore(
pref_filter_(pref_filter.Pass()),
initialized_(false),
filtering_in_progress_(false),
- read_error_(PREF_READ_ERROR_NONE) {
+ pending_lossy_write_(false),
+ read_error_(PREF_READ_ERROR_NONE),
+ write_count_histogram_(writer_.commit_interval(), path_) {
+ DCHECK(!path_.empty());
}
bool JsonPrefStore::GetValue(const std::string& key,
@@ -200,7 +220,9 @@ bool JsonPrefStore::GetMutableValue(const std::string& key,
return prefs_->Get(key, result);
}
-void JsonPrefStore::SetValue(const std::string& key, base::Value* value) {
+void JsonPrefStore::SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) {
DCHECK(CalledOnValidThread());
DCHECK(value);
@@ -208,13 +230,14 @@ void JsonPrefStore::SetValue(const std::string& key, base::Value* value) {
base::Value* old_value = NULL;
prefs_->Get(key, &old_value);
if (!old_value || !value->Equals(old_value)) {
- prefs_->Set(key, new_value.release());
- ReportValueChanged(key);
+ prefs_->Set(key, new_value.Pass());
+ ReportValueChanged(key, flags);
}
}
void JsonPrefStore::SetValueSilently(const std::string& key,
- base::Value* value) {
+ base::Value* value,
+ uint32 flags) {
DCHECK(CalledOnValidThread());
DCHECK(value);
@@ -222,25 +245,23 @@ void JsonPrefStore::SetValueSilently(const std::string& key,
base::Value* old_value = NULL;
prefs_->Get(key, &old_value);
if (!old_value || !value->Equals(old_value)) {
- prefs_->Set(key, new_value.release());
- if (!read_only_)
- writer_.ScheduleWrite(this);
+ prefs_->Set(key, new_value.Pass());
+ ScheduleWrite(flags);
}
}
-void JsonPrefStore::RemoveValue(const std::string& key) {
+void JsonPrefStore::RemoveValue(const std::string& key, uint32 flags) {
DCHECK(CalledOnValidThread());
if (prefs_->RemovePath(key, NULL))
- ReportValueChanged(key);
+ ReportValueChanged(key, flags);
}
-void JsonPrefStore::RemoveValueSilently(const std::string& key) {
+void JsonPrefStore::RemoveValueSilently(const std::string& key, uint32 flags) {
DCHECK(CalledOnValidThread());
prefs_->RemovePath(key, NULL);
- if (!read_only_)
- writer_.ScheduleWrite(this);
+ ScheduleWrite(flags);
}
bool JsonPrefStore::ReadOnly() const {
@@ -258,13 +279,6 @@ PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
DCHECK(CalledOnValidThread());
- if (path_.empty()) {
- scoped_ptr<ReadResult> no_file_result;
- no_file_result->error = PREF_READ_ERROR_FILE_NOT_SPECIFIED;
- OnFileRead(no_file_result.Pass());
- return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
- }
-
OnFileRead(ReadPrefsFromDisk(path_, alternate_path_));
return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
: read_error_;
@@ -275,12 +289,6 @@ void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
initialized_ = false;
error_delegate_.reset(error_delegate);
- if (path_.empty()) {
- scoped_ptr<ReadResult> no_file_result;
- no_file_result->error = PREF_READ_ERROR_FILE_NOT_SPECIFIED;
- OnFileRead(no_file_result.Pass());
- return;
- }
// Weakly binds the read task so that it doesn't kick in during shutdown.
base::PostTaskAndReplyWithResult(
@@ -293,11 +301,16 @@ void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
void JsonPrefStore::CommitPendingWrite() {
DCHECK(CalledOnValidThread());
+ // Schedule a write for any lossy writes that are outstanding to ensure that
+ // they get flushed when this function is called.
+ if (pending_lossy_write_)
+ writer_.ScheduleWrite(this);
+
if (writer_.HasPendingWrite() && !read_only_)
writer_.DoScheduledWrite();
}
-void JsonPrefStore::ReportValueChanged(const std::string& key) {
+void JsonPrefStore::ReportValueChanged(const std::string& key, uint32 flags) {
DCHECK(CalledOnValidThread());
if (pref_filter_)
@@ -305,8 +318,7 @@ void JsonPrefStore::ReportValueChanged(const std::string& key) {
FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
- if (!read_only_)
- writer_.ScheduleWrite(this);
+ ScheduleWrite(flags);
}
void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
@@ -385,32 +397,19 @@ JsonPrefStore::~JsonPrefStore() {
bool JsonPrefStore::SerializeData(std::string* output) {
DCHECK(CalledOnValidThread());
+ pending_lossy_write_ = false;
+
+ write_count_histogram_.RecordWriteOccured();
+
if (pref_filter_)
pref_filter_->FilterSerializeData(prefs_.get());
JSONStringValueSerializer serializer(output);
- serializer.set_pretty_print(true);
- bool result = serializer.Serialize(*prefs_);
-
- if (result) {
- std::string spaceless_basename;
- base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
- &spaceless_basename);
-
- // The histogram below is an expansion of the UMA_HISTOGRAM_COUNTS_10000
- // macro adapted to allow for a dynamically suffixed histogram name.
- // Note: The factory creates and owns the histogram.
- base::HistogramBase* histogram =
- base::LinearHistogram::FactoryGet(
- "Settings.JsonDataSizeKilobytes." + spaceless_basename,
- 1,
- 10000,
- 50,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(static_cast<int>(output->size()) / 1024);
- }
-
- return result;
+ // Not pretty-printing prefs shrinks pref file size by ~30%. To obtain
+ // readable prefs for debugging purposes, you can dump your prefs into any
+ // command-line or online JSON pretty printing tool.
+ serializer.set_pretty_print(false);
+ return serializer.Serialize(*prefs_);
}
void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
@@ -431,8 +430,8 @@ void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
initialized_ = true;
- if (schedule_write && !read_only_)
- writer_.ScheduleWrite(this);
+ if (schedule_write)
+ ScheduleWrite(DEFAULT_PREF_WRITE_FLAGS);
if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
error_delegate_->OnError(read_error_);
@@ -443,3 +442,101 @@ void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
return;
}
+
+void JsonPrefStore::ScheduleWrite(uint32 flags) {
+ if (read_only_)
+ return;
+
+ if (flags & LOSSY_PREF_WRITE_FLAG)
+ pending_lossy_write_ = true;
+ else
+ writer_.ScheduleWrite(this);
+}
+
+// NOTE: This value should NOT be changed without renaming the histogram
+// otherwise it will create incompatible buckets.
+const int32_t
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins = 5;
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+ const base::TimeDelta& commit_interval,
+ const base::FilePath& path)
+ : WriteCountHistogram(commit_interval,
+ path,
+ scoped_ptr<base::Clock>(new base::DefaultClock)) {
+}
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+ const base::TimeDelta& commit_interval,
+ const base::FilePath& path,
+ scoped_ptr<base::Clock> clock)
+ : commit_interval_(commit_interval),
+ path_(path),
+ clock_(clock.release()),
+ report_interval_(
+ base::TimeDelta::FromMinutes(kHistogramWriteReportIntervalMins)),
+ last_report_time_(clock_->Now()),
+ writes_since_last_report_(0) {
+}
+
+JsonPrefStore::WriteCountHistogram::~WriteCountHistogram() {
+ ReportOutstandingWrites();
+}
+
+void JsonPrefStore::WriteCountHistogram::RecordWriteOccured() {
+ ReportOutstandingWrites();
+
+ ++writes_since_last_report_;
+}
+
+void JsonPrefStore::WriteCountHistogram::ReportOutstandingWrites() {
+ base::Time current_time = clock_->Now();
+ base::TimeDelta time_since_last_report = current_time - last_report_time_;
+
+ if (time_since_last_report <= report_interval_)
+ return;
+
+ // If the time since the last report exceeds the report interval, report all
+ // the writes since the last report. They must have all occurred in the same
+ // report interval.
+ base::HistogramBase* histogram = GetHistogram();
+ histogram->Add(writes_since_last_report_);
+
+ // There may be several report intervals that elapsed that don't have any
+ // writes in them. Report these too.
+ int64 total_num_intervals_elapsed =
+ (time_since_last_report / report_interval_);
+ for (int64 i = 0; i < total_num_intervals_elapsed - 1; ++i)
+ histogram->Add(0);
+
+ writes_since_last_report_ = 0;
+ last_report_time_ += total_num_intervals_elapsed * report_interval_;
+}
+
+base::HistogramBase* JsonPrefStore::WriteCountHistogram::GetHistogram() {
+ std::string spaceless_basename;
+ base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
+ &spaceless_basename);
+ std::string histogram_name =
+ "Settings.JsonDataWriteCount." + spaceless_basename;
+
+ // The min value for a histogram is 1. The max value is the maximum number of
+ // writes that can occur in the window being recorded. The number of buckets
+ // used is the max value (plus the underflow/overflow buckets).
+ int32_t min_value = 1;
+ int32_t max_value = report_interval_ / commit_interval_;
+ int32_t num_buckets = max_value + 1;
+
+ // NOTE: These values should NOT be changed without renaming the histogram
+ // otherwise it will create incompatible buckets.
+ DCHECK_EQ(30, max_value);
+ DCHECK_EQ(31, num_buckets);
+
+ // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+ // macro adapted to allow for a dynamically suffixed histogram name.
+ // Note: The factory creates and owns the histogram.
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ histogram_name, min_value, max_value, num_buckets,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ return histogram;
+}
diff --git a/chromium/base/prefs/json_pref_store.h b/chromium/base/prefs/json_pref_store.h
index 16e431b3c92..ef260eb47da 100644
--- a/chromium/base/prefs/json_pref_store.h
+++ b/chromium/base/prefs/json_pref_store.h
@@ -13,9 +13,10 @@
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/important_file_writer.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/observer_list.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/persistent_pref_store.h"
@@ -24,11 +25,18 @@
class PrefFilter;
namespace base {
+class Clock;
class DictionaryValue;
class FilePath;
+class HistogramBase;
+class JsonPrefStoreLossyWriteTest;
class SequencedTaskRunner;
class SequencedWorkerPool;
class Value;
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps);
}
// A writable PrefStore implementation that is used for user preferences.
@@ -75,9 +83,13 @@ class BASE_PREFS_EXPORT JsonPrefStore
// PersistentPrefStore overrides:
bool GetMutableValue(const std::string& key, base::Value** result) override;
- void SetValue(const std::string& key, base::Value* value) override;
- void SetValueSilently(const std::string& key, base::Value* value) override;
- void RemoveValue(const std::string& key) override;
+ void SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void SetValueSilently(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void RemoveValue(const std::string& key, uint32 flags) override;
bool ReadOnly() const override;
PrefReadError GetReadError() const override;
// Note this method may be asynchronous if this instance has a |pref_filter_|
@@ -86,11 +98,11 @@ class BASE_PREFS_EXPORT JsonPrefStore
PrefReadError ReadPrefs() override;
void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
void CommitPendingWrite() override;
- void ReportValueChanged(const std::string& key) override;
+ void ReportValueChanged(const std::string& key, uint32 flags) override;
// Just like RemoveValue(), but doesn't notify observers. Used when doing some
// cleanup that shouldn't otherwise alert observers.
- void RemoveValueSilently(const std::string& key);
+ void RemoveValueSilently(const std::string& key, uint32 flags);
// Registers |on_next_successful_write| to be called once, on the next
// successful write event of |writer_|.
@@ -98,6 +110,64 @@ class BASE_PREFS_EXPORT JsonPrefStore
const base::Closure& on_next_successful_write);
private:
+ // Represents a histogram for recording the number of writes to the pref file
+ // that occur every kHistogramWriteReportIntervalInMins minutes.
+ class BASE_PREFS_EXPORT WriteCountHistogram {
+ public:
+ static const int32_t kHistogramWriteReportIntervalMins;
+
+ WriteCountHistogram(const base::TimeDelta& commit_interval,
+ const base::FilePath& path);
+ // Constructor for testing. |clock| is a test Clock that is used to retrieve
+ // the time.
+ WriteCountHistogram(const base::TimeDelta& commit_interval,
+ const base::FilePath& path,
+ scoped_ptr<base::Clock> clock);
+ ~WriteCountHistogram();
+
+ // Record that a write has occured.
+ void RecordWriteOccured();
+
+ // Reports writes (that have not yet been reported) in all of the recorded
+ // intervals that have elapsed up until current time.
+ void ReportOutstandingWrites();
+
+ base::HistogramBase* GetHistogram();
+
+ private:
+ // The minimum interval at which writes can occur.
+ const base::TimeDelta commit_interval_;
+
+ // The path to the file.
+ const base::FilePath path_;
+
+ // Clock which is used to retrieve the current time.
+ scoped_ptr<base::Clock> clock_;
+
+ // The interval at which to report write counts.
+ const base::TimeDelta report_interval_;
+
+ // The time at which the last histogram value was reported for the number
+ // of write counts.
+ base::Time last_report_time_;
+
+ // The number of writes that have occured since the last write count was
+ // reported.
+ uint32_t writes_since_last_report_;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteCountHistogram);
+ };
+
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestBasic);
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestSinglePeriod);
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestMultiplePeriods);
+ FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+ WriteCountHistogramTestPeriodWithGaps);
+ friend class base::JsonPrefStoreLossyWriteTest;
+
~JsonPrefStore() override;
// This method is called after the JSON file has been read. It then hands
@@ -122,6 +192,10 @@ class BASE_PREFS_EXPORT JsonPrefStore
scoped_ptr<base::DictionaryValue> prefs,
bool schedule_write);
+ // Schedule a write with the file writer as long as |flags| doesn't contain
+ // WriteablePrefStore::LOSSY_PREF_WRITE_FLAG.
+ void ScheduleWrite(uint32 flags);
+
const base::FilePath path_;
const base::FilePath alternate_path_;
const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
@@ -140,10 +214,13 @@ class BASE_PREFS_EXPORT JsonPrefStore
bool initialized_;
bool filtering_in_progress_;
+ bool pending_lossy_write_;
PrefReadError read_error_;
std::set<std::string> keys_need_empty_value_;
+ WriteCountHistogram write_count_histogram_;
+
DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
};
diff --git a/chromium/base/prefs/json_pref_store_unittest.cc b/chromium/base/prefs/json_pref_store_unittest.cc
index dc4043e32be..67a8adbb4d4 100644
--- a/chromium/base/prefs/json_pref_store_unittest.cc
+++ b/chromium/base/prefs/json_pref_store_unittest.cc
@@ -7,15 +7,20 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/path_service.h"
#include "base/prefs/pref_filter.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "base/values.h"
@@ -27,6 +32,12 @@ namespace {
const char kHomePage[] = "homepage";
+// Set the time on the given SimpleTestClock to the given time in minutes.
+void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
+ const int32_t kBaseTimeMins = 100;
+ clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
+}
+
// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
// to the |prefs| until explicitly asked to release them.
class InterceptingPrefFilter : public PrefFilter {
@@ -86,7 +97,7 @@ class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
class JsonPrefStoreTest : public testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_));
@@ -94,11 +105,10 @@ class JsonPrefStoreTest : public testing::Test {
ASSERT_TRUE(PathExists(data_dir_));
}
- virtual void TearDown() override {
+ void TearDown() override {
// Make sure all pending tasks have been processed (e.g., deleting the
// JsonPrefStore may post write tasks).
- message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
- message_loop_.Run();
+ RunLoop().RunUntilIdle();
}
// The path to temporary directory used to contain the test operations.
@@ -107,16 +117,18 @@ class JsonPrefStoreTest : public testing::Test {
base::FilePath data_dir_;
// A message loop that we can use as the file thread message loop.
MessageLoop message_loop_;
+
+ private:
+ // Ensure histograms are reset for each test.
+ StatisticsRecorder statistics_recorder_;
};
// Test fallback behavior for a nonexistent file.
TEST_F(JsonPrefStoreTest, NonExistentFile) {
- base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+ base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
@@ -124,16 +136,14 @@ TEST_F(JsonPrefStoreTest, NonExistentFile) {
// Test fallback behavior for a nonexistent file and alternate file.
TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
- base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+ base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
base::FilePath bogus_alternate_input_file =
- data_dir_.AppendASCII("read_alternate.txt");
+ temp_dir_.path().AppendASCII("read_alternate.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
ASSERT_FALSE(PathExists(bogus_alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file,
- bogus_alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
@@ -144,10 +154,8 @@ TEST_F(JsonPrefStoreTest, InvalidFile) {
base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
- scoped_refptr<JsonPrefStore> pref_store =
- new JsonPrefStore(invalid_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+ invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
@@ -184,7 +192,8 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
- pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()));
+ pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
EXPECT_TRUE(actual->GetAsString(&path));
EXPECT_EQ(some_path.value(), path);
@@ -195,7 +204,8 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
EXPECT_TRUE(actual->GetAsBoolean(&boolean));
EXPECT_TRUE(boolean);
- pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false));
+ pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
EXPECT_TRUE(actual->GetAsBoolean(&boolean));
EXPECT_FALSE(boolean);
@@ -204,13 +214,15 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
int integer = 0;
EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(20, integer);
- pref_store->SetValue(kMaxTabs, new FundamentalValue(10));
+ pref_store->SetValue(kMaxTabs, new FundamentalValue(10),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(10, integer);
pref_store->SetValue(kLongIntPref,
- new StringValue(base::Int64ToString(214748364842LL)));
+ new StringValue(base::Int64ToString(214748364842LL)),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
EXPECT_TRUE(actual->GetAsString(&string_value));
int64 value;
@@ -233,9 +245,7 @@ TEST_F(JsonPrefStoreTest, Basic) {
base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
ASSERT_TRUE(PathExists(input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
EXPECT_FALSE(pref_store->ReadOnly());
EXPECT_TRUE(pref_store->IsInitializationComplete());
@@ -262,9 +272,7 @@ TEST_F(JsonPrefStoreTest, BasicAsync) {
base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
ASSERT_TRUE(PathExists(input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
{
MockPrefStoreObserver mock_observer;
@@ -301,23 +309,21 @@ TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- pref_file,
- message_loop_.message_loop_proxy(),
- scoped_ptr<PrefFilter>());
+ pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
// Set some keys with empty values.
- pref_store->SetValue("list", new base::ListValue);
- pref_store->SetValue("dict", new base::DictionaryValue);
+ pref_store->SetValue("list", new base::ListValue,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ pref_store->SetValue("dict", new base::DictionaryValue,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
// Write to file.
pref_store->CommitPendingWrite();
- MessageLoop::current()->RunUntilIdle();
+ RunLoop().RunUntilIdle();
// Reload.
- pref_store = new JsonPrefStore(
- pref_file,
- message_loop_.message_loop_proxy(),
- scoped_ptr<PrefFilter>());
+ pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
+ scoped_ptr<PrefFilter>());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
ASSERT_FALSE(pref_store->ReadOnly());
@@ -335,15 +341,15 @@ TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- pref_file,
- message_loop_.message_loop_proxy(),
- scoped_ptr<PrefFilter>());
+ pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
base::DictionaryValue* dict = new base::DictionaryValue;
dict->SetString("key", "value");
- pref_store->SetValue("dict", dict);
+ pref_store->SetValue("dict", dict,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- pref_store->RemoveValue("dict.key");
+ pref_store->RemoveValue("dict.key",
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
const base::Value* retrieved_dict = NULL;
bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
@@ -352,12 +358,10 @@ TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
// Tests asynchronous reading of the file when there is no file.
TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
- base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+ base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- bogus_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
MockPrefStoreObserver mock_observer;
pref_store->AddObserver(&mock_observer);
@@ -385,10 +389,8 @@ TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
new InterceptingPrefFilter());
InterceptingPrefFilter* raw_intercepting_pref_filter_ =
intercepting_pref_filter.get();
- scoped_refptr<JsonPrefStore> pref_store =
- new JsonPrefStore(input_file,
- message_loop_.message_loop_proxy().get(),
- intercepting_pref_filter.Pass());
+ scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+ input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
pref_store->ReadPrefs());
@@ -432,10 +434,8 @@ TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
new InterceptingPrefFilter());
InterceptingPrefFilter* raw_intercepting_pref_filter_ =
intercepting_pref_filter.get();
- scoped_refptr<JsonPrefStore> pref_store =
- new JsonPrefStore(input_file,
- message_loop_.message_loop_proxy().get(),
- intercepting_pref_filter.Pass());
+ scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+ input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
MockPrefStoreObserver mock_observer;
pref_store->AddObserver(&mock_observer);
@@ -498,11 +498,9 @@ TEST_F(JsonPrefStoreTest, AlternateFile) {
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
@@ -544,11 +542,9 @@ TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_TRUE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_TRUE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
@@ -586,11 +582,9 @@ TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_TRUE(PathExists(input_file));
ASSERT_FALSE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_TRUE(PathExists(input_file));
ASSERT_FALSE(PathExists(alternate_input_file));
@@ -628,11 +622,9 @@ TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
temp_dir_.path().AppendASCII("alternate.json");
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
- scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
- input_file,
- alternate_input_file,
- message_loop_.message_loop_proxy().get(),
- scoped_ptr<PrefFilter>());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, alternate_input_file,
+ message_loop_.task_runner(), scoped_ptr<PrefFilter>());
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
@@ -671,4 +663,269 @@ TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
}
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ histogram.RecordWriteOccured();
+
+ SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(1, samples->GetCount(1));
+ ASSERT_EQ(1, samples->TotalCount());
+
+ ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
+ histogram.GetHistogram()->histogram_name());
+ ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // Nothing should be recorded until the report period has elapsed.
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(0, samples->TotalCount());
+
+ SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // Now the report period has elapsed.
+ samples = histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(1, samples->GetCount(3));
+ ASSERT_EQ(1, samples->TotalCount());
+
+ // The last write won't be recorded because the second count period hasn't
+ // fully elapsed.
+ SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+
+ samples = histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(1, samples->GetCount(3));
+ ASSERT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // The last write won't be recorded because the second count period hasn't
+ // fully elapsed
+ SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(2, samples->GetCount(3));
+ ASSERT_EQ(1, samples->GetCount(2));
+ ASSERT_EQ(3, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
+ SimpleTestClock* test_clock = new SimpleTestClock;
+ SetCurrentTimeInMinutes(0, test_clock);
+ JsonPrefStore::WriteCountHistogram histogram(
+ base::TimeDelta::FromSeconds(10),
+ base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+ scoped_ptr<base::Clock>(test_clock));
+ int32 report_interval =
+ JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+ // 1 write in the first period.
+ histogram.RecordWriteOccured();
+
+ // No writes in the second and third periods.
+
+ // 2 writes in the fourth period.
+ SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ // No writes in the fifth period.
+
+ // 3 writes in the sixth period.
+ SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+ SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
+ histogram.RecordWriteOccured();
+
+ SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
+ histogram.ReportOutstandingWrites();
+ scoped_ptr<HistogramSamples> samples =
+ histogram.GetHistogram()->SnapshotSamples();
+ ASSERT_EQ(3, samples->GetCount(0));
+ ASSERT_EQ(1, samples->GetCount(1));
+ ASSERT_EQ(1, samples->GetCount(2));
+ ASSERT_EQ(1, samples->GetCount(3));
+ ASSERT_EQ(6, samples->TotalCount());
+}
+
+class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
+ protected:
+ void SetUp() override {
+ JsonPrefStoreTest::SetUp();
+ test_file_ = temp_dir_.path().AppendASCII("test.json");
+ }
+
+ // Creates a JsonPrefStore with the given |file_writer|.
+ scoped_refptr<JsonPrefStore> CreatePrefStore() {
+ return new JsonPrefStore(test_file_, message_loop_.task_runner(),
+ scoped_ptr<PrefFilter>());
+ }
+
+ // Return the ImportantFileWriter for a given JsonPrefStore.
+ ImportantFileWriter* GetImportantFileWriter(
+ scoped_refptr<JsonPrefStore> pref_store) {
+ return &(pref_store->writer_);
+ }
+
+ // Get the contents of kTestFile. Pumps the message loop before returning the
+ // result.
+ std::string GetTestFileContents() {
+ RunLoop().RunUntilIdle();
+ std::string file_contents;
+ ReadFileToString(test_file_, &file_contents);
+ return file_contents;
+ }
+
+ private:
+ base::FilePath test_file_;
+};
+
+TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
+ scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+ // Set a normal pref and check that it gets scheduled to be written.
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ pref_store->SetValue("normal", new base::StringValue("normal"),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ ASSERT_TRUE(file_writer->HasPendingWrite());
+ file_writer->DoScheduledWrite();
+ ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+
+ // Set a lossy pref and check that it is not scheduled to be written.
+ // SetValue/RemoveValue.
+ pref_store->SetValue("lossy", new base::StringValue("lossy"),
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+
+ // SetValueSilently/RemoveValueSilently.
+ pref_store->SetValueSilently("lossy", new base::StringValue("lossy"),
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ pref_store->RemoveValueSilently("lossy",
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+
+ // ReportValueChanged.
+ pref_store->SetValue("lossy", new base::StringValue("lossy"),
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ pref_store->ReportValueChanged("lossy",
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+
+ // Call CommitPendingWrite and check that the lossy pref and the normal pref
+ // are there with the last values set above.
+ pref_store->CommitPendingWrite();
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
+ GetTestFileContents());
+}
+
+TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
+ scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+ // Set a lossy pref and check that it is not scheduled to be written.
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ pref_store->SetValue("lossy", new base::StringValue("lossy"),
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+
+ // Set a normal pref and check that it is scheduled to be written.
+ pref_store->SetValue("normal", new base::StringValue("normal"),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ ASSERT_TRUE(file_writer->HasPendingWrite());
+
+ // Call DoScheduledWrite and check both prefs get written.
+ file_writer->DoScheduledWrite();
+ ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
+ GetTestFileContents());
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+}
+
+TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
+ scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+ // Set a normal pref and check that it is scheduled to be written.
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+ pref_store->SetValue("normal", new base::StringValue("normal"),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ ASSERT_TRUE(file_writer->HasPendingWrite());
+
+ // Set a lossy pref and check that the write is still scheduled.
+ pref_store->SetValue("lossy", new base::StringValue("lossy"),
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+ ASSERT_TRUE(file_writer->HasPendingWrite());
+
+ // Call DoScheduledWrite and check both prefs get written.
+ file_writer->DoScheduledWrite();
+ ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
+ GetTestFileContents());
+ ASSERT_FALSE(file_writer->HasPendingWrite());
+}
+
} // namespace base
diff --git a/chromium/base/prefs/mock_pref_change_callback.h b/chromium/base/prefs/mock_pref_change_callback.h
index 422754afd6e..3030fab17c2 100644
--- a/chromium/base/prefs/mock_pref_change_callback.h
+++ b/chromium/base/prefs/mock_pref_change_callback.h
@@ -19,8 +19,7 @@ using testing::Truly;
// |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher
// checks that the value is not set.
MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") {
- const PrefService::Preference* pref =
- prefs->FindPreference(pref_name.c_str());
+ const PrefService::Preference* pref = prefs->FindPreference(pref_name);
if (!pref)
return false;
diff --git a/chromium/base/prefs/overlay_user_pref_store.cc b/chromium/base/prefs/overlay_user_pref_store.cc
index a708bb68363..e93dffd961a 100644
--- a/chromium/base/prefs/overlay_user_pref_store.cc
+++ b/chromium/base/prefs/overlay_user_pref_store.cc
@@ -63,34 +63,36 @@ bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
}
void OverlayUserPrefStore::SetValue(const std::string& key,
- base::Value* value) {
+ base::Value* value,
+ uint32 flags) {
if (!ShallBeStoredInOverlay(key)) {
- underlay_->SetValue(GetUnderlayKey(key), value);
+ underlay_->SetValue(GetUnderlayKey(key), value, flags);
return;
}
if (overlay_.SetValue(key, value))
- ReportValueChanged(key);
+ ReportValueChanged(key, flags);
}
void OverlayUserPrefStore::SetValueSilently(const std::string& key,
- base::Value* value) {
+ base::Value* value,
+ uint32 flags) {
if (!ShallBeStoredInOverlay(key)) {
- underlay_->SetValueSilently(GetUnderlayKey(key), value);
+ underlay_->SetValueSilently(GetUnderlayKey(key), value, flags);
return;
}
overlay_.SetValue(key, value);
}
-void OverlayUserPrefStore::RemoveValue(const std::string& key) {
+void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32 flags) {
if (!ShallBeStoredInOverlay(key)) {
- underlay_->RemoveValue(GetUnderlayKey(key));
+ underlay_->RemoveValue(GetUnderlayKey(key), flags);
return;
}
if (overlay_.RemoveValue(key))
- ReportValueChanged(key);
+ ReportValueChanged(key, flags);
}
bool OverlayUserPrefStore::ReadOnly() const {
@@ -119,13 +121,14 @@ void OverlayUserPrefStore::CommitPendingWrite() {
// We do not write our content intentionally.
}
-void OverlayUserPrefStore::ReportValueChanged(const std::string& key) {
+void OverlayUserPrefStore::ReportValueChanged(const std::string& key,
+ uint32 flags) {
FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
}
void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
if (!overlay_.GetValue(GetOverlayKey(key), NULL))
- ReportValueChanged(GetOverlayKey(key));
+ ReportValueChanged(GetOverlayKey(key), DEFAULT_PREF_WRITE_FLAGS);
}
void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
diff --git a/chromium/base/prefs/overlay_user_pref_store.h b/chromium/base/prefs/overlay_user_pref_store.h
index 5194a7bebd0..04c309d8a10 100644
--- a/chromium/base/prefs/overlay_user_pref_store.h
+++ b/chromium/base/prefs/overlay_user_pref_store.h
@@ -39,15 +39,19 @@ class BASE_PREFS_EXPORT OverlayUserPrefStore : public PersistentPrefStore,
// Methods of PersistentPrefStore.
bool GetMutableValue(const std::string& key, base::Value** result) override;
- void SetValue(const std::string& key, base::Value* value) override;
- void SetValueSilently(const std::string& key, base::Value* value) override;
- void RemoveValue(const std::string& key) override;
+ void SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void SetValueSilently(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void RemoveValue(const std::string& key, uint32 flags) override;
bool ReadOnly() const override;
PrefReadError GetReadError() const override;
PrefReadError ReadPrefs() override;
void ReadPrefsAsync(ReadErrorDelegate* delegate) override;
void CommitPendingWrite() override;
- void ReportValueChanged(const std::string& key) override;
+ void ReportValueChanged(const std::string& key, uint32 flags) override;
// Methods of PrefStore::Observer.
void OnPrefValueChanged(const std::string& key) override;
diff --git a/chromium/base/prefs/overlay_user_pref_store_unittest.cc b/chromium/base/prefs/overlay_user_pref_store_unittest.cc
index 66a7b3bd1a8..06b4ec989a6 100644
--- a/chromium/base/prefs/overlay_user_pref_store_unittest.cc
+++ b/chromium/base/prefs/overlay_user_pref_store_unittest.cc
@@ -37,7 +37,7 @@ class OverlayUserPrefStoreTest : public testing::Test {
overlay_->RegisterOverlayPref(mapped_overlay_key, mapped_underlay_key);
}
- virtual ~OverlayUserPrefStoreTest() {}
+ ~OverlayUserPrefStoreTest() override {}
scoped_refptr<TestingPrefStore> underlay_;
scoped_refptr<OverlayUserPrefStore> overlay_;
@@ -48,38 +48,47 @@ TEST_F(OverlayUserPrefStoreTest, Observer) {
overlay_->AddObserver(&obs);
// Check that underlay first value is reported.
- underlay_->SetValue(overlay_key, new FundamentalValue(42));
+ underlay_->SetValue(overlay_key, new FundamentalValue(42),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that underlay overwriting is reported.
- underlay_->SetValue(overlay_key, new FundamentalValue(43));
+ underlay_->SetValue(overlay_key, new FundamentalValue(43),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that overwriting change in overlay is reported.
- overlay_->SetValue(overlay_key, new FundamentalValue(44));
+ overlay_->SetValue(overlay_key, new FundamentalValue(44),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that hidden underlay change is not reported.
- underlay_->SetValue(overlay_key, new FundamentalValue(45));
+ underlay_->SetValue(overlay_key, new FundamentalValue(45),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
// Check that overlay remove is reported.
- overlay_->RemoveValue(overlay_key);
+ overlay_->RemoveValue(overlay_key,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that underlay remove is reported.
- underlay_->RemoveValue(overlay_key);
+ underlay_->RemoveValue(overlay_key,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check respecting of silence.
- overlay_->SetValueSilently(overlay_key, new FundamentalValue(46));
+ overlay_->SetValueSilently(overlay_key, new FundamentalValue(46),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
overlay_->RemoveObserver(&obs);
// Check successful unsubscription.
- underlay_->SetValue(overlay_key, new FundamentalValue(47));
- overlay_->SetValue(overlay_key, new FundamentalValue(48));
+ underlay_->SetValue(overlay_key, new FundamentalValue(47),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ overlay_->SetValue(overlay_key, new FundamentalValue(48),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
}
@@ -88,7 +97,8 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
- underlay_->SetValue(overlay_key, new FundamentalValue(42));
+ underlay_->SetValue(overlay_key, new FundamentalValue(42),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
// Value shines through:
EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
@@ -97,7 +107,8 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
- overlay_->SetValue(overlay_key, new FundamentalValue(43));
+ overlay_->SetValue(overlay_key, new FundamentalValue(43),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
@@ -105,7 +116,8 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
- overlay_->RemoveValue(overlay_key);
+ overlay_->RemoveValue(overlay_key,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
// Value shines through:
EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
@@ -117,7 +129,8 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
// Check that GetMutableValue does not return the dictionary of the underlay.
TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
- underlay_->SetValue(overlay_key, new DictionaryValue);
+ underlay_->SetValue(overlay_key, new DictionaryValue,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
Value* modify = NULL;
EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modify));
@@ -146,11 +159,13 @@ TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
const Value* value = NULL;
// Check that underlay first value is reported.
- underlay_->SetValue(regular_key, new FundamentalValue(42));
+ underlay_->SetValue(regular_key, new FundamentalValue(42),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(regular_key);
// Check that underlay overwriting is reported.
- underlay_->SetValue(regular_key, new FundamentalValue(43));
+ underlay_->SetValue(regular_key, new FundamentalValue(43),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(regular_key);
// Check that we get this value from the overlay
@@ -158,7 +173,8 @@ TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
// Check that overwriting change in overlay is reported.
- overlay_->SetValue(regular_key, new FundamentalValue(44));
+ overlay_->SetValue(regular_key, new FundamentalValue(44),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(regular_key);
// Check that we get this value from the overlay and the underlay.
@@ -168,7 +184,8 @@ TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
// Check that overlay remove is reported.
- overlay_->RemoveValue(regular_key);
+ overlay_->RemoveValue(regular_key,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(regular_key);
// Check that value was removed from overlay and underlay
@@ -176,14 +193,17 @@ TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
EXPECT_FALSE(underlay_->GetValue(regular_key, &value));
// Check respecting of silence.
- overlay_->SetValueSilently(regular_key, new FundamentalValue(46));
+ overlay_->SetValueSilently(regular_key, new FundamentalValue(46),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
overlay_->RemoveObserver(&obs);
// Check successful unsubscription.
- underlay_->SetValue(regular_key, new FundamentalValue(47));
- overlay_->SetValue(regular_key, new FundamentalValue(48));
+ underlay_->SetValue(regular_key, new FundamentalValue(47),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ overlay_->SetValue(regular_key, new FundamentalValue(48),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
}
@@ -196,11 +216,13 @@ TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
// Check that if there is no override in the overlay, changing underlay value
// is reported as changing an overlay value.
- underlay_->SetValue(mapped_underlay_key, new FundamentalValue(42));
+ underlay_->SetValue(mapped_underlay_key, new FundamentalValue(42),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(mapped_overlay_key);
// Check that underlay overwriting is reported.
- underlay_->SetValue(mapped_underlay_key, new FundamentalValue(43));
+ underlay_->SetValue(mapped_underlay_key, new FundamentalValue(43),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(mapped_overlay_key);
// Check that we get this value from the overlay with both keys
@@ -211,7 +233,8 @@ TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
// Check that overwriting change in overlay is reported.
- overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44));
+ overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(mapped_overlay_key);
// Check that we get an overriden value from overlay, while reading the
@@ -224,15 +247,18 @@ TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
// Check that hidden underlay change is not reported.
- underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45));
+ underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
// Check that overlay remove is reported.
- overlay_->RemoveValue(mapped_overlay_key);
+ overlay_->RemoveValue(mapped_overlay_key,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(mapped_overlay_key);
// Check that underlay remove is reported.
- underlay_->RemoveValue(mapped_underlay_key);
+ underlay_->RemoveValue(mapped_underlay_key,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(mapped_overlay_key);
// Check that value was removed.
@@ -240,14 +266,17 @@ TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value));
// Check respecting of silence.
- overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46));
+ overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
overlay_->RemoveObserver(&obs);
// Check successful unsubscription.
- underlay_->SetValue(mapped_underlay_key, new FundamentalValue(47));
- overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48));
+ underlay_->SetValue(mapped_underlay_key, new FundamentalValue(47),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
}
diff --git a/chromium/base/prefs/pref_change_registrar.cc b/chromium/base/prefs/pref_change_registrar.cc
index 28ac3740343..13193484ff4 100644
--- a/chromium/base/prefs/pref_change_registrar.cc
+++ b/chromium/base/prefs/pref_change_registrar.cc
@@ -23,12 +23,12 @@ void PrefChangeRegistrar::Init(PrefService* service) {
service_ = service;
}
-void PrefChangeRegistrar::Add(const char* path,
+void PrefChangeRegistrar::Add(const std::string& path,
const base::Closure& obs) {
Add(path, base::Bind(&PrefChangeRegistrar::InvokeUnnamedCallback, obs));
}
-void PrefChangeRegistrar::Add(const char* path,
+void PrefChangeRegistrar::Add(const std::string& path,
const NamedChangeCallback& obs) {
if (!service_) {
NOTREACHED();
@@ -40,7 +40,7 @@ void PrefChangeRegistrar::Add(const char* path,
observers_[path] = obs;
}
-void PrefChangeRegistrar::Remove(const char* path) {
+void PrefChangeRegistrar::Remove(const std::string& path) {
DCHECK(IsObserved(path));
observers_.erase(path);
@@ -50,7 +50,7 @@ void PrefChangeRegistrar::Remove(const char* path) {
void PrefChangeRegistrar::RemoveAll() {
for (ObserverMap::const_iterator it = observers_.begin();
it != observers_.end(); ++it) {
- service_->RemovePrefObserver(it->first.c_str(), this);
+ service_->RemovePrefObserver(it->first, this);
}
observers_.clear();
@@ -67,8 +67,7 @@ bool PrefChangeRegistrar::IsObserved(const std::string& pref) {
bool PrefChangeRegistrar::IsManaged() {
for (ObserverMap::const_iterator it = observers_.begin();
it != observers_.end(); ++it) {
- const PrefService::Preference* pref =
- service_->FindPreference(it->first.c_str());
+ const PrefService::Preference* pref = service_->FindPreference(it->first);
if (pref && pref->IsManaged())
return true;
}
diff --git a/chromium/base/prefs/pref_change_registrar.h b/chromium/base/prefs/pref_change_registrar.h
index 70c22fe3f43..acf0a684962 100644
--- a/chromium/base/prefs/pref_change_registrar.h
+++ b/chromium/base/prefs/pref_change_registrar.h
@@ -40,11 +40,11 @@ class BASE_PREFS_EXPORT PrefChangeRegistrar : public PrefObserver {
// the preference that is changing as its parameter.
//
// Only one observer may be registered per path.
- void Add(const char* path, const base::Closure& obs);
- void Add(const char* path, const NamedChangeCallback& obs);
+ void Add(const std::string& path, const base::Closure& obs);
+ void Add(const std::string& path, const NamedChangeCallback& obs);
// Removes the pref observer registered for |path|.
- void Remove(const char* path);
+ void Remove(const std::string& path);
// Removes all observers that have been previously added with a call to Add.
void RemoveAll();
diff --git a/chromium/base/prefs/pref_change_registrar_unittest.cc b/chromium/base/prefs/pref_change_registrar_unittest.cc
index e9255a0ec63..da425cfad28 100644
--- a/chromium/base/prefs/pref_change_registrar_unittest.cc
+++ b/chromium/base/prefs/pref_change_registrar_unittest.cc
@@ -27,10 +27,8 @@ class MockPrefService : public TestingPrefServiceSimple {
MockPrefService() {}
virtual ~MockPrefService() {}
- MOCK_METHOD2(AddPrefObserver,
- void(const char*, PrefObserver*));
- MOCK_METHOD2(RemovePrefObserver,
- void(const char*, PrefObserver*));
+ MOCK_METHOD2(AddPrefObserver, void(const std::string&, PrefObserver*));
+ MOCK_METHOD2(RemovePrefObserver, void(const std::string&, PrefObserver*));
};
} // namespace
@@ -38,10 +36,10 @@ class MockPrefService : public TestingPrefServiceSimple {
class PrefChangeRegistrarTest : public testing::Test {
public:
PrefChangeRegistrarTest() {}
- virtual ~PrefChangeRegistrarTest() {}
+ ~PrefChangeRegistrarTest() override {}
protected:
- virtual void SetUp() override;
+ void SetUp() override;
base::Closure observer() const {
return base::Bind(&base::DoNothing);
diff --git a/chromium/base/prefs/pref_member.cc b/chromium/base/prefs/pref_member.cc
index 4fa616f4fb6..64c3d6a9934 100644
--- a/chromium/base/prefs/pref_member.cc
+++ b/chromium/base/prefs/pref_member.cc
@@ -7,11 +7,10 @@
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/prefs/pref_service.h"
+#include "base/thread_task_runner_handle.h"
#include "base/value_conversions.h"
-using base::MessageLoopProxy;
using base::SingleThreadTaskRunner;
namespace subtle {
@@ -25,23 +24,20 @@ PrefMemberBase::~PrefMemberBase() {
Destroy();
}
-void PrefMemberBase::Init(const char* pref_name,
+void PrefMemberBase::Init(const std::string& pref_name,
PrefService* prefs,
const NamedChangeCallback& observer) {
observer_ = observer;
Init(pref_name, prefs);
}
-void PrefMemberBase::Init(const char* pref_name,
- PrefService* prefs) {
- DCHECK(pref_name);
+void PrefMemberBase::Init(const std::string& pref_name, PrefService* prefs) {
DCHECK(prefs);
DCHECK(pref_name_.empty()); // Check that Init is only called once.
prefs_ = prefs;
pref_name_ = pref_name;
// Check that the preference is registered.
- DCHECK(prefs_->FindPreference(pref_name_.c_str()))
- << pref_name << " not registered.";
+ DCHECK(prefs_->FindPreference(pref_name_)) << pref_name << " not registered.";
// Add ourselves as a pref observer so we can keep our local value in sync.
prefs_->AddPrefObserver(pref_name, this);
@@ -49,18 +45,18 @@ void PrefMemberBase::Init(const char* pref_name,
void PrefMemberBase::Destroy() {
if (prefs_ && !pref_name_.empty()) {
- prefs_->RemovePrefObserver(pref_name_.c_str(), this);
+ prefs_->RemovePrefObserver(pref_name_, this);
prefs_ = NULL;
}
}
void PrefMemberBase::MoveToThread(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ scoped_refptr<SingleThreadTaskRunner> task_runner) {
VerifyValuePrefName();
// Load the value from preferences if it hasn't been loaded so far.
if (!internal())
UpdateValueFromPref(base::Closure());
- internal()->MoveToThread(task_runner);
+ internal()->MoveToThread(task_runner.Pass());
}
void PrefMemberBase::OnPreferenceChanged(PrefService* service,
@@ -72,8 +68,7 @@ void PrefMemberBase::OnPreferenceChanged(PrefService* service,
void PrefMemberBase::UpdateValueFromPref(const base::Closure& callback) const {
VerifyValuePrefName();
- const PrefService::Preference* pref =
- prefs_->FindPreference(pref_name_.c_str());
+ const PrefService::Preference* pref = prefs_->FindPreference(pref_name_);
DCHECK(pref);
if (!internal())
CreateInternal();
@@ -95,15 +90,14 @@ void PrefMemberBase::InvokeUnnamedCallback(const base::Closure& callback,
}
PrefMemberBase::Internal::Internal()
- : thread_loop_(MessageLoopProxy::current()),
+ : thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
is_managed_(false),
is_user_modifiable_(false) {
}
PrefMemberBase::Internal::~Internal() { }
bool PrefMemberBase::Internal::IsOnCorrectThread() const {
- // In unit tests, there may not be a message loop.
- return thread_loop_.get() == NULL || thread_loop_->BelongsToCurrentThread();
+ return thread_task_runner_->BelongsToCurrentThread();
}
void PrefMemberBase::Internal::UpdateValue(
@@ -119,19 +113,18 @@ void PrefMemberBase::Internal::UpdateValue(
is_managed_ = is_managed;
is_user_modifiable_ = is_user_modifiable;
} else {
- bool may_run = thread_loop_->PostTask(
- FROM_HERE,
- base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
- value.release(), is_managed, is_user_modifiable,
- closure_runner.Release()));
+ bool may_run = thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
+ value.release(), is_managed, is_user_modifiable,
+ closure_runner.Release()));
DCHECK(may_run);
}
}
void PrefMemberBase::Internal::MoveToThread(
- const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ scoped_refptr<SingleThreadTaskRunner> task_runner) {
CheckOnCorrectThread();
- thread_loop_ = task_runner;
+ thread_task_runner_ = task_runner.Pass();
}
bool PrefMemberVectorStringUpdate(const base::Value& value,
@@ -158,7 +151,7 @@ bool PrefMemberVectorStringUpdate(const base::Value& value,
template <>
void PrefMember<bool>::UpdatePref(const bool& value) {
- prefs()->SetBoolean(pref_name().c_str(), value);
+ prefs()->SetBoolean(pref_name(), value);
}
template <>
@@ -169,7 +162,7 @@ bool PrefMember<bool>::Internal::UpdateValueInternal(
template <>
void PrefMember<int>::UpdatePref(const int& value) {
- prefs()->SetInteger(pref_name().c_str(), value);
+ prefs()->SetInteger(pref_name(), value);
}
template <>
@@ -180,7 +173,7 @@ bool PrefMember<int>::Internal::UpdateValueInternal(
template <>
void PrefMember<double>::UpdatePref(const double& value) {
- prefs()->SetDouble(pref_name().c_str(), value);
+ prefs()->SetDouble(pref_name(), value);
}
template <>
@@ -191,7 +184,7 @@ bool PrefMember<double>::Internal::UpdateValueInternal(const base::Value& value)
template <>
void PrefMember<std::string>::UpdatePref(const std::string& value) {
- prefs()->SetString(pref_name().c_str(), value);
+ prefs()->SetString(pref_name(), value);
}
template <>
@@ -203,7 +196,7 @@ bool PrefMember<std::string>::Internal::UpdateValueInternal(
template <>
void PrefMember<base::FilePath>::UpdatePref(const base::FilePath& value) {
- prefs()->SetFilePath(pref_name().c_str(), value);
+ prefs()->SetFilePath(pref_name(), value);
}
template <>
@@ -218,7 +211,7 @@ void PrefMember<std::vector<std::string> >::UpdatePref(
const std::vector<std::string>& value) {
base::ListValue list_value;
list_value.AppendStrings(value);
- prefs()->Set(pref_name().c_str(), list_value);
+ prefs()->Set(pref_name(), list_value);
}
template <>
diff --git a/chromium/base/prefs/pref_member.h b/chromium/base/prefs/pref_member.h
index a05d60ed36c..6dceb439ed7 100644
--- a/chromium/base/prefs/pref_member.h
+++ b/chromium/base/prefs/pref_member.h
@@ -65,8 +65,7 @@ class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver {
bool is_user_modifiable,
const base::Closure& callback) const;
- void MoveToThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+ void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// See PrefMember<> for description.
bool IsManaged() const {
@@ -92,7 +91,7 @@ class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver {
bool IsOnCorrectThread() const;
- scoped_refptr<base::SingleThreadTaskRunner> thread_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
mutable bool is_managed_;
mutable bool is_user_modifiable_;
@@ -103,17 +102,17 @@ class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver {
virtual ~PrefMemberBase();
// See PrefMember<> for description.
- void Init(const char* pref_name, PrefService* prefs,
+ void Init(const std::string& pref_name,
+ PrefService* prefs,
const NamedChangeCallback& observer);
- void Init(const char* pref_name, PrefService* prefs);
+ void Init(const std::string& pref_name, PrefService* prefs);
virtual void CreateInternal() const = 0;
// See PrefMember<> for description.
void Destroy();
- void MoveToThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+ void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// PrefObserver
void OnPreferenceChanged(PrefService* service,
@@ -169,17 +168,19 @@ class PrefMember : public subtle::PrefMemberBase {
// Do the actual initialization of the class. Use the two-parameter
// version if you don't want any notifications of changes. This
// method should only be called on the UI thread.
- void Init(const char* pref_name, PrefService* prefs,
+ void Init(const std::string& pref_name,
+ PrefService* prefs,
const NamedChangeCallback& observer) {
subtle::PrefMemberBase::Init(pref_name, prefs, observer);
}
- void Init(const char* pref_name, PrefService* prefs,
+ void Init(const std::string& pref_name,
+ PrefService* prefs,
const base::Closure& observer) {
subtle::PrefMemberBase::Init(
pref_name, prefs,
base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer));
}
- void Init(const char* pref_name, PrefService* prefs) {
+ void Init(const std::string& pref_name, PrefService* prefs) {
subtle::PrefMemberBase::Init(pref_name, prefs);
}
@@ -198,8 +199,7 @@ class PrefMember : public subtle::PrefMemberBase {
// via PostTask.
// This method should only be used from the thread the PrefMember is currently
// on, which is the UI thread by default.
- void MoveToThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
subtle::PrefMemberBase::MoveToThread(task_runner);
}
@@ -261,20 +261,21 @@ class PrefMember : public subtle::PrefMemberBase {
}
protected:
- virtual ~Internal() {}
+ ~Internal() override {}
- virtual BASE_PREFS_EXPORT bool UpdateValueInternal(
+ BASE_PREFS_EXPORT bool UpdateValueInternal(
const base::Value& value) const override;
// We cache the value of the pref so we don't have to keep walking the pref
// tree.
mutable ValueType value_;
+ private:
DISALLOW_COPY_AND_ASSIGN(Internal);
};
- virtual Internal* internal() const override { return internal_.get(); }
- virtual void CreateInternal() const override { internal_ = new Internal(); }
+ Internal* internal() const override { return internal_.get(); }
+ void CreateInternal() const override { internal_ = new Internal(); }
// This method is used to do the actual sync with pref of the specified type.
void BASE_PREFS_EXPORT UpdatePref(const ValueType& value);
diff --git a/chromium/base/prefs/pref_member_unittest.cc b/chromium/base/prefs/pref_member_unittest.cc
index d4d7e02c978..a776e2c2553 100644
--- a/chromium/base/prefs/pref_member_unittest.cc
+++ b/chromium/base/prefs/pref_member_unittest.cc
@@ -5,9 +5,10 @@
#include "base/prefs/pref_member.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/testing_pref_service.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -35,9 +36,9 @@ class GetPrefValueHelper
pref_thread_.Start();
}
- void Init(const char* pref_name, PrefService* prefs) {
+ void Init(const std::string& pref_name, PrefService* prefs) {
pref_.Init(pref_name, prefs);
- pref_.MoveToThread(pref_thread_.message_loop_proxy());
+ pref_.MoveToThread(pref_thread_.task_runner());
}
void Destroy() {
@@ -46,10 +47,9 @@ class GetPrefValueHelper
void FetchValue() {
base::WaitableEvent event(true, false);
- ASSERT_TRUE(
- pref_thread_.message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
+ ASSERT_TRUE(pref_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
event.Wait();
}
@@ -100,7 +100,11 @@ class PrefMemberTestClass {
} // anonymous namespace
-TEST(PrefMemberTest, BasicGetAndSet) {
+class PrefMemberTest : public testing::Test {
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(PrefMemberTest, BasicGetAndSet) {
TestingPrefServiceSimple prefs;
RegisterTestPrefs(prefs.registry());
@@ -227,7 +231,7 @@ TEST(PrefMemberTest, BasicGetAndSet) {
EXPECT_EQ(expected_vector, *string_list);
}
-TEST(PrefMemberTest, InvalidList) {
+TEST_F(PrefMemberTest, InvalidList) {
// Set the vector to an initial good value.
std::vector<std::string> expected_vector;
expected_vector.push_back("foo");
@@ -245,7 +249,7 @@ TEST(PrefMemberTest, InvalidList) {
EXPECT_EQ(expected_vector, vector);
}
-TEST(PrefMemberTest, TwoPrefs) {
+TEST_F(PrefMemberTest, TwoPrefs) {
// Make sure two DoublePrefMembers stay in sync.
TestingPrefServiceSimple prefs;
RegisterTestPrefs(prefs.registry());
@@ -266,7 +270,7 @@ TEST(PrefMemberTest, TwoPrefs) {
EXPECT_EQ(4.2, *pref2);
}
-TEST(PrefMemberTest, Observer) {
+TEST_F(PrefMemberTest, Observer) {
TestingPrefServiceSimple prefs;
RegisterTestPrefs(prefs.registry());
@@ -293,12 +297,12 @@ TEST(PrefMemberTest, Observer) {
EXPECT_EQ("hello", prefs.GetString(kStringPref));
}
-TEST(PrefMemberTest, NoInit) {
+TEST_F(PrefMemberTest, NoInit) {
// Make sure not calling Init on a PrefMember doesn't cause problems.
IntegerPrefMember pref;
}
-TEST(PrefMemberTest, MoveToThread) {
+TEST_F(PrefMemberTest, MoveToThread) {
TestingPrefServiceSimple prefs;
scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper());
RegisterTestPrefs(prefs.registry());
diff --git a/chromium/base/prefs/pref_notifier_impl.cc b/chromium/base/prefs/pref_notifier_impl.cc
index c02a7b3f5a5..7ae5fe679f8 100644
--- a/chromium/base/prefs/pref_notifier_impl.cc
+++ b/chromium/base/prefs/pref_notifier_impl.cc
@@ -22,7 +22,7 @@ PrefNotifierImpl::~PrefNotifierImpl() {
// Verify that there are no pref observers when we shut down.
for (PrefObserverMap::iterator it = pref_observers_.begin();
it != pref_observers_.end(); ++it) {
- PrefObserverList::Iterator obs_iterator(*(it->second));
+ PrefObserverList::Iterator obs_iterator(it->second);
if (obs_iterator.GetNext()) {
LOG(WARNING) << "pref observer found at shutdown " << it->first;
}
@@ -38,7 +38,7 @@ PrefNotifierImpl::~PrefNotifierImpl() {
init_observers_.clear();
}
-void PrefNotifierImpl::AddPrefObserver(const char* path,
+void PrefNotifierImpl::AddPrefObserver(const std::string& path,
PrefObserver* obs) {
// Get the pref observer list associated with the path.
PrefObserverList* observer_list = NULL;
@@ -56,7 +56,7 @@ void PrefNotifierImpl::AddPrefObserver(const char* path,
observer_list->AddObserver(obs);
}
-void PrefNotifierImpl::RemovePrefObserver(const char* path,
+void PrefNotifierImpl::RemovePrefObserver(const std::string& path,
PrefObserver* obs) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -98,7 +98,7 @@ void PrefNotifierImpl::FireObservers(const std::string& path) {
DCHECK(thread_checker_.CalledOnValidThread());
// Only send notifications for registered preferences.
- if (!pref_service_->FindPreference(path.c_str()))
+ if (!pref_service_->FindPreference(path))
return;
const PrefObserverMap::iterator observer_iterator =
diff --git a/chromium/base/prefs/pref_notifier_impl.h b/chromium/base/prefs/pref_notifier_impl.h
index 3f4c254c416..cfd46ff4211 100644
--- a/chromium/base/prefs/pref_notifier_impl.h
+++ b/chromium/base/prefs/pref_notifier_impl.h
@@ -29,8 +29,8 @@ class BASE_PREFS_EXPORT PrefNotifierImpl
// If the pref at the given path changes, we call the observer's
// OnPreferenceChanged method.
- void AddPrefObserver(const char* path, PrefObserver* observer);
- void RemovePrefObserver(const char* path, PrefObserver* observer);
+ void AddPrefObserver(const std::string& path, PrefObserver* observer);
+ void RemovePrefObserver(const std::string& path, PrefObserver* observer);
// We run the callback once, when initialization completes. The bool
// parameter will be set to true for successful initialization,
diff --git a/chromium/base/prefs/pref_notifier_impl_unittest.cc b/chromium/base/prefs/pref_notifier_impl_unittest.cc
index 8482c0289c7..c3cbf4f48c1 100644
--- a/chromium/base/prefs/pref_notifier_impl_unittest.cc
+++ b/chromium/base/prefs/pref_notifier_impl_unittest.cc
@@ -51,14 +51,14 @@ class MockPrefNotifier : public PrefNotifierImpl {
MOCK_METHOD1(FireObservers, void(const std::string& path));
- size_t CountObserver(const char* path, PrefObserver* obs) {
+ size_t CountObserver(const std::string& path, PrefObserver* obs) {
PrefObserverMap::const_iterator observer_iterator =
pref_observers()->find(path);
if (observer_iterator == pref_observers()->end())
return false;
PrefObserverList* observer_list = observer_iterator->second;
- PrefObserverList::Iterator it(*observer_list);
+ PrefObserverList::Iterator it(observer_list);
PrefObserver* existing_obs;
size_t count = 0;
while ((existing_obs = it.GetNext()) != NULL) {
@@ -85,7 +85,7 @@ class PrefObserverMock : public PrefObserver {
// Test fixture class.
class PrefNotifierTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
pref_service_.registry()->RegisterBooleanPref(kChangedPref, true);
pref_service_.registry()->RegisterBooleanPref(kUnchangedPref, true);
}
diff --git a/chromium/base/prefs/pref_registry.cc b/chromium/base/prefs/pref_registry.cc
index 134996185c4..74f4b522088 100644
--- a/chromium/base/prefs/pref_registry.cc
+++ b/chromium/base/prefs/pref_registry.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/prefs/default_pref_store.h"
#include "base/prefs/pref_store.h"
+#include "base/stl_util.h"
#include "base/values.h"
PrefRegistry::PrefRegistry()
@@ -16,6 +17,13 @@ PrefRegistry::PrefRegistry()
PrefRegistry::~PrefRegistry() {
}
+uint32 PrefRegistry::GetRegistrationFlags(const std::string& pref_name) const {
+ const auto& it = registration_flags_.find(pref_name);
+ if (it == registration_flags_.end())
+ return NO_REGISTRATION_FLAGS;
+ return it->second;
+}
+
scoped_refptr<PrefStore> PrefRegistry::defaults() {
return defaults_.get();
}
@@ -28,7 +36,7 @@ PrefRegistry::const_iterator PrefRegistry::end() const {
return defaults_->end();
}
-void PrefRegistry::SetDefaultPrefValue(const char* pref_name,
+void PrefRegistry::SetDefaultPrefValue(const std::string& pref_name,
base::Value* value) {
DCHECK(value);
const base::Value* current_value = NULL;
@@ -40,14 +48,19 @@ void PrefRegistry::SetDefaultPrefValue(const char* pref_name,
defaults_->ReplaceDefaultValue(pref_name, make_scoped_ptr(value));
}
-void PrefRegistry::RegisterPreference(const char* path,
- base::Value* default_value) {
+void PrefRegistry::RegisterPreference(const std::string& path,
+ base::Value* default_value,
+ uint32 flags) {
base::Value::Type orig_type = default_value->GetType();
DCHECK(orig_type != base::Value::TYPE_NULL &&
orig_type != base::Value::TYPE_BINARY) <<
"invalid preference type: " << orig_type;
DCHECK(!defaults_->GetValue(path, NULL)) <<
"Trying to register a previously registered pref: " << path;
+ DCHECK(!ContainsKey(registration_flags_, path)) <<
+ "Trying to register a previously registered pref: " << path;
defaults_->SetDefaultValue(path, make_scoped_ptr(default_value));
+ if (flags != NO_REGISTRATION_FLAGS)
+ registration_flags_[path] = flags;
}
diff --git a/chromium/base/prefs/pref_registry.h b/chromium/base/prefs/pref_registry.h
index 896db3ffa62..caf2a1afaf1 100644
--- a/chromium/base/prefs/pref_registry.h
+++ b/chromium/base/prefs/pref_registry.h
@@ -5,6 +5,7 @@
#ifndef BASE_PREFS_PREF_REGISTRY_H_
#define BASE_PREFS_PREF_REGISTRY_H_
+#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_value_map.h"
@@ -27,10 +28,30 @@ class PrefStore;
// also work, but this is being deprecated.
class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
public:
+ // Registration flags that can be specified which impact how the pref will
+ // behave or be stored. This will be passed in a bitmask when the pref is
+ // registered. Subclasses of PrefRegistry can specify their own flags. Care
+ // must be taken to ensure none of these overlap with the flags below.
+ enum PrefRegistrationFlags : uint32 {
+ // No flags are specified.
+ NO_REGISTRATION_FLAGS = 0,
+
+ // The first 8 bits are reserved for subclasses of PrefRegistry to use.
+
+ // This marks the pref as "lossy". There is no strict time guarantee on when
+ // a lossy pref will be persisted to permanent storage when it is modified.
+ LOSSY_PREF = 1 << 8,
+ };
+
typedef PrefValueMap::const_iterator const_iterator;
+ typedef base::hash_map<std::string, uint32> PrefRegistrationFlagsMap;
PrefRegistry();
+ // Retrieve the set of registration flags for the given preference. The return
+ // value is a bitmask of PrefRegistrationFlags.
+ uint32 GetRegistrationFlags(const std::string& pref_name) const;
+
// Gets the registered defaults.
scoped_refptr<PrefStore> defaults();
@@ -41,17 +62,23 @@ class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
// Changes the default value for a preference. Takes ownership of |value|.
//
// |pref_name| must be a previously registered preference.
- void SetDefaultPrefValue(const char* pref_name, base::Value* value);
+ void SetDefaultPrefValue(const std::string& pref_name, base::Value* value);
protected:
friend class base::RefCounted<PrefRegistry>;
virtual ~PrefRegistry();
- // Used by subclasses to register a default value for a preference.
- void RegisterPreference(const char* path, base::Value* default_value);
+ // Used by subclasses to register a default value and registration flags for
+ // a preference. |flags| is a bitmask of |PrefRegistrationFlags|.
+ void RegisterPreference(const std::string& path,
+ base::Value* default_value,
+ uint32 flags);
scoped_refptr<DefaultPrefStore> defaults_;
+ // A map of pref name to a bitmask of PrefRegistrationFlags.
+ PrefRegistrationFlagsMap registration_flags_;
+
private:
DISALLOW_COPY_AND_ASSIGN(PrefRegistry);
};
diff --git a/chromium/base/prefs/pref_registry_simple.cc b/chromium/base/prefs/pref_registry_simple.cc
index 7453016a272..93c268686d5 100644
--- a/chromium/base/prefs/pref_registry_simple.cc
+++ b/chromium/base/prefs/pref_registry_simple.cc
@@ -14,53 +14,148 @@ PrefRegistrySimple::PrefRegistrySimple() {
PrefRegistrySimple::~PrefRegistrySimple() {
}
-void PrefRegistrySimple::RegisterBooleanPref(const char* path,
+void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
bool default_value) {
- RegisterPreference(path, new base::FundamentalValue(default_value));
+ RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+ NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterIntegerPref(const char* path,
+void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
int default_value) {
- RegisterPreference(path, new base::FundamentalValue(default_value));
+ RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+ NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterDoublePref(const char* path,
+void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
double default_value) {
- RegisterPreference(path, new base::FundamentalValue(default_value));
+ RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+ NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterStringPref(const char* path,
+void PrefRegistrySimple::RegisterStringPref(const std::string& path,
const std::string& default_value) {
- RegisterPreference(path, new base::StringValue(default_value));
+ RegisterPrefAndNotify(path, new base::StringValue(default_value),
+ NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterFilePathPref(
- const char* path,
+ const std::string& path,
const base::FilePath& default_value) {
- RegisterPreference(path, new base::StringValue(default_value.value()));
+ RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+ NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterListPref(const char* path) {
- RegisterPreference(path, new base::ListValue());
+void PrefRegistrySimple::RegisterListPref(const std::string& path) {
+ RegisterPrefAndNotify(path, new base::ListValue(), NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterListPref(const char* path,
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
base::ListValue* default_value) {
- RegisterPreference(path, default_value);
+ RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterDictionaryPref(const char* path) {
- RegisterPreference(path, new base::DictionaryValue());
+void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path) {
+ RegisterPrefAndNotify(path, new base::DictionaryValue(),
+ NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterDictionaryPref(
- const char* path,
+ const std::string& path,
base::DictionaryValue* default_value) {
- RegisterPreference(path, default_value);
+ RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
}
-void PrefRegistrySimple::RegisterInt64Pref(const char* path,
+void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
int64 default_value) {
- RegisterPreference(
- path, new base::StringValue(base::Int64ToString(default_value)));
+ RegisterPrefAndNotify(
+ path, new base::StringValue(base::Int64ToString(default_value)),
+ NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
+ uint64 default_value) {
+ RegisterPrefAndNotify(
+ path, new base::StringValue(base::Uint64ToString(default_value)),
+ NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
+ bool default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
+ int default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
+ double default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterStringPref(const std::string& path,
+ const std::string& default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::StringValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterFilePathPref(
+ const std::string& path,
+ const base::FilePath& default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+ flags);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::ListValue(), flags);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+ base::ListValue* default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, default_value, flags);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, new base::DictionaryValue(), flags);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(
+ const std::string& path,
+ base::DictionaryValue* default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(path, default_value, flags);
+}
+
+void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
+ int64 default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(
+ path, new base::StringValue(base::Int64ToString(default_value)), flags);
+}
+
+void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
+ uint64 default_value,
+ uint32 flags) {
+ RegisterPrefAndNotify(
+ path, new base::StringValue(base::Uint64ToString(default_value)), flags);
+}
+
+void PrefRegistrySimple::OnPrefRegistered(const std::string& path,
+ base::Value* default_value,
+ uint32 flags) {
+}
+
+void PrefRegistrySimple::RegisterPrefAndNotify(const std::string& path,
+ base::Value* default_value,
+ uint32 flags) {
+ RegisterPreference(path, default_value, flags);
+ OnPrefRegistered(path, default_value, flags);
}
diff --git a/chromium/base/prefs/pref_registry_simple.h b/chromium/base/prefs/pref_registry_simple.h
index 41fe5900b19..6b69e30cc0d 100644
--- a/chromium/base/prefs/pref_registry_simple.h
+++ b/chromium/base/prefs/pref_registry_simple.h
@@ -21,23 +21,63 @@ class BASE_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
public:
PrefRegistrySimple();
- void RegisterBooleanPref(const char* path, bool default_value);
- void RegisterIntegerPref(const char* path, int default_value);
- void RegisterDoublePref(const char* path, double default_value);
- void RegisterStringPref(const char* path, const std::string& default_value);
- void RegisterFilePathPref(const char* path,
+ void RegisterBooleanPref(const std::string& path, bool default_value);
+ void RegisterIntegerPref(const std::string& path, int default_value);
+ void RegisterDoublePref(const std::string& path, double default_value);
+ void RegisterStringPref(const std::string& path,
+ const std::string& default_value);
+ void RegisterFilePathPref(const std::string& path,
const base::FilePath& default_value);
- void RegisterListPref(const char* path);
- void RegisterDictionaryPref(const char* path);
- void RegisterListPref(const char* path, base::ListValue* default_value);
- void RegisterDictionaryPref(const char* path,
+ void RegisterListPref(const std::string& path);
+ void RegisterDictionaryPref(const std::string& path);
+ void RegisterListPref(const std::string& path,
+ base::ListValue* default_value);
+ void RegisterDictionaryPref(const std::string& path,
base::DictionaryValue* default_value);
- void RegisterInt64Pref(const char* path,
- int64 default_value);
+ void RegisterInt64Pref(const std::string& path, int64 default_value);
+ void RegisterUint64Pref(const std::string&, uint64 default_value);
- private:
+ // Versions of registration functions that accept PrefRegistrationFlags.
+ // |flags| is a bitmask of PrefRegistrationFlags.
+ void RegisterBooleanPref(const std::string&,
+ bool default_value,
+ uint32 flags);
+ void RegisterIntegerPref(const std::string&, int default_value, uint32 flags);
+ void RegisterDoublePref(const std::string&,
+ double default_value,
+ uint32 flags);
+ void RegisterStringPref(const std::string&,
+ const std::string& default_value,
+ uint32 flags);
+ void RegisterFilePathPref(const std::string&,
+ const base::FilePath& default_value,
+ uint32 flags);
+ void RegisterListPref(const std::string&, uint32 flags);
+ void RegisterDictionaryPref(const std::string&, uint32 flags);
+ void RegisterListPref(const std::string&,
+ base::ListValue* default_value,
+ uint32 flags);
+ void RegisterDictionaryPref(const std::string&,
+ base::DictionaryValue* default_value,
+ uint32 flags);
+ void RegisterInt64Pref(const std::string&, int64 default_value, uint32 flags);
+ void RegisterUint64Pref(const std::string&,
+ uint64 default_value,
+ uint32 flags);
+
+ protected:
~PrefRegistrySimple() override;
+ // Allows subclasses to hook into pref registration.
+ virtual void OnPrefRegistered(const std::string&,
+ base::Value* default_value,
+ uint32 flags);
+
+ private:
+ void RegisterPrefAndNotify(const std::string&,
+ base::Value* default_value,
+ uint32 flags);
+
DISALLOW_COPY_AND_ASSIGN(PrefRegistrySimple);
};
diff --git a/chromium/base/prefs/pref_service.cc b/chromium/base/prefs/pref_service.cc
index 433f8145ec2..6e1d58ca0f1 100644
--- a/chromium/base/prefs/pref_service.cc
+++ b/chromium/base/prefs/pref_service.cc
@@ -8,16 +8,18 @@
#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/prefs/default_pref_store.h"
#include "base/prefs/pref_notifier_impl.h"
#include "base/prefs/pref_registry.h"
#include "base/prefs/pref_value_store.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/value_conversions.h"
#include "build/build_config.h"
@@ -36,6 +38,19 @@ class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate {
base::Callback<void(PersistentPrefStore::PrefReadError)> callback_;
};
+// Returns the WriteablePrefStore::PrefWriteFlags for the pref with the given
+// |path|.
+uint32 GetWriteFlags(const PrefService::Preference* pref) {
+ uint32 write_flags = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+
+ if (!pref)
+ return write_flags;
+
+ if (pref->registration_flags() & PrefRegistry::LOSSY_PREF)
+ write_flags |= WriteablePrefStore::LOSSY_PREF_WRITE_FLAG;
+ return write_flags;
+}
+
} // namespace
PrefService::PrefService(
@@ -53,6 +68,12 @@ PrefService::PrefService(
read_error_callback_(read_error_callback) {
pref_notifier_->SetPrefService(this);
+ // TODO(battre): This is a check for crbug.com/435208 to make sure that
+ // access violations are caused by a use-after-free bug and not by an
+ // initialization bug.
+ CHECK(pref_registry_);
+ CHECK(pref_value_store_);
+
InitFromStorage(async);
}
@@ -73,10 +94,9 @@ void PrefService::InitFromStorage(bool async) {
read_error_callback_.Run(user_pref_store_->ReadPrefs());
} else {
// Guarantee that initialization happens after this function returned.
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&PersistentPrefStore::ReadPrefsAsync,
- user_pref_store_.get(),
+ base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_.get(),
new ReadErrorHandler(read_error_callback_)));
}
}
@@ -86,7 +106,7 @@ void PrefService::CommitPendingWrite() {
user_pref_store_->CommitPendingWrite();
}
-bool PrefService::GetBoolean(const char* path) const {
+bool PrefService::GetBoolean(const std::string& path) const {
DCHECK(CalledOnValidThread());
bool result = false;
@@ -101,7 +121,7 @@ bool PrefService::GetBoolean(const char* path) const {
return result;
}
-int PrefService::GetInteger(const char* path) const {
+int PrefService::GetInteger(const std::string& path) const {
DCHECK(CalledOnValidThread());
int result = 0;
@@ -116,7 +136,7 @@ int PrefService::GetInteger(const char* path) const {
return result;
}
-double PrefService::GetDouble(const char* path) const {
+double PrefService::GetDouble(const std::string& path) const {
DCHECK(CalledOnValidThread());
double result = 0.0;
@@ -131,7 +151,7 @@ double PrefService::GetDouble(const char* path) const {
return result;
}
-std::string PrefService::GetString(const char* path) const {
+std::string PrefService::GetString(const std::string& path) const {
DCHECK(CalledOnValidThread());
std::string result;
@@ -146,7 +166,7 @@ std::string PrefService::GetString(const char* path) const {
return result;
}
-base::FilePath PrefService::GetFilePath(const char* path) const {
+base::FilePath PrefService::GetFilePath(const std::string& path) const {
DCHECK(CalledOnValidThread());
base::FilePath result;
@@ -161,7 +181,7 @@ base::FilePath PrefService::GetFilePath(const char* path) const {
return result;
}
-bool PrefService::HasPrefPath(const char* path) const {
+bool PrefService::HasPrefPath(const std::string& path) const {
const Preference* pref = FindPreference(path);
return pref && !pref->IsDefaultValue();
}
@@ -169,11 +189,21 @@ bool PrefService::HasPrefPath(const char* path) const {
scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const {
DCHECK(CalledOnValidThread());
scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
- PrefRegistry::const_iterator i = pref_registry_->begin();
- for (; i != pref_registry_->end(); ++i) {
- const base::Value* value = GetPreferenceValue(i->first);
- DCHECK(value);
- out->Set(i->first, value->DeepCopy());
+ for (const auto& it : *pref_registry_) {
+ out->Set(it.first, GetPreferenceValue(it.first)->CreateDeepCopy());
+ }
+ return out.Pass();
+}
+
+scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
+ const {
+ DCHECK(CalledOnValidThread());
+ scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+ for (const auto& it : *pref_registry_) {
+ const Preference* pref = FindPreference(it.first);
+ if (pref->IsDefaultValue())
+ continue;
+ out->Set(it.first, pref->GetValue()->CreateDeepCopy());
}
return out.Pass();
}
@@ -182,17 +212,16 @@ scoped_ptr<base::DictionaryValue>
PrefService::GetPreferenceValuesWithoutPathExpansion() const {
DCHECK(CalledOnValidThread());
scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
- PrefRegistry::const_iterator i = pref_registry_->begin();
- for (; i != pref_registry_->end(); ++i) {
- const base::Value* value = GetPreferenceValue(i->first);
+ for (const auto& it : *pref_registry_) {
+ const base::Value* value = GetPreferenceValue(it.first);
DCHECK(value);
- out->SetWithoutPathExpansion(i->first, value->DeepCopy());
+ out->SetWithoutPathExpansion(it.first, value->CreateDeepCopy());
}
return out.Pass();
}
const PrefService::Preference* PrefService::FindPreference(
- const char* pref_name) const {
+ const std::string& pref_name) const {
DCHECK(CalledOnValidThread());
PreferenceMap::iterator it = prefs_map_.find(pref_name);
if (it != prefs_map_.end())
@@ -225,18 +254,25 @@ PrefService::PrefInitializationStatus PrefService::GetInitializationStatus()
}
}
-bool PrefService::IsManagedPreference(const char* pref_name) const {
+bool PrefService::IsManagedPreference(const std::string& pref_name) const {
const Preference* pref = FindPreference(pref_name);
return pref && pref->IsManaged();
}
-bool PrefService::IsUserModifiablePreference(const char* pref_name) const {
+bool PrefService::IsPreferenceManagedByCustodian(
+ const std::string& pref_name) const {
+ const Preference* pref = FindPreference(pref_name);
+ return pref && pref->IsManagedByCustodian();
+}
+
+bool PrefService::IsUserModifiablePreference(
+ const std::string& pref_name) const {
const Preference* pref = FindPreference(pref_name);
return pref && pref->IsUserModifiable();
}
const base::DictionaryValue* PrefService::GetDictionary(
- const char* path) const {
+ const std::string& path) const {
DCHECK(CalledOnValidThread());
const base::Value* value = GetPreferenceValue(path);
@@ -251,7 +287,8 @@ const base::DictionaryValue* PrefService::GetDictionary(
return static_cast<const base::DictionaryValue*>(value);
}
-const base::Value* PrefService::GetUserPrefValue(const char* path) const {
+const base::Value* PrefService::GetUserPrefValue(
+ const std::string& path) const {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
@@ -274,13 +311,14 @@ const base::Value* PrefService::GetUserPrefValue(const char* path) const {
return value;
}
-void PrefService::SetDefaultPrefValue(const char* path,
+void PrefService::SetDefaultPrefValue(const std::string& path,
base::Value* value) {
DCHECK(CalledOnValidThread());
pref_registry_->SetDefaultPrefValue(path, value);
}
-const base::Value* PrefService::GetDefaultPrefValue(const char* path) const {
+const base::Value* PrefService::GetDefaultPrefValue(
+ const std::string& path) const {
DCHECK(CalledOnValidThread());
// Lookup the preference in the default store.
const base::Value* value = NULL;
@@ -291,7 +329,7 @@ const base::Value* PrefService::GetDefaultPrefValue(const char* path) const {
return value;
}
-const base::ListValue* PrefService::GetList(const char* path) const {
+const base::ListValue* PrefService::GetList(const std::string& path) const {
DCHECK(CalledOnValidThread());
const base::Value* value = GetPreferenceValue(path);
@@ -306,11 +344,12 @@ const base::ListValue* PrefService::GetList(const char* path) const {
return static_cast<const base::ListValue*>(value);
}
-void PrefService::AddPrefObserver(const char* path, PrefObserver* obs) {
+void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) {
pref_notifier_->AddPrefObserver(path, obs);
}
-void PrefService::RemovePrefObserver(const char* path, PrefObserver* obs) {
+void PrefService::RemovePrefObserver(const std::string& path,
+ PrefObserver* obs) {
pref_notifier_->RemovePrefObserver(path, obs);
}
@@ -322,7 +361,7 @@ PrefRegistry* PrefService::DeprecatedGetPrefRegistry() {
return pref_registry_.get();
}
-void PrefService::ClearPref(const char* path) {
+void PrefService::ClearPref(const std::string& path) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
@@ -330,38 +369,39 @@ void PrefService::ClearPref(const char* path) {
NOTREACHED() << "Trying to clear an unregistered pref: " << path;
return;
}
- user_pref_store_->RemoveValue(path);
+ user_pref_store_->RemoveValue(path, GetWriteFlags(pref));
}
-void PrefService::Set(const char* path, const base::Value& value) {
+void PrefService::Set(const std::string& path, const base::Value& value) {
SetUserPrefValue(path, value.DeepCopy());
}
-void PrefService::SetBoolean(const char* path, bool value) {
+void PrefService::SetBoolean(const std::string& path, bool value) {
SetUserPrefValue(path, new base::FundamentalValue(value));
}
-void PrefService::SetInteger(const char* path, int value) {
+void PrefService::SetInteger(const std::string& path, int value) {
SetUserPrefValue(path, new base::FundamentalValue(value));
}
-void PrefService::SetDouble(const char* path, double value) {
+void PrefService::SetDouble(const std::string& path, double value) {
SetUserPrefValue(path, new base::FundamentalValue(value));
}
-void PrefService::SetString(const char* path, const std::string& value) {
+void PrefService::SetString(const std::string& path, const std::string& value) {
SetUserPrefValue(path, new base::StringValue(value));
}
-void PrefService::SetFilePath(const char* path, const base::FilePath& value) {
+void PrefService::SetFilePath(const std::string& path,
+ const base::FilePath& value) {
SetUserPrefValue(path, base::CreateFilePathValue(value));
}
-void PrefService::SetInt64(const char* path, int64 value) {
+void PrefService::SetInt64(const std::string& path, int64 value) {
SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value)));
}
-int64 PrefService::GetInt64(const char* path) const {
+int64 PrefService::GetInt64(const std::string& path) const {
DCHECK(CalledOnValidThread());
const base::Value* value = GetPreferenceValue(path);
@@ -378,11 +418,11 @@ int64 PrefService::GetInt64(const char* path) const {
return val;
}
-void PrefService::SetUint64(const char* path, uint64 value) {
+void PrefService::SetUint64(const std::string& path, uint64 value) {
SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value)));
}
-uint64 PrefService::GetUint64(const char* path) const {
+uint64 PrefService::GetUint64(const std::string& path) const {
DCHECK(CalledOnValidThread());
const base::Value* value = GetPreferenceValue(path);
@@ -399,7 +439,7 @@ uint64 PrefService::GetUint64(const char* path) const {
return val;
}
-base::Value* PrefService::GetMutableUserPref(const char* path,
+base::Value* PrefService::GetMutableUserPref(const std::string& path,
base::Value::Type type) {
CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST);
DCHECK(CalledOnValidThread());
@@ -426,17 +466,18 @@ base::Value* PrefService::GetMutableUserPref(const char* path,
} else {
NOTREACHED();
}
- user_pref_store_->SetValueSilently(path, value);
+ user_pref_store_->SetValueSilently(path, value, GetWriteFlags(pref));
}
return value;
}
void PrefService::ReportUserPrefChanged(const std::string& key) {
DCHECK(CalledOnValidThread());
- user_pref_store_->ReportValueChanged(key);
+ user_pref_store_->ReportValueChanged(key, GetWriteFlags(FindPreference(key)));
}
-void PrefService::SetUserPrefValue(const char* path, base::Value* new_value) {
+void PrefService::SetUserPrefValue(const std::string& path,
+ base::Value* new_value) {
scoped_ptr<base::Value> owned_value(new_value);
DCHECK(CalledOnValidThread());
@@ -452,7 +493,7 @@ void PrefService::SetUserPrefValue(const char* path, base::Value* new_value) {
return;
}
- user_pref_store_->SetValue(path, owned_value.release());
+ user_pref_store_->SetValue(path, owned_value.release(), GetWriteFlags(pref));
}
void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
@@ -463,13 +504,13 @@ void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
// PrefService::Preference
PrefService::Preference::Preference(const PrefService* service,
- const char* name,
+ const std::string& name,
base::Value::Type type)
- : name_(name),
- type_(type),
- pref_service_(service) {
- DCHECK(name);
+ : name_(name), type_(type), pref_service_(service) {
DCHECK(service);
+ // Cache the registration flags at creation time to avoid multiple map lookups
+ // later.
+ registration_flags_ = service->pref_registry_->GetRegistrationFlags(name_);
}
const std::string PrefService::Preference::name() const {
@@ -487,8 +528,8 @@ const base::Value* PrefService::Preference::GetValue() const {
}
const base::Value* PrefService::Preference::GetRecommendedValue() const {
- DCHECK(pref_service_->FindPreference(name_.c_str())) <<
- "Must register pref before getting its value";
+ DCHECK(pref_service_->FindPreference(name_))
+ << "Must register pref before getting its value";
const base::Value* found_value = NULL;
if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) {
@@ -501,44 +542,56 @@ const base::Value* PrefService::Preference::GetRecommendedValue() const {
}
bool PrefService::Preference::IsManaged() const {
- return pref_value_store()->PrefValueInManagedStore(name_.c_str());
+ return pref_value_store()->PrefValueInManagedStore(name_);
+}
+
+bool PrefService::Preference::IsManagedByCustodian() const {
+ return pref_value_store()->PrefValueInSupervisedStore(name_.c_str());
}
bool PrefService::Preference::IsRecommended() const {
- return pref_value_store()->PrefValueFromRecommendedStore(name_.c_str());
+ return pref_value_store()->PrefValueFromRecommendedStore(name_);
}
bool PrefService::Preference::HasExtensionSetting() const {
- return pref_value_store()->PrefValueInExtensionStore(name_.c_str());
+ return pref_value_store()->PrefValueInExtensionStore(name_);
}
bool PrefService::Preference::HasUserSetting() const {
- return pref_value_store()->PrefValueInUserStore(name_.c_str());
+ return pref_value_store()->PrefValueInUserStore(name_);
}
bool PrefService::Preference::IsExtensionControlled() const {
- return pref_value_store()->PrefValueFromExtensionStore(name_.c_str());
+ return pref_value_store()->PrefValueFromExtensionStore(name_);
}
bool PrefService::Preference::IsUserControlled() const {
- return pref_value_store()->PrefValueFromUserStore(name_.c_str());
+ return pref_value_store()->PrefValueFromUserStore(name_);
}
bool PrefService::Preference::IsDefaultValue() const {
- return pref_value_store()->PrefValueFromDefaultStore(name_.c_str());
+ return pref_value_store()->PrefValueFromDefaultStore(name_);
}
bool PrefService::Preference::IsUserModifiable() const {
- return pref_value_store()->PrefValueUserModifiable(name_.c_str());
+ return pref_value_store()->PrefValueUserModifiable(name_);
}
bool PrefService::Preference::IsExtensionModifiable() const {
- return pref_value_store()->PrefValueExtensionModifiable(name_.c_str());
+ return pref_value_store()->PrefValueExtensionModifiable(name_);
}
const base::Value* PrefService::GetPreferenceValue(
const std::string& path) const {
DCHECK(CalledOnValidThread());
+
+ // TODO(battre): This is a check for crbug.com/435208. After analyzing some
+ // crash dumps it looks like the PrefService is accessed even though it has
+ // been cleared already.
+ CHECK(pref_registry_);
+ CHECK(pref_registry_->defaults());
+ CHECK(pref_value_store_);
+
const base::Value* default_value = NULL;
if (pref_registry_->defaults()->GetValue(path, &default_value)) {
const base::Value* found_value = NULL;
diff --git a/chromium/base/prefs/pref_service.h b/chromium/base/prefs/pref_service.h
index 186433c1b62..1fc6c127c05 100644
--- a/chromium/base/prefs/pref_service.h
+++ b/chromium/base/prefs/pref_service.h
@@ -65,7 +65,7 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// dictionary (a branch), or list. You shouldn't need to construct this on
// your own; use the PrefService::Register*Pref methods instead.
Preference(const PrefService* service,
- const char* name,
+ const std::string& name,
base::Value::Type type);
~Preference() {}
@@ -88,6 +88,11 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// whether the pref is actually being controlled by the policy setting.
bool IsManaged() const;
+ // Returns true if the Preference is controlled by the custodian of the
+ // supervised user. Since a supervised user is not expected to have an admin
+ // policy, this is the controlling pref if set.
+ bool IsManagedByCustodian() const;
+
// Returns true if the Preference is recommended, i.e. set by an admin
// policy but the user is allowed to change it.
bool IsRecommended() const;
@@ -123,6 +128,10 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// the Preference.
bool IsExtensionModifiable() const;
+ // Return the registration flags for this pref as a bitmask of
+ // PrefRegistry::PrefRegistrationFlags.
+ uint32 registration_flags() const { return registration_flags_; }
+
private:
friend class PrefService;
@@ -134,6 +143,8 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
const base::Value::Type type_;
+ uint32 registration_flags_;
+
// Reference to the PrefService in which this pref was created.
const PrefService* pref_service_;
};
@@ -156,81 +167,87 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// Returns true if the preference for the given preference name is available
// and is managed.
- bool IsManagedPreference(const char* pref_name) const;
+ bool IsManagedPreference(const std::string& pref_name) const;
+
+ // Returns true if the preference for the given preference name is available
+ // and is controlled by the parent/guardian of the child Account.
+ bool IsPreferenceManagedByCustodian(const std::string& pref_name) const;
// Returns |true| if a preference with the given name is available and its
// value can be changed by the user.
- bool IsUserModifiablePreference(const char* pref_name) const;
+ bool IsUserModifiablePreference(const std::string& pref_name) const;
// Look up a preference. Returns NULL if the preference is not
// registered.
- const PrefService::Preference* FindPreference(const char* path) const;
+ const PrefService::Preference* FindPreference(const std::string& path) const;
// If the path is valid and the value at the end of the path matches the type
// specified, it will return the specified value. Otherwise, the default
// value (set when the pref was registered) will be returned.
- bool GetBoolean(const char* path) const;
- int GetInteger(const char* path) const;
- double GetDouble(const char* path) const;
- std::string GetString(const char* path) const;
- base::FilePath GetFilePath(const char* path) const;
+ bool GetBoolean(const std::string& path) const;
+ int GetInteger(const std::string& path) const;
+ double GetDouble(const std::string& path) const;
+ std::string GetString(const std::string& path) const;
+ base::FilePath GetFilePath(const std::string& path) const;
// Returns the branch if it exists, or the registered default value otherwise.
// Note that |path| must point to a registered preference. In that case, these
// functions will never return NULL.
- const base::DictionaryValue* GetDictionary(
- const char* path) const;
- const base::ListValue* GetList(const char* path) const;
+ const base::DictionaryValue* GetDictionary(const std::string& path) const;
+ const base::ListValue* GetList(const std::string& path) const;
// Removes a user pref and restores the pref to its default value.
- void ClearPref(const char* path);
+ void ClearPref(const std::string& path);
// If the path is valid (i.e., registered), update the pref value in the user
// prefs.
// To set the value of dictionary or list values in the pref tree use
// Set(), but to modify the value of a dictionary or list use either
// ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h.
- void Set(const char* path, const base::Value& value);
- void SetBoolean(const char* path, bool value);
- void SetInteger(const char* path, int value);
- void SetDouble(const char* path, double value);
- void SetString(const char* path, const std::string& value);
- void SetFilePath(const char* path, const base::FilePath& value);
+ void Set(const std::string& path, const base::Value& value);
+ void SetBoolean(const std::string& path, bool value);
+ void SetInteger(const std::string& path, int value);
+ void SetDouble(const std::string& path, double value);
+ void SetString(const std::string& path, const std::string& value);
+ void SetFilePath(const std::string& path, const base::FilePath& value);
// Int64 helper methods that actually store the given value as a string.
// Note that if obtaining the named value via GetDictionary or GetList, the
// Value type will be TYPE_STRING.
- void SetInt64(const char* path, int64 value);
- int64 GetInt64(const char* path) const;
+ void SetInt64(const std::string& path, int64 value);
+ int64 GetInt64(const std::string& path) const;
// As above, but for unsigned values.
- void SetUint64(const char* path, uint64 value);
- uint64 GetUint64(const char* path) const;
+ void SetUint64(const std::string& path, uint64 value);
+ uint64 GetUint64(const std::string& path) const;
// Returns the value of the given preference, from the user pref store. If
// the preference is not set in the user pref store, returns NULL.
- const base::Value* GetUserPrefValue(const char* path) const;
+ const base::Value* GetUserPrefValue(const std::string& path) const;
// Changes the default value for a preference. Takes ownership of |value|.
//
// Will cause a pref change notification to be fired if this causes
// the effective value to change.
- void SetDefaultPrefValue(const char* path, base::Value* value);
+ void SetDefaultPrefValue(const std::string& path, base::Value* value);
// Returns the default value of the given preference. |path| must point to a
// registered preference. In that case, will never return NULL.
- const base::Value* GetDefaultPrefValue(const char* path) const;
+ const base::Value* GetDefaultPrefValue(const std::string& path) const;
// Returns true if a value has been set for the specified path.
// NOTE: this is NOT the same as FindPreference. In particular
// FindPreference returns whether RegisterXXX has been invoked, where as
// this checks if a value exists for the path.
- bool HasPrefPath(const char* path) const;
+ bool HasPrefPath(const std::string& path) const;
- // Returns a dictionary with effective preference values. The ownership
- // is passed to the caller.
+ // Returns a dictionary with effective preference values.
scoped_ptr<base::DictionaryValue> GetPreferenceValues() const;
+ // Returns a dictionary with effective preference values, omitting prefs that
+ // are at their default values.
+ scoped_ptr<base::DictionaryValue> GetPreferenceValuesOmitDefaults() const;
+
// Returns a dictionary with effective preference values. Contrary to
// GetPreferenceValues(), the paths of registered preferences are not split on
// '.' characters. If a registered preference stores a dictionary, however,
@@ -238,7 +255,6 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// For example, if "foo.bar" is a registered preference, the result could look
// like this:
// {"foo.bar": {"a": {"b": true}}}.
- // The ownership is passed to the caller.
scoped_ptr<base::DictionaryValue> GetPreferenceValuesWithoutPathExpansion()
const;
@@ -297,6 +313,7 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// Give access to ReportUserPrefChanged() and GetMutableUserPref().
friend class subtle::ScopedUserPrefUpdateBase;
+ friend class PrefServiceTest_WriteablePrefStoreFlags_Test;
// Registration of pref change observers must be done using the
// PrefChangeRegistrar, which is declared as a friend here to grant it
@@ -316,8 +333,8 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// make sure the observer gets cleaned up properly.
//
// Virtual for testing.
- virtual void AddPrefObserver(const char* path, PrefObserver* obs);
- virtual void RemovePrefObserver(const char* path, PrefObserver* obs);
+ virtual void AddPrefObserver(const std::string& path, PrefObserver* obs);
+ virtual void RemovePrefObserver(const std::string& path, PrefObserver* obs);
// Sends notification of a changed preference. This needs to be called by
// a ScopedUserPrefUpdate if a DictionaryValue or ListValue is changed.
@@ -325,7 +342,7 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// Sets the value for this pref path in the user pref store and informs the
// PrefNotifier of the change.
- void SetUserPrefValue(const char* path, base::Value* new_value);
+ void SetUserPrefValue(const std::string& path, base::Value* new_value);
// Load preferences from storage, attempting to diagnose and handle errors.
// This should only be called from the constructor.
@@ -338,7 +355,7 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// |type| may only be Values::TYPE_DICTIONARY or Values::TYPE_LIST and
// |path| must point to a registered preference of type |type|.
// Ownership of the returned value remains at the user pref store.
- base::Value* GetMutableUserPref(const char* path,
+ base::Value* GetMutableUserPref(const std::string& path,
base::Value::Type type);
// GetPreferenceValue is the equivalent of FindPreference(path)->GetValue(),
diff --git a/chromium/base/prefs/pref_service_factory.cc b/chromium/base/prefs/pref_service_factory.cc
index d644cb1c2b0..8caf073e7bb 100644
--- a/chromium/base/prefs/pref_service_factory.cc
+++ b/chromium/base/prefs/pref_service_factory.cc
@@ -10,8 +10,8 @@
#include "base/prefs/pref_filter.h"
#include "base/prefs/pref_notifier_impl.h"
#include "base/prefs/pref_service.h"
-
#include "base/prefs/pref_value_store.h"
+#include "base/sequenced_task_runner.h"
namespace base {
diff --git a/chromium/base/prefs/pref_service_unittest.cc b/chromium/base/prefs/pref_service_unittest.cc
index 36ad887df2c..262d7e9de9d 100644
--- a/chromium/base/prefs/pref_service_unittest.cc
+++ b/chromium/base/prefs/pref_service_unittest.cc
@@ -8,6 +8,7 @@
#include "base/prefs/mock_pref_change_callback.h"
#include "base/prefs/pref_change_registrar.h"
#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service_factory.h"
#include "base/prefs/pref_value_store.h"
#include "base/prefs/testing_pref_service.h"
#include "base/prefs/testing_pref_store.h"
@@ -227,6 +228,115 @@ TEST(PrefServiceTest, GetValueAndGetRecommendedValue) {
EXPECT_EQ(kRecommendedValue, actual_int_value);
}
+// A PrefStore which just stores the last write flags that were used to write
+// values to it.
+class WriteFlagChecker : public TestingPrefStore {
+ public:
+ WriteFlagChecker() {}
+
+ void ReportValueChanged(const std::string& key, uint32 flags) override {
+ SetLastWriteFlags(flags);
+ }
+
+ void SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) override {
+ SetLastWriteFlags(flags);
+ delete value;
+ }
+
+ void SetValueSilently(const std::string& key,
+ base::Value* value,
+ uint32 flags) override {
+ SetLastWriteFlags(flags);
+ delete value;
+ }
+
+ void RemoveValue(const std::string& key, uint32 flags) override {
+ SetLastWriteFlags(flags);
+ }
+
+ uint32 GetLastFlagsAndClear() {
+ CHECK(last_write_flags_set_);
+ uint32 result = last_write_flags_;
+ last_write_flags_set_ = false;
+ last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+ return result;
+ }
+
+ bool last_write_flags_set() { return last_write_flags_set_; }
+
+ private:
+ ~WriteFlagChecker() override {}
+
+ void SetLastWriteFlags(uint32 flags) {
+ CHECK(!last_write_flags_set_);
+ last_write_flags_set_ = true;
+ last_write_flags_ = flags;
+ }
+
+ bool last_write_flags_set_ = false;
+ uint32 last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+};
+
+TEST(PrefServiceTest, WriteablePrefStoreFlags) {
+ scoped_refptr<WriteFlagChecker> flag_checker(new WriteFlagChecker);
+ scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple);
+ base::PrefServiceFactory factory;
+ factory.set_user_prefs(flag_checker);
+ scoped_ptr<PrefService> prefs(factory.Create(registry.get()));
+
+ // The first 8 bits of write flags are reserved for subclasses. Create a
+ // custom flag in this range
+ uint32 kCustomRegistrationFlag = 1 << 2;
+
+ // A map of the registration flags that will be tested and the write flags
+ // they are expected to convert to.
+ struct RegistrationToWriteFlags {
+ const char* pref_name;
+ uint32 registration_flags;
+ uint32 write_flags;
+ };
+ const RegistrationToWriteFlags kRegistrationToWriteFlags[] = {
+ {"none",
+ PrefRegistry::NO_REGISTRATION_FLAGS,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS},
+ {"lossy",
+ PrefRegistry::LOSSY_PREF,
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG},
+ {"custom",
+ kCustomRegistrationFlag,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS},
+ {"lossyandcustom",
+ PrefRegistry::LOSSY_PREF | kCustomRegistrationFlag,
+ WriteablePrefStore::LOSSY_PREF_WRITE_FLAG}};
+
+ for (size_t i = 0; i < arraysize(kRegistrationToWriteFlags); ++i) {
+ RegistrationToWriteFlags entry = kRegistrationToWriteFlags[i];
+ registry->RegisterDictionaryPref(
+ entry.pref_name, new base::DictionaryValue(), entry.registration_flags);
+
+ SCOPED_TRACE("Currently testing pref with name: " +
+ std::string(entry.pref_name));
+
+ prefs->GetMutableUserPref(entry.pref_name, base::Value::TYPE_DICTIONARY);
+ EXPECT_TRUE(flag_checker->last_write_flags_set());
+ EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+ prefs->ReportUserPrefChanged(entry.pref_name);
+ EXPECT_TRUE(flag_checker->last_write_flags_set());
+ EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+ prefs->ClearPref(entry.pref_name);
+ EXPECT_TRUE(flag_checker->last_write_flags_set());
+ EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+ prefs->SetUserPrefValue(entry.pref_name, new base::DictionaryValue());
+ EXPECT_TRUE(flag_checker->last_write_flags_set());
+ EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+ }
+}
+
class PrefServiceSetValueTest : public testing::Test {
protected:
static const char kName[];
diff --git a/chromium/base/prefs/pref_value_map.cc b/chromium/base/prefs/pref_value_map.cc
index 7d3dbe7761a..5f2dc506b69 100644
--- a/chromium/base/prefs/pref_value_map.cc
+++ b/chromium/base/prefs/pref_value_map.cc
@@ -4,6 +4,8 @@
#include "base/prefs/pref_value_map.h"
+#include <map>
+
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
@@ -18,56 +20,53 @@ PrefValueMap::~PrefValueMap() {
bool PrefValueMap::GetValue(const std::string& key,
const base::Value** value) const {
const Map::const_iterator entry = prefs_.find(key);
- if (entry != prefs_.end()) {
- if (value)
- *value = entry->second;
- return true;
- }
+ if (entry == prefs_.end())
+ return false;
- return false;
+ if (value)
+ *value = entry->second;
+ return true;
}
bool PrefValueMap::GetValue(const std::string& key, base::Value** value) {
const Map::const_iterator entry = prefs_.find(key);
- if (entry != prefs_.end()) {
- if (value)
- *value = entry->second;
- return true;
- }
+ if (entry == prefs_.end())
+ return false;
- return false;
+ if (value)
+ *value = entry->second;
+ return true;
}
bool PrefValueMap::SetValue(const std::string& key, base::Value* value) {
DCHECK(value);
+ auto result = prefs_.insert(std::make_pair(key, value));
+ if (result.second)
+ return true;
+
scoped_ptr<base::Value> value_ptr(value);
- const Map::iterator entry = prefs_.find(key);
- if (entry != prefs_.end()) {
- if (base::Value::Equals(entry->second, value))
- return false;
- delete entry->second;
- entry->second = value_ptr.release();
- } else {
- prefs_[key] = value_ptr.release();
- }
+ const Map::iterator& entry = result.first;
+ if (base::Value::Equals(entry->second, value))
+ return false;
+
+ delete entry->second;
+ entry->second = value_ptr.release();
return true;
}
bool PrefValueMap::RemoveValue(const std::string& key) {
const Map::iterator entry = prefs_.find(key);
- if (entry != prefs_.end()) {
- delete entry->second;
- prefs_.erase(entry);
- return true;
- }
+ if (entry == prefs_.end())
+ return false;
- return false;
+ delete entry->second;
+ prefs_.erase(entry);
+ return true;
}
void PrefValueMap::Clear() {
STLDeleteValues(&prefs_);
- prefs_.clear();
}
void PrefValueMap::Swap(PrefValueMap* other) {
@@ -92,7 +91,7 @@ PrefValueMap::const_iterator PrefValueMap::end() const {
bool PrefValueMap::GetBoolean(const std::string& key,
bool* value) const {
- const base::Value* stored_value = NULL;
+ const base::Value* stored_value = nullptr;
return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value);
}
@@ -102,7 +101,7 @@ void PrefValueMap::SetBoolean(const std::string& key, bool value) {
bool PrefValueMap::GetString(const std::string& key,
std::string* value) const {
- const base::Value* stored_value = NULL;
+ const base::Value* stored_value = nullptr;
return GetValue(key, &stored_value) && stored_value->GetAsString(value);
}
@@ -112,7 +111,7 @@ void PrefValueMap::SetString(const std::string& key,
}
bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
- const base::Value* stored_value = NULL;
+ const base::Value* stored_value = nullptr;
return GetValue(key, &stored_value) && stored_value->GetAsInteger(value);
}
@@ -129,10 +128,15 @@ void PrefValueMap::GetDifferingKeys(
std::vector<std::string>* differing_keys) const {
differing_keys->clear();
+ // Put everything into ordered maps.
+ std::map<std::string, base::Value*> this_prefs(prefs_.begin(), prefs_.end());
+ std::map<std::string, base::Value*> other_prefs(other->prefs_.begin(),
+ other->prefs_.end());
+
// Walk over the maps in lockstep, adding everything that is different.
- Map::const_iterator this_pref(prefs_.begin());
- Map::const_iterator other_pref(other->prefs_.begin());
- while (this_pref != prefs_.end() && other_pref != other->prefs_.end()) {
+ auto this_pref(this_prefs.begin());
+ auto other_pref(other_prefs.begin());
+ while (this_pref != this_prefs.end() && other_pref != other_prefs.end()) {
const int diff = this_pref->first.compare(other_pref->first);
if (diff == 0) {
if (!this_pref->second->Equals(other_pref->second))
@@ -149,8 +153,8 @@ void PrefValueMap::GetDifferingKeys(
}
// Add the remaining entries.
- for ( ; this_pref != prefs_.end(); ++this_pref)
+ for ( ; this_pref != this_prefs.end(); ++this_pref)
differing_keys->push_back(this_pref->first);
- for ( ; other_pref != other->prefs_.end(); ++other_pref)
+ for ( ; other_pref != other_prefs.end(); ++other_pref)
differing_keys->push_back(other_pref->first);
}
diff --git a/chromium/base/prefs/pref_value_map.h b/chromium/base/prefs/pref_value_map.h
index 2db18ab2a18..12b30c69739 100644
--- a/chromium/base/prefs/pref_value_map.h
+++ b/chromium/base/prefs/pref_value_map.h
@@ -5,11 +5,11 @@
#ifndef BASE_PREFS_PREF_VALUE_MAP_H_
#define BASE_PREFS_PREF_VALUE_MAP_H_
-#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
#include "base/prefs/base_prefs_export.h"
namespace base {
@@ -19,8 +19,9 @@ class Value;
// A generic string to value map used by the PrefStore implementations.
class BASE_PREFS_EXPORT PrefValueMap {
public:
- typedef std::map<std::string, base::Value*>::iterator iterator;
- typedef std::map<std::string, base::Value*>::const_iterator const_iterator;
+ using Map = base::hash_map<std::string, base::Value*>;
+ using iterator = Map::iterator;
+ using const_iterator = Map::const_iterator;
PrefValueMap();
virtual ~PrefValueMap();
@@ -81,8 +82,6 @@ class BASE_PREFS_EXPORT PrefValueMap {
std::vector<std::string>* differing_keys) const;
private:
- typedef std::map<std::string, base::Value*> Map;
-
Map prefs_;
DISALLOW_COPY_AND_ASSIGN(PrefValueMap);
diff --git a/chromium/base/prefs/pref_value_store.cc b/chromium/base/prefs/pref_value_store.cc
index 2c22f17febe..1a0ec08dccb 100644
--- a/chromium/base/prefs/pref_value_store.cc
+++ b/chromium/base/prefs/pref_value_store.cc
@@ -109,8 +109,8 @@ bool PrefValueStore::GetValue(const std::string& name,
// Check the |PrefStore|s in order of their priority from highest to lowest,
// looking for the first preference value with the given |name| and |type|.
for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
- if (GetValueFromStoreWithType(name.c_str(), type,
- static_cast<PrefStoreType>(i), out_value))
+ if (GetValueFromStoreWithType(name, type, static_cast<PrefStoreType>(i),
+ out_value))
return true;
}
return false;
@@ -119,12 +119,11 @@ bool PrefValueStore::GetValue(const std::string& name,
bool PrefValueStore::GetRecommendedValue(const std::string& name,
base::Value::Type type,
const base::Value** out_value) const {
- return GetValueFromStoreWithType(name.c_str(), type, RECOMMENDED_STORE,
- out_value);
+ return GetValueFromStoreWithType(name, type, RECOMMENDED_STORE, out_value);
}
void PrefValueStore::NotifyPrefChanged(
- const char* path,
+ const std::string& path,
PrefValueStore::PrefStoreType new_store) {
DCHECK(new_store != INVALID_STORE);
// A notification is sent when the pref value in any store changes. If this
@@ -135,41 +134,48 @@ void PrefValueStore::NotifyPrefChanged(
pref_changed_callback_.Run(path);
}
-bool PrefValueStore::PrefValueInManagedStore(const char* name) const {
+bool PrefValueStore::PrefValueInManagedStore(const std::string& name) const {
return PrefValueInStore(name, MANAGED_STORE);
}
-bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
+bool PrefValueStore::PrefValueInSupervisedStore(const std::string& name) const {
+ return PrefValueInStore(name, SUPERVISED_USER_STORE);
+}
+
+bool PrefValueStore::PrefValueInExtensionStore(const std::string& name) const {
return PrefValueInStore(name, EXTENSION_STORE);
}
-bool PrefValueStore::PrefValueInUserStore(const char* name) const {
+bool PrefValueStore::PrefValueInUserStore(const std::string& name) const {
return PrefValueInStore(name, USER_STORE);
}
-bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
+bool PrefValueStore::PrefValueFromExtensionStore(
+ const std::string& name) const {
return ControllingPrefStoreForPref(name) == EXTENSION_STORE;
}
-bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
+bool PrefValueStore::PrefValueFromUserStore(const std::string& name) const {
return ControllingPrefStoreForPref(name) == USER_STORE;
}
-bool PrefValueStore::PrefValueFromRecommendedStore(const char* name) const {
+bool PrefValueStore::PrefValueFromRecommendedStore(
+ const std::string& name) const {
return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE;
}
-bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
+bool PrefValueStore::PrefValueFromDefaultStore(const std::string& name) const {
return ControllingPrefStoreForPref(name) == DEFAULT_STORE;
}
-bool PrefValueStore::PrefValueUserModifiable(const char* name) const {
+bool PrefValueStore::PrefValueUserModifiable(const std::string& name) const {
PrefStoreType effective_store = ControllingPrefStoreForPref(name);
return effective_store >= USER_STORE ||
effective_store == INVALID_STORE;
}
-bool PrefValueStore::PrefValueExtensionModifiable(const char* name) const {
+bool PrefValueStore::PrefValueExtensionModifiable(
+ const std::string& name) const {
PrefStoreType effective_store = ControllingPrefStoreForPref(name);
return effective_store >= EXTENSION_STORE ||
effective_store == INVALID_STORE;
@@ -180,7 +186,7 @@ void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) {
}
bool PrefValueStore::PrefValueInStore(
- const char* name,
+ const std::string& name,
PrefValueStore::PrefStoreType store) const {
// Declare a temp Value* and call GetValueFromStore,
// ignoring the output value.
@@ -189,7 +195,7 @@ bool PrefValueStore::PrefValueInStore(
}
bool PrefValueStore::PrefValueInStoreRange(
- const char* name,
+ const std::string& name,
PrefValueStore::PrefStoreType first_checked_store,
PrefValueStore::PrefStoreType last_checked_store) const {
if (first_checked_store > last_checked_store) {
@@ -206,7 +212,7 @@ bool PrefValueStore::PrefValueInStoreRange(
}
PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
- const char* name) const {
+ const std::string& name) const {
for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
return static_cast<PrefStoreType>(i);
@@ -214,7 +220,7 @@ PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
return INVALID_STORE;
}
-bool PrefValueStore::GetValueFromStore(const char* name,
+bool PrefValueStore::GetValueFromStore(const std::string& name,
PrefValueStore::PrefStoreType store_type,
const base::Value** out_value) const {
// Only return true if we find a value and it is the correct type, so stale
@@ -230,7 +236,7 @@ bool PrefValueStore::GetValueFromStore(const char* name,
}
bool PrefValueStore::GetValueFromStoreWithType(
- const char* name,
+ const std::string& name,
base::Value::Type type,
PrefStoreType store,
const base::Value** out_value) const {
@@ -249,7 +255,7 @@ bool PrefValueStore::GetValueFromStoreWithType(
void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type,
const std::string& key) {
- NotifyPrefChanged(key.c_str(), type);
+ NotifyPrefChanged(key, type);
}
void PrefValueStore::OnInitializationCompleted(
diff --git a/chromium/base/prefs/pref_value_store.h b/chromium/base/prefs/pref_value_store.h
index db82a822e1d..51601156604 100644
--- a/chromium/base/prefs/pref_value_store.h
+++ b/chromium/base/prefs/pref_value_store.h
@@ -94,25 +94,26 @@ class BASE_PREFS_EXPORT PrefValueStore {
// These methods return true if a preference with the given name is in the
// indicated pref store, even if that value is currently being overridden by
// a higher-priority source.
- bool PrefValueInManagedStore(const char* name) const;
- bool PrefValueInExtensionStore(const char* name) const;
- bool PrefValueInUserStore(const char* name) const;
+ bool PrefValueInManagedStore(const std::string& name) const;
+ bool PrefValueInSupervisedStore(const std::string& name) const;
+ bool PrefValueInExtensionStore(const std::string& name) const;
+ bool PrefValueInUserStore(const std::string& name) const;
// These methods return true if a preference with the given name is actually
// being controlled by the indicated pref store and not being overridden by
// a higher-priority source.
- bool PrefValueFromExtensionStore(const char* name) const;
- bool PrefValueFromUserStore(const char* name) const;
- bool PrefValueFromRecommendedStore(const char* name) const;
- bool PrefValueFromDefaultStore(const char* name) const;
+ bool PrefValueFromExtensionStore(const std::string& name) const;
+ bool PrefValueFromUserStore(const std::string& name) const;
+ bool PrefValueFromRecommendedStore(const std::string& name) const;
+ bool PrefValueFromDefaultStore(const std::string& name) const;
// Check whether a Preference value is modifiable by the user, i.e. whether
// there is no higher-priority source controlling it.
- bool PrefValueUserModifiable(const char* name) const;
+ bool PrefValueUserModifiable(const std::string& name) const;
// Check whether a Preference value is modifiable by an extension, i.e.
// whether there is no higher-priority source controlling it.
- bool PrefValueExtensionModifiable(const char* name) const;
+ bool PrefValueExtensionModifiable(const std::string& name) const;
// Update the command line PrefStore with |command_line_prefs|.
void UpdateCommandLinePrefStore(PrefStore* command_line_prefs);
@@ -188,13 +189,13 @@ class BASE_PREFS_EXPORT PrefValueStore {
// Returns true if the preference with the given name has a value in the
// given PrefStoreType, of the same value type as the preference was
// registered with.
- bool PrefValueInStore(const char* name, PrefStoreType store) const;
+ bool PrefValueInStore(const std::string& name, PrefStoreType store) const;
// Returns true if a preference has an explicit value in any of the
// stores in the range specified by |first_checked_store| and
// |last_checked_store|, even if that value is currently being
// overridden by a higher-priority store.
- bool PrefValueInStoreRange(const char* name,
+ bool PrefValueInStoreRange(const std::string& name,
PrefStoreType first_checked_store,
PrefStoreType last_checked_store) const;
@@ -203,15 +204,15 @@ class BASE_PREFS_EXPORT PrefValueStore {
// INVALID_STORE is returned. In practice, the default PrefStore
// should always have a value for any registered preferencem, so INVALID_STORE
// indicates an error.
- PrefStoreType ControllingPrefStoreForPref(const char* name) const;
+ PrefStoreType ControllingPrefStoreForPref(const std::string& name) const;
// Get a value from the specified |store|.
- bool GetValueFromStore(const char* name,
+ bool GetValueFromStore(const std::string& name,
PrefStoreType store,
const base::Value** out_value) const;
// Get a value from the specified |store| if its |type| matches.
- bool GetValueFromStoreWithType(const char* name,
+ bool GetValueFromStoreWithType(const std::string& name,
base::Value::Type type,
PrefStoreType store,
const base::Value** out_value) const;
@@ -220,7 +221,7 @@ class BASE_PREFS_EXPORT PrefValueStore {
// the user-visible pref value has changed. Triggers the change notification
// if the effective value of the preference has changed, or if the store
// controlling the pref has changed.
- void NotifyPrefChanged(const char* path, PrefStoreType new_store);
+ void NotifyPrefChanged(const std::string& path, PrefStoreType new_store);
// Called from the PrefStoreKeeper implementation when a pref value for |key|
// changed in the pref store for |type|.
diff --git a/chromium/base/prefs/pref_value_store_unittest.cc b/chromium/base/prefs/pref_value_store_unittest.cc
index 3afe9dcefd1..e214adfa1c7 100644
--- a/chromium/base/prefs/pref_value_store_unittest.cc
+++ b/chromium/base/prefs/pref_value_store_unittest.cc
@@ -98,7 +98,7 @@ const char kDefaultValue[] = "default:default";
class PrefValueStoreTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
// Create TestingPrefStores.
CreateManagedPrefs();
CreateSupervisedUserPrefs();
@@ -237,7 +237,7 @@ class PrefValueStoreTest : public testing::Test {
default_pref::kDefaultValue);
}
- void ExpectValueChangeNotifications(const char* name) {
+ void ExpectValueChangeNotifications(const std::string& name) {
EXPECT_CALL(pref_notifier_, OnPreferenceChanged(name));
EXPECT_CALL(*sync_associator_, ProcessPrefChange(name));
}
diff --git a/chromium/base/prefs/scoped_user_pref_update.cc b/chromium/base/prefs/scoped_user_pref_update.cc
index 7871c75ce37..1440a5711d8 100644
--- a/chromium/base/prefs/scoped_user_pref_update.cc
+++ b/chromium/base/prefs/scoped_user_pref_update.cc
@@ -11,10 +11,8 @@
namespace subtle {
ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service,
- const char* path)
- : service_(service),
- path_(path),
- value_(NULL) {
+ const std::string& path)
+ : service_(service), path_(path), value_(NULL) {
DCHECK(service_->CalledOnValidThread());
}
@@ -25,7 +23,7 @@ ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() {
base::Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) {
DCHECK(CalledOnValidThread());
if (!value_)
- value_ = service_->GetMutableUserPref(path_.c_str(), type);
+ value_ = service_->GetMutableUserPref(path_, type);
return value_;
}
diff --git a/chromium/base/prefs/scoped_user_pref_update.h b/chromium/base/prefs/scoped_user_pref_update.h
index 82d6739dd32..f8bebfe435c 100644
--- a/chromium/base/prefs/scoped_user_pref_update.h
+++ b/chromium/base/prefs/scoped_user_pref_update.h
@@ -33,7 +33,7 @@ namespace subtle {
// PrefService::ReportUserPrefChanged.
class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe {
protected:
- ScopedUserPrefUpdateBase(PrefService* service, const char* path);
+ ScopedUserPrefUpdateBase(PrefService* service, const std::string& path);
// Calls Notify().
~ScopedUserPrefUpdateBase();
@@ -66,7 +66,7 @@ class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe {
template <typename T, base::Value::Type type_enum_value>
class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
public:
- ScopedUserPrefUpdate(PrefService* service, const char* path)
+ ScopedUserPrefUpdate(PrefService* service, const std::string& path)
: ScopedUserPrefUpdateBase(service, path) {}
// Triggers an update notification if Get() was called.
diff --git a/chromium/base/prefs/scoped_user_pref_update_unittest.cc b/chromium/base/prefs/scoped_user_pref_update_unittest.cc
index dfe2074720d..48e3dc4f7d4 100644
--- a/chromium/base/prefs/scoped_user_pref_update_unittest.cc
+++ b/chromium/base/prefs/scoped_user_pref_update_unittest.cc
@@ -16,10 +16,10 @@ using testing::Mock;
class ScopedUserPrefUpdateTest : public testing::Test {
public:
ScopedUserPrefUpdateTest() : observer_(&prefs_) {}
- virtual ~ScopedUserPrefUpdateTest() {}
+ ~ScopedUserPrefUpdateTest() override {}
protected:
- virtual void SetUp() {
+ void SetUp() override {
prefs_.registry()->RegisterDictionaryPref(kPref);
registrar_.Init(&prefs_);
registrar_.Add(kPref, observer_.GetCallback());
diff --git a/chromium/base/prefs/testing_pref_service.h b/chromium/base/prefs/testing_pref_service.h
index 2f6d4940c81..75873836b41 100644
--- a/chromium/base/prefs/testing_pref_service.h
+++ b/chromium/base/prefs/testing_pref_service.h
@@ -27,25 +27,25 @@ class TestingPrefServiceBase : public SuperPrefService {
// Read the value of a preference from the managed layer. Returns NULL if the
// preference is not defined at the managed layer.
- const base::Value* GetManagedPref(const char* path) const;
+ const base::Value* GetManagedPref(const std::string& path) const;
// Set a preference on the managed layer and fire observers if the preference
// changed. Assumes ownership of |value|.
- void SetManagedPref(const char* path, base::Value* value);
+ void SetManagedPref(const std::string& path, base::Value* value);
// Clear the preference on the managed layer and fire observers if the
// preference has been defined previously.
- void RemoveManagedPref(const char* path);
+ void RemoveManagedPref(const std::string& path);
// Similar to the above, but for user preferences.
- const base::Value* GetUserPref(const char* path) const;
- void SetUserPref(const char* path, base::Value* value);
- void RemoveUserPref(const char* path);
+ const base::Value* GetUserPref(const std::string& path) const;
+ void SetUserPref(const std::string& path, base::Value* value);
+ void RemoveUserPref(const std::string& path);
// Similar to the above, but for recommended policy preferences.
- const base::Value* GetRecommendedPref(const char* path) const;
- void SetRecommendedPref(const char* path, base::Value* value);
- void RemoveRecommendedPref(const char* path);
+ const base::Value* GetRecommendedPref(const std::string& path) const;
+ void SetRecommendedPref(const std::string& path, base::Value* value);
+ void RemoveRecommendedPref(const std::string& path);
// Do-nothing implementation for TestingPrefService.
static void HandleReadError(PersistentPrefStore::PrefReadError error) {}
@@ -62,14 +62,15 @@ class TestingPrefServiceBase : public SuperPrefService {
// Reads the value of the preference indicated by |path| from |pref_store|.
// Returns NULL if the preference was not found.
const base::Value* GetPref(TestingPrefStore* pref_store,
- const char* path) const;
+ const std::string& path) const;
// Sets the value for |path| in |pref_store|.
- void SetPref(TestingPrefStore* pref_store, const char* path,
+ void SetPref(TestingPrefStore* pref_store,
+ const std::string& path,
base::Value* value);
// Removes the preference identified by |path| from |pref_store|.
- void RemovePref(TestingPrefStore* pref_store, const char* path);
+ void RemovePref(TestingPrefStore* pref_store, const std::string& path);
// Pointers to the pref stores our value store uses.
scoped_refptr<TestingPrefStore> managed_prefs_;
@@ -110,89 +111,85 @@ TestingPrefServiceBase<
SuperPrefService, ConstructionPrefRegistry>::~TestingPrefServiceBase() {
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
+template <class SuperPrefService, class ConstructionPrefRegistry>
const base::Value* TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::GetManagedPref(
- const char* path) const {
+ SuperPrefService,
+ ConstructionPrefRegistry>::GetManagedPref(const std::string& path) const {
return GetPref(managed_prefs_.get(), path);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::SetManagedPref(
- const char* path, base::Value* value) {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetManagedPref(const std::string& path, base::Value* value) {
SetPref(managed_prefs_.get(), path, value);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::RemoveManagedPref(
- const char* path) {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ RemoveManagedPref(const std::string& path) {
RemovePref(managed_prefs_.get(), path);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-const base::Value* TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::GetUserPref(
- const char* path) const {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetUserPref(
+ const std::string& path) const {
return GetPref(user_prefs_.get(), path);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::SetUserPref(
- const char* path, base::Value* value) {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetUserPref(const std::string& path, base::Value* value) {
SetPref(user_prefs_.get(), path, value);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::RemoveUserPref(
- const char* path) {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ RemoveUserPref(const std::string& path) {
RemovePref(user_prefs_.get(), path);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-const base::Value* TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::GetRecommendedPref(
- const char* path) const {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ GetRecommendedPref(const std::string& path) const {
return GetPref(recommended_prefs_, path);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::SetRecommendedPref(
- const char* path, base::Value* value) {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetRecommendedPref(const std::string& path, base::Value* value) {
SetPref(recommended_prefs_.get(), path, value);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::RemoveRecommendedPref(
- const char* path) {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ RemoveRecommendedPref(const std::string& path) {
RemovePref(recommended_prefs_.get(), path);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-const base::Value* TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::GetPref(
- TestingPrefStore* pref_store, const char* path) const {
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetPref(
+ TestingPrefStore* pref_store,
+ const std::string& path) const {
const base::Value* res;
return pref_store->GetValue(path, &res) ? res : NULL;
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::SetPref(
- TestingPrefStore* pref_store, const char* path, base::Value* value) {
- pref_store->SetValue(path, value);
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetPref(TestingPrefStore* pref_store,
+ const std::string& path,
+ base::Value* value) {
+ pref_store->SetValue(path, value,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
-template<class SuperPrefService, class ConstructionPrefRegistry>
-void TestingPrefServiceBase<
- SuperPrefService, ConstructionPrefRegistry>::RemovePref(
- TestingPrefStore* pref_store, const char* path) {
- pref_store->RemoveValue(path);
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ RemovePref(TestingPrefStore* pref_store, const std::string& path) {
+ pref_store->RemoveValue(path, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
#endif // BASE_PREFS_TESTING_PREF_SERVICE_H_
diff --git a/chromium/base/prefs/testing_pref_store.cc b/chromium/base/prefs/testing_pref_store.cc
index f20824e1733..35c9763eec5 100644
--- a/chromium/base/prefs/testing_pref_store.cc
+++ b/chromium/base/prefs/testing_pref_store.cc
@@ -42,7 +42,9 @@ bool TestingPrefStore::IsInitializationComplete() const {
return init_complete_;
}
-void TestingPrefStore::SetValue(const std::string& key, base::Value* value) {
+void TestingPrefStore::SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) {
if (prefs_.SetValue(key, value)) {
committed_ = false;
NotifyPrefValueChanged(key);
@@ -50,12 +52,13 @@ void TestingPrefStore::SetValue(const std::string& key, base::Value* value) {
}
void TestingPrefStore::SetValueSilently(const std::string& key,
- base::Value* value) {
+ base::Value* value,
+ uint32 flags) {
if (prefs_.SetValue(key, value))
committed_ = false;
}
-void TestingPrefStore::RemoveValue(const std::string& key) {
+void TestingPrefStore::RemoveValue(const std::string& key, uint32 flags) {
if (prefs_.RemoveValue(key)) {
committed_ = false;
NotifyPrefValueChanged(key);
@@ -103,21 +106,22 @@ void TestingPrefStore::NotifyInitializationCompleted() {
Observer, observers_, OnInitializationCompleted(read_success_));
}
-void TestingPrefStore::ReportValueChanged(const std::string& key) {
+void TestingPrefStore::ReportValueChanged(const std::string& key,
+ uint32 flags) {
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
void TestingPrefStore::SetString(const std::string& key,
const std::string& value) {
- SetValue(key, new base::StringValue(value));
+ SetValue(key, new base::StringValue(value), DEFAULT_PREF_WRITE_FLAGS);
}
void TestingPrefStore::SetInteger(const std::string& key, int value) {
- SetValue(key, new base::FundamentalValue(value));
+ SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
}
void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
- SetValue(key, new base::FundamentalValue(value));
+ SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
}
bool TestingPrefStore::GetString(const std::string& key,
diff --git a/chromium/base/prefs/testing_pref_store.h b/chromium/base/prefs/testing_pref_store.h
index 866b4aeb029..3de5cacb1bf 100644
--- a/chromium/base/prefs/testing_pref_store.h
+++ b/chromium/base/prefs/testing_pref_store.h
@@ -30,10 +30,14 @@ class TestingPrefStore : public PersistentPrefStore {
// PersistentPrefStore overrides:
bool GetMutableValue(const std::string& key, base::Value** result) override;
- void ReportValueChanged(const std::string& key) override;
- void SetValue(const std::string& key, base::Value* value) override;
- void SetValueSilently(const std::string& key, base::Value* value) override;
- void RemoveValue(const std::string& key) override;
+ void ReportValueChanged(const std::string& key, uint32 flags) override;
+ void SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void SetValueSilently(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void RemoveValue(const std::string& key, uint32 flags) override;
bool ReadOnly() const override;
PrefReadError GetReadError() const override;
PersistentPrefStore::PrefReadError ReadPrefs() override;
diff --git a/chromium/base/prefs/value_map_pref_store.cc b/chromium/base/prefs/value_map_pref_store.cc
index 8af12826df3..d8501501f04 100644
--- a/chromium/base/prefs/value_map_pref_store.cc
+++ b/chromium/base/prefs/value_map_pref_store.cc
@@ -28,12 +28,14 @@ bool ValueMapPrefStore::HasObservers() const {
return observers_.might_have_observers();
}
-void ValueMapPrefStore::SetValue(const std::string& key, base::Value* value) {
+void ValueMapPrefStore::SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) {
if (prefs_.SetValue(key, value))
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
-void ValueMapPrefStore::RemoveValue(const std::string& key) {
+void ValueMapPrefStore::RemoveValue(const std::string& key, uint32 flags) {
if (prefs_.RemoveValue(key))
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
@@ -43,12 +45,14 @@ bool ValueMapPrefStore::GetMutableValue(const std::string& key,
return prefs_.GetValue(key, value);
}
-void ValueMapPrefStore::ReportValueChanged(const std::string& key) {
+void ValueMapPrefStore::ReportValueChanged(const std::string& key,
+ uint32 flags) {
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
void ValueMapPrefStore::SetValueSilently(const std::string& key,
- base::Value* value) {
+ base::Value* value,
+ uint32 flags) {
prefs_.SetValue(key, value);
}
diff --git a/chromium/base/prefs/value_map_pref_store.h b/chromium/base/prefs/value_map_pref_store.h
index 8c515ed345d..86c94bb50ca 100644
--- a/chromium/base/prefs/value_map_pref_store.h
+++ b/chromium/base/prefs/value_map_pref_store.h
@@ -28,11 +28,15 @@ class BASE_PREFS_EXPORT ValueMapPrefStore : public WriteablePrefStore {
bool HasObservers() const override;
// WriteablePrefStore overrides:
- void SetValue(const std::string& key, base::Value* value) override;
- void RemoveValue(const std::string& key) override;
+ void SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
+ void RemoveValue(const std::string& key, uint32 flags) override;
bool GetMutableValue(const std::string& key, base::Value** value) override;
- void ReportValueChanged(const std::string& key) override;
- void SetValueSilently(const std::string& key, base::Value* value) override;
+ void ReportValueChanged(const std::string& key, uint32 flags) override;
+ void SetValueSilently(const std::string& key,
+ base::Value* value,
+ uint32 flags) override;
protected:
~ValueMapPrefStore() override;
diff --git a/chromium/base/prefs/writeable_pref_store.h b/chromium/base/prefs/writeable_pref_store.h
index 5ebab642823..d85b4c8d427 100644
--- a/chromium/base/prefs/writeable_pref_store.h
+++ b/chromium/base/prefs/writeable_pref_store.h
@@ -17,14 +17,27 @@ class Value;
// A pref store that can be written to as well as read from.
class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
public:
+ // PrefWriteFlags can be used to change the way a pref will be written to
+ // storage.
+ enum PrefWriteFlags : uint32 {
+ // No flags are specified.
+ DEFAULT_PREF_WRITE_FLAGS = 0,
+
+ // This marks the pref as "lossy". There is no strict time guarantee on when
+ // a lossy pref will be persisted to permanent storage when it is modified.
+ LOSSY_PREF_WRITE_FLAG = 1 << 1
+ };
+
WriteablePrefStore() {}
// Sets a |value| for |key| in the store. Assumes ownership of |value|, which
- // must be non-NULL.
- virtual void SetValue(const std::string& key, base::Value* value) = 0;
+ // must be non-NULL. |flags| is a bitmask of PrefWriteFlags.
+ virtual void SetValue(const std::string& key,
+ base::Value* value,
+ uint32 flags) = 0;
// Removes the value for |key|.
- virtual void RemoveValue(const std::string& key) = 0;
+ virtual void RemoveValue(const std::string& key, uint32 flags) = 0;
// Equivalent to PrefStore::GetValue but returns a mutable value.
virtual bool GetMutableValue(const std::string& key,
@@ -34,13 +47,17 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
// if one retrieves a list or dictionary with GetMutableValue and change its
// value. SetValue takes care of notifications itself. Note that
// ReportValueChanged will trigger notifications even if nothing has changed.
- virtual void ReportValueChanged(const std::string& key) = 0;
+ // |flags| is a bitmask of PrefWriteFlags.
+ virtual void ReportValueChanged(const std::string& key, uint32 flags) = 0;
// Same as SetValue, but doesn't generate notifications. This is used by
// PrefService::GetMutableUserPref() in order to put empty entries
// into the user pref store. Using SetValue is not an option since existing
- // tests rely on the number of notifications generated.
- virtual void SetValueSilently(const std::string& key, base::Value* value) = 0;
+ // tests rely on the number of notifications generated. |flags| is a bitmask
+ // of PrefWriteFlags.
+ virtual void SetValueSilently(const std::string& key,
+ base::Value* value,
+ uint32 flags) = 0;
protected:
~WriteablePrefStore() override {}
diff --git a/chromium/base/process/BUILD.gn b/chromium/base/process/BUILD.gn
new file mode 100644
index 00000000000..814459b13e0
--- /dev/null
+++ b/chromium/base/process/BUILD.gn
@@ -0,0 +1,108 @@
+# Copyright (c) 2015 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.
+
+source_set("process") {
+ sources = [
+ "internal_linux.cc",
+ "internal_linux.h",
+ "kill.cc",
+ "kill.h",
+ "kill_mac.cc",
+ "kill_posix.cc",
+ "kill_win.cc",
+ "launch.cc",
+ "launch.h",
+ "launch_ios.cc",
+ "launch_mac.cc",
+ "launch_posix.cc",
+ "launch_win.cc",
+ "memory.cc",
+ "memory.h",
+ "memory_linux.cc",
+ "memory_mac.mm",
+ "memory_win.cc",
+ "process.h",
+ "process_handle_freebsd.cc",
+ "process_handle_linux.cc",
+ "process_handle_mac.cc",
+ "process_handle_openbsd.cc",
+ "process_handle_posix.cc",
+ "process_handle_win.cc",
+ "process_info.h",
+ "process_info_linux.cc",
+ "process_info_mac.cc",
+ "process_info_win.cc",
+ "process_iterator.cc",
+ "process_iterator.h",
+ "process_iterator_freebsd.cc",
+ "process_iterator_linux.cc",
+ "process_iterator_mac.cc",
+ "process_iterator_openbsd.cc",
+ "process_iterator_win.cc",
+ "process_linux.cc",
+ "process_mac.cc",
+ "process_metrics.cc",
+ "process_metrics.h",
+ "process_metrics_freebsd.cc",
+ "process_metrics_ios.cc",
+ "process_metrics_linux.cc",
+ "process_metrics_mac.cc",
+ "process_metrics_openbsd.cc",
+ "process_metrics_posix.cc",
+ "process_metrics_win.cc",
+ "process_posix.cc",
+ "process_win.cc",
+ ]
+
+ sources -= [
+ "process_handle_freebsd.cc",
+ "process_handle_openbsd.cc",
+ "process_iterator_freebsd.cc",
+ "process_iterator_openbsd.cc",
+ "process_metrics_freebsd.cc",
+ "process_metrics_openbsd.cc",
+ ]
+
+ if (is_android) {
+ # Android uses some Linux sources, put those back.
+ set_sources_assignment_filter([])
+ sources += [
+ "internal_linux.cc",
+ "memory_linux.cc",
+ "process_handle_linux.cc",
+ "process_iterator_linux.cc",
+ "process_metrics_linux.cc",
+ ]
+ set_sources_assignment_filter(sources_assignment_filter)
+ }
+
+ if (is_nacl) {
+ sources -= [
+ "kill.cc",
+ "kill.h",
+ "kill_posix.cc",
+ "launch.cc",
+ "launch.h",
+ "launch_posix.cc",
+ "memory.cc",
+ "memory.h",
+ "process_iterator.cc",
+ "process_iterator.h",
+ "process_metrics.cc",
+ "process_metrics_posix.cc",
+ "process_posix.cc",
+ ]
+ }
+
+ configs += [ "//base:base_implementation" ]
+
+ deps = [
+ "//base/memory",
+ "//base/third_party/dynamic_annotations",
+ ]
+
+ allow_circular_includes_from = [ "//base/memory" ]
+
+ visibility = [ "//base/*" ]
+}
diff --git a/chromium/base/process/internal_linux.cc b/chromium/base/process/internal_linux.cc
index ed7d7f4cf5e..d2e9ec52e53 100644
--- a/chromium/base/process/internal_linux.cc
+++ b/chromium/base/process/internal_linux.cc
@@ -106,12 +106,10 @@ bool ParseProcStats(const std::string& stats_data,
typedef std::map<std::string, std::string> ProcStatMap;
void ParseProcStat(const std::string& contents, ProcStatMap* output) {
- typedef std::pair<std::string, std::string> StringPair;
- std::vector<StringPair> key_value_pairs;
+ base::StringPairs key_value_pairs;
SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
for (size_t i = 0; i < key_value_pairs.size(); ++i) {
- const StringPair& key_value_pair = key_value_pairs[i];
- output->insert(key_value_pair);
+ output->insert(key_value_pairs[i]);
}
}
diff --git a/chromium/base/process/internal_linux.h b/chromium/base/process/internal_linux.h
index 5fc33566607..1837f94ce52 100644
--- a/chromium/base/process/internal_linux.h
+++ b/chromium/base/process/internal_linux.h
@@ -5,8 +5,8 @@
// This file contains internal routines that are called by other files in
// base/process/.
-#ifndef BASE_PROCESS_LINUX_INTERNAL_H_
-#define BASE_PROCESS_LINUX_INTERNAL_H_
+#ifndef BASE_PROCESS_INTERNAL_LINUX_H_
+#define BASE_PROCESS_INTERNAL_LINUX_H_
#include <unistd.h>
@@ -87,4 +87,4 @@ TimeDelta ClockTicksToTimeDelta(int clock_ticks);
} // namespace internal
} // namespace base
-#endif // BASE_PROCESS_LINUX_INTERNAL_H_
+#endif // BASE_PROCESS_INTERNAL_LINUX_H_
diff --git a/chromium/base/process/kill.cc b/chromium/base/process/kill.cc
index caca3484a11..5d8ba6a2d75 100644
--- a/chromium/base/process/kill.cc
+++ b/chromium/base/process/kill.cc
@@ -14,11 +14,8 @@ bool KillProcesses(const FilePath::StringType& executable_name,
bool result = true;
NamedProcessIterator iter(executable_name, filter);
while (const ProcessEntry* entry = iter.NextProcessEntry()) {
-#if defined(OS_WIN)
- result &= KillProcessById(entry->pid(), exit_code, true);
-#else
- result &= KillProcess(entry->pid(), exit_code, true);
-#endif
+ Process process = Process::Open(entry->pid());
+ result &= process.Terminate(exit_code, true);
}
return result;
}
diff --git a/chromium/base/process/kill.h b/chromium/base/process/kill.h
index de72d7a8dca..af00b03d984 100644
--- a/chromium/base/process/kill.h
+++ b/chromium/base/process/kill.h
@@ -9,6 +9,7 @@
#define BASE_PROCESS_KILL_H_
#include "base/files/file_path.h"
+#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
@@ -44,24 +45,12 @@ BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name,
int exit_code,
const ProcessFilter* filter);
-// Attempts to kill the process identified by the given process
-// entry structure, giving it the specified exit code. If |wait| is true, wait
-// for the process to be actually terminated before returning.
-// Returns true if this is successful, false otherwise.
-BASE_EXPORT bool KillProcess(ProcessHandle process, int exit_code, bool wait);
-
#if defined(OS_POSIX)
// Attempts to kill the process group identified by |process_group_id|. Returns
// true on success.
BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id);
#endif // defined(OS_POSIX)
-#if defined(OS_WIN)
-BASE_EXPORT bool KillProcessById(ProcessId process_id,
- int exit_code,
- bool wait);
-#endif // defined(OS_WIN)
-
// 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
@@ -93,22 +82,6 @@ BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus(
ProcessHandle handle, int* exit_code);
#endif // defined(OS_POSIX)
-// Waits for process to exit. On POSIX systems, if the process hasn't been
-// signaled then puts the exit code in |exit_code|; otherwise it's considered
-// a failure. On Windows |exit_code| is always filled. Returns true on success,
-// and closes |handle| in any case.
-BASE_EXPORT bool WaitForExitCode(ProcessHandle handle, int* exit_code);
-
-// Waits for process to exit. If it did exit within |timeout_milliseconds|,
-// then puts the exit code in |exit_code|, and returns true.
-// In POSIX systems, if the process has been signaled then |exit_code| is set
-// to -1. Returns false on failure (the caller is then responsible for closing
-// |handle|).
-// The caller is always responsible for closing the |handle|.
-BASE_EXPORT bool WaitForExitCodeWithTimeout(ProcessHandle handle,
- int* exit_code,
- base::TimeDelta timeout);
-
// Wait for all the processes based on the named executable to exit. If filter
// is non-null, then only processes selected by the filter are waited on.
// Returns after all processes have exited or wait_milliseconds have expired.
@@ -118,12 +91,6 @@ BASE_EXPORT bool WaitForProcessesToExit(
base::TimeDelta wait,
const ProcessFilter* filter);
-// Wait for a single process to exit. Return true if it exited cleanly within
-// the given time limit. On Linux |handle| must be a child process, however
-// on Mac and Windows it can be any process.
-BASE_EXPORT bool WaitForSingleProcess(ProcessHandle handle,
- base::TimeDelta wait);
-
// Waits a certain amount of time (can be 0) for all the processes with a given
// executable name to exit, then kills off any of them that are still around.
// If filter is non-null, then only processes selected by the filter are waited
@@ -146,15 +113,15 @@ BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
// On Linux this method does not block the calling thread.
// On OS X this method may block for up to 2 seconds.
//
-// NOTE: The process handle must have been opened with the PROCESS_TERMINATE
-// and SYNCHRONIZE permissions.
+// NOTE: The process must have been opened with the PROCESS_TERMINATE and
+// SYNCHRONIZE permissions.
//
-BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle);
+BASE_EXPORT void EnsureProcessTerminated(Process process);
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// The nicer version of EnsureProcessTerminated() that is patient and will
-// wait for |process_handle| to finish and then reap it.
-BASE_EXPORT void EnsureProcessGetsReaped(ProcessHandle process_handle);
+// wait for |pid| to finish and then reap it.
+BASE_EXPORT void EnsureProcessGetsReaped(ProcessId pid);
#endif
} // namespace base
diff --git a/chromium/base/process/kill_mac.cc b/chromium/base/process/kill_mac.cc
index 9257ee6929a..a4e0a14cf8f 100644
--- a/chromium/base/process/kill_mac.cc
+++ b/chromium/base/process/kill_mac.cc
@@ -66,8 +66,8 @@ void BlockingReap(pid_t child) {
// work in that case, but waitpid won't, and killing a non-child might not be
// the best approach.
void WaitForChildToDie(pid_t child, int timeout) {
- DCHECK(child > 0);
- DCHECK(timeout > 0);
+ DCHECK_GT(child, 0);
+ DCHECK_GT(timeout, 0);
// DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that
// |child| has been reaped. Specifically, even if a kqueue, kevent, or other
@@ -165,8 +165,8 @@ void WaitForChildToDie(pid_t child, int timeout) {
} // namespace
-void EnsureProcessTerminated(ProcessHandle process) {
- WaitForChildToDie(process, kWaitBeforeKillSeconds);
+void EnsureProcessTerminated(Process process) {
+ WaitForChildToDie(process.Pid(), kWaitBeforeKillSeconds);
}
} // namespace base
diff --git a/chromium/base/process/kill_posix.cc b/chromium/base/process/kill_posix.cc
index d17e9907626..0e303c67d3c 100644
--- a/chromium/base/process/kill_posix.cc
+++ b/chromium/base/process/kill_posix.cc
@@ -15,77 +15,12 @@
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_iterator.h"
#include "base/synchronization/waitable_event.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/platform_thread.h"
namespace base {
namespace {
-#if !defined(OS_NACL_NONSFI)
-bool WaitpidWithTimeout(ProcessHandle handle,
- int* status,
- base::TimeDelta wait) {
- // This POSIX version of this function only guarantees that we wait no less
- // than |wait| for the process to exit. The child process may
- // exit sometime before the timeout has ended but we may still block for up
- // to 256 milliseconds after the fact.
- //
- // waitpid() has no direct support on POSIX for specifying a timeout, you can
- // either ask it to block indefinitely or return immediately (WNOHANG).
- // When a child process terminates a SIGCHLD signal is sent to the parent.
- // Catching this signal would involve installing a signal handler which may
- // affect other parts of the application and would be difficult to debug.
- //
- // Our strategy is to call waitpid() once up front to check if the process
- // has already exited, otherwise to loop for |wait|, sleeping for
- // at most 256 milliseconds each time using usleep() and then calling
- // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and
- // we double it every 4 sleep cycles.
- //
- // usleep() is speced to exit if a signal is received for which a handler
- // has been installed. This means that when a SIGCHLD is sent, it will exit
- // depending on behavior external to this function.
- //
- // This function is used primarily for unit tests, if we want to use it in
- // the application itself it would probably be best to examine other routes.
-
- if (wait.InMilliseconds() == base::kNoTimeout) {
- return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
- }
-
- pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
- static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
- int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
- int64 double_sleep_time = 0;
-
- // If the process hasn't exited yet, then sleep and try again.
- TimeTicks wakeup_time = TimeTicks::Now() + wait;
- while (ret_pid == 0) {
- TimeTicks now = TimeTicks::Now();
- if (now > wakeup_time)
- break;
- // Guaranteed to be non-negative!
- int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
- // Sleep for a bit while we wait for the process to finish.
- if (sleep_time_usecs > max_sleep_time_usecs)
- sleep_time_usecs = max_sleep_time_usecs;
-
- // usleep() will return 0 and set errno to EINTR on receipt of a signal
- // such as SIGCHLD.
- usleep(sleep_time_usecs);
- ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
-
- if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
- (double_sleep_time++ % 4 == 0)) {
- max_sleep_time_usecs *= 2;
- }
- }
-
- return ret_pid > 0;
-}
-#endif // !defined(OS_NACL_NONSFI)
-
TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
bool can_block,
int* exit_code) {
@@ -133,61 +68,6 @@ TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
} // namespace
#if !defined(OS_NACL_NONSFI)
-// Attempts to kill the process identified by the given process
-// entry structure. Ignores specified exit_code; posix can't force that.
-// Returns true if this is successful, false otherwise.
-bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
- DCHECK_GT(process_id, 1) << " tried to kill invalid process_id";
- if (process_id <= 1)
- return false;
- bool result = kill(process_id, SIGTERM) == 0;
- if (result && wait) {
- int tries = 60;
-
- if (RunningOnValgrind()) {
- // Wait for some extra time when running under Valgrind since the child
- // processes may take some time doing leak checking.
- tries *= 2;
- }
-
- unsigned sleep_ms = 4;
-
- // The process may not end immediately due to pending I/O
- bool exited = false;
- while (tries-- > 0) {
- pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
- if (pid == process_id) {
- exited = true;
- break;
- }
- if (pid == -1) {
- if (errno == ECHILD) {
- // The wait may fail with ECHILD if another process also waited for
- // the same pid, causing the process state to get cleaned up.
- exited = true;
- break;
- }
- DPLOG(ERROR) << "Error waiting for process " << process_id;
- }
-
- usleep(sleep_ms * 1000);
- const unsigned kMaxSleepMs = 1000;
- if (sleep_ms < kMaxSleepMs)
- 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;
- }
-
- if (!result)
- DPLOG(ERROR) << "Unable to terminate process " << process_id;
-
- return result;
-}
-
bool KillProcessGroup(ProcessHandle process_group_id) {
bool result = kill(-1 * process_group_id, SIGKILL) == 0;
if (!result)
@@ -211,173 +91,29 @@ TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
}
#if !defined(OS_NACL_NONSFI)
-bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
- int status;
- if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) {
- NOTREACHED();
- return false;
- }
-
- if (WIFEXITED(status)) {
- *exit_code = WEXITSTATUS(status);
- return true;
- }
-
- // If it didn't exit cleanly, it must have been signaled.
- DCHECK(WIFSIGNALED(status));
- return false;
-}
-
-bool WaitForExitCodeWithTimeout(ProcessHandle handle,
- int* exit_code,
- base::TimeDelta timeout) {
- int status;
- if (!WaitpidWithTimeout(handle, &status, timeout))
- return false;
- if (WIFSIGNALED(status)) {
- *exit_code = -1;
- return true;
- }
- if (WIFEXITED(status)) {
- *exit_code = WEXITSTATUS(status);
- return true;
- }
- return false;
-}
-
bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
- base::TimeDelta wait,
+ TimeDelta wait,
const ProcessFilter* filter) {
bool result = false;
// TODO(port): This is inefficient, but works if there are multiple procs.
// TODO(port): use waitpid to avoid leaving zombies around
- base::TimeTicks end_time = base::TimeTicks::Now() + wait;
+ TimeTicks end_time = TimeTicks::Now() + wait;
do {
NamedProcessIterator iter(executable_name, filter);
if (!iter.NextProcessEntry()) {
result = true;
break;
}
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
- } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta());
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+ } while ((end_time - TimeTicks::Now()) > TimeDelta());
return result;
}
-#if defined(OS_MACOSX)
-// Using kqueue on Mac so that we can wait on non-child processes.
-// We can't use kqueues on child processes because we need to reap
-// our own children using wait.
-static bool WaitForSingleNonChildProcess(ProcessHandle handle,
- base::TimeDelta wait) {
- DCHECK_GT(handle, 0);
- DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
-
- ScopedFD kq(kqueue());
- if (!kq.is_valid()) {
- DPLOG(ERROR) << "kqueue";
- return false;
- }
-
- struct kevent change = {0};
- EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
- int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
- if (result == -1) {
- if (errno == ESRCH) {
- // If the process wasn't found, it must be dead.
- return true;
- }
-
- DPLOG(ERROR) << "kevent (setup " << handle << ")";
- return false;
- }
-
- // Keep track of the elapsed time to be able to restart kevent if it's
- // interrupted.
- bool wait_forever = wait.InMilliseconds() == base::kNoTimeout;
- base::TimeDelta remaining_delta;
- base::TimeTicks deadline;
- if (!wait_forever) {
- remaining_delta = wait;
- deadline = base::TimeTicks::Now() + remaining_delta;
- }
-
- result = -1;
- struct kevent event = {0};
-
- while (wait_forever || remaining_delta > base::TimeDelta()) {
- struct timespec remaining_timespec;
- struct timespec* remaining_timespec_ptr;
- if (wait_forever) {
- remaining_timespec_ptr = NULL;
- } else {
- remaining_timespec = remaining_delta.ToTimeSpec();
- remaining_timespec_ptr = &remaining_timespec;
- }
-
- result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
-
- if (result == -1 && errno == EINTR) {
- if (!wait_forever) {
- remaining_delta = deadline - base::TimeTicks::Now();
- }
- result = 0;
- } else {
- break;
- }
- }
-
- if (result < 0) {
- DPLOG(ERROR) << "kevent (wait " << handle << ")";
- return false;
- } else if (result > 1) {
- DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
- << result;
- return false;
- } else if (result == 0) {
- // Timed out.
- return false;
- }
-
- DCHECK_EQ(result, 1);
-
- if (event.filter != EVFILT_PROC ||
- (event.fflags & NOTE_EXIT) == 0 ||
- event.ident != static_cast<uintptr_t>(handle)) {
- DLOG(ERROR) << "kevent (wait " << handle
- << "): unexpected event: filter=" << event.filter
- << ", fflags=" << event.fflags
- << ", ident=" << event.ident;
- return false;
- }
-
- return true;
-}
-#endif // OS_MACOSX
-
-bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
- ProcessHandle parent_pid = GetParentProcessId(handle);
- ProcessHandle our_pid = GetCurrentProcessHandle();
- if (parent_pid != our_pid) {
-#if defined(OS_MACOSX)
- // On Mac we can wait on non child processes.
- return WaitForSingleNonChildProcess(handle, wait);
-#else
- // Currently on Linux we can't handle non child processes.
- NOTIMPLEMENTED();
-#endif // OS_MACOSX
- }
-
- int status;
- if (!WaitpidWithTimeout(handle, &status, wait))
- return false;
- return WIFEXITED(status);
-}
-
bool CleanupProcesses(const FilePath::StringType& executable_name,
- base::TimeDelta wait,
+ TimeDelta wait,
int exit_code,
const ProcessFilter* filter) {
bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
@@ -463,22 +199,22 @@ class BackgroundReaper : public PlatformThread::Delegate {
} // namespace
-void EnsureProcessTerminated(ProcessHandle process) {
+void EnsureProcessTerminated(Process process) {
// If the child is already dead, then there's nothing to do.
- if (IsChildDead(process))
+ if (IsChildDead(process.Pid()))
return;
const unsigned timeout = 2; // seconds
- BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
+ BackgroundReaper* reaper = new BackgroundReaper(process.Pid(), timeout);
PlatformThread::CreateNonJoinable(0, reaper);
}
-void EnsureProcessGetsReaped(ProcessHandle process) {
+void EnsureProcessGetsReaped(ProcessId pid) {
// If the child is already dead, then there's nothing to do.
- if (IsChildDead(process))
+ if (IsChildDead(pid))
return;
- BackgroundReaper* reaper = new BackgroundReaper(process, 0);
+ BackgroundReaper* reaper = new BackgroundReaper(pid, 0);
PlatformThread::CreateNonJoinable(0, reaper);
}
diff --git a/chromium/base/process/kill_win.cc b/chromium/base/process/kill_win.cc
index b102a8781d0..0da3a26ae4f 100644
--- a/chromium/base/process/kill_win.cc
+++ b/chromium/base/process/kill_win.cc
@@ -12,7 +12,6 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process_iterator.h"
-#include "base/profiler/scoped_tracker.h"
#include "base/win/object_watcher.h"
namespace base {
@@ -38,46 +37,40 @@ static const int kWaitInterval = 2000;
class TimerExpiredTask : public win::ObjectWatcher::Delegate {
public:
- explicit TimerExpiredTask(ProcessHandle process);
- ~TimerExpiredTask();
+ explicit TimerExpiredTask(Process process);
+ ~TimerExpiredTask() override;
void TimedOut();
// MessageLoop::Watcher -----------------------------------------------------
- virtual void OnObjectSignaled(HANDLE object);
+ void OnObjectSignaled(HANDLE object) override;
private:
void KillProcess();
// The process that we are watching.
- ProcessHandle process_;
+ Process process_;
win::ObjectWatcher watcher_;
DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
};
-TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
- watcher_.StartWatching(process_, this);
+TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) {
+ watcher_.StartWatching(process_.Handle(), this);
}
TimerExpiredTask::~TimerExpiredTask() {
TimedOut();
- DCHECK(!process_) << "Make sure to close the handle.";
}
void TimerExpiredTask::TimedOut() {
- if (process_)
+ if (process_.IsValid())
KillProcess();
}
void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("TimerExpiredTask_OnObjectSignaled"));
-
- CloseHandle(process_);
- process_ = NULL;
+ process_.Close();
}
void TimerExpiredTask::KillProcess() {
@@ -88,42 +81,14 @@ void TimerExpiredTask::KillProcess() {
// terminates. We just care that it eventually terminates, and that's what
// TerminateProcess should do for us. Don't check for the result code since
// it fails quite often. This should be investigated eventually.
- base::KillProcess(process_, kProcessKilledExitCode, false);
+ process_.Terminate(kProcessKilledExitCode, false);
// Now, just cleanup as if the process exited normally.
- OnObjectSignaled(process_);
+ OnObjectSignaled(process_.Handle());
}
} // namespace
-bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
- bool result = (TerminateProcess(process, exit_code) != FALSE);
- if (result && wait) {
- // The process may not end immediately due to pending I/O
- if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
- DPLOG(ERROR) << "Error waiting for process exit";
- } else if (!result) {
- DPLOG(ERROR) << "Unable to terminate process";
- }
- return result;
-}
-
-// Attempts to kill the process identified by the given process
-// entry structure, giving it the specified exit code.
-// Returns true if this is successful, false otherwise.
-bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
- HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
- FALSE, // Don't inherit handle
- process_id);
- if (!process) {
- DPLOG(ERROR) << "Unable to open process " << process_id;
- return false;
- }
- bool ret = KillProcess(process, exit_code, wait);
- CloseHandle(process);
- return ret;
-}
-
TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
DWORD tmp_exit_code = 0;
@@ -182,29 +147,8 @@ TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
}
}
-bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
- bool success = WaitForExitCodeWithTimeout(
- handle, exit_code, base::TimeDelta::FromMilliseconds(INFINITE));
- CloseProcessHandle(handle);
- return success;
-}
-
-bool WaitForExitCodeWithTimeout(ProcessHandle handle,
- int* exit_code,
- base::TimeDelta timeout) {
- if (::WaitForSingleObject(
- handle, static_cast<DWORD>(timeout.InMilliseconds())) != WAIT_OBJECT_0)
- return false;
- DWORD temp_code; // Don't clobber out-parameters in case of failure.
- if (!::GetExitCodeProcess(handle, &temp_code))
- return false;
-
- *exit_code = temp_code;
- return true;
-}
-
bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
- base::TimeDelta wait,
+ TimeDelta wait,
const ProcessFilter* filter) {
bool result = true;
DWORD start_time = GetTickCount();
@@ -226,13 +170,8 @@ bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
return result;
}
-bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
- int exit_code;
- return WaitForExitCodeWithTimeout(handle, &exit_code, wait) && exit_code == 0;
-}
-
bool CleanupProcesses(const FilePath::StringType& executable_name,
- base::TimeDelta wait,
+ TimeDelta wait,
int exit_code,
const ProcessFilter* filter) {
if (WaitForProcessesToExit(executable_name, wait, filter))
@@ -241,20 +180,19 @@ bool CleanupProcesses(const FilePath::StringType& executable_name,
return false;
}
-void EnsureProcessTerminated(ProcessHandle process) {
- DCHECK(process != GetCurrentProcess());
+void EnsureProcessTerminated(Process process) {
+ DCHECK(!process.is_current());
// If already signaled, then we are done!
- if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
- CloseHandle(process);
+ if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) {
return;
}
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
- base::Bind(&TimerExpiredTask::TimedOut,
- base::Owned(new TimerExpiredTask(process))),
- base::TimeDelta::FromMilliseconds(kWaitInterval));
+ Bind(&TimerExpiredTask::TimedOut,
+ Owned(new TimerExpiredTask(process.Pass()))),
+ TimeDelta::FromMilliseconds(kWaitInterval));
}
} // namespace base
diff --git a/chromium/base/process/launch.cc b/chromium/base/process/launch.cc
index a1c4d2159cb..c179b2f5f37 100644
--- a/chromium/base/process/launch.cc
+++ b/chromium/base/process/launch.cc
@@ -27,7 +27,11 @@ LaunchOptions::LaunchOptions()
#if defined(OS_LINUX)
, clone_flags(0)
, allow_new_privs(false)
+ , kill_on_parent_death(false)
#endif // OS_LINUX
+#if defined(OS_POSIX)
+ , pre_exec_delegate(NULL)
+#endif // OS_POSIX
#if defined(OS_CHROMEOS)
, ctrl_terminal_fd(-1)
#endif // OS_CHROMEOS
diff --git a/chromium/base/process/launch.h b/chromium/base/process/launch.h
index 261019b138f..56f27a82109 100644
--- a/chromium/base/process/launch.h
+++ b/chromium/base/process/launch.h
@@ -14,6 +14,7 @@
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/environment.h"
+#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/strings/string_piece.h"
@@ -21,7 +22,6 @@
#include "base/posix/file_descriptor_shuffle.h"
#elif defined(OS_WIN)
#include <windows.h>
-#include "base/win/scoped_handle.h"
#endif
namespace base {
@@ -37,6 +37,24 @@ typedef std::vector<std::pair<int, int> > FileHandleMappingVector;
// Options for launching a subprocess that are passed to LaunchProcess().
// The default constructor constructs the object with default options.
struct BASE_EXPORT LaunchOptions {
+#if defined(OS_POSIX)
+ // Delegate to be run in between fork and exec in the subprocess (see
+ // pre_exec_delegate below)
+ class BASE_EXPORT PreExecDelegate {
+ public:
+ PreExecDelegate() {}
+ virtual ~PreExecDelegate() {}
+
+ // Since this is to be run between fork and exec, and fork may have happened
+ // while multiple threads were running, this function needs to be async
+ // safe.
+ virtual void RunAsyncSafe() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PreExecDelegate);
+ };
+#endif // defined(OS_POSIX)
+
LaunchOptions();
~LaunchOptions();
@@ -115,13 +133,32 @@ struct BASE_EXPORT LaunchOptions {
#if defined(OS_LINUX)
// If non-zero, start the process using clone(), using flags as provided.
+ // Unlike in clone, clone_flags may not contain a custom termination signal
+ // that is sent to the parent when the child dies. The termination signal will
+ // always be set to SIGCHLD.
int clone_flags;
// By default, child processes will have the PR_SET_NO_NEW_PRIVS bit set. If
// true, then this bit will not be set in the new child process.
bool allow_new_privs;
+
+ // Sets parent process death signal to SIGKILL.
+ bool kill_on_parent_death;
#endif // defined(OS_LINUX)
+#if defined(OS_POSIX)
+ // If not empty, change to this directory before execing the new process.
+ base::FilePath current_directory;
+
+ // If non-null, a delegate to be run immediately prior to executing the new
+ // program in the child process.
+ //
+ // WARNING: If LaunchProcess is called in the presence of multiple threads,
+ // code running in this delegate essentially needs to be async-signal safe
+ // (see man 7 signal for a list of allowed functions).
+ PreExecDelegate* pre_exec_delegate;
+#endif // defined(OS_POSIX)
+
#if defined(OS_CHROMEOS)
// If non-negative, the specified file descriptor will be set as the launched
// process' controlling terminal.
@@ -143,12 +180,7 @@ struct BASE_EXPORT LaunchOptions {
// Launch a process via the command line |cmdline|.
// See the documentation of LaunchOptions for details on |options|.
//
-// Returns true upon success.
-//
-// Upon success, if |process_handle| is non-null, it will be filled in with the
-// handle of the launched process. NOTE: In this case, the caller is
-// responsible for closing the handle so that it doesn't leak!
-// Otherwise, the process handle will be implicitly closed.
+// Returns a valid Process upon success.
//
// Unix-specific notes:
// - All file descriptors open in the parent process will be closed in the
@@ -158,9 +190,8 @@ struct BASE_EXPORT LaunchOptions {
// parent's stdout and stderr.
// - If the first argument on the command line does not contain a slash,
// PATH will be searched. (See man execvp.)
-BASE_EXPORT bool LaunchProcess(const CommandLine& cmdline,
- const LaunchOptions& options,
- ProcessHandle* process_handle);
+BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline,
+ const LaunchOptions& options);
#if defined(OS_WIN)
// Windows-specific LaunchProcess that takes the command line as a
@@ -173,28 +204,24 @@ BASE_EXPORT bool LaunchProcess(const CommandLine& cmdline,
//
// Example (including literal quotes)
// cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
-BASE_EXPORT bool LaunchProcess(const string16& cmdline,
- const LaunchOptions& options,
- win::ScopedHandle* process_handle);
+BASE_EXPORT Process LaunchProcess(const string16& cmdline,
+ const LaunchOptions& options);
// Launches a process with elevated privileges. This does not behave exactly
// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
// create the process. This means the process will have elevated privileges
-// and thus some common operations like OpenProcess will fail. The process will
-// be available through the |process_handle| argument. Currently the only
-// supported LaunchOptions are |start_hidden| and |wait|.
-BASE_EXPORT bool LaunchElevatedProcess(const CommandLine& cmdline,
- const LaunchOptions& options,
- ProcessHandle* process_handle);
+// and thus some common operations like OpenProcess will fail. Currently the
+// only supported LaunchOptions are |start_hidden| and |wait|.
+BASE_EXPORT Process LaunchElevatedProcess(const CommandLine& cmdline,
+ const LaunchOptions& options);
#elif defined(OS_POSIX)
// A POSIX-specific version of LaunchProcess that takes an argv array
// instead of a CommandLine. Useful for situations where you need to
// control the command line arguments directly, but prefer the
// CommandLine version if launching Chrome itself.
-BASE_EXPORT bool LaunchProcess(const std::vector<std::string>& argv,
- const LaunchOptions& options,
- ProcessHandle* process_handle);
+BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv,
+ const LaunchOptions& options);
// 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
@@ -270,6 +297,25 @@ void ReplaceBootstrapPort(const std::string& replacement_bootstrap_name);
// binary. This should not be called in production/released code.
BASE_EXPORT LaunchOptions LaunchOptionsForTest();
+#if defined(OS_LINUX)
+// A wrapper for clone with fork-like behavior, meaning that it returns the
+// child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
+// as in the clone system call (the CLONE_VM flag is not supported).
+//
+// This function uses the libc clone wrapper (which updates libc's pid cache)
+// internally, so callers may expect things like getpid() to work correctly
+// after in both the child and parent. An exception is when this code is run
+// under Valgrind. Valgrind does not support the libc clone wrapper, so the libc
+// pid cache may be incorrect after this function is called under Valgrind.
+//
+// As with fork(), callers should be extremely careful when calling this while
+// multiple threads are running, since at the time the fork happened, the
+// threads could have been in any state (potentially holding locks, etc.).
+// Callers should most likely call execve() in the child soon after calling
+// this.
+BASE_EXPORT pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid);
+#endif
+
} // namespace base
#endif // BASE_PROCESS_LAUNCH_H_
diff --git a/chromium/base/process/launch_posix.cc b/chromium/base/process/launch_posix.cc
index bc6294b2dad..77edc128319 100644
--- a/chromium/base/process/launch_posix.cc
+++ b/chromium/base/process/launch_posix.cc
@@ -7,9 +7,12 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <sched.h>
+#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/resource.h>
+#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -30,13 +33,15 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/process/kill.h"
+#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/third_party/valgrind/valgrind.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_LINUX)
#include <sys/prctl.h>
@@ -184,6 +189,54 @@ void ResetChildSignalHandlersToDefaults(void) {
#endif // !defined(OS_LINUX) ||
// (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
+#if defined(OS_LINUX)
+bool IsRunningOnValgrind() {
+ return RUNNING_ON_VALGRIND;
+}
+
+// This function runs on the stack specified on the clone call. It uses longjmp
+// to switch back to the original stack so the child can return from sys_clone.
+int CloneHelper(void* arg) {
+ jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
+ longjmp(*env_ptr, 1);
+
+ // Should not be reached.
+ RAW_CHECK(false);
+ return 1;
+}
+
+// This function is noinline to ensure that stack_buf is below the stack pointer
+// that is saved when setjmp is called below. This is needed because when
+// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
+// upwards. See crbug.com/442912 for more details.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function to make sure
+// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
+// Under ASan longjmp() will attempt to clean up the area between the old and
+// new stack pointers and print a warning that may confuse the user.
+__attribute__((no_sanitize_address))
+#endif
+NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
+ pid_t* ptid,
+ pid_t* ctid,
+ jmp_buf* env) {
+ // We use the libc clone wrapper instead of making the syscall
+ // directly because making the syscall may fail to update the libc's
+ // internal pid cache. The libc interface unfortunately requires
+ // specifying a new stack, so we use setjmp/longjmp to emulate
+ // fork-like behavior.
+ char stack_buf[PTHREAD_STACK_MIN];
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+ defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+ // The stack grows downward.
+ void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+ return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
+}
+#endif // defined(OS_LINUX)
+
} // anonymous namespace
// Functor for |ScopedDIR| (below).
@@ -277,9 +330,13 @@ void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
}
}
-bool LaunchProcess(const std::vector<std::string>& argv,
- const LaunchOptions& options,
- ProcessHandle* process_handle) {
+Process LaunchProcess(const CommandLine& cmdline,
+ const LaunchOptions& options) {
+ return LaunchProcess(cmdline.argv(), options);
+}
+
+Process LaunchProcess(const std::vector<std::string>& argv,
+ const LaunchOptions& options) {
size_t fd_shuffle_size = 0;
if (options.fds_to_remap) {
fd_shuffle_size = options.fds_to_remap->size();
@@ -290,7 +347,12 @@ bool LaunchProcess(const std::vector<std::string>& argv,
fd_shuffle1.reserve(fd_shuffle_size);
fd_shuffle2.reserve(fd_shuffle_size);
- scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]);
+ scoped_ptr<char* []> argv_cstr(new char* [argv.size() + 1]);
+ for (size_t i = 0; i < argv.size(); i++) {
+ argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+ }
+ argv_cstr[argv.size()] = NULL;
+
scoped_ptr<char*[]> new_environ;
char* const empty_environ = NULL;
char* const* old_environ = GetEnvironment();
@@ -303,6 +365,11 @@ bool LaunchProcess(const std::vector<std::string>& argv,
sigfillset(&full_sigset);
const sigset_t orig_sigmask = SetSignalMask(full_sigset);
+ const char* current_directory = nullptr;
+ if (!options.current_directory.empty()) {
+ current_directory = options.current_directory.value().c_str();
+ }
+
pid_t pid;
#if defined(OS_LINUX)
if (options.clone_flags) {
@@ -311,7 +378,17 @@ bool LaunchProcess(const std::vector<std::string>& argv,
// and that signal handling follows the process-creation rules.
RAW_CHECK(
!(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM)));
- pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0);
+
+ // We specify a null ptid and ctid.
+ RAW_CHECK(
+ !(options.clone_flags &
+ (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT_SETTID)));
+
+ // Since we use waitpid, we do not support custom termination signals in the
+ // clone flags.
+ RAW_CHECK((options.clone_flags & 0xff) == 0);
+
+ pid = ForkWithFlags(options.clone_flags | SIGCHLD, nullptr, nullptr);
} else
#endif
{
@@ -325,7 +402,7 @@ bool LaunchProcess(const std::vector<std::string>& argv,
if (pid < 0) {
DPLOG(ERROR) << "fork";
- return false;
+ return Process();
} else if (pid == 0) {
// Child process
@@ -446,11 +523,23 @@ bool LaunchProcess(const std::vector<std::string>& argv,
RAW_LOG(FATAL, "prctl(PR_SET_NO_NEW_PRIVS) failed");
}
}
+
+ if (options.kill_on_parent_death) {
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) {
+ RAW_LOG(ERROR, "prctl(PR_SET_PDEATHSIG) failed");
+ _exit(127);
+ }
+ }
#endif
- for (size_t i = 0; i < argv.size(); i++)
- argv_cstr[i] = const_cast<char*>(argv[i].c_str());
- argv_cstr[argv.size()] = NULL;
+ if (current_directory != nullptr) {
+ RAW_CHECK(chdir(current_directory) == 0);
+ }
+
+ if (options.pre_exec_delegate != nullptr) {
+ options.pre_exec_delegate->RunAsyncSafe();
+ }
+
execvp(argv_cstr[0], argv_cstr.get());
RAW_LOG(ERROR, "LaunchProcess: failed to execvp:");
@@ -465,19 +554,9 @@ bool LaunchProcess(const std::vector<std::string>& argv,
pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
DPCHECK(ret > 0);
}
-
- if (process_handle)
- *process_handle = pid;
}
- return true;
-}
-
-
-bool LaunchProcess(const CommandLine& cmdline,
- const LaunchOptions& options,
- ProcessHandle* process_handle) {
- return LaunchProcess(cmdline.argv(), options, process_handle);
+ return Process(pid);
}
void RaiseProcessToHighPriority() {
@@ -612,7 +691,8 @@ static GetAppOutputInternalResult GetAppOutputInternal(
// Always wait for exit code (even if we know we'll declare
// GOT_MAX_OUTPUT).
- bool success = WaitForExitCode(pid, exit_code);
+ Process process(pid);
+ bool success = process.WaitForExit(exit_code);
// If we stopped because we read as much as we wanted, we return
// GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
@@ -661,4 +741,45 @@ bool GetAppOutputWithExitCode(const CommandLine& cl,
return result == EXECUTE_SUCCESS;
}
+#if defined(OS_LINUX)
+pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
+ const bool clone_tls_used = flags & CLONE_SETTLS;
+ const bool invalid_ctid =
+ (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
+ const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid;
+
+ // We do not support CLONE_VM.
+ const bool clone_vm_used = flags & CLONE_VM;
+
+ if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) {
+ RAW_LOG(FATAL, "Invalid usage of ForkWithFlags");
+ }
+
+ // Valgrind's clone implementation does not support specifiying a child_stack
+ // without CLONE_VM, so we cannot use libc's clone wrapper when running under
+ // Valgrind. As a result, the libc pid cache may be incorrect under Valgrind.
+ // See crbug.com/442817 for more details.
+ if (IsRunningOnValgrind()) {
+ // See kernel/fork.c in Linux. There is different ordering of sys_clone
+ // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options.
+#if defined(ARCH_CPU_X86_64)
+ return syscall(__NR_clone, flags, nullptr, ptid, ctid, nullptr);
+#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \
+ defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)
+ // CONFIG_CLONE_BACKWARDS defined.
+ return syscall(__NR_clone, flags, nullptr, ptid, nullptr, ctid);
+#else
+#error "Unsupported architecture"
+#endif
+ }
+
+ jmp_buf env;
+ if (setjmp(env) == 0) {
+ return CloneAndLongjmpInChild(flags, ptid, ctid, &env);
+ }
+
+ return 0;
+}
+#endif // defined(OS_LINUX)
+
} // namespace base
diff --git a/chromium/base/process/launch_win.cc b/chromium/base/process/launch_win.cc
index a3303a5e085..ebc19b83130 100644
--- a/chromium/base/process/launch_win.cc
+++ b/chromium/base/process/launch_win.cc
@@ -105,9 +105,13 @@ void RouteStdioToConsole() {
std::ios::sync_with_stdio();
}
-bool LaunchProcess(const string16& cmdline,
- const LaunchOptions& options,
- win::ScopedHandle* process_handle) {
+Process LaunchProcess(const CommandLine& cmdline,
+ const LaunchOptions& options) {
+ return LaunchProcess(cmdline.GetCommandLineString(), options);
+}
+
+Process LaunchProcess(const string16& cmdline,
+ const LaunchOptions& options) {
win::StartupInformation startup_info_wrapper;
STARTUPINFO* startup_info = startup_info_wrapper.startup_info();
@@ -119,18 +123,18 @@ bool LaunchProcess(const string16& cmdline,
} else {
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
DLOG(ERROR) << "Specifying handles to inherit requires Vista or later.";
- return false;
+ return Process();
}
if (options.handles_to_inherit->size() >
std::numeric_limits<DWORD>::max() / sizeof(HANDLE)) {
DLOG(ERROR) << "Too many handles to inherit.";
- return false;
+ return Process();
}
if (!startup_info_wrapper.InitializeProcThreadAttributeList(1)) {
DPLOG(ERROR);
- return false;
+ return Process();
}
if (!startup_info_wrapper.UpdateProcThreadAttribute(
@@ -139,7 +143,7 @@ bool LaunchProcess(const string16& cmdline,
static_cast<DWORD>(options.handles_to_inherit->size() *
sizeof(HANDLE)))) {
DPLOG(ERROR);
- return false;
+ return Process();
}
inherit_handles = true;
@@ -184,7 +188,7 @@ bool LaunchProcess(const string16& cmdline,
if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) {
DPLOG(ERROR);
- return false;
+ return Process();
}
BOOL launched =
@@ -197,7 +201,7 @@ bool LaunchProcess(const string16& cmdline,
if (!launched) {
DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
<< std::endl;;
- return false;
+ return Process();
}
} else {
if (!CreateProcess(NULL,
@@ -206,7 +210,7 @@ bool LaunchProcess(const string16& cmdline,
startup_info, &temp_process_info)) {
DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
<< std::endl;;
- return false;
+ return Process();
}
}
base::win::ScopedProcessInformation process_info(temp_process_info);
@@ -215,8 +219,9 @@ bool LaunchProcess(const string16& cmdline,
if (0 == AssignProcessToJobObject(options.job_handle,
process_info.process_handle())) {
DLOG(ERROR) << "Could not AssignProcessToObject.";
- KillProcess(process_info.process_handle(), kProcessKilledExitCode, true);
- return false;
+ Process scoped_process(process_info.TakeProcessHandle());
+ scoped_process.Terminate(kProcessKilledExitCode, true);
+ return Process();
}
ResumeThread(process_info.thread_handle());
@@ -225,28 +230,11 @@ bool LaunchProcess(const string16& cmdline,
if (options.wait)
WaitForSingleObject(process_info.process_handle(), INFINITE);
- // If the caller wants the process handle, we won't close it.
- if (process_handle)
- process_handle->Set(process_info.TakeProcessHandle());
-
- return true;
-}
-
-bool LaunchProcess(const CommandLine& cmdline,
- const LaunchOptions& options,
- ProcessHandle* process_handle) {
- if (!process_handle)
- return LaunchProcess(cmdline.GetCommandLineString(), options, NULL);
-
- win::ScopedHandle process;
- bool rv = LaunchProcess(cmdline.GetCommandLineString(), options, &process);
- *process_handle = process.Take();
- return rv;
+ return Process(process_info.TakeProcessHandle());
}
-bool LaunchElevatedProcess(const CommandLine& cmdline,
- const LaunchOptions& options,
- ProcessHandle* process_handle) {
+Process LaunchElevatedProcess(const CommandLine& cmdline,
+ const LaunchOptions& options) {
const string16 file = cmdline.GetProgram().value();
const string16 arguments = cmdline.GetArgumentsString();
@@ -263,20 +251,13 @@ bool LaunchElevatedProcess(const CommandLine& cmdline,
if (!ShellExecuteEx(&shex_info)) {
DPLOG(ERROR);
- return false;
+ return Process();
}
if (options.wait)
WaitForSingleObject(shex_info.hProcess, INFINITE);
- // If the caller wants the process handle give it to them, otherwise just
- // close it. Closing it does not terminate the process.
- if (process_handle)
- *process_handle = shex_info.hProcess;
- else
- CloseHandle(shex_info.hProcess);
-
- return true;
+ return Process(shex_info.hProcess);
}
bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) {
diff --git a/chromium/base/process/memory.cc b/chromium/base/process/memory.cc
index 1dbc3630703..133a72a0f75 100644
--- a/chromium/base/process/memory.cc
+++ b/chromium/base/process/memory.cc
@@ -2,10 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/debug/alias.h"
+#include "base/logging.h"
#include "base/process/memory.h"
namespace base {
+namespace {
+
+// Breakpad server classifies base::`anonymous namespace'::OnNoMemory as
+// out-of-memory crash.
+NOINLINE void OnNoMemory(size_t size) {
+ size_t tmp_size = size;
+ base::debug::Alias(&tmp_size);
+ LOG(FATAL) << "Out of memory. size=" << tmp_size;
+}
+
+} // namespace
+
+void TerminateBecauseOutOfMemory(size_t size) {
+ OnNoMemory(size);
+}
+
// Defined in memory_mac.mm for Mac.
#if !defined(OS_MACOSX)
@@ -27,4 +45,4 @@ bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
#endif
-}
+} // namespace base
diff --git a/chromium/base/process/memory.h b/chromium/base/process/memory.h
index 100d9c72f43..da27151d1b1 100644
--- a/chromium/base/process/memory.h
+++ b/chromium/base/process/memory.h
@@ -39,6 +39,10 @@ BASE_EXPORT void EnableTerminationOnHeapCorruption();
// Turns on process termination if memory runs out.
BASE_EXPORT void EnableTerminationOnOutOfMemory();
+// Terminates process. Should be called only for out of memory errors.
+// Crash reporting classifies such crashes as OOM.
+BASE_EXPORT void TerminateBecauseOutOfMemory(size_t size);
+
#if defined(OS_WIN)
// Returns the module handle to which an address belongs. The reference count
// of the module is not incremented.
diff --git a/chromium/base/process/memory_mac.mm b/chromium/base/process/memory_mac.mm
index e59e63fa87f..4d719f8054e 100644
--- a/chromium/base/process/memory_mac.mm
+++ b/chromium/base/process/memory_mac.mm
@@ -4,12 +4,6 @@
#include "base/process/memory.h"
-// AddressSanitizer handles heap corruption, and on 64 bit Macs, the malloc
-// system automatically abort()s on heap corruption.
-#if !defined(ADDRESS_SANITIZER) && ARCH_CPU_32_BITS
-#define HANDLE_MEMORY_CORRUPTION_MANUALLY
-#endif
-
#include <CoreFoundation/CoreFoundation.h>
#include <errno.h>
#include <mach/mach.h>
@@ -27,170 +21,12 @@
#include "third_party/apple_apsl/CFBase.h"
#include "third_party/apple_apsl/malloc.h"
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
-#include <dlfcn.h>
-#include <mach-o/nlist.h>
-
-#include "base/threading/thread_local.h"
-#include "third_party/mach_override/mach_override.h"
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
-
namespace base {
-// These are helpers for EnableTerminationOnHeapCorruption, which is a no-op
-// on 64 bit Macs.
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
-namespace {
-
-// Finds the library path for malloc() and thus the libC part of libSystem,
-// which in Lion is in a separate image.
-const char* LookUpLibCPath() {
- const void* addr = reinterpret_cast<void*>(&malloc);
-
- Dl_info info;
- if (dladdr(addr, &info))
- return info.dli_fname;
-
- DLOG(WARNING) << "Could not find image path for malloc()";
- return NULL;
-}
-
-typedef void(*malloc_error_break_t)(void);
-malloc_error_break_t g_original_malloc_error_break = NULL;
-
-// Returns the function pointer for malloc_error_break. This symbol is declared
-// as __private_extern__ and cannot be dlsym()ed. Instead, use nlist() to
-// get it.
-malloc_error_break_t LookUpMallocErrorBreak() {
- const char* lib_c_path = LookUpLibCPath();
- if (!lib_c_path)
- return NULL;
-
- // Only need to look up two symbols, but nlist() requires a NULL-terminated
- // array and takes no count.
- struct nlist nl[3];
- bzero(&nl, sizeof(nl));
-
- // The symbol to find.
- nl[0].n_un.n_name = const_cast<char*>("_malloc_error_break");
-
- // A reference symbol by which the address of the desired symbol will be
- // calculated.
- nl[1].n_un.n_name = const_cast<char*>("_malloc");
-
- int rv = nlist(lib_c_path, nl);
- if (rv != 0 || nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF) {
- return NULL;
- }
-
- // nlist() returns addresses as offsets in the image, not the instruction
- // pointer in memory. Use the known in-memory address of malloc()
- // to compute the offset for malloc_error_break().
- uintptr_t reference_addr = reinterpret_cast<uintptr_t>(&malloc);
- reference_addr -= nl[1].n_value;
- reference_addr += nl[0].n_value;
-
- return reinterpret_cast<malloc_error_break_t>(reference_addr);
-}
-
-// Combines ThreadLocalBoolean with AutoReset. It would be convenient
-// to compose ThreadLocalPointer<bool> with base::AutoReset<bool>, but that
-// would require allocating some storage for the bool.
-class ThreadLocalBooleanAutoReset {
- public:
- ThreadLocalBooleanAutoReset(ThreadLocalBoolean* tlb, bool new_value)
- : scoped_tlb_(tlb),
- original_value_(tlb->Get()) {
- scoped_tlb_->Set(new_value);
- }
- ~ThreadLocalBooleanAutoReset() {
- scoped_tlb_->Set(original_value_);
- }
-
- private:
- ThreadLocalBoolean* scoped_tlb_;
- bool original_value_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset);
-};
-
-base::LazyInstance<ThreadLocalBoolean>::Leaky
- g_unchecked_alloc = LAZY_INSTANCE_INITIALIZER;
-
-// NOTE(shess): This is called when the malloc library noticed that the heap
-// is fubar. Avoid calls which will re-enter the malloc library.
-void CrMallocErrorBreak() {
- g_original_malloc_error_break();
-
- // Out of memory is certainly not heap corruption, and not necessarily
- // something for which the process should be terminated. Leave that decision
- // to the OOM killer.
- if (errno == ENOMEM)
- return;
-
- // The malloc library attempts to log to ASL (syslog) before calling this
- // code, which fails accessing a Unix-domain socket when sandboxed. The
- // failed socket results in writing to a -1 fd, leaving EBADF in errno. If
- // UncheckedMalloc() is on the stack, for large allocations (15k and up) only
- // an OOM failure leads here. Smaller allocations could also arrive here due
- // to freelist corruption, but there is no way to distinguish that from OOM at
- // this point.
- //
- // NOTE(shess): I hypothesize that EPERM case in 10.9 is the same root cause
- // as EBADF. Unfortunately, 10.9's opensource releases don't include malloc
- // source code at this time.
- // <http://crbug.com/312234>
- if ((errno == EBADF || errno == EPERM) && g_unchecked_alloc.Get().Get())
- return;
-
- // A unit test checks this error message, so it needs to be in release builds.
- char buf[1024] =
- "Terminating process due to a potential for future heap corruption: "
- "errno=";
- char errnobuf[] = {
- '0' + ((errno / 100) % 10),
- '0' + ((errno / 10) % 10),
- '0' + (errno % 10),
- '\000'
- };
- COMPILE_ASSERT(ELAST <= 999, errno_too_large_to_encode);
- strlcat(buf, errnobuf, sizeof(buf));
- RAW_LOG(ERROR, buf);
-
- // Crash by writing to NULL+errno to allow analyzing errno from
- // crash dump info (setting a breakpad key would re-enter the malloc
- // library). Max documented errno in intro(2) is actually 102, but
- // it really just needs to be "small" to stay on the right vm page.
- const int kMaxErrno = 256;
- char* volatile death_ptr = NULL;
- death_ptr += std::min(errno, kMaxErrno);
- *death_ptr = '!';
-}
-
-} // namespace
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
-
void EnableTerminationOnHeapCorruption() {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- // Only override once, otherwise CrMallocErrorBreak() will recurse
- // to itself.
- if (g_original_malloc_error_break)
- return;
-
- malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak();
- if (!malloc_error_break) {
- DLOG(WARNING) << "Could not find malloc_error_break";
- return;
- }
-
- mach_error_t err = mach_override_ptr(
- (void*)malloc_error_break,
- (void*)&CrMallocErrorBreak,
- (void**)&g_original_malloc_error_break);
-
- if (err != err_none)
- DLOG(WARNING) << "Could not override malloc_error_break; error = " << err;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
+#if !ARCH_CPU_64_BITS
+ DLOG(WARNING) << "EnableTerminationOnHeapCorruption only works on 64-bit";
+#endif
}
// ------------------------------------------------------------------------
@@ -293,142 +129,106 @@ memalign_type g_old_memalign_purgeable;
void* oom_killer_malloc(struct _malloc_zone_t* zone,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_malloc(zone, size);
if (!result && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
return result;
}
void* oom_killer_calloc(struct _malloc_zone_t* zone,
size_t num_items,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_calloc(zone, num_items, size);
if (!result && num_items && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(num_items * size);
return result;
}
void* oom_killer_valloc(struct _malloc_zone_t* zone,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_valloc(zone, size);
if (!result && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
return result;
}
void oom_killer_free(struct _malloc_zone_t* zone,
void* ptr) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
g_old_free(zone, ptr);
}
void* oom_killer_realloc(struct _malloc_zone_t* zone,
void* ptr,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_realloc(zone, ptr, size);
if (!result && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
return result;
}
void* oom_killer_memalign(struct _malloc_zone_t* zone,
size_t alignment,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_memalign(zone, alignment, size);
// Only die if posix_memalign would have returned ENOMEM, since there are
// other reasons why NULL might be returned (see
// http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
- if (!result && size && alignment >= sizeof(void*)
- && (alignment & (alignment - 1)) == 0) {
- debug::BreakDebugger();
+ if (!result && size && alignment >= sizeof(void*) &&
+ (alignment & (alignment - 1)) == 0) {
+ TerminateBecauseOutOfMemory(size);
}
return result;
}
void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_malloc_purgeable(zone, size);
if (!result && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
return result;
}
void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
size_t num_items,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_calloc_purgeable(zone, num_items, size);
if (!result && num_items && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(num_items * size);
return result;
}
void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_valloc_purgeable(zone, size);
if (!result && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
return result;
}
void oom_killer_free_purgeable(struct _malloc_zone_t* zone,
void* ptr) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
g_old_free_purgeable(zone, ptr);
}
void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
void* ptr,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_realloc_purgeable(zone, ptr, size);
if (!result && size)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
return result;
}
void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
size_t alignment,
size_t size) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
void* result = g_old_memalign_purgeable(zone, alignment, size);
// Only die if posix_memalign would have returned ENOMEM, since there are
// other reasons why NULL might be returned (see
// http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
if (!result && size && alignment >= sizeof(void*)
&& (alignment & (alignment - 1)) == 0) {
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(size);
}
return result;
}
@@ -438,7 +238,7 @@ void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
// === C++ operator new ===
void oom_killer_new() {
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(0);
}
#if !defined(ADDRESS_SANITIZER)
@@ -477,7 +277,7 @@ void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
void* info) {
void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
if (!result)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(alloc_size);
return result;
}
@@ -486,7 +286,7 @@ void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
void* info) {
void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
if (!result)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(alloc_size);
return result;
}
@@ -495,7 +295,7 @@ void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
void* info) {
void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
if (!result)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(alloc_size);
return result;
}
@@ -510,7 +310,7 @@ id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone)
{
id result = g_old_allocWithZone(self, _cmd, zone);
if (!result)
- debug::BreakDebugger();
+ TerminateBecauseOutOfMemory(0);
return result;
}
@@ -521,10 +321,6 @@ bool UncheckedMalloc(size_t size, void** result) {
*result = malloc(size);
#else
if (g_old_malloc) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
- ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true);
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
*result = g_old_malloc(malloc_default_zone(), size);
} else {
*result = malloc(size);
@@ -539,10 +335,6 @@ bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
*result = calloc(num_items, size);
#else
if (g_old_calloc) {
-#if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
- ScopedClearErrno clear_errno;
- ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true);
-#endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY)
*result = g_old_calloc(malloc_default_zone(), num_items, size);
} else {
*result = calloc(num_items, size);
diff --git a/chromium/base/process/memory_unittest.cc b/chromium/base/process/memory_unittest.cc
index afbf5c629c2..0276b495915 100644
--- a/chromium/base/process/memory_unittest.cc
+++ b/chromium/base/process/memory_unittest.cc
@@ -26,6 +26,7 @@
#endif
#if defined(OS_LINUX)
#include <malloc.h>
+#include "base/test/malloc_wrapper.h"
#endif
#if defined(OS_WIN)
@@ -105,37 +106,6 @@ TEST(ProcessMemoryTest, EnableLFH) {
// test suite setup and does not need to be done again, else mach_override
// will fail.
-#if !defined(ADDRESS_SANITIZER)
-// The following code tests the system implementation of malloc() thus no need
-// to test it under AddressSanitizer.
-TEST(ProcessMemoryTest, MacMallocFailureDoesNotTerminate) {
-#if ARCH_CPU_32_BITS
- // The Mavericks malloc library changed in a way which breaks the tricks used
- // to implement EnableTerminationOnOutOfMemory() with UncheckedMalloc() under
- // 32-bit. Under 64-bit the oom_killer code handles this.
- if (base::mac::IsOSMavericksOrLater())
- return;
-#endif
-
- // Test that ENOMEM doesn't crash via CrMallocErrorBreak two ways: the exit
- // code and lack of the error string. The number of bytes is one less than
- // MALLOC_ABSOLUTE_MAX_SIZE, more than which the system early-returns NULL and
- // does not call through malloc_error_break(). See the comment at
- // EnableTerminationOnOutOfMemory() for more information.
- void* buf = NULL;
- ASSERT_EXIT(
- {
- base::EnableTerminationOnOutOfMemory();
-
- buf = malloc(std::numeric_limits<size_t>::max() - (2 * PAGE_SIZE) - 1);
- },
- testing::KilledBySignal(SIGTRAP),
- "\\*\\*\\* error: can't allocate region.*\\n?.*");
-
- base::debug::Alias(buf);
-}
-#endif // !defined(ADDRESS_SANITIZER)
-
TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) {
// Assert that freeing an unallocated pointer will crash the process.
char buf[9];
@@ -150,20 +120,19 @@ TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) {
ASSERT_DEATH(free(buf), "attempting free on address which "
"was not malloc\\(\\)-ed");
#else
- ASSERT_DEATH(free(buf), "being freed.*\\n?\\.*"
- "\\*\\*\\* set a breakpoint in malloc_error_break to debug.*\\n?.*"
- "Terminating process due to a potential for future heap corruption");
-#endif // ARCH_CPU_64_BITS || defined(ADDRESS_SANITIZER)
+ ADD_FAILURE() << "This test is not supported in this build configuration.";
+#endif
}
#endif // defined(OS_MACOSX)
// Android doesn't implement set_new_handler, so we can't use the
-// OutOfMemoryTest cases.
-// OpenBSD does not support these tests either.
+// OutOfMemoryTest cases. OpenBSD does not support these tests either.
+// Don't test these on ASan/TSan/MSan configurations: only test the real
+// allocator.
// TODO(vandebo) make this work on Windows too.
-#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \
- !defined(OS_WIN)
+#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && \
+ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
#if defined(USE_TCMALLOC)
extern "C" {
@@ -171,6 +140,10 @@ int tc_set_new_mode(int mode);
}
#endif // defined(USE_TCMALLOC)
+namespace {
+const char *kOomRegex = "Out of memory";
+} // namespace
+
class OutOfMemoryTest : public testing::Test {
public:
OutOfMemoryTest()
@@ -182,13 +155,9 @@ class OutOfMemoryTest : public testing::Test {
}
#if defined(USE_TCMALLOC)
- virtual void SetUp() override {
- tc_set_new_mode(1);
- }
+ void SetUp() override { tc_set_new_mode(1); }
- virtual void TearDown() override {
- tc_set_new_mode(0);
- }
+ void TearDown() override { tc_set_new_mode(0); }
#endif // defined(USE_TCMALLOC)
protected:
@@ -213,42 +182,42 @@ TEST_F(OutOfMemoryDeathTest, New) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = operator new(test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, NewArray) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = new char[test_size_];
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, Malloc) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = malloc(test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, Realloc) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = realloc(NULL, test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, Calloc) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = calloc(1024, test_size_ / 1024L);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, Valloc) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = valloc(test_size_);
- }, "");
+ }, kOomRegex);
}
#if defined(OS_LINUX)
@@ -258,7 +227,7 @@ TEST_F(OutOfMemoryDeathTest, Pvalloc) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = pvalloc(test_size_);
- }, "");
+ }, kOomRegex);
}
#endif // PVALLOC_AVAILABLE == 1
@@ -266,18 +235,16 @@ TEST_F(OutOfMemoryDeathTest, Memalign) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = memalign(4, test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
// This tests that the run-time symbol resolution is overriding malloc for
- // shared libraries (including libc itself) as well as for our code.
- std::string format = base::StringPrintf("%%%zud", test_size_);
- char *value = NULL;
+ // shared libraries as well as for our code.
ASSERT_DEATH({
- SetUpInDeathAssert();
- EXPECT_EQ(-1, asprintf(&value, format.c_str(), 0));
- }, "");
+ SetUpInDeathAssert();
+ value_ = MallocWrapper(test_size_);
+ }, kOomRegex);
}
#endif // OS_LINUX
@@ -290,7 +257,7 @@ TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
ASSERT_DEATH({
SetUpInDeathAssert();
EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
- }, "");
+ }, kOomRegex);
}
#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
@@ -303,7 +270,7 @@ TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = malloc_zone_malloc(zone, test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
@@ -311,7 +278,7 @@ TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = malloc_zone_realloc(zone, NULL, test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
@@ -319,7 +286,7 @@ TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
@@ -327,7 +294,7 @@ TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = malloc_zone_valloc(zone, test_size_);
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
@@ -335,7 +302,7 @@ TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
ASSERT_DEATH({
SetUpInDeathAssert();
value_ = malloc_zone_memalign(zone, 8, test_size_);
- }, "");
+ }, kOomRegex);
}
// Since these allocation functions take a signed size, it's possible that
@@ -350,7 +317,7 @@ TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
SetUpInDeathAssert();
while ((value_ =
base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
@@ -358,7 +325,7 @@ TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
SetUpInDeathAssert();
while ((value_ =
base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
- }, "");
+ }, kOomRegex);
}
TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
@@ -366,7 +333,7 @@ TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
SetUpInDeathAssert();
while ((value_ =
base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
- }, "");
+ }, kOomRegex);
}
#if !defined(ARCH_CPU_64_BITS)
@@ -378,7 +345,7 @@ TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
ASSERT_DEATH({
SetUpInDeathAssert();
while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
- }, "");
+ }, kOomRegex);
}
#endif // !ARCH_CPU_64_BITS
@@ -390,7 +357,7 @@ class OutOfMemoryHandledTest : public OutOfMemoryTest {
static const size_t kSafeCallocSize = 128;
static const size_t kSafeCallocItems = 4;
- virtual void SetUp() {
+ void SetUp() override {
OutOfMemoryTest::SetUp();
// We enable termination on OOM - just as Chrome does at early
@@ -448,4 +415,5 @@ TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) {
EXPECT_TRUE(value_ == NULL);
}
#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-#endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN)
+#endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) &&
+ // !defined(ADDRESS_SANITIZER)
diff --git a/chromium/base/process/memory_win.cc b/chromium/base/process/memory_win.cc
index 668214ceaf0..fc57b48f1f7 100644
--- a/chromium/base/process/memory_win.cc
+++ b/chromium/base/process/memory_win.cc
@@ -4,6 +4,7 @@
#include "base/process/memory.h"
+#include <new.h>
#include <psapi.h>
#include "base/logging.h"
@@ -13,15 +14,19 @@ namespace base {
namespace {
-void OnNoMemory() {
- // Kill the process. This is important for security, since WebKit doesn't
- // NULL-check many memory allocations. If a malloc fails, returns NULL, and
- // the buffer is then used, it provides a handy mapping of memory starting at
- // address 0 for an attacker to utilize.
+#pragma warning(push)
+#pragma warning(disable: 4702)
+
+int OnNoMemory(size_t) {
+ // Kill the process. This is important for security since most of code
+ // does not check the result of memory allocation.
__debugbreak();
_exit(1);
+ return 0;
}
+#pragma warning(pop)
+
// HeapSetInformation function pointer.
typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
@@ -68,7 +73,8 @@ void EnableTerminationOnHeapCorruption() {
}
void EnableTerminationOnOutOfMemory() {
- std::set_new_handler(&OnNoMemory);
+ _set_new_handler(&OnNoMemory);
+ _set_new_mode(1);
}
HMODULE GetModuleFromAddress(void* address) {
diff --git a/chromium/base/process/process.h b/chromium/base/process/process.h
index 701947491d7..7fb1b69954c 100644
--- a/chromium/base/process/process.h
+++ b/chromium/base/process/process.h
@@ -1,14 +1,15 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_PROCESS_PROCESS_PROCESS_H_
-#define BASE_PROCESS_PROCESS_PROCESS_H_
+#ifndef BASE_PROCESS_PROCESS_H_
+#define BASE_PROCESS_PROCESS_H_
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/move.h"
#include "base/process/process_handle.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -40,7 +41,7 @@ class BASE_EXPORT Process {
Process(RValue other);
// The destructor does not terminate the process.
- ~Process() {}
+ ~Process();
// Move operator= for C++03 move emulation of this type.
Process& operator=(RValue other);
@@ -48,6 +49,26 @@ class BASE_EXPORT Process {
// Returns an object for the current process.
static Process Current();
+ // Returns a Process for the given |pid|.
+ static Process Open(ProcessId pid);
+
+ // Returns a Process for the given |pid|. On Windows the handle is opened
+ // with more access rights and must only be used by trusted code (can read the
+ // address space and duplicate handles).
+ static Process OpenWithExtraPrivileges(ProcessId pid);
+
+#if defined(OS_WIN)
+ // Returns a Process for the given |pid|, using some |desired_access|.
+ // See ::OpenProcess documentation for valid |desired_access|.
+ static Process OpenWithAccess(ProcessId pid, DWORD desired_access);
+#endif
+
+ // Creates an object from a |handle| owned by someone else.
+ // Don't use this for new code. It is only intended to ease the migration to
+ // a strict ownership model.
+ // TODO(rvargas) crbug.com/417532: Remove this code.
+ static Process DeprecatedGetProcessFromHandle(ProcessHandle handle);
+
// Returns true if processes can be backgrounded.
static bool CanBackgroundProcesses();
@@ -62,7 +83,7 @@ class BASE_EXPORT Process {
Process Duplicate() const;
// Get the PID for this process.
- ProcessId pid() const;
+ ProcessId Pid() const;
// Returns true if this process is the current process.
bool is_current() const;
@@ -70,11 +91,40 @@ class BASE_EXPORT Process {
// Close the process handle. This will not terminate the process.
void Close();
- // Terminates the process with extreme prejudice. The given |result_code| will
- // be the exit code of the process.
- // NOTE: On POSIX |result_code| is ignored.
- void Terminate(int result_code);
-
+ // Terminates the process with extreme prejudice. The given |exit_code| will
+ // be the exit code of the process. If |wait| is true, this method will wait
+ // for up to one minute for the process to actually terminate.
+ // Returns true if the process terminates within the allowed time.
+ // NOTE: On POSIX |exit_code| is ignored.
+ bool Terminate(int exit_code, bool wait) const;
+
+ // Waits for the process to exit. Returns true on success.
+ // On POSIX, if the process has been signaled then |exit_code| is set to -1.
+ // On Linux this must be a child process, however on Mac and Windows it can be
+ // any process.
+ bool WaitForExit(int* exit_code);
+
+ // Same as WaitForExit() but only waits for up to |timeout|.
+ bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
+
+#if defined(OS_MACOSX)
+ // The Mac needs a Mach port in order to manipulate a process's priority,
+ // and there's no good way to get that from base given the pid. These Mac
+ // variants of the IsProcessBackgrounded and SetProcessBackgrounded API take
+ // the Mach port for this reason. See crbug.com/460102
+ //
+ // A process is backgrounded when its priority is lower than normal.
+ // Return true if the process with mach port |task_port| is backgrounded,
+ // false otherwise.
+ bool IsProcessBackgrounded(mach_port_t task_port) const;
+
+ // Set the process with the specified mach port as backgrounded. If value is
+ // true, the priority of the process will be lowered. If value is false, the
+ // priority of the process will be made "normal" - equivalent to default
+ // process priority. Returns true if the priority was changed, false
+ // otherwise.
+ bool SetProcessBackgrounded(mach_port_t task_port, bool value);
+#else
// A process is backgrounded when it's priority is lower than normal.
// Return true if this process is backgrounded, false otherwise.
bool IsProcessBackgrounded() const;
@@ -84,7 +134,7 @@ class BASE_EXPORT Process {
// will be made "normal" - equivalent to default process priority.
// Returns true if the priority was changed, false otherwise.
bool SetProcessBackgrounded(bool value);
-
+#endif // defined(OS_MACOSX)
// Returns an integer representing the priority of a process. The meaning
// of this value is OS dependent.
int GetPriority() const;
@@ -100,4 +150,4 @@ class BASE_EXPORT Process {
} // namespace base
-#endif // BASE_PROCESS_PROCESS_PROCESS_H_
+#endif // BASE_PROCESS_PROCESS_H_
diff --git a/chromium/base/process/process_handle.h b/chromium/base/process/process_handle.h
index 6f8094ee80b..77f2c585cfc 100644
--- a/chromium/base/process/process_handle.h
+++ b/chromium/base/process/process_handle.h
@@ -40,47 +40,12 @@ BASE_EXPORT ProcessId GetCurrentProcId();
// Returns the ProcessHandle of the current process.
BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
-// Converts a PID to a process handle. This handle must be closed by
-// CloseProcessHandle when you are done with it. Returns true on success.
-BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
-
-// Converts a PID to a process handle. On Windows the handle is opened
-// with more access rights and must only be used by trusted code.
-// You have to close returned handle using CloseProcessHandle. Returns true
-// on success.
-// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the
-// more specific OpenProcessHandleWithAccess method and delete this.
-BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid,
- ProcessHandle* handle);
-
-// Converts a PID to a process handle using the desired access flags. Use a
-// combination of the kProcessAccess* flags defined above for |access_flags|.
-BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid,
- uint32 access_flags,
- ProcessHandle* handle);
-
-// Closes the process handle opened by OpenProcessHandle.
-BASE_EXPORT void CloseProcessHandle(ProcessHandle process);
-
// Returns the unique ID for the specified process. This is functionally the
// same as Windows' GetProcessId(), but works on versions of Windows before
// Win XP SP1 as well.
+// DEPRECATED. New code should be using Process::Pid() instead.
BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
-#if defined(OS_WIN)
-enum IntegrityLevel {
- INTEGRITY_UNKNOWN,
- LOW_INTEGRITY,
- MEDIUM_INTEGRITY,
- HIGH_INTEGRITY,
-};
-// Determine the integrity level of the specified process. Returns false
-// if the system does not support integrity levels (pre-Vista) or in the case
-// of an underlying system failure.
-BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process,
- IntegrityLevel* level);
-#endif
-
#if defined(OS_POSIX)
// Returns the path to the executable of the given process.
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
diff --git a/chromium/base/process/process_handle_posix.cc b/chromium/base/process/process_handle_posix.cc
index 4013254a5c2..4e332df1a0f 100644
--- a/chromium/base/process/process_handle_posix.cc
+++ b/chromium/base/process/process_handle_posix.cc
@@ -16,32 +16,6 @@ ProcessHandle GetCurrentProcessHandle() {
return GetCurrentProcId();
}
-bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
- // On Posix platforms, process handles are the same as PIDs, so we
- // don't need to do anything.
- *handle = pid;
- return true;
-}
-
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
- // On POSIX permissions are checked for each operation on process,
- // not when opening a "handle".
- return OpenProcessHandle(pid, handle);
-}
-
-bool OpenProcessHandleWithAccess(ProcessId pid,
- uint32 access_flags,
- ProcessHandle* handle) {
- // On POSIX permissions are checked for each operation on process,
- // not when opening a "handle".
- return OpenProcessHandle(pid, handle);
-}
-
-void CloseProcessHandle(ProcessHandle process) {
- // See OpenProcessHandle, nothing to do.
- return;
-}
-
ProcessId GetProcId(ProcessHandle process) {
return process;
}
diff --git a/chromium/base/process/process_handle_win.cc b/chromium/base/process/process_handle_win.cc
index 3bc3a125e0d..f2ffff8e882 100644
--- a/chromium/base/process/process_handle_win.cc
+++ b/chromium/base/process/process_handle_win.cc
@@ -20,107 +20,9 @@ ProcessHandle GetCurrentProcessHandle() {
return ::GetCurrentProcess();
}
-bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
- // We try to limit privileges granted to the handle. If you need this
- // for test code, consider using OpenPrivilegedProcessHandle instead of
- // adding more privileges here.
- ProcessHandle result = OpenProcess(PROCESS_TERMINATE |
- PROCESS_QUERY_INFORMATION |
- SYNCHRONIZE,
- FALSE, pid);
-
- if (result == NULL)
- return false;
-
- *handle = result;
- return true;
-}
-
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
- ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
- PROCESS_TERMINATE |
- PROCESS_QUERY_INFORMATION |
- PROCESS_VM_READ |
- SYNCHRONIZE,
- FALSE, pid);
-
- if (result == NULL)
- return false;
-
- *handle = result;
- return true;
-}
-
-bool OpenProcessHandleWithAccess(ProcessId pid,
- uint32 access_flags,
- ProcessHandle* handle) {
- ProcessHandle result = OpenProcess(access_flags, FALSE, pid);
-
- if (result == NULL)
- return false;
-
- *handle = result;
- return true;
-}
-
-void CloseProcessHandle(ProcessHandle process) {
- CloseHandle(process);
-}
-
ProcessId GetProcId(ProcessHandle process) {
// This returns 0 if we have insufficient rights to query the process handle.
return GetProcessId(process);
}
-bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
- if (!level)
- return false;
-
- if (win::GetVersion() < base::win::VERSION_VISTA)
- return false;
-
- HANDLE process_token;
- if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE,
- &process_token))
- return false;
-
- win::ScopedHandle scoped_process_token(process_token);
-
- DWORD token_info_length = 0;
- if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
- &token_info_length) ||
- GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return false;
-
- scoped_ptr<char[]> token_label_bytes(new char[token_info_length]);
- if (!token_label_bytes.get())
- return false;
-
- TOKEN_MANDATORY_LABEL* token_label =
- reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
- if (!token_label)
- return false;
-
- if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
- token_info_length, &token_info_length))
- return false;
-
- DWORD integrity_level = *GetSidSubAuthority(token_label->Label.Sid,
- (DWORD)(UCHAR)(*GetSidSubAuthorityCount(token_label->Label.Sid)-1));
-
- if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID) {
- *level = LOW_INTEGRITY;
- } else if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
- integrity_level < SECURITY_MANDATORY_HIGH_RID) {
- *level = MEDIUM_INTEGRITY;
- } else if (integrity_level >= SECURITY_MANDATORY_HIGH_RID) {
- *level = HIGH_INTEGRITY;
- } else {
- NOTREACHED();
- return false;
- }
-
- return true;
-}
-
} // namespace base
diff --git a/chromium/base/process/process_info.h b/chromium/base/process/process_info.h
index e9e7b4e8151..85f204d04cf 100644
--- a/chromium/base/process/process_info.h
+++ b/chromium/base/process/process_info.h
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_PROCESS_PROCESS_PROCESS_INFO_H_
-#define BASE_PROCESS_PROCESS_PROCESS_INFO_H_
+#ifndef BASE_PROCESS_PROCESS_INFO_H_
+#define BASE_PROCESS_PROCESS_INFO_H_
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "build/build_config.h"
namespace base {
@@ -20,6 +21,24 @@ class BASE_EXPORT CurrentProcessInfo {
static const Time CreationTime();
};
+#if defined(OS_WIN)
+
+enum IntegrityLevel {
+ INTEGRITY_UNKNOWN,
+ LOW_INTEGRITY,
+ MEDIUM_INTEGRITY,
+ HIGH_INTEGRITY,
+};
+
+// Returns the integrity level of the process. Returns INTEGRITY_UNKNOWN if the
+// system does not support integrity levels (pre-Vista) or in the case of an
+// underlying system failure.
+BASE_EXPORT IntegrityLevel GetCurrentProcessIntegrityLevel();
+
+#endif // defined(OS_WIN)
+
+
+
} // namespace base
-#endif // BASE_PROCESS_PROCESS_PROCESS_INFO_H_
+#endif // BASE_PROCESS_PROCESS_INFO_H_
diff --git a/chromium/base/process/process_info_win.cc b/chromium/base/process/process_info_win.cc
index b930ae6dd88..2b9c40653fd 100644
--- a/chromium/base/process/process_info_win.cc
+++ b/chromium/base/process/process_info_win.cc
@@ -7,11 +7,14 @@
#include <windows.h>
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
namespace base {
-//static
+// static
const Time CurrentProcessInfo::CreationTime() {
FILETIME creation_time = {};
FILETIME ignore = {};
@@ -22,4 +25,55 @@ const Time CurrentProcessInfo::CreationTime() {
return Time::FromFileTime(creation_time);
}
+IntegrityLevel GetCurrentProcessIntegrityLevel() {
+ if (win::GetVersion() < base::win::VERSION_VISTA)
+ return INTEGRITY_UNKNOWN;
+
+ HANDLE process_token;
+ if (!::OpenProcessToken(::GetCurrentProcess(),
+ TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
+ return INTEGRITY_UNKNOWN;
+ }
+ win::ScopedHandle scoped_process_token(process_token);
+
+ DWORD token_info_length = 0;
+ if (::GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
+ &token_info_length) ||
+ ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ return INTEGRITY_UNKNOWN;
+ }
+
+ scoped_ptr<char[]> token_label_bytes(new char[token_info_length]);
+ if (!token_label_bytes.get())
+ return INTEGRITY_UNKNOWN;
+
+ TOKEN_MANDATORY_LABEL* token_label =
+ reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
+ if (!token_label)
+ return INTEGRITY_UNKNOWN;
+
+ if (!::GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
+ token_info_length, &token_info_length)) {
+ return INTEGRITY_UNKNOWN;
+ }
+
+ DWORD integrity_level = *::GetSidSubAuthority(
+ token_label->Label.Sid,
+ static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid)-1));
+
+ if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID)
+ return LOW_INTEGRITY;
+
+ if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
+ integrity_level < SECURITY_MANDATORY_HIGH_RID) {
+ return MEDIUM_INTEGRITY;
+ }
+
+ if (integrity_level >= SECURITY_MANDATORY_HIGH_RID)
+ return HIGH_INTEGRITY;
+
+ NOTREACHED();
+ return INTEGRITY_UNKNOWN;
+}
+
} // namespace base
diff --git a/chromium/base/process/process_iterator.h b/chromium/base/process/process_iterator.h
index bdd07c698de..ec6500e653c 100644
--- a/chromium/base/process/process_iterator.h
+++ b/chromium/base/process/process_iterator.h
@@ -36,26 +36,6 @@ struct ProcessEntry : public PROCESSENTRY32 {
ProcessId parent_pid() const { return th32ParentProcessID; }
const wchar_t* exe_file() const { return szExeFile; }
};
-
-// Process access masks. These constants provide platform-independent
-// definitions for the standard Windows access masks.
-// See http://msdn.microsoft.com/en-us/library/ms684880(VS.85).aspx for
-// the specific semantics of each mask value.
-const uint32 kProcessAccessTerminate = PROCESS_TERMINATE;
-const uint32 kProcessAccessCreateThread = PROCESS_CREATE_THREAD;
-const uint32 kProcessAccessSetSessionId = PROCESS_SET_SESSIONID;
-const uint32 kProcessAccessVMOperation = PROCESS_VM_OPERATION;
-const uint32 kProcessAccessVMRead = PROCESS_VM_READ;
-const uint32 kProcessAccessVMWrite = PROCESS_VM_WRITE;
-const uint32 kProcessAccessDuplicateHandle = PROCESS_DUP_HANDLE;
-const uint32 kProcessAccessCreateProcess = PROCESS_CREATE_PROCESS;
-const uint32 kProcessAccessSetQuota = PROCESS_SET_QUOTA;
-const uint32 kProcessAccessSetInformation = PROCESS_SET_INFORMATION;
-const uint32 kProcessAccessQueryInformation = PROCESS_QUERY_INFORMATION;
-const uint32 kProcessAccessSuspendResume = PROCESS_SUSPEND_RESUME;
-const uint32 kProcessAccessQueryLimitedInfomation =
- PROCESS_QUERY_LIMITED_INFORMATION;
-const uint32 kProcessAccessWaitForTermination = SYNCHRONIZE;
#elif defined(OS_POSIX)
struct BASE_EXPORT ProcessEntry {
ProcessEntry();
@@ -75,23 +55,6 @@ struct BASE_EXPORT ProcessEntry {
std::string exe_file_;
std::vector<std::string> cmd_line_args_;
};
-
-// Process access masks. They are not used on Posix because access checking
-// does not happen during handle creation.
-const uint32 kProcessAccessTerminate = 0;
-const uint32 kProcessAccessCreateThread = 0;
-const uint32 kProcessAccessSetSessionId = 0;
-const uint32 kProcessAccessVMOperation = 0;
-const uint32 kProcessAccessVMRead = 0;
-const uint32 kProcessAccessVMWrite = 0;
-const uint32 kProcessAccessDuplicateHandle = 0;
-const uint32 kProcessAccessCreateProcess = 0;
-const uint32 kProcessAccessSetQuota = 0;
-const uint32 kProcessAccessSetInformation = 0;
-const uint32 kProcessAccessQueryInformation = 0;
-const uint32 kProcessAccessSuspendResume = 0;
-const uint32 kProcessAccessQueryLimitedInfomation = 0;
-const uint32 kProcessAccessWaitForTermination = 0;
#endif // defined(OS_POSIX)
// Used to filter processes by process ID.
diff --git a/chromium/base/process/process_linux.cc b/chromium/base/process/process_linux.cc
index 59ee288f880..88a310eccdb 100644
--- a/chromium/base/process/process_linux.cc
+++ b/chromium/base/process/process_linux.cc
@@ -103,7 +103,7 @@ bool Process::IsProcessBackgrounded() const {
&proc)) {
std::vector<std::string> proc_parts;
base::SplitString(proc, ':', &proc_parts);
- DCHECK(proc_parts.size() == 3);
+ DCHECK_EQ(proc_parts.size(), 3u);
bool ret = proc_parts[2] == std::string(kBackground);
return ret;
} else {
diff --git a/chromium/base/process/process_mac.cc b/chromium/base/process/process_mac.cc
new file mode 100644
index 00000000000..1913cc378e8
--- /dev/null
+++ b/chromium/base/process/process_mac.cc
@@ -0,0 +1,128 @@
+// Copyright 2015 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/process/process.h"
+
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+
+#include <mach/mach.h>
+
+// The following was added to <mach/task_policy.h> after 10.8.
+// TODO(shrike): Remove the TASK_OVERRIDE_QOS_POLICY ifndef once builders
+// reach 10.9 or higher.
+#ifndef TASK_OVERRIDE_QOS_POLICY
+
+#define TASK_OVERRIDE_QOS_POLICY 9
+
+typedef struct task_category_policy task_category_policy_data_t;
+typedef struct task_category_policy* task_category_policy_t;
+
+enum task_latency_qos {
+ LATENCY_QOS_TIER_UNSPECIFIED = 0x0,
+ LATENCY_QOS_TIER_0 = ((0xFF << 16) | 1),
+ LATENCY_QOS_TIER_1 = ((0xFF << 16) | 2),
+ LATENCY_QOS_TIER_2 = ((0xFF << 16) | 3),
+ LATENCY_QOS_TIER_3 = ((0xFF << 16) | 4),
+ LATENCY_QOS_TIER_4 = ((0xFF << 16) | 5),
+ LATENCY_QOS_TIER_5 = ((0xFF << 16) | 6)
+};
+typedef integer_t task_latency_qos_t;
+enum task_throughput_qos {
+ THROUGHPUT_QOS_TIER_UNSPECIFIED = 0x0,
+ THROUGHPUT_QOS_TIER_0 = ((0xFE << 16) | 1),
+ THROUGHPUT_QOS_TIER_1 = ((0xFE << 16) | 2),
+ THROUGHPUT_QOS_TIER_2 = ((0xFE << 16) | 3),
+ THROUGHPUT_QOS_TIER_3 = ((0xFE << 16) | 4),
+ THROUGHPUT_QOS_TIER_4 = ((0xFE << 16) | 5),
+ THROUGHPUT_QOS_TIER_5 = ((0xFE << 16) | 6),
+};
+
+#define LATENCY_QOS_LAUNCH_DEFAULT_TIER LATENCY_QOS_TIER_3
+#define THROUGHPUT_QOS_LAUNCH_DEFAULT_TIER THROUGHPUT_QOS_TIER_3
+
+typedef integer_t task_throughput_qos_t;
+
+struct task_qos_policy {
+ task_latency_qos_t task_latency_qos_tier;
+ task_throughput_qos_t task_throughput_qos_tier;
+};
+
+typedef struct task_qos_policy* task_qos_policy_t;
+#define TASK_QOS_POLICY_COUNT \
+ ((mach_msg_type_number_t)(sizeof(struct task_qos_policy) / sizeof(integer_t)))
+
+#endif // TASK_OVERRIDE_QOS_POLICY
+
+namespace base {
+
+bool Process::CanBackgroundProcesses() {
+ return true;
+}
+
+bool Process::IsProcessBackgrounded(mach_port_t task_port) const {
+ // See SetProcessBackgrounded().
+ DCHECK(IsValid());
+ DCHECK_NE(task_port, TASK_NULL);
+
+ task_category_policy_data_t category_policy;
+ mach_msg_type_number_t task_info_count = TASK_CATEGORY_POLICY_COUNT;
+ boolean_t get_default = FALSE;
+
+ kern_return_t result =
+ task_policy_get(task_port, TASK_CATEGORY_POLICY,
+ reinterpret_cast<task_policy_t>(&category_policy),
+ &task_info_count, &get_default);
+ MACH_LOG_IF(ERROR, result != KERN_SUCCESS, result) <<
+ "task_policy_get TASK_CATEGORY_POLICY";
+
+ if (result == KERN_SUCCESS && get_default == FALSE) {
+ return category_policy.role == TASK_BACKGROUND_APPLICATION;
+ }
+ return false;
+}
+
+bool Process::SetProcessBackgrounded(mach_port_t task_port, bool background) {
+ DCHECK(IsValid());
+ DCHECK_NE(task_port, TASK_NULL);
+
+ if (!CanBackgroundProcesses()) {
+ return false;
+ } else if (IsProcessBackgrounded(task_port) == background) {
+ return true;
+ }
+
+ task_category_policy category_policy;
+ category_policy.role =
+ background ? TASK_BACKGROUND_APPLICATION : TASK_FOREGROUND_APPLICATION;
+ kern_return_t result =
+ task_policy_set(task_port, TASK_CATEGORY_POLICY,
+ reinterpret_cast<task_policy_t>(&category_policy),
+ TASK_CATEGORY_POLICY_COUNT);
+
+ if (result != KERN_SUCCESS) {
+ MACH_LOG(ERROR, result) << "task_policy_set TASK_CATEGORY_POLICY";
+ return false;
+ } else if (!mac::IsOSMavericksOrLater()) {
+ return true;
+ }
+
+ // Latency QoS regulates timer throttling/accuracy. Select default tier
+ // on foreground because precise timer firing isn't needed.
+ struct task_qos_policy qos_policy = {
+ background ? LATENCY_QOS_TIER_5 : LATENCY_QOS_TIER_UNSPECIFIED,
+ background ? THROUGHPUT_QOS_TIER_5 : THROUGHPUT_QOS_TIER_UNSPECIFIED
+ };
+ result = task_policy_set(task_port, TASK_OVERRIDE_QOS_POLICY,
+ reinterpret_cast<task_policy_t>(&qos_policy),
+ TASK_QOS_POLICY_COUNT);
+ if (result != KERN_SUCCESS) {
+ MACH_LOG(ERROR, result) << "task_policy_set TASK_OVERRIDE_QOS_POLICY";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace base
diff --git a/chromium/base/process/process_metrics.cc b/chromium/base/process/process_metrics.cc
index 2edd9c755de..e4863391076 100644
--- a/chromium/base/process/process_metrics.cc
+++ b/chromium/base/process/process_metrics.cc
@@ -33,11 +33,11 @@ scoped_ptr<Value> SystemMetrics::ToValue() const {
res->SetInteger("committed_memory", static_cast<int>(committed_memory_));
#if defined(OS_LINUX) || defined(OS_ANDROID)
- res->Set("meminfo", memory_info_.ToValue().release());
- res->Set("diskinfo", disk_info_.ToValue().release());
+ res->Set("meminfo", memory_info_.ToValue());
+ res->Set("diskinfo", disk_info_.ToValue());
#endif
#if defined(OS_CHROMEOS)
- res->Set("swapinfo", swap_info_.ToValue().release());
+ res->Set("swapinfo", swap_info_.ToValue());
#endif
return res.Pass();
diff --git a/chromium/base/process/process_metrics.h b/chromium/base/process/process_metrics.h
index 3eb3604b7a3..5916b94148c 100644
--- a/chromium/base/process/process_metrics.h
+++ b/chromium/base/process/process_metrics.h
@@ -85,17 +85,6 @@ struct CommittedKBytes {
size_t image;
};
-// Free memory (Megabytes marked as free) in the 2G process address space.
-// total : total amount in megabytes marked as free. Maximum value is 2048.
-// largest : size of the largest contiguous amount of memory found. It is
-// always smaller or equal to FreeMBytes::total.
-// largest_ptr: starting address of the largest memory block.
-struct FreeMBytes {
- size_t total;
- size_t largest;
- void* largest_ptr;
-};
-
// Convert a POSIX timeval to microseconds.
BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv);
@@ -154,6 +143,14 @@ class BASE_EXPORT ProcessMetrics {
// usage in bytes, as per definition of WorkingSetBytes.
bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
+#if defined(OS_MACOSX)
+ // Fills both CommitedKBytes and WorkingSetKBytes in a single operation. This
+ // is more efficient on Mac OS X, as the two can be retrieved with a single
+ // system call.
+ bool GetCommittedAndWorkingSetKBytes(CommittedKBytes* usage,
+ WorkingSetKBytes* ws_usage) const;
+#endif
+
// Returns the CPU usage in percent since the last time this method or
// GetPlatformIndependentCPUUsage() was called. The first time this method
// is called it returns 0 and will return the actual CPU info on subsequent
@@ -231,10 +228,13 @@ class BASE_EXPORT ProcessMetrics {
// Returns 0 if it can't compute the commit charge.
BASE_EXPORT size_t GetSystemCommitCharge();
+// Returns the number of bytes in a memory page.
+BASE_EXPORT size_t GetPageSize();
+
#if defined(OS_POSIX)
// Returns the maximum number of file descriptors that can be open by a process
// at once. If the number is unavailable, a conservative best guess is returned.
-size_t GetMaxFds();
+BASE_EXPORT size_t GetMaxFds();
// Sets the file descriptor soft limit to |max_descriptors| or the OS hard
// limit, whichever is lower.
diff --git a/chromium/base/process/process_metrics_ios.cc b/chromium/base/process/process_metrics_ios.cc
index 405c373c9fd..07f2c8de1d4 100644
--- a/chromium/base/process/process_metrics_ios.cc
+++ b/chromium/base/process/process_metrics_ios.cc
@@ -6,6 +6,8 @@
#include <mach/task.h>
+#include "base/logging.h"
+
namespace base {
namespace {
@@ -30,6 +32,11 @@ ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
return new ProcessMetrics(process);
}
+double ProcessMetrics::GetCPUUsage() {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
size_t ProcessMetrics::GetPagefileUsage() const {
task_basic_info_64 task_info_data;
if (!GetTaskInfo(&task_info_data))
@@ -65,4 +72,14 @@ void SetFdLimit(unsigned int max_descriptors) {
// Unimplemented.
}
+size_t GetPageSize() {
+ return getpagesize();
+}
+
+// Bytes committed by the system.
+size_t GetSystemCommitCharge() {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
} // namespace base
diff --git a/chromium/base/process/process_metrics_linux.cc b/chromium/base/process/process_metrics_linux.cc
index e8db571a317..2d54c4c7265 100644
--- a/chromium/base/process/process_metrics_linux.cc
+++ b/chromium/base/process/process_metrics_linux.cc
@@ -399,17 +399,36 @@ size_t GetSystemCommitCharge() {
return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
}
-// Exposed for testing.
int ParseProcStatCPU(const std::string& input) {
- std::vector<std::string> proc_stats;
- if (!internal::ParseProcStats(input, &proc_stats))
+ // |input| may be empty if the process disappeared somehow.
+ // e.g. http://crbug.com/145811.
+ if (input.empty())
return -1;
- if (proc_stats.size() <= internal::VM_STIME)
+ size_t start = input.find_last_of(')');
+ if (start == input.npos)
return -1;
- int utime = GetProcStatsFieldAsInt64(proc_stats, internal::VM_UTIME);
- int stime = GetProcStatsFieldAsInt64(proc_stats, internal::VM_STIME);
- return utime + stime;
+
+ // Number of spaces remaining until reaching utime's index starting after the
+ // last ')'.
+ int num_spaces_remaining = internal::VM_UTIME - 1;
+
+ size_t i = start;
+ while ((i = input.find(' ', i + 1)) != input.npos) {
+ // Validate the assumption that there aren't any contiguous spaces
+ // in |input| before utime.
+ DCHECK_NE(input[i - 1], ' ');
+ if (--num_spaces_remaining == 0) {
+ int utime = 0;
+ int stime = 0;
+ if (sscanf(&input.data()[i], "%d %d", &utime, &stime) != 2)
+ return -1;
+
+ return utime + stime;
+ }
+ }
+
+ return -1;
}
const char kProcSelfExe[] = "/proc/self/exe";
@@ -650,13 +669,13 @@ bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
}
#if defined(OS_CHROMEOS)
- // Report on Chrome OS GEM object graphics memory. /var/run/debugfs_gpu is a
+ // Report on Chrome OS GEM object graphics memory. /run/debugfs_gpu is a
// bind mount into /sys/kernel/debug and synchronously reading the in-memory
// files in /sys is fast.
#if defined(ARCH_CPU_ARM_FAMILY)
- FilePath geminfo_file("/var/run/debugfs_gpu/exynos_gem_objects");
+ FilePath geminfo_file("/run/debugfs_gpu/exynos_gem_objects");
#else
- FilePath geminfo_file("/var/run/debugfs_gpu/i915_gem_objects");
+ FilePath geminfo_file("/run/debugfs_gpu/i915_gem_objects");
#endif
std::string geminfo_data;
meminfo->gem_objects = -1;
diff --git a/chromium/base/process/process_metrics_mac.cc b/chromium/base/process/process_metrics_mac.cc
index a07d3cd1049..f84b435a109 100644
--- a/chromium/base/process/process_metrics_mac.cc
+++ b/chromium/base/process/process_metrics_mac.cc
@@ -209,15 +209,32 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
}
void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
+ WorkingSetKBytes unused;
+ if (!GetCommittedAndWorkingSetKBytes(usage, &unused)) {
+ *usage = CommittedKBytes();
+ }
}
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
- size_t priv = GetWorkingSetSize();
- if (!priv)
+ CommittedKBytes unused;
+ return GetCommittedAndWorkingSetKBytes(&unused, ws_usage);
+}
+
+bool ProcessMetrics::GetCommittedAndWorkingSetKBytes(
+ CommittedKBytes* usage,
+ WorkingSetKBytes* ws_usage) const {
+ task_basic_info_64 task_info_data;
+ if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
return false;
- ws_usage->priv = priv / 1024;
+
+ usage->priv = task_info_data.virtual_size / 1024;
+ usage->mapped = 0;
+ usage->image = 0;
+
+ ws_usage->priv = task_info_data.resident_size / 1024;
ws_usage->shareable = 0;
ws_usage->shared = 0;
+
return true;
}
diff --git a/chromium/base/process/process_metrics_posix.cc b/chromium/base/process/process_metrics_posix.cc
index ea79d7348ff..42b3f2d6655 100644
--- a/chromium/base/process/process_metrics_posix.cc
+++ b/chromium/base/process/process_metrics_posix.cc
@@ -12,9 +12,8 @@
namespace base {
int64 TimeValToMicroseconds(const struct timeval& tv) {
- static const int kMicrosecondsPerSecond = 1000000;
int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow.
- ret *= kMicrosecondsPerSecond;
+ ret *= Time::kMicrosecondsPerSecond;
ret += tv.tv_usec;
return ret;
}
@@ -69,4 +68,8 @@ void SetFdLimit(unsigned int max_descriptors) {
}
}
+size_t GetPageSize() {
+ return getpagesize();
+}
+
} // namespace base
diff --git a/chromium/base/process/process_metrics_unittest.cc b/chromium/base/process/process_metrics_unittest.cc
index 69f5e837cb9..76767b09a95 100644
--- a/chromium/base/process/process_metrics_unittest.cc
+++ b/chromium/base/process/process_metrics_unittest.cc
@@ -143,29 +143,29 @@ TEST_F(SystemMetricsTest, ParseMeminfo) {
"Hugepagesize: 4096 kB\n";
EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo));
- EXPECT_TRUE(meminfo.total == 3981504);
- EXPECT_TRUE(meminfo.free == 140764);
- EXPECT_TRUE(meminfo.buffers == 116480);
- EXPECT_TRUE(meminfo.cached == 406160);
- EXPECT_TRUE(meminfo.active_anon == 2972352);
- EXPECT_TRUE(meminfo.active_file == 179688);
- EXPECT_TRUE(meminfo.inactive_anon == 270108);
- EXPECT_TRUE(meminfo.inactive_file == 202748);
- EXPECT_TRUE(meminfo.swap_total == 5832280);
- EXPECT_TRUE(meminfo.swap_free == 3672368);
- EXPECT_TRUE(meminfo.dirty == 184);
+ EXPECT_EQ(meminfo.total, 3981504);
+ EXPECT_EQ(meminfo.free, 140764);
+ EXPECT_EQ(meminfo.buffers, 116480);
+ EXPECT_EQ(meminfo.cached, 406160);
+ EXPECT_EQ(meminfo.active_anon, 2972352);
+ EXPECT_EQ(meminfo.active_file, 179688);
+ EXPECT_EQ(meminfo.inactive_anon, 270108);
+ EXPECT_EQ(meminfo.inactive_file, 202748);
+ EXPECT_EQ(meminfo.swap_total, 5832280);
+ EXPECT_EQ(meminfo.swap_free, 3672368);
+ EXPECT_EQ(meminfo.dirty, 184);
#if defined(OS_CHROMEOS)
- EXPECT_TRUE(meminfo.shmem == 140204);
- EXPECT_TRUE(meminfo.slab == 54212);
+ EXPECT_EQ(meminfo.shmem, 140204);
+ EXPECT_EQ(meminfo.slab, 54212);
#endif
EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo));
- EXPECT_TRUE(meminfo.total == 255908);
- EXPECT_TRUE(meminfo.free == 69936);
- EXPECT_TRUE(meminfo.buffers == 15812);
- EXPECT_TRUE(meminfo.cached == 115124);
- EXPECT_TRUE(meminfo.swap_total == 524280);
- EXPECT_TRUE(meminfo.swap_free == 524200);
- EXPECT_TRUE(meminfo.dirty == 4);
+ EXPECT_EQ(meminfo.total, 255908);
+ EXPECT_EQ(meminfo.free, 69936);
+ EXPECT_EQ(meminfo.buffers, 15812);
+ EXPECT_EQ(meminfo.cached, 115124);
+ EXPECT_EQ(meminfo.swap_total, 524280);
+ EXPECT_EQ(meminfo.swap_free, 524200);
+ EXPECT_EQ(meminfo.dirty, 4);
}
TEST_F(SystemMetricsTest, ParseVmstat) {
@@ -260,13 +260,13 @@ TEST_F(SystemMetricsTest, ParseVmstat) {
"pgrefill_high 0\n"
"pgrefill_movable 0\n";
EXPECT_TRUE(ParseProcVmstat(valid_input1, &meminfo));
- EXPECT_TRUE(meminfo.pswpin == 179);
- EXPECT_TRUE(meminfo.pswpout == 406);
- EXPECT_TRUE(meminfo.pgmajfault == 487192);
+ EXPECT_EQ(meminfo.pswpin, 179);
+ EXPECT_EQ(meminfo.pswpout, 406);
+ EXPECT_EQ(meminfo.pgmajfault, 487192);
EXPECT_TRUE(ParseProcVmstat(valid_input2, &meminfo));
- EXPECT_TRUE(meminfo.pswpin == 12);
- EXPECT_TRUE(meminfo.pswpout == 901);
- EXPECT_TRUE(meminfo.pgmajfault == 2023);
+ EXPECT_EQ(meminfo.pswpin, 12);
+ EXPECT_EQ(meminfo.pswpout, 901);
+ EXPECT_EQ(meminfo.pgmajfault, 2023);
}
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
@@ -323,6 +323,17 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
+
+ // Some weird long-running process with a weird name that I created for the
+ // purposes of this test.
+ const char kWeirdNameStat[] = "26115 (Hello) You ())) ) R 24614 26115 24614"
+ " 34839 26115 4218880 227 0 0 0 "
+ "5186 11 0 0 "
+ "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 "
+ "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
+ "6295056 6295616 16519168 140735857770710 140735857770737 "
+ "140735857770737 140735857774557 0";
+ EXPECT_EQ(5186 + 11, base::ParseProcStatCPU(kWeirdNameStat));
}
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
diff --git a/chromium/base/process/process_metrics_win.cc b/chromium/base/process/process_metrics_win.cc
index 16db44f63f6..1dd97e629cf 100644
--- a/chromium/base/process/process_metrics_win.cc
+++ b/chromium/base/process/process_metrics_win.cc
@@ -284,4 +284,8 @@ size_t GetSystemCommitCharge() {
return (info.CommitTotal * system_info.dwPageSize) / 1024;
}
+size_t GetPageSize() {
+ return PAGESIZE_KB * 1024;
+}
+
} // namespace base
diff --git a/chromium/base/process/process_posix.cc b/chromium/base/process/process_posix.cc
index ea8fd8cea1e..8037da3ac6e 100644
--- a/chromium/base/process/process_posix.cc
+++ b/chromium/base/process/process_posix.cc
@@ -1,20 +1,217 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/process/process.h"
#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
+#include <sys/wait.h>
+#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#if defined(OS_MACOSX)
+#include <sys/event.h>
+#endif
+
+namespace {
+
+#if !defined(OS_NACL_NONSFI)
+
+bool WaitpidWithTimeout(base::ProcessHandle handle,
+ int* status,
+ base::TimeDelta wait) {
+ // This POSIX version of this function only guarantees that we wait no less
+ // than |wait| for the process to exit. The child process may
+ // exit sometime before the timeout has ended but we may still block for up
+ // to 256 milliseconds after the fact.
+ //
+ // waitpid() has no direct support on POSIX for specifying a timeout, you can
+ // either ask it to block indefinitely or return immediately (WNOHANG).
+ // When a child process terminates a SIGCHLD signal is sent to the parent.
+ // Catching this signal would involve installing a signal handler which may
+ // affect other parts of the application and would be difficult to debug.
+ //
+ // Our strategy is to call waitpid() once up front to check if the process
+ // has already exited, otherwise to loop for |wait|, sleeping for
+ // at most 256 milliseconds each time using usleep() and then calling
+ // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and
+ // we double it every 4 sleep cycles.
+ //
+ // usleep() is speced to exit if a signal is received for which a handler
+ // has been installed. This means that when a SIGCHLD is sent, it will exit
+ // depending on behavior external to this function.
+ //
+ // This function is used primarily for unit tests, if we want to use it in
+ // the application itself it would probably be best to examine other routes.
+
+ if (wait == base::TimeDelta::Max()) {
+ return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
+ }
+
+ pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
+ static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
+ int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
+ int64 double_sleep_time = 0;
+
+ // If the process hasn't exited yet, then sleep and try again.
+ base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait;
+ while (ret_pid == 0) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ if (now > wakeup_time)
+ break;
+ // Guaranteed to be non-negative!
+ int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
+ // Sleep for a bit while we wait for the process to finish.
+ if (sleep_time_usecs > max_sleep_time_usecs)
+ sleep_time_usecs = max_sleep_time_usecs;
+
+ // usleep() will return 0 and set errno to EINTR on receipt of a signal
+ // such as SIGCHLD.
+ usleep(sleep_time_usecs);
+ ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
+
+ if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
+ (double_sleep_time++ % 4 == 0)) {
+ max_sleep_time_usecs *= 2;
+ }
+ }
+
+ return ret_pid > 0;
+}
+
+#if defined(OS_MACOSX)
+// Using kqueue on Mac so that we can wait on non-child processes.
+// We can't use kqueues on child processes because we need to reap
+// our own children using wait.
+static bool WaitForSingleNonChildProcess(base::ProcessHandle handle,
+ base::TimeDelta wait) {
+ DCHECK_GT(handle, 0);
+ DCHECK_GT(wait, base::TimeDelta());
+
+ base::ScopedFD kq(kqueue());
+ if (!kq.is_valid()) {
+ DPLOG(ERROR) << "kqueue";
+ return false;
+ }
+
+ struct kevent change = {0};
+ EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+ int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
+ if (result == -1) {
+ if (errno == ESRCH) {
+ // If the process wasn't found, it must be dead.
+ return true;
+ }
+
+ DPLOG(ERROR) << "kevent (setup " << handle << ")";
+ return false;
+ }
+
+ // Keep track of the elapsed time to be able to restart kevent if it's
+ // interrupted.
+ bool wait_forever = (wait == base::TimeDelta::Max());
+ base::TimeDelta remaining_delta;
+ base::TimeTicks deadline;
+ if (!wait_forever) {
+ remaining_delta = wait;
+ deadline = base::TimeTicks::Now() + remaining_delta;
+ }
+
+ result = -1;
+ struct kevent event = {0};
+
+ while (wait_forever || remaining_delta > base::TimeDelta()) {
+ struct timespec remaining_timespec;
+ struct timespec* remaining_timespec_ptr;
+ if (wait_forever) {
+ remaining_timespec_ptr = NULL;
+ } else {
+ remaining_timespec = remaining_delta.ToTimeSpec();
+ remaining_timespec_ptr = &remaining_timespec;
+ }
+
+ result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
+
+ if (result == -1 && errno == EINTR) {
+ if (!wait_forever) {
+ remaining_delta = deadline - base::TimeTicks::Now();
+ }
+ result = 0;
+ } else {
+ break;
+ }
+ }
+
+ if (result < 0) {
+ DPLOG(ERROR) << "kevent (wait " << handle << ")";
+ return false;
+ } else if (result > 1) {
+ DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
+ << result;
+ return false;
+ } else if (result == 0) {
+ // Timed out.
+ return false;
+ }
+
+ DCHECK_EQ(result, 1);
+
+ if (event.filter != EVFILT_PROC ||
+ (event.fflags & NOTE_EXIT) == 0 ||
+ event.ident != static_cast<uintptr_t>(handle)) {
+ DLOG(ERROR) << "kevent (wait " << handle
+ << "): unexpected event: filter=" << event.filter
+ << ", fflags=" << event.fflags
+ << ", ident=" << event.ident;
+ return false;
+ }
+
+ return true;
+}
+#endif // OS_MACOSX
+
+bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle,
+ int* exit_code,
+ base::TimeDelta timeout) {
+ base::ProcessHandle parent_pid = base::GetParentProcessId(handle);
+ base::ProcessHandle our_pid = base::GetCurrentProcessHandle();
+ if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+ // On Mac we can wait on non child processes.
+ return WaitForSingleNonChildProcess(handle, timeout);
+#else
+ // Currently on Linux we can't handle non child processes.
+ NOTIMPLEMENTED();
+#endif // OS_MACOSX
+ }
+
+ int status;
+ if (!WaitpidWithTimeout(handle, &status, timeout))
+ return false;
+ if (WIFSIGNALED(status)) {
+ *exit_code = -1;
+ return true;
+ }
+ if (WIFEXITED(status)) {
+ *exit_code = WEXITSTATUS(status);
+ return true;
+ }
+ return false;
+}
+#endif // !defined(OS_NACL_NONSFI)
+
+} // namespace
namespace base {
Process::Process(ProcessHandle handle) : process_(handle) {
- CHECK_NE(handle, GetCurrentProcessHandle());
+}
+
+Process::~Process() {
}
Process::Process(RValue other)
@@ -32,17 +229,36 @@ Process& Process::operator=(RValue other) {
// static
Process Process::Current() {
- Process process;
- process.process_ = GetCurrentProcessHandle();
- return process.Pass();
+ return Process(GetCurrentProcessHandle());
+}
+
+// static
+Process Process::Open(ProcessId pid) {
+ if (pid == GetCurrentProcId())
+ return Current();
+
+ // On POSIX process handles are the same as PIDs.
+ return Process(pid);
+}
+
+// static
+Process Process::OpenWithExtraPrivileges(ProcessId pid) {
+ // On POSIX there are no privileges to set.
+ return Open(pid);
}
-#if !defined(OS_LINUX)
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+ DCHECK_NE(handle, GetCurrentProcessHandle());
+ return Process(handle);
+}
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
// static
bool Process::CanBackgroundProcesses() {
return false;
}
-#endif // !defined(OS_LINUX)
+#endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
bool Process::IsValid() const {
return process_ != kNullProcessHandle;
@@ -59,7 +275,7 @@ Process Process::Duplicate() const {
return Process(process_);
}
-ProcessId Process::pid() const {
+ProcessId Process::Pid() const {
DCHECK(IsValid());
return GetProcId(process_);
}
@@ -75,15 +291,69 @@ void Process::Close() {
// end up w/ a zombie when it does finally exit.
}
-void Process::Terminate(int result_code) {
+#if !defined(OS_NACL_NONSFI)
+bool Process::Terminate(int exit_code, bool wait) const {
// result_code isn't supportable.
DCHECK(IsValid());
- // We don't wait here. It's the responsibility of other code to reap the
- // child.
- KillProcess(process_, result_code, false);
+ DCHECK_GT(process_, 1);
+ bool result = kill(process_, SIGTERM) == 0;
+ if (result && wait) {
+ int tries = 60;
+
+ if (RunningOnValgrind()) {
+ // Wait for some extra time when running under Valgrind since the child
+ // processes may take some time doing leak checking.
+ tries *= 2;
+ }
+
+ unsigned sleep_ms = 4;
+
+ // The process may not end immediately due to pending I/O
+ bool exited = false;
+ while (tries-- > 0) {
+ pid_t pid = HANDLE_EINTR(waitpid(process_, NULL, WNOHANG));
+ if (pid == process_) {
+ exited = true;
+ break;
+ }
+ if (pid == -1) {
+ if (errno == ECHILD) {
+ // The wait may fail with ECHILD if another process also waited for
+ // the same pid, causing the process state to get cleaned up.
+ exited = true;
+ break;
+ }
+ DPLOG(ERROR) << "Error waiting for process " << process_;
+ }
+
+ usleep(sleep_ms * 1000);
+ const unsigned kMaxSleepMs = 1000;
+ if (sleep_ms < kMaxSleepMs)
+ 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_, SIGKILL) == 0;
+ }
+
+ if (!result)
+ DPLOG(ERROR) << "Unable to terminate process " << process_;
+
+ return result;
+}
+#endif // !defined(OS_NACL_NONSFI)
+
+bool Process::WaitForExit(int* exit_code) {
+ return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+ return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
}
-#if !defined(OS_LINUX)
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
bool Process::IsProcessBackgrounded() const {
// See SetProcessBackgrounded().
DCHECK(IsValid());
@@ -91,17 +361,17 @@ bool Process::IsProcessBackgrounded() const {
}
bool Process::SetProcessBackgrounded(bool value) {
- // POSIX only allows lowering the priority of a process, so if we
- // were to lower it we wouldn't be able to raise it back to its initial
- // priority.
- DCHECK(IsValid());
+ // Not implemented for POSIX systems other than Mac and Linux. With POSIX, if
+ // we were to lower the process priority we wouldn't be able to raise it back
+ // to its initial priority.
+ NOTIMPLEMENTED();
return false;
}
-#endif // !defined(OS_LINUX)
+#endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
int Process::GetPriority() const {
DCHECK(IsValid());
return getpriority(PRIO_PROCESS, process_);
}
-} // namspace base
+} // namespace base
diff --git a/chromium/base/process/process_unittest.cc b/chromium/base/process/process_unittest.cc
index 66d6e634661..e094c032f3b 100644
--- a/chromium/base/process/process_unittest.cc
+++ b/chromium/base/process/process_unittest.cc
@@ -11,6 +11,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#endif // OS_MACOSX
namespace {
@@ -69,7 +72,7 @@ TEST_F(ProcessTest, Duplicate) {
Process process2 = process1.Duplicate();
ASSERT_TRUE(process1.IsValid());
ASSERT_TRUE(process2.IsValid());
- EXPECT_EQ(process1.pid(), process2.pid());
+ EXPECT_EQ(process1.Pid(), process2.Pid());
EXPECT_FALSE(process1.is_current());
EXPECT_FALSE(process2.is_current());
@@ -84,7 +87,7 @@ TEST_F(ProcessTest, DuplicateCurrent) {
Process process2 = process1.Duplicate();
ASSERT_TRUE(process1.IsValid());
ASSERT_TRUE(process2.IsValid());
- EXPECT_EQ(process1.pid(), process2.pid());
+ EXPECT_EQ(process1.Pid(), process2.Pid());
EXPECT_TRUE(process1.is_current());
EXPECT_TRUE(process2.is_current());
@@ -92,6 +95,21 @@ TEST_F(ProcessTest, DuplicateCurrent) {
ASSERT_TRUE(process2.IsValid());
}
+TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) {
+ Process process1(SpawnChild("SimpleChildProcess"));
+ ASSERT_TRUE(process1.IsValid());
+
+ Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle());
+ ASSERT_TRUE(process1.IsValid());
+ ASSERT_TRUE(process2.IsValid());
+ EXPECT_EQ(process1.Pid(), process2.Pid());
+ EXPECT_FALSE(process1.is_current());
+ EXPECT_FALSE(process2.is_current());
+
+ process1.Close();
+ ASSERT_TRUE(process2.IsValid());
+}
+
MULTIPROCESS_TEST_MAIN(SleepyChildProcess) {
PlatformThread::Sleep(TestTimeouts::action_max_timeout());
return 0;
@@ -109,8 +127,9 @@ TEST_F(ProcessTest, Terminate) {
exit_code = kDummyExitCode;
int kExpectedExitCode = 250;
- process.Terminate(kExpectedExitCode);
- WaitForSingleProcess(process.Handle(), TestTimeouts::action_max_timeout());
+ process.Terminate(kExpectedExitCode, false);
+ process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+ &exit_code);
EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING,
GetTerminationStatus(process.Handle(), &exit_code));
@@ -120,6 +139,34 @@ TEST_F(ProcessTest, Terminate) {
#endif
}
+MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) {
+ PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10);
+ return 0;
+}
+
+TEST_F(ProcessTest, WaitForExit) {
+ Process process(SpawnChild("FastSleepyChildProcess"));
+ ASSERT_TRUE(process.IsValid());
+
+ const int kDummyExitCode = 42;
+ int exit_code = kDummyExitCode;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_EQ(0, exit_code);
+}
+
+TEST_F(ProcessTest, WaitForExitWithTimeout) {
+ Process process(SpawnChild("SleepyChildProcess"));
+ ASSERT_TRUE(process.IsValid());
+
+ const int kDummyExitCode = 42;
+ int exit_code = kDummyExitCode;
+ TimeDelta timeout = TestTimeouts::tiny_timeout();
+ EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code));
+ EXPECT_EQ(kDummyExitCode, exit_code);
+
+ process.Terminate(kDummyExitCode, false);
+}
+
// Ensure that the priority of a process is restored correctly after
// backgrounding and restoring.
// Note: a platform may not be willing or able to lower the priority of
@@ -127,7 +174,19 @@ TEST_F(ProcessTest, Terminate) {
TEST_F(ProcessTest, SetProcessBackgrounded) {
Process process(SpawnChild("SimpleChildProcess"));
int old_priority = process.GetPriority();
-#if defined(OS_WIN)
+#if defined(OS_MACOSX)
+ // On the Mac, backgrounding a process requires a port to that process.
+ // In the browser it's available through the MachBroker class, which is not
+ // part of base. Additionally, there is an indefinite amount of time between
+ // spawning a process and receiving its port. Because this test just checks
+ // the ability to background/foreground a process, we can use the current
+ // process's port instead.
+ mach_port_t process_port = mach_task_self();
+ EXPECT_TRUE(process.SetProcessBackgrounded(process_port, true));
+ EXPECT_TRUE(process.IsProcessBackgrounded(process_port));
+ EXPECT_TRUE(process.SetProcessBackgrounded(process_port, false));
+ EXPECT_FALSE(process.IsProcessBackgrounded(process_port));
+#elif defined(OS_WIN)
EXPECT_TRUE(process.SetProcessBackgrounded(true));
EXPECT_TRUE(process.IsProcessBackgrounded());
EXPECT_TRUE(process.SetProcessBackgrounded(false));
@@ -145,7 +204,13 @@ TEST_F(ProcessTest, SetProcessBackgrounded) {
TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
Process process = Process::Current();
int old_priority = process.GetPriority();
-#if defined(OS_WIN)
+#if defined(OS_MACOSX)
+ mach_port_t process_port = mach_task_self();
+ EXPECT_TRUE(process.SetProcessBackgrounded(process_port, true));
+ EXPECT_TRUE(process.IsProcessBackgrounded(process_port));
+ EXPECT_TRUE(process.SetProcessBackgrounded(process_port, false));
+ EXPECT_FALSE(process.IsProcessBackgrounded(process_port));
+#elif defined(OS_WIN)
EXPECT_TRUE(process.SetProcessBackgrounded(true));
EXPECT_TRUE(process.IsProcessBackgrounded());
EXPECT_TRUE(process.SetProcessBackgrounded(false));
diff --git a/chromium/base/process/process_util_unittest.cc b/chromium/base/process/process_util_unittest.cc
index d846d1acfae..11d8874a52a 100644
--- a/chromium/base/process/process_util_unittest.cc
+++ b/chromium/base/process/process_util_unittest.cc
@@ -10,6 +10,8 @@
#include "base/debug/alias.h"
#include "base/debug/stack_trace.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
@@ -27,21 +29,26 @@
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
#if defined(OS_LINUX)
#include <malloc.h>
#include <sched.h>
+#include <sys/syscall.h>
#endif
#if defined(OS_POSIX)
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
+#include <sched.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <sys/wait.h>
+#include <unistd.h>
#endif
#if defined(OS_WIN)
#include <windows.h>
@@ -142,11 +149,11 @@ MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
// TODO(viettrungluu): This should be in a "MultiProcessTestTest".
TEST_F(ProcessUtilTest, SpawnChild) {
- base::ProcessHandle handle = SpawnChild("SimpleChildProcess");
- ASSERT_NE(base::kNullProcessHandle, handle);
- EXPECT_TRUE(base::WaitForSingleProcess(
- handle, TestTimeouts::action_max_timeout()));
- base::CloseProcessHandle(handle);
+ base::Process process = SpawnChild("SimpleChildProcess");
+ ASSERT_TRUE(process.IsValid());
+ int exit_code;
+ EXPECT_TRUE(process.WaitForExitWithTimeout(
+ TestTimeouts::action_max_timeout(), &exit_code));
}
MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
@@ -158,12 +165,12 @@ TEST_F(ProcessUtilTest, KillSlowChild) {
const std::string signal_file =
ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
remove(signal_file.c_str());
- base::ProcessHandle handle = SpawnChild("SlowChildProcess");
- ASSERT_NE(base::kNullProcessHandle, handle);
+ base::Process process = SpawnChild("SlowChildProcess");
+ ASSERT_TRUE(process.IsValid());
SignalChildren(signal_file.c_str());
- EXPECT_TRUE(base::WaitForSingleProcess(
- handle, TestTimeouts::action_max_timeout()));
- base::CloseProcessHandle(handle);
+ int exit_code;
+ EXPECT_TRUE(process.WaitForExitWithTimeout(
+ TestTimeouts::action_max_timeout(), &exit_code));
remove(signal_file.c_str());
}
@@ -172,21 +179,20 @@ TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) {
const std::string signal_file =
ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
remove(signal_file.c_str());
- base::ProcessHandle handle = SpawnChild("SlowChildProcess");
- ASSERT_NE(base::kNullProcessHandle, handle);
+ base::Process process = SpawnChild("SlowChildProcess");
+ ASSERT_TRUE(process.IsValid());
int exit_code = 42;
EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
- base::GetTerminationStatus(handle, &exit_code));
+ base::GetTerminationStatus(process.Handle(), &exit_code));
EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
SignalChildren(signal_file.c_str());
exit_code = 42;
base::TerminationStatus status =
- WaitForChildTermination(handle, &exit_code);
+ WaitForChildTermination(process.Handle(), &exit_code);
EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
EXPECT_EQ(0, exit_code);
- base::CloseProcessHandle(handle);
remove(signal_file.c_str());
}
@@ -195,12 +201,11 @@ TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) {
TEST_F(ProcessUtilTest, GetProcId) {
base::ProcessId id1 = base::GetProcId(GetCurrentProcess());
EXPECT_NE(0ul, id1);
- base::ProcessHandle handle = SpawnChild("SimpleChildProcess");
- ASSERT_NE(base::kNullProcessHandle, handle);
- base::ProcessId id2 = base::GetProcId(handle);
+ base::Process process = SpawnChild("SimpleChildProcess");
+ ASSERT_TRUE(process.IsValid());
+ base::ProcessId id2 = process.Pid();
EXPECT_NE(0ul, id2);
EXPECT_NE(id1, id2);
- base::CloseProcessHandle(handle);
}
#endif
@@ -239,18 +244,18 @@ TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
const std::string signal_file =
ProcessUtilTest::GetSignalFilePath(kSignalFileCrash);
remove(signal_file.c_str());
- base::ProcessHandle handle = SpawnChild("CrashingChildProcess");
- ASSERT_NE(base::kNullProcessHandle, handle);
+ base::Process process = SpawnChild("CrashingChildProcess");
+ ASSERT_TRUE(process.IsValid());
int exit_code = 42;
EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
- base::GetTerminationStatus(handle, &exit_code));
+ base::GetTerminationStatus(process.Handle(), &exit_code));
EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
SignalChildren(signal_file.c_str());
exit_code = 42;
base::TerminationStatus status =
- WaitForChildTermination(handle, &exit_code);
+ WaitForChildTermination(process.Handle(), &exit_code);
EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
#if defined(OS_WIN)
@@ -261,7 +266,6 @@ TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
int signal = WTERMSIG(exit_code);
EXPECT_EQ(SIGSEGV, signal);
#endif
- base::CloseProcessHandle(handle);
// Reset signal handlers back to "normal".
base::debug::EnableInProcessStackDumping();
@@ -286,18 +290,18 @@ TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
const std::string signal_file =
ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
remove(signal_file.c_str());
- base::ProcessHandle handle = SpawnChild("KilledChildProcess");
- ASSERT_NE(base::kNullProcessHandle, handle);
+ base::Process process = SpawnChild("KilledChildProcess");
+ ASSERT_TRUE(process.IsValid());
int exit_code = 42;
EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
- base::GetTerminationStatus(handle, &exit_code));
+ base::GetTerminationStatus(process.Handle(), &exit_code));
EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
SignalChildren(signal_file.c_str());
exit_code = 42;
base::TerminationStatus status =
- WaitForChildTermination(handle, &exit_code);
+ WaitForChildTermination(process.Handle(), &exit_code);
EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
#if defined(OS_WIN)
EXPECT_EQ(kExpectedKilledExitCode, exit_code);
@@ -307,7 +311,6 @@ TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
int signal = WTERMSIG(exit_code);
EXPECT_EQ(SIGKILL, signal);
#endif
- base::CloseProcessHandle(handle);
remove(signal_file.c_str());
}
@@ -325,7 +328,7 @@ TEST_F(ProcessUtilTest, GetAppOutput) {
expected += "\r\n";
FilePath cmd(L"cmd.exe");
- CommandLine cmd_line(cmd);
+ base::CommandLine cmd_line(cmd);
cmd_line.AppendArg("/c");
cmd_line.AppendArg("echo " + message + "");
std::string output;
@@ -333,7 +336,7 @@ TEST_F(ProcessUtilTest, GetAppOutput) {
EXPECT_EQ(expected, output);
// Let's make sure stderr is ignored.
- CommandLine other_cmd_line(cmd);
+ base::CommandLine other_cmd_line(cmd);
other_cmd_line.AppendArg("/c");
// http://msdn.microsoft.com/library/cc772622.aspx
cmd_line.AppendArg("echo " + message + " >&2");
@@ -348,22 +351,23 @@ TEST_F(ProcessUtilTest, LaunchAsUser) {
ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
base::LaunchOptions options;
options.as_user = token;
- EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"), options,
- NULL));
+ EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"),
+ options).IsValid());
}
static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle";
MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) {
std::string handle_value_string =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
kEventToTriggerHandleSwitch);
CHECK(!handle_value_string.empty());
uint64 handle_value_uint64;
CHECK(base::StringToUint64(handle_value_string, &handle_value_uint64));
// Give ownership of the handle to |event|.
- base::WaitableEvent event(reinterpret_cast<HANDLE>(handle_value_uint64));
+ base::WaitableEvent event(base::win::ScopedHandle(
+ reinterpret_cast<HANDLE>(handle_value_uint64)));
event.Signal();
@@ -378,26 +382,26 @@ TEST_F(ProcessUtilTest, InheritSpecifiedHandles) {
security_attributes.bInheritHandle = true;
// Takes ownership of the event handle.
- base::WaitableEvent event(
- CreateEvent(&security_attributes, true, false, NULL));
+ base::WaitableEvent event(base::win::ScopedHandle(
+ CreateEvent(&security_attributes, true, false, NULL)));
base::HandlesToInheritVector handles_to_inherit;
handles_to_inherit.push_back(event.handle());
base::LaunchOptions options;
options.handles_to_inherit = &handles_to_inherit;
- CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess");
+ base::CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess");
cmd_line.AppendSwitchASCII(kEventToTriggerHandleSwitch,
base::Uint64ToString(reinterpret_cast<uint64>(event.handle())));
// This functionality actually requires Vista or later. Make sure that it
// fails properly on XP.
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
- EXPECT_FALSE(base::LaunchProcess(cmd_line, options, NULL));
+ EXPECT_FALSE(base::LaunchProcess(cmd_line, options).IsValid());
return;
}
// Launch the process and wait for it to trigger the event.
- ASSERT_TRUE(base::LaunchProcess(cmd_line, options, NULL));
+ ASSERT_TRUE(base::LaunchProcess(cmd_line, options).IsValid());
EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
}
#endif // defined(OS_WIN)
@@ -534,9 +538,9 @@ int ProcessUtilTest::CountOpenFDsInChild() {
fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe));
base::LaunchOptions options;
options.fds_to_remap = &fd_mapping_vec;
- base::ProcessHandle handle =
+ base::Process process =
SpawnChildWithOptions("ProcessUtilsLeakFDChildProcess", options);
- CHECK(handle);
+ CHECK(process.IsValid());
int ret = IGNORE_EINTR(close(fds[1]));
DPCHECK(ret == 0);
@@ -548,11 +552,12 @@ int ProcessUtilTest::CountOpenFDsInChild() {
#if defined(THREAD_SANITIZER)
// Compiler-based ThreadSanitizer makes this test slow.
- CHECK(base::WaitForSingleProcess(handle, base::TimeDelta::FromSeconds(3)));
+ base::TimeDelta timeout = base::TimeDelta::FromSeconds(3);
#else
- CHECK(base::WaitForSingleProcess(handle, base::TimeDelta::FromSeconds(1)));
+ base::TimeDelta timeout = base::TimeDelta::FromSeconds(1);
#endif
- base::CloseProcessHandle(handle);
+ int exit_code;
+ CHECK(process.WaitForExitWithTimeout(timeout, &exit_code));
ret = IGNORE_EINTR(close(fds[0]));
DPCHECK(ret == 0);
@@ -611,7 +616,7 @@ std::string TestLaunchProcess(const std::vector<std::string>& args,
#else
CHECK_EQ(0, clone_flags);
#endif // OS_LINUX
- EXPECT_TRUE(base::LaunchProcess(args, options, NULL));
+ EXPECT_TRUE(base::LaunchProcess(args, options).IsValid());
PCHECK(IGNORE_EINTR(close(fds[1])) == 0);
char buf[512];
@@ -683,10 +688,8 @@ TEST_F(ProcessUtilTest, LaunchProcess) {
// Test a non-trival value for clone_flags.
// Don't test on Valgrind as it has limited support for clone().
if (!RunningOnValgrind()) {
- EXPECT_EQ(
- "wibble\n",
- TestLaunchProcess(
- echo_base_test, env_changes, no_clear_environ, CLONE_FS | SIGCHLD));
+ EXPECT_EQ("wibble\n", TestLaunchProcess(echo_base_test, env_changes,
+ no_clear_environ, CLONE_FS));
}
EXPECT_EQ(
@@ -710,27 +713,29 @@ TEST_F(ProcessUtilTest, GetAppOutput) {
argv.push_back("-c");
argv.push_back("exit 0");
- EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
+ EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
EXPECT_STREQ("", output.c_str());
argv[2] = "exit 1";
- EXPECT_FALSE(base::GetAppOutput(CommandLine(argv), &output));
+ EXPECT_FALSE(base::GetAppOutput(base::CommandLine(argv), &output));
EXPECT_STREQ("", output.c_str());
argv[2] = "echo foobar42";
- EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
+ EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
EXPECT_STREQ("foobar42\n", output.c_str());
#else
- EXPECT_TRUE(base::GetAppOutput(CommandLine(FilePath("true")), &output));
+ EXPECT_TRUE(base::GetAppOutput(base::CommandLine(FilePath("true")),
+ &output));
EXPECT_STREQ("", output.c_str());
- EXPECT_FALSE(base::GetAppOutput(CommandLine(FilePath("false")), &output));
+ EXPECT_FALSE(base::GetAppOutput(base::CommandLine(FilePath("false")),
+ &output));
std::vector<std::string> argv;
argv.push_back("/bin/echo");
argv.push_back("-n");
argv.push_back("foobar42");
- EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
+ EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
EXPECT_STREQ("foobar42", output.c_str());
#endif // defined(OS_ANDROID)
}
@@ -754,34 +759,39 @@ TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestricted) {
// need absolute paths).
argv.push_back("exit 0"); // argv[2]; equivalent to "true"
std::string output = "abc";
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 100));
EXPECT_STREQ("", output.c_str());
argv[2] = "exit 1"; // equivalent to "false"
output = "before";
- EXPECT_FALSE(base::GetAppOutputRestricted(CommandLine(argv),
- &output, 100));
+ EXPECT_FALSE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 100));
EXPECT_STREQ("", output.c_str());
// Amount of output exactly equal to space allowed.
argv[2] = "echo 123456789"; // (the sh built-in doesn't take "-n")
output.clear();
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 10));
EXPECT_STREQ("123456789\n", output.c_str());
// Amount of output greater than space allowed.
output.clear();
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 5));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 5));
EXPECT_STREQ("12345", output.c_str());
// Amount of output less than space allowed.
output.clear();
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 15));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 15));
EXPECT_STREQ("123456789\n", output.c_str());
// Zero space allowed.
output = "abc";
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 0));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 0));
EXPECT_STREQ("", output.c_str());
}
@@ -796,11 +806,13 @@ TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) {
argv.push_back("-c");
#if defined(OS_ANDROID)
argv.push_back("while echo 12345678901234567890; do :; done");
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 10));
EXPECT_STREQ("1234567890", output.c_str());
#else
argv.push_back("yes");
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 10));
EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str());
#endif
}
@@ -826,14 +838,16 @@ TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestrictedNoZombies) {
// 10.5) times with an output buffer big enough to capture all output.
for (int i = 0; i < 300; i++) {
std::string output;
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 100));
EXPECT_STREQ("123456789012345678901234567890\n", output.c_str());
}
// Ditto, but with an output buffer too small to capture all output.
for (int i = 0; i < 300; i++) {
std::string output;
- EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
+ EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+ 10));
EXPECT_STREQ("1234567890", output.c_str());
}
}
@@ -846,7 +860,7 @@ TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
argv.push_back(std::string(kShellPath)); // argv[0]
argv.push_back("-c"); // argv[1]
argv.push_back("echo foo"); // argv[2];
- EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output,
+ EXPECT_TRUE(base::GetAppOutputWithExitCode(base::CommandLine(argv), &output,
&exit_code));
EXPECT_STREQ("foo\n", output.c_str());
EXPECT_EQ(exit_code, 0);
@@ -855,7 +869,7 @@ TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
// code.
output.clear();
argv[2] = "echo foo; exit 2";
- EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output,
+ EXPECT_TRUE(base::GetAppOutputWithExitCode(base::CommandLine(argv), &output,
&exit_code));
EXPECT_STREQ("foo\n", output.c_str());
EXPECT_EQ(exit_code, 2);
@@ -876,14 +890,15 @@ bool IsProcessDead(base::ProcessHandle child) {
}
TEST_F(ProcessUtilTest, DelayedTermination) {
- base::ProcessHandle child_process = SpawnChild("process_util_test_never_die");
- ASSERT_TRUE(child_process);
- base::EnsureProcessTerminated(child_process);
- base::WaitForSingleProcess(child_process, base::TimeDelta::FromSeconds(5));
+ base::Process child_process = SpawnChild("process_util_test_never_die");
+ ASSERT_TRUE(child_process.IsValid());
+ base::EnsureProcessTerminated(child_process.Duplicate());
+ int exit_code;
+ child_process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5),
+ &exit_code);
// Check that process was really killed.
- EXPECT_TRUE(IsProcessDead(child_process));
- base::CloseProcessHandle(child_process);
+ EXPECT_TRUE(IsProcessDead(child_process.Handle()));
}
MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
@@ -894,20 +909,159 @@ MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
}
TEST_F(ProcessUtilTest, ImmediateTermination) {
- base::ProcessHandle child_process =
- SpawnChild("process_util_test_die_immediately");
- ASSERT_TRUE(child_process);
+ base::Process child_process = SpawnChild("process_util_test_die_immediately");
+ ASSERT_TRUE(child_process.IsValid());
// Give it time to die.
sleep(2);
- base::EnsureProcessTerminated(child_process);
+ base::EnsureProcessTerminated(child_process.Duplicate());
// Check that process was really killed.
- EXPECT_TRUE(IsProcessDead(child_process));
- base::CloseProcessHandle(child_process);
+ EXPECT_TRUE(IsProcessDead(child_process.Handle()));
}
MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
return 0;
}
+#if !defined(OS_ANDROID)
+const char kPipeValue = '\xcc';
+
+class ReadFromPipeDelegate : public base::LaunchOptions::PreExecDelegate {
+ public:
+ explicit ReadFromPipeDelegate(int fd) : fd_(fd) {}
+ ~ReadFromPipeDelegate() override {}
+ void RunAsyncSafe() override {
+ char c;
+ RAW_CHECK(HANDLE_EINTR(read(fd_, &c, 1)) == 1);
+ RAW_CHECK(IGNORE_EINTR(close(fd_)) == 0);
+ RAW_CHECK(c == kPipeValue);
+ }
+
+ private:
+ int fd_;
+ DISALLOW_COPY_AND_ASSIGN(ReadFromPipeDelegate);
+};
+
+TEST_F(ProcessUtilTest, PreExecHook) {
+ int pipe_fds[2];
+ ASSERT_EQ(0, pipe(pipe_fds));
+
+ base::ScopedFD read_fd(pipe_fds[0]);
+ base::ScopedFD write_fd(pipe_fds[1]);
+ base::FileHandleMappingVector fds_to_remap;
+ fds_to_remap.push_back(std::make_pair(read_fd.get(), read_fd.get()));
+
+ ReadFromPipeDelegate read_from_pipe_delegate(read_fd.get());
+ base::LaunchOptions options;
+ options.fds_to_remap = &fds_to_remap;
+ options.pre_exec_delegate = &read_from_pipe_delegate;
+ base::Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+ ASSERT_TRUE(process.IsValid());
+
+ read_fd.reset();
+ ASSERT_EQ(1, HANDLE_EINTR(write(write_fd.get(), &kPipeValue, 1)));
+
+ int exit_code = 42;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_EQ(0, exit_code);
+}
+#endif // !defined(OS_ANDROID)
+
#endif // defined(OS_POSIX)
+
+#if defined(OS_LINUX)
+const int kSuccess = 0;
+
+MULTIPROCESS_TEST_MAIN(CheckPidProcess) {
+ const pid_t kInitPid = 1;
+ const pid_t pid = syscall(__NR_getpid);
+ CHECK(pid == kInitPid);
+ CHECK(getpid() == pid);
+ return kSuccess;
+}
+
+TEST_F(ProcessUtilTest, CloneFlags) {
+ if (RunningOnValgrind() ||
+ !base::PathExists(FilePath("/proc/self/ns/user")) ||
+ !base::PathExists(FilePath("/proc/self/ns/pid"))) {
+ // User or PID namespaces are not supported.
+ return;
+ }
+
+ base::LaunchOptions options;
+ options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID;
+
+ base::Process process(SpawnChildWithOptions("CheckPidProcess", options));
+ ASSERT_TRUE(process.IsValid());
+
+ int exit_code = 42;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_EQ(kSuccess, exit_code);
+}
+
+TEST(ForkWithFlagsTest, UpdatesPidCache) {
+ // The libc clone function, which allows ForkWithFlags to keep the pid cache
+ // up to date, does not work on Valgrind.
+ if (RunningOnValgrind()) {
+ return;
+ }
+
+ // Warm up the libc pid cache, if there is one.
+ ASSERT_EQ(syscall(__NR_getpid), getpid());
+
+ pid_t ctid = 0;
+ const pid_t pid =
+ base::ForkWithFlags(SIGCHLD | CLONE_CHILD_SETTID, nullptr, &ctid);
+ if (pid == 0) {
+ // In child. Check both the raw getpid syscall and the libc getpid wrapper
+ // (which may rely on a pid cache).
+ RAW_CHECK(syscall(__NR_getpid) == ctid);
+ RAW_CHECK(getpid() == ctid);
+ _exit(kSuccess);
+ }
+
+ ASSERT_NE(-1, pid);
+ int status = 42;
+ ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+ ASSERT_TRUE(WIFEXITED(status));
+ EXPECT_EQ(kSuccess, WEXITSTATUS(status));
+}
+
+MULTIPROCESS_TEST_MAIN(CheckCwdProcess) {
+ base::FilePath expected;
+ CHECK(base::GetTempDir(&expected));
+ base::FilePath actual;
+ CHECK(base::GetCurrentDirectory(&actual));
+ CHECK(actual == expected);
+ return kSuccess;
+}
+
+TEST_F(ProcessUtilTest, CurrentDirectory) {
+ // TODO(rickyz): Add support for passing arguments to multiprocess children,
+ // then create a special directory for this test.
+ base::FilePath tmp_dir;
+ ASSERT_TRUE(base::GetTempDir(&tmp_dir));
+
+ base::LaunchOptions options;
+ options.current_directory = tmp_dir;
+
+ base::Process process(SpawnChildWithOptions("CheckCwdProcess", options));
+ ASSERT_TRUE(process.IsValid());
+
+ int exit_code = 42;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_EQ(kSuccess, exit_code);
+}
+
+TEST_F(ProcessUtilTest, InvalidCurrentDirectory) {
+ base::LaunchOptions options;
+ options.current_directory = base::FilePath("/dev/null");
+
+ base::Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+ ASSERT_TRUE(process.IsValid());
+
+ int exit_code = kSuccess;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_NE(kSuccess, exit_code);
+}
+#endif
diff --git a/chromium/base/process/process_win.cc b/chromium/base/process/process_win.cc
index 05041b20dda..0d312a35990 100644
--- a/chromium/base/process/process_win.cc
+++ b/chromium/base/process/process_win.cc
@@ -6,8 +6,18 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/process/kill.h"
#include "base/win/windows_version.h"
+namespace {
+
+DWORD kBasicProcessAccess =
+ PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
+
+} // namespace
+
namespace base {
Process::Process(ProcessHandle handle)
@@ -22,6 +32,9 @@ Process::Process(RValue other)
other.object->Close();
}
+Process::~Process() {
+}
+
Process& Process::operator=(RValue other) {
if (this != other.object) {
process_.Set(other.object->process_.Take());
@@ -39,6 +52,34 @@ Process Process::Current() {
}
// static
+Process Process::Open(ProcessId pid) {
+ return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
+}
+
+// static
+Process Process::OpenWithExtraPrivileges(ProcessId pid) {
+ DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
+ return Process(::OpenProcess(access, FALSE, pid));
+}
+
+// static
+Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
+ return Process(::OpenProcess(desired_access, FALSE, pid));
+}
+
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+ DCHECK_NE(handle, ::GetCurrentProcess());
+ ProcessHandle out_handle;
+ if (!::DuplicateHandle(GetCurrentProcess(), handle,
+ GetCurrentProcess(), &out_handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ return Process();
+ }
+ return Process(out_handle);
+}
+
+// static
bool Process::CanBackgroundProcesses() {
return true;
}
@@ -68,7 +109,7 @@ Process Process::Duplicate() const {
return Process(out_handle);
}
-ProcessId Process::pid() const {
+ProcessId Process::Pid() const {
DCHECK(IsValid());
return GetProcId(Handle());
}
@@ -85,17 +126,36 @@ void Process::Close() {
process_.Close();
}
-void Process::Terminate(int result_code) {
+bool Process::Terminate(int exit_code, bool wait) const {
DCHECK(IsValid());
+ bool result = (::TerminateProcess(Handle(), exit_code) != FALSE);
+ if (result && wait) {
+ // The process may not end immediately due to pending I/O
+ if (::WaitForSingleObject(Handle(), 60 * 1000) != WAIT_OBJECT_0)
+ DPLOG(ERROR) << "Error waiting for process exit";
+ } else if (!result) {
+ DPLOG(ERROR) << "Unable to terminate process";
+ }
+ return result;
+}
+
+bool Process::WaitForExit(int* exit_code) {
+ return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE),
+ exit_code);
+}
- // Call NtTerminateProcess directly, without going through the import table,
- // which might have been hooked with a buggy replacement by third party
- // software. http://crbug.com/81449.
- HMODULE module = GetModuleHandle(L"ntdll.dll");
- typedef UINT (WINAPI *TerminateProcessPtr)(HANDLE handle, UINT code);
- TerminateProcessPtr terminate_process = reinterpret_cast<TerminateProcessPtr>(
- GetProcAddress(module, "NtTerminateProcess"));
- terminate_process(Handle(), result_code);
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+ // Limit timeout to INFINITE.
+ DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
+ if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0)
+ return false;
+
+ DWORD temp_code; // Don't clobber out-parameters in case of failure.
+ if (!::GetExitCodeProcess(Handle(), &temp_code))
+ return false;
+
+ *exit_code = temp_code;
+ return true;
}
bool Process::IsProcessBackgrounded() const {
@@ -117,7 +177,21 @@ bool Process::SetProcessBackgrounded(bool value) {
priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
PROCESS_MODE_BACKGROUND_END;
} else {
- priority = value ? BELOW_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
+ // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a
+ // background priority for background renderers (this code path is
+ // technically for more than just the renderers but they're the only use
+ // case in practice and experimenting here direclty is thus easier -- plus
+ // it doesn't really hurt as above we already state our intent of using
+ // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially
+ // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the
+ // asbence of field trials to get coverage on the perf waterfall.
+ DWORD background_priority = IDLE_PRIORITY_CLASS;
+ base::FieldTrial* trial =
+ base::FieldTrialList::Find("BackgroundRendererProcesses");
+ if (trial && trial->group_name() == "AllowBelowNormalFromBrowser")
+ background_priority = BELOW_NORMAL_PRIORITY_CLASS;
+
+ priority = value ? background_priority : NORMAL_PRIORITY_CLASS;
}
return (::SetPriorityClass(Handle(), priority) != 0);
diff --git a/chromium/base/profiler/alternate_timer.cc b/chromium/base/profiler/alternate_timer.cc
index 4eba89c255e..02763cd9ef9 100644
--- a/chromium/base/profiler/alternate_timer.cc
+++ b/chromium/base/profiler/alternate_timer.cc
@@ -4,7 +4,7 @@
#include "base/profiler/alternate_timer.h"
-#include "base/logging.h"
+#include "base/basictypes.h"
namespace {
@@ -21,7 +21,6 @@ const char kAlternateProfilerTime[] = "CHROME_PROFILER_TIME";
// Set an alternate timer function to replace the OS time function when
// profiling.
void SetAlternateTimeSource(NowFunction* now_function, TimeSourceType type) {
- DCHECK_EQ(reinterpret_cast<NowFunction*>(NULL), g_time_function);
g_time_function = now_function;
g_time_source_type = type;
}
diff --git a/chromium/base/profiler/native_stack_sampler.cc b/chromium/base/profiler/native_stack_sampler.cc
new file mode 100644
index 00000000000..8b4731b6cce
--- /dev/null
+++ b/chromium/base/profiler/native_stack_sampler.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 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/profiler/native_stack_sampler.h"
+
+namespace base {
+
+NativeStackSampler::NativeStackSampler() {}
+
+NativeStackSampler::~NativeStackSampler() {}
+
+} // namespace base
diff --git a/chromium/base/profiler/native_stack_sampler.h b/chromium/base/profiler/native_stack_sampler.h
new file mode 100644
index 00000000000..bc170dcf933
--- /dev/null
+++ b/chromium/base/profiler/native_stack_sampler.h
@@ -0,0 +1,50 @@
+// Copyright 2015 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_PROFILER_NATIVE_STACK_SAMPLER_H_
+#define BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// NativeStackSampler is an implementation detail of StackSamplingProfiler. It
+// abstracts the native implementation required to record a stack sample for a
+// given thread.
+class NativeStackSampler {
+ public:
+ virtual ~NativeStackSampler();
+
+ // Creates a stack sampler that records samples for |thread_handle|. Returns
+ // null if this platform does not support stack sampling.
+ static scoped_ptr<NativeStackSampler> Create(PlatformThreadId thread_id);
+
+ // The following functions are all called on the SamplingThread (not the
+ // thread being sampled).
+
+ // Notifies the sampler that we're starting to record a new profile. Modules
+ // shared across samples in the profile should be recorded in |modules|.
+ virtual void ProfileRecordingStarting(
+ std::vector<StackSamplingProfiler::Module>* modules) = 0;
+
+ // Records a stack sample to |sample|.
+ virtual void RecordStackSample(StackSamplingProfiler::Sample* sample) = 0;
+
+ // Notifies the sampler that we've stopped recording the current
+ // profile.
+ virtual void ProfileRecordingStopped() = 0;
+
+ protected:
+ NativeStackSampler();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
+};
+
+} // namespace base
+
+#endif // BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+
diff --git a/chromium/base/profiler/scoped_profile.cc b/chromium/base/profiler/scoped_profile.cc
index 4f8bc2d1e0e..f06a8c6f5dd 100644
--- a/chromium/base/profiler/scoped_profile.cc
+++ b/chromium/base/profiler/scoped_profile.cc
@@ -20,7 +20,6 @@ ScopedProfile::ScopedProfile(const Location& location, Mode mode)
if (!birth_)
return;
- ThreadData::PrepareForStartOfRun(birth_);
stopwatch_.Start();
}
diff --git a/chromium/base/profiler/scoped_profile.h b/chromium/base/profiler/scoped_profile.h
index c1e283026dc..2c4105d24aa 100644
--- a/chromium/base/profiler/scoped_profile.h
+++ b/chromium/base/profiler/scoped_profile.h
@@ -30,6 +30,14 @@
FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name), \
::tracked_objects::ScopedProfile::ENABLED)
+// Same as TRACK_RUN_IN_THIS_SCOPED_REGION except that there's an extra param
+// which is concatenated with the function name for better filtering.
+#define TRACK_SCOPED_REGION(category_name, dispatch_function_name) \
+ ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+ FROM_HERE_WITH_EXPLICIT_FUNCTION( \
+ "[" category_name "]" dispatch_function_name), \
+ ::tracked_objects::ScopedProfile::ENABLED)
+
namespace tracked_objects {
class Births;
@@ -54,4 +62,4 @@ class BASE_EXPORT ScopedProfile {
} // namespace tracked_objects
-#endif // BASE_PROFILER_SCOPED_PROFILE_H_
+#endif // BASE_PROFILER_SCOPED_PROFILE_H_
diff --git a/chromium/base/profiler/scoped_tracker.cc b/chromium/base/profiler/scoped_tracker.cc
index 26b17c01553..d15b7de6dcd 100644
--- a/chromium/base/profiler/scoped_tracker.cc
+++ b/chromium/base/profiler/scoped_tracker.cc
@@ -12,13 +12,6 @@ namespace {
ScopedProfile::Mode g_scoped_profile_mode = ScopedProfile::DISABLED;
-// Executes |callback|, augmenting it with provided |location|.
-void ExecuteAndTrackCallback(const Location& location,
- const base::Closure& callback) {
- ScopedProfile tracking_profile(location, ScopedProfile::ENABLED);
- callback.Run();
-}
-
} // namespace
// static
@@ -26,15 +19,6 @@ void ScopedTracker::Enable() {
g_scoped_profile_mode = ScopedProfile::ENABLED;
}
-// static
-base::Closure ScopedTracker::TrackCallback(const Location& location,
- const base::Closure& callback) {
- if (g_scoped_profile_mode != ScopedProfile::ENABLED)
- return callback;
-
- return base::Bind(ExecuteAndTrackCallback, location, callback);
-}
-
ScopedTracker::ScopedTracker(const Location& location)
: scoped_profile_(location, g_scoped_profile_mode) {
}
diff --git a/chromium/base/profiler/scoped_tracker.h b/chromium/base/profiler/scoped_tracker.h
index f83654e1bd4..23e2f07b61f 100644
--- a/chromium/base/profiler/scoped_tracker.h
+++ b/chromium/base/profiler/scoped_tracker.h
@@ -10,6 +10,7 @@
// found using profiler data.
#include "base/base_export.h"
+#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/location.h"
#include "base/profiler/scoped_profile.h"
@@ -47,10 +48,24 @@ class BASE_EXPORT ScopedTracker {
// many possible callbacks, but they come from a relatively small number of
// places. We can instrument these few places and at least know which one
// passes the janky callback.
- static base::Closure TrackCallback(const Location& location,
- const base::Closure& callback);
+ template <typename P1>
+ static base::Callback<void(P1)> TrackCallback(
+ const Location& location,
+ const base::Callback<void(P1)>& callback) {
+ return base::Bind(&ScopedTracker::ExecuteAndTrackCallback<P1>, location,
+ callback);
+ }
private:
+ // Executes |callback|, augmenting it with provided |location|.
+ template <typename P1>
+ static void ExecuteAndTrackCallback(const Location& location,
+ const base::Callback<void(P1)>& callback,
+ P1 p1) {
+ ScopedTracker tracking_profile(location);
+ callback.Run(p1);
+ }
+
const ScopedProfile scoped_profile_;
DISALLOW_COPY_AND_ASSIGN(ScopedTracker);
diff --git a/chromium/base/profiler/stack_sampling_profiler.cc b/chromium/base/profiler/stack_sampling_profiler.cc
new file mode 100644
index 00000000000..9da662859fd
--- /dev/null
+++ b/chromium/base/profiler/stack_sampling_profiler.cc
@@ -0,0 +1,311 @@
+// Copyright 2015 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/profiler/stack_sampling_profiler.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/singleton.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/synchronization/lock.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+// DefaultProfileProcessor ----------------------------------------------------
+
+namespace {
+
+// Singleton class responsible for providing the default processing for profiles
+// (i.e. for profiles generated by profilers without their own completed
+// callback).
+class DefaultProfileProcessor {
+ public:
+ using CompletedCallback = StackSamplingProfiler::CompletedCallback;
+
+ ~DefaultProfileProcessor();
+
+ static DefaultProfileProcessor* GetInstance();
+
+ // Sets the callback to use for processing profiles captured without a
+ // per-profiler completed callback. Pending completed profiles are stored in
+ // this object until a non-null callback is provided here. This function is
+ // thread-safe.
+ void SetCompletedCallback(CompletedCallback callback);
+
+ // Processes |profiles|. This function is thread safe.
+ void ProcessProfiles(
+ const StackSamplingProfiler::CallStackProfiles& profiles);
+
+ private:
+ friend struct DefaultSingletonTraits<DefaultProfileProcessor>;
+
+ DefaultProfileProcessor();
+
+ // Copies the pending profiles from |profiles_| into |profiles|, and clears
+ // |profiles_|. This function may be called on any thread.
+ void GetAndClearPendingProfiles(
+ StackSamplingProfiler::CallStackProfiles* profiles);
+
+ // Gets the current completed callback, with proper locking.
+ CompletedCallback GetCompletedCallback() const;
+
+ mutable Lock callback_lock_;
+ CompletedCallback default_completed_callback_;
+
+ Lock profiles_lock_;
+ StackSamplingProfiler::CallStackProfiles profiles_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultProfileProcessor);
+};
+
+DefaultProfileProcessor::~DefaultProfileProcessor() {}
+
+// static
+DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() {
+ return Singleton<DefaultProfileProcessor>::get();
+}
+
+void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) {
+ {
+ AutoLock scoped_lock(callback_lock_);
+ default_completed_callback_ = callback;
+ }
+
+ if (!callback.is_null()) {
+ // Provide any pending profiles to the callback immediately.
+ StackSamplingProfiler::CallStackProfiles profiles;
+ GetAndClearPendingProfiles(&profiles);
+ if (!profiles.empty())
+ callback.Run(profiles);
+ }
+}
+
+void DefaultProfileProcessor::ProcessProfiles(
+ const StackSamplingProfiler::CallStackProfiles& profiles) {
+ CompletedCallback callback = GetCompletedCallback();
+
+ // Store pending profiles if we don't have a valid callback.
+ if (!callback.is_null()) {
+ callback.Run(profiles);
+ } else {
+ AutoLock scoped_lock(profiles_lock_);
+ profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
+ }
+}
+
+DefaultProfileProcessor::DefaultProfileProcessor() {}
+
+void DefaultProfileProcessor::GetAndClearPendingProfiles(
+ StackSamplingProfiler::CallStackProfiles* profiles) {
+ profiles->clear();
+
+ AutoLock scoped_lock(profiles_lock_);
+ profiles_.swap(*profiles);
+}
+
+DefaultProfileProcessor::CompletedCallback
+DefaultProfileProcessor::GetCompletedCallback() const {
+ AutoLock scoped_lock(callback_lock_);
+ return default_completed_callback_;
+}
+
+} // namespace
+
+// StackSamplingProfiler::Module ----------------------------------------------
+
+StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
+StackSamplingProfiler::Module::Module(const void* base_address,
+ const std::string& id,
+ const FilePath& filename)
+ : base_address(base_address), id(id), filename(filename) {}
+
+StackSamplingProfiler::Module::~Module() {}
+
+// StackSamplingProfiler::Frame -----------------------------------------------
+
+StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
+ size_t module_index)
+ : instruction_pointer(instruction_pointer),
+ module_index(module_index) {}
+
+StackSamplingProfiler::Frame::~Frame() {}
+
+// StackSamplingProfiler::CallStackProfile ------------------------------------
+
+StackSamplingProfiler::CallStackProfile::CallStackProfile()
+ : preserve_sample_ordering(false), user_data(0) {}
+
+StackSamplingProfiler::CallStackProfile::~CallStackProfile() {}
+
+// StackSamplingProfiler::SamplingThread --------------------------------------
+
+StackSamplingProfiler::SamplingThread::SamplingThread(
+ scoped_ptr<NativeStackSampler> native_sampler,
+ const SamplingParams& params,
+ CompletedCallback completed_callback)
+ : native_sampler_(native_sampler.Pass()),
+ params_(params),
+ stop_event_(false, false),
+ completed_callback_(completed_callback) {
+}
+
+StackSamplingProfiler::SamplingThread::~SamplingThread() {}
+
+void StackSamplingProfiler::SamplingThread::ThreadMain() {
+ PlatformThread::SetName("Chrome_SamplingProfilerThread");
+
+ CallStackProfiles profiles;
+ CollectProfiles(&profiles);
+ completed_callback_.Run(profiles);
+}
+
+// Depending on how long the sampling takes and the length of the sampling
+// interval, a burst of samples could take arbitrarily longer than
+// samples_per_burst * sampling_interval. In this case, we (somewhat
+// arbitrarily) honor the number of samples requested rather than strictly
+// adhering to the sampling intervals. Once we have established users for the
+// StackSamplingProfiler and the collected data to judge, we may go the other
+// way or make this behavior configurable.
+bool StackSamplingProfiler::SamplingThread::CollectProfile(
+ CallStackProfile* profile,
+ TimeDelta* elapsed_time) {
+ ElapsedTimer profile_timer;
+ CallStackProfile current_profile;
+ native_sampler_->ProfileRecordingStarting(&current_profile.modules);
+ current_profile.sampling_period = params_.sampling_interval;
+ bool burst_completed = true;
+ TimeDelta previous_elapsed_sample_time;
+ for (int i = 0; i < params_.samples_per_burst; ++i) {
+ if (i != 0) {
+ // Always wait, even if for 0 seconds, so we can observe a signal on
+ // stop_event_.
+ if (stop_event_.TimedWait(
+ std::max(params_.sampling_interval - previous_elapsed_sample_time,
+ TimeDelta()))) {
+ burst_completed = false;
+ break;
+ }
+ }
+ ElapsedTimer sample_timer;
+ current_profile.samples.push_back(Sample());
+ native_sampler_->RecordStackSample(&current_profile.samples.back());
+ previous_elapsed_sample_time = sample_timer.Elapsed();
+ }
+
+ *elapsed_time = profile_timer.Elapsed();
+ current_profile.profile_duration = *elapsed_time;
+ current_profile.preserve_sample_ordering = params_.preserve_sample_ordering;
+ current_profile.user_data = params_.user_data;
+ native_sampler_->ProfileRecordingStopped();
+
+ if (burst_completed)
+ *profile = current_profile;
+
+ return burst_completed;
+}
+
+// In an analogous manner to CollectProfile() and samples exceeding the expected
+// total sampling time, bursts may also exceed the burst_interval. We adopt the
+// same wait-and-see approach here.
+void StackSamplingProfiler::SamplingThread::CollectProfiles(
+ CallStackProfiles* profiles) {
+ if (stop_event_.TimedWait(params_.initial_delay))
+ return;
+
+ TimeDelta previous_elapsed_profile_time;
+ for (int i = 0; i < params_.bursts; ++i) {
+ if (i != 0) {
+ // Always wait, even if for 0 seconds, so we can observe a signal on
+ // stop_event_.
+ if (stop_event_.TimedWait(
+ std::max(params_.burst_interval - previous_elapsed_profile_time,
+ TimeDelta())))
+ return;
+ }
+
+ CallStackProfile profile;
+ if (!CollectProfile(&profile, &previous_elapsed_profile_time))
+ return;
+ profiles->push_back(profile);
+ }
+}
+
+void StackSamplingProfiler::SamplingThread::Stop() {
+ stop_event_.Signal();
+}
+
+// StackSamplingProfiler ------------------------------------------------------
+
+StackSamplingProfiler::SamplingParams::SamplingParams()
+ : initial_delay(TimeDelta::FromMilliseconds(0)),
+ bursts(1),
+ burst_interval(TimeDelta::FromMilliseconds(10000)),
+ samples_per_burst(300),
+ sampling_interval(TimeDelta::FromMilliseconds(100)),
+ preserve_sample_ordering(false),
+ user_data(0) {
+}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params)
+ : thread_id_(thread_id), params_(params) {}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params,
+ CompletedCallback callback)
+ : thread_id_(thread_id), params_(params), completed_callback_(callback) {}
+
+StackSamplingProfiler::~StackSamplingProfiler() {
+ Stop();
+ if (!sampling_thread_handle_.is_null())
+ PlatformThread::Join(sampling_thread_handle_);
+}
+
+void StackSamplingProfiler::Start() {
+ scoped_ptr<NativeStackSampler> native_sampler =
+ NativeStackSampler::Create(thread_id_);
+ if (!native_sampler)
+ return;
+
+ CompletedCallback callback =
+ !completed_callback_.is_null() ? completed_callback_ :
+ Bind(&DefaultProfileProcessor::ProcessProfiles,
+ Unretained(DefaultProfileProcessor::GetInstance()));
+ sampling_thread_.reset(
+ new SamplingThread(native_sampler.Pass(), params_, callback));
+ if (!PlatformThread::Create(0, sampling_thread_.get(),
+ &sampling_thread_handle_))
+ sampling_thread_.reset();
+}
+
+void StackSamplingProfiler::Stop() {
+ if (sampling_thread_)
+ sampling_thread_->Stop();
+}
+
+// static
+void StackSamplingProfiler::SetDefaultCompletedCallback(
+ CompletedCallback callback) {
+ DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback);
+}
+
+// StackSamplingProfiler::Frame global functions ------------------------------
+
+bool operator==(const StackSamplingProfiler::Frame &a,
+ const StackSamplingProfiler::Frame &b) {
+ return a.instruction_pointer == b.instruction_pointer &&
+ a.module_index == b.module_index;
+}
+
+bool operator<(const StackSamplingProfiler::Frame &a,
+ const StackSamplingProfiler::Frame &b) {
+ return (a.module_index < b.module_index) ||
+ (a.module_index == b.module_index &&
+ a.instruction_pointer < b.instruction_pointer);
+}
+
+} // namespace base
diff --git a/chromium/base/profiler/stack_sampling_profiler.h b/chromium/base/profiler/stack_sampling_profiler.h
new file mode 100644
index 00000000000..9d52f27a7ef
--- /dev/null
+++ b/chromium/base/profiler/stack_sampling_profiler.h
@@ -0,0 +1,264 @@
+// Copyright 2015 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_PROFILER_STACK_SAMPLING_PROFILER_H_
+#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class NativeStackSampler;
+
+// StackSamplingProfiler periodically stops a thread to sample its stack, for
+// the purpose of collecting information about which code paths are
+// executing. This information is used in aggregate by UMA to identify hot
+// and/or janky code paths.
+//
+// Sample StackSamplingProfiler usage:
+//
+// // Create and customize params as desired.
+// base::StackStackSamplingProfiler::SamplingParams params;
+// // Any thread's ID may be passed as the target.
+// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+// params);
+//
+// // Or, to process the profiles within Chrome rather than via UMA, use a
+// // custom completed callback:
+// base::StackStackSamplingProfiler::CompletedCallback
+// thread_safe_callback = ...;
+// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+// params, thread_safe_callback);
+//
+// profiler.Start();
+// // ... work being done on the target thread here ...
+// profiler.Stop(); // optional, stops collection before complete per params
+//
+// The default SamplingParams causes stacks to be recorded in a single burst at
+// a 10Hz interval for a total of 30 seconds. All of these parameters may be
+// altered as desired.
+//
+// When all call stack profiles are complete or the profiler is stopped, if the
+// custom completed callback was set it is called from a thread created by the
+// profiler with the completed profiles. A profile is considered complete if all
+// requested samples were recorded for the profile (i.e. it was not stopped
+// prematurely). If no callback was set, the default completed callback will be
+// called with the profiles. It is expected that the the default completed
+// callback is set by the metrics system to allow profiles to be provided via
+// UMA.
+//
+// The results of the profiling are passed to the completed callback and consist
+// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
+// burst as specified in SamplingParams and contains a set of Samples and
+// Modules. One Sample corresponds to a single recorded stack, and the Modules
+// record those modules associated with the recorded stack frames.
+class BASE_EXPORT StackSamplingProfiler {
+ public:
+ // Module represents the module (DLL or exe) corresponding to a stack frame.
+ struct BASE_EXPORT Module {
+ Module();
+ Module(const void* base_address, const std::string& id,
+ const FilePath& filename);
+ ~Module();
+
+ // Points to the base address of the module.
+ const void* base_address;
+
+ // An opaque binary string that uniquely identifies a particular program
+ // version with high probability. This is parsed from headers of the loaded
+ // module.
+ // For binaries generated by GNU tools:
+ // Contents of the .note.gnu.build-id field.
+ // On Windows:
+ // GUID + AGE in the debug image headers of a module.
+ std::string id;
+
+ // The filename of the module.
+ FilePath filename;
+ };
+
+ // Frame represents an individual sampled stack frame with module information.
+ struct BASE_EXPORT Frame {
+ // Identifies an unknown module.
+ static const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
+
+ Frame(const void* instruction_pointer, size_t module_index);
+ ~Frame();
+
+ // The sampled instruction pointer within the function.
+ const void* instruction_pointer;
+
+ // Index of the module in CallStackProfile::modules. We don't represent
+ // module state directly here to save space.
+ size_t module_index;
+ };
+
+ // Sample represents a set of stack frames.
+ using Sample = std::vector<Frame>;
+
+ // CallStackProfile represents a set of samples.
+ struct BASE_EXPORT CallStackProfile {
+ CallStackProfile();
+ ~CallStackProfile();
+
+ std::vector<Module> modules;
+ std::vector<Sample> samples;
+
+ // Duration of this profile.
+ TimeDelta profile_duration;
+
+ // Time between samples.
+ TimeDelta sampling_period;
+
+ // True if sample ordering is important and should be preserved if and when
+ // this profile is compressed and processed.
+ bool preserve_sample_ordering;
+
+ // User data associated with this profile.
+ uintptr_t user_data;
+ };
+
+ using CallStackProfiles = std::vector<CallStackProfile>;
+
+ // Represents parameters that configure the sampling.
+ struct BASE_EXPORT SamplingParams {
+ SamplingParams();
+
+ // Time to delay before first samples are taken. Defaults to 0.
+ TimeDelta initial_delay;
+
+ // Number of sampling bursts to perform. Defaults to 1.
+ int bursts;
+
+ // Interval between sampling bursts. This is the desired duration from the
+ // start of one burst to the start of the next burst. Defaults to 10s.
+ TimeDelta burst_interval;
+
+ // Number of samples to record per burst. Defaults to 300.
+ int samples_per_burst;
+
+ // Interval between samples during a sampling burst. This is the desired
+ // duration from the start of one sample to the start of the next
+ // sample. Defaults to 100ms.
+ TimeDelta sampling_interval;
+
+ // True if sample ordering is important and should be preserved if and when
+ // this profile is compressed and processed. Defaults to false.
+ bool preserve_sample_ordering;
+
+ // User data associated with this profile.
+ uintptr_t user_data;
+ };
+
+ // The callback type used to collect completed profiles.
+ //
+ // IMPORTANT NOTE: the callback is invoked on a thread the profiler
+ // constructs, rather than on the thread used to construct the profiler and
+ // set the callback, and thus the callback must be callable on any thread. For
+ // threads with message loops that create StackSamplingProfilers, posting a
+ // task to the message loop with a copy of the profiles is the recommended
+ // thread-safe callback implementation.
+ using CompletedCallback = Callback<void(const CallStackProfiles&)>;
+
+ // Creates a profiler that sends completed profiles to the default completed
+ // callback.
+ StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params);
+ // Creates a profiler that sends completed profiles to |completed_callback|.
+ StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params,
+ CompletedCallback callback);
+ ~StackSamplingProfiler();
+
+ // Initializes the profiler and starts sampling.
+ void Start();
+
+ // Stops the profiler and any ongoing sampling. Calling this function is
+ // optional; if not invoked profiling terminates when all the profiling bursts
+ // specified in the SamplingParams are completed.
+ void Stop();
+
+ // Sets a callback to process profiles collected by profiler instances without
+ // a completed callback. Profiles are queued internally until a non-null
+ // callback is provided to this function,
+ //
+ // The callback is typically called on a thread created by the profiler. If
+ // completed profiles are queued when set, however, it will also be called
+ // immediately on the calling thread.
+ static void SetDefaultCompletedCallback(CompletedCallback callback);
+
+ private:
+ // SamplingThread is a separate thread used to suspend and sample stacks from
+ // the target thread.
+ class SamplingThread : public PlatformThread::Delegate {
+ public:
+ // Samples stacks using |native_sampler|. When complete, invokes
+ // |completed_callback| with the collected call stack profiles.
+ // |completed_callback| must be callable on any thread.
+ SamplingThread(scoped_ptr<NativeStackSampler> native_sampler,
+ const SamplingParams& params,
+ CompletedCallback completed_callback);
+ ~SamplingThread() override;
+
+ // PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ void Stop();
+
+ private:
+ // Collects a call stack profile from a single burst. Returns true if the
+ // profile was collected, or false if collection was stopped before it
+ // completed.
+ bool CollectProfile(CallStackProfile* profile, TimeDelta* elapsed_time);
+
+ // Collects call stack profiles from all bursts, or until the sampling is
+ // stopped. If stopped before complete, |call_stack_profiles| will contain
+ // only full bursts.
+ void CollectProfiles(CallStackProfiles* profiles);
+
+ scoped_ptr<NativeStackSampler> native_sampler_;
+ const SamplingParams params_;
+
+ // If Stop() is called, it signals this event to force the sampling to
+ // terminate before all the samples specified in |params_| are collected.
+ WaitableEvent stop_event_;
+
+ const CompletedCallback completed_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplingThread);
+ };
+
+ // The thread whose stack will be sampled.
+ PlatformThreadId thread_id_;
+
+ const SamplingParams params_;
+
+ scoped_ptr<SamplingThread> sampling_thread_;
+ PlatformThreadHandle sampling_thread_handle_;
+
+ const CompletedCallback completed_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
+};
+
+// The metrics provider code wants to put Samples in a map and compare them,
+// which requires us to define a few operators.
+BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
+ const StackSamplingProfiler::Frame& b);
+BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
+ const StackSamplingProfiler::Frame& b);
+
+} // namespace base
+
+#endif // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
diff --git a/chromium/base/profiler/stack_sampling_profiler_posix.cc b/chromium/base/profiler/stack_sampling_profiler_posix.cc
new file mode 100644
index 00000000000..bce37e10c3a
--- /dev/null
+++ b/chromium/base/profiler/stack_sampling_profiler_posix.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 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/profiler/native_stack_sampler.h"
+
+namespace base {
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+ PlatformThreadId thread_id) {
+ return scoped_ptr<NativeStackSampler>();
+}
+
+} // namespace base
diff --git a/chromium/base/profiler/stack_sampling_profiler_unittest.cc b/chromium/base/profiler/stack_sampling_profiler_unittest.cc
new file mode 100644
index 00000000000..5ade15a6edc
--- /dev/null
+++ b/chromium/base/profiler/stack_sampling_profiler_unittest.cc
@@ -0,0 +1,445 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/path_service.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+using SamplingParams = StackSamplingProfiler::SamplingParams;
+using Frame = StackSamplingProfiler::Frame;
+using Module = StackSamplingProfiler::Module;
+using Sample = StackSamplingProfiler::Sample;
+using CallStackProfile = StackSamplingProfiler::CallStackProfile;
+using CallStackProfiles = StackSamplingProfiler::CallStackProfiles;
+
+namespace {
+
+// A thread to target for profiling, whose stack is guaranteed to contain
+// SignalAndWaitUntilSignaled() when coordinated with the main thread.
+class TargetThread : public PlatformThread::Delegate {
+ public:
+ TargetThread();
+
+ // PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ // Waits for the thread to have started and be executing in
+ // SignalAndWaitUntilSignaled().
+ void WaitForThreadStart();
+
+ // Allows the thread to return from SignalAndWaitUntilSignaled() and finish
+ // execution.
+ void SignalThreadToFinish();
+
+ // This function is guaranteed to be executing between calls to
+ // WaitForThreadStart() and SignalThreadToFinish(). This function is static so
+ // that we can get a straightforward address for it in one of the tests below,
+ // rather than dealing with the complexity of a member function pointer
+ // representation.
+ static void SignalAndWaitUntilSignaled(WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event);
+
+ PlatformThreadId id() const { return id_; }
+
+ private:
+ WaitableEvent thread_started_event_;
+ WaitableEvent finish_event_;
+ PlatformThreadId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(TargetThread);
+};
+
+TargetThread::TargetThread()
+ : thread_started_event_(false, false), finish_event_(false, false),
+ id_(0) {}
+
+void TargetThread::ThreadMain() {
+ id_ = PlatformThread::CurrentId();
+ SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_);
+}
+
+void TargetThread::WaitForThreadStart() {
+ thread_started_event_.Wait();
+}
+
+void TargetThread::SignalThreadToFinish() {
+ finish_event_.Signal();
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
+ WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event) {
+ thread_started_event->Signal();
+ volatile int x = 1;
+ finish_event->Wait();
+ x = 0; // Prevent tail call to WaitableEvent::Wait().
+ ALLOW_UNUSED_LOCAL(x);
+}
+
+// Called on the profiler thread when complete, to collect profiles.
+void SaveProfiles(CallStackProfiles* profiles,
+ const CallStackProfiles& pending_profiles) {
+ *profiles = pending_profiles;
+}
+
+// Called on the profiler thread when complete. Collects profiles produced by
+// the profiler, and signals an event to allow the main thread to know that that
+// the profiler is done.
+void SaveProfilesAndSignalEvent(CallStackProfiles* profiles,
+ WaitableEvent* event,
+ const CallStackProfiles& pending_profiles) {
+ *profiles = pending_profiles;
+ event->Signal();
+}
+
+// Executes the function with the target thread running and executing within
+// SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
+// and shutdown work before and afterward.
+template <class Function>
+void WithTargetThread(Function function) {
+ TargetThread target_thread;
+ PlatformThreadHandle target_thread_handle;
+ EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
+
+ target_thread.WaitForThreadStart();
+
+ function(target_thread.id());
+
+ target_thread.SignalThreadToFinish();
+
+ PlatformThread::Join(target_thread_handle);
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Waits up to |profiler_wait_time| for the profiler to
+// complete.
+void CaptureProfilesWithObjectCallback(const SamplingParams& params,
+ CallStackProfiles* profiles,
+ TimeDelta profiler_wait_time) {
+ profiles->clear();
+
+ WithTargetThread([&params, profiles, profiler_wait_time](
+ PlatformThreadId target_thread_id) {
+ WaitableEvent sampling_thread_completed(true, false);
+ const StackSamplingProfiler::CompletedCallback callback =
+ Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+ Unretained(&sampling_thread_completed));
+ StackSamplingProfiler profiler(target_thread_id, params, callback);
+ profiler.Start();
+ sampling_thread_completed.TimedWait(profiler_wait_time);
+ profiler.Stop();
+ sampling_thread_completed.Wait();
+ });
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Uses the default callback rather than a per-object
+// callback.
+void CaptureProfilesWithDefaultCallback(const SamplingParams& params,
+ CallStackProfiles* profiles) {
+ profiles->clear();
+
+ WithTargetThread([&params, profiles](PlatformThreadId target_thread_id) {
+ WaitableEvent sampling_thread_completed(false, false);
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+ Unretained(&sampling_thread_completed)));
+
+ StackSamplingProfiler profiler(target_thread_id, params);
+ profiler.Start();
+ sampling_thread_completed.Wait();
+
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ StackSamplingProfiler::CompletedCallback());
+ });
+}
+
+// Runs the profiler with |params| on the TargetThread, with no default or
+// per-object callback.
+void RunProfilerWithNoCallback(const SamplingParams& params,
+ TimeDelta profiler_wait_time) {
+ WithTargetThread([&params, profiler_wait_time](
+ PlatformThreadId target_thread_id) {
+ StackSamplingProfiler profiler(target_thread_id, params);
+ profiler.Start();
+ // Since we don't specify a callback, we don't have a synchronization
+ // mechanism with the sampling thread. Just sleep instead.
+ PlatformThread::Sleep(profiler_wait_time);
+ profiler.Stop();
+ });
+}
+
+// If this executable was linked with /INCREMENTAL (the default for non-official
+// debug and release builds on Windows), function addresses do not correspond to
+// function code itself, but instead to instructions in the Incremental Link
+// Table that jump to the functions. Checks for a jump instruction and if
+// present does a little decompilation to find the function's actual starting
+// address.
+const void* MaybeFixupFunctionAddressForILT(const void* function_address) {
+#if defined(_WIN64)
+ const unsigned char* opcode =
+ reinterpret_cast<const unsigned char*>(function_address);
+ if (*opcode == 0xe9) {
+ // This is a relative jump instruction. Assume we're in the ILT and compute
+ // the function start address from the instruction offset.
+ const int32* offset = reinterpret_cast<const int32*>(opcode + 1);
+ const unsigned char* next_instruction =
+ reinterpret_cast<const unsigned char*>(offset + 1);
+ return next_instruction + *offset;
+ }
+#endif
+ return function_address;
+}
+
+// Searches through the frames in |sample|, returning an iterator to the first
+// frame that has an instruction pointer between |function_address| and
+// |function_address| + |size|. Returns sample.end() if no such frames are
+// found.
+Sample::const_iterator FindFirstFrameWithinFunction(
+ const Sample& sample,
+ const void* function_address,
+ int function_size) {
+ function_address = MaybeFixupFunctionAddressForILT(function_address);
+ for (auto it = sample.begin(); it != sample.end(); ++it) {
+ if ((it->instruction_pointer >= function_address) &&
+ (it->instruction_pointer <
+ (static_cast<const unsigned char*>(function_address) + function_size)))
+ return it;
+ }
+ return sample.end();
+}
+
+// Formats a sample into a string that can be output for test diagnostics.
+std::string FormatSampleForDiagnosticOutput(
+ const Sample& sample,
+ const std::vector<Module>& modules) {
+ std::string output;
+ for (const Frame& frame: sample) {
+ output += StringPrintf(
+ "0x%p %s\n", frame.instruction_pointer,
+ modules[frame.module_index].filename.AsUTF8Unsafe().c_str());
+ }
+ return output;
+}
+
+// Returns a duration that is longer than the test timeout. We would use
+// TimeDelta::Max() but https://crbug.com/465948.
+TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
+
+} // namespace
+
+
+// The tests below are enabled for Win x64 only, pending implementation of the
+// tested functionality on other platforms/architectures.
+
+// Checks that the basic expected information is present in a sampled call stack
+// profile.
+#if defined(_WIN64)
+#define MAYBE_Basic Basic
+#else
+#define MAYBE_Basic DISABLED_Basic
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_Basic) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(0);
+ params.samples_per_burst = 1;
+ params.user_data = 100;
+ params.preserve_sample_ordering = true;
+
+ std::vector<CallStackProfile> profiles;
+ CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+
+ // Check that the profile and samples sizes are correct, and the module
+ // indices are in range.
+ ASSERT_EQ(1u, profiles.size());
+ const CallStackProfile& profile = profiles[0];
+ ASSERT_EQ(1u, profile.samples.size());
+ EXPECT_EQ(params.sampling_interval, profile.sampling_period);
+ const Sample& sample = profile.samples[0];
+ for (const auto& frame : sample) {
+ ASSERT_GE(frame.module_index, 0u);
+ ASSERT_LT(frame.module_index, profile.modules.size());
+ }
+ EXPECT_EQ(100u, profile.user_data);
+ EXPECT_EQ(true, profile.preserve_sample_ordering);
+
+ // Check that the stack contains a frame for
+ // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
+ // executable's module.
+ //
+ // Since we don't have a good way to know the function size, use 100 bytes as
+ // a reasonable window to locate the instruction pointer.
+ Sample::const_iterator loc = FindFirstFrameWithinFunction(
+ sample,
+ reinterpret_cast<const void*>(&TargetThread::SignalAndWaitUntilSignaled),
+ 100);
+ ASSERT_TRUE(loc != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(
+ reinterpret_cast<const void*>(
+ &TargetThread::SignalAndWaitUntilSignaled))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+ FilePath executable_path;
+ EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path));
+ EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
+}
+
+// Checks that the expected number of profiles and samples are present in the
+// call stack profiles produced.
+#if defined(_WIN64)
+#define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
+#else
+#define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) {
+ SamplingParams params;
+ params.burst_interval = params.sampling_interval =
+ TimeDelta::FromMilliseconds(0);
+ params.bursts = 2;
+ params.samples_per_burst = 3;
+
+ std::vector<CallStackProfile> profiles;
+ CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+
+ ASSERT_EQ(2u, profiles.size());
+ EXPECT_EQ(3u, profiles[0].samples.size());
+ EXPECT_EQ(3u, profiles[1].samples.size());
+}
+
+// Checks that no call stack profiles are captured if the profiling is stopped
+// during the initial delay.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
+#else
+#define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) {
+ SamplingParams params;
+ params.initial_delay = TimeDelta::FromSeconds(60);
+
+ std::vector<CallStackProfile> profiles;
+ CaptureProfilesWithObjectCallback(params, &profiles,
+ TimeDelta::FromMilliseconds(0));
+
+ EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that the single completed call stack profile is captured if the
+// profiling is stopped between bursts.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
+#else
+#define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(0);
+ params.burst_interval = TimeDelta::FromSeconds(60);
+ params.bursts = 2;
+ params.samples_per_burst = 1;
+
+ std::vector<CallStackProfile> profiles;
+ CaptureProfilesWithObjectCallback(params, &profiles,
+ TimeDelta::FromMilliseconds(50));
+
+ ASSERT_EQ(1u, profiles.size());
+ EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that only completed call stack profiles are captured.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
+#else
+#define MAYBE_StopDuringInterSampleInterval \
+ DISABLED_StopDuringInterSampleInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromSeconds(60);
+ params.samples_per_burst = 2;
+
+ std::vector<CallStackProfile> profiles;
+ CaptureProfilesWithObjectCallback(params, &profiles,
+ TimeDelta::FromMilliseconds(50));
+
+ EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that profiles are captured via the default completed callback.
+#if defined(_WIN64)
+#define MAYBE_DefaultCallback DefaultCallback
+#else
+#define MAYBE_DefaultCallback DISABLED_DefaultCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DefaultCallback) {
+ SamplingParams params;
+ params.samples_per_burst = 1;
+
+ CallStackProfiles profiles;
+ CaptureProfilesWithDefaultCallback(params, &profiles);
+
+ EXPECT_EQ(1u, profiles.size());
+ EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that profiles are queued until a default callback is set, then
+// delivered.
+#if defined(_WIN64)
+#define MAYBE_ProfilesQueuedWithNoCallback ProfilesQueuedWithNoCallback
+#else
+#define MAYBE_ProfilesQueuedWithNoCallback DISABLED_ProfilesQueuedWithNoCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_ProfilesQueuedWithNoCallback) {
+ SamplingParams params;
+ params.samples_per_burst = 1;
+
+ RunProfilerWithNoCallback(params, TimeDelta::FromMilliseconds(50));
+
+ CallStackProfiles profiles;
+ // This should immediately call SaveProfiles on this thread.
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ Bind(&SaveProfiles, Unretained(&profiles)));
+ EXPECT_EQ(1u, profiles.size());
+ EXPECT_EQ(1u, profiles[0].samples.size());
+ StackSamplingProfiler::SetDefaultCompletedCallback(
+ StackSamplingProfiler::CompletedCallback());
+}
+
+// Checks that we can destroy the profiler while profiling.
+#if defined(_WIN64)
+#define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling
+#else
+#define MAYBE_DestroyProfilerWhileProfiling \
+ DISABLED_DestroyProfilerWhileProfiling
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DestroyProfilerWhileProfiling) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(10);
+
+ CallStackProfiles profiles;
+ WithTargetThread([&params, &profiles](PlatformThreadId target_thread_id) {
+ scoped_ptr<StackSamplingProfiler> profiler;
+ profiler.reset(new StackSamplingProfiler(
+ target_thread_id, params, Bind(&SaveProfiles, Unretained(&profiles))));
+ profiler->Start();
+ profiler.reset();
+
+ // Wait longer than a sample interval to catch any use-after-free actions by
+ // the profiler thread.
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
+ });
+}
+
+} // namespace base
diff --git a/chromium/base/profiler/stack_sampling_profiler_win.cc b/chromium/base/profiler/stack_sampling_profiler_win.cc
new file mode 100644
index 00000000000..1ccd13412a6
--- /dev/null
+++ b/chromium/base/profiler/stack_sampling_profiler_win.cc
@@ -0,0 +1,357 @@
+// Copyright 2015 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 <objbase.h>
+#include <windows.h>
+
+#include <map>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/win/pe_image.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+namespace {
+
+// Walks the stack represented by |context| from the current frame downwards,
+// recording the instruction pointers for each frame in |instruction_pointers|.
+int RecordStack(CONTEXT* context,
+ int max_stack_size,
+ const void* instruction_pointers[],
+ bool* last_frame_is_unknown_function) {
+#ifdef _WIN64
+ *last_frame_is_unknown_function = false;
+
+ int i = 0;
+ for (; (i < max_stack_size) && context->Rip; ++i) {
+ // Try to look up unwind metadata for the current function.
+ ULONG64 image_base;
+ PRUNTIME_FUNCTION runtime_function =
+ RtlLookupFunctionEntry(context->Rip, &image_base, nullptr);
+
+ instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
+
+ if (runtime_function) {
+ KNONVOLATILE_CONTEXT_POINTERS nvcontext = {0};
+ void* handler_data;
+ ULONG64 establisher_frame;
+ RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
+ &handler_data, &establisher_frame, &nvcontext);
+ } else {
+ // If we don't have a RUNTIME_FUNCTION, then in theory this should be a
+ // leaf function whose frame contains only a return address, at
+ // RSP. However, crash data also indicates that some third party libraries
+ // do not provide RUNTIME_FUNCTION information for non-leaf functions. We
+ // could manually unwind the stack in the former case, but attempting to
+ // do so in the latter case would produce wrong results and likely crash,
+ // so just bail out.
+ //
+ // Ad hoc runs with instrumentation show that ~5% of stack traces end with
+ // a valid leaf function. To avoid selectively omitting these traces it
+ // makes sense to ultimately try to distinguish these two cases and
+ // selectively unwind the stack for legitimate leaf functions. For the
+ // purposes of avoiding crashes though, just ignore them all for now.
+ return i;
+ }
+ }
+ return i;
+#else
+ return 0;
+#endif
+}
+
+// Fills in |module_handles| corresponding to the pointers to code in
+// |addresses|. The module handles are returned with reference counts
+// incremented and should be freed with FreeModuleHandles. See note in
+// SuspendThreadAndRecordStack for why |addresses| and |module_handles| are
+// arrays.
+void FindModuleHandlesForAddresses(const void* const addresses[],
+ HMODULE module_handles[], int stack_depth,
+ bool last_frame_is_unknown_function) {
+ const int module_frames =
+ last_frame_is_unknown_function ? stack_depth - 1 : stack_depth;
+ for (int i = 0; i < module_frames; ++i) {
+ HMODULE module_handle = NULL;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<LPCTSTR>(addresses[i]),
+ &module_handle)) {
+ // HMODULE actually represents the base address of the module, so we can
+ // use it directly as an address.
+ DCHECK_LE(reinterpret_cast<const void*>(module_handle), addresses[i]);
+ module_handles[i] = module_handle;
+ }
+ }
+}
+
+// Frees the modules handles returned by FindModuleHandlesForAddresses. See note
+// in SuspendThreadAndRecordStack for why |module_handles| is an array.
+void FreeModuleHandles(int stack_depth, HMODULE module_handles[]) {
+ for (int i = 0; i < stack_depth; ++i) {
+ if (module_handles[i])
+ ::FreeLibrary(module_handles[i]);
+ }
+}
+
+// Gets the unique build ID for a module. Windows build IDs are created by a
+// concatenation of a GUID and AGE fields found in the headers of a module. The
+// GUID is stored in the first 16 bytes and the AGE is stored in the last 4
+// bytes. Returns the empty string if the function fails to get the build ID.
+//
+// Example:
+// dumpbin chrome.exe /headers | find "Format:"
+// ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
+//
+// The resulting buildID string of this instance of chrome.exe is
+// "16B2A4281DED442E9A36FCE8CBD2972610".
+//
+// Note that the AGE field is encoded in decimal, not hex.
+std::string GetBuildIDForModule(HMODULE module_handle) {
+ GUID guid;
+ DWORD age;
+ win::PEImage(module_handle).GetDebugId(&guid, &age);
+ const int kGUIDSize = 39;
+ std::wstring build_id;
+ int result =
+ ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize);
+ if (result != kGUIDSize)
+ return std::string();
+ RemoveChars(build_id, L"{}-", &build_id);
+ build_id += StringPrintf(L"%d", age);
+ return WideToUTF8(build_id);
+}
+
+// Disables priority boost on a thread for the lifetime of the object.
+class ScopedDisablePriorityBoost {
+ public:
+ ScopedDisablePriorityBoost(HANDLE thread_handle);
+ ~ScopedDisablePriorityBoost();
+
+ private:
+ HANDLE thread_handle_;
+ BOOL got_previous_boost_state_;
+ BOOL boost_state_was_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDisablePriorityBoost);
+};
+
+ScopedDisablePriorityBoost::ScopedDisablePriorityBoost(HANDLE thread_handle)
+ : thread_handle_(thread_handle),
+ got_previous_boost_state_(false),
+ boost_state_was_disabled_(false) {
+ got_previous_boost_state_ =
+ ::GetThreadPriorityBoost(thread_handle_, &boost_state_was_disabled_);
+ if (got_previous_boost_state_) {
+ // Confusingly, TRUE disables priority boost.
+ ::SetThreadPriorityBoost(thread_handle_, TRUE);
+ }
+}
+
+ScopedDisablePriorityBoost::~ScopedDisablePriorityBoost() {
+ if (got_previous_boost_state_)
+ ::SetThreadPriorityBoost(thread_handle_, boost_state_was_disabled_);
+}
+
+// Suspends the thread with |thread_handle|, records the stack into
+// |instruction_pointers|, then resumes the thread. Returns the size of the
+// stack.
+//
+// IMPORTANT NOTE: No heap allocations may occur between SuspendThread and
+// ResumeThread. Otherwise this code can deadlock on heap locks acquired by the
+// target thread before it was suspended. This is why we pass instruction
+// pointers and module handles as preallocated arrays rather than vectors, since
+// vectors make it too easy to subtly allocate memory.
+int SuspendThreadAndRecordStack(HANDLE thread_handle, int max_stack_size,
+ const void* instruction_pointers[],
+ bool* last_frame_is_unknown_function) {
+ if (::SuspendThread(thread_handle) == -1)
+ return 0;
+
+ int stack_depth = 0;
+ CONTEXT thread_context = {0};
+ thread_context.ContextFlags = CONTEXT_FULL;
+ if (::GetThreadContext(thread_handle, &thread_context)) {
+ stack_depth = RecordStack(&thread_context, max_stack_size,
+ instruction_pointers,
+ last_frame_is_unknown_function);
+ }
+
+ // Disable the priority boost that the thread would otherwise receive on
+ // resume. We do this to avoid artificially altering the dynamics of the
+ // executing application any more than we already are by suspending and
+ // resuming the thread.
+ //
+ // Note that this can racily disable a priority boost that otherwise would
+ // have been given to the thread, if the thread is waiting on other wait
+ // conditions at the time of SuspendThread and those conditions are satisfied
+ // before priority boost is reenabled. The measured length of this window is
+ // ~100us, so this should occur fairly rarely.
+ ScopedDisablePriorityBoost disable_priority_boost(thread_handle);
+ bool resume_thread_succeeded = ::ResumeThread(thread_handle) != -1;
+ CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
+
+ return stack_depth;
+}
+
+class NativeStackSamplerWin : public NativeStackSampler {
+ public:
+ explicit NativeStackSamplerWin(win::ScopedHandle thread_handle);
+ ~NativeStackSamplerWin() override;
+
+ // StackSamplingProfiler::NativeStackSampler:
+ void ProfileRecordingStarting(
+ std::vector<StackSamplingProfiler::Module>* modules) override;
+ void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
+ void ProfileRecordingStopped() override;
+
+ private:
+ // Attempts to query the module filename, base address, and id for
+ // |module_handle|, and store them in |module|. Returns true if it succeeded.
+ static bool GetModuleForHandle(HMODULE module_handle,
+ StackSamplingProfiler::Module* module);
+
+ // Gets the index for the Module corresponding to |module_handle| in
+ // |modules|, adding it if it's not already present. Returns
+ // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
+ // determined for |module|.
+ size_t GetModuleIndex(HMODULE module_handle,
+ std::vector<StackSamplingProfiler::Module>* modules);
+
+ // Copies the stack information represented by |instruction_pointers| into
+ // |sample| and |modules|.
+ void CopyToSample(const void* const instruction_pointers[],
+ const HMODULE module_handles[],
+ int stack_depth,
+ StackSamplingProfiler::Sample* sample,
+ std::vector<StackSamplingProfiler::Module>* modules);
+
+ win::ScopedHandle thread_handle_;
+ // Weak. Points to the modules associated with the profile being recorded
+ // between ProfileRecordingStarting() and ProfileRecordingStopped().
+ std::vector<StackSamplingProfiler::Module>* current_modules_;
+ // Maps a module handle to the corresponding Module's index within
+ // current_modules_.
+ std::map<HMODULE, size_t> profile_module_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
+};
+
+NativeStackSamplerWin::NativeStackSamplerWin(win::ScopedHandle thread_handle)
+ : thread_handle_(thread_handle.Take()) {
+}
+
+NativeStackSamplerWin::~NativeStackSamplerWin() {
+}
+
+void NativeStackSamplerWin::ProfileRecordingStarting(
+ std::vector<StackSamplingProfiler::Module>* modules) {
+ current_modules_ = modules;
+ profile_module_index_.clear();
+}
+
+void NativeStackSamplerWin::RecordStackSample(
+ StackSamplingProfiler::Sample* sample) {
+ DCHECK(current_modules_);
+
+ const int max_stack_size = 64;
+ const void* instruction_pointers[max_stack_size] = {0};
+ HMODULE module_handles[max_stack_size] = {0};
+
+ bool last_frame_is_unknown_function = false;
+ int stack_depth = SuspendThreadAndRecordStack(
+ thread_handle_.Get(), max_stack_size, instruction_pointers,
+ &last_frame_is_unknown_function);
+ FindModuleHandlesForAddresses(instruction_pointers, module_handles,
+ stack_depth, last_frame_is_unknown_function);
+ CopyToSample(instruction_pointers, module_handles, stack_depth, sample,
+ current_modules_);
+ FreeModuleHandles(stack_depth, module_handles);
+}
+
+void NativeStackSamplerWin::ProfileRecordingStopped() {
+ current_modules_ = nullptr;
+}
+
+// static
+bool NativeStackSamplerWin::GetModuleForHandle(
+ HMODULE module_handle,
+ StackSamplingProfiler::Module* module) {
+ wchar_t module_name[MAX_PATH];
+ DWORD result_length =
+ GetModuleFileName(module_handle, module_name, arraysize(module_name));
+ if (result_length == 0)
+ return false;
+
+ module->filename = base::FilePath(module_name);
+
+ module->base_address = reinterpret_cast<const void*>(module_handle);
+
+ module->id = GetBuildIDForModule(module_handle);
+ if (module->id.empty())
+ return false;
+
+ return true;
+}
+
+size_t NativeStackSamplerWin::GetModuleIndex(
+ HMODULE module_handle,
+ std::vector<StackSamplingProfiler::Module>* modules) {
+ if (!module_handle)
+ return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+
+ auto loc = profile_module_index_.find(module_handle);
+ if (loc == profile_module_index_.end()) {
+ StackSamplingProfiler::Module module;
+ if (!GetModuleForHandle(module_handle, &module))
+ return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+ modules->push_back(module);
+ loc = profile_module_index_.insert(std::make_pair(
+ module_handle, modules->size() - 1)).first;
+ }
+
+ return loc->second;
+}
+
+void NativeStackSamplerWin::CopyToSample(
+ const void* const instruction_pointers[],
+ const HMODULE module_handles[],
+ int stack_depth,
+ StackSamplingProfiler::Sample* sample,
+ std::vector<StackSamplingProfiler::Module>* module) {
+ sample->clear();
+ sample->reserve(stack_depth);
+
+ for (int i = 0; i < stack_depth; ++i) {
+ sample->push_back(StackSamplingProfiler::Frame(
+ instruction_pointers[i],
+ GetModuleIndex(module_handles[i], module)));
+ }
+}
+
+} // namespace
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+ PlatformThreadId thread_id) {
+#if _WIN64
+ // Get the thread's handle.
+ HANDLE thread_handle = ::OpenThread(
+ THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
+ FALSE,
+ thread_id);
+
+ if (thread_handle) {
+ return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin(
+ win::ScopedHandle(thread_handle)));
+ }
+#endif
+ return scoped_ptr<NativeStackSampler>();
+}
+
+} // namespace base
diff --git a/chromium/base/profiler/tracked_time.cc b/chromium/base/profiler/tracked_time.cc
index 7791c3adc6b..e5da68f5221 100644
--- a/chromium/base/profiler/tracked_time.cc
+++ b/chromium/base/profiler/tracked_time.cc
@@ -46,20 +46,12 @@ int32 Duration::InMilliseconds() const { return ms_; }
TrackedTime::TrackedTime() : ms_(0) {}
TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
TrackedTime::TrackedTime(const base::TimeTicks& time)
- : ms_((time - base::TimeTicks()).InMilliseconds()) {
+ : ms_(static_cast<int32>((time - base::TimeTicks()).InMilliseconds())) {
}
// static
TrackedTime TrackedTime::Now() {
-#if defined(OS_WIN)
- // Use lock-free accessor to 32 bit time.
- // Note that TimeTicks::Now() is built on this, so we have "compatible"
- // times when we down-convert a TimeTicks sample.
- return TrackedTime(base::TimeTicks::UnprotectedNow());
-#else
- // Posix has nice cheap 64 bit times, so we just down-convert it.
return TrackedTime(base::TimeTicks::Now());
-#endif // OS_WIN
}
Duration TrackedTime::operator-(const TrackedTime& other) const {
diff --git a/chromium/base/profiler/tracked_time_unittest.cc b/chromium/base/profiler/tracked_time_unittest.cc
index 3fa93830af0..c105688b31d 100644
--- a/chromium/base/profiler/tracked_time_unittest.cc
+++ b/chromium/base/profiler/tracked_time_unittest.cc
@@ -70,17 +70,14 @@ TEST(TrackedTimeTest, TrackedTimerVsTimeTicks) {
TEST(TrackedTimeTest, TrackedTimerDisabled) {
// Check to be sure disabling the collection of data induces a null time
// (which we know will return much faster).
- if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED))
- return;
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
// Since we disabled tracking, we should get a null response.
TrackedTime track_now = ThreadData::Now();
EXPECT_TRUE(track_now.is_null());
}
TEST(TrackedTimeTest, TrackedTimerEnabled) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE))
- return;
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
// Make sure that when we enable tracking, we get a real timer result.
// First get a 64 bit timer (which should not be null).
diff --git a/chromium/base/rand_util_unittest.cc b/chromium/base/rand_util_unittest.cc
index d26227505d0..90690ec2dbb 100644
--- a/chromium/base/rand_util_unittest.cc
+++ b/chromium/base/rand_util_unittest.cc
@@ -134,10 +134,10 @@ TEST(RandUtilTest, DISABLED_RandBytesPerf) {
const size_t kTestBufferSize = 1 * 1024 * 1024;
scoped_ptr<uint8[]> buffer(new uint8[kTestBufferSize]);
- const base::TimeTicks now = base::TimeTicks::HighResNow();
+ const base::TimeTicks now = base::TimeTicks::Now();
for (int i = 0; i < kTestIterations; ++i)
base::RandBytes(buffer.get(), kTestBufferSize);
- const base::TimeTicks end = base::TimeTicks::HighResNow();
+ const base::TimeTicks end = base::TimeTicks::Now();
LOG(INFO) << "RandBytes(" << kTestBufferSize << ") took: "
<< (end - now).InMicroseconds() << "µs";
diff --git a/chromium/base/scoped_generic.h b/chromium/base/scoped_generic.h
index da42609e5c4..f6807e2b58f 100644
--- a/chromium/base/scoped_generic.h
+++ b/chromium/base/scoped_generic.h
@@ -53,7 +53,7 @@ namespace base {
// typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo;
template<typename T, typename Traits>
class ScopedGeneric {
- MOVE_ONLY_TYPE_FOR_CPP_03(ScopedGeneric, RValue)
+ MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedGeneric)
private:
// This must be first since it's used inline below.
@@ -83,15 +83,21 @@ class ScopedGeneric {
: data_(value, traits) {
}
- // Move constructor for C++03 move emulation.
- ScopedGeneric(RValue rvalue)
- : data_(rvalue.object->release(), rvalue.object->get_traits()) {
+ // Move constructor. Allows initialization from a ScopedGeneric rvalue.
+ ScopedGeneric(ScopedGeneric<T, Traits>&& rvalue)
+ : data_(rvalue.release(), rvalue.get_traits()) {
}
~ScopedGeneric() {
FreeIfNecessary();
}
+ // operator=. Allows assignment from a ScopedGeneric rvalue.
+ ScopedGeneric& operator=(ScopedGeneric<T, Traits>&& rvalue) {
+ reset(rvalue.release());
+ return *this;
+ }
+
// Frees the currently owned object, if any. Then takes ownership of a new
// object, if given. Self-resets are not allowd as on scoped_ptr. See
// http://crbug.com/162971
diff --git a/chromium/base/scoped_generic_unittest.cc b/chromium/base/scoped_generic_unittest.cc
index f0dca22e693..b28e154372e 100644
--- a/chromium/base/scoped_generic_unittest.cc
+++ b/chromium/base/scoped_generic_unittest.cc
@@ -85,7 +85,7 @@ TEST(ScopedGenericTest, ScopedGeneric) {
EXPECT_EQ(kSecond, values_freed[1]);
values_freed.clear();
- // Pass.
+ // Pass constructor.
{
ScopedInt a(kFirst, traits);
ScopedInt b(a.Pass());
@@ -93,8 +93,25 @@ TEST(ScopedGenericTest, ScopedGeneric) {
ASSERT_EQ(IntTraits::InvalidValue(), a.get());
ASSERT_EQ(kFirst, b.get());
}
+
ASSERT_EQ(1u, values_freed.size());
ASSERT_EQ(kFirst, values_freed[0]);
+ values_freed.clear();
+
+ // Pass assign.
+ {
+ ScopedInt a(kFirst, traits);
+ ScopedInt b(kSecond, traits);
+ b = a.Pass();
+ ASSERT_EQ(1u, values_freed.size());
+ EXPECT_EQ(kSecond, values_freed[0]);
+ ASSERT_EQ(IntTraits::InvalidValue(), a.get());
+ ASSERT_EQ(kFirst, b.get());
+ }
+
+ ASSERT_EQ(2u, values_freed.size());
+ EXPECT_EQ(kFirst, values_freed[1]);
+ values_freed.clear();
}
TEST(ScopedGenericTest, Operators) {
diff --git a/chromium/base/scoped_native_library.h b/chromium/base/scoped_native_library.h
index e9923f43424..c0e93f37212 100644
--- a/chromium/base/scoped_native_library.h
+++ b/chromium/base/scoped_native_library.h
@@ -49,4 +49,4 @@ class BASE_EXPORT ScopedNativeLibrary {
} // namespace base
-#endif // BASE_MEMORY_NATIVE_LIBRARY_H_
+#endif // BASE_SCOPED_NATIVE_LIBRARY_H_
diff --git a/chromium/base/scoped_observer.h b/chromium/base/scoped_observer.h
index 5b0d53353ba..422701bc219 100644
--- a/chromium/base/scoped_observer.h
+++ b/chromium/base/scoped_observer.h
@@ -48,6 +48,8 @@ class ScopedObserver {
sources_.end();
}
+ bool IsObservingSources() const { return !sources_.empty(); }
+
private:
Observer* observer_;
diff --git a/chromium/base/security_unittest.cc b/chromium/base/security_unittest.cc
index a6d3480ef55..07ba6f5a0f2 100644
--- a/chromium/base/security_unittest.cc
+++ b/chromium/base/security_unittest.cc
@@ -23,17 +23,53 @@
#include <unistd.h>
#endif
+#if defined(OS_WIN)
+#include <new.h>
+#endif
+
using std::nothrow;
using std::numeric_limits;
namespace {
+#if defined(OS_WIN)
+// This is a permitted size but exhausts memory pretty quickly.
+const size_t kLargePermittedAllocation = 0x7FFFE000;
+
+int OnNoMemory(size_t) {
+ _exit(1);
+}
+
+void ExhaustMemoryWithMalloc() {
+ for (;;) {
+ // Without the |volatile|, clang optimizes away the allocation.
+ void* volatile buf = malloc(kLargePermittedAllocation);
+ if (!buf)
+ break;
+ }
+}
+
+void ExhaustMemoryWithRealloc() {
+ size_t size = kLargePermittedAllocation;
+ void* buf = malloc(size);
+ if (!buf)
+ return;
+ for (;;) {
+ size += kLargePermittedAllocation;
+ void* new_buf = realloc(buf, size);
+ if (!buf)
+ break;
+ buf = new_buf;
+ }
+}
+#endif
+
// This function acts as a compiler optimization barrier. We use it to
// prevent the compiler from making an expression a compile-time constant.
// We also use it so that the compiler doesn't discard certain return values
// as something we don't need (see the comment with calloc below).
template <typename Type>
-Type HideValueFromCompiler(volatile Type value) {
+NOINLINE Type HideValueFromCompiler(volatile Type value) {
#if defined(__GNUC__)
// In a GCC compatible compiler (GCC or Clang), make this compiler barrier
// more robust than merely using "volatile".
@@ -42,15 +78,18 @@ Type HideValueFromCompiler(volatile Type value) {
return value;
}
+// Tcmalloc and Windows allocator shim support setting malloc limits.
// - NO_TCMALLOC (should be defined if compiled with use_allocator!="tcmalloc")
// - ADDRESS_SANITIZER and SYZYASAN because they have their own memory allocator
// - IOS does not use tcmalloc
// - OS_MACOSX does not use tcmalloc
-#if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \
- !defined(OS_IOS) && !defined(OS_MACOSX) && !defined(SYZYASAN)
- #define TCMALLOC_TEST(function) function
+// - Windows allocator shim defines ALLOCATOR_SHIM
+#if (!defined(NO_TCMALLOC) || defined(ALLOCATOR_SHIM)) && \
+ !defined(ADDRESS_SANITIZER) && !defined(OS_IOS) && !defined(OS_MACOSX) && \
+ !defined(SYZYASAN)
+#define MALLOC_OVERFLOW_TEST(function) function
#else
- #define TCMALLOC_TEST(function) DISABLED_##function
+#define MALLOC_OVERFLOW_TEST(function) DISABLED_##function
#endif
// TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
@@ -64,12 +103,6 @@ bool IsTcMallocBypassed() {
char* g_slice = getenv("G_SLICE");
if (g_slice && !strcmp(g_slice, "always-malloc"))
return true;
-#elif defined(OS_WIN)
- // This should detect a TCMalloc bypass from setting
- // the CHROME_ALLOCATOR environment variable.
- char* allocator = getenv("CHROME_ALLOCATOR");
- if (allocator && strcmp(allocator, "tcmalloc"))
- return true;
#endif
return false;
}
@@ -89,7 +122,7 @@ bool CallocDiesOnOOM() {
}
// Fake test that allow to know the state of TCMalloc by looking at bots.
-TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) {
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(IsTCMallocDynamicallyBypassed)) {
printf("Malloc is dynamically bypassed: %s\n",
IsTcMallocBypassed() ? "yes." : "no.");
}
@@ -99,7 +132,7 @@ TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) {
// vulnerabilities in libraries that use int instead of size_t. See
// crbug.com/169327.
-TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) {
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsMalloc)) {
if (!IsTcMallocBypassed()) {
scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
HideValueFromCompiler(malloc(kTooBigAllocSize))));
@@ -107,7 +140,43 @@ TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) {
}
}
-TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) {
+#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationMallocDeathTest)) {
+ _set_new_handler(&OnNoMemory);
+ _set_new_mode(1);
+ {
+ scoped_ptr<char, base::FreeDeleter> ptr;
+ EXPECT_DEATH(ptr.reset(static_cast<char*>(
+ HideValueFromCompiler(malloc(kTooBigAllocSize)))),
+ "");
+ ASSERT_TRUE(!ptr);
+ }
+ _set_new_handler(NULL);
+ _set_new_mode(0);
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationExhaustDeathTest)) {
+ _set_new_handler(&OnNoMemory);
+ _set_new_mode(1);
+ {
+ ASSERT_DEATH(ExhaustMemoryWithMalloc(), "");
+ }
+ _set_new_handler(NULL);
+ _set_new_mode(0);
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryReallocationExhaustDeathTest)) {
+ _set_new_handler(&OnNoMemory);
+ _set_new_mode(1);
+ {
+ ASSERT_DEATH(ExhaustMemoryWithRealloc(), "");
+ }
+ _set_new_handler(NULL);
+ _set_new_mode(0);
+}
+#endif
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsCalloc)) {
if (!IsTcMallocBypassed()) {
scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
@@ -115,7 +184,7 @@ TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) {
}
}
-TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) {
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsRealloc)) {
if (!IsTcMallocBypassed()) {
char* orig_ptr = static_cast<char*>(malloc(1));
ASSERT_TRUE(orig_ptr);
@@ -131,7 +200,7 @@ typedef struct {
char large_array[kTooBigAllocSize];
} VeryLargeStruct;
-TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) {
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNew)) {
if (!IsTcMallocBypassed()) {
scoped_ptr<VeryLargeStruct> ptr(
HideValueFromCompiler(new (nothrow) VeryLargeStruct));
@@ -139,7 +208,20 @@ TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) {
}
}
-TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) {
+#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationNewDeathTest)) {
+ _set_new_handler(&OnNoMemory);
+ {
+ scoped_ptr<VeryLargeStruct> ptr;
+ EXPECT_DEATH(
+ ptr.reset(HideValueFromCompiler(new (nothrow) VeryLargeStruct)), "");
+ ASSERT_TRUE(!ptr);
+ }
+ _set_new_handler(NULL);
+}
+#endif
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNewArray)) {
if (!IsTcMallocBypassed()) {
scoped_ptr<char[]> ptr(
HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
@@ -194,7 +276,9 @@ TEST(SecurityTest, MAYBE_NewOverflow) {
}
// On windows, the compiler prevents static array sizes of more than
// 0x7fffffff (error C2148).
-#if !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+ ALLOW_UNUSED_LOCAL(kDynamicArraySize);
+#else
{
scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow)
char[kDynamicArraySize][kArraySize2]);
@@ -209,8 +293,8 @@ bool CallocReturnsNull(size_t nmemb, size_t size) {
scoped_ptr<char, base::FreeDeleter> array_pointer(
static_cast<char*>(calloc(nmemb, size)));
// We need the call to HideValueFromCompiler(): we have seen LLVM
- // optimize away the call to calloc() entirely and assume
- // the pointer to not be NULL.
+ // optimize away the call to calloc() entirely and assume the pointer to not
+ // be NULL.
return HideValueFromCompiler(array_pointer.get()) == NULL;
}
@@ -240,7 +324,7 @@ bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
}
// Check if TCMalloc uses an underlying random memory allocator.
-TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) {
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(RandomMemoryAllocations)) {
if (IsTcMallocBypassed())
return;
size_t kPageSize = 4096; // We support x86_64 only.
diff --git a/chromium/base/sequence_checker_unittest.cc b/chromium/base/sequence_checker_unittest.cc
index ad77db0999d..0aa0f9cdbb7 100644
--- a/chromium/base/sequence_checker_unittest.cc
+++ b/chromium/base/sequence_checker_unittest.cc
@@ -9,8 +9,8 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -56,14 +56,12 @@ class SequenceCheckerTest : public testing::Test {
public:
SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {}
- virtual ~SequenceCheckerTest() {}
-
- virtual void SetUp() override {
+ void SetUp() override {
other_thread_.Start();
ResetPool();
}
- virtual void TearDown() override {
+ void TearDown() override {
other_thread_.Stop();
pool()->Shutdown();
}
@@ -86,10 +84,9 @@ class SequenceCheckerTest : public testing::Test {
void PostDoStuffToOtherThread(
SequenceCheckedObject* sequence_checked_object) {
- other_thread()->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&SequenceCheckedObject::DoStuff,
- base::Unretained(sequence_checked_object)));
+ other_thread()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&SequenceCheckedObject::DoStuff,
+ base::Unretained(sequence_checked_object)));
}
void PostDeleteToOtherThread(
diff --git a/chromium/base/sequenced_task_runner.h b/chromium/base/sequenced_task_runner.h
index 71dcf05c750..6bb3f2b8717 100644
--- a/chromium/base/sequenced_task_runner.h
+++ b/chromium/base/sequenced_task_runner.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_SEQUENCED_TASKRUNNER_H_
-#define BASE_SEQUENCED_TASKRUNNER_H_
+#ifndef BASE_SEQUENCED_TASK_RUNNER_H_
+#define BASE_SEQUENCED_TASK_RUNNER_H_
#include "base/base_export.h"
#include "base/sequenced_task_runner_helpers.h"
@@ -156,4 +156,4 @@ class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
} // namespace base
-#endif // BASE_SEQUENCED_TASKRUNNER_H_
+#endif // BASE_SEQUENCED_TASK_RUNNER_H_
diff --git a/chromium/base/single_thread_task_runner.h b/chromium/base/single_thread_task_runner.h
index b5311db1694..6e931931489 100644
--- a/chromium/base/single_thread_task_runner.h
+++ b/chromium/base/single_thread_task_runner.h
@@ -16,7 +16,8 @@ namespace base {
// there is a specific need to run tasks on only a single thread.
//
// SingleThreadTaskRunner implementations might:
-// - Post tasks to an existing thread's MessageLoop (see MessageLoopProxy).
+// - Post tasks to an existing thread's MessageLoop (see
+// MessageLoop::task_runner()).
// - Create their own worker thread and MessageLoop to post tasks to.
// - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
// be processed. This allows TaskRunner-oriented code run on threads
diff --git a/chromium/base/stl_util.h b/chromium/base/stl_util.h
index 3602df0377a..e937d2f3ed9 100644
--- a/chromium/base/stl_util.h
+++ b/chromium/base/stl_util.h
@@ -90,6 +90,14 @@ void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
}
}
+// Counts the number of instances of val in a container.
+template <typename Container, typename T>
+typename std::iterator_traits<
+ typename Container::const_iterator>::difference_type
+STLCount(const Container& container, const T& val) {
+ return std::count(container.begin(), container.end(), val);
+}
+
// To treat a possibly-empty vector as an array, use these functions.
// If you know the array will never be empty, you can use &*v.begin()
// directly, but that is undefined behaviour if |v| is empty.
@@ -148,8 +156,7 @@ template <class T>
void STLDeleteValues(T* container) {
if (!container)
return;
- for (typename T::iterator i(container->begin()); i != container->end(); ++i)
- delete i->second;
+ STLDeleteContainerPairSecondPointers(container->begin(), container->end());
container->clear();
}
@@ -196,6 +203,14 @@ bool ContainsKey(const Collection& collection, const Key& key) {
return collection.find(key) != collection.end();
}
+// Test to see if a collection like a vector contains a particular value.
+// Returns true if the value is in the collection.
+template <typename Collection, typename Value>
+bool ContainsValue(const Collection& collection, const Value& value) {
+ return std::find(collection.begin(), collection.end(), value) !=
+ collection.end();
+}
+
namespace base {
// Returns true if the container is sorted.
diff --git a/chromium/base/stl_util_unittest.cc b/chromium/base/stl_util_unittest.cc
index a3f8e16f2ce..42004eb869b 100644
--- a/chromium/base/stl_util_unittest.cc
+++ b/chromium/base/stl_util_unittest.cc
@@ -28,7 +28,7 @@ class ComparableValue {
int value_;
};
-}
+} // namespace
namespace base {
namespace {
@@ -238,5 +238,30 @@ TEST(STLUtilTest, STLIncludes) {
EXPECT_TRUE(STLIncludes<std::set<int> >(a3, a2));
}
+TEST(StringAsArrayTest, Empty) {
+ std::string empty;
+ EXPECT_EQ(nullptr, string_as_array(&empty));
+}
+
+TEST(StringAsArrayTest, NullTerminated) {
+ // If any std::string implementation is not null-terminated, this should
+ // fail. All compilers we use return a null-terminated buffer, but please do
+ // not rely on this fact in your code.
+ std::string str("abcde");
+ str.resize(3);
+ EXPECT_STREQ("abc", string_as_array(&str));
+}
+
+TEST(StringAsArrayTest, WriteCopy) {
+ // With a COW implementation, this test will fail if
+ // string_as_array(&str) is implemented as
+ // const_cast<char*>(str->data()).
+ std::string s1("abc");
+ const std::string s2(s1);
+ string_as_array(&s1)[1] = 'x';
+ EXPECT_EQ("axc", s1);
+ EXPECT_EQ("abc", s2);
+}
+
} // namespace
} // namespace base
diff --git a/chromium/base/strings/nullable_string16.h b/chromium/base/strings/nullable_string16.h
index 5997d174419..016c25c2501 100644
--- a/chromium/base/strings/nullable_string16.h
+++ b/chromium/base/strings/nullable_string16.h
@@ -41,6 +41,6 @@ inline bool operator!=(const NullableString16& a, const NullableString16& b) {
BASE_EXPORT std::ostream& operator<<(std::ostream& out,
const NullableString16& value);
-} // namespace
+} // namespace base
#endif // BASE_STRINGS_NULLABLE_STRING16_H_
diff --git a/chromium/base/strings/safe_sprintf.cc b/chromium/base/strings/safe_sprintf.cc
index 5b575635519..b1fcf45b24f 100644
--- a/chromium/base/strings/safe_sprintf.cc
+++ b/chromium/base/strings/safe_sprintf.cc
@@ -510,11 +510,11 @@ ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args,
buffer.Pad(' ', padding, 1);
// Convert the argument to an ASCII character and output it.
- char ch = static_cast<char>(arg.integer.i);
- if (!ch) {
+ char as_char = static_cast<char>(arg.integer.i);
+ if (!as_char) {
goto end_of_output_buffer;
}
- buffer.Out(ch);
+ buffer.Out(as_char);
break; }
case 'd': // Output a possibly signed decimal value.
case 'o': // Output an unsigned octal value.
diff --git a/chromium/base/strings/safe_sprintf_unittest.cc b/chromium/base/strings/safe_sprintf_unittest.cc
index 02c75f990d1..ff05c6e2990 100644
--- a/chromium/base/strings/safe_sprintf_unittest.cc
+++ b/chromium/base/strings/safe_sprintf_unittest.cc
@@ -61,7 +61,7 @@ TEST(SafeSPrintfTest, NoArguments) {
// always add a trailing NUL; it always deduplicates '%' characters).
static const char text[] = "hello world";
char ref[20], buf[20];
- memset(ref, 'X', sizeof(char) * arraysize(buf));
+ memset(ref, 'X', sizeof(ref));
memcpy(buf, ref, sizeof(buf));
// A negative buffer size should always result in an error.
diff --git a/chromium/base/strings/string16.h b/chromium/base/strings/string16.h
index 804dca42e45..1a01a9613e7 100644
--- a/chromium/base/strings/string16.h
+++ b/chromium/base/strings/string16.h
@@ -94,7 +94,7 @@ struct string16_char_traits {
return c16memchr(s, a, n);
}
- static char_type* move(char_type* s1, const char_type* s2, int_type n) {
+ static char_type* move(char_type* s1, const char_type* s2, size_t n) {
return c16memmove(s1, s2, n);
}
diff --git a/chromium/base/strings/string_piece_unittest.cc b/chromium/base/strings/string_piece_unittest.cc
index 7f50cfbf679..53366036d6f 100644
--- a/chromium/base/strings/string_piece_unittest.cc
+++ b/chromium/base/strings/string_piece_unittest.cc
@@ -602,13 +602,13 @@ TYPED_TEST(CommonStringPieceTest, CheckComparisons2) {
// check comparison operations on strings longer than 4 bytes.
ASSERT_TRUE(abc == BasicStringPiece<TypeParam>(alphabet));
- ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet)) == 0);
+ ASSERT_EQ(abc.compare(BasicStringPiece<TypeParam>(alphabet)), 0);
ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z));
- ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)) < 0);
+ ASSERT_LT(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)), 0);
ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y));
- ASSERT_TRUE(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)) > 0);
+ ASSERT_GT(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)), 0);
}
// Test operations only supported by std::string version.
diff --git a/chromium/base/strings/string_split.cc b/chromium/base/strings/string_split.cc
index 7ef4760c58f..88a623664fc 100644
--- a/chromium/base/strings/string_split.cc
+++ b/chromium/base/strings/string_split.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
namespace base {
@@ -138,9 +137,9 @@ void SplitString(const std::string& str,
char c,
std::vector<std::string>* r) {
#if CHAR_MIN < 0
- DCHECK(c >= 0);
+ DCHECK_GE(c, 0);
#endif
- DCHECK(c < 0x7F);
+ DCHECK_LT(c, 0x7F);
SplitStringT(str, c, true, r);
}
@@ -193,11 +192,10 @@ void SplitStringDontTrim(const string16& str,
void SplitStringDontTrim(const std::string& str,
char c,
std::vector<std::string>* r) {
- DCHECK(IsStringUTF8(str));
#if CHAR_MIN < 0
- DCHECK(c >= 0);
+ DCHECK_GE(c, 0);
#endif
- DCHECK(c < 0x7F);
+ DCHECK_LT(c, 0x7F);
SplitStringT(str, c, false, r);
}
diff --git a/chromium/base/strings/string_util.cc b/chromium/base/strings/string_util.cc
index 43f15a360d9..e084cb5597d 100644
--- a/chromium/base/strings/string_util.cc
+++ b/chromium/base/strings/string_util.cc
@@ -406,7 +406,7 @@ bool IsStringASCII(const std::wstring& str) {
}
#endif
-bool IsStringUTF8(const std::string& str) {
+bool IsStringUTF8(const StringPiece& str) {
const char *src = str.data();
int32 src_len = static_cast<int32>(str.length());
int32 char_index = 0;
@@ -556,23 +556,103 @@ string16 FormatBytesUnlocalized(int64 bytes) {
return base::ASCIIToUTF16(buf);
}
+// Runs in O(n) time in the length of |str|.
template<class StringType>
void DoReplaceSubstringsAfterOffset(StringType* str,
- size_t start_offset,
+ size_t offset,
const StringType& find_this,
const StringType& replace_with,
bool replace_all) {
- if ((start_offset == StringType::npos) || (start_offset >= str->length()))
+ DCHECK(!find_this.empty());
+
+ // If the find string doesn't appear, there's nothing to do.
+ offset = str->find(find_this, offset);
+ if (offset == StringType::npos)
return;
- DCHECK(!find_this.empty());
- for (size_t offs(str->find(find_this, start_offset));
- offs != StringType::npos; offs = str->find(find_this, offs)) {
- str->replace(offs, find_this.length(), replace_with);
- offs += replace_with.length();
+ // If we're only replacing one instance, there's no need to do anything
+ // complicated.
+ size_t find_length = find_this.length();
+ if (!replace_all) {
+ str->replace(offset, find_length, replace_with);
+ return;
+ }
- if (!replace_all)
- break;
+ // If the find and replace strings are the same length, we can simply use
+ // replace() on each instance, and finish the entire operation in O(n) time.
+ size_t replace_length = replace_with.length();
+ if (find_length == replace_length) {
+ do {
+ str->replace(offset, find_length, replace_with);
+ offset = str->find(find_this, offset + replace_length);
+ } while (offset != StringType::npos);
+ return;
+ }
+
+ // Since the find and replace strings aren't the same length, a loop like the
+ // one above would be O(n^2) in the worst case, as replace() will shift the
+ // entire remaining string each time. We need to be more clever to keep
+ // things O(n).
+ //
+ // If we're shortening the string, we can alternate replacements with shifting
+ // forward the intervening characters using memmove().
+ size_t str_length = str->length();
+ if (find_length > replace_length) {
+ size_t write_offset = offset;
+ do {
+ if (replace_length) {
+ str->replace(write_offset, replace_length, replace_with);
+ write_offset += replace_length;
+ }
+ size_t read_offset = offset + find_length;
+ offset = std::min(str->find(find_this, read_offset), str_length);
+ size_t length = offset - read_offset;
+ if (length) {
+ memmove(&(*str)[write_offset], &(*str)[read_offset],
+ length * sizeof(typename StringType::value_type));
+ write_offset += length;
+ }
+ } while (offset < str_length);
+ str->resize(write_offset);
+ return;
+ }
+
+ // We're lengthening the string. We can use alternating replacements and
+ // memmove() calls like above, but we need to precalculate the final string
+ // length and then expand from back-to-front to avoid overwriting the string
+ // as we're reading it, needing to shift, or having to copy to a second string
+ // temporarily.
+ size_t first_match = offset;
+
+ // First, calculate the final length and resize the string.
+ size_t final_length = str_length;
+ size_t expansion = replace_length - find_length;
+ size_t current_match;
+ do {
+ final_length += expansion;
+ // Minor optimization: save this offset into |current_match|, so that on
+ // exit from the loop, |current_match| will point at the last instance of
+ // the find string, and we won't need to find() it again immediately.
+ current_match = offset;
+ offset = str->find(find_this, offset + find_length);
+ } while (offset != StringType::npos);
+ str->resize(final_length);
+
+ // Now do the replacement loop, working backwards through the string.
+ for (size_t prev_match = str_length, write_offset = final_length; ;
+ current_match = str->rfind(find_this, current_match - 1)) {
+ size_t read_offset = current_match + find_length;
+ size_t length = prev_match - read_offset;
+ if (length) {
+ write_offset -= length;
+ memmove(&(*str)[write_offset], &(*str)[read_offset],
+ length * sizeof(typename StringType::value_type));
+ }
+ write_offset -= replace_length;
+ str->replace(write_offset, replace_length, replace_with);
+ if (current_match == first_match)
+ return;
+ prev_match = current_match;
}
}
diff --git a/chromium/base/strings/string_util.h b/chromium/base/strings/string_util.h
index 1e2ac700e10..5ab2ad5d547 100644
--- a/chromium/base/strings/string_util.h
+++ b/chromium/base/strings/string_util.h
@@ -248,7 +248,7 @@ BASE_EXPORT bool ContainsOnlyChars(const StringPiece16& input,
//
// IsStringASCII assumes the input is likely all ASCII, and does not leave early
// if it is not the case.
-BASE_EXPORT bool IsStringUTF8(const std::string& str);
+BASE_EXPORT bool IsStringUTF8(const StringPiece& str);
BASE_EXPORT bool IsStringASCII(const StringPiece& str);
BASE_EXPORT bool IsStringASCII(const StringPiece16& str);
// A convenience adaptor for WebStrings, as they don't convert into
diff --git a/chromium/base/strings/string_util_unittest.cc b/chromium/base/strings/string_util_unittest.cc
index f29baac17b4..d887c0b35db 100644
--- a/chromium/base/strings/string_util_unittest.cc
+++ b/chromium/base/strings/string_util_unittest.cc
@@ -494,10 +494,10 @@ TEST(StringUtilTest, ConvertASCII) {
const char chars_with_nul[] = "test\0string";
const int length_with_nul = arraysize(chars_with_nul) - 1;
std::string string_with_nul(chars_with_nul, length_with_nul);
- std::wstring wide_with_nul = ASCIIToWide(string_with_nul);
- EXPECT_EQ(static_cast<std::wstring::size_type>(length_with_nul),
- wide_with_nul.length());
- std::string narrow_with_nul = UTF16ToASCII(WideToUTF16(wide_with_nul));
+ base::string16 string16_with_nul = ASCIIToUTF16(string_with_nul);
+ EXPECT_EQ(static_cast<base::string16::size_type>(length_with_nul),
+ string16_with_nul.length());
+ std::string narrow_with_nul = UTF16ToASCII(string16_with_nul);
EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul),
narrow_with_nul.length());
EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul));
@@ -669,39 +669,6 @@ TEST(StringUtilTest, HexDigitToInt) {
EXPECT_EQ(15, HexDigitToInt('f'));
}
-// This checks where we can use the assignment operator for a va_list. We need
-// a way to do this since Visual C doesn't support va_copy, but assignment on
-// va_list is not guaranteed to be a copy. See StringAppendVT which uses this
-// capability.
-static void VariableArgsFunc(const char* format, ...) {
- va_list org;
- va_start(org, format);
-
- va_list dup;
- GG_VA_COPY(dup, org);
- int i1 = va_arg(org, int);
- int j1 = va_arg(org, int);
- char* s1 = va_arg(org, char*);
- double d1 = va_arg(org, double);
- va_end(org);
-
- int i2 = va_arg(dup, int);
- int j2 = va_arg(dup, int);
- char* s2 = va_arg(dup, char*);
- double d2 = va_arg(dup, double);
-
- EXPECT_EQ(i1, i2);
- EXPECT_EQ(j1, j2);
- EXPECT_STREQ(s1, s2);
- EXPECT_EQ(d1, d2);
-
- va_end(dup);
-}
-
-TEST(StringUtilTest, VAList) {
- VariableArgsFunc("%d %d %s %lf", 45, 92, "This is interesting", 9.21);
-}
-
// Test for Tokenize
template <typename STR>
void TokenizeTest() {
diff --git a/chromium/base/strings/string_util_win.h b/chromium/base/strings/string_util_win.h
index 602ba273784..61eda2009d0 100644
--- a/chromium/base/strings/string_util_win.h
+++ b/chromium/base/strings/string_util_win.h
@@ -34,12 +34,9 @@ inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
inline int vsnprintf(char* buffer, size_t size,
const char* format, va_list arguments) {
- int length = _vsprintf_p(buffer, size, format, arguments);
- if (length < 0) {
- if (size > 0)
- buffer[0] = 0;
- return _vscprintf_p(format, arguments);
- }
+ int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
+ if (length < 0)
+ return _vscprintf(format, arguments);
return length;
}
@@ -47,12 +44,9 @@ inline int vswprintf(wchar_t* buffer, size_t size,
const wchar_t* format, va_list arguments) {
DCHECK(IsWprintfFormatPortable(format));
- int length = _vswprintf_p(buffer, size, format, arguments);
- if (length < 0) {
- if (size > 0)
- buffer[0] = 0;
- return _vscwprintf_p(format, arguments);
- }
+ int length = _vsnwprintf_s(buffer, size, size - 1, format, arguments);
+ if (length < 0)
+ return _vscwprintf(format, arguments);
return length;
}
diff --git a/chromium/base/strings/stringprintf.cc b/chromium/base/strings/stringprintf.cc
index 3d024fa65aa..537873d71c8 100644
--- a/chromium/base/strings/stringprintf.cc
+++ b/chromium/base/strings/stringprintf.cc
@@ -6,6 +6,8 @@
#include <errno.h>
+#include <vector>
+
#include "base/scoped_clear_errno.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -27,7 +29,7 @@ inline int vsnprintfT(char* buffer,
return base::vsnprintf(buffer, buf_size, format, argptr);
}
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
inline int vsnprintfT(wchar_t* buffer,
size_t buf_size,
const wchar_t* format,
@@ -48,7 +50,7 @@ static void StringAppendVT(StringType* dst,
typename StringType::value_type stack_buf[1024];
va_list ap_copy;
- GG_VA_COPY(ap_copy, ap);
+ va_copy(ap_copy, ap);
#if !defined(OS_WIN)
ScopedClearErrno clear_errno;
@@ -94,7 +96,7 @@ static void StringAppendVT(StringType* dst,
// NOTE: You can only use a va_list once. Since we're in a while loop, we
// need to make a new copy each time so we don't use up the original.
- GG_VA_COPY(ap_copy, ap);
+ va_copy(ap_copy, ap);
result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
va_end(ap_copy);
@@ -117,7 +119,7 @@ std::string StringPrintf(const char* format, ...) {
return result;
}
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
std::wstring StringPrintf(const wchar_t* format, ...) {
va_list ap;
va_start(ap, format);
@@ -143,7 +145,7 @@ const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
return *dst;
}
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
const std::wstring& SStringPrintf(std::wstring* dst,
const wchar_t* format, ...) {
va_list ap;
@@ -162,7 +164,7 @@ void StringAppendF(std::string* dst, const char* format, ...) {
va_end(ap);
}
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
va_list ap;
va_start(ap, format);
@@ -175,7 +177,7 @@ void StringAppendV(std::string* dst, const char* format, va_list ap) {
StringAppendVT(dst, format, ap);
}
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
StringAppendVT(dst, format, ap);
}
diff --git a/chromium/base/strings/stringprintf.h b/chromium/base/strings/stringprintf.h
index d924a0e59f2..523f7ee55bf 100644
--- a/chromium/base/strings/stringprintf.h
+++ b/chromium/base/strings/stringprintf.h
@@ -17,8 +17,7 @@ namespace base {
// Return a C++ string given printf-like input.
BASE_EXPORT std::string StringPrintf(const char* format, ...)
PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
-// OS_ANDROID's libc does not support wchar_t, so several overloads are omitted.
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
#endif
@@ -31,7 +30,7 @@ BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
const char* format, ...)
PRINTF_FORMAT(2, 3);
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
const wchar_t* format, ...)
WPRINTF_FORMAT(2, 3);
@@ -40,9 +39,7 @@ BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
// Append result to a supplied string.
BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
PRINTF_FORMAT(2, 3);
-#if !defined(OS_ANDROID)
-// TODO(evanm): this is only used in a few places in the code;
-// replace with string16 version.
+#if defined(OS_WIN)
BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
WPRINTF_FORMAT(2, 3);
#endif
@@ -51,7 +48,7 @@ BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
// string. All other routines are just convenience wrappers around it.
BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
PRINTF_FORMAT(2, 0);
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
BASE_EXPORT void StringAppendV(std::wstring* dst,
const wchar_t* format, va_list ap)
WPRINTF_FORMAT(2, 0);
diff --git a/chromium/base/strings/stringprintf_unittest.cc b/chromium/base/strings/stringprintf_unittest.cc
index 4935b553b0e..c49637c23f2 100644
--- a/chromium/base/strings/stringprintf_unittest.cc
+++ b/chromium/base/strings/stringprintf_unittest.cc
@@ -31,7 +31,7 @@ TEST(StringPrintfTest, StringPrintfEmpty) {
TEST(StringPrintfTest, StringPrintfMisc) {
EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
#endif
}
@@ -41,7 +41,7 @@ TEST(StringPrintfTest, StringAppendfEmptyString) {
StringAppendF(&value, "%s", "");
EXPECT_EQ("Hello", value);
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
std::wstring valuew(L"Hello");
StringAppendF(&valuew, L"%ls", L"");
EXPECT_EQ(L"Hello", valuew);
@@ -53,7 +53,7 @@ TEST(StringPrintfTest, StringAppendfString) {
StringAppendF(&value, " %s", "World");
EXPECT_EQ("Hello World", value);
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
std::wstring valuew(L"Hello");
StringAppendF(&valuew, L" %ls", L"World");
EXPECT_EQ(L"Hello World", valuew);
@@ -65,7 +65,7 @@ TEST(StringPrintfTest, StringAppendfInt) {
StringAppendF(&value, " %d", 123);
EXPECT_EQ("Hello 123", value);
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
std::wstring valuew(L"Hello");
StringAppendF(&valuew, L" %d", 123);
EXPECT_EQ(L"Hello 123", valuew);
@@ -90,7 +90,7 @@ TEST(StringPrintfTest, StringPrintfBounds) {
SStringPrintf(&out, "%s", src);
EXPECT_STREQ(src, out.c_str());
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
srcw[kSrcLen - i] = 0;
std::wstring outw;
SStringPrintf(&outw, L"%ls", srcw);
@@ -163,19 +163,6 @@ TEST(StringPrintfTest, Invalid) {
}
#endif
-// Test that the positional parameters work.
-TEST(StringPrintfTest, PositionalParameters) {
- std::string out;
- SStringPrintf(&out, "%1$s %1$s", "test");
- EXPECT_STREQ("test test", out.c_str());
-
-#if defined(OS_WIN)
- std::wstring wout;
- SStringPrintf(&wout, L"%1$ls %1$ls", L"test");
- EXPECT_STREQ(L"test test", wout.c_str());
-#endif
-}
-
// Test that StringPrintf and StringAppendV do not change errno.
TEST(StringPrintfTest, StringPrintfErrno) {
errno = 1;
diff --git a/chromium/base/strings/sys_string_conversions_posix.cc b/chromium/base/strings/sys_string_conversions_posix.cc
index 1e926bb5490..3b1845622fd 100644
--- a/chromium/base/strings/sys_string_conversions_posix.cc
+++ b/chromium/base/strings/sys_string_conversions_posix.cc
@@ -24,11 +24,10 @@ std::wstring SysUTF8ToWide(const StringPiece& utf8) {
return out;
}
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID)
// TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb()
// support and a better understanding of what calls these routines.
-// ChromeOS always runs in UTF-8 locale.
std::string SysWideToNativeMB(const std::wstring& wide) {
return WideToUTF8(wide);
}
diff --git a/chromium/base/strings/sys_string_conversions_unittest.cc b/chromium/base/strings/sys_string_conversions_unittest.cc
index d2d38e40cc4..0cdd4281ecf 100644
--- a/chromium/base/strings/sys_string_conversions_unittest.cc
+++ b/chromium/base/strings/sys_string_conversions_unittest.cc
@@ -75,7 +75,9 @@ TEST(SysStrings, SysUTF8ToWide) {
#if defined(OS_LINUX) // Tests depend on setting a specific Linux locale.
TEST(SysStrings, SysWideToNativeMB) {
+#if !defined(SYSTEM_NATIVE_UTF8)
ScopedLocale locale("en_US.utf-8");
+#endif
EXPECT_EQ("Hello, world", SysWideToNativeMB(L"Hello, world"));
EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToNativeMB(L"\x4f60\x597d"));
@@ -105,7 +107,9 @@ TEST(SysStrings, SysWideToNativeMB) {
// We assume the test is running in a UTF8 locale.
TEST(SysStrings, SysNativeMBToWide) {
+#if !defined(SYSTEM_NATIVE_UTF8)
ScopedLocale locale("en_US.utf-8");
+#endif
EXPECT_EQ(L"Hello, world", SysNativeMBToWide("Hello, world"));
EXPECT_EQ(L"\x4f60\x597d", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
// >16 bits
@@ -159,7 +163,9 @@ static const wchar_t* const kConvertRoundtripCases[] = {
TEST(SysStrings, SysNativeMBAndWide) {
+#if !defined(SYSTEM_NATIVE_UTF8)
ScopedLocale locale("en_US.utf-8");
+#endif
for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
std::wstring wide = kConvertRoundtripCases[i];
std::wstring trip = SysNativeMBToWide(SysWideToNativeMB(wide));
diff --git a/chromium/base/strings/utf_offset_string_conversions_unittest.cc b/chromium/base/strings/utf_offset_string_conversions_unittest.cc
index 529939f6013..9398a56233c 100644
--- a/chromium/base/strings/utf_offset_string_conversions_unittest.cc
+++ b/chromium/base/strings/utf_offset_string_conversions_unittest.cc
@@ -293,4 +293,4 @@ TEST(UTFOffsetStringConversionsTest, MergeSequentialAdjustments) {
EXPECT_EQ(2u, adjustments_on_adjusted_string[5].output_length);
}
-} // namaspace base
+} // namespace base
diff --git a/chromium/base/strings/utf_string_conversions.cc b/chromium/base/strings/utf_string_conversions.cc
index 9796eec5e15..1480d48086f 100644
--- a/chromium/base/strings/utf_string_conversions.cc
+++ b/chromium/base/strings/utf_string_conversions.cc
@@ -209,11 +209,6 @@ std::string UTF16ToUTF8(const string16& utf16) {
#endif
-std::wstring ASCIIToWide(const StringPiece& ascii) {
- DCHECK(IsStringASCII(ascii)) << ascii;
- return std::wstring(ascii.begin(), ascii.end());
-}
-
string16 ASCIIToUTF16(const StringPiece& ascii) {
DCHECK(IsStringASCII(ascii)) << ascii;
return string16(ascii.begin(), ascii.end());
diff --git a/chromium/base/strings/utf_string_conversions.h b/chromium/base/strings/utf_string_conversions.h
index 13e0b7193be..06a3bc64767 100644
--- a/chromium/base/strings/utf_string_conversions.h
+++ b/chromium/base/strings/utf_string_conversions.h
@@ -39,9 +39,8 @@ BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
std::string* output);
BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
-// These convert an ASCII string, typically a hardcoded constant, to a
-// UTF16/Wide string.
-BASE_EXPORT std::wstring ASCIIToWide(const StringPiece& ascii);
+// This converts an ASCII string, typically a hardcoded constant, to a UTF16
+// string.
BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
diff --git a/chromium/base/strings/utf_string_conversions_unittest.cc b/chromium/base/strings/utf_string_conversions_unittest.cc
index 009af7c4f53..a7b12ffe0e0 100644
--- a/chromium/base/strings/utf_string_conversions_unittest.cc
+++ b/chromium/base/strings/utf_string_conversions_unittest.cc
@@ -208,4 +208,4 @@ TEST(UTFStringConversionsTest, ConvertMultiString) {
EXPECT_EQ(expected, converted);
}
-} // base
+} // namespace base
diff --git a/chromium/base/supports_user_data.h b/chromium/base/supports_user_data.h
index 6d515d7341e..711ee7d8979 100644
--- a/chromium/base/supports_user_data.h
+++ b/chromium/base/supports_user_data.h
@@ -61,7 +61,7 @@ class BASE_EXPORT SupportsUserData {
template <typename T>
class UserDataAdapter : public base::SupportsUserData::Data {
public:
- static T* Get(SupportsUserData* supports_user_data, const void* key) {
+ static T* Get(const SupportsUserData* supports_user_data, const void* key) {
UserDataAdapter* data =
static_cast<UserDataAdapter*>(supports_user_data->GetUserData(key));
return data ? static_cast<T*>(data->object_.get()) : NULL;
diff --git a/chromium/base/sync_socket.h b/chromium/base/sync_socket.h
index 4da9d3b6b3a..36d6bc1f59b 100644
--- a/chromium/base/sync_socket.h
+++ b/chromium/base/sync_socket.h
@@ -124,11 +124,11 @@ class BASE_EXPORT CancelableSyncSocket : public SyncSocket {
// and there isn't a way to cancel a blocking synchronous Read that is
// supported on <Vista. So, for Windows only, we override these
// SyncSocket methods in order to support shutting down the 'socket'.
- virtual bool Close() override;
- virtual size_t Receive(void* buffer, size_t length) override;
- virtual size_t ReceiveWithTimeout(void* buffer,
- size_t length,
- TimeDelta timeout) override;
+ bool Close() override;
+ size_t Receive(void* buffer, size_t length) override;
+ size_t ReceiveWithTimeout(void* buffer,
+ size_t length,
+ TimeDelta timeout) override;
#endif
// Send() is overridden to catch cases where the remote end is not responding
diff --git a/chromium/base/synchronization/cancellation_flag.cc b/chromium/base/synchronization/cancellation_flag.cc
index ad3b551169d..ca5c0a82837 100644
--- a/chromium/base/synchronization/cancellation_flag.cc
+++ b/chromium/base/synchronization/cancellation_flag.cc
@@ -19,4 +19,8 @@ bool CancellationFlag::IsSet() const {
return base::subtle::Acquire_Load(&flag_) != 0;
}
+void CancellationFlag::UnsafeResetForTesting() {
+ base::subtle::Release_Store(&flag_, 0);
+}
+
} // namespace base
diff --git a/chromium/base/synchronization/cancellation_flag.h b/chromium/base/synchronization/cancellation_flag.h
index 51a4def1eb3..0f0f08ee8f7 100644
--- a/chromium/base/synchronization/cancellation_flag.h
+++ b/chromium/base/synchronization/cancellation_flag.h
@@ -29,6 +29,11 @@ class BASE_EXPORT CancellationFlag {
void Set();
bool IsSet() const; // Returns true iff the flag was set.
+ // For subtle reasons that may be different on different architectures,
+ // a different thread testing IsSet() may erroneously read 'true' after
+ // this method has been called.
+ void UnsafeResetForTesting();
+
private:
base::subtle::Atomic32 flag_;
#if !defined(NDEBUG)
diff --git a/chromium/base/synchronization/cancellation_flag_unittest.cc b/chromium/base/synchronization/cancellation_flag_unittest.cc
index 02b08b6a9de..13c74bcbd45 100644
--- a/chromium/base/synchronization/cancellation_flag_unittest.cc
+++ b/chromium/base/synchronization/cancellation_flag_unittest.cc
@@ -7,8 +7,9 @@
#include "base/synchronization/cancellation_flag.h"
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/spin_wait.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
@@ -56,7 +57,7 @@ TEST(CancellationFlagTest, SetOnDifferentThreadDeathTest) {
ASSERT_TRUE(t.IsRunning());
CancellationFlag flag;
- t.message_loop()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
+ t.task_runner()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
}
} // namespace
diff --git a/chromium/base/synchronization/condition_variable_unittest.cc b/chromium/base/synchronization/condition_variable_unittest.cc
index 5d7a0ab8b60..e63a723d009 100644
--- a/chromium/base/synchronization/condition_variable_unittest.cc
+++ b/chromium/base/synchronization/condition_variable_unittest.cc
@@ -9,8 +9,10 @@
#include <vector>
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/spin_wait.h"
@@ -220,7 +222,7 @@ TEST_F(ConditionVariableTest, DISABLED_TimeoutAcrossSetTimeOfDay) {
Thread thread("Helper");
thread.Start();
- thread.message_loop()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
+ thread.task_runner()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
TimeTicks start = TimeTicks::Now();
const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300);
diff --git a/chromium/base/synchronization/condition_variable_win.cc b/chromium/base/synchronization/condition_variable_win.cc
index 6dc4831a78f..5f165c8a86e 100644
--- a/chromium/base/synchronization/condition_variable_win.cc
+++ b/chromium/base/synchronization/condition_variable_win.cc
@@ -72,12 +72,12 @@ class ConditionVarImpl {
class WinVistaCondVar: public ConditionVarImpl {
public:
WinVistaCondVar(Lock* user_lock);
- ~WinVistaCondVar() {};
+ ~WinVistaCondVar() override {}
// Overridden from ConditionVarImpl.
- virtual void Wait() override;
- virtual void TimedWait(const TimeDelta& max_time) override;
- virtual void Broadcast() override;
- virtual void Signal() override;
+ void Wait() override;
+ void TimedWait(const TimeDelta& max_time) override;
+ void Broadcast() override;
+ void Signal() override;
private:
base::Lock& user_lock_;
@@ -127,12 +127,12 @@ void WinVistaCondVar::Signal() {
class WinXPCondVar : public ConditionVarImpl {
public:
WinXPCondVar(Lock* user_lock);
- ~WinXPCondVar();
+ ~WinXPCondVar() override;
// Overridden from ConditionVarImpl.
- virtual void Wait() override;
- virtual void TimedWait(const TimeDelta& max_time) override;
- virtual void Broadcast() override;
- virtual void Signal() override;
+ void Wait() override;
+ void TimedWait(const TimeDelta& max_time) override;
+ void Broadcast() override;
+ void Signal() override;
// Define Event class that is used to form circularly linked lists.
// The list container is an element with NULL as its handle_ value.
diff --git a/chromium/base/synchronization/waitable_event.h b/chromium/base/synchronization/waitable_event.h
index 39c0d11538c..c35af5467f6 100644
--- a/chromium/base/synchronization/waitable_event.h
+++ b/chromium/base/synchronization/waitable_event.h
@@ -21,9 +21,6 @@
namespace base {
-// This replaces INFINITE from Win32
-static const int kNoTimeout = -1;
-
class TimeDelta;
// A WaitableEvent can be a useful thread synchronization tool when you want to
@@ -53,11 +50,7 @@ class BASE_EXPORT WaitableEvent {
// Create a WaitableEvent from an Event HANDLE which has already been
// created. This objects takes ownership of the HANDLE and will close it when
// deleted.
- // TODO(rvargas): Pass ScopedHandle instead (and on Release).
- explicit WaitableEvent(HANDLE event_handle);
-
- // Releases ownership of the handle from this object.
- HANDLE Release();
+ explicit WaitableEvent(win::ScopedHandle event_handle);
#endif
~WaitableEvent();
diff --git a/chromium/base/synchronization/waitable_event_unittest.cc b/chromium/base/synchronization/waitable_event_unittest.cc
index abba9356bb1..be56cf171a1 100644
--- a/chromium/base/synchronization/waitable_event_unittest.cc
+++ b/chromium/base/synchronization/waitable_event_unittest.cc
@@ -73,29 +73,27 @@ TEST(WaitableEventTest, WaitManyShortcut) {
class WaitableEventSignaler : public PlatformThread::Delegate {
public:
- WaitableEventSignaler(double seconds, WaitableEvent* ev)
- : seconds_(seconds),
- ev_(ev) {
+ WaitableEventSignaler(TimeDelta delay, WaitableEvent* event)
+ : delay_(delay),
+ event_(event) {
}
void ThreadMain() override {
- PlatformThread::Sleep(TimeDelta::FromSecondsD(seconds_));
- ev_->Signal();
+ PlatformThread::Sleep(delay_);
+ event_->Signal();
}
private:
- const double seconds_;
- WaitableEvent *const ev_;
+ const TimeDelta delay_;
+ WaitableEvent* event_;
};
+// Tests that a WaitableEvent can be safely deleted when |Wait| is done without
+// additional synchronization.
TEST(WaitableEventTest, WaitAndDelete) {
- // This test tests that if a WaitableEvent can be safely deleted
- // when |Wait| is done without additional synchrnization.
- // If this test crashes, it is a bug.
-
WaitableEvent* ev = new WaitableEvent(false, false);
- WaitableEventSignaler signaler(0.01, ev);
+ WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev);
PlatformThreadHandle thread;
PlatformThread::Create(0, &signaler, &thread);
@@ -105,16 +103,14 @@ TEST(WaitableEventTest, WaitAndDelete) {
PlatformThread::Join(thread);
}
+// Tests that a WaitableEvent can be safely deleted when |WaitMany| is done
+// without additional synchronization.
TEST(WaitableEventTest, WaitMany) {
- // This test tests that if a WaitableEvent can be safely deleted
- // when |WaitMany| is done without additional synchrnization.
- // If this test crashes, it is a bug.
-
WaitableEvent* ev[5];
for (unsigned i = 0; i < 5; ++i)
ev[i] = new WaitableEvent(false, false);
- WaitableEventSignaler signaler(0.01, ev[2]);
+ WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev[2]);
PlatformThreadHandle thread;
PlatformThread::Create(0, &signaler, &thread);
@@ -127,4 +123,28 @@ TEST(WaitableEventTest, WaitMany) {
EXPECT_EQ(2u, index);
}
+// Tests that using TimeDelta::Max() on TimedWait() is not the same as passing
+// a timeout of 0. (crbug.com/465948)
+#if defined(OS_POSIX)
+// crbug.com/465948 not fixed yet.
+#define MAYBE_TimedWait DISABLED_TimedWait
+#else
+#define MAYBE_TimedWait TimedWait
+#endif
+TEST(WaitableEventTest, MAYBE_TimedWait) {
+ WaitableEvent* ev = new WaitableEvent(false, false);
+
+ TimeDelta thread_delay = TimeDelta::FromMilliseconds(10);
+ WaitableEventSignaler signaler(thread_delay, ev);
+ PlatformThreadHandle thread;
+ TimeTicks start = TimeTicks::Now();
+ PlatformThread::Create(0, &signaler, &thread);
+
+ ev->TimedWait(TimeDelta::Max());
+ EXPECT_GE(TimeTicks::Now() - start, thread_delay);
+ delete ev;
+
+ PlatformThread::Join(thread);
+}
+
} // namespace base
diff --git a/chromium/base/synchronization/waitable_event_watcher.h b/chromium/base/synchronization/waitable_event_watcher.h
index d4d8e7779bd..eb51effa499 100644
--- a/chromium/base/synchronization/waitable_event_watcher.h
+++ b/chromium/base/synchronization/waitable_event_watcher.h
@@ -92,7 +92,7 @@ class BASE_EXPORT WaitableEventWatcher
private:
#if defined(OS_WIN)
- virtual void OnObjectSignaled(HANDLE h) override;
+ void OnObjectSignaled(HANDLE h) override;
win::ObjectWatcher watcher_;
#else
// Implementation of MessageLoop::DestructionObserver
diff --git a/chromium/base/synchronization/waitable_event_watcher_posix.cc b/chromium/base/synchronization/waitable_event_watcher_posix.cc
index 6fc337cc81b..ad66a4c769a 100644
--- a/chromium/base/synchronization/waitable_event_watcher_posix.cc
+++ b/chromium/base/synchronization/waitable_event_watcher_posix.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
@@ -68,7 +68,7 @@ class AsyncWaiter : public WaitableEvent::Waiter {
bool Fire(WaitableEvent* event) override {
// Post the callback if we haven't been cancelled.
if (!flag_->value()) {
- message_loop_->PostTask(FROM_HERE, callback_);
+ message_loop_->task_runner()->PostTask(FROM_HERE, callback_);
}
// We are removed from the wait-list by the WaitableEvent itself. It only
@@ -158,7 +158,7 @@ bool WaitableEventWatcher::StartWatching(
// No hairpinning - we can't call the delegate directly here. We have to
// enqueue a task on the MessageLoop as normal.
- current_ml->PostTask(FROM_HERE, internal_callback_);
+ current_ml->task_runner()->PostTask(FROM_HERE, internal_callback_);
return true;
}
diff --git a/chromium/base/synchronization/waitable_event_watcher_win.cc b/chromium/base/synchronization/waitable_event_watcher_win.cc
index f5218f1361d..46d47ac581a 100644
--- a/chromium/base/synchronization/waitable_event_watcher_win.cc
+++ b/chromium/base/synchronization/waitable_event_watcher_win.cc
@@ -5,7 +5,6 @@
#include "base/synchronization/waitable_event_watcher.h"
#include "base/compiler_specific.h"
-#include "base/profiler/scoped_tracker.h"
#include "base/synchronization/waitable_event.h"
#include "base/win/object_watcher.h"
@@ -37,10 +36,6 @@ WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
}
void WaitableEventWatcher::OnObjectSignaled(HANDLE h) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("WaitableEventWatche_OnObjectSignaled"));
-
WaitableEvent* event = event_;
EventCallback callback = callback_;
event_ = NULL;
diff --git a/chromium/base/synchronization/waitable_event_win.cc b/chromium/base/synchronization/waitable_event_win.cc
index ec2d84f2679..4db56277b7c 100644
--- a/chromium/base/synchronization/waitable_event_win.cc
+++ b/chromium/base/synchronization/waitable_event_win.cc
@@ -4,10 +4,10 @@
#include "base/synchronization/waitable_event.h"
-#include <math.h>
#include <windows.h>
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
@@ -20,18 +20,14 @@ WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
CHECK(handle_.IsValid());
}
-WaitableEvent::WaitableEvent(HANDLE handle)
- : handle_(handle) {
+WaitableEvent::WaitableEvent(win::ScopedHandle handle)
+ : handle_(handle.Pass()) {
CHECK(handle_.IsValid()) << "Tried to create WaitableEvent from NULL handle";
}
WaitableEvent::~WaitableEvent() {
}
-HANDLE WaitableEvent::Release() {
- return handle_.Take();
-}
-
void WaitableEvent::Reset() {
ResetEvent(handle_.Get());
}
@@ -41,7 +37,7 @@ void WaitableEvent::Signal() {
}
bool WaitableEvent::IsSignaled() {
- return TimedWait(TimeDelta::FromMilliseconds(0));
+ return TimedWait(TimeDelta());
}
void WaitableEvent::Wait() {
@@ -54,13 +50,13 @@ void WaitableEvent::Wait() {
bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
base::ThreadRestrictions::AssertWaitAllowed();
- DCHECK(max_time >= TimeDelta::FromMicroseconds(0));
- // Be careful here. TimeDelta has a precision of microseconds, but this API
- // is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6?
- // It should be 6 to avoid returning too early.
- double timeout = ceil(max_time.InMillisecondsF());
- DWORD result = WaitForSingleObject(handle_.Get(),
- static_cast<DWORD>(timeout));
+ DCHECK_GE(max_time, TimeDelta());
+ // Truncate the timeout to milliseconds. The API specifies that this method
+ // can return in less than |max_time| (when returning false), as the argument
+ // is the maximum time that a caller is willing to wait.
+ DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds());
+
+ DWORD result = WaitForSingleObject(handle_.Get(), timeout);
switch (result) {
case WAIT_OBJECT_0:
return true;
diff --git a/chromium/base/sys_info.cc b/chromium/base/sys_info.cc
index cb93480b979..8640dc14edc 100644
--- a/chromium/base/sys_info.cc
+++ b/chromium/base/sys_info.cc
@@ -7,7 +7,9 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
+#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/sys_info_internal.h"
#include "base/time/time.h"
@@ -19,15 +21,9 @@ static const int kLowMemoryDeviceThresholdMB = 512;
bool DetectLowEndDevice() {
CommandLine* command_line = CommandLine::ForCurrentProcess();
- int int_value = 0;
- if (command_line->HasSwitch(switches::kLowEndDeviceMode)) {
- std::string string_value =
- command_line->GetSwitchValueASCII(switches::kLowEndDeviceMode);
- StringToInt(string_value, &int_value);
- }
- if (int_value == 1)
+ if (command_line->HasSwitch(switches::kEnableLowEndDeviceMode))
return true;
- if (int_value != 2)
+ if (command_line->HasSwitch(switches::kDisableLowEndDeviceMode))
return false;
int ram_size_mb = SysInfo::AmountOfPhysicalMemoryMB();
@@ -40,6 +36,14 @@ static LazyInstance<
// static
bool SysInfo::IsLowEndDevice() {
+ const std::string group_name =
+ base::FieldTrialList::FindFullName("MemoryReduction");
+
+ // Low End Device Mode will be enabled if this client is assigned to
+ // one of those EnabledXXX groups.
+ if (StartsWithASCII(group_name, "Enabled", true))
+ return true;
+
return g_lazy_low_end_device.Get().value();
}
#endif
diff --git a/chromium/base/sys_info.h b/chromium/base/sys_info.h
index 660343d06f7..654d6945a34 100644
--- a/chromium/base/sys_info.h
+++ b/chromium/base/sys_info.h
@@ -94,7 +94,7 @@ class BASE_EXPORT SysInfo {
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// Returns the maximum SysV shared memory segment size, or zero if there is no
// limit.
- static size_t MaxSharedMemorySize();
+ static uint64 MaxSharedMemorySize();
#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
#if defined(OS_CHROMEOS)
diff --git a/chromium/base/sys_info_android.cc b/chromium/base/sys_info_android.cc
index 0d885ee019a..245097ffdc0 100644
--- a/chromium/base/sys_info_android.cc
+++ b/chromium/base/sys_info_android.cc
@@ -47,7 +47,7 @@ static base::LazyInstance<base::internal::LazySysInfoValue<
// from Chrome we work around this by defining a weak stub here, which uses
// dlsym to but ensures that Chrome uses the real system
// implementatation when loaded. http://crbug.com/392191.
-int __system_property_get(const char* name, char* value) {
+BASE_EXPORT int __system_property_get(const char* name, char* value) {
return g_lazy_real_system_property_get.Get().value()(name, value);
}
@@ -59,8 +59,8 @@ namespace {
// cannot be acquired. Use the latest Android release with a higher bug fix
// version to avoid unnecessarily comparison errors with the latest release.
// This should be manually kept up-to-date on each Android release.
-const int kDefaultAndroidMajorVersion = 4;
-const int kDefaultAndroidMinorVersion = 4;
+const int kDefaultAndroidMajorVersion = 5;
+const int kDefaultAndroidMinorVersion = 1;
const int kDefaultAndroidBugfixVersion = 99;
// Parse out the OS version numbers from the system properties.
diff --git a/chromium/base/sys_info_chromeos.cc b/chromium/base/sys_info_chromeos.cc
index ef5f1fedb51..9915055996d 100644
--- a/chromium/base/sys_info_chromeos.cc
+++ b/chromium/base/sys_info_chromeos.cc
@@ -109,7 +109,7 @@ class ChromeOSVersionInfo {
// Parse and cache lsb_release key pairs. There should only be a handful
// of entries so the overhead for this will be small, and it can be
// useful for debugging.
- std::vector<std::pair<std::string, std::string> > pairs;
+ base::StringPairs pairs;
SplitStringIntoKeyValuePairs(lsb_release, '=', '\n', &pairs);
for (size_t i = 0; i < pairs.size(); ++i) {
std::string key, value;
diff --git a/chromium/base/sys_info_freebsd.cc b/chromium/base/sys_info_freebsd.cc
index 832b35985be..515b59d6e98 100644
--- a/chromium/base/sys_info_freebsd.cc
+++ b/chromium/base/sys_info_freebsd.cc
@@ -23,14 +23,14 @@ int64 SysInfo::AmountOfPhysicalMemory() {
}
// static
-size_t SysInfo::MaxSharedMemorySize() {
+uint64 SysInfo::MaxSharedMemorySize() {
size_t limit;
size_t size = sizeof(limit);
if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) {
NOTREACHED();
return 0;
}
- return limit;
+ return static_cast<uint64>(limit);
}
} // namespace base
diff --git a/chromium/base/sys_info_linux.cc b/chromium/base/sys_info_linux.cc
index 2e679ed39f3..1bbfe9c604e 100644
--- a/chromium/base/sys_info_linux.cc
+++ b/chromium/base/sys_info_linux.cc
@@ -9,6 +9,7 @@
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_info_internal.h"
@@ -28,7 +29,7 @@ int64 AmountOfPhysicalMemory() {
return AmountOfMemory(_SC_PHYS_PAGES);
}
-size_t MaxSharedMemorySize() {
+uint64 MaxSharedMemorySize() {
std::string contents;
base::ReadFileToString(base::FilePath("/proc/sys/kernel/shmmax"), &contents);
DCHECK(!contents.empty());
@@ -40,18 +41,15 @@ size_t MaxSharedMemorySize() {
if (!base::StringToUint64(contents, &limit)) {
limit = 0;
}
- if (limit > std::numeric_limits<size_t>::max()) {
- limit = 0;
- }
- DCHECK(limit > 0);
- return static_cast<size_t>(limit);
+ DCHECK_GT(limit, 0u);
+ return limit;
}
base::LazyInstance<
base::internal::LazySysInfoValue<int64, AmountOfPhysicalMemory> >::Leaky
g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<
- base::internal::LazySysInfoValue<size_t, MaxSharedMemorySize> >::Leaky
+ base::internal::LazySysInfoValue<uint64, MaxSharedMemorySize> >::Leaky
g_lazy_max_shared_memory = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -69,7 +67,7 @@ int64 SysInfo::AmountOfPhysicalMemory() {
}
// static
-size_t SysInfo::MaxSharedMemorySize() {
+uint64 SysInfo::MaxSharedMemorySize() {
return g_lazy_max_shared_memory.Get().value();
}
diff --git a/chromium/base/sys_info_openbsd.cc b/chromium/base/sys_info_openbsd.cc
index edbb2c9d86c..595291b0e01 100644
--- a/chromium/base/sys_info_openbsd.cc
+++ b/chromium/base/sys_info_openbsd.cc
@@ -49,7 +49,7 @@ int64 SysInfo::AmountOfAvailablePhysicalMemory() {
}
// static
-size_t SysInfo::MaxSharedMemorySize() {
+uint64 SysInfo::MaxSharedMemorySize() {
int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
size_t limit;
size_t size = sizeof(limit);
@@ -57,7 +57,7 @@ size_t SysInfo::MaxSharedMemorySize() {
NOTREACHED();
return 0;
}
- return limit;
+ return static_cast<uint64>(limit);
}
// static
diff --git a/chromium/base/sys_info_win.cc b/chromium/base/sys_info_win.cc
index 9cc0cfa48a3..c8314c7a6a9 100644
--- a/chromium/base/sys_info_win.cc
+++ b/chromium/base/sys_info_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -24,9 +24,7 @@ int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {
}
int64 rv = static_cast<int64>(memory_info.*memory_field);
- if (rv < 0)
- rv = kint64max;
- return rv;
+ return rv < 0 ? kint64max : rv;
}
} // namespace
@@ -55,19 +53,16 @@ int64 SysInfo::AmountOfVirtualMemory() {
// static
int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
ULARGE_INTEGER available, total, free;
- if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free)) {
+ if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
return -1;
- }
+
int64 rv = static_cast<int64>(available.QuadPart);
- if (rv < 0)
- rv = kint64max;
- return rv;
+ return rv < 0 ? kint64max : rv;
}
-// static
std::string SysInfo::OperatingSystemName() {
return "Windows NT";
}
diff --git a/chromium/base/system_monitor/system_monitor.cc b/chromium/base/system_monitor/system_monitor.cc
index 11dd000a16e..99152ab8a85 100644
--- a/chromium/base/system_monitor/system_monitor.cc
+++ b/chromium/base/system_monitor/system_monitor.cc
@@ -46,7 +46,7 @@ void SystemMonitor::RemoveDevicesChangedObserver(DevicesChangedObserver* obs) {
void SystemMonitor::NotifyDevicesChanged(DeviceType device_type) {
DVLOG(1) << "DevicesChanged with device type " << device_type;
devices_changed_observer_list_->Notify(
- &DevicesChangedObserver::OnDevicesChanged, device_type);
+ FROM_HERE, &DevicesChangedObserver::OnDevicesChanged, device_type);
}
} // namespace base
diff --git a/chromium/base/system_monitor/system_monitor_unittest.cc b/chromium/base/system_monitor/system_monitor_unittest.cc
index e49405ec45e..f3db4c77c94 100644
--- a/chromium/base/system_monitor/system_monitor_unittest.cc
+++ b/chromium/base/system_monitor/system_monitor_unittest.cc
@@ -19,11 +19,11 @@ class SystemMonitorTest : public testing::Test {
SystemMonitorTest() {
system_monitor_.reset(new SystemMonitor);
}
- virtual ~SystemMonitorTest() {}
MessageLoop message_loop_;
scoped_ptr<SystemMonitor> system_monitor_;
+ private:
DISALLOW_COPY_AND_ASSIGN(SystemMonitorTest);
};
diff --git a/chromium/base/task/cancelable_task_tracker.cc b/chromium/base/task/cancelable_task_tracker.cc
index b6e4b6ac4de..a2e4799f438 100644
--- a/chromium/base/task/cancelable_task_tracker.cc
+++ b/chromium/base/task/cancelable_task_tracker.cc
@@ -11,9 +11,10 @@
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/cancellation_flag.h"
#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
using base::Bind;
using base::CancellationFlag;
@@ -85,7 +86,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
DCHECK(thread_checker_.CalledOnValidThread());
// We need a MessageLoop to run reply.
- DCHECK(base::MessageLoopProxy::current().get());
+ DCHECK(base::ThreadTaskRunnerHandle::IsSet());
// Owned by reply callback below.
CancellationFlag* flag = new CancellationFlag();
@@ -113,7 +114,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
IsCanceledCallback* is_canceled_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(base::MessageLoopProxy::current().get());
+ DCHECK(base::ThreadTaskRunnerHandle::IsSet());
TaskId id = next_id_;
next_id_++; // int64 is big enough that we ignore the potential overflow.
@@ -129,7 +130,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
// Will always run |untrack_and_delete_flag| on current MessageLoop.
base::ScopedClosureRunner* untrack_and_delete_flag_runner =
new base::ScopedClosureRunner(Bind(&RunOrPostToTaskRunner,
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
untrack_and_delete_flag));
*is_canceled_cb =
diff --git a/chromium/base/task/cancelable_task_tracker_unittest.cc b/chromium/base/task/cancelable_task_tracker_unittest.cc
index e122e8deef0..ff9e40b855e 100644
--- a/chromium/base/task/cancelable_task_tracker_unittest.cc
+++ b/chromium/base/task/cancelable_task_tracker_unittest.cc
@@ -13,8 +13,8 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,7 +25,7 @@ namespace {
class CancelableTaskTrackerTest : public testing::Test {
protected:
- virtual ~CancelableTaskTrackerTest() { RunCurrentLoopUntilIdle(); }
+ ~CancelableTaskTrackerTest() override { RunCurrentLoopUntilIdle(); }
void RunCurrentLoopUntilIdle() {
RunLoop run_loop;
@@ -84,15 +84,13 @@ TEST_F(CancelableTaskTrackerTest, NoCancel) {
Thread worker_thread("worker thread");
ASSERT_TRUE(worker_thread.Start());
- ignore_result(task_tracker_.PostTask(worker_thread.message_loop_proxy().get(),
+ ignore_result(task_tracker_.PostTask(worker_thread.task_runner().get(),
FROM_HERE,
MakeExpectedRunClosure(FROM_HERE)));
- ignore_result(
- task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
- FROM_HERE,
- MakeExpectedRunClosure(FROM_HERE),
- MakeExpectedRunClosure(FROM_HERE)));
+ ignore_result(task_tracker_.PostTaskAndReply(
+ worker_thread.task_runner().get(), FROM_HERE,
+ MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE)));
CancelableTaskTracker::IsCanceledCallback is_canceled;
ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
@@ -166,11 +164,9 @@ TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
Thread worker_thread("worker thread");
ASSERT_TRUE(worker_thread.Start());
- CancelableTaskTracker::TaskId task_id =
- task_tracker_.PostTaskAndReply(worker_thread.message_loop_proxy().get(),
- FROM_HERE,
- Bind(&DoNothing),
- MakeExpectedNotRunClosure(FROM_HERE));
+ CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply(
+ worker_thread.task_runner().get(), FROM_HERE, Bind(&DoNothing),
+ MakeExpectedNotRunClosure(FROM_HERE));
EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
task_tracker_.TryCancel(task_id);
@@ -196,14 +192,14 @@ TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
Thread other_thread("other thread");
ASSERT_TRUE(other_thread.Start());
- other_thread.message_loop_proxy()->PostTask(
+ other_thread.task_runner()->PostTask(
FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, false));
other_thread.Stop();
task_tracker_.TryCancel(task_id);
ASSERT_TRUE(other_thread.Start());
- other_thread.message_loop_proxy()->PostTask(
+ other_thread.task_runner()->PostTask(
FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, true));
other_thread.Stop();
}
@@ -346,8 +342,6 @@ class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
// The default style "fast" does not support multi-threaded tests.
::testing::FLAGS_gtest_death_test_style = "threadsafe";
}
-
- virtual ~CancelableTaskTrackerDeathTest() {}
};
// Duplicated from base/threading/thread_checker.h so that we can be
@@ -380,11 +374,9 @@ TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
Thread bad_thread("bad thread");
ASSERT_TRUE(bad_thread.Start());
- bad_thread.message_loop_proxy()->PostTask(
- FROM_HERE,
- Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
- Unretained(&task_tracker_),
- Bind(&PostDoNothingTask)));
+ bad_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ Unretained(&task_tracker_), Bind(&PostDoNothingTask)));
}
void TryCancel(CancelableTaskTracker::TaskId task_id,
@@ -403,11 +395,9 @@ TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- bad_thread.message_loop_proxy()->PostTask(
- FROM_HERE,
- Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
- Unretained(&task_tracker_),
- Bind(&TryCancel, task_id)));
+ bad_thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+ Unretained(&task_tracker_), Bind(&TryCancel, task_id)));
test_task_runner->RunUntilIdle();
}
@@ -423,10 +413,9 @@ TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
- bad_thread.message_loop_proxy()->PostTask(
+ bad_thread.task_runner()->PostTask(
FROM_HERE,
- Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
- Unretained(&task_tracker_),
+ Bind(&MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_),
Bind(&CancelableTaskTracker::TryCancelAll)));
test_task_runner->RunUntilIdle();
diff --git a/chromium/base/task_runner_util_unittest.cc b/chromium/base/task_runner_util_unittest.cc
index 481f09ebd19..8245cfcdc50 100644
--- a/chromium/base/task_runner_util_unittest.cc
+++ b/chromium/base/task_runner_util_unittest.cc
@@ -5,7 +5,7 @@
#include "base/task_runner_util.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -69,8 +69,7 @@ TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
int result = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
Bind(&ReturnFourtyTwo),
Bind(&StoreValue, &result));
@@ -83,8 +82,7 @@ TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultImplicitConvert) {
double result = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
Bind(&ReturnFourtyTwo),
Bind(&StoreDoubleValue, &result));
@@ -98,10 +96,8 @@ TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) {
g_foo_free_count = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
- Bind(&CreateFoo),
- Bind(&ExpectFoo));
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+ Bind(&CreateFoo), Bind(&ExpectFoo));
RunLoop().RunUntilIdle();
@@ -114,10 +110,8 @@ TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassedFreeProc) {
g_foo_free_count = 0;
MessageLoop message_loop;
- PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(),
- FROM_HERE,
- Bind(&CreateScopedFoo),
- Bind(&ExpectScopedFoo));
+ PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+ Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo));
RunLoop().RunUntilIdle();
diff --git a/chromium/base/third_party/dynamic_annotations/BUILD.gn b/chromium/base/third_party/dynamic_annotations/BUILD.gn
index 9a478674f1b..bc324ae4a78 100644
--- a/chromium/base/third_party/dynamic_annotations/BUILD.gn
+++ b/chromium/base/third_party/dynamic_annotations/BUILD.gn
@@ -2,14 +2,25 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("dynamic_annotations") {
- sources = [
- "dynamic_annotations.c",
- "dynamic_annotations.h",
- "../valgrind/valgrind.h",
- ]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
- configs += [ "//build/config/compiler:optimize_max" ]
+if (is_nacl) {
+ # Native client doesn't need dynamic annotations, so we provide a
+ # dummy target in order for clients to not have to special-case the
+ # dependency.
+ source_set("dynamic_annotations") {
+ sources = [
+ "dynamic_annotations.h",
+ ]
+ }
+} else {
+ source_set("dynamic_annotations") {
+ sources = [
+ "../valgrind/valgrind.h",
+ "dynamic_annotations.c",
+ "dynamic_annotations.h",
+ ]
+ if (is_android && !is_debug) {
+ configs -= [ "//build/config/compiler:optimize" ]
+ configs += [ "//build/config/compiler:optimize_max" ]
+ }
}
}
diff --git a/chromium/base/third_party/dynamic_annotations/README.chromium b/chromium/base/third_party/dynamic_annotations/README.chromium
index dc8bdef0531..ff21b19e502 100644
--- a/chromium/base/third_party/dynamic_annotations/README.chromium
+++ b/chromium/base/third_party/dynamic_annotations/README.chromium
@@ -3,6 +3,13 @@ URL: http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
Version: 4384
License: BSD
+ATTENTION: please avoid using these annotations in Chromium code.
+They were mainly intended to instruct the Valgrind-based version of
+ThreadSanitizer to handle atomic operations. The new version of ThreadSanitizer
+based on compiler instrumentation understands atomic operations out of the box,
+so normally you don't need the annotations.
+If you still think you do, please consider writing a comment at http://crbug.com/349861
+
One header and one source file (dynamic_annotations.h and dynamic_annotations.c)
in this directory define runtime macros useful for annotating synchronization
utilities and benign data races so data race detectors can handle Chromium code
diff --git a/chromium/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/chromium/base/third_party/dynamic_annotations/dynamic_annotations.gyp
index 12cfb6588eb..8d2e9ec96c5 100644
--- a/chromium/base/third_party/dynamic_annotations/dynamic_annotations.gyp
+++ b/chromium/base/third_party/dynamic_annotations/dynamic_annotations.gyp
@@ -12,9 +12,9 @@
'../../../',
],
'sources': [
+ '../valgrind/valgrind.h',
'dynamic_annotations.c',
'dynamic_annotations.h',
- '../valgrind/valgrind.h',
],
'includes': [
'../../../build/android/increase_size_for_speed.gypi',
diff --git a/chromium/base/third_party/nspr/BUILD.gn b/chromium/base/third_party/nspr/BUILD.gn
deleted file mode 100644
index 516ca1f60f0..00000000000
--- a/chromium/base/third_party/nspr/BUILD.gn
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (c) 2013 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.
-
-source_set("nspr") {
- visibility = [ "//base" ]
- sources = [
- "prtime.cc",
- "prtime.h",
- ]
-
- # In GYP this project is part of base, so it uses the base implementation
- # define. TODO(brettw) rename this define.
- defines = [ "BASE_IMPLEMENTATION" ]
-
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:optimize" ]
- configs += [ "//build/config/compiler:optimize_max" ]
- }
-}
diff --git a/chromium/base/third_party/xdg_mime/README.chromium b/chromium/base/third_party/xdg_mime/README.chromium
index 29d239a4ce0..95f3a9658d1 100644
--- a/chromium/base/third_party/xdg_mime/README.chromium
+++ b/chromium/base/third_party/xdg_mime/README.chromium
@@ -7,5 +7,7 @@ git://anongit.freedesktop.org/xdg/xdgmime
@ 2cdd8d36d7930d5a594587286cb1949ff62f7027 on 2012/08/06.
In addition, we have the following patch(es):
-- compile.patch: small tweaks to make the code compile.
-- Added a LICENSE file.
+ - compile.patch: small tweaks to make the code compile.
+ - free_pointer_later.patch: small patch that fixes potential crash in
+ xdg_mime_get_mime_type_for_file() - use of pointer after being freed.
+ - Added a LICENSE file.
diff --git a/chromium/base/third_party/xdg_mime/free_pointer_later.patch b/chromium/base/third_party/xdg_mime/free_pointer_later.patch
new file mode 100644
index 00000000000..76687610d52
--- /dev/null
+++ b/chromium/base/third_party/xdg_mime/free_pointer_later.patch
@@ -0,0 +1,22 @@
+diff --git a/base/third_party/xdg_mime/xdgmime.c b/base/third_party/xdg_mime/xdgmime.c
+index c7b16bb..6dc58c2 100644
+--- a/base/third_party/xdg_mime/xdgmime.c
++++ b/base/third_party/xdg_mime/xdgmime.c
+@@ -558,13 +558,13 @@ xdg_mime_get_mime_type_for_file (const char *file_name,
+ mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
+ mime_types, n);
+
+- free (data);
+ fclose (file);
+
+- if (mime_type)
+- return mime_type;
++ if (!mime_type)
++ mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+
+- return _xdg_binary_or_text_fallback(data, bytes_read);
++ free (data);
++ return mime_type;
+ }
+
+ const char *
diff --git a/chromium/base/third_party/xdg_mime/xdgmime.c b/chromium/base/third_party/xdg_mime/xdgmime.c
index c7b16bbca76..6dc58c253fa 100644
--- a/chromium/base/third_party/xdg_mime/xdgmime.c
+++ b/chromium/base/third_party/xdg_mime/xdgmime.c
@@ -558,13 +558,13 @@ xdg_mime_get_mime_type_for_file (const char *file_name,
mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
mime_types, n);
- free (data);
fclose (file);
- if (mime_type)
- return mime_type;
+ if (!mime_type)
+ mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
- return _xdg_binary_or_text_fallback(data, bytes_read);
+ free (data);
+ return mime_type;
}
const char *
diff --git a/chromium/base/threading/platform_thread.h b/chromium/base/threading/platform_thread.h
index 28743145610..d8f06e5884d 100644
--- a/chromium/base/threading/platform_thread.h
+++ b/chromium/base/threading/platform_thread.h
@@ -110,15 +110,17 @@ class PlatformThreadHandle {
const PlatformThreadId kInvalidThreadId(0);
-// Valid values for SetThreadPriority()
-enum ThreadPriority{
- kThreadPriority_Normal,
- // Suitable for low-latency, glitch-resistant audio.
- kThreadPriority_RealtimeAudio,
- // Suitable for threads which generate data for the display (at ~60Hz).
- kThreadPriority_Display,
+// Valid values for SetThreadPriority(), listed in increasing order of
+// importance.
+enum class ThreadPriority {
// Suitable for threads that shouldn't disrupt high priority work.
- kThreadPriority_Background
+ BACKGROUND,
+ // Default priority level.
+ NORMAL,
+ // Suitable for threads which generate data for the display (at ~60Hz).
+ DISPLAY,
+ // Suitable for low-latency, glitch-resistant audio.
+ REALTIME_AUDIO,
};
// A namespace for low-level thread functions.
@@ -141,7 +143,10 @@ class BASE_EXPORT PlatformThread {
// we're on the right thread quickly.
static PlatformThreadRef CurrentRef();
- // Get the current handle.
+ // Get the handle representing the current thread. On Windows, this is a
+ // pseudo handle constant which will always represent the thread using it and
+ // hence should not be shared with other threads nor be used to differentiate
+ // the current thread from another.
static PlatformThreadHandle CurrentHandle();
// Yield the current thread so another thread can be scheduled.
@@ -151,9 +156,8 @@ class BASE_EXPORT PlatformThread {
static void Sleep(base::TimeDelta duration);
// Sets the thread name visible to debuggers/tools. This has no effect
- // otherwise. This name pointer is not copied internally. Thus, it must stay
- // valid until the thread ends.
- static void SetName(const char* name);
+ // otherwise.
+ static void SetName(const std::string& name);
// Gets the thread name, if previously set by SetName.
static const char* GetName();
@@ -171,9 +175,7 @@ class BASE_EXPORT PlatformThread {
// CreateWithPriority() does the same thing as Create() except the priority of
// the thread is set based on |priority|. Can be used in place of Create()
- // followed by SetThreadPriority(). SetThreadPriority() has not been
- // implemented on the Linux platform yet, this is the only way to get a high
- // priority thread on Linux.
+ // followed by SetThreadPriority().
static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
PlatformThreadHandle* thread_handle,
ThreadPriority priority);
@@ -191,6 +193,8 @@ class BASE_EXPORT PlatformThread {
static void SetThreadPriority(PlatformThreadHandle handle,
ThreadPriority priority);
+ static ThreadPriority GetThreadPriority(PlatformThreadHandle handle);
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
};
diff --git a/chromium/base/threading/platform_thread_android.cc b/chromium/base/threading/platform_thread_android.cc
index f8395e59221..11e5e2e3c87 100644
--- a/chromium/base/threading/platform_thread_android.cc
+++ b/chromium/base/threading/platform_thread_android.cc
@@ -7,81 +7,64 @@
#include <errno.h>
#include <sys/prctl.h>
#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "base/android/jni_android.h"
#include "base/android/thread_utils.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/tracked_objects.h"
#include "jni/ThreadUtils_jni.h"
namespace base {
-namespace {
-int ThreadNiceValue(ThreadPriority priority) {
- // These nice values are taken from Android, which uses nice
- // values like linux, but defines some preset nice values.
- // Process.THREAD_PRIORITY_AUDIO = -16
- // Process.THREAD_PRIORITY_BACKGROUND = 10
- // Process.THREAD_PRIORITY_DEFAULT = 0;
- // Process.THREAD_PRIORITY_DISPLAY = -4;
- // Process.THREAD_PRIORITY_FOREGROUND = -2;
- // Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
- // Process.THREAD_PRIORITY_LOWEST = 19;
- // Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
- // Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
- // Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
- // We use -6 for display, but we may want to split this
- // into urgent (-8) and non-urgent (-4).
- static const int threadPriorityAudio = -16;
- static const int threadPriorityBackground = 10;
- static const int threadPriorityDefault = 0;
- static const int threadPriorityDisplay = -6;
- switch (priority) {
- case kThreadPriority_RealtimeAudio:
- return threadPriorityAudio;
- case kThreadPriority_Background:
- return threadPriorityBackground;
- case kThreadPriority_Normal:
- return threadPriorityDefault;
- case kThreadPriority_Display:
- return threadPriorityDisplay;
- default:
- NOTREACHED() << "Unknown priority.";
- return 0;
- }
-}
-} // namespace
-
-//static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
+namespace internal {
+
+// These nice values are taken from Android, which uses nice values like linux,
+// but defines some preset nice values.
+// Process.THREAD_PRIORITY_AUDIO = -16
+// Process.THREAD_PRIORITY_BACKGROUND = 10
+// Process.THREAD_PRIORITY_DEFAULT = 0;
+// Process.THREAD_PRIORITY_DISPLAY = -4;
+// Process.THREAD_PRIORITY_FOREGROUND = -2;
+// Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
+// Process.THREAD_PRIORITY_LOWEST = 19;
+// Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
+// Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
+// Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
+// We use -6 for display, but we may want to split this into urgent (-8) and
+// non-urgent (-4).
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+ {ThreadPriority::BACKGROUND, 10},
+ {ThreadPriority::NORMAL, 0},
+ {ThreadPriority::DISPLAY, -6},
+ {ThreadPriority::REALTIME_AUDIO, -16},
+};
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority) {
// On Android, we set the Audio priority through JNI as Audio priority
// will also allow the process to run while it is backgrounded.
- if (priority == kThreadPriority_RealtimeAudio) {
+ if (priority == ThreadPriority::REALTIME_AUDIO) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId());
- return;
+ return true;
}
+ return false;
+}
- // setpriority(2) should change the whole thread group's (i.e. process)
- // priority. however, on linux it will only change the target thread's
- // priority. see the bugs section in
- // http://man7.org/linux/man-pages/man2/getpriority.2.html.
- // we prefer using 0 rather than the current thread id since they are
- // equivalent but it makes sandboxing easier (https://crbug.com/399473).
- DCHECK_NE(handle.id_, kInvalidThreadId);
- int kNiceSetting = ThreadNiceValue(priority);
- const PlatformThreadId current_id = PlatformThread::CurrentId();
- if (setpriority(PRIO_PROCESS,
- handle.id_ == current_id ? 0 : handle.id_,
- kNiceSetting)) {
- LOG(ERROR) << "Failed to set nice value of thread to " << kNiceSetting;
- }
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority* priority) {
+ NOTIMPLEMENTED();
+ return false;
}
-void PlatformThread::SetName(const char* name) {
+} // namespace internal
+
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
@@ -93,7 +76,7 @@ void PlatformThread::SetName(const char* name) {
return;
// Set the name for the LWP (which gets truncated to 15 characters).
- int err = prctl(PR_SET_NAME, name);
+ int err = prctl(PR_SET_NAME, name.c_str());
if (err < 0 && errno != EPERM)
DPLOG(ERROR) << "prctl(PR_SET_NAME)";
}
@@ -106,7 +89,7 @@ void InitOnThread() {
// Threads on linux/android may inherit their priority from the thread
// where they were created. This sets all new threads to the default.
PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
- kThreadPriority_Normal);
+ ThreadPriority::NORMAL);
}
void TerminateOnThread() {
diff --git a/chromium/base/threading/platform_thread_freebsd.cc b/chromium/base/threading/platform_thread_freebsd.cc
index 7a24f4e055e..f4fded0ebb2 100644
--- a/chromium/base/threading/platform_thread_freebsd.cc
+++ b/chromium/base/threading/platform_thread_freebsd.cc
@@ -9,42 +9,67 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/safe_strerror_posix.h"
#include "base/threading/thread_id_name_manager.h"
-#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
#if !defined(OS_NACL)
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
+#include <pthread.h>
+#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
#endif
namespace base {
+namespace internal {
+
namespace {
-int ThreadNiceValue(ThreadPriority priority) {
- switch (priority) {
- case kThreadPriority_RealtimeAudio:
- return -10;
- case kThreadPriority_Background:
- return 10;
- case kThreadPriority_Normal:
- return 0;
- case kThreadPriority_Display:
- return -6;
- default:
- NOTREACHED() << "Unknown priority.";
- return 0;
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+} // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+ {ThreadPriority::BACKGROUND, 10},
+ {ThreadPriority::NORMAL, 0},
+ {ThreadPriority::DISPLAY, -6},
+ {ThreadPriority::REALTIME_AUDIO, -10},
+}
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority) {
+#if !defined(OS_NACL)
+ // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+ // of |handle|. http://crbug.com/468793.
+ return priority == ThreadPriority::REALTIME_AUDIO &&
+ pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+ return false;
+#endif
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority* priority) {
+#if !defined(OS_NACL)
+ // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+ // of |handle|. http://crbug.com/468793.
+ int maybe_sched_rr = 0;
+ struct sched_param maybe_realtime_prio = {0};
+ if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
+ &maybe_realtime_prio) == 0 &&
+ maybe_sched_rr == SCHED_RR &&
+ maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
+ *priority = ThreadPriority::REALTIME_AUDIO;
+ return true;
}
+#endif
+ return false;
}
-} // namespace
+
+} // namespace internal
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
@@ -55,32 +80,7 @@ void PlatformThread::SetName(const char* name) {
// killall to stop working.
if (PlatformThread::CurrentId() == getpid())
return;
- setproctitle("%s", name);
-#endif // !defined(OS_NACL)
-}
-
-// static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
-#if !defined(OS_NACL)
- if (priority == kThreadPriority_RealtimeAudio) {
- const struct sched_param kRealTimePrio = { 8 };
- if (pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0) {
- // Got real time priority, no need to set nice level.
- return;
- }
- }
-
- // setpriority(2) will set a thread's priority if it is passed a tid as
- // the 'process identifier', not affecting the rest of the threads in the
- // process. Setting this priority will only succeed if the user has been
- // granted permission to adjust nice values on the system.
- DCHECK_NE(handle.id_, kInvalidThreadId);
- const int kNiceSetting = ThreadNiceValue(priority);
- if (setpriority(PRIO_PROCESS, handle.id_, kNiceSetting)) {
- DVPLOG(1) << "Failed to set nice value of thread ("
- << handle.id_ << ") to " << kNiceSetting;
- }
+ setproctitle("%s", name.c_str());
#endif // !defined(OS_NACL)
}
diff --git a/chromium/base/threading/platform_thread_internal_posix.cc b/chromium/base/threading/platform_thread_internal_posix.cc
new file mode 100644
index 00000000000..9af02044fce
--- /dev/null
+++ b/chromium/base/threading/platform_thread_internal_posix.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 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/threading/platform_thread_internal_posix.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+int ThreadPriorityToNiceValue(ThreadPriority priority) {
+ for (const ThreadPriorityToNiceValuePair& pair :
+ kThreadPriorityToNiceValueMap) {
+ if (pair.priority == priority)
+ return pair.nice_value;
+ }
+ NOTREACHED() << "Unknown ThreadPriority";
+ return 0;
+}
+
+ThreadPriority NiceValueToThreadPriority(int nice_value) {
+ for (const ThreadPriorityToNiceValuePair& pair :
+ kThreadPriorityToNiceValueMap) {
+ if (pair.nice_value == nice_value)
+ return pair.priority;
+ }
+ NOTREACHED() << "Unknown nice value";
+ return ThreadPriority::NORMAL;
+}
+
+} // namespace internal
+
+} // namespace base
diff --git a/chromium/base/threading/platform_thread_internal_posix.h b/chromium/base/threading/platform_thread_internal_posix.h
new file mode 100644
index 00000000000..62006ce13c9
--- /dev/null
+++ b/chromium/base/threading/platform_thread_internal_posix.h
@@ -0,0 +1,45 @@
+// Copyright 2015 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_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace internal {
+
+struct ThreadPriorityToNiceValuePair {
+ ThreadPriority priority;
+ int nice_value;
+};
+extern const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4];
+
+// Returns the nice value matching |priority| based on the platform-specific
+// implementation of kThreadPriorityToNiceValueMap.
+int ThreadPriorityToNiceValue(ThreadPriority priority);
+
+// Returns the ThreadPrioirty matching |nice_value| based on the platform-
+// specific implementation of kThreadPriorityToNiceValueMap.
+ThreadPriority NiceValueToThreadPriority(int nice_value);
+
+// Allows platform specific tweaks to the generic POSIX solution for
+// SetThreadPriority. Returns true if the platform-specific implementation
+// handled this |priority| change, false if the generic implementation should
+// instead proceed.
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority);
+
+// Returns true if there is a platform-specific ThreadPriority set on |handle|
+// (and returns the actual ThreadPriority via |priority|). Returns false
+// otherwise, leaving |priority| untouched.
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority* priority);
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
diff --git a/chromium/base/threading/platform_thread_linux.cc b/chromium/base/threading/platform_thread_linux.cc
index d9e2bd9932f..9f7437418a7 100644
--- a/chromium/base/threading/platform_thread_linux.cc
+++ b/chromium/base/threading/platform_thread_linux.cc
@@ -9,44 +9,68 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/safe_strerror_posix.h"
+#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
-#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
#if !defined(OS_NACL)
+#include <pthread.h>
#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
+#include <sys/types.h>
#include <unistd.h>
#endif
namespace base {
+namespace internal {
+
namespace {
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+} // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+ {ThreadPriority::BACKGROUND, 10},
+ {ThreadPriority::NORMAL, 0},
+ {ThreadPriority::DISPLAY, -6},
+ {ThreadPriority::REALTIME_AUDIO, -10},
+};
-int ThreadNiceValue(ThreadPriority priority) {
- switch (priority) {
- case kThreadPriority_RealtimeAudio:
- return -10;
- case kThreadPriority_Background:
- return 10;
- case kThreadPriority_Normal:
- return 0;
- case kThreadPriority_Display:
- return -6;
- default:
- NOTREACHED() << "Unknown priority.";
- return 0;
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority) {
+#if !defined(OS_NACL)
+ // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+ // of |handle|. http://crbug.com/468793.
+ return priority == ThreadPriority::REALTIME_AUDIO &&
+ pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+ return false;
+#endif
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority* priority) {
+#if !defined(OS_NACL)
+ int maybe_sched_rr = 0;
+ struct sched_param maybe_realtime_prio = {0};
+ // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+ // of |handle|. http://crbug.com/468793.
+ if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
+ &maybe_realtime_prio) == 0 &&
+ maybe_sched_rr == SCHED_RR &&
+ maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
+ *priority = ThreadPriority::REALTIME_AUDIO;
+ return true;
}
+#endif
+ return false;
}
-} // namespace
+} // namespace internal
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
@@ -63,43 +87,13 @@ void PlatformThread::SetName(const char* name) {
// Note that glibc also has a 'pthread_setname_np' api, but it may not be
// available everywhere and it's only benefit over using prctl directly is
// that it can set the name of threads other than the current thread.
- int err = prctl(PR_SET_NAME, name);
+ int err = prctl(PR_SET_NAME, name.c_str());
// We expect EPERM failures in sandboxed processes, just ignore those.
if (err < 0 && errno != EPERM)
DPLOG(ERROR) << "prctl(PR_SET_NAME)";
#endif // !defined(OS_NACL)
}
-// static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
-#if !defined(OS_NACL)
- if (priority == kThreadPriority_RealtimeAudio) {
- const struct sched_param kRealTimePrio = {8};
- if (pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0) {
- // Got real time priority, no need to set nice level.
- return;
- }
- }
-
- // setpriority(2) should change the whole thread group's (i.e. process)
- // priority. however, on linux it will only change the target thread's
- // priority. see the bugs section in
- // http://man7.org/linux/man-pages/man2/getpriority.2.html.
- // we prefer using 0 rather than the current thread id since they are
- // equivalent but it makes sandboxing easier (https://crbug.com/399473).
- DCHECK_NE(handle.id_, kInvalidThreadId);
- const int kNiceSetting = ThreadNiceValue(priority);
- const PlatformThreadId current_id = PlatformThread::CurrentId();
- if (setpriority(PRIO_PROCESS,
- handle.id_ == current_id ? 0 : handle.id_,
- kNiceSetting)) {
- DVPLOG(1) << "Failed to set nice value of thread (" << handle.id_ << ") to "
- << kNiceSetting;
- }
-#endif // !defined(OS_NACL)
-}
-
void InitThreading() {}
void InitOnThread() {}
diff --git a/chromium/base/threading/platform_thread_mac.mm b/chromium/base/threading/platform_thread_mac.mm
index 147e625dbc8..a9c347a5b53 100644
--- a/chromium/base/threading/platform_thread_mac.mm
+++ b/chromium/base/threading/platform_thread_mac.mm
@@ -42,14 +42,14 @@ void InitThreading() {
}
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
// Mac OS X does not expose the length limit of the name, so
// hardcode it.
const int kMaxNameLength = 63;
- std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+ std::string shortened_name = name.substr(0, kMaxNameLength);
// pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
// See http://crbug.com/47058
pthread_setname_np(shortened_name.c_str());
@@ -161,10 +161,10 @@ void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
mach_port_t mach_thread_id = pthread_mach_thread_np(handle.handle_);
switch (priority) {
- case kThreadPriority_Normal:
+ case ThreadPriority::NORMAL:
SetPriorityNormal(mach_thread_id);
break;
- case kThreadPriority_RealtimeAudio:
+ case ThreadPriority::REALTIME_AUDIO:
SetPriorityRealtimeAudio(mach_thread_id);
break;
default:
@@ -173,6 +173,12 @@ void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
}
}
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ NOTIMPLEMENTED();
+ return ThreadPriority::NORMAL;
+}
+
size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
#if defined(OS_IOS)
return 0;
diff --git a/chromium/base/threading/platform_thread_posix.cc b/chromium/base/threading/platform_thread_posix.cc
index 42b416d4a38..3dbdc980875 100644
--- a/chromium/base/threading/platform_thread_posix.cc
+++ b/chromium/base/threading/platform_thread_posix.cc
@@ -5,28 +5,25 @@
#include "base/threading/platform_thread.h"
#include <errno.h>
+#include <pthread.h>
#include <sched.h>
+#include <sys/resource.h>
+#include <sys/time.h>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/safe_strerror_posix.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
-#if defined(OS_MACOSX)
-#include <sys/resource.h>
-#include <algorithm>
-#endif
-
#if defined(OS_LINUX)
-#include <sys/prctl.h>
-#include <sys/resource.h>
#include <sys/syscall.h>
-#include <sys/time.h>
-#include <unistd.h>
+#elif defined(OS_ANDROID)
+#include <sys/types.h>
#endif
namespace base {
@@ -42,7 +39,7 @@ struct ThreadParams {
ThreadParams()
: delegate(NULL),
joinable(false),
- priority(kThreadPriority_Normal),
+ priority(ThreadPriority::NORMAL),
handle(NULL),
handle_set(false, false) {
}
@@ -62,7 +59,7 @@ void* ThreadFunc(void* params) {
if (!thread_params->joinable)
base::ThreadRestrictions::SetSingletonAllowed(false);
- if (thread_params->priority != kThreadPriority_Normal) {
+ if (thread_params->priority != ThreadPriority::NORMAL) {
PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
thread_params->priority);
}
@@ -204,7 +201,7 @@ bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
PlatformThreadHandle* thread_handle) {
base::ThreadRestrictions::ScopedAllowWait allow_wait;
return CreateThread(stack_size, true /* joinable thread */,
- delegate, thread_handle, kThreadPriority_Normal);
+ delegate, thread_handle, ThreadPriority::NORMAL);
}
// static
@@ -222,7 +219,7 @@ bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
base::ThreadRestrictions::ScopedAllowWait allow_wait;
bool result = CreateThread(stack_size, false /* non-joinable thread */,
- delegate, &unused, kThreadPriority_Normal);
+ delegate, &unused, ThreadPriority::NORMAL);
return result;
}
@@ -235,4 +232,64 @@ void PlatformThread::Join(PlatformThreadHandle thread_handle) {
CHECK_EQ(0, pthread_join(thread_handle.handle_, NULL));
}
+// Mac has its own Set/GetThreadPriority() implementations.
+#if !defined(OS_MACOSX)
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+ ThreadPriority priority) {
+#if defined(OS_NACL)
+ NOTIMPLEMENTED();
+#else
+ if (internal::SetThreadPriorityForPlatform(handle, priority))
+ return;
+
+ // setpriority(2) should change the whole thread group's (i.e. process)
+ // priority. However, as stated in the bugs section of
+ // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
+ // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
+ // attribute". Also, 0 is prefered to the current thread id since it is
+ // equivalent but makes sandboxing easier (https://crbug.com/399473).
+ DCHECK_NE(handle.id_, kInvalidThreadId);
+ const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+ const PlatformThreadId current_id = PlatformThread::CurrentId();
+ if (setpriority(PRIO_PROCESS, handle.id_ == current_id ? 0 : handle.id_,
+ nice_setting)) {
+ DVPLOG(1) << "Failed to set nice value of thread (" << handle.id_ << ") to "
+ << nice_setting;
+ }
+#endif // defined(OS_NACL)
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+#if defined(OS_NACL)
+ NOTIMPLEMENTED();
+ return ThreadPriority::NORMAL;
+#else
+ // Mirrors SetThreadPriority()'s implementation.
+ ThreadPriority platform_specific_priority;
+ if (internal::GetThreadPriorityForPlatform(handle,
+ &platform_specific_priority)) {
+ return platform_specific_priority;
+ }
+
+ DCHECK_NE(handle.id_, kInvalidThreadId);
+ const PlatformThreadId current_id = PlatformThread::CurrentId();
+ // Need to clear errno before calling getpriority():
+ // http://man7.org/linux/man-pages/man2/getpriority.2.html
+ errno = 0;
+ int nice_value =
+ getpriority(PRIO_PROCESS, handle.id_ == current_id ? 0 : handle.id_);
+ if (errno != 0) {
+ DVPLOG(1) << "Failed to get nice value of thread (" << handle.id_ << ")";
+ return ThreadPriority::NORMAL;
+ }
+
+ return internal::NiceValueToThreadPriority(nice_value);
+#endif // !defined(OS_NACL)
+}
+
+#endif // !defined(OS_MACOSX)
+
} // namespace base
diff --git a/chromium/base/threading/platform_thread_unittest.cc b/chromium/base/threading/platform_thread_unittest.cc
index 21260e5ec36..c4b3d5d7ecc 100644
--- a/chromium/base/threading/platform_thread_unittest.cc
+++ b/chromium/base/threading/platform_thread_unittest.cc
@@ -3,10 +3,15 @@
// found in the LICENSE file.
#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
-
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
namespace base {
// Trivial tests that thread runs and doesn't crash on create and join ---------
@@ -51,26 +56,59 @@ TEST(PlatformThreadTest, TrivialTimesTen) {
// Tests of basic thread functions ---------------------------------------------
-class FunctionTestThread : public TrivialThread {
+class FunctionTestThread : public PlatformThread::Delegate {
public:
- FunctionTestThread() : thread_id_(0) {}
+ FunctionTestThread()
+ : thread_id_(kInvalidThreadId),
+ thread_started_(true, false),
+ terminate_thread_(true, false),
+ done_(false) {}
+ ~FunctionTestThread() override {
+ EXPECT_TRUE(terminate_thread_.IsSignaled())
+ << "Need to mark thread for termination and join the underlying thread "
+ << "before destroying a FunctionTestThread as it owns the "
+ << "WaitableEvent blocking the underlying thread's main.";
+ }
+ // Grabs |thread_id_|, signals |thread_started_|, and then waits for
+ // |terminate_thread_| to be signaled before exiting.
void ThreadMain() override {
thread_id_ = PlatformThread::CurrentId();
- PlatformThread::YieldCurrentThread();
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
+ EXPECT_NE(thread_id_, kInvalidThreadId);
// Make sure that the thread ID is the same across calls.
EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
- TrivialThread::ThreadMain();
+ thread_started_.Signal();
+
+ terminate_thread_.Wait();
+
+ done_ = true;
+ }
+
+ PlatformThreadId thread_id() const {
+ EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown";
+ return thread_id_;
}
- PlatformThreadId thread_id() const { return thread_id_; }
+ bool IsRunning() const {
+ return thread_started_.IsSignaled() && !done_;
+ }
+
+ // Blocks until this thread is started.
+ void WaitForThreadStart() { thread_started_.Wait(); }
+
+ // Mark this thread for termination (callers must then join this thread to be
+ // guaranteed of termination).
+ void MarkForTermination() { terminate_thread_.Signal(); }
private:
PlatformThreadId thread_id_;
+ mutable WaitableEvent thread_started_;
+ WaitableEvent terminate_thread_;
+ bool done_;
+
DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
};
@@ -80,12 +118,16 @@ TEST(PlatformThreadTest, Function) {
FunctionTestThread thread;
PlatformThreadHandle handle;
- ASSERT_FALSE(thread.did_run());
+ ASSERT_FALSE(thread.IsRunning());
ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Join(handle);
- ASSERT_TRUE(thread.did_run());
+ thread.WaitForThreadStart();
+ ASSERT_TRUE(thread.IsRunning());
EXPECT_NE(thread.thread_id(), main_thread_id);
+ thread.MarkForTermination();
+ PlatformThread::Join(handle);
+ ASSERT_FALSE(thread.IsRunning());
+
// Make sure that the thread ID is the same across calls.
EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
}
@@ -97,13 +139,15 @@ TEST(PlatformThreadTest, FunctionTimesTen) {
PlatformThreadHandle handle[arraysize(thread)];
for (size_t n = 0; n < arraysize(thread); n++)
- ASSERT_FALSE(thread[n].did_run());
+ ASSERT_FALSE(thread[n].IsRunning());
+
for (size_t n = 0; n < arraysize(thread); n++)
ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
for (size_t n = 0; n < arraysize(thread); n++)
- PlatformThread::Join(handle[n]);
+ thread[n].WaitForThreadStart();
+
for (size_t n = 0; n < arraysize(thread); n++) {
- ASSERT_TRUE(thread[n].did_run());
+ ASSERT_TRUE(thread[n].IsRunning());
EXPECT_NE(thread[n].thread_id(), main_thread_id);
// Make sure no two threads get the same ID.
@@ -112,8 +156,120 @@ TEST(PlatformThreadTest, FunctionTimesTen) {
}
}
+ for (size_t n = 0; n < arraysize(thread); n++)
+ thread[n].MarkForTermination();
+ for (size_t n = 0; n < arraysize(thread); n++)
+ PlatformThread::Join(handle[n]);
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_FALSE(thread[n].IsRunning());
+
// Make sure that the thread ID is the same across calls.
EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
}
+namespace {
+
+const ThreadPriority kThreadPriorityTestValues[] = {
+// Disable non-normal priority toggling on POSIX as it appears to be broken
+// (http://crbug.com/468793). This is prefered to disabling the tests altogether
+// on POSIX as it at least provides coverage for running this code under
+// "normal" priority.
+#if !defined(OS_POSIX)
+ ThreadPriority::DISPLAY,
+ ThreadPriority::REALTIME_AUDIO,
+ // Keep BACKGROUND second to last to test backgrounding from other
+ // priorities.
+ ThreadPriority::BACKGROUND,
+#endif // !defined(OS_POSIX)
+ // Keep NORMAL last to test unbackgrounding.
+ ThreadPriority::NORMAL
+};
+
+} // namespace
+
+// Test changing another thread's priority.
+// NOTE: This test is partially disabled on POSIX, see note above and
+// http://crbug.com/468793.
+TEST(PlatformThreadTest, ThreadPriorityOtherThread) {
+ PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+
+ // Confirm that the current thread's priority is as expected.
+ EXPECT_EQ(ThreadPriority::NORMAL,
+ PlatformThread::GetThreadPriority(current_handle));
+
+ // Create a test thread.
+ FunctionTestThread thread;
+ PlatformThreadHandle handle;
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ thread.WaitForThreadStart();
+ EXPECT_NE(thread.thread_id(), kInvalidThreadId);
+ EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
+
+ // New threads should get normal priority by default.
+ EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
+
+ // Toggle each supported priority on the test thread and confirm it only
+ // affects it (and not the current thread).
+ for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+ SCOPED_TRACE(i);
+
+ // Alter and verify the test thread's priority.
+ PlatformThread::SetThreadPriority(handle, kThreadPriorityTestValues[i]);
+ EXPECT_EQ(kThreadPriorityTestValues[i],
+ PlatformThread::GetThreadPriority(handle));
+
+ // Make sure the current thread was otherwise unaffected.
+ EXPECT_EQ(ThreadPriority::NORMAL,
+ PlatformThread::GetThreadPriority(current_handle));
+ }
+
+ thread.MarkForTermination();
+ PlatformThread::Join(handle);
+}
+
+// Test changing the current thread's priority (which has different semantics on
+// some platforms).
+// NOTE: This test is partially disabled on POSIX, see note above and
+// http://crbug.com/468793.
+TEST(PlatformThreadTest, ThreadPriorityCurrentThread) {
+ PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+
+ // Confirm that the current thread's priority is as expected.
+ EXPECT_EQ(ThreadPriority::NORMAL,
+ PlatformThread::GetThreadPriority(current_handle));
+
+ // Create a test thread for verification purposes only.
+ FunctionTestThread thread;
+ PlatformThreadHandle handle;
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ thread.WaitForThreadStart();
+ EXPECT_NE(thread.thread_id(), kInvalidThreadId);
+ EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
+
+ // Confirm that the new thread's priority is as expected.
+ EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
+
+ // Toggle each supported priority on the current thread and confirm it only
+ // affects it (and not the test thread).
+ for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+ SCOPED_TRACE(i);
+
+ // Alter and verify the current thread's priority.
+ PlatformThread::SetThreadPriority(current_handle,
+ kThreadPriorityTestValues[i]);
+ EXPECT_EQ(kThreadPriorityTestValues[i],
+ PlatformThread::GetThreadPriority(current_handle));
+
+ // Make sure the test thread was otherwise unaffected.
+ EXPECT_EQ(ThreadPriority::NORMAL,
+ PlatformThread::GetThreadPriority(handle));
+ }
+
+ // Restore current thread priority for follow-up tests.
+ PlatformThread::SetThreadPriority(current_handle, ThreadPriority::NORMAL);
+
+ thread.MarkForTermination();
+ PlatformThread::Join(handle);
+}
+
} // namespace base
diff --git a/chromium/base/threading/platform_thread_win.cc b/chromium/base/threading/platform_thread_win.cc
index 3df371943f5..4eb2cb2b33d 100644
--- a/chromium/base/threading/platform_thread_win.cc
+++ b/chromium/base/threading/platform_thread_win.cc
@@ -126,18 +126,17 @@ bool CreateThreadInternal(size_t stack_size,
// static
PlatformThreadId PlatformThread::CurrentId() {
- return GetCurrentThreadId();
+ return ::GetCurrentThreadId();
}
// static
PlatformThreadRef PlatformThread::CurrentRef() {
- return PlatformThreadRef(GetCurrentThreadId());
+ return PlatformThreadRef(::GetCurrentThreadId());
}
// static
PlatformThreadHandle PlatformThread::CurrentHandle() {
- NOTIMPLEMENTED(); // See OpenThread()
- return PlatformThreadHandle();
+ return PlatformThreadHandle(::GetCurrentThread());
}
// static
@@ -155,7 +154,7 @@ void PlatformThread::Sleep(TimeDelta duration) {
}
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const std::string& name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
// On Windows only, we don't need to tell the profiler about the "BrokerEvent"
@@ -164,7 +163,7 @@ void PlatformThread::SetName(const char* name) {
// which would also (as a side effect) initialize the profiler in this unused
// context, including setting up thread local storage, etc. The performance
// impact is not terrible, but there is no reason to do initialize it.
- if (0 != strcmp(name, "BrokerEvent"))
+ if (name != "BrokerEvent")
tracked_objects::ThreadData::InitializeThreadContext(name);
// The debugger needs to be around to catch the name in the exception. If
@@ -174,7 +173,7 @@ void PlatformThread::SetName(const char* name) {
if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
return;
- SetNameInternal(CurrentId(), name);
+ SetNameInternal(CurrentId(), name.c_str());
}
// static
@@ -234,17 +233,56 @@ void PlatformThread::Join(PlatformThreadHandle thread_handle) {
// static
void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
ThreadPriority priority) {
+ DCHECK(!handle.is_null());
+
+ int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
switch (priority) {
- case kThreadPriority_Normal:
- ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_NORMAL);
+ case ThreadPriority::BACKGROUND:
+ desired_priority = THREAD_PRIORITY_LOWEST;
+ break;
+ case ThreadPriority::NORMAL:
+ desired_priority = THREAD_PRIORITY_NORMAL;
+ break;
+ case ThreadPriority::DISPLAY:
+ desired_priority = THREAD_PRIORITY_ABOVE_NORMAL;
break;
- case kThreadPriority_RealtimeAudio:
- ::SetThreadPriority(handle.handle_, THREAD_PRIORITY_TIME_CRITICAL);
+ case ThreadPriority::REALTIME_AUDIO:
+ desired_priority = THREAD_PRIORITY_TIME_CRITICAL;
break;
default:
NOTREACHED() << "Unknown priority.";
break;
}
+ DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN);
+
+#ifndef NDEBUG
+ const BOOL success =
+#endif
+ ::SetThreadPriority(handle.handle_, desired_priority);
+ DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
+ << desired_priority;
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+ DCHECK(!handle.is_null());
+
+ int priority = ::GetThreadPriority(handle.handle_);
+ switch (priority) {
+ case THREAD_PRIORITY_LOWEST:
+ return ThreadPriority::BACKGROUND;
+ case THREAD_PRIORITY_NORMAL:
+ return ThreadPriority::NORMAL;
+ case THREAD_PRIORITY_ABOVE_NORMAL:
+ return ThreadPriority::DISPLAY;
+ case THREAD_PRIORITY_TIME_CRITICAL:
+ return ThreadPriority::REALTIME_AUDIO;
+ case THREAD_PRIORITY_ERROR_RETURN:
+ DPCHECK(false) << "GetThreadPriority error"; // Falls through.
+ default:
+ NOTREACHED() << "Unexpected priority: " << priority;
+ return ThreadPriority::NORMAL;
+ }
}
} // namespace base
diff --git a/chromium/base/threading/post_task_and_reply_impl.cc b/chromium/base/threading/post_task_and_reply_impl.cc
index a82a4fd8043..f3e88abf608 100644
--- a/chromium/base/threading/post_task_and_reply_impl.cc
+++ b/chromium/base/threading/post_task_and_reply_impl.cc
@@ -25,30 +25,30 @@ namespace {
class PostTaskAndReplyRelay {
public:
PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
- const Closure& task, const Closure& reply)
+ const Closure& task,
+ const Closure& reply)
: from_here_(from_here),
- origin_loop_(ThreadTaskRunnerHandle::Get()) {
+ origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
task_ = task;
reply_ = reply;
}
~PostTaskAndReplyRelay() {
- DCHECK(origin_loop_->BelongsToCurrentThread());
+ DCHECK(origin_task_runner_->BelongsToCurrentThread());
task_.Reset();
reply_.Reset();
}
void Run() {
task_.Run();
- origin_loop_->PostTask(
- from_here_,
- Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
- base::Unretained(this)));
+ origin_task_runner_->PostTask(
+ from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
+ base::Unretained(this)));
}
private:
void RunReplyAndSelfDestruct() {
- DCHECK(origin_loop_->BelongsToCurrentThread());
+ DCHECK(origin_task_runner_->BelongsToCurrentThread());
// Force |task_| to be released before |reply_| is to ensure that no one
// accidentally depends on |task_| keeping one of its arguments alive while
@@ -62,7 +62,7 @@ class PostTaskAndReplyRelay {
}
tracked_objects::Location from_here_;
- scoped_refptr<SingleThreadTaskRunner> origin_loop_;
+ scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
Closure reply_;
Closure task_;
};
diff --git a/chromium/base/threading/post_task_and_reply_impl.h b/chromium/base/threading/post_task_and_reply_impl.h
index 076a46d69e8..a5b9580e6dc 100644
--- a/chromium/base/threading/post_task_and_reply_impl.h
+++ b/chromium/base/threading/post_task_and_reply_impl.h
@@ -3,7 +3,7 @@
// found in the LICENSE file.
// This file contains the implementation shared by
-// MessageLoopProxy::PostTaskAndReply and WorkerPool::PostTaskAndReply.
+// TaskRunner::PostTaskAndReply and WorkerPool::PostTaskAndReply.
#ifndef BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
#define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
@@ -21,11 +21,11 @@ namespace internal {
// MessageLoop.
//
// If you're looking for a concrete implementation of
-// PostTaskAndReply, you probably want base::MessageLoopProxy, or you
+// PostTaskAndReply, you probably want base::SingleThreadTaskRunner, or you
// may want base::WorkerPool.
class PostTaskAndReplyImpl {
public:
- // Implementation for MessageLoopProxy::PostTaskAndReply and
+ // Implementation for TaskRunner::PostTaskAndReply and
// WorkerPool::PostTaskAndReply.
bool PostTaskAndReply(const tracked_objects::Location& from_here,
const Closure& task,
diff --git a/chromium/base/threading/sequenced_worker_pool.cc b/chromium/base/threading/sequenced_worker_pool.cc
index 4c37320b5bc..7bbca92a2fb 100644
--- a/chromium/base/threading/sequenced_worker_pool.cc
+++ b/chromium/base/threading/sequenced_worker_pool.cc
@@ -14,20 +14,20 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/critical_closure.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
#if defined(OS_MACOSX)
@@ -239,24 +239,41 @@ class SequencedWorkerPool::Worker : public SimpleThread {
// SimpleThread implementation. This actually runs the background thread.
void Run() override;
+ // Indicates that a task is about to be run. The parameters provide
+ // additional metainformation about the task being run.
void set_running_task_info(SequenceToken token,
WorkerShutdown shutdown_behavior) {
- running_sequence_ = token;
- running_shutdown_behavior_ = shutdown_behavior;
+ is_processing_task_ = true;
+ task_sequence_token_ = token;
+ task_shutdown_behavior_ = shutdown_behavior;
}
- SequenceToken running_sequence() const {
- return running_sequence_;
+ // Indicates that the task has finished running.
+ void reset_running_task_info() { is_processing_task_ = false; }
+
+ // Whether the worker is processing a task.
+ bool is_processing_task() { return is_processing_task_; }
+
+ SequenceToken task_sequence_token() const {
+ DCHECK(is_processing_task_);
+ return task_sequence_token_;
}
- WorkerShutdown running_shutdown_behavior() const {
- return running_shutdown_behavior_;
+ WorkerShutdown task_shutdown_behavior() const {
+ DCHECK(is_processing_task_);
+ return task_shutdown_behavior_;
}
private:
scoped_refptr<SequencedWorkerPool> worker_pool_;
- SequenceToken running_sequence_;
- WorkerShutdown running_shutdown_behavior_;
+ // The sequence token of the task being processed. Only valid when
+ // is_processing_task_ is true.
+ SequenceToken task_sequence_token_;
+ // The shutdown behavior of the task being processed. Only valid when
+ // is_processing_task_ is true.
+ WorkerShutdown task_shutdown_behavior_;
+ // Whether the Worker is processing a task.
+ bool is_processing_task_;
DISALLOW_COPY_AND_ASSIGN(Worker);
};
@@ -326,11 +343,6 @@ class SequencedWorkerPool::Inner {
// Called from within the lock, this returns the next sequence task number.
int64 LockedGetNextSequenceTaskNumber();
- // Called from within the lock, returns the shutdown behavior of the task
- // running on the currently executing worker thread. If invoked from a thread
- // that is not one of the workers, returns CONTINUE_ON_SHUTDOWN.
- WorkerShutdown LockedCurrentThreadShutdownBehavior() const;
-
// Gets new task. There are 3 cases depending on the return value:
//
// 1) If the return value is |GET_WORK_FOUND|, |task| is filled in and should
@@ -483,7 +495,8 @@ SequencedWorkerPool::Worker::Worker(
const std::string& prefix)
: SimpleThread(prefix + StringPrintf("Worker%d", thread_number)),
worker_pool_(worker_pool),
- running_shutdown_behavior_(CONTINUE_ON_SHUTDOWN) {
+ task_shutdown_behavior_(BLOCK_SHUTDOWN),
+ is_processing_task_(false) {
Start();
}
@@ -497,7 +510,7 @@ void SequencedWorkerPool::Worker::Run() {
// Store a pointer to the running sequence in thread local storage for
// static function access.
- g_lazy_tls_ptr.Get().Set(&running_sequence_);
+ g_lazy_tls_ptr.Get().Set(&task_sequence_token_);
// Just jump back to the Inner object to run the thread, since it has all the
// tracking information and queues. It might be more natural to implement
@@ -583,10 +596,19 @@ bool SequencedWorkerPool::Inner::PostTask(
{
AutoLock lock(lock_);
if (shutdown_called_) {
- if (shutdown_behavior != BLOCK_SHUTDOWN ||
- LockedCurrentThreadShutdownBehavior() == CONTINUE_ON_SHUTDOWN) {
+ // Don't allow a new task to be posted if it doesn't block shutdown.
+ if (shutdown_behavior != BLOCK_SHUTDOWN)
+ return false;
+
+ // If the current thread is running a task, and that task doesn't block
+ // shutdown, then it shouldn't be allowed to post any more tasks.
+ ThreadMap::const_iterator found =
+ threads_.find(PlatformThread::CurrentId());
+ if (found != threads_.end() && found->second->is_processing_task() &&
+ found->second->task_shutdown_behavior() != BLOCK_SHUTDOWN) {
return false;
}
+
if (max_blocking_tasks_after_shutdown_ <= 0) {
DLOG(WARNING) << "BLOCK_SHUTDOWN task disallowed";
return false;
@@ -635,7 +657,8 @@ bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
if (found == threads_.end())
return false;
- return sequence_token.Equals(found->second->running_sequence());
+ return found->second->is_processing_task() &&
+ sequence_token.Equals(found->second->task_sequence_token());
}
// See https://code.google.com/p/chromium/issues/detail?id=168415
@@ -754,7 +777,6 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
this_worker->set_running_task_info(
SequenceToken(task.sequence_token_id), task.shutdown_behavior);
- tracked_objects::ThreadData::PrepareForStartOfRun(task.birth_tally);
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
task.task.Run();
@@ -765,13 +787,12 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
// Make sure our task is erased outside the lock for the
// same reason we do this with delete_these_oustide_lock.
- // Also, do it before calling set_running_task_info() so
+ // Also, do it before calling reset_running_task_info() so
// that sequence-checking from within the task's destructor
// still works.
task.task = Closure();
- this_worker->set_running_task_info(
- SequenceToken(), CONTINUE_ON_SHUTDOWN);
+ this_worker->reset_running_task_info();
}
DidRunWorkerTask(task); // Must be done inside the lock.
} else if (cleanup_state_ == CLEANUP_RUNNING) {
@@ -798,9 +819,25 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
// to run them. Also, there may be some tasks stuck behind running
// ones with the same sequence token, but additional threads won't
// help this case.
- if (shutdown_called_ &&
- blocking_shutdown_pending_task_count_ == 0)
+ if (shutdown_called_ && blocking_shutdown_pending_task_count_ == 0) {
+ AutoUnlock unlock(lock_);
+ delete_these_outside_lock.clear();
break;
+ }
+
+ // No work was found, but there are tasks that need deletion. The
+ // deletion must happen outside of the lock.
+ if (delete_these_outside_lock.size()) {
+ AutoUnlock unlock(lock_);
+ delete_these_outside_lock.clear();
+
+ // Since the lock has been released, |status| may no longer be
+ // accurate. It might read GET_WORK_WAIT even if there are tasks
+ // ready to perform work. Jump to the top of the loop to recalculate
+ // |status|.
+ continue;
+ }
+
waiting_thread_count_++;
switch (status) {
@@ -888,15 +925,6 @@ int64 SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
return next_sequence_task_number_++;
}
-SequencedWorkerPool::WorkerShutdown
-SequencedWorkerPool::Inner::LockedCurrentThreadShutdownBehavior() const {
- lock_.AssertAcquired();
- ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
- if (found == threads_.end())
- return CONTINUE_ON_SHUTDOWN;
- return found->second->running_shutdown_behavior();
-}
-
SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork(
SequencedTask* task,
TimeDelta* wait_time,
@@ -1089,7 +1117,7 @@ int SequencedWorkerPool::Inner::PrepareToStartAdditionalThreadIfHelpful() {
void SequencedWorkerPool::Inner::FinishStartingAdditionalThread(
int thread_number) {
// Called outside of the lock.
- DCHECK(thread_number > 0);
+ DCHECK_GT(thread_number, 0);
// The worker is assigned to the list when the thread actually starts, which
// will manage the memory of the pointer.
@@ -1129,29 +1157,26 @@ SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
return *token;
}
-SequencedWorkerPool::SequencedWorkerPool(
- size_t max_threads,
- const std::string& thread_name_prefix)
- : constructor_message_loop_(MessageLoopProxy::current()),
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+ const std::string& thread_name_prefix)
+ : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
inner_(new Inner(this, max_threads, thread_name_prefix, NULL)) {
}
-SequencedWorkerPool::SequencedWorkerPool(
- size_t max_threads,
- const std::string& thread_name_prefix,
- TestingObserver* observer)
- : constructor_message_loop_(MessageLoopProxy::current()),
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+ const std::string& thread_name_prefix,
+ TestingObserver* observer)
+ : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
inner_(new Inner(this, max_threads, thread_name_prefix, observer)) {
}
SequencedWorkerPool::~SequencedWorkerPool() {}
void SequencedWorkerPool::OnDestruct() const {
- DCHECK(constructor_message_loop_.get());
// Avoid deleting ourselves on a worker thread (which would
// deadlock).
if (RunsTasksOnCurrentThread()) {
- constructor_message_loop_->DeleteSoon(FROM_HERE, this);
+ constructor_task_runner_->DeleteSoon(FROM_HERE, this);
} else {
delete this;
}
@@ -1271,7 +1296,7 @@ void SequencedWorkerPool::SignalHasWorkForTesting() {
}
void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) {
- DCHECK(constructor_message_loop_->BelongsToCurrentThread());
+ DCHECK(constructor_task_runner_->BelongsToCurrentThread());
inner_->Shutdown(max_new_blocking_tasks_after_shutdown);
}
diff --git a/chromium/base/threading/sequenced_worker_pool.h b/chromium/base/threading/sequenced_worker_pool.h
index 63c6204ebbb..ee282bc2312 100644
--- a/chromium/base/threading/sequenced_worker_pool.h
+++ b/chromium/base/threading/sequenced_worker_pool.h
@@ -13,6 +13,7 @@
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_runner.h"
namespace tracked_objects {
@@ -21,7 +22,7 @@ class Location;
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
template <class T> class DeleteHelper;
@@ -320,12 +321,10 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// Must be called from the same thread this object was constructed on.
void Shutdown() { Shutdown(0); }
- // A variant that allows an arbitrary number of new blocking tasks to
- // be posted during shutdown from within tasks that execute during shutdown.
- // Only tasks designated as BLOCKING_SHUTDOWN will be allowed, and only if
- // posted by tasks that are not designated as CONTINUE_ON_SHUTDOWN. Once
+ // A variant that allows an arbitrary number of new blocking tasks to be
+ // posted during shutdown. The tasks cannot be posted within the execution
+ // context of tasks whose shutdown behavior is not BLOCKING_SHUTDOWN. Once
// the limit is reached, subsequent calls to post task fail in all cases.
- //
// Must be called from the same thread this object was constructed on.
void Shutdown(int max_new_blocking_tasks_after_shutdown);
@@ -347,7 +346,7 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
class Inner;
class Worker;
- const scoped_refptr<MessageLoopProxy> constructor_message_loop_;
+ const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_;
// Avoid pulling in too many headers by putting (almost) everything
// into |inner_|.
diff --git a/chromium/base/threading/sequenced_worker_pool_unittest.cc b/chromium/base/threading/sequenced_worker_pool_unittest.cc
index b1fe2764442..05989a5487a 100644
--- a/chromium/base/threading/sequenced_worker_pool_unittest.cc
+++ b/chromium/base/threading/sequenced_worker_pool_unittest.cc
@@ -11,7 +11,6 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/test/sequenced_task_runner_test_template.h"
@@ -54,7 +53,7 @@ class ThreadBlocker {
void Unblock(size_t count) {
{
base::AutoLock lock(lock_);
- DCHECK(unblock_counter_ == 0);
+ DCHECK_EQ(unblock_counter_, 0u);
unblock_counter_ = count;
}
cond_var_.Signal();
@@ -67,6 +66,23 @@ class ThreadBlocker {
size_t unblock_counter_;
};
+class DestructionDeadlockChecker
+ : public base::RefCountedThreadSafe<DestructionDeadlockChecker> {
+ public:
+ DestructionDeadlockChecker(const scoped_refptr<SequencedWorkerPool>& pool)
+ : pool_(pool) {}
+
+ protected:
+ virtual ~DestructionDeadlockChecker() {
+ // This method should not deadlock.
+ pool_->RunsTasksOnCurrentThread();
+ }
+
+ private:
+ scoped_refptr<SequencedWorkerPool> pool_;
+ friend class base::RefCountedThreadSafe<DestructionDeadlockChecker>;
+};
+
class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
public:
TestTracker()
@@ -117,6 +133,41 @@ class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
SignalWorkerDone(id);
}
+ // This task posts itself back onto the SequencedWorkerPool before it
+ // finishes running. Each instance of the task maintains a strong reference
+ // to a DestructionDeadlockChecker. The DestructionDeadlockChecker is only
+ // destroyed when the task is destroyed without being run, which only happens
+ // during destruction of the SequencedWorkerPool.
+ void PostRepostingTask(
+ const scoped_refptr<SequencedWorkerPool>& pool,
+ const scoped_refptr<DestructionDeadlockChecker>& checker) {
+ Closure reposting_task =
+ base::Bind(&TestTracker::PostRepostingTask, this, pool, checker);
+ pool->PostWorkerTaskWithShutdownBehavior(
+ FROM_HERE, reposting_task, SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+ }
+
+ // This task reposts itself back onto the SequencedWorkerPool before it
+ // finishes running.
+ void PostRepostingBlockingTask(
+ const scoped_refptr<SequencedWorkerPool>& pool,
+ const SequencedWorkerPool::SequenceToken& token) {
+ Closure reposting_task =
+ base::Bind(&TestTracker::PostRepostingBlockingTask, this, pool, token);
+ pool->PostSequencedWorkerTaskWithShutdownBehavior(token,
+ FROM_HERE, reposting_task, SequencedWorkerPool::BLOCK_SHUTDOWN);
+ }
+
+ void PostBlockingTaskThenUnblockThreads(
+ const scoped_refptr<SequencedWorkerPool>& pool,
+ ThreadBlocker* blocker,
+ size_t threads_to_wake) {
+ Closure arbitrary_task = base::Bind(&TestTracker::FastTask, this, 0);
+ pool->PostWorkerTaskWithShutdownBehavior(
+ FROM_HERE, arbitrary_task, SequencedWorkerPool::BLOCK_SHUTDOWN);
+ blocker->Unblock(threads_to_wake);
+ }
+
// Waits until the given number of tasks have started executing.
void WaitUntilTasksBlocked(size_t count) {
{
@@ -183,13 +234,7 @@ class SequencedWorkerPoolTest : public testing::Test {
ResetPool();
}
- virtual ~SequencedWorkerPoolTest() {}
-
- virtual void SetUp() override {}
-
- virtual void TearDown() override {
- pool()->Shutdown();
- }
+ void TearDown() override { pool()->Shutdown(); }
const scoped_refptr<SequencedWorkerPool>& pool() {
return pool_owner_->pool();
@@ -251,7 +296,7 @@ class SequencedWorkerPoolTest : public testing::Test {
// Checks that the given number of entries are in the tasks to complete of
// the given tracker, and then signals the given event the given number of
-// times. This is used to wakt up blocked background threads before blocking
+// times. This is used to wake up blocked background threads before blocking
// on shutdown.
void EnsureTasksToCompleteCountAndUnblock(scoped_refptr<TestTracker> tracker,
size_t expected_tasks_to_complete,
@@ -547,6 +592,34 @@ TEST_F(SequencedWorkerPoolTest, AllowsAfterShutdown) {
tracker()->ClearCompleteSequence();
}
+// Tests that blocking tasks can still be posted during shutdown, as long as
+// the task is not being posted within the context of a running task.
+TEST_F(SequencedWorkerPoolTest,
+ AllowsBlockingTasksDuringShutdownOutsideOfRunningTask) {
+ EnsureAllWorkersCreated();
+ ThreadBlocker blocker;
+
+ // Start tasks to take all the threads and block them.
+ const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads);
+ for (int i = 0; i < kNumBlockTasks; ++i) {
+ EXPECT_TRUE(pool()->PostWorkerTask(
+ FROM_HERE,
+ base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker)));
+ }
+ tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+ // Setup to open the floodgates from within Shutdown().
+ SetWillWaitForShutdownCallback(
+ base::Bind(&TestTracker::PostBlockingTaskThenUnblockThreads,
+ scoped_refptr<TestTracker>(tracker()), pool(), &blocker,
+ kNumWorkerThreads));
+ pool()->Shutdown(kNumWorkerThreads + 1);
+
+ // Ensure that the correct number of tasks actually got run.
+ tracker()->WaitUntilTasksComplete(static_cast<size_t>(kNumWorkerThreads + 1));
+ tracker()->ClearCompleteSequence();
+}
+
// Tests that unrun tasks are discarded properly according to their shutdown
// mode.
TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) {
@@ -755,6 +828,41 @@ TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
unused_pool->Shutdown();
}
+// Checks that tasks are destroyed in the right context during shutdown. If a
+// task is destroyed while SequencedWorkerPool's global lock is held,
+// SequencedWorkerPool might deadlock.
+TEST_F(SequencedWorkerPoolTest, AvoidsDeadlockOnShutdown) {
+ for (int i = 0; i < 4; ++i) {
+ scoped_refptr<DestructionDeadlockChecker> checker(
+ new DestructionDeadlockChecker(pool()));
+ tracker()->PostRepostingTask(pool(), checker);
+ }
+
+ // Shutting down the pool should destroy the DestructionDeadlockCheckers,
+ // which in turn should not deadlock in their destructors.
+ pool()->Shutdown();
+}
+
+// Similar to the test AvoidsDeadlockOnShutdown, but there are now also
+// sequenced, blocking tasks in the queue during shutdown.
+TEST_F(SequencedWorkerPoolTest,
+ AvoidsDeadlockOnShutdownWithSequencedBlockingTasks) {
+ const std::string sequence_token_name("name");
+ for (int i = 0; i < 4; ++i) {
+ scoped_refptr<DestructionDeadlockChecker> checker(
+ new DestructionDeadlockChecker(pool()));
+ tracker()->PostRepostingTask(pool(), checker);
+
+ SequencedWorkerPool::SequenceToken token1 =
+ pool()->GetNamedSequenceToken(sequence_token_name);
+ tracker()->PostRepostingBlockingTask(pool(), token1);
+ }
+
+ // Shutting down the pool should destroy the DestructionDeadlockCheckers,
+ // which in turn should not deadlock in their destructors.
+ pool()->Shutdown();
+}
+
// Verify that FlushForTesting works as intended.
TEST_F(SequencedWorkerPoolTest, FlushForTesting) {
// Should be fine to call on a new instance.
diff --git a/chromium/base/threading/simple_thread.cc b/chromium/base/threading/simple_thread.cc
index 028d4f4ab23..1bc31135941 100644
--- a/chromium/base/threading/simple_thread.cc
+++ b/chromium/base/threading/simple_thread.cc
@@ -52,7 +52,7 @@ void SimpleThread::ThreadMain() {
// Construct our full name of the form "name_prefix_/TID".
name_.push_back('/');
name_.append(IntToString(tid_));
- PlatformThread::SetName(name_.c_str());
+ PlatformThread::SetName(name_);
// We've initialized our new thread, signal that we're done to Start().
event_.Signal();
diff --git a/chromium/base/threading/thread.cc b/chromium/base/threading/thread.cc
index ad1360be3e4..0e4aab2c354 100644
--- a/chromium/base/threading/thread.cc
+++ b/chromium/base/threading/thread.cc
@@ -6,11 +6,13 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/synchronization/waitable_event.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
-#include "base/synchronization/waitable_event.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
@@ -111,6 +113,11 @@ bool Thread::StartWithOptions(const Options& options) {
return false;
}
+ // TODO(kinuko): Remove once crbug.com/465458 is solved.
+ tracked_objects::ScopedTracker tracking_profile_wait(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "465458 base::Thread::StartWithOptions (Wait)"));
+
// Wait for the thread to start and initialize message_loop_
base::ThreadRestrictions::ScopedAllowWait allow_wait;
startup_data.event.Wait();
@@ -156,7 +163,7 @@ void Thread::StopSoon() {
return;
stopping_ = true;
- message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+ task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
}
bool Thread::IsRunning() const {
@@ -201,7 +208,7 @@ void Thread::ThreadMain() {
// Complete the initialization of our Thread object.
thread_id_ = PlatformThread::CurrentId();
- PlatformThread::SetName(name_.c_str());
+ PlatformThread::SetName(name_);
ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
message_loop->set_thread_name(name_);
message_loop->SetTimerSlack(startup_data_->options.timer_slack);
diff --git a/chromium/base/threading/thread.h b/chromium/base/threading/thread.h
index 5010f0ec428..49156063929 100644
--- a/chromium/base/threading/thread.h
+++ b/chromium/base/threading/thread.h
@@ -11,8 +11,8 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/message_loop/timer_slack.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/platform_thread.h"
namespace base {
@@ -156,7 +156,7 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {
// hold on to this even after the thread is gone; in this situation, attempts
// to PostTask() will fail.
scoped_refptr<SingleThreadTaskRunner> task_runner() const {
- return message_loop_proxy();
+ return message_loop_->task_runner();
}
// Returns the name of this thread (for display in debugger too).
diff --git a/chromium/base/threading/thread_checker.h b/chromium/base/threading/thread_checker.h
index 4d71f798d4d..449247af9dd 100644
--- a/chromium/base/threading/thread_checker.h
+++ b/chromium/base/threading/thread_checker.h
@@ -30,7 +30,7 @@ namespace base {
// right version for your build configuration.
class ThreadCheckerDoNothing {
public:
- bool CalledOnValidThread() const {
+ bool CalledOnValidThread() const WARN_UNUSED_RESULT {
return true;
}
diff --git a/chromium/base/threading/thread_checker_impl.h b/chromium/base/threading/thread_checker_impl.h
index 879ac3ab354..c92e143db0c 100644
--- a/chromium/base/threading/thread_checker_impl.h
+++ b/chromium/base/threading/thread_checker_impl.h
@@ -6,6 +6,7 @@
#define BASE_THREADING_THREAD_CHECKER_IMPL_H_
#include "base/base_export.h"
+#include "base/compiler_specific.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
@@ -22,7 +23,7 @@ class BASE_EXPORT ThreadCheckerImpl {
ThreadCheckerImpl();
~ThreadCheckerImpl();
- bool CalledOnValidThread() const;
+ bool CalledOnValidThread() const WARN_UNUSED_RESULT;
// Changes the thread that is checked for in CalledOnValidThread. This may
// be useful when an object may be created on one thread and then used
diff --git a/chromium/base/threading/thread_collision_warner_unittest.cc b/chromium/base/threading/thread_collision_warner_unittest.cc
index 26faff404f6..d7ce79ec378 100644
--- a/chromium/base/threading/thread_collision_warner_unittest.cc
+++ b/chromium/base/threading/thread_collision_warner_unittest.cc
@@ -146,24 +146,23 @@ TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
class QueueUser : public base::DelegateSimpleThread::Delegate {
public:
- explicit QueueUser(NonThreadSafeQueue& queue)
- : queue_(queue) {}
+ explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
void Run() override {
- queue_.push(0);
- queue_.pop();
+ queue_->push(0);
+ queue_->pop();
}
private:
- NonThreadSafeQueue& queue_;
+ NonThreadSafeQueue* queue_;
};
AssertReporter* local_reporter = new AssertReporter();
NonThreadSafeQueue queue(local_reporter);
- QueueUser queue_user_a(queue);
- QueueUser queue_user_b(queue);
+ QueueUser queue_user_a(&queue);
+ QueueUser queue_user_b(&queue);
base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
@@ -204,24 +203,23 @@ TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
class QueueUser : public base::DelegateSimpleThread::Delegate {
public:
- explicit QueueUser(NonThreadSafeQueue& queue)
- : queue_(queue) {}
+ explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
void Run() override {
- queue_.push(0);
- queue_.pop();
+ queue_->push(0);
+ queue_->pop();
}
private:
- NonThreadSafeQueue& queue_;
+ NonThreadSafeQueue* queue_;
};
AssertReporter* local_reporter = new AssertReporter();
NonThreadSafeQueue queue(local_reporter);
- QueueUser queue_user_a(queue);
- QueueUser queue_user_b(queue);
+ QueueUser queue_user_a(&queue);
+ QueueUser queue_user_b(&queue);
base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
@@ -264,23 +262,22 @@ TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
// a lock.
class QueueUser : public base::DelegateSimpleThread::Delegate {
public:
- QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
- : queue_(queue),
- lock_(lock) {}
+ QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
+ : queue_(queue), lock_(lock) {}
void Run() override {
{
- base::AutoLock auto_lock(lock_);
- queue_.push(0);
+ base::AutoLock auto_lock(*lock_);
+ queue_->push(0);
}
{
- base::AutoLock auto_lock(lock_);
- queue_.pop();
+ base::AutoLock auto_lock(*lock_);
+ queue_->pop();
}
}
private:
- NonThreadSafeQueue& queue_;
- base::Lock& lock_;
+ NonThreadSafeQueue* queue_;
+ base::Lock* lock_;
};
AssertReporter* local_reporter = new AssertReporter();
@@ -289,8 +286,8 @@ TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
base::Lock lock;
- QueueUser queue_user_a(queue, lock);
- QueueUser queue_user_b(queue, lock);
+ QueueUser queue_user_a(&queue, &lock);
+ QueueUser queue_user_b(&queue, &lock);
base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
@@ -338,27 +335,26 @@ TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
// a lock.
class QueueUser : public base::DelegateSimpleThread::Delegate {
public:
- QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
- : queue_(queue),
- lock_(lock) {}
+ QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
+ : queue_(queue), lock_(lock) {}
void Run() override {
{
- base::AutoLock auto_lock(lock_);
- queue_.push(0);
+ base::AutoLock auto_lock(*lock_);
+ queue_->push(0);
}
{
- base::AutoLock auto_lock(lock_);
- queue_.bar();
+ base::AutoLock auto_lock(*lock_);
+ queue_->bar();
}
{
- base::AutoLock auto_lock(lock_);
- queue_.pop();
+ base::AutoLock auto_lock(*lock_);
+ queue_->pop();
}
}
private:
- NonThreadSafeQueue& queue_;
- base::Lock& lock_;
+ NonThreadSafeQueue* queue_;
+ base::Lock* lock_;
};
AssertReporter* local_reporter = new AssertReporter();
@@ -367,8 +363,8 @@ TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
base::Lock lock;
- QueueUser queue_user_a(queue, lock);
- QueueUser queue_user_b(queue, lock);
+ QueueUser queue_user_a(&queue, &lock);
+ QueueUser queue_user_b(&queue, &lock);
base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
diff --git a/chromium/base/threading/thread_id_name_manager.cc b/chromium/base/threading/thread_id_name_manager.cc
index 7c85c1b5e99..56cfa273a87 100644
--- a/chromium/base/threading/thread_id_name_manager.cc
+++ b/chromium/base/threading/thread_id_name_manager.cc
@@ -48,17 +48,16 @@ void ThreadIdNameManager::RegisterThread(PlatformThreadHandle::Handle handle,
name_to_interned_name_[kDefaultName];
}
-void ThreadIdNameManager::SetName(PlatformThreadId id, const char* name) {
- std::string str_name(name);
-
+void ThreadIdNameManager::SetName(PlatformThreadId id,
+ const std::string& name) {
AutoLock locked(lock_);
- NameToInternedNameMap::iterator iter = name_to_interned_name_.find(str_name);
+ NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name);
std::string* leaked_str = NULL;
if (iter != name_to_interned_name_.end()) {
leaked_str = iter->second;
} else {
- leaked_str = new std::string(str_name);
- name_to_interned_name_[str_name] = leaked_str;
+ leaked_str = new std::string(name);
+ name_to_interned_name_[name] = leaked_str;
}
ThreadIdToHandleMap::iterator id_to_handle_iter =
diff --git a/chromium/base/threading/thread_id_name_manager.h b/chromium/base/threading/thread_id_name_manager.h
index 0ea59df6572..927d25fe1e8 100644
--- a/chromium/base/threading/thread_id_name_manager.h
+++ b/chromium/base/threading/thread_id_name_manager.h
@@ -27,7 +27,7 @@ class BASE_EXPORT ThreadIdNameManager {
void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
// Set the name for the given id.
- void SetName(PlatformThreadId id, const char* name);
+ void SetName(PlatformThreadId id, const std::string& name);
// Get the name for the given id.
const char* GetName(PlatformThreadId id);
diff --git a/chromium/base/threading/thread_local_android.cc b/chromium/base/threading/thread_local_android.cc
index c890237f67d..813dd78b5ec 100644
--- a/chromium/base/threading/thread_local_android.cc
+++ b/chromium/base/threading/thread_local_android.cc
@@ -4,15 +4,12 @@
#include "base/threading/thread_local.h"
-#include "base/logging.h"
-
namespace base {
namespace internal {
// static
void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
- bool succeed = slot->Initialize(NULL);
- CHECK(succeed);
+ slot->Initialize(nullptr);
}
// static
diff --git a/chromium/base/threading/thread_local_storage.cc b/chromium/base/threading/thread_local_storage.cc
index 4f4169fe718..0bb396cfd79 100644
--- a/chromium/base/threading/thread_local_storage.cc
+++ b/chromium/base/threading/thread_local_storage.cc
@@ -140,8 +140,8 @@ void OnThreadExitInternal(void* value) {
base::subtle::Atomic32 last_used_tls_key =
base::subtle::NoBarrier_Load(&g_last_used_tls_key);
for (int slot = last_used_tls_key; slot > 0; --slot) {
- void* value = stack_allocated_tls_data[slot];
- if (value == NULL)
+ void* tls_value = stack_allocated_tls_data[slot];
+ if (tls_value == NULL)
continue;
base::ThreadLocalStorage::TLSDestructorFunc destructor =
@@ -149,7 +149,7 @@ void OnThreadExitInternal(void* value) {
if (destructor == NULL)
continue;
stack_allocated_tls_data[slot] = NULL; // pre-clear the slot.
- destructor(value);
+ destructor(tls_value);
// Any destructor might have called a different service, which then set
// a different slot to a non-NULL value. Hence we need to check
// the whole vector again. This is a pthread standard.
@@ -197,7 +197,7 @@ ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
Initialize(destructor);
}
-bool ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
+void ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
PlatformThreadLocalStorage::TLSKey key =
base::subtle::NoBarrier_Load(&g_native_tls_key);
if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES ||
@@ -212,7 +212,6 @@ bool ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
// Setup our destructor.
g_tls_destructors[slot_] = destructor;
initialized_ = true;
- return true;
}
void ThreadLocalStorage::StaticSlot::Free() {
diff --git a/chromium/base/threading/thread_local_storage.h b/chromium/base/threading/thread_local_storage.h
index 53ebe55e51c..50f88685a57 100644
--- a/chromium/base/threading/thread_local_storage.h
+++ b/chromium/base/threading/thread_local_storage.h
@@ -98,8 +98,7 @@ class BASE_EXPORT ThreadLocalStorage {
// Set up the TLS slot. Called by the constructor.
// 'destructor' is a pointer to a function to perform per-thread cleanup of
// this object. If set to NULL, no cleanup is done for this TLS slot.
- // Returns false on error.
- bool Initialize(TLSDestructorFunc destructor);
+ void Initialize(TLSDestructorFunc destructor);
// Free a previously allocated TLS 'slot'.
// If a destructor was set for this slot, removes
@@ -136,6 +135,7 @@ class BASE_EXPORT ThreadLocalStorage {
DISALLOW_COPY_AND_ASSIGN(Slot);
};
+ private:
DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
};
diff --git a/chromium/base/threading/thread_local_storage_unittest.cc b/chromium/base/threading/thread_local_storage_unittest.cc
index b53f5777158..bcc1d1b9db5 100644
--- a/chromium/base/threading/thread_local_storage_unittest.cc
+++ b/chromium/base/threading/thread_local_storage_unittest.cc
@@ -79,17 +79,16 @@ TEST(ThreadLocalStorageTest, Basics) {
EXPECT_EQ(value, 123);
}
-#if defined(THREAD_SANITIZER) || \
- (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && \
- defined(INCREMENTAL_LINKING))
+#if defined(THREAD_SANITIZER) || \
+ (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG))
// Do not run the test under ThreadSanitizer. Because this test iterates its
// own TSD destructor for the maximum possible number of times, TSan can't jump
// in after the last destructor invocation, therefore the destructor remains
// unsynchronized with the following users of the same TSD slot. This results
// in race reports between the destructor and functions in other tests.
//
-// It is disabled on Win x64 with incremental linking pending resolution of
-// http://crbug.com/251251.
+// It is disabled on Win x64 with incremental linking (i.e. "Debug") pending
+// resolution of http://crbug.com/251251.
#define MAYBE_TLSDestructors DISABLED_TLSDestructors
#else
#define MAYBE_TLSDestructors TLSDestructors
diff --git a/chromium/base/threading/thread_local_unittest.cc b/chromium/base/threading/thread_local_unittest.cc
index 8dc7cd2bdde..e94c1db1c8d 100644
--- a/chromium/base/threading/thread_local_unittest.cc
+++ b/chromium/base/threading/thread_local_unittest.cc
@@ -14,7 +14,7 @@ namespace {
class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
public:
- typedef base::ThreadLocalPointer<ThreadLocalTesterBase> TLPType;
+ typedef base::ThreadLocalPointer<char> TLPType;
ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
: tlp_(tlp),
@@ -35,7 +35,7 @@ class SetThreadLocal : public ThreadLocalTesterBase {
}
~SetThreadLocal() override {}
- void set_value(ThreadLocalTesterBase* val) { val_ = val; }
+ void set_value(char* val) { val_ = val; }
void Run() override {
DCHECK(!done_->IsSignaled());
@@ -44,7 +44,7 @@ class SetThreadLocal : public ThreadLocalTesterBase {
}
private:
- ThreadLocalTesterBase* val_;
+ char* val_;
};
class GetThreadLocal : public ThreadLocalTesterBase {
@@ -55,7 +55,7 @@ class GetThreadLocal : public ThreadLocalTesterBase {
}
~GetThreadLocal() override {}
- void set_ptr(ThreadLocalTesterBase** ptr) { ptr_ = ptr; }
+ void set_ptr(char** ptr) { ptr_ = ptr; }
void Run() override {
DCHECK(!done_->IsSignaled());
@@ -64,7 +64,7 @@ class GetThreadLocal : public ThreadLocalTesterBase {
}
private:
- ThreadLocalTesterBase** ptr_;
+ char** ptr_;
};
} // namespace
@@ -77,12 +77,11 @@ TEST(ThreadLocalTest, Pointer) {
tp1.Start();
tp2.Start();
- base::ThreadLocalPointer<ThreadLocalTesterBase> tlp;
+ base::ThreadLocalPointer<char> tlp;
- static ThreadLocalTesterBase* const kBogusPointer =
- reinterpret_cast<ThreadLocalTesterBase*>(0x1234);
+ static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
- ThreadLocalTesterBase* tls_val;
+ char* tls_val;
base::WaitableEvent done(true, false);
GetThreadLocal getter(&tlp, &done);
@@ -93,13 +92,13 @@ TEST(ThreadLocalTest, Pointer) {
done.Reset();
tp1.AddWork(&getter);
done.Wait();
- EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
+ EXPECT_EQ(static_cast<char*>(NULL), tls_val);
tls_val = kBogusPointer;
done.Reset();
tp2.AddWork(&getter);
done.Wait();
- EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
+ EXPECT_EQ(static_cast<char*>(NULL), tls_val);
SetThreadLocal setter(&tlp, &done);
@@ -121,7 +120,7 @@ TEST(ThreadLocalTest, Pointer) {
done.Reset();
tp2.AddWork(&getter);
done.Wait();
- EXPECT_EQ(static_cast<ThreadLocalTesterBase*>(NULL), tls_val);
+ EXPECT_EQ(static_cast<char*>(NULL), tls_val);
// Set thread 2 to kBogusPointer + 1.
setter.set_value(kBogusPointer + 1);
diff --git a/chromium/base/threading/thread_perftest.cc b/chromium/base/threading/thread_perftest.cc
index 9fbc844ec2e..3bc9fb409ce 100644
--- a/chromium/base/threading/thread_perftest.cc
+++ b/chromium/base/threading/thread_perftest.cc
@@ -5,7 +5,9 @@
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/location.h"
#include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -54,12 +56,9 @@ class ThreadPerfTest : public testing::Test {
base::TimeTicks ThreadNow(base::Thread* thread) {
base::WaitableEvent done(false, false);
base::TimeTicks ticks;
- thread->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadPerfTest::TimeOnThread,
- base::Unretained(this),
- &ticks,
- &done));
+ thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadPerfTest::TimeOnThread,
+ base::Unretained(this), &ticks, &done));
done.Wait();
return ticks;
}
@@ -76,10 +75,10 @@ class ThreadPerfTest : public testing::Test {
Init();
- base::TimeTicks start = base::TimeTicks::HighResNow();
+ base::TimeTicks start = base::TimeTicks::Now();
PingPong(kNumRuns);
done_.Wait();
- base::TimeTicks end = base::TimeTicks::HighResNow();
+ base::TimeTicks end = base::TimeTicks::Now();
// Gather the cpu-time spent on each thread. This does one extra tasks,
// but that should be in the noise given enough runs.
@@ -128,10 +127,9 @@ class TaskPerfTest : public ThreadPerfTest {
FinishMeasurement();
return;
}
- NextThread(hops)->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(
- &ThreadPerfTest::PingPong, base::Unretained(this), hops - 1));
+ NextThread(hops)->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadPerfTest::PingPong, base::Unretained(this),
+ hops - 1));
}
};
@@ -174,12 +172,12 @@ TEST_F(TaskObserverPerfTest, TaskPingPong) {
template <typename WaitableEventType>
class EventPerfTest : public ThreadPerfTest {
public:
- virtual void Init() override {
+ void Init() override {
for (size_t i = 0; i < threads_.size(); i++)
events_.push_back(new WaitableEventType(false, false));
}
- virtual void Reset() override { events_.clear(); }
+ void Reset() override { events_.clear(); }
void WaitAndSignalOnThread(size_t event) {
size_t next_event = (event + 1) % events_.size();
@@ -195,14 +193,12 @@ class EventPerfTest : public ThreadPerfTest {
FinishMeasurement();
}
- virtual void PingPong(int hops) override {
+ void PingPong(int hops) override {
remaining_hops_ = hops;
for (size_t i = 0; i < threads_.size(); i++) {
- threads_[i]->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&EventPerfTest::WaitAndSignalOnThread,
- base::Unretained(this),
- i));
+ threads_[i]->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&EventPerfTest::WaitAndSignalOnThread,
+ base::Unretained(this), i));
}
// Kick off the Signal ping-ponging.
diff --git a/chromium/base/threading/thread_restrictions.h b/chromium/base/threading/thread_restrictions.h
index 7c46fd2bdb4..54f50ebca87 100644
--- a/chromium/base/threading/thread_restrictions.h
+++ b/chromium/base/threading/thread_restrictions.h
@@ -22,6 +22,7 @@ class ScopedAllowWaitForLegacyWebViewApi;
namespace cc {
class CompletionEvent;
+class TaskGraphRunner;
}
namespace chromeos {
class BlockingMethodCaller;
@@ -41,8 +42,9 @@ class GpuChannelHost;
class NestedMessagePumpAndroid;
class RenderWidgetResizeHelper;
class ScopedAllowWaitForAndroidLayoutTests;
+class ScopedAllowWaitForDebugURL;
class TextInputClientMac;
-}
+} // namespace content
namespace dbus {
class Bus;
}
@@ -174,9 +176,11 @@ class BASE_EXPORT ThreadRestrictions {
friend class content::NestedMessagePumpAndroid;
friend class content::RenderWidgetResizeHelper;
friend class content::ScopedAllowWaitForAndroidLayoutTests;
+ friend class content::ScopedAllowWaitForDebugURL;
friend class ::HistogramSynchronizer;
friend class ::ScopedAllowWaitForLegacyWebViewApi;
friend class cc::CompletionEvent;
+ friend class cc::TaskGraphRunner;
friend class mojo::common::WatcherThreadManager;
friend class remoting::AutoThread;
friend class MessagePumpDefault;
diff --git a/chromium/base/threading/thread_unittest.cc b/chromium/base/threading/thread_unittest.cc
index f3fb3343e9a..a89768e9d0a 100644
--- a/chromium/base/threading/thread_unittest.cc
+++ b/chromium/base/threading/thread_unittest.cc
@@ -7,7 +7,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -133,13 +134,18 @@ TEST_F(ThreadTest, StartWithOptions_StackSize) {
// Ensure that the thread can work with only 12 kb and still process a
// message.
Thread::Options options;
+#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
+ // ASan bloats the stack variables and overflows the 12 kb stack on OSX.
+ options.stack_size = 24*1024;
+#else
options.stack_size = 12*1024;
+#endif
EXPECT_TRUE(a.StartWithOptions(options));
EXPECT_TRUE(a.message_loop());
EXPECT_TRUE(a.IsRunning());
bool was_invoked = false;
- a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
+ a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
// wait for the task to run (we could use a kernel event here
// instead to avoid busy waiting, but this is sufficient for
@@ -160,14 +166,12 @@ TEST_F(ThreadTest, TwoTasks) {
// Test that all events are dispatched before the Thread object is
// destroyed. We do this by dispatching a sleep event before the
// event that will toggle our sentinel value.
- a.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(
- static_cast<void (*)(base::TimeDelta)>(
- &base::PlatformThread::Sleep),
- base::TimeDelta::FromMilliseconds(20)));
- a.message_loop()->PostTask(FROM_HERE, base::Bind(&ToggleValue,
- &was_invoked));
+ a.task_runner()->PostTask(
+ FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
+ &base::PlatformThread::Sleep),
+ base::TimeDelta::FromMilliseconds(20)));
+ a.task_runner()->PostTask(FROM_HERE,
+ base::Bind(&ToggleValue, &was_invoked));
}
EXPECT_TRUE(was_invoked);
}
@@ -216,7 +220,7 @@ TEST_F(ThreadTest, CleanUp) {
// Register an observer that writes into |captured_events| once the
// thread's message loop is destroyed.
- t.message_loop()->PostTask(
+ t.task_runner()->PostTask(
FROM_HERE, base::Bind(&RegisterDestructionObserver,
base::Unretained(&loop_destruction_observer)));
diff --git a/chromium/base/threading/watchdog.cc b/chromium/base/threading/watchdog.cc
index 769119efc4b..c0637998a4b 100644
--- a/chromium/base/threading/watchdog.cc
+++ b/chromium/base/threading/watchdog.cc
@@ -169,7 +169,7 @@ void Watchdog::ThreadDelegate::ThreadMain() {
void Watchdog::ThreadDelegate::SetThreadName() const {
std::string name = watchdog_->thread_watched_name_ + " Watchdog";
- PlatformThread::SetName(name.c_str());
+ PlatformThread::SetName(name);
DVLOG(1) << "Watchdog active: " << name;
}
diff --git a/chromium/base/threading/watchdog_unittest.cc b/chromium/base/threading/watchdog_unittest.cc
index b8cc7b7e004..627f46d8a9b 100644
--- a/chromium/base/threading/watchdog_unittest.cc
+++ b/chromium/base/threading/watchdog_unittest.cc
@@ -43,9 +43,7 @@ class WatchdogCounter : public Watchdog {
class WatchdogTest : public testing::Test {
public:
- virtual void SetUp() override {
- Watchdog::ResetStaticData();
- }
+ void SetUp() override { Watchdog::ResetStaticData(); }
};
} // namespace
diff --git a/chromium/base/threading/worker_pool.h b/chromium/base/threading/worker_pool.h
index 333b4950f6b..a52a41428b3 100644
--- a/chromium/base/threading/worker_pool.h
+++ b/chromium/base/threading/worker_pool.h
@@ -36,7 +36,7 @@ class BASE_EXPORT WorkerPool {
static bool PostTask(const tracked_objects::Location& from_here,
const base::Closure& task, bool task_is_slow);
- // Just like MessageLoopProxy::PostTaskAndReply, except the destination
+ // Just like TaskRunner::PostTaskAndReply, except the destination
// for |task| is a worker thread and you can specify |task_is_slow| just
// like you can for PostTask above.
static bool PostTaskAndReply(const tracked_objects::Location& from_here,
diff --git a/chromium/base/threading/worker_pool_posix.cc b/chromium/base/threading/worker_pool_posix.cc
index cd3c9dc7543..349b5d751c1 100644
--- a/chromium/base/threading/worker_pool_posix.cc
+++ b/chromium/base/threading/worker_pool_posix.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
@@ -14,6 +13,7 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread_local.h"
#include "base/threading/worker_pool.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
using tracked_objects::TrackedTime;
@@ -27,14 +27,6 @@ base::LazyInstance<ThreadLocalBoolean>::Leaky
const int kIdleSecondsBeforeExit = 10 * 60;
-#ifdef ADDRESS_SANITIZER
-const int kWorkerThreadStackSize = 256 * 1024;
-#else
-// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
-// function of NSS because of NSS bug 439169.
-const int kWorkerThreadStackSize = 128 * 1024;
-#endif
-
class WorkerPoolImpl {
public:
WorkerPoolImpl();
@@ -85,7 +77,7 @@ void WorkerThread::ThreadMain() {
const std::string name = base::StringPrintf(
"%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
// Note |name.c_str()| must remain valid for for the whole life of the thread.
- PlatformThread::SetName(name.c_str());
+ PlatformThread::SetName(name);
for (;;) {
PendingTask pending_task = pool_->WaitForTask();
@@ -95,15 +87,13 @@ void WorkerThread::ThreadMain() {
"src_file", pending_task.posted_from.file_name(),
"src_func", pending_task.posted_from.function_name());
- tracked_objects::ThreadData::PrepareForStartOfRun(pending_task.birth_tally);
tracked_objects::TaskStopwatch stopwatch;
stopwatch.Start();
pending_task.task.Run();
stopwatch.Stop();
tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
- pending_task.birth_tally, TrackedTime(pending_task.time_posted),
- stopwatch);
+ pending_task.birth_tally, pending_task.time_posted, stopwatch);
}
// The WorkerThread is non-joinable, so it deletes itself.
@@ -169,7 +159,7 @@ void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
// which will delete itself on exit.
WorkerThread* worker =
new WorkerThread(name_prefix_, this);
- PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
+ PlatformThread::CreateNonJoinable(0, worker);
}
}
diff --git a/chromium/base/threading/worker_pool_posix_unittest.cc b/chromium/base/threading/worker_pool_posix_unittest.cc
index b694155fdfd..354a99c538d 100644
--- a/chromium/base/threading/worker_pool_posix_unittest.cc
+++ b/chromium/base/threading/worker_pool_posix_unittest.cc
@@ -97,11 +97,11 @@ class PosixDynamicThreadPoolTest : public testing::Test {
num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
start_(true, false) {}
- virtual void SetUp() override {
+ void SetUp() override {
peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
}
- virtual void TearDown() override {
+ void TearDown() override {
// Wake up the idle threads so they can terminate.
if (pool_.get()) pool_->Terminate();
}
diff --git a/chromium/base/threading/worker_pool_win.cc b/chromium/base/threading/worker_pool_win.cc
index ff3cc832dc5..1b0ade5e244 100644
--- a/chromium/base/threading/worker_pool_win.cc
+++ b/chromium/base/threading/worker_pool_win.cc
@@ -6,10 +6,10 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/pending_task.h"
#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
namespace base {
@@ -25,8 +25,6 @@ DWORD CALLBACK WorkItemCallback(void* param) {
"src_file", pending_task->posted_from.file_name(),
"src_func", pending_task->posted_from.function_name());
- tracked_objects::ThreadData::PrepareForStartOfRun(pending_task->birth_tally);
-
g_worker_pool_running_on_this_thread.Get().Set(true);
tracked_objects::TaskStopwatch stopwatch;
@@ -37,9 +35,7 @@ DWORD CALLBACK WorkItemCallback(void* param) {
g_worker_pool_running_on_this_thread.Get().Set(false);
tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
- pending_task->birth_tally,
- tracked_objects::TrackedTime(pending_task->time_posted),
- stopwatch);
+ pending_task->birth_tally, pending_task->time_posted, stopwatch);
delete pending_task;
return 0;
diff --git a/chromium/base/time/clock.h b/chromium/base/time/clock.h
index be389be999d..507a850ff0a 100644
--- a/chromium/base/time/clock.h
+++ b/chromium/base/time/clock.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_CLOCK_H_
-#define BASE_CLOCK_H_
+#ifndef BASE_TIME_CLOCK_H_
+#define BASE_TIME_CLOCK_H_
#include "base/base_export.h"
#include "base/time/time.h"
@@ -37,4 +37,4 @@ class BASE_EXPORT Clock {
} // namespace base
-#endif // BASE_CLOCK_H_
+#endif // BASE_TIME_CLOCK_H_
diff --git a/chromium/base/time/default_clock.h b/chromium/base/time/default_clock.h
index 3d2e9473c18..0b8250e539b 100644
--- a/chromium/base/time/default_clock.h
+++ b/chromium/base/time/default_clock.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEFAULT_CLOCK_H_
-#define BASE_DEFAULT_CLOCK_H_
+#ifndef BASE_TIME_DEFAULT_CLOCK_H_
+#define BASE_TIME_DEFAULT_CLOCK_H_
#include "base/base_export.h"
#include "base/compiler_specific.h"
@@ -22,4 +22,4 @@ class BASE_EXPORT DefaultClock : public Clock {
} // namespace base
-#endif // BASE_DEFAULT_CLOCK_H_
+#endif // BASE_TIME_DEFAULT_CLOCK_H_
diff --git a/chromium/base/time/default_tick_clock.h b/chromium/base/time/default_tick_clock.h
index a6d6b15d02c..cb041e6124a 100644
--- a/chromium/base/time/default_tick_clock.h
+++ b/chromium/base/time/default_tick_clock.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEFAULT_TICK_CLOCK_H_
-#define BASE_DEFAULT_TICK_CLOCK_H_
+#ifndef BASE_TIME_DEFAULT_TICK_CLOCK_H_
+#define BASE_TIME_DEFAULT_TICK_CLOCK_H_
#include "base/base_export.h"
#include "base/compiler_specific.h"
@@ -22,4 +22,4 @@ class BASE_EXPORT DefaultTickClock : public TickClock {
} // namespace base
-#endif // BASE_DEFAULT_CLOCK_H_
+#endif // BASE_TIME_DEFAULT_TICK_CLOCK_H_
diff --git a/chromium/base/time/pr_time_unittest.cc b/chromium/base/time/pr_time_unittest.cc
index 2853e964802..06043a5b8eb 100644
--- a/chromium/base/time/pr_time_unittest.cc
+++ b/chromium/base/time/pr_time_unittest.cc
@@ -25,7 +25,7 @@ PRTime comparison_time_2 = INT64_C(1373275692441381); // represented as GMT
// tested by comparing them to a known time in the local zone.
class PRTimeTest : public testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
// Use mktime to get a time_t, and turn it into a PRTime by converting
// seconds to microseconds. Use 15th Oct 2007 12:45:00 local. This
// must be a time guaranteed to be outside of a DST fallback hour in
diff --git a/chromium/base/time/tick_clock.h b/chromium/base/time/tick_clock.h
index 3e53d832857..f7aba537430 100644
--- a/chromium/base/time/tick_clock.h
+++ b/chromium/base/time/tick_clock.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_TICK_CLOCK_H_
-#define BASE_TICK_CLOCK_H_
+#ifndef BASE_TIME_TICK_CLOCK_H_
+#define BASE_TIME_TICK_CLOCK_H_
#include "base/base_export.h"
#include "base/time/time.h"
@@ -17,8 +17,8 @@ namespace base {
// See DefaultTickClock (base/time/default_tick_clock.h) for the default
// implementation that simply uses TimeTicks::Now().
//
-// (Other implementations that use TimeTicks::HighResNow() or
-// TimeTicks::NowFromSystemTime() should be added as needed.)
+// (Other implementations that use TimeTicks::NowFromSystemTime() should
+// be added as needed.)
//
// See SimpleTestTickClock (base/test/simple_test_tick_clock.h) for a
// simple test implementation.
@@ -37,4 +37,4 @@ class BASE_EXPORT TickClock {
} // namespace base
-#endif // BASE_TICK_CLOCK_H_
+#endif // BASE_TIME_TICK_CLOCK_H_
diff --git a/chromium/base/time/time.cc b/chromium/base/time/time.cc
index ce9d12c0c2e..9834188597d 100644
--- a/chromium/base/time/time.cc
+++ b/chromium/base/time/time.cc
@@ -4,12 +4,12 @@
#include "base/time/time.h"
+#include <cmath>
#include <ios>
#include <limits>
#include <ostream>
#include <sstream>
-#include "base/float_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
@@ -97,6 +97,36 @@ int64 TimeDelta::InMicroseconds() const {
return delta_;
}
+namespace time_internal {
+
+int64 SaturatedAdd(TimeDelta delta, int64 value) {
+ CheckedNumeric<int64> rv(delta.delta_);
+ rv += value;
+ return FromCheckedNumeric(rv);
+}
+
+int64 SaturatedSub(TimeDelta delta, int64 value) {
+ CheckedNumeric<int64> rv(delta.delta_);
+ rv -= value;
+ return FromCheckedNumeric(rv);
+}
+
+int64 FromCheckedNumeric(const CheckedNumeric<int64> value) {
+ if (value.IsValid())
+ return value.ValueUnsafe();
+
+ // We could return max/min but we don't really expose what the maximum delta
+ // is. Instead, return max/(-max), which is something that clients can reason
+ // about.
+ // TODO(rvargas) crbug.com/332611: don't use internal values.
+ int64 limit = std::numeric_limits<int64>::max();
+ if (value.validity() == internal::RANGE_UNDERFLOW)
+ limit = -limit;
+ return value.ValueOrDefault(limit);
+}
+
+} // namespace time_internal
+
std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
return os << time_delta.InSecondsF() << "s";
}
@@ -134,7 +164,7 @@ time_t Time::ToTimeT() const {
// static
Time Time::FromDoubleT(double dt) {
- if (dt == 0 || IsNaN(dt))
+ if (dt == 0 || std::isnan(dt))
return Time(); // Preserve 0 so we can tell it doesn't exist.
if (dt == std::numeric_limits<double>::infinity())
return Max();
@@ -274,6 +304,19 @@ TimeTicks TimeTicks::UnixEpoch() {
return leaky_unix_epoch_singleton_instance.Get().unix_epoch();
}
+TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
+ TimeDelta tick_interval) const {
+ // |interval_offset| is the offset from |this| to the next multiple of
+ // |tick_interval| after |tick_phase|, possibly negative if in the past.
+ TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
+ // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
+ // Otherwise, if |tick_phase| was in the past, adjust forward to the next
+ // tick after |this|.
+ if (!interval_offset.is_zero() && tick_phase < *this)
+ interval_offset += tick_interval;
+ return *this + interval_offset;
+}
+
std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
// This function formats a TimeTicks object as "bogo-microseconds".
// The origin and granularity of the count are platform-specific, and may very
diff --git a/chromium/base/time/time.h b/chromium/base/time/time.h
index 9cb007ec222..0a267783861 100644
--- a/chromium/base/time/time.h
+++ b/chromium/base/time/time.h
@@ -33,6 +33,7 @@
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "base/numerics/safe_math.h"
#include "build/build_config.h"
#if defined(OS_MACOSX)
@@ -56,8 +57,23 @@
namespace base {
-class Time;
-class TimeTicks;
+class TimeDelta;
+
+// The functions in the time_internal namespace are meant to be used only by the
+// time classes and functions. Please use the math operators defined in the
+// time classes instead.
+namespace time_internal {
+
+// Add or subtract |value| from a TimeDelta. The int64 argument and return value
+// are in terms of a microsecond timebase.
+BASE_EXPORT int64 SaturatedAdd(TimeDelta delta, int64 value);
+BASE_EXPORT int64 SaturatedSub(TimeDelta delta, int64 value);
+
+// Clamp |value| on overflow and underflow conditions. The int64 argument and
+// return value are in terms of a microsecond timebase.
+BASE_EXPORT int64 FromCheckedNumeric(const CheckedNumeric<int64> value);
+
+} // namespace time_internal
// TimeDelta ------------------------------------------------------------------
@@ -100,6 +116,20 @@ class BASE_EXPORT TimeDelta {
return delta_;
}
+ // Returns the magnitude (absolute value) of this TimeDelta.
+ TimeDelta magnitude() const {
+ // Some toolchains provide an incomplete C++11 implementation and lack an
+ // int64 overload for std::abs(). The following is a simple branchless
+ // implementation:
+ const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1);
+ return TimeDelta((delta_ + mask) ^ mask);
+ }
+
+ // Returns true if the time delta is zero.
+ bool is_zero() const {
+ return delta_ == 0;
+ }
+
// Returns true if the time delta is the maximum time delta.
bool is_max() const {
return delta_ == std::numeric_limits<int64>::max();
@@ -131,47 +161,50 @@ class BASE_EXPORT TimeDelta {
// Computations with other deltas.
TimeDelta operator+(TimeDelta other) const {
- return TimeDelta(delta_ + other.delta_);
+ return TimeDelta(time_internal::SaturatedAdd(*this, other.delta_));
}
TimeDelta operator-(TimeDelta other) const {
- return TimeDelta(delta_ - other.delta_);
+ return TimeDelta(time_internal::SaturatedSub(*this, other.delta_));
}
TimeDelta& operator+=(TimeDelta other) {
- delta_ += other.delta_;
- return *this;
+ return *this = (*this + other);
}
TimeDelta& operator-=(TimeDelta other) {
- delta_ -= other.delta_;
- return *this;
+ return *this = (*this - other);
}
TimeDelta operator-() const {
return TimeDelta(-delta_);
}
- // Computations with ints, note that we only allow multiplicative operations
- // with ints, and additive operations with other deltas.
- TimeDelta operator*(int64 a) const {
- return TimeDelta(delta_ * a);
+ // Computations with numeric types.
+ template<typename T>
+ TimeDelta operator*(T a) const {
+ CheckedNumeric<int64> rv(delta_);
+ rv *= a;
+ return TimeDelta(time_internal::FromCheckedNumeric(rv));
}
- TimeDelta operator/(int64 a) const {
- return TimeDelta(delta_ / a);
+ template<typename T>
+ TimeDelta operator/(T a) const {
+ CheckedNumeric<int64> rv(delta_);
+ rv /= a;
+ return TimeDelta(time_internal::FromCheckedNumeric(rv));
}
- TimeDelta& operator*=(int64 a) {
- delta_ *= a;
- return *this;
+ template<typename T>
+ TimeDelta& operator*=(T a) {
+ return *this = (*this * a);
}
- TimeDelta& operator/=(int64 a) {
- delta_ /= a;
- return *this;
+ template<typename T>
+ TimeDelta& operator/=(T a) {
+ return *this = (*this / a);
}
+
int64 operator/(TimeDelta a) const {
return delta_ / a.delta_;
}
-
- // Defined below because it depends on the definition of the other classes.
- Time operator+(Time t) const;
- TimeTicks operator+(TimeTicks t) const;
+ TimeDelta operator%(TimeDelta a) const {
+ return TimeDelta(delta_ % a.delta_);
+ }
// Comparison operators.
bool operator==(TimeDelta other) const {
@@ -194,9 +227,8 @@ class BASE_EXPORT TimeDelta {
}
private:
- friend class Time;
- friend class TimeTicks;
- friend TimeDelta operator*(int64 a, TimeDelta td);
+ friend int64 time_internal::SaturatedAdd(TimeDelta delta, int64 value);
+ friend int64 time_internal::SaturatedSub(TimeDelta delta, int64 value);
// Constructs a delta given the duration in microseconds. This is private
// to avoid confusion by callers with an integer constructor. Use
@@ -208,30 +240,139 @@ class BASE_EXPORT TimeDelta {
int64 delta_;
};
-inline TimeDelta operator*(int64 a, TimeDelta td) {
- return TimeDelta(a * td.delta_);
+template<typename T>
+inline TimeDelta operator*(T a, TimeDelta td) {
+ return td * a;
}
// For logging use only.
BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeDelta time_delta);
-// Time -----------------------------------------------------------------------
+// Do not reference the time_internal::TimeBase template class directly. Please
+// use one of the time subclasses instead, and only reference the public
+// TimeBase members via those classes.
+namespace time_internal {
+
+// TimeBase--------------------------------------------------------------------
-// Represents a wall clock time in UTC.
-class BASE_EXPORT Time {
+// Provides value storage and comparison/math operations common to all time
+// classes. Each subclass provides for strong type-checking to ensure
+// semantically meaningful comparison/math of time values from the same clock
+// source or timeline.
+template<class TimeClass>
+class TimeBase {
public:
+ static const int64 kHoursPerDay = 24;
static const int64 kMillisecondsPerSecond = 1000;
+ static const int64 kMillisecondsPerDay = kMillisecondsPerSecond * 60 * 60 *
+ kHoursPerDay;
static const int64 kMicrosecondsPerMillisecond = 1000;
static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
kMillisecondsPerSecond;
static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
- static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * 24;
+ static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * kHoursPerDay;
static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
static const int64 kNanosecondsPerMicrosecond = 1000;
static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
kMicrosecondsPerSecond;
+ // Returns true if this object has not been initialized.
+ //
+ // Warning: Be careful when writing code that performs math on time values,
+ // since it's possible to produce a valid "zero" result that should not be
+ // interpreted as a "null" value.
+ bool is_null() const {
+ return us_ == 0;
+ }
+
+ // Returns true if this object represents the maximum time.
+ bool is_max() const {
+ return us_ == std::numeric_limits<int64>::max();
+ }
+
+ // For serializing only. Use FromInternalValue() to reconstitute. Please don't
+ // use this and do arithmetic on it, as it is more error prone than using the
+ // provided operators.
+ int64 ToInternalValue() const {
+ return us_;
+ }
+
+ TimeClass& operator=(TimeClass other) {
+ us_ = other.us_;
+ return *(static_cast<TimeClass*>(this));
+ }
+
+ // Compute the difference between two times.
+ TimeDelta operator-(TimeClass other) const {
+ return TimeDelta::FromMicroseconds(us_ - other.us_);
+ }
+
+ // Return a new time modified by some delta.
+ TimeClass operator+(TimeDelta delta) const {
+ return TimeClass(time_internal::SaturatedAdd(delta, us_));
+ }
+ TimeClass operator-(TimeDelta delta) const {
+ return TimeClass(-time_internal::SaturatedSub(delta, us_));
+ }
+
+ // Modify by some time delta.
+ TimeClass& operator+=(TimeDelta delta) {
+ return static_cast<TimeClass&>(*this = (*this + delta));
+ }
+ TimeClass& operator-=(TimeDelta delta) {
+ return static_cast<TimeClass&>(*this = (*this - delta));
+ }
+
+ // Comparison operators
+ bool operator==(TimeClass other) const {
+ return us_ == other.us_;
+ }
+ bool operator!=(TimeClass other) const {
+ return us_ != other.us_;
+ }
+ bool operator<(TimeClass other) const {
+ return us_ < other.us_;
+ }
+ bool operator<=(TimeClass other) const {
+ return us_ <= other.us_;
+ }
+ bool operator>(TimeClass other) const {
+ return us_ > other.us_;
+ }
+ bool operator>=(TimeClass other) const {
+ return us_ >= other.us_;
+ }
+
+ // Converts an integer value representing TimeClass to a class. This is used
+ // when deserializing a |TimeClass| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ static TimeClass FromInternalValue(int64 us) {
+ return TimeClass(us);
+ }
+
+ protected:
+ explicit TimeBase(int64 us) : us_(us) {
+ }
+
+ // Time value in a microsecond timebase.
+ int64 us_;
+};
+
+} // namespace time_internal
+
+template<class TimeClass>
+inline TimeClass operator+(TimeDelta delta, TimeClass t) {
+ return t + delta;
+}
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time in UTC. Values are not guaranteed to be
+// monotonically non-decreasing and are subject to large amounts of skew.
+class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
+ public:
// The representation of Jan 1, 1970 UTC in microseconds since the
// platform-dependent epoch.
static const int64 kTimeTToMicrosecondsOffset;
@@ -271,17 +412,7 @@ class BASE_EXPORT Time {
};
// Contains the NULL time. Use Time::Now() to get the current time.
- Time() : us_(0) {
- }
-
- // Returns true if the time object has not been initialized.
- bool is_null() const {
- return us_ == 0;
- }
-
- // Returns true if the time object is the maximum time.
- bool is_max() const {
- return us_ == std::numeric_limits<int64>::max();
+ Time() : TimeBase(0) {
}
// Returns the time for epoch in Unix-like system (Jan 1, 1970).
@@ -380,14 +511,6 @@ class BASE_EXPORT Time {
return FromExploded(true, exploded);
}
- // Converts an integer value representing Time to a class. This is used
- // when deserializing a |Time| structure, using a value known to be
- // compatible. It is not provided as a constructor because the integer type
- // may be unclear from the perspective of a caller.
- static Time FromInternalValue(int64 us) {
- return Time(us);
- }
-
// Converts a string representation of time to a Time object.
// An example of a time string which is converted is as below:-
// "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
@@ -403,13 +526,6 @@ class BASE_EXPORT Time {
return FromStringInternal(time_string, false, parsed_time);
}
- // For serializing, use FromInternalValue to reconstitute. Please don't use
- // this and do arithmetic on it, as it is more error prone than using the
- // provided operators.
- int64 ToInternalValue() const {
- return us_;
- }
-
// Fills the given exploded structure with either the local time or UTC from
// this time structure (containing UTC).
void UTCExplode(Exploded* exploded) const {
@@ -423,58 +539,10 @@ class BASE_EXPORT Time {
// midnight on that day.
Time LocalMidnight() const;
- Time& operator=(Time other) {
- us_ = other.us_;
- return *this;
- }
-
- // Compute the difference between two times.
- TimeDelta operator-(Time other) const {
- return TimeDelta(us_ - other.us_);
- }
-
- // Modify by some time delta.
- Time& operator+=(TimeDelta delta) {
- us_ += delta.delta_;
- return *this;
- }
- Time& operator-=(TimeDelta delta) {
- us_ -= delta.delta_;
- return *this;
- }
-
- // Return a new time modified by some delta.
- Time operator+(TimeDelta delta) const {
- return Time(us_ + delta.delta_);
- }
- Time operator-(TimeDelta delta) const {
- return Time(us_ - delta.delta_);
- }
-
- // Comparison operators
- bool operator==(Time other) const {
- return us_ == other.us_;
- }
- bool operator!=(Time other) const {
- return us_ != other.us_;
- }
- bool operator<(Time other) const {
- return us_ < other.us_;
- }
- bool operator<=(Time other) const {
- return us_ <= other.us_;
- }
- bool operator>(Time other) const {
- return us_ > other.us_;
- }
- bool operator>=(Time other) const {
- return us_ >= other.us_;
- }
-
private:
- friend class TimeDelta;
+ friend class time_internal::TimeBase<Time>;
- explicit Time(int64 us) : us_(us) {
+ explicit Time(int64 us) : TimeBase(us) {
}
// Explodes the given time to either local time |is_local = true| or UTC
@@ -495,9 +563,6 @@ class BASE_EXPORT Time {
static bool FromStringInternal(const char* time_string,
bool is_local,
Time* parsed_time);
-
- // Time in microseconds in UTC.
- int64 us_;
};
// Inline the TimeDelta factory methods, for fast TimeDelta construction.
@@ -566,16 +631,13 @@ inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
return TimeDelta(us);
}
-inline Time TimeDelta::operator+(Time t) const {
- return Time(t.us_ + delta_);
-}
-
// For logging use only.
BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time);
// TimeTicks ------------------------------------------------------------------
-class BASE_EXPORT TimeTicks {
+// Represents monotonically non-decreasing clock time.
+class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
public:
// We define this even without OS_CHROMEOS for seccomp sandbox testing.
#if defined(OS_LINUX)
@@ -585,21 +647,20 @@ class BASE_EXPORT TimeTicks {
static const clockid_t kClockSystemTrace = 11;
#endif
- TimeTicks() : ticks_(0) {
+ TimeTicks() : TimeBase(0) {
}
- // Platform-dependent tick count representing "right now."
- // The resolution of this clock is ~1-15ms. Resolution varies depending
- // on hardware/operating system configuration.
+ // Platform-dependent tick count representing "right now." When
+ // IsHighResolution() returns false, the resolution of the clock could be
+ // as coarse as ~15.6ms. Otherwise, the resolution should be no worse than one
+ // microsecond.
static TimeTicks Now();
- // Returns a platform-dependent high-resolution tick count. Implementation
- // is hardware dependent and may or may not return sub-millisecond
- // resolution. THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND
- // SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
- static TimeTicks HighResNow();
-
- static bool IsHighResNowFastAndReliable();
+ // Returns true if the high resolution clock is working on this system and
+ // Now() will return high resolution values. Note that, on systems where the
+ // high resolution clock works but is deemed inefficient, the low resolution
+ // clock will be used instead.
+ static bool IsHighResolution();
// Returns true if ThreadNow() is supported on this system.
static bool IsThreadNowSupported() {
@@ -616,42 +677,35 @@ class BASE_EXPORT TimeTicks {
// to (approximately) measure how much time the calling thread spent doing
// actual work vs. being de-scheduled. May return bogus results if the thread
// migrates to another CPU between two calls.
+ //
+ // WARNING: The returned value might NOT have the same origin as Now(). Do not
+ // perform math between TimeTicks values returned by Now() and ThreadNow() and
+ // expect meaningful results.
+ // TODO(miu): Since the timeline of these values is different, the values
+ // should be of a different type.
static TimeTicks ThreadNow();
- // Returns the current system trace time or, if none is defined, the current
- // high-res time (i.e. HighResNow()). On systems where a global trace clock
- // is defined, timestamping TraceEvents's with this value guarantees
- // synchronization between events collected inside chrome and events
- // collected outside (e.g. kernel, X server).
+ // Returns the current system trace time or, if not available on this
+ // platform, a high-resolution time value; or a low-resolution time value if
+ // neither are avalable. On systems where a global trace clock is defined,
+ // timestamping TraceEvents's with this value guarantees synchronization
+ // between events collected inside chrome and events collected outside
+ // (e.g. kernel, X server).
+ //
+ // WARNING: The returned value might NOT have the same origin as Now(). Do not
+ // perform math between TimeTicks values returned by Now() and
+ // NowFromSystemTraceTime() and expect meaningful results.
+ // TODO(miu): Since the timeline of these values is different, the values
+ // should be of a different type.
static TimeTicks NowFromSystemTraceTime();
#if defined(OS_WIN)
- // Get the absolute value of QPC time drift. For testing.
- static int64 GetQPCDriftMicroseconds();
-
+ // Translates an absolute QPC timestamp into a TimeTicks value. The returned
+ // value has the same origin as Now(). Do NOT attempt to use this if
+ // IsHighResolution() returns false.
static TimeTicks FromQPCValue(LONGLONG qpc_value);
-
- // Returns true if the high resolution clock is working on this system.
- // This is only for testing.
- static bool IsHighResClockWorking();
-
- // Returns a time value that is NOT rollover protected.
- static TimeTicks UnprotectedNow();
#endif
- // Returns true if this object has not been initialized.
- bool is_null() const {
- return ticks_ == 0;
- }
-
- // Converts an integer value representing TimeTicks to a class. This is used
- // when deserializing a |TimeTicks| structure, using a value known to be
- // compatible. It is not provided as a constructor because the integer type
- // may be unclear from the perspective of a caller.
- static TimeTicks FromInternalValue(int64 ticks) {
- return TimeTicks(ticks);
- }
-
// Get the TimeTick value at the time of the UnixEpoch. This is useful when
// you need to relate the value of TimeTicks to a real time and date.
// Note: Upon first invocation, this function takes a snapshot of the realtime
@@ -660,80 +714,26 @@ class BASE_EXPORT TimeTicks {
// application runs.
static TimeTicks UnixEpoch();
- // Returns the internal numeric value of the TimeTicks object.
- // For serializing, use FromInternalValue to reconstitute.
- int64 ToInternalValue() const {
- return ticks_;
- }
-
- TimeTicks& operator=(TimeTicks other) {
- ticks_ = other.ticks_;
- return *this;
- }
-
- // Compute the difference between two times.
- TimeDelta operator-(TimeTicks other) const {
- return TimeDelta(ticks_ - other.ticks_);
- }
-
- // Modify by some time delta.
- TimeTicks& operator+=(TimeDelta delta) {
- ticks_ += delta.delta_;
- return *this;
- }
- TimeTicks& operator-=(TimeDelta delta) {
- ticks_ -= delta.delta_;
- return *this;
- }
-
- // Return a new TimeTicks modified by some delta.
- TimeTicks operator+(TimeDelta delta) const {
- return TimeTicks(ticks_ + delta.delta_);
- }
- TimeTicks operator-(TimeDelta delta) const {
- return TimeTicks(ticks_ - delta.delta_);
- }
-
- // Comparison operators
- bool operator==(TimeTicks other) const {
- return ticks_ == other.ticks_;
- }
- bool operator!=(TimeTicks other) const {
- return ticks_ != other.ticks_;
- }
- bool operator<(TimeTicks other) const {
- return ticks_ < other.ticks_;
- }
- bool operator<=(TimeTicks other) const {
- return ticks_ <= other.ticks_;
- }
- bool operator>(TimeTicks other) const {
- return ticks_ > other.ticks_;
- }
- bool operator>=(TimeTicks other) const {
- return ticks_ >= other.ticks_;
- }
-
- protected:
- friend class TimeDelta;
-
- // Please use Now() to create a new object. This is for internal use
- // and testing. Ticks is in microseconds.
- explicit TimeTicks(int64 ticks) : ticks_(ticks) {
- }
-
- // Tick count in microseconds.
- int64 ticks_;
+ // Returns |this| snapped to the next tick, given a |tick_phase| and
+ // repeating |tick_interval| in both directions. |this| may be before,
+ // after, or equal to the |tick_phase|.
+ TimeTicks SnappedToNextTick(TimeTicks tick_phase,
+ TimeDelta tick_interval) const;
#if defined(OS_WIN)
+ protected:
typedef DWORD (*TickFunctionType)(void);
static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
#endif
-};
-inline TimeTicks TimeDelta::operator+(TimeTicks t) const {
- return TimeTicks(t.ticks_ + delta_);
-}
+ private:
+ friend class time_internal::TimeBase<TimeTicks>;
+
+ // Please use Now() to create a new object. This is for internal use
+ // and testing.
+ explicit TimeTicks(int64 us) : TimeBase(us) {
+ }
+};
// For logging use only.
BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks);
diff --git a/chromium/base/time/time_mac.cc b/chromium/base/time/time_mac.cc
index 26c5d7a715b..e263d079459 100644
--- a/chromium/base/time/time_mac.cc
+++ b/chromium/base/time/time_mac.cc
@@ -219,12 +219,7 @@ TimeTicks TimeTicks::Now() {
}
// static
-TimeTicks TimeTicks::HighResNow() {
- return Now();
-}
-
-// static
-bool TimeTicks::IsHighResNowFastAndReliable() {
+bool TimeTicks::IsHighResolution() {
return true;
}
@@ -235,7 +230,7 @@ TimeTicks TimeTicks::ThreadNow() {
// static
TimeTicks TimeTicks::NowFromSystemTraceTime() {
- return HighResNow();
+ return Now();
}
} // namespace base
diff --git a/chromium/base/time/time_posix.cc b/chromium/base/time/time_posix.cc
index ad00c513685..8b207eb36a9 100644
--- a/chromium/base/time/time_posix.cc
+++ b/chromium/base/time/time_posix.cc
@@ -314,12 +314,7 @@ TimeTicks TimeTicks::Now() {
}
// static
-TimeTicks TimeTicks::HighResNow() {
- return Now();
-}
-
-// static
-bool TimeTicks::IsHighResNowFastAndReliable() {
+bool TimeTicks::IsHighResolution() {
return true;
}
@@ -343,7 +338,7 @@ TimeTicks TimeTicks::NowFromSystemTraceTime() {
struct timespec ts;
if (clock_gettime(kClockSystemTrace, &ts) != 0) {
// NB: fall-back for a chrome os build running on linux
- return HighResNow();
+ return Now();
}
absolute_micro =
@@ -357,7 +352,7 @@ TimeTicks TimeTicks::NowFromSystemTraceTime() {
// static
TimeTicks TimeTicks::NowFromSystemTraceTime() {
- return HighResNow();
+ return Now();
}
#endif // defined(OS_CHROMEOS)
diff --git a/chromium/base/time/time_unittest.cc b/chromium/base/time/time_unittest.cc
index ef80e438593..456782c6452 100644
--- a/chromium/base/time/time_unittest.cc
+++ b/chromium/base/time/time_unittest.cc
@@ -6,6 +6,7 @@
#include <time.h>
+#include <limits>
#include <string>
#include "base/compiler_specific.h"
@@ -24,7 +25,7 @@ namespace {
// See also pr_time_unittests.cc
class TimeTest : public testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
// Use mktime to get a time_t, and turn it into a PRTime by converting
// seconds to microseconds. Use 15th Oct 2007 12:45:00 local. This
// must be a time guaranteed to be outside of a DST fallback hour in
@@ -642,12 +643,10 @@ TEST(TimeTicks, Deltas) {
}
static void HighResClockTest(TimeTicks (*GetTicks)()) {
-#if defined(OS_WIN)
- // HighResNow doesn't work on some systems. Since the product still works
- // even if it doesn't work, it makes this entire test questionable.
- if (!TimeTicks::IsHighResClockWorking())
+ // IsHighResolution() is false on some systems. Since the product still works
+ // even if it's false, it makes this entire test questionable.
+ if (!TimeTicks::IsHighResolution())
return;
-#endif
// Why do we loop here?
// We're trying to measure that intervals increment in a VERY small amount
@@ -680,8 +679,8 @@ static void HighResClockTest(TimeTicks (*GetTicks)()) {
EXPECT_TRUE(success);
}
-TEST(TimeTicks, HighResNow) {
- HighResClockTest(&TimeTicks::HighResNow);
+TEST(TimeTicks, HighRes) {
+ HighResClockTest(&TimeTicks::Now);
}
// Fails frequently on Android http://crbug.com/352633 with:
@@ -712,10 +711,66 @@ TEST(TimeTicks, MAYBE_ThreadNow) {
}
TEST(TimeTicks, NowFromSystemTraceTime) {
- // Re-use HighResNow test for now since clock properties are identical.
+ // Re-use HighRes test for now since clock properties are identical.
HighResClockTest(&TimeTicks::NowFromSystemTraceTime);
}
+TEST(TimeTicks, SnappedToNextTickBasic) {
+ base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000);
+ base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000);
+ base::TimeTicks timestamp;
+
+ // Timestamp in previous interval.
+ timestamp = base::TimeTicks::FromInternalValue(3500);
+ EXPECT_EQ(4000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+ // Timestamp in next interval.
+ timestamp = base::TimeTicks::FromInternalValue(4500);
+ EXPECT_EQ(5000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+ // Timestamp multiple intervals before.
+ timestamp = base::TimeTicks::FromInternalValue(2500);
+ EXPECT_EQ(3000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+ // Timestamp multiple intervals after.
+ timestamp = base::TimeTicks::FromInternalValue(6500);
+ EXPECT_EQ(7000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+ // Timestamp on previous interval.
+ timestamp = base::TimeTicks::FromInternalValue(3000);
+ EXPECT_EQ(3000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+ // Timestamp on next interval.
+ timestamp = base::TimeTicks::FromInternalValue(5000);
+ EXPECT_EQ(5000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+ // Timestamp equal to phase.
+ timestamp = base::TimeTicks::FromInternalValue(4000);
+ EXPECT_EQ(4000,
+ timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+}
+
+TEST(TimeTicks, SnappedToNextTickOverflow) {
+ // int(big_timestamp / interval) < 0, so this causes a crash if the number of
+ // intervals elapsed is attempted to be stored in an int.
+ base::TimeTicks phase = base::TimeTicks::FromInternalValue(0);
+ base::TimeDelta interval = base::TimeDelta::FromMicroseconds(4000);
+ base::TimeTicks big_timestamp =
+ base::TimeTicks::FromInternalValue(8635916564000);
+
+ EXPECT_EQ(8635916564000,
+ big_timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+ EXPECT_EQ(8635916564000,
+ big_timestamp.SnappedToNextTick(big_timestamp, interval)
+ .ToInternalValue());
+}
+
TEST(TimeDelta, FromAndIn) {
EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
@@ -792,6 +847,172 @@ std::string AnyToString(Any any) {
return oss.str();
}
+TEST(TimeDelta, Magnitude) {
+ const int64 zero = 0;
+ EXPECT_EQ(TimeDelta::FromMicroseconds(zero),
+ TimeDelta::FromMicroseconds(zero).magnitude());
+
+ const int64 one = 1;
+ const int64 negative_one = -1;
+ EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+ TimeDelta::FromMicroseconds(one).magnitude());
+ EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+ TimeDelta::FromMicroseconds(negative_one).magnitude());
+
+ const int64 max_int64_minus_one = std::numeric_limits<int64>::max() - 1;
+ const int64 min_int64_plus_two = std::numeric_limits<int64>::min() + 2;
+ EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
+ TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude());
+ EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
+ TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
+}
+
+
+TEST(TimeDelta, NumericOperators) {
+ double d = 0.5;
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) * d);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) / d);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) *= d);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) /= d);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ d * TimeDelta::FromMilliseconds(1000));
+
+ float f = 0.5;
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) * f);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) / f);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) *= f);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) /= f);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ f * TimeDelta::FromMilliseconds(1000));
+
+
+ int i = 2;
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) * i);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) / i);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) *= i);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) /= i);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ i * TimeDelta::FromMilliseconds(1000));
+
+ int64_t i64 = 2;
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) * i64);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) / i64);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) *= i64);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) /= i64);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ i64 * TimeDelta::FromMilliseconds(1000));
+
+
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) * 0.5);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) / 0.5);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) *= 0.5);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) /= 0.5);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ 0.5 * TimeDelta::FromMilliseconds(1000));
+
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) * 2);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) / 2);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000) *= 2);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000) /= 2);
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ 2 * TimeDelta::FromMilliseconds(1000));
+}
+
+bool IsMin(TimeDelta delta) {
+ return (-delta).is_max();
+}
+
+TEST(TimeDelta, Overflows) {
+ // Some sanity checks.
+ EXPECT_TRUE(TimeDelta::Max().is_max());
+ EXPECT_TRUE(IsMin(-TimeDelta::Max()));
+ EXPECT_GT(TimeDelta(), -TimeDelta::Max());
+
+ TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1);
+ TimeDelta large_negative = -large_delta;
+ EXPECT_GT(TimeDelta(), large_negative);
+ EXPECT_FALSE(large_delta.is_max());
+ EXPECT_FALSE(IsMin(-large_negative));
+ TimeDelta one_second = TimeDelta::FromSeconds(1);
+
+ // Test +, -, * and / operators.
+ EXPECT_TRUE((large_delta + one_second).is_max());
+ EXPECT_TRUE(IsMin(large_negative + (-one_second)));
+ EXPECT_TRUE(IsMin(large_negative - one_second));
+ EXPECT_TRUE((large_delta - (-one_second)).is_max());
+ EXPECT_TRUE((large_delta * 2).is_max());
+ EXPECT_TRUE(IsMin(large_delta * -2));
+ EXPECT_TRUE((large_delta / 0.5).is_max());
+ EXPECT_TRUE(IsMin(large_delta / -0.5));
+
+ // Test +=, -=, *= and /= operators.
+ TimeDelta delta = large_delta;
+ delta += one_second;
+ EXPECT_TRUE(delta.is_max());
+ delta = large_negative;
+ delta += -one_second;
+ EXPECT_TRUE(IsMin(delta));
+
+ delta = large_negative;
+ delta -= one_second;
+ EXPECT_TRUE(IsMin(delta));
+ delta = large_delta;
+ delta -= -one_second;
+ EXPECT_TRUE(delta.is_max());
+
+ delta = large_delta;
+ delta *= 2;
+ EXPECT_TRUE(delta.is_max());
+ delta = large_negative;
+ delta *= 1.5;
+ EXPECT_TRUE(IsMin(delta));
+
+ delta = large_delta;
+ delta /= 0.5;
+ EXPECT_TRUE(delta.is_max());
+ delta = large_negative;
+ delta /= 0.5;
+ EXPECT_TRUE(IsMin(delta));
+
+ // Test operations with Time and TimeTicks.
+ EXPECT_TRUE((large_delta + Time::Now()).is_max());
+ EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max());
+ EXPECT_TRUE((Time::Now() + large_delta).is_max());
+ EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max());
+
+ Time time_now = Time::Now();
+ EXPECT_EQ(one_second, (time_now + one_second) - time_now);
+ EXPECT_EQ(-one_second, (time_now - one_second) - time_now);
+
+ TimeTicks ticks_now = TimeTicks::Now();
+ EXPECT_EQ(-one_second, (ticks_now - one_second) - ticks_now);
+ EXPECT_EQ(one_second, (ticks_now + one_second) - ticks_now);
+}
+
TEST(TimeDeltaLogging, DCheckEqCompiles) {
DCHECK_EQ(TimeDelta(), TimeDelta());
}
diff --git a/chromium/base/time/time_win.cc b/chromium/base/time/time_win.cc
index 006118091fc..d2403f21b7f 100644
--- a/chromium/base/time/time_win.cc
+++ b/chromium/base/time/time_win.cc
@@ -203,12 +203,12 @@ bool Time::ActivateHighResolutionTimer(bool activating) {
UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
: kMinTimerIntervalLowResMs;
if (activating) {
- DCHECK(g_high_res_timer_count != max);
+ DCHECK_NE(g_high_res_timer_count, max);
++g_high_res_timer_count;
if (g_high_res_timer_count == 1)
timeBeginPeriod(period);
} else {
- DCHECK(g_high_res_timer_count != 0);
+ DCHECK_NE(g_high_res_timer_count, 0u);
--g_high_res_timer_count;
if (g_high_res_timer_count == 0)
timeEndPeriod(period);
@@ -307,13 +307,13 @@ DWORD timeGetTimeWrapper() {
return timeGetTime();
}
-DWORD (*tick_function)(void) = &timeGetTimeWrapper;
+DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
// Accumulation of time lost due to rollover (in milliseconds).
-int64 rollover_ms = 0;
+int64 g_rollover_ms = 0;
// The last timeGetTime value we saw, to detect rollover.
-DWORD last_seen_now = 0;
+DWORD g_last_seen_now = 0;
// Lock protecting rollover_ms and last_seen_now.
// Note: this is a global object, and we usually avoid these. However, the time
@@ -321,169 +321,161 @@ DWORD last_seen_now = 0;
// easy to use a Singleton without even knowing it, and that may lead to many
// gotchas). Its impact on startup time should be negligible due to low-level
// nature of time code.
-base::Lock rollover_lock;
+base::Lock g_rollover_lock;
// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
// because it returns the number of milliseconds since Windows has started,
// which will roll over the 32-bit value every ~49 days. We try to track
// rollover ourselves, which works if TimeTicks::Now() is called at least every
// 49 days.
-TimeDelta RolloverProtectedNow() {
- base::AutoLock locked(rollover_lock);
+TimeTicks RolloverProtectedNow() {
+ base::AutoLock locked(g_rollover_lock);
// We should hold the lock while calling tick_function to make sure that
// we keep last_seen_now stay correctly in sync.
- DWORD now = tick_function();
- if (now < last_seen_now)
- rollover_ms += 0x100000000I64; // ~49.7 days.
- last_seen_now = now;
- return TimeDelta::FromMilliseconds(now + rollover_ms);
+ DWORD now = g_tick_function();
+ if (now < g_last_seen_now)
+ g_rollover_ms += 0x100000000I64; // ~49.7 days.
+ g_last_seen_now = now;
+ return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms);
}
-bool IsBuggyAthlon(const base::CPU& cpu) {
- // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
- // unreliable. Fallback to low-res clock.
- return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
-}
-
-// Overview of time counters:
+// Discussion of tick counter options on Windows:
+//
// (1) CPU cycle counter. (Retrieved via RDTSC)
// The CPU counter provides the highest resolution time stamp and is the least
-// expensive to retrieve. However, the CPU counter is unreliable and should not
-// be used in production. Its biggest issue is that it is per processor and it
-// is not synchronized between processors. Also, on some computers, the counters
-// will change frequency due to thermal and power changes, and stop in some
-// states.
+// expensive to retrieve. However, on older CPUs, two issues can affect its
+// reliability: First it is maintained per processor and not synchronized
+// between processors. Also, the counters will change frequency due to thermal
+// and power changes, and stop in some states.
//
// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
-// resolution (100 nanoseconds) time stamp but is comparatively more expensive
-// to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
-// (with some help from ACPI).
-// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
-// in the worst case, it gets the counter from the rollover interrupt on the
+// resolution (<1 microsecond) time stamp. On most hardware running today, it
+// auto-detects and uses the constant-rate RDTSC counter to provide extremely
+// efficient and reliable time stamps.
+//
+// On older CPUs where RDTSC is unreliable, it falls back to using more
+// expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI
+// PM timer, and can involve system calls; and all this is up to the HAL (with
+// some help from ACPI). According to
+// http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the
+// worst case, it gets the counter from the rollover interrupt on the
// programmable interrupt timer. In best cases, the HAL may conclude that the
// RDTSC counter runs at a constant frequency, then it uses that instead. On
// multiprocessor machines, it will try to verify the values returned from
// RDTSC on each processor are consistent with each other, and apply a handful
// of workarounds for known buggy hardware. In other words, QPC is supposed to
-// give consistent result on a multiprocessor computer, but it is unreliable in
-// reality due to bugs in BIOS or HAL on some, especially old computers.
-// With recent updates on HAL and newer BIOS, QPC is getting more reliable but
-// it should be used with caution.
+// give consistent results on a multiprocessor computer, but for older CPUs it
+// can be unreliable due bugs in BIOS or HAL.
//
-// (3) System time. The system time provides a low-resolution (typically 10ms
-// to 55 milliseconds) time stamp but is comparatively less expensive to
-// retrieve and more reliable.
-class HighResNowSingleton {
- public:
- HighResNowSingleton()
- : ticks_per_second_(0),
- skew_(0) {
-
- base::CPU cpu;
- if (IsBuggyAthlon(cpu))
- return;
-
- // Synchronize the QPC clock with GetSystemTimeAsFileTime.
- LARGE_INTEGER ticks_per_sec = {0};
- if (!QueryPerformanceFrequency(&ticks_per_sec))
- return; // QPC is not available.
- ticks_per_second_ = ticks_per_sec.QuadPart;
-
- skew_ = UnreliableNow() - ReliableNow();
+// (3) System time. The system time provides a low-resolution (from ~1 to ~15.6
+// milliseconds) time stamp but is comparatively less expensive to retrieve and
+// more reliable. Time::EnableHighResolutionTimer() and
+// Time::ActivateHighResolutionTimer() can be called to alter the resolution of
+// this timer; and also other Windows applications can alter it, affecting this
+// one.
+
+using NowFunction = TimeTicks (*)(void);
+
+TimeTicks InitialNowFunction();
+TimeTicks InitialSystemTraceNowFunction();
+
+// See "threading notes" in InitializeNowFunctionPointers() for details on how
+// concurrent reads/writes to these globals has been made safe.
+NowFunction g_now_function = &InitialNowFunction;
+NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction;
+int64 g_qpc_ticks_per_second = 0;
+
+// As of January 2015, use of <atomic> is forbidden in Chromium code. This is
+// what std::atomic_thread_fence does on Windows on all Intel architectures when
+// the memory_order argument is anything but std::memory_order_seq_cst:
+#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
+
+TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
+ // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
+ // InitializeNowFunctionPointers(), has happened by this point.
+ ATOMIC_THREAD_FENCE(memory_order_acquire);
+
+ DCHECK_GT(g_qpc_ticks_per_second, 0);
+
+ // If the QPC Value is below the overflow threshold, we proceed with
+ // simple multiply and divide.
+ if (qpc_value < Time::kQPCOverflowThreshold) {
+ return TimeDelta::FromMicroseconds(
+ qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
}
+ // Otherwise, calculate microseconds in a round about manner to avoid
+ // overflow and precision issues.
+ int64 whole_seconds = qpc_value / g_qpc_ticks_per_second;
+ int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
+ return TimeDelta::FromMicroseconds(
+ (whole_seconds * Time::kMicrosecondsPerSecond) +
+ ((leftover_ticks * Time::kMicrosecondsPerSecond) /
+ g_qpc_ticks_per_second));
+}
- bool IsUsingHighResClock() {
- return ticks_per_second_ != 0;
- }
-
- TimeDelta Now() {
- if (IsUsingHighResClock())
- return TimeDelta::FromMicroseconds(UnreliableNow());
-
- // Just fallback to the slower clock.
- return RolloverProtectedNow();
- }
-
- int64 GetQPCDriftMicroseconds() {
- if (!IsUsingHighResClock())
- return 0;
- return abs((UnreliableNow() - ReliableNow()) - skew_);
- }
-
- int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
- if (!ticks_per_second_)
- return 0;
- // If the QPC Value is below the overflow threshold, we proceed with
- // simple multiply and divide.
- if (qpc_value < Time::kQPCOverflowThreshold)
- return qpc_value * Time::kMicrosecondsPerSecond / ticks_per_second_;
- // Otherwise, calculate microseconds in a round about manner to avoid
- // overflow and precision issues.
- int64 whole_seconds = qpc_value / ticks_per_second_;
- int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_);
- int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
- ((leftover_ticks * Time::kMicrosecondsPerSecond) /
- ticks_per_second_);
- return microseconds;
- }
-
- private:
- // Get the number of microseconds since boot in an unreliable fashion.
- int64 UnreliableNow() {
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- return QPCValueToMicroseconds(now.QuadPart);
- }
-
- // Get the number of microseconds since boot in a reliable fashion.
- int64 ReliableNow() {
- return RolloverProtectedNow().InMicroseconds();
- }
-
- int64 ticks_per_second_; // 0 indicates QPF failed and we're broken.
- int64 skew_; // Skew between lo-res and hi-res clocks (for debugging).
-};
-
-static base::LazyInstance<HighResNowSingleton>::Leaky
- leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER;
-
-HighResNowSingleton* GetHighResNowSingleton() {
- return leaky_high_res_now_singleton.Pointer();
+TimeTicks QPCNow() {
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ return TimeTicks() + QPCValueToTimeDelta(now.QuadPart);
}
-TimeDelta HighResNowWrapper() {
- return GetHighResNowSingleton()->Now();
+bool IsBuggyAthlon(const base::CPU& cpu) {
+ // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
+ return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
}
-typedef TimeDelta (*NowFunction)(void);
+void InitializeNowFunctionPointers() {
+ LARGE_INTEGER ticks_per_sec = {0};
+ if (!QueryPerformanceFrequency(&ticks_per_sec))
+ ticks_per_sec.QuadPart = 0;
-bool CPUReliablySupportsHighResTime() {
+ // If Windows cannot provide a QPC implementation, both Now() and
+ // NowFromSystemTraceTime() must use the low-resolution clock.
+ //
+ // If the QPC implementation is expensive and/or unreliable, Now() will use
+ // the low-resolution clock, but NowFromSystemTraceTime() will use the QPC (in
+ // the hope that it is still useful for tracing purposes). A CPU lacking a
+ // non-stop time counter will cause Windows to provide an alternate QPC
+ // implementation that works, but is expensive to use. Certain Athlon CPUs are
+ // known to make the QPC implementation unreliable.
+ //
+ // Otherwise, both Now functions can use the high-resolution QPC clock. As of
+ // 4 January 2015, ~68% of users fall within this category.
+ NowFunction now_function;
+ NowFunction system_trace_now_function;
base::CPU cpu;
- if (!cpu.has_non_stop_time_stamp_counter() ||
- !GetHighResNowSingleton()->IsUsingHighResClock())
- return false;
-
- if (IsBuggyAthlon(cpu))
- return false;
+ if (ticks_per_sec.QuadPart <= 0) {
+ now_function = system_trace_now_function = &RolloverProtectedNow;
+ } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
+ now_function = &RolloverProtectedNow;
+ system_trace_now_function = &QPCNow;
+ } else {
+ now_function = system_trace_now_function = &QPCNow;
+ }
- return true;
+ // Threading note 1: In an unlikely race condition, it's possible for two or
+ // more threads to enter InitializeNowFunctionPointers() in parallel. This is
+ // not a problem since all threads should end up writing out the same values
+ // to the global variables.
+ //
+ // Threading note 2: A release fence is placed here to ensure, from the
+ // perspective of other threads using the function pointers, that the
+ // assignment to |g_qpc_ticks_per_second| happens before the function pointers
+ // are changed.
+ g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
+ ATOMIC_THREAD_FENCE(memory_order_release);
+ g_now_function = now_function;
+ g_system_trace_now_function = system_trace_now_function;
}
-TimeDelta InitialNowFunction();
-
-volatile NowFunction now_function = InitialNowFunction;
+TimeTicks InitialNowFunction() {
+ InitializeNowFunctionPointers();
+ return g_now_function();
+}
-TimeDelta InitialNowFunction() {
- if (!CPUReliablySupportsHighResTime()) {
- InterlockedExchangePointer(
- reinterpret_cast<void* volatile*>(&now_function),
- &RolloverProtectedNow);
- return RolloverProtectedNow();
- }
- InterlockedExchangePointer(
- reinterpret_cast<void* volatile*>(&now_function),
- &HighResNowWrapper);
- return HighResNowWrapper();
+TimeTicks InitialSystemTraceNowFunction() {
+ InitializeNowFunctionPointers();
+ return g_system_trace_now_function();
}
} // namespace
@@ -491,27 +483,24 @@ TimeDelta InitialNowFunction() {
// static
TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
TickFunctionType ticker) {
- base::AutoLock locked(rollover_lock);
- TickFunctionType old = tick_function;
- tick_function = ticker;
- rollover_ms = 0;
- last_seen_now = 0;
+ base::AutoLock locked(g_rollover_lock);
+ TickFunctionType old = g_tick_function;
+ g_tick_function = ticker;
+ g_rollover_ms = 0;
+ g_last_seen_now = 0;
return old;
}
// static
TimeTicks TimeTicks::Now() {
- return TimeTicks() + now_function();
+ return g_now_function();
}
// static
-TimeTicks TimeTicks::HighResNow() {
- return TimeTicks() + HighResNowWrapper();
-}
-
-// static
-bool TimeTicks::IsHighResNowFastAndReliable() {
- return CPUReliablySupportsHighResTime();
+bool TimeTicks::IsHighResolution() {
+ if (g_now_function == &InitialNowFunction)
+ InitializeNowFunctionPointers();
+ return g_now_function == &QPCNow;
}
// static
@@ -522,35 +511,17 @@ TimeTicks TimeTicks::ThreadNow() {
// static
TimeTicks TimeTicks::NowFromSystemTraceTime() {
- return HighResNow();
-}
-
-// static
-int64 TimeTicks::GetQPCDriftMicroseconds() {
- return GetHighResNowSingleton()->GetQPCDriftMicroseconds();
+ return g_system_trace_now_function();
}
// static
TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
- return TimeTicks(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
-}
-
-// static
-bool TimeTicks::IsHighResClockWorking() {
- return GetHighResNowSingleton()->IsUsingHighResClock();
-}
-
-TimeTicks TimeTicks::UnprotectedNow() {
- if (now_function == HighResNowWrapper) {
- return Now();
- } else {
- return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime());
- }
+ return TimeTicks() + QPCValueToTimeDelta(qpc_value);
}
// TimeDelta ------------------------------------------------------------------
// static
TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
- return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
+ return QPCValueToTimeDelta(qpc_value);
}
diff --git a/chromium/base/time/time_win_unittest.cc b/chromium/base/time/time_win_unittest.cc
index 058dfd79d14..82be8c5254d 100644
--- a/chromium/base/time/time_win_unittest.cc
+++ b/chromium/base/time/time_win_unittest.cc
@@ -6,6 +6,10 @@
#include <mmsystem.h>
#include <process.h>
+#include <cmath>
+#include <limits>
+#include <vector>
+
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -112,9 +116,9 @@ TEST(TimeTicks, WinRollover) {
}
TEST(TimeTicks, SubMillisecondTimers) {
- // HighResNow doesn't work on some systems. Since the product still works
- // even if it doesn't work, it makes this entire test questionable.
- if (!TimeTicks::IsHighResClockWorking())
+ // IsHighResolution() is false on some systems. Since the product still works
+ // even if it's false, it makes this entire test questionable.
+ if (!TimeTicks::IsHighResolution())
return;
const int kRetries = 1000;
@@ -122,11 +126,11 @@ TEST(TimeTicks, SubMillisecondTimers) {
// Run kRetries attempts to see a sub-millisecond timer.
for (int index = 0; index < kRetries; index++) {
- TimeTicks last_time = TimeTicks::HighResNow();
+ TimeTicks last_time = TimeTicks::Now();
TimeDelta delta;
// Spin until the clock has detected a change.
do {
- delta = TimeTicks::HighResNow() - last_time;
+ delta = TimeTicks::Now() - last_time;
} while (delta.InMicroseconds() == 0);
if (delta.InMicroseconds() < 1000) {
saw_submillisecond_timer = true;
@@ -183,16 +187,16 @@ TEST(TimeTicks, TimerPerformance) {
TestCase cases[] = {
{ reinterpret_cast<TestFunc>(Time::Now), "Time::Now" },
{ TimeTicks::Now, "TimeTicks::Now" },
- { TimeTicks::HighResNow, "TimeTicks::HighResNow" },
+ { TimeTicks::NowFromSystemTraceTime, "TimeTicks::NowFromSystemTraceTime" },
{ NULL, "" }
};
int test_case = 0;
while (cases[test_case].func) {
- TimeTicks start = TimeTicks::HighResNow();
+ TimeTicks start = TimeTicks::Now();
for (int index = 0; index < kLoops; index++)
cases[test_case].func();
- TimeTicks stop = TimeTicks::HighResNow();
+ TimeTicks stop = TimeTicks::Now();
// Turning off the check for acceptible delays. Without this check,
// the test really doesn't do much other than measure. But the
// measurements are still useful for testing timers on various platforms.
@@ -207,65 +211,57 @@ TEST(TimeTicks, TimerPerformance) {
}
}
-// http://crbug.com/396384
-TEST(TimeTicks, DISABLED_Drift) {
- // If QPC is disabled, this isn't measuring anything.
- if (!TimeTicks::IsHighResClockWorking())
- return;
-
- const int kIterations = 100;
- int64 total_drift = 0;
-
- for (int i = 0; i < kIterations; ++i) {
- int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds();
-
- // Make sure the drift never exceeds our limit.
- EXPECT_LT(drift_microseconds, 50000);
-
- // Sleep for a few milliseconds (note that it means 1000 microseconds).
- // If we check the drift too frequently, it's going to increase
- // monotonically, making our measurement less realistic.
- base::PlatformThread::Sleep(
- base::TimeDelta::FromMilliseconds((i % 2 == 0) ? 1 : 2));
-
- total_drift += drift_microseconds;
- }
-
- // Sanity check. We expect some time drift to occur, especially across
- // the number of iterations we do.
- EXPECT_LT(0, total_drift);
-
- printf("average time drift in microseconds: %lld\n",
- total_drift / kIterations);
-}
-
-int64 QPCValueToMicrosecondsSafely(LONGLONG qpc_value,
- int64 ticks_per_second) {
- int64 whole_seconds = qpc_value / ticks_per_second;
- int64 leftover_ticks = qpc_value % ticks_per_second;
- int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
- ((leftover_ticks * Time::kMicrosecondsPerSecond) /
- ticks_per_second);
- return microseconds;
-}
-
TEST(TimeTicks, FromQPCValue) {
- if (!TimeTicks::IsHighResClockWorking())
+ if (!TimeTicks::IsHighResolution())
return;
+
LARGE_INTEGER frequency;
- QueryPerformanceFrequency(&frequency);
- int64 ticks_per_second = frequency.QuadPart;
- LONGLONG qpc_value = Time::kQPCOverflowThreshold;
- TimeTicks expected_value = TimeTicks::FromInternalValue(
- QPCValueToMicrosecondsSafely(qpc_value + 1, ticks_per_second));
- EXPECT_EQ(expected_value,
- TimeTicks::FromQPCValue(qpc_value + 1));
- expected_value = TimeTicks::FromInternalValue(
- QPCValueToMicrosecondsSafely(qpc_value, ticks_per_second));
- EXPECT_EQ(expected_value,
- TimeTicks::FromQPCValue(qpc_value));
- expected_value = TimeTicks::FromInternalValue(
- QPCValueToMicrosecondsSafely(qpc_value - 1, ticks_per_second));
- EXPECT_EQ(expected_value,
- TimeTicks::FromQPCValue(qpc_value - 1));
+ ASSERT_TRUE(QueryPerformanceFrequency(&frequency));
+ const int64 ticks_per_second = frequency.QuadPart;
+ ASSERT_GT(ticks_per_second, 0);
+
+ // Generate the tick values to convert, advancing the tick count by varying
+ // amounts. These values will ensure that both the fast and overflow-safe
+ // conversion logic in FromQPCValue() is tested, and across the entire range
+ // of possible QPC tick values.
+ std::vector<int64> test_cases;
+ test_cases.push_back(0);
+ const int kNumAdvancements = 100;
+ int64 ticks = 0;
+ int64 ticks_increment = 10;
+ for (int i = 0; i < kNumAdvancements; ++i) {
+ test_cases.push_back(ticks);
+ ticks += ticks_increment;
+ ticks_increment = ticks_increment * 6 / 5;
+ }
+ test_cases.push_back(Time::kQPCOverflowThreshold - 1);
+ test_cases.push_back(Time::kQPCOverflowThreshold);
+ test_cases.push_back(Time::kQPCOverflowThreshold + 1);
+ ticks = Time::kQPCOverflowThreshold + 10;
+ ticks_increment = 10;
+ for (int i = 0; i < kNumAdvancements; ++i) {
+ test_cases.push_back(ticks);
+ ticks += ticks_increment;
+ ticks_increment = ticks_increment * 6 / 5;
+ }
+ test_cases.push_back(std::numeric_limits<int64>::max());
+
+ // Test that the conversions using FromQPCValue() match those computed here
+ // using simple floating-point arithmetic. The floating-point math provides
+ // enough precision to confirm the implementation is correct to the
+ // microsecond for all |test_cases| (though it would be insufficient to
+ // confirm many "very large" tick values which are not being tested here).
+ for (int64 ticks : test_cases) {
+ const double expected_microseconds_since_origin =
+ (static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) /
+ ticks_per_second;
+ const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks);
+ const double converted_microseconds_since_origin =
+ static_cast<double>((converted_value - TimeTicks()).InMicroseconds());
+ EXPECT_NEAR(expected_microseconds_since_origin,
+ converted_microseconds_since_origin,
+ 1.0)
+ << "ticks=" << ticks << ", to be converted via logic path: "
+ << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE");
+ }
}
diff --git a/chromium/base/timer/elapsed_timer.h b/chromium/base/timer/elapsed_timer.h
index 1cb9f1193d8..592858a6e50 100644
--- a/chromium/base/timer/elapsed_timer.h
+++ b/chromium/base/timer/elapsed_timer.h
@@ -6,7 +6,7 @@
#define BASE_TIMER_ELAPSED_TIMER_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/time/time.h"
namespace base {
@@ -15,10 +15,9 @@ namespace base {
class BASE_EXPORT ElapsedTimer {
public:
ElapsedTimer();
- virtual ~ElapsedTimer() {}
// Returns the time elapsed since object construction.
- virtual TimeDelta Elapsed() const;
+ TimeDelta Elapsed() const;
private:
TimeTicks begin_;
diff --git a/chromium/base/timer/mock_timer.h b/chromium/base/timer/mock_timer.h
index b07c9c06337..e18a5c0489b 100644
--- a/chromium/base/timer/mock_timer.h
+++ b/chromium/base/timer/mock_timer.h
@@ -38,4 +38,4 @@ class BASE_EXPORT MockTimer : public Timer {
} // namespace base
-#endif // !BASE_TIMER_MOCK_TIMER_H_
+#endif // BASE_TIMER_MOCK_TIMER_H_
diff --git a/chromium/base/timer/timer.cc b/chromium/base/timer/timer.cc
index 11f73ca4290..fa6b8cd2724 100644
--- a/chromium/base/timer/timer.cc
+++ b/chromium/base/timer/timer.cc
@@ -163,8 +163,10 @@ void Timer::PostNewScheduledTask(TimeDelta delay) {
}
// Remember the thread ID that posts the first task -- this will be verified
// later when the task is abandoned to detect misuse from multiple threads.
- if (!thread_id_)
+ if (!thread_id_) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
thread_id_ = static_cast<int>(PlatformThread::CurrentId());
+ }
}
scoped_refptr<SingleThreadTaskRunner> Timer::GetTaskRunner() {
diff --git a/chromium/base/timer/timer.h b/chromium/base/timer/timer.h
index 7e2c1d41f13..1ef58a3ea0b 100644
--- a/chromium/base/timer/timer.h
+++ b/chromium/base/timer/timer.h
@@ -89,7 +89,8 @@ class BASE_EXPORT Timer {
virtual TimeDelta GetCurrentDelay() const;
// Set the task runner on which the task should be scheduled. This method can
- // only be called before any tasks have been scheduled.
+ // only be called before any tasks have been scheduled. The task runner must
+ // run tasks on the same thread the timer is used on.
virtual void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
// Start the timer to run at the given |delay| from now. If the timer is
@@ -259,7 +260,7 @@ class DelayTimer : protected Timer {
base::Bind(method, base::Unretained(receiver)),
false) {}
- void Reset() { Timer::Reset(); }
+ void Reset() override { Timer::Reset(); }
};
} // namespace base
diff --git a/chromium/base/timer/timer_unittest.cc b/chromium/base/timer/timer_unittest.cc
index 1cbccd1626d..7213b809b7b 100644
--- a/chromium/base/timer/timer_unittest.cc
+++ b/chromium/base/timer/timer_unittest.cc
@@ -189,10 +189,6 @@ void RunTest_RepeatingTimer_Cancel(base::MessageLoop::Type message_loop_type,
class DelayTimerTarget {
public:
- DelayTimerTarget()
- : signaled_(false) {
- }
-
bool signaled() const { return signaled_; }
void Signal() {
@@ -201,7 +197,7 @@ class DelayTimerTarget {
}
private:
- bool signaled_;
+ bool signaled_ = false;
};
void RunTest_DelayTimer_NoCall(base::MessageLoop::Type message_loop_type) {
diff --git a/chromium/base/trace_event/BUILD.gn b/chromium/base/trace_event/BUILD.gn
new file mode 100644
index 00000000000..633ab90ca7c
--- /dev/null
+++ b/chromium/base/trace_event/BUILD.gn
@@ -0,0 +1,107 @@
+# Copyright 2015 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.
+
+source_set("trace_event") {
+ sources = [
+ "java_heap_dump_provider_android.cc",
+ "java_heap_dump_provider_android.h",
+ "memory_allocator_dump.cc",
+ "memory_allocator_dump.h",
+ "memory_dump_manager.cc",
+ "memory_dump_manager.h",
+ "memory_dump_provider.h",
+ "memory_dump_request_args.h",
+ "memory_dump_session_state.cc",
+ "memory_dump_session_state.h",
+ "process_memory_dump.cc",
+ "process_memory_dump.h",
+ "process_memory_maps.cc",
+ "process_memory_maps.h",
+ "process_memory_maps_dump_provider.cc",
+ "process_memory_maps_dump_provider.h",
+ "process_memory_totals.cc",
+ "process_memory_totals.h",
+ "process_memory_totals_dump_provider.cc",
+ "process_memory_totals_dump_provider.h",
+ "trace_event.h",
+ "trace_event_android.cc",
+ "trace_event_argument.cc",
+ "trace_event_argument.h",
+ "trace_event_etw_export_win.cc",
+ "trace_event_etw_export_win.h",
+ "trace_event_impl.cc",
+ "trace_event_impl.h",
+ "trace_event_impl_constants.cc",
+ "trace_event_memory.cc",
+ "trace_event_memory.h",
+ "trace_event_synthetic_delay.cc",
+ "trace_event_synthetic_delay.h",
+ "trace_event_system_stats_monitor.cc",
+ "trace_event_system_stats_monitor.h",
+ "trace_event_win.cc",
+ "trace_event_win.h",
+ "winheap_dump_provider_win.cc",
+ "winheap_dump_provider_win.h",
+ ]
+
+ if (is_nacl) {
+ sources -= [
+ "process_memory_totals_dump_provider.cc",
+ "trace_event_system_stats_monitor.cc",
+ ]
+ }
+
+ if (is_linux || is_android) {
+ sources += [
+ "malloc_dump_provider.cc",
+ "malloc_dump_provider.h",
+ ]
+ }
+
+ configs += [ "//base:base_implementation" ]
+
+ deps = [
+ "//base/debug",
+ "//base/json",
+ "//base/memory",
+ "//base/process",
+ "//base/third_party/dynamic_annotations",
+ ]
+
+ if (is_win) {
+ deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
+ }
+
+ allow_circular_includes_from = [
+ "//base/debug",
+ "//base/memory",
+ "//base/process",
+ ]
+
+ visibility = [ "//base/*" ]
+}
+
+source_set("trace_event_unittests") {
+ testonly = true
+ sources = [
+ "java_heap_dump_provider_android_unittest.cc",
+ "memory_allocator_dump_unittest.cc",
+ "memory_dump_manager_unittest.cc",
+ "process_memory_maps_dump_provider_unittest.cc",
+ "process_memory_totals_dump_provider_unittest.cc",
+ "trace_event_argument_unittest.cc",
+ "trace_event_memory_unittest.cc",
+ "trace_event_synthetic_delay_unittest.cc",
+ "trace_event_system_stats_monitor_unittest.cc",
+ "trace_event_unittest.cc",
+ "trace_event_win_unittest.cc",
+ "winheap_dump_provider_win_unittest.cc",
+ ]
+
+ deps = [
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/base/trace_event/OWNERS b/chromium/base/trace_event/OWNERS
new file mode 100644
index 00000000000..aa1d675f75a
--- /dev/null
+++ b/chromium/base/trace_event/OWNERS
@@ -0,0 +1,4 @@
+nduca@chromium.org
+dsinclair@chromium.org
+primiano@chromium.org
+per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/chromium/base/trace_event/etw_manifest/BUILD.gn b/chromium/base/trace_event/etw_manifest/BUILD.gn
new file mode 100644
index 00000000000..f62e356b118
--- /dev/null
+++ b/chromium/base/trace_event/etw_manifest/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2015 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.
+
+assert(is_win, "This only runs on Windows.")
+
+# Makes the .h/.rc files from the .man file.
+action("chrome_events_win_generate") {
+ visibility = [ ":*" ]
+ script = "build/message_compiler.py"
+
+ sources = [
+ "chrome_events_win.man",
+ ]
+
+ outputs = [
+ "$target_gen_dir/chrome_events_win.h",
+ "$target_gen_dir/chrome_events_win.rc",
+ ]
+
+ args = [
+ # Where to put the header.
+ "-h",
+ rebase_path("$target_gen_dir", root_build_dir),
+
+ # Where to put the .rc file.
+ "-r",
+ rebase_path("$target_gen_dir", root_build_dir),
+
+ # Generate the user-mode code.
+ "-um",
+ rebase_path("chrome_events_win.man", root_build_dir),
+ ]
+}
+
+# Compile the generated files.
+source_set("chrome_events_win") {
+ visibility = [
+ "//base/trace_event/*",
+ "//chrome:main_dll",
+ ]
+
+ sources = get_target_outputs(":chrome_events_win_generate")
+
+ deps = [
+ ":chrome_events_win_generate",
+ ]
+}
diff --git a/chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py b/chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py
new file mode 100644
index 00000000000..be5927d9bec
--- /dev/null
+++ b/chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py
@@ -0,0 +1,16 @@
+# Copyright 2015 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.
+
+# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
+# GN build, which can only run Python and not native binaries.
+
+import subprocess
+import sys
+
+# mc writes to stderr, so this explicily redirects to stdout and eats it.
+try:
+ subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT)
+except subprocess.CalledProcessError as e:
+ print e.output
+ sys.exit(e.returncode)
diff --git a/chromium/base/trace_event/etw_manifest/chrome_events_win.man b/chromium/base/trace_event/etw_manifest/chrome_events_win.man
new file mode 100644
index 00000000000..10a8ddf16f6
--- /dev/null
+++ b/chromium/base/trace_event/etw_manifest/chrome_events_win.man
@@ -0,0 +1,84 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<instrumentationManifest
+ xmlns="http://schemas.microsoft.com/win/2004/08/events"
+ xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
+ >
+ <instrumentation>
+ <events>
+ <provider
+ guid="{D2D578D9-2936-45B6-A09f-30E32715F42D}"
+ messageFileName="chrome.dll"
+ name="Chrome"
+ resourceFileName="chrome.dll"
+ symbol="CHROME"
+ >
+ <channels>
+ <importChannel
+ chid="SYSTEM"
+ name="System"
+ />
+ </channels>
+ <templates>
+ <template tid="tid_chrome_event">
+ <data
+ inType="win:AnsiString"
+ name="Name"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Phase"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Arg Name 1"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Arg Value 1"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Arg Name 2"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Arg Value 2"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Arg Name 3"
+ />
+ <data
+ inType="win:AnsiString"
+ name="Arg Value 3"
+ />
+ </template>
+ </templates>
+ <events>
+ <event
+ channel="SYSTEM"
+ level="win:Informational"
+ message="$(string.ChromeEvent.EventMessage)"
+ opcode="win:Info"
+ symbol="ChromeEvent"
+ template="tid_chrome_event"
+ value="1"
+ />
+ </events>
+ </provider>
+ </events>
+ </instrumentation>
+ <localization xmlns="http://schemas.microsoft.com/win/2004/08/events">
+ <resources culture="en-US">
+ <stringTable>
+ <string
+ id="ChromeEvent.EventMessage"
+ value="Chrome Event: %1 (%2)"
+ />
+ </stringTable>
+ </resources>
+ </localization>
+</instrumentationManifest>
diff --git a/chromium/base/trace_event/etw_manifest/etw_manifest.gyp b/chromium/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 00000000000..b2f0eb8ea11
--- /dev/null
+++ b/chromium/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -0,0 +1,41 @@
+# Copyright 2015 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.
+{
+ 'targets': [
+ {
+ # GN version: //base/trace_event/etw_manifest/BUILD.gn
+ 'target_name': 'etw_manifest',
+ 'type': 'none',
+ 'toolsets': ['host', 'target'],
+ 'hard_dependency': 1,
+ 'conditions': [
+ ['OS=="win"', {
+ 'sources': [
+ 'chrome_events_win.man',
+ ],
+ 'variables': {
+ 'man_output_dir': '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest',
+ },
+ 'rules': [{
+ # Rule to run the message compiler.
+ 'rule_name': 'message_compiler',
+ 'extension': 'man',
+ 'outputs': [
+ '<(man_output_dir)/chrome_events_win.h',
+ '<(man_output_dir)/chrome_events_win.rc',
+ ],
+ 'action': [
+ 'mc.exe',
+ '-h', '<(man_output_dir)',
+ '-r', '<(man_output_dir)/.',
+ '-um',
+ '<(RULE_INPUT_PATH)',
+ ],
+ 'message': 'Running message compiler on <(RULE_INPUT_PATH)',
+ }],
+ }],
+ ],
+ }
+ ]
+}
diff --git a/chromium/base/trace_event/java_heap_dump_provider_android.cc b/chromium/base/trace_event/java_heap_dump_provider_android.cc
new file mode 100644
index 00000000000..2a84b81b8db
--- /dev/null
+++ b/chromium/base/trace_event/java_heap_dump_provider_android.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/android/java_runtime.h"
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+JavaHeapDumpProvider* JavaHeapDumpProvider::GetInstance() {
+ return Singleton<JavaHeapDumpProvider,
+ LeakySingletonTraits<JavaHeapDumpProvider>>::get();
+}
+
+JavaHeapDumpProvider::JavaHeapDumpProvider() {
+}
+
+JavaHeapDumpProvider::~JavaHeapDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot with the memory counters
+// for the current process.
+bool JavaHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+ MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("java_heap");
+
+ // These numbers come from java.lang.Runtime stats.
+ long total_heap_size = 0;
+ long free_heap_size = 0;
+ android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, total_heap_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes,
+ total_heap_size - free_heap_size);
+ return true;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/java_heap_dump_provider_android.h b/chromium/base/trace_event/java_heap_dump_provider_android.h
new file mode 100644
index 00000000000..2f31047b50b
--- /dev/null
+++ b/chromium/base/trace_event/java_heap_dump_provider_android.h
@@ -0,0 +1,34 @@
+// Copyright 2015 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_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+#define BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT JavaHeapDumpProvider : public MemoryDumpProvider {
+ public:
+ static JavaHeapDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
+
+ JavaHeapDumpProvider();
+ ~JavaHeapDumpProvider() override;
+
+ DISALLOW_COPY_AND_ASSIGN(JavaHeapDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
diff --git a/chromium/base/trace_event/java_heap_dump_provider_android_unittest.cc b/chromium/base/trace_event/java_heap_dump_provider_android_unittest.cc
new file mode 100644
index 00000000000..bbefba518d0
--- /dev/null
+++ b/chromium/base/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
+ auto jhdp = JavaHeapDumpProvider::GetInstance();
+ scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+
+ jhdp->OnMemoryDump(pmd.get());
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/malloc_dump_provider.cc b/chromium/base/trace_event/malloc_dump_provider.cc
new file mode 100644
index 00000000000..c04b8588c27
--- /dev/null
+++ b/chromium/base/trace_event/malloc_dump_provider.cc
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/malloc_dump_provider.h"
+
+#include <malloc.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+MallocDumpProvider* MallocDumpProvider::GetInstance() {
+ return Singleton<MallocDumpProvider,
+ LeakySingletonTraits<MallocDumpProvider>>::get();
+}
+
+MallocDumpProvider::MallocDumpProvider() {
+}
+
+MallocDumpProvider::~MallocDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool MallocDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+ struct mallinfo info = mallinfo();
+ DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
+
+ MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("malloc");
+ if (!dump)
+ return false;
+
+ // When the system allocator is implemented by tcmalloc, the total physical
+ // size is given by |arena| and |hblkhd| is 0. In case of Android's jemalloc
+ // |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
+ // dlmalloc the total is given by |arena| + |hblkhd|.
+ // For more details see link: http://goo.gl/fMR8lF.
+ dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, info.arena + info.hblkhd);
+
+ // Total allocated space is given by |uordblks|.
+ dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, info.uordblks);
+
+ return true;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/malloc_dump_provider.h b/chromium/base/trace_event/malloc_dump_provider.h
new file mode 100644
index 00000000000..ec8683a2e20
--- /dev/null
+++ b/chromium/base/trace_event/malloc_dump_provider.h
@@ -0,0 +1,36 @@
+// Copyright 2015 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_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
+ public:
+ static MallocDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<MallocDumpProvider>;
+
+ MallocDumpProvider();
+ ~MallocDumpProvider() override;
+
+ DISALLOW_COPY_AND_ASSIGN(MallocDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
diff --git a/chromium/base/trace_event/memory_allocator_dump.cc b/chromium/base/trace_event/memory_allocator_dump.cc
new file mode 100644
index 00000000000..edec31b1fdb
--- /dev/null
+++ b/chromium/base/trace_event/memory_allocator_dump.cc
@@ -0,0 +1,119 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+// Returns the c-string pointer from a dictionary value without performing extra
+// std::string copies. The ptr will be valid as long as the value exists.
+bool GetDictionaryValueAsCStr(const DictionaryValue* dict_value,
+ const std::string& key,
+ const char** out_cstr) {
+ const Value* value = nullptr;
+ const StringValue* str_value = nullptr;
+ if (!dict_value->GetWithoutPathExpansion(key, &value))
+ return false;
+ if (!value->GetAsString(&str_value))
+ return false;
+ *out_cstr = str_value->GetString().c_str();
+ return true;
+}
+} // namespace
+
+const char MemoryAllocatorDump::kNameOuterSize[] = "outer_size";
+const char MemoryAllocatorDump::kNameInnerSize[] = "inner_size";
+const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
+const char MemoryAllocatorDump::kTypeString[] = "string";
+const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
+const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
+ ProcessMemoryDump* process_memory_dump)
+ : absolute_name_(absolute_name), process_memory_dump_(process_memory_dump) {
+ // The |absolute_name| cannot be empty.
+ DCHECK(!absolute_name.empty());
+
+ // The |absolute_name| can contain slash separator, but not leading or
+ // trailing ones.
+ DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
+
+ // Dots are not allowed anywhere as the underlying base::DictionaryValue
+ // would treat them magically and split in sub-nodes, which is not intended.
+ DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
+}
+
+MemoryAllocatorDump::~MemoryAllocatorDump() {
+}
+
+void MemoryAllocatorDump::Add(const std::string& name,
+ const char* type,
+ const char* units,
+ scoped_ptr<Value> value) {
+ scoped_ptr<DictionaryValue> attribute(new DictionaryValue());
+ DCHECK(!attributes_.HasKey(name));
+ attribute->SetStringWithoutPathExpansion("type", type);
+ attribute->SetStringWithoutPathExpansion("units", units);
+ attribute->SetWithoutPathExpansion("value", value.Pass());
+ attributes_.SetWithoutPathExpansion(name, attribute.Pass());
+}
+
+bool MemoryAllocatorDump::Get(const std::string& name,
+ const char** out_type,
+ const char** out_units,
+ const Value** out_value) const {
+ const DictionaryValue* attribute = nullptr;
+ if (!attributes_.GetDictionaryWithoutPathExpansion(name, &attribute))
+ return false;
+
+ if (!GetDictionaryValueAsCStr(attribute, "type", out_type))
+ return false;
+
+ if (!GetDictionaryValueAsCStr(attribute, "units", out_units))
+ return false;
+
+ if (!attribute->GetWithoutPathExpansion("value", out_value))
+ return false;
+
+ return true;
+}
+
+void MemoryAllocatorDump::AddScalar(const std::string& name,
+ const char* units,
+ uint64 value) {
+ scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
+ Add(name, kTypeScalar, units, hex_value.Pass());
+}
+
+void MemoryAllocatorDump::AddString(const std::string& name,
+ const char* units,
+ const std::string& value) {
+ scoped_ptr<Value> str_value(new StringValue(value));
+ Add(name, kTypeString, units, str_value.Pass());
+}
+
+void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
+ value->BeginDictionary(absolute_name_.c_str());
+ value->BeginDictionary("attrs");
+
+ for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
+ value->SetValue(it.key().c_str(), it.value().CreateDeepCopy());
+
+ value->EndDictionary(); // "attrs": { ... }
+ value->EndDictionary(); // "allocator_name/heap_subheap": { ... }
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/memory_allocator_dump.h b/chromium/base/trace_event/memory_allocator_dump.h
new file mode 100644
index 00000000000..1bb27f952e1
--- /dev/null
+++ b/chromium/base/trace_event/memory_allocator_dump.h
@@ -0,0 +1,82 @@
+// Copyright 2015 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_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpManager;
+class ProcessMemoryDump;
+class TracedValue;
+
+// Data model for user-land memory allocator dumps.
+class BASE_EXPORT MemoryAllocatorDump {
+ public:
+ // MemoryAllocatorDump is owned by ProcessMemoryDump.
+ MemoryAllocatorDump(const std::string& absolute_name,
+ ProcessMemoryDump* process_memory_dump);
+ ~MemoryAllocatorDump();
+
+ // Standard attribute name to model total space requested by the allocator
+ // (e.g., amount of pages requested to the system).
+ static const char kNameOuterSize[];
+
+ // Standard attribute name to model space for allocated objects, without
+ // taking into account allocator metadata or fragmentation.
+ static const char kNameInnerSize[];
+
+ // Standard attribute name to model the number of objects allocated.
+ static const char kNameObjectsCount[];
+
+ static const char kTypeScalar[]; // Type name for scalar attributes.
+ static const char kTypeString[]; // Type name for string attributes.
+ static const char kUnitsBytes[]; // Unit name to represent bytes.
+ static const char kUnitsObjects[]; // Unit name to represent #objects.
+
+ // Absolute name, unique within the scope of an entire ProcessMemoryDump.
+ const std::string& absolute_name() const { return absolute_name_; }
+
+ // Generic attribute setter / getter.
+ void Add(const std::string& name,
+ const char* type,
+ const char* units,
+ scoped_ptr<Value> value);
+ bool Get(const std::string& name,
+ const char** out_type,
+ const char** out_units,
+ const Value** out_value) const;
+
+ // Helper setter for scalar attributes.
+ void AddScalar(const std::string& name, const char* units, uint64 value);
+ void AddString(const std::string& name,
+ const char* units,
+ const std::string& value);
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ // Get the ProcessMemoryDump instance that owns this.
+ ProcessMemoryDump* process_memory_dump() const {
+ return process_memory_dump_;
+ }
+
+ private:
+ const std::string absolute_name_;
+ ProcessMemoryDump* const process_memory_dump_; // Not owned (PMD owns this).
+ DictionaryValue attributes_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
diff --git a/chromium/base/trace_event/memory_allocator_dump_unittest.cc b/chromium/base/trace_event/memory_allocator_dump_unittest.cc
new file mode 100644
index 00000000000..0b2cbdf513d
--- /dev/null
+++ b/chromium/base/trace_event/memory_allocator_dump_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
+ public:
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+ MemoryAllocatorDump* root_heap =
+ pmd->CreateAllocatorDump("foobar_allocator");
+
+ root_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, 4096);
+ root_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, 1000);
+ root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kUnitsObjects, 42);
+ root_heap->AddScalar("attr1", "units1", 1234);
+ root_heap->AddString("attr2", "units2", "string_value");
+
+ MemoryAllocatorDump* sub_heap =
+ pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, 1);
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, 2);
+ sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kUnitsObjects, 3);
+
+ pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
+ // Leave the rest of sub heap deliberately uninitialized, to check that
+ // CreateAllocatorDump returns a properly zero-initialized object.
+
+ return true;
+ }
+};
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+ const std::string& name,
+ const char* expected_type,
+ const char* expected_units,
+ const std::string& expected_value) {
+ const char* attr_type;
+ const char* attr_units;
+ const Value* attr_value;
+ std::string attr_str_value;
+ bool res = dump->Get(name, &attr_type, &attr_units, &attr_value);
+ EXPECT_TRUE(res);
+ if (!res)
+ return;
+ EXPECT_EQ(expected_type, std::string(attr_type));
+ EXPECT_EQ(expected_units, std::string(attr_units));
+ EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
+ EXPECT_EQ(expected_value, attr_str_value);
+}
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+ const std::string& name,
+ const char* expected_type,
+ const char* expected_units,
+ uint64 expected_value) {
+ CheckAttribute(dump, name, expected_type, expected_units,
+ StringPrintf("%" PRIx64, expected_value));
+}
+} // namespace
+
+TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
+ FakeMemoryAllocatorDumpProvider fmadp;
+ ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+ fmadp.OnMemoryDump(&pmd);
+
+ ASSERT_EQ(3u, pmd.allocator_dumps().size());
+
+ const MemoryAllocatorDump* root_heap =
+ pmd.GetAllocatorDump("foobar_allocator");
+ ASSERT_NE(nullptr, root_heap);
+ EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
+ CheckAttribute(root_heap, MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 4096);
+ CheckAttribute(root_heap, MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 1000);
+ CheckAttribute(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsObjects, 42);
+ CheckAttribute(root_heap, "attr1", MemoryAllocatorDump::kTypeScalar, "units1",
+ 1234);
+ CheckAttribute(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
+ "string_value");
+
+ const MemoryAllocatorDump* sub_heap =
+ pmd.GetAllocatorDump("foobar_allocator/sub_heap");
+ ASSERT_NE(nullptr, sub_heap);
+ EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
+ CheckAttribute(sub_heap, MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 1);
+ CheckAttribute(sub_heap, MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsBytes, 2);
+ CheckAttribute(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kTypeScalar,
+ MemoryAllocatorDump::kUnitsObjects, 3);
+
+ const MemoryAllocatorDump* empty_sub_heap =
+ pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
+ ASSERT_NE(nullptr, empty_sub_heap);
+ EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
+ ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameOuterSize, nullptr,
+ nullptr, nullptr));
+ ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameInnerSize, nullptr,
+ nullptr, nullptr));
+ ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameObjectsCount,
+ nullptr, nullptr, nullptr));
+
+ // Check that the AsValueInfo doesn't hit any DCHECK.
+ scoped_refptr<TracedValue> traced_value(new TracedValue());
+ pmd.AsValueInto(traced_value.get());
+}
+
+// DEATH tests are not supported in Android / iOS.
+#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
+TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
+ FakeMemoryAllocatorDumpProvider fmadp;
+ ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+ pmd.CreateAllocatorDump("foo_allocator");
+ pmd.CreateAllocatorDump("bar_allocator/heap");
+ ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
+ ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
+ ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
+}
+#endif
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/memory_dump_manager.cc b/chromium/base/trace_event/memory_dump_manager.cc
new file mode 100644
index 00000000000..1e4d8229aef
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_manager.cc
@@ -0,0 +1,405 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+
+#include <algorithm>
+
+#include "base/atomic_sequence_num.h"
+#include "base/compiler_specific.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if !defined(OS_NACL)
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include "base/trace_event/malloc_dump_provider.h"
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/trace_event/java_heap_dump_provider_android.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/trace_event/winheap_dump_provider_win.h"
+#endif
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// TODO(primiano): this should be smarter and should do something similar to
+// trace event synthetic delays.
+const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
+MemoryDumpManager* g_instance_for_testing = nullptr;
+const int kDumpIntervalSeconds = 2;
+const int kTraceEventNumArgs = 1;
+const char* kTraceEventArgNames[] = {"dumps"};
+const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+StaticAtomicSequenceNumber g_next_guid;
+
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+ switch (dump_type) {
+ case MemoryDumpType::TASK_BEGIN:
+ return "TASK_BEGIN";
+ case MemoryDumpType::TASK_END:
+ return "TASK_END";
+ case MemoryDumpType::PERIODIC_INTERVAL:
+ return "PERIODIC_INTERVAL";
+ case MemoryDumpType::EXPLICITLY_TRIGGERED:
+ return "EXPLICITLY_TRIGGERED";
+ }
+ NOTREACHED();
+ return "UNKNOWN";
+}
+
+// Internal class used to hold details about ProcessMemoryDump requests for the
+// current process.
+// TODO(primiano): In the upcoming CLs, ProcessMemoryDump will become async.
+// and this class will be used to convey more details across PostTask()s.
+class ProcessMemoryDumpHolder
+ : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
+ public:
+ ProcessMemoryDumpHolder(
+ MemoryDumpRequestArgs req_args,
+ const scoped_refptr<MemoryDumpSessionState>& session_state,
+ MemoryDumpCallback callback)
+ : process_memory_dump(session_state),
+ req_args(req_args),
+ callback(callback),
+ task_runner(MessageLoop::current()->task_runner()),
+ num_pending_async_requests(0) {}
+
+ ProcessMemoryDump process_memory_dump;
+ const MemoryDumpRequestArgs req_args;
+
+ // Callback passed to the initial call to CreateProcessDump().
+ MemoryDumpCallback callback;
+
+ // Thread on which FinalizeDumpAndAddToTrace() should be called, which is the
+ // same that invoked the initial CreateProcessDump().
+ const scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+ // Number of pending ContinueAsyncProcessDump() calls.
+ int num_pending_async_requests;
+
+ private:
+ friend class RefCountedThreadSafe<ProcessMemoryDumpHolder>;
+ virtual ~ProcessMemoryDumpHolder() {}
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpHolder);
+};
+
+void FinalizeDumpAndAddToTrace(
+ const scoped_refptr<ProcessMemoryDumpHolder>& pmd_holder) {
+ DCHECK_EQ(0, pmd_holder->num_pending_async_requests);
+
+ if (!pmd_holder->task_runner->BelongsToCurrentThread()) {
+ pmd_holder->task_runner->PostTask(
+ FROM_HERE, Bind(&FinalizeDumpAndAddToTrace, pmd_holder));
+ return;
+ }
+
+ scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
+ pmd_holder->process_memory_dump.AsValueInto(
+ static_cast<TracedValue*>(event_value.get()));
+ const char* const event_name =
+ MemoryDumpTypeToString(pmd_holder->req_args.dump_type);
+
+ TRACE_EVENT_API_ADD_TRACE_EVENT(
+ TRACE_EVENT_PHASE_MEMORY_DUMP,
+ TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+ pmd_holder->req_args.dump_guid, kTraceEventNumArgs, kTraceEventArgNames,
+ kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+ TRACE_EVENT_FLAG_HAS_ID);
+
+ if (!pmd_holder->callback.is_null()) {
+ pmd_holder->callback.Run(pmd_holder->req_args.dump_guid, true);
+ pmd_holder->callback.Reset();
+ }
+}
+
+void RequestPeriodicGlobalDump() {
+ MemoryDumpManager::GetInstance()->RequestGlobalDump(
+ MemoryDumpType::PERIODIC_INTERVAL);
+}
+
+} // namespace
+
+// static
+const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
+
+// static
+MemoryDumpManager* MemoryDumpManager::GetInstance() {
+ if (g_instance_for_testing)
+ return g_instance_for_testing;
+
+ return Singleton<MemoryDumpManager,
+ LeakySingletonTraits<MemoryDumpManager>>::get();
+}
+
+// static
+void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
+ if (instance)
+ instance->skip_core_dumpers_auto_registration_for_testing_ = true;
+ g_instance_for_testing = instance;
+}
+
+MemoryDumpManager::MemoryDumpManager()
+ : delegate_(nullptr),
+ memory_tracing_enabled_(0),
+ skip_core_dumpers_auto_registration_for_testing_(false) {
+ g_next_guid.GetNext(); // Make sure that first guid is not zero.
+}
+
+MemoryDumpManager::~MemoryDumpManager() {
+ base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void MemoryDumpManager::Initialize() {
+ TRACE_EVENT0(kTraceCategory, "init"); // Add to trace-viewer category list.
+ trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+
+ if (skip_core_dumpers_auto_registration_for_testing_)
+ return;
+
+ // Enable the core dump providers.
+#if !defined(OS_NACL)
+ RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
+ RegisterDumpProvider(MallocDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_ANDROID)
+ RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_WIN)
+ RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+#endif
+}
+
+void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
+ AutoLock lock(lock_);
+ DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
+ delegate_ = delegate;
+}
+
+void MemoryDumpManager::RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ MemoryDumpProviderInfo mdp_info(task_runner);
+ AutoLock lock(lock_);
+ dump_providers_.insert(std::make_pair(mdp, mdp_info));
+}
+
+void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+ RegisterDumpProvider(mdp, nullptr);
+}
+
+void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+ AutoLock lock(lock_);
+
+ auto it = dump_providers_.find(mdp);
+ if (it == dump_providers_.end())
+ return;
+
+ const MemoryDumpProviderInfo& mdp_info = it->second;
+ // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
+ // only if the MDP has specified a thread affinity (via task_runner()) AND
+ // the unregistration happens on the same thread (so the MDP cannot unregister
+ // and OnMemoryDump() at the same time).
+ // Otherwise, it is not possible to guarantee that its unregistration is
+ // race-free. If you hit this DCHECK, your MDP has a bug.
+ DCHECK_IMPLIES(
+ subtle::NoBarrier_Load(&memory_tracing_enabled_),
+ mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
+ << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
+ << " Please file a crbug.";
+
+ // Remove from the enabled providers list. This is to deal with the case that
+ // UnregisterDumpProvider is called while the trace is enabled.
+ dump_providers_.erase(it);
+}
+
+void MemoryDumpManager::RequestGlobalDump(
+ MemoryDumpType dump_type,
+ const MemoryDumpCallback& callback) {
+ // Bail out immediately if tracing is not enabled at all.
+ if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
+ return;
+
+ const uint64 guid =
+ TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
+
+ // The delegate_ is supposed to be thread safe, immutable and long lived.
+ // No need to keep the lock after we ensure that a delegate has been set.
+ MemoryDumpManagerDelegate* delegate;
+ {
+ AutoLock lock(lock_);
+ delegate = delegate_;
+ }
+
+ if (delegate) {
+ // The delegate is in charge to coordinate the request among all the
+ // processes and call the CreateLocalDumpPoint on the local process.
+ MemoryDumpRequestArgs args = {guid, dump_type};
+ delegate->RequestGlobalMemoryDump(args, callback);
+ } else if (!callback.is_null()) {
+ callback.Run(guid, false /* success */);
+ }
+}
+
+void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
+ RequestGlobalDump(dump_type, MemoryDumpCallback());
+}
+
+// Creates a memory dump for the current process and appends it to the trace.
+void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback) {
+ scoped_refptr<ProcessMemoryDumpHolder> pmd_holder(
+ new ProcessMemoryDumpHolder(args, session_state_, callback));
+ ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+ bool did_any_provider_dump = false;
+
+ // Iterate over the active dump providers and invoke OnMemoryDump(pmd).
+ // The MDM guarantees linearity (at most one MDP is active within one
+ // process) and thread-safety (MDM enforces the right locking when entering /
+ // leaving the MDP.OnMemoryDump() call). This is to simplify the clients'
+ // design
+ // and not let the MDPs worry about locking.
+ // As regards thread affinity, depending on the MDP configuration (see
+ // memory_dump_provider.h), the OnMemoryDump() invocation can happen:
+ // - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
+ // - Posted on MDP.task_runner(), when MDP.task_runner() is set.
+ {
+ AutoLock lock(lock_);
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+ MemoryDumpProvider* mdp = it->first;
+ MemoryDumpProviderInfo* mdp_info = &it->second;
+ if (mdp_info->disabled)
+ continue;
+ if (mdp_info->task_runner) {
+ // The OnMemoryDump() call must be posted.
+ bool did_post_async_task = mdp_info->task_runner->PostTask(
+ FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+ Unretained(this), Unretained(mdp), pmd_holder));
+ // The thread underlying the TaskRunner might have gone away.
+ if (did_post_async_task)
+ ++pmd_holder->num_pending_async_requests;
+ } else {
+ // Invoke the dump provider synchronously.
+ did_any_provider_dump |= InvokeDumpProviderLocked(mdp, pmd);
+ }
+ }
+ } // AutoLock
+
+ // If at least one synchronous provider did dump and there are no pending
+ // asynchronous requests, add the dump to the trace and invoke the callback
+ // straight away (FinalizeDumpAndAddToTrace() takes care of the callback).
+ if (did_any_provider_dump && pmd_holder->num_pending_async_requests == 0)
+ FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+// Invokes the MemoryDumpProvider.OnMemoryDump(), taking care of the fail-safe
+// logic which disables the dumper when failing (crbug.com/461788).
+bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+ ProcessMemoryDump* pmd) {
+ lock_.AssertAcquired();
+ bool dump_successful = mdp->OnMemoryDump(pmd);
+ if (!dump_successful) {
+ LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
+ "(crbug.com/461788), disabling it for current process. Try "
+ "restarting chrome with the --no-sandbox switch.";
+ dump_providers_.find(mdp)->second.disabled = true;
+ }
+ return dump_successful;
+}
+
+// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
+// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
+// happen on a different thread.
+void MemoryDumpManager::ContinueAsyncProcessDump(
+ MemoryDumpProvider* mdp,
+ scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
+ bool should_finalize_dump = false;
+ {
+ // The lock here is to guarantee that different asynchronous dumps on
+ // different threads are still serialized, so that the MemoryDumpProvider
+ // has a consistent view of the |pmd| argument passed.
+ AutoLock lock(lock_);
+ ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+
+ // Check if the MemoryDumpProvider is still there. It might have been
+ // destroyed and unregistered while hopping threads.
+ if (dump_providers_.count(mdp))
+ InvokeDumpProviderLocked(mdp, pmd);
+
+ // Finalize the dump appending it to the trace if this was the last
+ // asynchronous request pending.
+ --pmd_holder->num_pending_async_requests;
+ if (pmd_holder->num_pending_async_requests == 0)
+ should_finalize_dump = true;
+ } // AutoLock(lock_)
+
+ if (should_finalize_dump)
+ FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+void MemoryDumpManager::OnTraceLogEnabled() {
+ // TODO(primiano): at this point we query TraceLog::GetCurrentCategoryFilter
+ // to figure out (and cache) which dumpers should be enabled or not.
+ // For the moment piggy back everything on the generic "memory" category.
+ bool enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+
+ AutoLock lock(lock_);
+
+ // There is no point starting the tracing without a delegate.
+ if (!enabled || !delegate_) {
+ // Disable all the providers.
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+ it->second.disabled = true;
+ return;
+ }
+
+ session_state_ = new MemoryDumpSessionState();
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+ it->second.disabled = false;
+
+ subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
+
+ if (delegate_->IsCoordinatorProcess()) {
+ periodic_dump_timer_.Start(FROM_HERE,
+ TimeDelta::FromSeconds(kDumpIntervalSeconds),
+ base::Bind(&RequestPeriodicGlobalDump));
+ }
+}
+
+void MemoryDumpManager::OnTraceLogDisabled() {
+ AutoLock lock(lock_);
+ periodic_dump_timer_.Stop();
+ subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
+ session_state_ = nullptr;
+}
+
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+ : task_runner(task_runner), disabled(false) {
+}
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/memory_dump_manager.h b/chromium/base/trace_event/memory_dump_manager.h
new file mode 100644
index 00000000000..3645ac18ba4
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_manager.h
@@ -0,0 +1,170 @@
+// Copyright 2015 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_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+namespace {
+class ProcessMemoryDumpHolder;
+}
+
+class MemoryDumpManagerDelegate;
+class MemoryDumpProvider;
+class ProcessMemoryDump;
+class MemoryDumpSessionState;
+
+// This is the interface exposed to the rest of the codebase to deal with
+// memory tracing. The main entry point for clients is represented by
+// RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
+class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
+ public:
+ static const char* const kTraceCategoryForTesting;
+
+ static MemoryDumpManager* GetInstance();
+
+ // Invoked once per process to register the TraceLog observer.
+ void Initialize();
+
+ // See the lifetime and thread-safety requirements on the delegate below in
+ // the |MemoryDumpManagerDelegate| docstring.
+ void SetDelegate(MemoryDumpManagerDelegate* delegate);
+
+ // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
+ // expected to either be a singleton or unregister itself.
+ // If the optional |task_runner| argument is non-null, all the calls to the
+ // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
+ // able to handle calls on arbitrary threads.
+ void RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+ void RegisterDumpProvider(MemoryDumpProvider* mdp);
+ void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+
+ // Requests a memory dump. The dump might happen or not depending on the
+ // filters and categories specified when enabling tracing.
+ // The optional |callback| is executed asynchronously, on an arbitrary thread,
+ // to notify about the completion of the global dump (i.e. after all the
+ // processes have dumped) and its success (true iff all the dumps were
+ // successful).
+ void RequestGlobalDump(MemoryDumpType dump_type,
+ const MemoryDumpCallback& callback);
+
+ // Same as above (still asynchronous), but without callback.
+ void RequestGlobalDump(MemoryDumpType dump_type);
+
+ // TraceLog::EnabledStateObserver implementation.
+ void OnTraceLogEnabled() override;
+ void OnTraceLogDisabled() override;
+
+ // Returns the MemoryDumpSessionState object, which is shared by all the
+ // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
+ // session lifetime.
+ const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+ return session_state_;
+ }
+
+ private:
+ // Descriptor struct used to hold information about registered MDPs. It is
+ // deliberately copyable, in order to allow to be used as hash_map value.
+ struct MemoryDumpProviderInfo {
+ MemoryDumpProviderInfo(
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+ ~MemoryDumpProviderInfo();
+
+ scoped_refptr<SingleThreadTaskRunner> task_runner; // Optional.
+ bool disabled; // For fail-safe logic (auto-disable failing MDPs).
+ };
+
+ friend struct DefaultDeleter<MemoryDumpManager>; // For the testing instance.
+ friend struct DefaultSingletonTraits<MemoryDumpManager>;
+ friend class MemoryDumpManagerDelegate;
+ friend class MemoryDumpManagerTest;
+
+ static void SetInstanceForTesting(MemoryDumpManager* instance);
+
+ MemoryDumpManager();
+ virtual ~MemoryDumpManager();
+
+ // Internal, used only by MemoryDumpManagerDelegate.
+ // Creates a memory dump for the current process and appends it to the trace.
+ // |callback| will be invoked asynchronously upon completion on the same
+ // thread on which CreateProcessDump() was called.
+ void CreateProcessDump(const MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback);
+
+ bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+ ProcessMemoryDump* pmd);
+ void ContinueAsyncProcessDump(
+ MemoryDumpProvider* mdp,
+ scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
+
+ hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
+
+ // Shared among all the PMDs to keep state scoped to the tracing session.
+ scoped_refptr<MemoryDumpSessionState> session_state_;
+
+ MemoryDumpManagerDelegate* delegate_; // Not owned.
+
+ // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
+ // to guard against disabling logging while dumping on another thread.
+ Lock lock_;
+
+ // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
+ // dump_providers_enabled_ list) when tracing is not enabled.
+ subtle::AtomicWord memory_tracing_enabled_;
+
+ // For time-triggered periodic dumps.
+ RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
+
+ // Skips the auto-registration of the core dumpers during Initialize().
+ bool skip_core_dumpers_auto_registration_for_testing_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
+};
+
+// The delegate is supposed to be long lived (read: a Singleton) and thread
+// safe (i.e. should expect calls from any thread and handle thread hopping).
+class BASE_EXPORT MemoryDumpManagerDelegate {
+ public:
+ virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback) = 0;
+
+ // Determines whether the MemoryDumpManager instance should be the master
+ // (the ones which initiates and coordinates the multiprocess dumps) or not.
+ virtual bool IsCoordinatorProcess() const = 0;
+
+ protected:
+ MemoryDumpManagerDelegate() {}
+ virtual ~MemoryDumpManagerDelegate() {}
+
+ void CreateProcessDump(const MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback) {
+ MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
diff --git a/chromium/base/trace_event/memory_dump_manager_unittest.cc b/chromium/base/trace_event/memory_dump_manager_unittest.cc
new file mode 100644
index 00000000000..1da9429588e
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_manager_unittest.cc
@@ -0,0 +1,276 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
+namespace base {
+namespace trace_event {
+
+// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
+// instead of performing IPC dances.
+class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
+ public:
+ void RequestGlobalMemoryDump(
+ const base::trace_event::MemoryDumpRequestArgs& args,
+ const MemoryDumpCallback& callback) override {
+ CreateProcessDump(args, callback);
+ }
+
+ bool IsCoordinatorProcess() const override { return false; }
+};
+
+class MemoryDumpManagerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ message_loop_.reset(new MessageLoop());
+ mdm_.reset(new MemoryDumpManager());
+ MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+ ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
+ MemoryDumpManager::GetInstance()->Initialize();
+ MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
+ }
+
+ void TearDown() override {
+ MemoryDumpManager::SetInstanceForTesting(nullptr);
+ mdm_.reset();
+ message_loop_.reset();
+ TraceLog::DeleteForTesting();
+ }
+
+ void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
+ Closure closure,
+ uint64 dump_guid,
+ bool success) {
+ task_runner->PostTask(FROM_HERE, closure);
+ }
+
+ protected:
+ const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
+
+ void EnableTracing(const char* category) {
+ TraceLog::GetInstance()->SetEnabled(
+ CategoryFilter(category), TraceLog::RECORDING_MODE, TraceOptions());
+ }
+
+ void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+
+ scoped_ptr<MemoryDumpManager> mdm_;
+
+ private:
+ scoped_ptr<MessageLoop> message_loop_;
+ MemoryDumpManagerDelegateForTesting delegate_;
+
+ // We want our singleton torn down after each test.
+ ShadowingAtExitManager at_exit_manager_;
+};
+
+class MockDumpProvider : public MemoryDumpProvider {
+ public:
+ MockDumpProvider() : last_session_state_(nullptr) {}
+
+ // Ctor used by the RespectTaskRunnerAffinity test.
+ explicit MockDumpProvider(
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+ : last_session_state_(nullptr), task_runner_(task_runner) {}
+
+ virtual ~MockDumpProvider() {}
+
+ MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));
+
+ // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
+ bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
+ EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
+ return true;
+ }
+
+ // OnMemoryDump() override for the SharedSessionState test.
+ bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
+ MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
+ if (last_session_state_)
+ EXPECT_EQ(last_session_state_, cur_session_state);
+ last_session_state_ = cur_session_state;
+ return true;
+ }
+
+ private:
+ MemoryDumpSessionState* last_session_state_;
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
+};
+
+TEST_F(MemoryDumpManagerTest, SingleDumper) {
+ MockDumpProvider mdp;
+ mdm_->RegisterDumpProvider(&mdp);
+
+ // Check that the dumper is not called if the memory category is not enabled.
+ EnableTracing("foo-and-bar-but-not-memory");
+ EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ // Now repeat enabling the memory category and check that the dumper is
+ // invoked this time.
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
+ for (int i = 0; i < 3; ++i)
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ mdm_->UnregisterDumpProvider(&mdp);
+
+ // Finally check the unregister logic (no calls to the mdp after unregister).
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(MemoryDumpManagerTest, SharedSessionState) {
+ MockDumpProvider mdp1;
+ MockDumpProvider mdp2;
+ mdm_->RegisterDumpProvider(&mdp1);
+ mdm_->RegisterDumpProvider(&mdp2);
+
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, OnMemoryDump(_))
+ .Times(2)
+ .WillRepeatedly(
+ Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+ EXPECT_CALL(mdp2, OnMemoryDump(_))
+ .Times(2)
+ .WillRepeatedly(
+ Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+
+ for (int i = 0; i < 2; ++i)
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+ DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
+ MockDumpProvider mdp1;
+ MockDumpProvider mdp2;
+
+ // Enable only mdp1.
+ mdm_->RegisterDumpProvider(&mdp1);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ // Invert: enable mdp1 and disable mdp2.
+ mdm_->UnregisterDumpProvider(&mdp1);
+ mdm_->RegisterDumpProvider(&mdp2);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+
+ // Enable both mdp1 and mdp2.
+ mdm_->RegisterDumpProvider(&mdp1);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+}
+
+// Checks that the MemoryDumpManager respects the thread affinity when a
+// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
+// threads and registering a MemoryDumpProvider on each of them. At each
+// iteration, one thread is removed, to check the live unregistration logic.
+TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
+ const uint32 kNumInitialThreads = 8;
+
+ ScopedVector<Thread> threads;
+ ScopedVector<MockDumpProvider> mdps;
+
+ // Create the threads and setup the expectations. Given that at each iteration
+ // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
+ // invoked a number of times equal to its index.
+ for (uint32 i = kNumInitialThreads; i > 0; --i) {
+ threads.push_back(new Thread("test thread"));
+ threads.back()->Start();
+ mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
+ MockDumpProvider* mdp = mdps.back();
+ mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
+ EXPECT_CALL(*mdp, OnMemoryDump(_))
+ .Times(i)
+ .WillRepeatedly(
+ Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
+ }
+
+ EnableTracing(kTraceCategory);
+
+ while (!threads.empty()) {
+ {
+ RunLoop run_loop;
+ MemoryDumpCallback callback =
+ Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+ MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
+ // This nested message loop (|run_loop|) will be quit if and only if
+ // the RequestGlobalDump callback is invoked.
+ run_loop.Run();
+ }
+
+ // Unregister a MDP and destroy one thread at each iteration to check the
+ // live unregistration logic. The unregistration needs to happen on the same
+ // thread the MDP belongs to.
+ {
+ RunLoop run_loop;
+ Closure unregistration =
+ Bind(&MemoryDumpManager::UnregisterDumpProvider,
+ Unretained(mdm_.get()), Unretained(mdps.back()));
+ threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+ mdps.pop_back();
+ threads.back()->Stop();
+ threads.pop_back();
+ }
+
+ DisableTracing();
+}
+
+// Enable both dump providers, make mdp1 fail and assert that only mdp2 is
+// invoked the 2nd time.
+// FIXME(primiano): remove once crbug.com/461788 gets fixed.
+TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
+ MockDumpProvider mdp1;
+ MockDumpProvider mdp2;
+
+ mdm_->RegisterDumpProvider(&mdp1);
+ mdm_->RegisterDumpProvider(&mdp2);
+ EnableTracing(kTraceCategory);
+
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+ EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+ EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+ DisableTracing();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/memory_dump_provider.h b/chromium/base/trace_event/memory_dump_provider.h
new file mode 100644
index 00000000000..6e6551cc039
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_provider.h
@@ -0,0 +1,36 @@
+// Copyright 2015 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_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// The contract interface that memory dump providers must implement.
+class BASE_EXPORT MemoryDumpProvider {
+ public:
+ // Called by the MemoryDumpManager when generating memory dumps.
+ // The embedder should return true if the |pmd| was successfully populated,
+ // false if something went wrong and the dump should be considered invalid.
+ // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
+ // MemoryDumpProvider for the entire trace session if it fails consistently).
+ virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
+
+ protected:
+ MemoryDumpProvider() {}
+ virtual ~MemoryDumpProvider() {}
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
diff --git a/chromium/base/trace_event/memory_dump_request_args.h b/chromium/base/trace_event/memory_dump_request_args.h
new file mode 100644
index 00000000000..4d3763acf16
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_request_args.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
+
+// This file defines the types and structs used to issue memory dump requests.
+// These are also used in the IPCs for coordinating inter-process memory dumps.
+
+#include "base/base_export.h"
+#include "base/callback.h"
+
+namespace base {
+namespace trace_event {
+
+// Captures the reason why a memory dump is being requested. This is to allow
+// selective enabling of dumps, filtering and post-processing.
+enum class MemoryDumpType {
+ TASK_BEGIN, // Dumping memory at the beginning of a message-loop task.
+ TASK_END, // Dumping memory at the ending of a message-loop task.
+ PERIODIC_INTERVAL, // Dumping memory at periodic intervals.
+ EXPLICITLY_TRIGGERED, // Non maskable dump request.
+ LAST = EXPLICITLY_TRIGGERED // For IPC macros.
+};
+
+using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+
+struct BASE_EXPORT MemoryDumpRequestArgs {
+ // Globally unique identifier. In multi-process dumps, all processes issue a
+ // local dump with the same guid. This allows the trace importers to
+ // reconstruct the global dump.
+ uint64 dump_guid;
+
+ MemoryDumpType dump_type;
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
diff --git a/chromium/base/trace_event/memory_dump_session_state.cc b/chromium/base/trace_event/memory_dump_session_state.cc
new file mode 100644
index 00000000000..433ac14cbfa
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_session_state.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_session_state.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryDumpSessionState::MemoryDumpSessionState() {
+}
+
+MemoryDumpSessionState::~MemoryDumpSessionState() {
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/memory_dump_session_state.h b/chromium/base/trace_event/memory_dump_session_state.h
new file mode 100644
index 00000000000..cf29b85559c
--- /dev/null
+++ b/chromium/base/trace_event/memory_dump_session_state.h
@@ -0,0 +1,31 @@
+// Copyright 2015 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_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+namespace trace_event {
+
+// Container for state variables that should be shared across all the memory
+// dumps in a tracing session.
+class BASE_EXPORT MemoryDumpSessionState
+ : public RefCountedThreadSafe<MemoryDumpSessionState> {
+ public:
+ MemoryDumpSessionState();
+
+ private:
+ friend class RefCountedThreadSafe<MemoryDumpSessionState>;
+ ~MemoryDumpSessionState();
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
diff --git a/chromium/base/trace_event/process_memory_dump.cc b/chromium/base/trace_event/process_memory_dump.cc
new file mode 100644
index 00000000000..54fcad6f231
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_dump.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_dump.h"
+
+#include "base/trace_event/process_memory_totals.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+ProcessMemoryDump::ProcessMemoryDump(
+ const scoped_refptr<MemoryDumpSessionState>& session_state)
+ : has_process_totals_(false),
+ has_process_mmaps_(false),
+ session_state_(session_state) {
+}
+
+ProcessMemoryDump::~ProcessMemoryDump() {
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+ const std::string& absolute_name) {
+ MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this);
+ DCHECK_EQ(0ul, allocator_dumps_.count(absolute_name));
+ allocator_dumps_storage_.push_back(mad);
+ allocator_dumps_[absolute_name] = mad;
+ return mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
+ const std::string& absolute_name) const {
+ auto it = allocator_dumps_.find(absolute_name);
+ return it == allocator_dumps_.end() ? nullptr : it->second;
+}
+
+void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
+ // Build up the [dumper name] -> [value] dictionary.
+ if (has_process_totals_) {
+ value->BeginDictionary("process_totals");
+ process_totals_.AsValueInto(value);
+ value->EndDictionary();
+ }
+ if (has_process_mmaps_) {
+ value->BeginDictionary("process_mmaps");
+ process_mmaps_.AsValueInto(value);
+ value->EndDictionary();
+ }
+ if (allocator_dumps_storage_.size() > 0) {
+ value->BeginDictionary("allocators");
+ for (const MemoryAllocatorDump* allocator_dump : allocator_dumps_storage_)
+ allocator_dump->AsValueInto(value);
+ value->EndDictionary();
+ }
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/process_memory_dump.h b/chromium/base/trace_event/process_memory_dump.h
new file mode 100644
index 00000000000..889356d65aa
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_dump.h
@@ -0,0 +1,94 @@
+// Copyright 2015 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_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+class ConvertableToTraceFormat;
+class MemoryDumpManager;
+class MemoryDumpSessionState;
+
+// ProcessMemoryDump is as a strongly typed container which enforces the data
+// model for each memory dump and holds the dumps produced by the
+// MemoryDumpProvider(s) for a specific process.
+// At trace generation time (i.e. when AsValue() is called), ProcessMemoryDump
+// will compose a key-value dictionary of the various dumps obtained at trace
+// dump point time.
+class BASE_EXPORT ProcessMemoryDump {
+ public:
+ // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
+ // MemoryAllocatorDump instances.
+ using AllocatorDumpsMap =
+ SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
+
+ ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
+ ~ProcessMemoryDump();
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ ProcessMemoryTotals* process_totals() { return &process_totals_; }
+ bool has_process_totals() const { return has_process_totals_; }
+ void set_has_process_totals() { has_process_totals_ = true; }
+
+ ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+ bool has_process_mmaps() const { return has_process_mmaps_; }
+ void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
+ // Creates a new MemoryAllocatorDump with the given name and returns the
+ // empty object back to the caller.
+ // Arguments:
+ // absolute_name: a name that uniquely identifies allocator dumps produced
+ // by this provider. It is possible to specify nesting by using a
+ // path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
+ // Leading or trailing slashes are not allowed.
+ // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
+ MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
+
+ // Looks up a MemoryAllocatorDump given its allocator and heap names, or
+ // nullptr if not found.
+ MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
+
+ // Returns the map of the MemoryAllocatorDumps added to this dump.
+ const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+
+ const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+ return session_state_;
+ }
+
+ private:
+ ProcessMemoryTotals process_totals_;
+ bool has_process_totals_;
+
+ ProcessMemoryMaps process_mmaps_;
+ bool has_process_mmaps_;
+
+ AllocatorDumpsMap allocator_dumps_;
+
+ // ProcessMemoryDump handles the memory ownership of all its belongings.
+ ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
+
+ // State shared among all PMDs instances created in a given trace session.
+ scoped_refptr<MemoryDumpSessionState> session_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
diff --git a/chromium/base/trace_event/process_memory_maps.cc b/chromium/base/trace_event/process_memory_maps.cc
new file mode 100644
index 00000000000..d553ee88e80
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_maps.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+
+ProcessMemoryMaps::ProcessMemoryMaps() {
+}
+
+ProcessMemoryMaps::~ProcessMemoryMaps() {
+}
+
+void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
+ static const char kHexFmt[] = "%" PRIx64;
+
+ // Refer to the design doc goo.gl/sxfFY8 for the semantic of these fields.
+ value->BeginArray("vm_regions");
+ for (const auto& region : vm_regions_) {
+ value->BeginDictionary();
+
+ value->SetString("sa", StringPrintf(kHexFmt, region.start_address));
+ value->SetString("sz", StringPrintf(kHexFmt, region.size_in_bytes));
+ value->SetInteger("pf", region.protection_flags);
+ value->SetString("mf", region.mapped_file);
+
+ value->BeginDictionary("bs"); // byte stats
+ value->SetString(
+ "pss", StringPrintf(kHexFmt, region.byte_stats_proportional_resident));
+ value->SetString("prv",
+ StringPrintf(kHexFmt, region.byte_stats_private_resident));
+ value->SetString("shr",
+ StringPrintf(kHexFmt, region.byte_stats_shared_resident));
+ value->EndDictionary();
+
+ value->EndDictionary();
+ }
+ value->EndArray();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/process_memory_maps.h b/chromium/base/trace_event/process_memory_maps.h
new file mode 100644
index 00000000000..dc1892fd622
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_maps.h
@@ -0,0 +1,58 @@
+// Copyright 2015 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_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMaps {
+ public:
+ struct VMRegion {
+ static const uint32 kProtectionFlagsRead;
+ static const uint32 kProtectionFlagsWrite;
+ static const uint32 kProtectionFlagsExec;
+
+ uint64 start_address;
+ uint64 size_in_bytes;
+ uint32 protection_flags;
+ std::string mapped_file;
+
+ // private_resident + shared_resident = resident set size.
+ uint64 byte_stats_private_resident;
+ uint64 byte_stats_shared_resident;
+
+ // For multiprocess accounting.
+ uint64 byte_stats_proportional_resident;
+ };
+
+ ProcessMemoryMaps();
+ ~ProcessMemoryMaps();
+
+ void AddVMRegion(const VMRegion& region) { vm_regions_.push_back(region); }
+ const std::vector<VMRegion>& vm_regions() const { return vm_regions_; }
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ private:
+ std::vector<VMRegion> vm_regions_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMaps);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
diff --git a/chromium/base/trace_event/process_memory_maps_dump_provider.cc b/chromium/base/trace_event/process_memory_maps_dump_provider.cc
new file mode 100644
index 00000000000..680fa29609e
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_maps_dump_provider.cc
@@ -0,0 +1,189 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <cctype>
+#include <fstream>
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// static
+std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
+
+namespace {
+
+const uint32 kMaxLineSize = 4096;
+
+bool ParseSmapsHeader(std::istream* smaps,
+ ProcessMemoryMaps::VMRegion* region) {
+ // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n"
+ bool res = true; // Whether this region should be appended or skipped.
+ uint64 end_addr;
+ std::string protection_flags;
+ std::string ignored;
+ *smaps >> std::hex >> region->start_address;
+ smaps->ignore(1);
+ *smaps >> std::hex >> end_addr;
+ if (end_addr > region->start_address) {
+ region->size_in_bytes = end_addr - region->start_address;
+ } else {
+ // This is not just paranoia, it can actually happen (See crbug.com/461237).
+ region->size_in_bytes = 0;
+ res = false;
+ }
+
+ region->protection_flags = 0;
+ *smaps >> protection_flags;
+ CHECK_EQ(4UL, protection_flags.size());
+ if (protection_flags[0] == 'r') {
+ region->protection_flags |=
+ ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+ }
+ if (protection_flags[1] == 'w') {
+ region->protection_flags |=
+ ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+ }
+ if (protection_flags[2] == 'x') {
+ region->protection_flags |=
+ ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+ }
+ *smaps >> ignored; // Ignore mapped file offset.
+ *smaps >> ignored; // Ignore device maj-min (fc:01 in the example above).
+ *smaps >> ignored; // Ignore inode number (1234 in the example above).
+
+ while (smaps->peek() == ' ')
+ smaps->ignore(1);
+ char mapped_file[kMaxLineSize];
+ smaps->getline(mapped_file, sizeof(mapped_file));
+ region->mapped_file = mapped_file;
+
+ return res;
+}
+
+uint64 ReadCounterBytes(std::istream* smaps) {
+ uint64 counter_value = 0;
+ *smaps >> std::dec >> counter_value;
+ return counter_value * 1024;
+}
+
+uint32 ParseSmapsCounter(std::istream* smaps,
+ ProcessMemoryMaps::VMRegion* region) {
+ // A smaps counter lines looks as follows: "RSS: 0 Kb\n"
+ uint32 res = 0;
+ std::string counter_name;
+ *smaps >> counter_name;
+
+ // TODO(primiano): "Swap" should also be accounted as resident. Check
+ // whether Rss isn't already counting swapped and fix below if that is
+ // the case.
+ if (counter_name == "Pss:") {
+ region->byte_stats_proportional_resident = ReadCounterBytes(smaps);
+ res = 1;
+ } else if (counter_name == "Private_Dirty:" ||
+ counter_name == "Private_Clean:") {
+ // For Private and Shared counters keep the sum of the dirty + clean stats.
+ region->byte_stats_private_resident += ReadCounterBytes(smaps);
+ res = 1;
+ } else if (counter_name == "Shared_Dirty:" ||
+ counter_name == "Shared_Clean:") {
+ region->byte_stats_shared_resident += ReadCounterBytes(smaps);
+ res = 1;
+ }
+
+#ifndef NDEBUG
+ // Paranoid check against changes of the Kernel /proc interface.
+ if (res) {
+ std::string unit;
+ *smaps >> unit;
+ DCHECK_EQ("kB", unit);
+ }
+#endif
+
+ smaps->ignore(kMaxLineSize, '\n');
+
+ return res;
+}
+
+uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
+ if (!smaps->good())
+ return 0;
+
+ const uint32 kNumExpectedCountersPerRegion = 5;
+ uint32 counters_parsed_for_current_region = 0;
+ uint32 num_valid_regions = 0;
+ ProcessMemoryMaps::VMRegion region;
+ bool should_add_current_region = false;
+ for (;;) {
+ int next = smaps->peek();
+ if (next == std::ifstream::traits_type::eof() || next == '\n')
+ break;
+ if (isxdigit(next) && !isupper(next)) {
+ region = {0};
+ counters_parsed_for_current_region = 0;
+ should_add_current_region = ParseSmapsHeader(smaps, &region);
+ } else {
+ counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+ DCHECK_LE(counters_parsed_for_current_region,
+ kNumExpectedCountersPerRegion);
+ if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
+ if (should_add_current_region) {
+ pmm->AddVMRegion(region);
+ ++num_valid_regions;
+ should_add_current_region = false;
+ }
+ }
+ }
+ }
+ return num_valid_regions;
+}
+
+} // namespace
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// static
+ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
+ return Singleton<ProcessMemoryMapsDumpProvider,
+ LeakySingletonTraits<ProcessMemoryMapsDumpProvider>>::get();
+}
+
+ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() {
+}
+
+ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory maps for the
+// current process.
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+ uint32 res = 0;
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ if (UNLIKELY(proc_smaps_for_testing)) {
+ res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
+ } else {
+ std::ifstream proc_self_smaps("/proc/self/smaps");
+ res = ReadLinuxProcSmapsFile(&proc_self_smaps, pmd->process_mmaps());
+ }
+#else
+ LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
+#endif
+
+ if (res > 0) {
+ pmd->set_has_process_mmaps();
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/process_memory_maps_dump_provider.h b/chromium/base/trace_event/process_memory_maps_dump_provider.h
new file mode 100644
index 00000000000..c73c4d2be66
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_maps_dump_provider.h
@@ -0,0 +1,42 @@
+// Copyright 2015 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_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
+ public:
+ static ProcessMemoryMapsDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
+ FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ static std::istream* proc_smaps_for_testing;
+#endif
+
+ ProcessMemoryMapsDumpProvider();
+ ~ProcessMemoryMapsDumpProvider() override;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMapsDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
diff --git a/chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc
new file mode 100644
index 00000000000..e45d30a6507
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+namespace {
+const char kTestSmaps1[] =
+ "00400000-004be000 r-xp 00000000 fc:01 1234 /file/1\n"
+ "Size: 760 kB\n"
+ "Rss: 296 kB\n"
+ "Pss: 162 kB\n"
+ "Shared_Clean: 228 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 0 kB\n"
+ "Private_Dirty: 68 kB\n"
+ "Referenced: 296 kB\n"
+ "Anonymous: 68 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd\n"
+ "ff000000-ff800000 -w-p 00001080 fc:01 0 /file/name with space\n"
+ "Size: 0 kB\n"
+ "Rss: 192 kB\n"
+ "Pss: 128 kB\n"
+ "Shared_Clean: 120 kB\n"
+ "Shared_Dirty: 4 kB\n"
+ "Private_Clean: 60 kB\n"
+ "Private_Dirty: 8 kB\n"
+ "Referenced: 296 kB\n"
+ "Anonymous: 0 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd";
+
+const char kTestSmaps2[] =
+ // An invalid region, with zero size and overlapping with the last one
+ // (See crbug.com/461237).
+ "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
+ "Size: 4 kB\n"
+ "Rss: 0 kB\n"
+ "Pss: 0 kB\n"
+ "Shared_Clean: 0 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 0 kB\n"
+ "Private_Dirty: 0 kB\n"
+ "Referenced: 0 kB\n"
+ "Anonymous: 0 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd\n"
+ // A invalid region with its range going backwards.
+ "00400000-00200000 ---p 00000000 00:00 0 \n"
+ "Size: 4 kB\n"
+ "Rss: 0 kB\n"
+ "Pss: 0 kB\n"
+ "Shared_Clean: 0 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 0 kB\n"
+ "Private_Dirty: 0 kB\n"
+ "Referenced: 0 kB\n"
+ "Anonymous: 0 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd\n"
+ // A good anonymous region at the end.
+ "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
+ "Size: 48 kB\n"
+ "Rss: 40 kB\n"
+ "Pss: 32 kB\n"
+ "Shared_Clean: 16 kB\n"
+ "Shared_Dirty: 12 kB\n"
+ "Private_Clean: 8 kB\n"
+ "Private_Dirty: 4 kB\n"
+ "Referenced: 40 kB\n"
+ "Anonymous: 16 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd wr mr mw me ac sd\n";
+} // namespace
+
+TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
+ const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+ const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+ const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+
+ auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
+
+ // Emulate a non-existent /proc/self/smaps.
+ ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
+ std::ifstream non_existent_file("/tmp/does-not-exist");
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
+ CHECK_EQ(false, non_existent_file.good());
+ pmmdp->OnMemoryDump(&pmd_invalid);
+ ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+ // Emulate an empty /proc/self/smaps.
+ std::ifstream empty_file("/dev/null");
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
+ CHECK_EQ(true, empty_file.good());
+ pmmdp->OnMemoryDump(&pmd_invalid);
+ ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+ // Parse the 1st smaps file.
+ ProcessMemoryDump pmd_1(nullptr /* session_state */);
+ std::istringstream test_smaps_1(kTestSmaps1);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
+ pmmdp->OnMemoryDump(&pmd_1);
+ ASSERT_TRUE(pmd_1.has_process_mmaps());
+ const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
+ ASSERT_EQ(2UL, regions_1.size());
+
+ EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
+ EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
+ EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
+ EXPECT_EQ("/file/1", regions_1[0].mapped_file);
+ EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
+ EXPECT_EQ((228 + 0) * 1024UL, regions_1[0].byte_stats_shared_resident);
+ EXPECT_EQ((0 + 68) * 1024UL, regions_1[0].byte_stats_private_resident);
+
+ EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
+ EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
+ EXPECT_EQ(kProtW, regions_1[1].protection_flags);
+ EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
+ EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
+ EXPECT_EQ((120 + 4) * 1024UL, regions_1[1].byte_stats_shared_resident);
+ EXPECT_EQ((60 + 8) * 1024UL, regions_1[1].byte_stats_private_resident);
+
+ // Parse the 2nd smaps file.
+ ProcessMemoryDump pmd_2(nullptr /* session_state */);
+ std::istringstream test_smaps_2(kTestSmaps2);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
+ pmmdp->OnMemoryDump(&pmd_2);
+ ASSERT_TRUE(pmd_2.has_process_mmaps());
+ const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
+ ASSERT_EQ(1UL, regions_2.size());
+ EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
+ EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
+ EXPECT_EQ(0U, regions_2[0].protection_flags);
+ EXPECT_EQ("", regions_2[0].mapped_file);
+ EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
+ EXPECT_EQ((16 + 12) * 1024UL, regions_2[0].byte_stats_shared_resident);
+ EXPECT_EQ((8 + 4) * 1024UL, regions_2[0].byte_stats_private_resident);
+}
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/process_memory_totals.cc b/chromium/base/trace_event/process_memory_totals.cc
new file mode 100644
index 00000000000..9b0c3776eea
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_totals.cc
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
+ value->SetString("resident_set_bytes",
+ StringPrintf("%" PRIx64, resident_set_bytes_));
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/process_memory_totals.h b/chromium/base/trace_event/process_memory_totals.h
new file mode 100644
index 00000000000..29c94c9aacc
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_totals.h
@@ -0,0 +1,36 @@
+// Copyright 2015 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_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotals {
+ public:
+ ProcessMemoryTotals() : resident_set_bytes_(0) {}
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ uint64 resident_set_bytes() const { return resident_set_bytes_; }
+ void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+
+ private:
+ uint64 resident_set_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/chromium/base/trace_event/process_memory_totals_dump_provider.cc b/chromium/base/trace_event/process_memory_totals_dump_provider.cc
new file mode 100644
index 00000000000..06b537c4188
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_totals_dump_provider.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+uint64 ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+namespace {
+
+ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+ return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
+#else
+ return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle(), NULL);
+#endif
+}
+} // namespace
+
+// static
+ProcessMemoryTotalsDumpProvider*
+ProcessMemoryTotalsDumpProvider::GetInstance() {
+ return Singleton<
+ ProcessMemoryTotalsDumpProvider,
+ LeakySingletonTraits<ProcessMemoryTotalsDumpProvider>>::get();
+}
+
+ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
+ : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
+}
+
+ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+ const uint64 rss_bytes = rss_bytes_for_testing
+ ? rss_bytes_for_testing
+ : process_metrics_->GetWorkingSetSize();
+
+ if (rss_bytes > 0) {
+ pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+ pmd->set_has_process_totals();
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/process_memory_totals_dump_provider.h b/chromium/base/trace_event/process_memory_totals_dump_provider.h
new file mode 100644
index 00000000000..6c86eb6b4a1
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_totals_dump_provider.h
@@ -0,0 +1,44 @@
+// Copyright 2015 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_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+
+class ProcessMetrics;
+
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider {
+ public:
+ static ProcessMemoryTotalsDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
+ FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS);
+
+ static uint64 rss_bytes_for_testing;
+
+ ProcessMemoryTotalsDumpProvider();
+ ~ProcessMemoryTotalsDumpProvider() override;
+
+ scoped_ptr<ProcessMetrics> process_metrics_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotalsDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
diff --git a/chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc
new file mode 100644
index 00000000000..f9bb6c071ce
--- /dev/null
+++ b/chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
+ auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
+ scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr));
+ scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
+
+ ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
+ pmtdp->OnMemoryDump(pmd_before.get());
+
+ // Pretend that the RSS of the process increased of +1M.
+ const size_t kAllocSize = 1048576;
+ ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
+
+ pmtdp->OnMemoryDump(pmd_after.get());
+
+ ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+ ASSERT_TRUE(pmd_before->has_process_totals());
+ ASSERT_TRUE(pmd_after->has_process_totals());
+
+ const uint64 rss_before = pmd_before->process_totals()->resident_set_bytes();
+ const uint64 rss_after = pmd_after->process_totals()->resident_set_bytes();
+
+ EXPECT_NE(0U, rss_before);
+ EXPECT_NE(0U, rss_after);
+
+ EXPECT_EQ(rss_after - rss_before, kAllocSize);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/trace_event.gypi b/chromium/base/trace_event/trace_event.gypi
new file mode 100644
index 00000000000..9a072e49003
--- /dev/null
+++ b/chromium/base/trace_event/trace_event.gypi
@@ -0,0 +1,70 @@
+# Copyright 2015 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.
+{
+ 'variables': {
+ 'trace_event_sources' : [
+ 'trace_event/java_heap_dump_provider_android.cc',
+ 'trace_event/java_heap_dump_provider_android.h',
+ 'trace_event/memory_allocator_dump.cc',
+ 'trace_event/memory_allocator_dump.h',
+ 'trace_event/memory_dump_manager.cc',
+ 'trace_event/memory_dump_manager.h',
+ 'trace_event/memory_dump_provider.h',
+ 'trace_event/memory_dump_request_args.h',
+ 'trace_event/memory_dump_session_state.cc',
+ 'trace_event/memory_dump_session_state.h',
+ 'trace_event/process_memory_dump.cc',
+ 'trace_event/process_memory_dump.h',
+ 'trace_event/process_memory_maps.cc',
+ 'trace_event/process_memory_maps.h',
+ 'trace_event/process_memory_maps_dump_provider.cc',
+ 'trace_event/process_memory_maps_dump_provider.h',
+ 'trace_event/process_memory_totals.cc',
+ 'trace_event/process_memory_totals.h',
+ 'trace_event/process_memory_totals_dump_provider.cc',
+ 'trace_event/process_memory_totals_dump_provider.h',
+ 'trace_event/trace_event.h',
+ 'trace_event/trace_event_android.cc',
+ 'trace_event/trace_event_argument.cc',
+ 'trace_event/trace_event_argument.h',
+ 'trace_event/trace_event_etw_export_win.cc',
+ 'trace_event/trace_event_etw_export_win.h',
+ 'trace_event/trace_event_impl.cc',
+ 'trace_event/trace_event_impl.h',
+ 'trace_event/trace_event_impl_constants.cc',
+ 'trace_event/trace_event_memory.cc',
+ 'trace_event/trace_event_memory.h',
+ 'trace_event/trace_event_synthetic_delay.cc',
+ 'trace_event/trace_event_synthetic_delay.h',
+ 'trace_event/trace_event_system_stats_monitor.cc',
+ 'trace_event/trace_event_system_stats_monitor.h',
+ 'trace_event/trace_event_win.cc',
+ 'trace_event/trace_event_win.h',
+ 'trace_event/winheap_dump_provider_win.cc',
+ 'trace_event/winheap_dump_provider_win.h',
+ ],
+ 'conditions': [
+ ['OS == "linux" or OS == "android"', {
+ 'trace_event_sources': [
+ 'trace_event/malloc_dump_provider.cc',
+ 'trace_event/malloc_dump_provider.h',
+ ],
+ }],
+ ],
+ 'trace_event_test_sources' : [
+ 'trace_event/java_heap_dump_provider_android_unittest.cc',
+ 'trace_event/memory_allocator_dump_unittest.cc',
+ 'trace_event/memory_dump_manager_unittest.cc',
+ 'trace_event/process_memory_maps_dump_provider_unittest.cc',
+ 'trace_event/process_memory_totals_dump_provider_unittest.cc',
+ 'trace_event/trace_event_argument_unittest.cc',
+ 'trace_event/trace_event_memory_unittest.cc',
+ 'trace_event/trace_event_synthetic_delay_unittest.cc',
+ 'trace_event/trace_event_system_stats_monitor_unittest.cc',
+ 'trace_event/trace_event_unittest.cc',
+ 'trace_event/trace_event_win_unittest.cc',
+ 'trace_event/winheap_dump_provider_win_unittest.cc',
+ ],
+ },
+}
diff --git a/chromium/base/debug/trace_event.h b/chromium/base/trace_event/trace_event.h
index 62a9b1f047a..2c30b3340a2 100644
--- a/chromium/base/debug/trace_event.h
+++ b/chromium/base/trace_event/trace_event.h
@@ -141,14 +141,14 @@
// means, if the category for the event is disabled, the conversion will not
// happen.
//
-// class MyData : public base::debug::ConvertableToTraceFormat {
+// class MyData : public base::trace_event::ConvertableToTraceFormat {
// public:
// MyData() {}
-// virtual void AppendAsTraceFormat(std::string* out) const override {
+// void AppendAsTraceFormat(std::string* out) const override {
// out->append("{\"foo\":1}");
// }
// private:
-// virtual ~MyData() {}
+// ~MyData() override {}
// DISALLOW_COPY_AND_ASSIGN(MyData);
// };
//
@@ -186,16 +186,16 @@
// trace points would carry a significant performance cost of acquiring a lock
// and resolving the category.
-#ifndef BASE_DEBUG_TRACE_EVENT_H_
-#define BASE_DEBUG_TRACE_EVENT_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_H_
#include <string>
#include "base/atomicops.h"
-#include "base/debug/trace_event_impl.h"
-#include "base/debug/trace_event_memory.h"
-#include "base/debug/trace_event_system_stats_monitor.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_event_memory.h"
+#include "base/trace_event/trace_event_system_stats_monitor.h"
#include "build/build_config.h"
// By default, const char* argument values are assumed to have long-lived scope
@@ -395,6 +395,18 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+ timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+ timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
+ arg2_val)
// Records a single END event for "name" immediately. If the category
// is not enabled, then this does nothing.
@@ -439,6 +451,18 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+ timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \
+ category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+ timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
+ arg2_val)
// Records the value of a counter called "name" immediately. Value
// must be representable as a 32 bit integer.
@@ -510,6 +534,27 @@
value1_name, static_cast<int>(value1_val), \
value2_name, static_cast<int>(value2_val))
+// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name, \
+ thread_id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+ TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1( \
+ category_group, name, thread_id, timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name, \
+ thread_id, timestamp, \
+ arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
// ASYNC_STEP_* APIs should be only used by legacy code. New code should
// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
// event.
@@ -570,6 +615,12 @@
TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
static_cast<int>(base::PlatformThread::CurrentId()), \
timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
+ name, id, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+ static_cast<int>(base::PlatformThread::CurrentId()), \
+ timestamp, TRACE_EVENT_FLAG_COPY)
// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
// category is not enabled, then this does nothing. The |name| and |id| must
@@ -586,6 +637,15 @@
category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
arg1_name, arg1_val)
+// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, \
+ id, step, timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
+ static_cast<int>(base::PlatformThread::CurrentId()), \
+ timestamp, TRACE_EVENT_FLAG_NONE, "step", step)
+
// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
// category is not enabled, then this does nothing. The |name| and |id| must
// match the ASYNC_BEGIN event above. The |step| param identifies this step
@@ -641,31 +701,65 @@
// events.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
-// - |id| is used to match the NESTABLE_ASYNC_BEGIN event with the
-// NESTABLE_ASYNC_END event. Events are considered to match if their
-// category_group, name and id values all match. |id| must either be a
-// pointer or an integer value up to 64 bits. If it's a pointer, the bits
-// will be xored with a hash of the process ID so that the same pointer on two
-// different processes will not collide.
+// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
+// considered as a match if their category_group, name and id all match.
+// - |id| must either be a pointer or an integer value up to 64 bits.
+// If it's a pointer, the bits will be xored with a hash of the process ID so
+// that the same pointer on two different processes will not collide.
+// - |id| is used to match a child NESTABLE_ASYNC event with its parent
+// NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
+// be logged using the same id and category_group.
//
-// Unmatched NESTABLE_ASYNC_END event will be parsed as an instant event,
-// and unmatched NESTABLE_ASYNC_BEGIN event will be parsed as an event that
-// ends at the last NESTABLE_ASYNC_END event of that |id|.
-
-// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with 2
-// associated arguments. If the category is not enabled, then this does nothing.
+// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
+// at the first NESTABLE_ASYNC event of that id, and unmatched
+// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
+// NESTABLE_ASYNC event of that id. Corresponding warning messages for
+// unmatched events will be shown in the analysis view.
+
+// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with
+// 0, 1 or 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+ category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+ arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+ category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
arg1_val, arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
-// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 2
-// associated arguments. If the category is not enabled, then this does nothing.
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0,
+// 1, or 2 associated arguments. If the category is not enabled, then this does
+// nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+ category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
+ arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+ category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
arg1_val, arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
+
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
+ id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
+ id, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+ category_group, name, id, \
+ TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
// with 2 associated arguments. If the category is not enabled, then this
// does nothing.
@@ -784,9 +878,10 @@
category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
- UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
- (base::debug::TraceLog::ENABLED_FOR_RECORDING | \
- base::debug::TraceLog::ENABLED_FOR_EVENT_CALLBACK))
+ UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
+ (base::trace_event::TraceLog::ENABLED_FOR_RECORDING | \
+ base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK | \
+ base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
// Macro to efficiently determine if a given category group is enabled.
#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
@@ -829,16 +924,16 @@
// const unsigned char*
// TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
- base::debug::TraceLog::GetCategoryGroupEnabled
+ base::trace_event::TraceLog::GetCategoryGroupEnabled
// Get the number of times traces have been recorded. This is used to implement
// the TRACE_EVENT_IS_NEW_TRACE facility.
// unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED()
#define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED \
- base::debug::TraceLog::GetInstance()->GetNumTracesRecorded
+ base::trace_event::TraceLog::GetInstance()->GetNumTracesRecorded
// Add a trace event to the platform tracing system.
-// base::debug::TraceEventHandle TRACE_EVENT_API_ADD_TRACE_EVENT(
+// base::trace_event::TraceEventHandle TRACE_EVENT_API_ADD_TRACE_EVENT(
// char phase,
// const unsigned char* category_group_enabled,
// const char* name,
@@ -849,10 +944,11 @@
// const unsigned long long* arg_values,
// unsigned char flags)
#define TRACE_EVENT_API_ADD_TRACE_EVENT \
- base::debug::TraceLog::GetInstance()->AddTraceEvent
+ base::trace_event::TraceLog::GetInstance()->AddTraceEvent
// Add a trace event to the platform tracing system.
-// base::debug::TraceEventHandle TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
// char phase,
// const unsigned char* category_group_enabled,
// const char* name,
@@ -865,15 +961,16 @@
// const unsigned long long* arg_values,
// unsigned char flags)
#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \
- base::debug::TraceLog::GetInstance()->AddTraceEventWithThreadIdAndTimestamp
+ base::trace_event::TraceLog::GetInstance() \
+ ->AddTraceEventWithThreadIdAndTimestamp
// Set the duration field of a COMPLETE trace event.
// void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
// const unsigned char* category_group_enabled,
// const char* name,
-// base::debug::TraceEventHandle id)
+// base::trace_event::TraceEventHandle id)
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
- base::debug::TraceLog::GetInstance()->UpdateTraceEventDuration
+ base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDuration
// Defines atomic operations used internally by the tracing system.
#define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord
@@ -946,11 +1043,12 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
- base::debug::TraceEventHandle h = trace_event_internal::AddTraceEvent( \
- TRACE_EVENT_PHASE_COMPLETE, \
- INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
- name, trace_event_internal::kNoEventId, \
- TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
+ base::trace_event::TraceEventHandle h = \
+ trace_event_internal::AddTraceEvent( \
+ TRACE_EVENT_PHASE_COMPLETE, \
+ INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_internal::kNoEventId, TRACE_EVENT_FLAG_NONE, \
+ ##__VA_ARGS__); \
INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
}
@@ -986,7 +1084,8 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
name, trace_event_trace_id.data(), \
thread_id, base::TimeTicks::FromInternalValue(timestamp), \
- trace_event_flags, ##__VA_ARGS__); \
+ trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ ##__VA_ARGS__); \
} \
} while (0)
@@ -1016,6 +1115,7 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N')
#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O')
#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D')
+#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned char>(0))
@@ -1023,9 +1123,12 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned char>(1 << 1))
#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned char>(1 << 2))
#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned char>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned char>(1 << 6))
#define TRACE_EVENT_FLAG_SCOPE_MASK (static_cast<unsigned char>( \
- TRACE_EVENT_FLAG_SCOPE_OFFSET | (TRACE_EVENT_FLAG_SCOPE_OFFSET << 1)))
+ TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
// Type values for identifying types in the TraceValue union.
#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
@@ -1243,7 +1346,7 @@ static inline void SetTraceValue(const base::TimeTicks arg,
// pointers to the internal c_str and pass through to the tracing API,
// the arg_values must live throughout these procedures.
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1253,7 +1356,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const base::TimeTicks& timestamp,
unsigned char flags,
const char* arg1_name,
- const scoped_refptr<base::debug::ConvertableToTraceFormat>& arg1_val) {
+ const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+ arg1_val) {
const int num_args = 1;
unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
@@ -1262,7 +1366,7 @@ AddTraceEventWithThreadIdAndTimestamp(
}
template<class ARG1_TYPE>
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1274,7 +1378,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const char* arg1_name,
const ARG1_TYPE& arg1_val,
const char* arg2_name,
- const scoped_refptr<base::debug::ConvertableToTraceFormat>& arg2_val) {
+ const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+ arg2_val) {
const int num_args = 2;
const char* arg_names[2] = { arg1_name, arg2_name };
@@ -1283,7 +1388,8 @@ AddTraceEventWithThreadIdAndTimestamp(
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
arg_types[1] = TRACE_VALUE_TYPE_CONVERTABLE;
- scoped_refptr<base::debug::ConvertableToTraceFormat> convertable_values[2];
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ convertable_values[2];
convertable_values[1] = arg2_val;
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
@@ -1292,7 +1398,7 @@ AddTraceEventWithThreadIdAndTimestamp(
}
template<class ARG2_TYPE>
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1302,7 +1408,7 @@ AddTraceEventWithThreadIdAndTimestamp(
const base::TimeTicks& timestamp,
unsigned char flags,
const char* arg1_name,
- const scoped_refptr<base::debug::ConvertableToTraceFormat>& arg1_val,
+ const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
const char* arg2_name,
const ARG2_TYPE& arg2_val) {
const int num_args = 2;
@@ -1314,7 +1420,8 @@ AddTraceEventWithThreadIdAndTimestamp(
arg_values[0] = 0;
SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
- scoped_refptr<base::debug::ConvertableToTraceFormat> convertable_values[2];
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ convertable_values[2];
convertable_values[0] = arg1_val;
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
@@ -1322,7 +1429,7 @@ AddTraceEventWithThreadIdAndTimestamp(
num_args, arg_names, arg_types, arg_values, convertable_values, flags);
}
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1332,22 +1439,23 @@ AddTraceEventWithThreadIdAndTimestamp(
const base::TimeTicks& timestamp,
unsigned char flags,
const char* arg1_name,
- const scoped_refptr<base::debug::ConvertableToTraceFormat>& arg1_val,
+ const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
const char* arg2_name,
- const scoped_refptr<base::debug::ConvertableToTraceFormat>& arg2_val) {
+ const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+ arg2_val) {
const int num_args = 2;
const char* arg_names[2] = { arg1_name, arg2_name };
unsigned char arg_types[2] =
{ TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE };
- scoped_refptr<base::debug::ConvertableToTraceFormat> convertable_values[2] =
- { arg1_val, arg2_val };
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ convertable_values[2] = {arg1_val, arg2_val};
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
phase, category_group_enabled, name, id, thread_id, timestamp,
num_args, arg_names, arg_types, NULL, convertable_values, flags);
}
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1361,20 +1469,20 @@ AddTraceEventWithThreadIdAndTimestamp(
kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
}
-static inline base::debug::TraceEventHandle AddTraceEvent(
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
unsigned char flags) {
- int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+ const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ const base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
name, id, thread_id, now, flags);
}
template<class ARG1_TYPE>
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1395,7 +1503,7 @@ AddTraceEventWithThreadIdAndTimestamp(
}
template<class ARG1_TYPE>
-static inline base::debug::TraceEventHandle AddTraceEvent(
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
@@ -1411,7 +1519,7 @@ static inline base::debug::TraceEventHandle AddTraceEvent(
}
template<class ARG1_TYPE, class ARG2_TYPE>
-static inline base::debug::TraceEventHandle
+static inline base::trace_event::TraceEventHandle
AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
@@ -1436,7 +1544,7 @@ AddTraceEventWithThreadIdAndTimestamp(
}
template<class ARG1_TYPE, class ARG2_TYPE>
-static inline base::debug::TraceEventHandle AddTraceEvent(
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
@@ -1468,7 +1576,7 @@ class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
void Initialize(const unsigned char* category_group_enabled,
const char* name,
- base::debug::TraceEventHandle event_handle) {
+ base::trace_event::TraceEventHandle event_handle) {
data_.category_group_enabled = category_group_enabled;
data_.name = name;
data_.event_handle = event_handle;
@@ -1484,7 +1592,7 @@ class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
struct Data {
const unsigned char* category_group_enabled;
const char* name;
- base::debug::TraceEventHandle event_handle;
+ base::trace_event::TraceEventHandle event_handle;
};
Data* p_data_;
Data data_;
@@ -1499,7 +1607,7 @@ class TRACE_EVENT_API_CLASS_EXPORT ScopedTraceBinaryEfficient {
private:
const unsigned char* category_group_enabled_;
const char* name_;
- base::debug::TraceEventHandle event_handle_;
+ base::trace_event::TraceEventHandle event_handle_;
};
// This macro generates less code then TRACE_EVENT0 but is also
@@ -1545,7 +1653,7 @@ class TraceEventSamplingStateScope {
} // namespace trace_event_internal
namespace base {
-namespace debug {
+namespace trace_event {
template<typename IDType> class TraceScopedTrackableObject {
public:
@@ -1573,7 +1681,7 @@ template<typename IDType> class TraceScopedTrackableObject {
DISALLOW_COPY_AND_ASSIGN(TraceScopedTrackableObject);
};
-} // namespace debug
-} // namespace base
+} // namespace trace_event
+} // namespace base
-#endif /* BASE_DEBUG_TRACE_EVENT_H_ */
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_H_
diff --git a/chromium/base/debug/trace_event_android.cc b/chromium/base/trace_event/trace_event_android.cc
index f08fffca35f..26bd0c777d4 100644
--- a/chromium/base/debug/trace_event_android.cc
+++ b/chromium/base/trace_event/trace_event_android.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_impl.h"
+#include "base/trace_event/trace_event_impl.h"
#include <fcntl.h>
-#include "base/debug/trace_event.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
namespace {
@@ -24,8 +24,8 @@ void WriteEvent(
unsigned long long id,
const char** arg_names,
const unsigned char* arg_types,
- const base::debug::TraceEvent::TraceValue* arg_values,
- const scoped_refptr<base::debug::ConvertableToTraceFormat>*
+ const base::trace_event::TraceEvent::TraceValue* arg_values,
+ const scoped_refptr<base::trace_event::ConvertableToTraceFormat>*
convertable_values,
unsigned char flags) {
std::string out = base::StringPrintf("%c|%d|%s", phase, getpid(), name);
@@ -33,7 +33,8 @@ void WriteEvent(
base::StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
out += '|';
- for (int i = 0; i < base::debug::kTraceMaxNumArgs && arg_names[i]; ++i) {
+ for (int i = 0; i < base::trace_event::kTraceMaxNumArgs && arg_names[i];
+ ++i) {
if (i)
out += ';';
out += arg_names[i];
@@ -42,8 +43,8 @@ void WriteEvent(
if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
convertable_values[i]->AppendAsTraceFormat(&out);
} else {
- base::debug::TraceEvent::AppendValueAsJSON(
- arg_types[i], arg_values[i], &out);
+ base::trace_event::TraceEvent::AppendValueAsJSON(arg_types[i],
+ arg_values[i], &out);
}
// Remove the quotes which may confuse the atrace script.
ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
@@ -65,7 +66,7 @@ void NoOpOutputCallback(base::WaitableEvent* complete_event,
complete_event->Signal();
}
-void EndChromeTracing(base::debug::TraceLog* trace_log,
+void EndChromeTracing(base::trace_event::TraceLog* trace_log,
base::WaitableEvent* complete_event) {
trace_log->SetDisabled();
// Delete the buffered trace events as they have been sent to atrace.
@@ -75,7 +76,7 @@ void EndChromeTracing(base::debug::TraceLog* trace_log,
} // namespace
namespace base {
-namespace debug {
+namespace trace_event {
// These functions support Android systrace.py when 'webview' category is
// traced. With the new adb_profile_chrome, we may have two phases:
@@ -113,7 +114,7 @@ void TraceLog::StopATrace() {
Thread end_chrome_tracing_thread("end_chrome_tracing");
WaitableEvent complete_event(false, false);
end_chrome_tracing_thread.Start();
- end_chrome_tracing_thread.message_loop()->PostTask(
+ end_chrome_tracing_thread.task_runner()->PostTask(
FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this),
Unretained(&complete_event)));
complete_event.Wait();
@@ -195,5 +196,5 @@ void TraceLog::AddClockSyncMetadataEvent() {
close(atrace_fd);
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_argument.cc b/chromium/base/trace_event/trace_event_argument.cc
index 90e924f119e..88b1879b8b3 100644
--- a/chromium/base/debug/trace_event_argument.cc
+++ b/chromium/base/trace_event/trace_event_argument.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/json/json_writer.h"
#include "base/values.h"
namespace base {
-namespace debug {
+namespace trace_event {
TracedValue::TracedValue() : root_(new DictionaryValue()) {
stack_.push_back(root_.get());
@@ -34,19 +34,19 @@ void TracedValue::SetString(const char* name, const std::string& value) {
GetCurrentDictionary()->SetString(name, value);
}
-void TracedValue::SetValue(const char* name, Value* value) {
- GetCurrentDictionary()->Set(name, value);
+void TracedValue::SetValue(const char* name, scoped_ptr<Value> value) {
+ GetCurrentDictionary()->Set(name, value.Pass());
}
void TracedValue::BeginDictionary(const char* name) {
DictionaryValue* dictionary = new DictionaryValue();
- GetCurrentDictionary()->Set(name, dictionary);
+ GetCurrentDictionary()->Set(name, make_scoped_ptr(dictionary));
stack_.push_back(dictionary);
}
void TracedValue::BeginArray(const char* name) {
ListValue* array = new ListValue();
- GetCurrentDictionary()->Set(name, array);
+ GetCurrentDictionary()->Set(name, make_scoped_ptr(array));
stack_.push_back(array);
}
@@ -113,5 +113,5 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const {
DCHECK_EQ(1u, stack_.size()) << tmp;
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_argument.h b/chromium/base/trace_event/trace_event_argument.h
index 98f1bcf2fc9..d86cfd1f82a 100644
--- a/chromium/base/debug/trace_event_argument.h
+++ b/chromium/base/trace_event/trace_event_argument.h
@@ -2,21 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEBUG_TRACE_EVENT_ARGUMENT_H_
-#define BASE_DEBUG_TRACE_EVENT_ARGUMENT_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
#include <string>
#include <vector>
-#include "base/debug/trace_event.h"
#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
namespace base {
class DictionaryValue;
class ListValue;
class Value;
-namespace debug {
+namespace trace_event {
class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
public:
@@ -29,7 +29,7 @@ class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
void SetDouble(const char* name, double);
void SetBoolean(const char* name, bool value);
void SetString(const char* name, const std::string& value);
- void SetValue(const char* name, Value* value);
+ void SetValue(const char* name, scoped_ptr<Value> value);
void BeginDictionary(const char* name);
void BeginArray(const char* name);
@@ -49,11 +49,11 @@ class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
ListValue* GetCurrentArray();
scoped_ptr<base::Value> root_;
- std::vector<Value*> stack_;
+ std::vector<Value*> stack_; // Weak references.
DISALLOW_COPY_AND_ASSIGN(TracedValue);
};
-} // namespace debug
+} // namespace trace_event
} // namespace base
-#endif // BASE_DEBUG_TRACE_EVENT_ARGUMENT_H_
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
diff --git a/chromium/base/debug/trace_event_argument_unittest.cc b/chromium/base/trace_event/trace_event_argument_unittest.cc
index 06a7697f082..c59910e4465 100644
--- a/chromium/base/debug/trace_event_argument_unittest.cc
+++ b/chromium/base/trace_event/trace_event_argument_unittest.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
-namespace debug {
+namespace trace_event {
TEST(TraceEventArgumentTest, FlatDictionary) {
scoped_refptr<TracedValue> value = new TracedValue();
@@ -49,5 +49,5 @@ TEST(TraceEventArgumentTest, Hierarchy) {
json);
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/trace_event/trace_event_etw_export_win.cc b/chromium/base/trace_event/trace_event_etw_export_win.cc
new file mode 100644
index 00000000000..28c154c1647
--- /dev/null
+++ b/chromium/base/trace_event/trace_event_etw_export_win.cc
@@ -0,0 +1,251 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_etw_export_win.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// The GetProcAddress technique is borrowed from
+// https://github.com/randomascii/main/tree/master/xperf/ETWProviders
+//
+// EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
+// We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
+// implement these functions locally instead of using the import library, and
+// can therefore still run on Windows XP.
+#define EVNTAPI __stdcall
+// Include the event register/write/unregister macros compiled from the manifest
+// file. Note that this includes evntprov.h which requires a Vista+ Windows SDK.
+//
+// In SHARED_INTERMEDIATE_DIR.
+#include "base/trace_event/etw_manifest/chrome_events_win.h" // NOLINT
+
+namespace {
+// Typedefs for use with GetProcAddress
+typedef ULONG(__stdcall* tEventRegister)(LPCGUID ProviderId,
+ PENABLECALLBACK EnableCallback,
+ PVOID CallbackContext,
+ PREGHANDLE RegHandle);
+typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle,
+ PCEVENT_DESCRIPTOR EventDescriptor,
+ ULONG UserDataCount,
+ PEVENT_DATA_DESCRIPTOR UserData);
+typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
+
+tEventRegister EventRegisterProc = nullptr;
+tEventWrite EventWriteProc = nullptr;
+tEventUnregister EventUnregisterProc = nullptr;
+} // namespace
+
+// Redirector function for EventRegister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventRegister(LPCGUID ProviderId,
+ PENABLECALLBACK EnableCallback,
+ PVOID CallbackContext,
+ PREGHANDLE RegHandle) {
+ if (EventRegisterProc)
+ return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
+ RegHandle);
+ return 0;
+}
+
+// Redirector function for EventWrite. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventWrite(REGHANDLE RegHandle,
+ PCEVENT_DESCRIPTOR EventDescriptor,
+ ULONG UserDataCount,
+ PEVENT_DATA_DESCRIPTOR UserData) {
+ if (EventWriteProc)
+ return EventWriteProc(RegHandle, EventDescriptor, UserDataCount, UserData);
+ return 0;
+}
+
+// Redirector function for EventUnregister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
+ if (EventUnregisterProc)
+ return EventUnregisterProc(RegHandle);
+ return 0;
+}
+
+namespace base {
+namespace trace_event {
+
+TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
+ // Find Advapi32.dll. This should always succeed.
+ HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
+ if (AdvapiDLL) {
+ // Try to find the ETW functions. This will fail on XP.
+ EventRegisterProc = reinterpret_cast<tEventRegister>(
+ ::GetProcAddress(AdvapiDLL, "EventRegister"));
+ EventWriteProc = reinterpret_cast<tEventWrite>(
+ ::GetProcAddress(AdvapiDLL, "EventWrite"));
+ EventUnregisterProc = reinterpret_cast<tEventUnregister>(
+ ::GetProcAddress(AdvapiDLL, "EventUnregister"));
+
+ // Register the ETW provider. If registration fails then the event logging
+ // calls will fail (on XP this call will do nothing).
+ EventRegisterChrome();
+ }
+}
+
+TraceEventETWExport::~TraceEventETWExport() {
+ EventUnregisterChrome();
+}
+
+// static
+TraceEventETWExport* TraceEventETWExport::GetInstance() {
+ return Singleton<TraceEventETWExport,
+ StaticMemorySingletonTraits<TraceEventETWExport>>::get();
+}
+
+// static
+void TraceEventETWExport::EnableETWExport() {
+ if (GetInstance())
+ GetInstance()->ETWExportEnabled_ = true;
+}
+
+// static
+void TraceEventETWExport::DisableETWExport() {
+ if (GetInstance())
+ GetInstance()->ETWExportEnabled_ = false;
+}
+
+// static
+void TraceEventETWExport::AddEvent(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
+ // We bail early in case exporting is disabled or no consumer is listening.
+ if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+ !EventEnabledChromeEvent())
+ return;
+
+ const char* phase_string = nullptr;
+ // Space to store the phase identifier and null-terminator, when needed.
+ char phase_buffer[2];
+ switch (phase) {
+ case TRACE_EVENT_PHASE_BEGIN:
+ phase_string = "Begin";
+ break;
+ case TRACE_EVENT_PHASE_END:
+ phase_string = "End";
+ break;
+ case TRACE_EVENT_PHASE_COMPLETE:
+ phase_string = "Complete";
+ break;
+ case TRACE_EVENT_PHASE_INSTANT:
+ phase_string = "Instant";
+ break;
+ case TRACE_EVENT_PHASE_ASYNC_BEGIN:
+ phase_string = "Async Begin";
+ break;
+ case TRACE_EVENT_PHASE_ASYNC_STEP_INTO:
+ phase_string = "Async Step Into";
+ break;
+ case TRACE_EVENT_PHASE_ASYNC_STEP_PAST:
+ phase_string = "Async Step Past";
+ break;
+ case TRACE_EVENT_PHASE_ASYNC_END:
+ phase_string = "Async End";
+ break;
+ case TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN:
+ phase_string = "Nestable Async Begin";
+ break;
+ case TRACE_EVENT_PHASE_NESTABLE_ASYNC_END:
+ phase_string = "Nestable Async End";
+ break;
+ case TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT:
+ phase_string = "Nestable Async Instant";
+ break;
+ case TRACE_EVENT_PHASE_FLOW_BEGIN:
+ phase_string = "Phase Flow Begin";
+ break;
+ case TRACE_EVENT_PHASE_FLOW_STEP:
+ phase_string = "Phase Flow Step";
+ break;
+ case TRACE_EVENT_PHASE_FLOW_END:
+ phase_string = "Phase Flow End";
+ break;
+ case TRACE_EVENT_PHASE_METADATA:
+ phase_string = "Phase Metadata";
+ break;
+ case TRACE_EVENT_PHASE_COUNTER:
+ phase_string = "Phase Counter";
+ break;
+ case TRACE_EVENT_PHASE_SAMPLE:
+ phase_string = "Phase Sample";
+ break;
+ case TRACE_EVENT_PHASE_CREATE_OBJECT:
+ phase_string = "Phase Create Object";
+ break;
+ case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT:
+ phase_string = "Phase Snapshot Object";
+ break;
+ case TRACE_EVENT_PHASE_DELETE_OBJECT:
+ phase_string = "Phase Delete Object";
+ break;
+ default:
+ phase_buffer[0] = phase;
+ phase_buffer[1] = 0;
+ phase_string = phase_buffer;
+ break;
+ }
+
+ std::string arg_values_string[3];
+ for (int i = 0; i < num_args; i++) {
+ if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+ // Temporarily do nothing here. This function consumes 1/3 to 1/2 of
+ // *total* process CPU time when ETW tracing, and many of the strings
+ // created exceed WPA's 4094 byte limit and are shown as:
+ // "Unable to parse data". See crbug.com/488257
+ //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
+ } else {
+ TraceEvent::TraceValue trace_event;
+ trace_event.as_uint = arg_values[i];
+ TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
+ arg_values_string + i);
+ }
+ }
+
+ EventWriteChromeEvent(
+ name, phase_string, num_args > 0 ? arg_names[0] : "",
+ arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
+ arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
+ arg_values_string[2].c_str());
+}
+
+// static
+void TraceEventETWExport::AddCustomEvent(const char* name,
+ char const* phase,
+ const char* arg_name_1,
+ const char* arg_value_1,
+ const char* arg_name_2,
+ const char* arg_value_2,
+ const char* arg_name_3,
+ const char* arg_value_3) {
+ if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+ !EventEnabledChromeEvent())
+ return;
+
+ EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
+ arg_value_2, arg_name_3, arg_value_3);
+}
+
+void TraceEventETWExport::Resurrect() {
+ StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/trace_event_etw_export_win.h b/chromium/base/trace_event/trace_event_etw_export_win.h
new file mode 100644
index 00000000000..eefe8204812
--- /dev/null
+++ b/chromium/base/trace_event/trace_event_etw_export_win.h
@@ -0,0 +1,75 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the Windows-specific exporting to ETW.
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT TraceEventETWExport {
+ public:
+ ~TraceEventETWExport();
+
+ // Retrieves the singleton.
+ // Note that this may return NULL post-AtExit processing.
+ static TraceEventETWExport* GetInstance();
+
+ // Enables/disables exporting of events to ETW. If disabled,
+ // AddEvent and AddCustomEvent will simply return when called.
+ static void EnableETWExport();
+ static void DisableETWExport();
+
+ static bool isETWExportEnabled() {
+ return (GetInstance() && GetInstance()->ETWExportEnabled_);
+ }
+
+ // Exports an event to ETW. This is mainly used in
+ // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
+ static void AddEvent(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values);
+
+ // Exports an event to ETW. This should be used when exporting an event only
+ // to ETW. Supports three arguments to be passed to ETW.
+ // TODO(georgesak): Allow different providers.
+ static void AddCustomEvent(const char* name,
+ char const* phase,
+ const char* arg_name_1,
+ const char* arg_value_1,
+ const char* arg_name_2,
+ const char* arg_value_2,
+ const char* arg_name_3,
+ const char* arg_value_3);
+
+ void Resurrect();
+
+ private:
+ bool ETWExportEnabled_;
+ // Ensure only the provider can construct us.
+ friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
+ TraceEventETWExport();
+
+ DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
diff --git a/chromium/base/debug/trace_event_impl.cc b/chromium/base/trace_event/trace_event_impl.cc
index ce62766da3d..5ae7fb2572f 100644
--- a/chromium/base/debug/trace_event_impl.cc
+++ b/chromium/base/trace_event/trace_event_impl.cc
@@ -2,22 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_impl.h"
+#include "base/trace_event/trace_event_impl.h"
#include <algorithm>
+#include <cmath>
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_synthetic_delay.h"
-#include "base/float_util.h"
#include "base/format_macros.h"
#include "base/json/string_escape.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
#include "base/process/process_metrics.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -30,19 +28,24 @@
#include "base/synchronization/waitable_event.h"
#include "base/sys_info.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/worker_pool.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
#if defined(OS_WIN)
-#include "base/debug/trace_event_win.h"
+#include "base/trace_event/trace_event_etw_export_win.h"
+#include "base/trace_event/trace_event_win.h"
#endif
class DeleteTraceLogForTesting {
public:
static void Delete() {
- Singleton<base::debug::TraceLog,
- LeakySingletonTraits<base::debug::TraceLog> >::OnExit(0);
+ Singleton<base::trace_event::TraceLog,
+ LeakySingletonTraits<base::trace_event::TraceLog>>::OnExit(0);
}
};
@@ -50,7 +53,7 @@ class DeleteTraceLogForTesting {
BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
namespace base {
-namespace debug {
+namespace trace_event {
namespace {
@@ -73,7 +76,7 @@ const size_t kTraceEventVectorBigBufferChunks =
512000000 / kTraceBufferChunkSize;
const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
-const size_t kTraceEventBatchChunks = 1000 / kTraceBufferChunkSize;
+const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
// Can store results for 30 seconds with 1 ms sampling interval.
const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
@@ -430,25 +433,22 @@ scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
// and unlocks at the end of scope if locked.
class TraceLog::OptionalAutoLock {
public:
- explicit OptionalAutoLock(Lock& lock)
- : lock_(lock),
- locked_(false) {
- }
+ explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
~OptionalAutoLock() {
if (locked_)
- lock_.Release();
+ lock_->Release();
}
void EnsureAcquired() {
if (!locked_) {
- lock_.Acquire();
+ lock_->Acquire();
locked_ = true;
}
}
private:
- Lock& lock_;
+ Lock* lock_;
bool locked_;
DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
};
@@ -624,7 +624,7 @@ void TraceEvent::Reset() {
void TraceEvent::UpdateDuration(const TimeTicks& now,
const TimeTicks& thread_now) {
- DCHECK(duration_.ToInternalValue() == -1);
+ DCHECK_EQ(duration_.ToInternalValue(), -1);
duration_ = now - timestamp_;
thread_duration_ = thread_now - thread_timestamp_;
}
@@ -648,7 +648,7 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
// should be made into a common method.
std::string real;
double val = value.as_double;
- if (IsFinite(val)) {
+ if (std::isfinite(val)) {
real = DoubleToString(val);
// Ensure that the number has a .0 if there's no decimal or 'e'. This
// makes sure that when we read the JSON back, it's interpreted as a
@@ -666,7 +666,7 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
// "-.1" bad "-0.1" good
real.insert(1, "0");
}
- } else if (IsNaN(val)){
+ } else if (std::isnan(val)){
// The JSON spec doesn't allow NaN and Infinity (since these are
// objects in EcmaScript). Use strings instead.
real = "\"NaN\"";
@@ -701,13 +701,13 @@ void TraceEvent::AppendAsJSON(std::string* out) const {
// Category group checked at category creation time.
DCHECK(!strchr(name_, '"'));
StringAppendF(out,
- "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ","
- "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{",
- TraceLog::GetCategoryGroupName(category_group_enabled_),
+ "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ","
+ "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{",
process_id,
thread_id_,
time_int64,
phase_,
+ TraceLog::GetCategoryGroupName(category_group_enabled_),
name_);
// Output argument names and values, stop at first NULL argument name.
@@ -742,6 +742,11 @@ void TraceEvent::AppendAsJSON(std::string* out) const {
StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
}
+ // Output async tts marker field if flag is set.
+ if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
+ StringAppendF(out, ", \"use_async_tts\":1");
+ }
+
// If id_ is set, print it out as a hex string so we don't loose any
// bits (it might be a 64-bit pointer).
if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
@@ -1185,6 +1190,12 @@ void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
// find the generation mismatch and delete this buffer soon.
}
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {
+}
+
+TraceLogStatus::~TraceLogStatus() {
+}
+
// static
TraceLog* TraceLog::GetInstance() {
return Singleton<TraceLog, LeakySingletonTraits<TraceLog> >::get();
@@ -1205,7 +1216,8 @@ TraceLog::TraceLog()
event_callback_category_filter_(
CategoryFilter::kDefaultCategoryFilterString),
thread_shared_chunk_index_(0),
- generation_(0) {
+ generation_(0),
+ use_worker_thread_(false) {
// Trace is enabled or disabled on one thread while other threads are
// accessing the enabled flag. We don't care whether edge-case events are
// traced or not, so we allow races on the enabled flag to keep the trace
@@ -1287,6 +1299,11 @@ void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
if (event_callback_ &&
event_callback_category_filter_.IsCategoryGroupEnabled(category_group))
enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
+#if defined(OS_WIN)
+ if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
+ enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+#endif
+
g_category_group_enabled[category_index] = enabled_flag;
}
@@ -1395,7 +1412,7 @@ void TraceLog::SetEnabled(const CategoryFilter& category_filter,
AutoLock lock(lock_);
// Can't enable tracing when Flush() is in progress.
- DCHECK(!flush_message_loop_proxy_.get());
+ DCHECK(!flush_task_runner_);
InternalTraceOptions new_options =
GetInternalOptionsFromTraceOptions(options);
@@ -1586,10 +1603,12 @@ bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
return it != enabled_state_observer_list_.end();
}
-float TraceLog::GetBufferPercentFull() const {
+TraceLogStatus TraceLog::GetStatus() const {
AutoLock lock(lock_);
- return static_cast<float>(static_cast<double>(logged_events_->Size()) /
- logged_events_->Capacity());
+ TraceLogStatus result;
+ result.event_capacity = logged_events_->Capacity();
+ result.event_count = logged_events_->Size();
+ return result;
}
bool TraceLog::BufferIsFull() const {
@@ -1667,16 +1686,18 @@ void TraceLog::SetEventCallbackDisabled() {
}
// Flush() works as the following:
-// 1. Flush() is called in threadA whose message loop is saved in
-// flush_message_loop_proxy_;
-// 2. If thread_message_loops_ is not empty, threadA posts task to each message
+// 1. Flush() is called in thread A whose task runner is saved in
+// flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
// loop to flush the thread local buffers; otherwise finish the flush;
// 3. FlushCurrentThread() deletes the thread local event buffer:
// - The last batch of events of the thread are flushed into the main buffer;
// - The message loop will be removed from thread_message_loops_;
// If this is the last message loop, finish the flush;
// 4. If any thread hasn't finish its flush in time, finish the flush.
-void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
+void TraceLog::Flush(const TraceLog::OutputCallback& cb,
+ bool use_worker_thread) {
+ use_worker_thread_ = use_worker_thread;
if (IsEnabled()) {
// Can't flush when tracing is enabled because otherwise PostTask would
// - generate more trace events;
@@ -1695,9 +1716,11 @@ void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
thread_message_loop_task_runners;
{
AutoLock lock(lock_);
- DCHECK(!flush_message_loop_proxy_.get());
- flush_message_loop_proxy_ = MessageLoopProxy::current();
- DCHECK(!thread_message_loops_.size() || flush_message_loop_proxy_.get());
+ DCHECK(!flush_task_runner_);
+ flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+ ? ThreadTaskRunnerHandle::Get()
+ : nullptr;
+ DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
flush_output_callback_ = cb;
if (thread_shared_chunk_) {
@@ -1720,7 +1743,7 @@ void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
FROM_HERE,
Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
}
- flush_message_loop_proxy_->PostDelayedTask(
+ flush_task_runner_->PostDelayedTask(
FROM_HERE,
Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
@@ -1730,6 +1753,7 @@ void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
FinishFlush(generation);
}
+// Usually it runs on a different thread.
void TraceLog::ConvertTraceEventsToTraceFormat(
scoped_ptr<TraceBuffer> logged_events,
const TraceLog::OutputCallback& flush_output_callback) {
@@ -1744,19 +1768,17 @@ void TraceLog::ConvertTraceEventsToTraceFormat(
scoped_refptr<RefCountedString> json_events_str_ptr =
new RefCountedString();
- for (size_t i = 0; i < kTraceEventBatchChunks; ++i) {
+ while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) {
const TraceBufferChunk* chunk = logged_events->NextChunk();
- if (!chunk) {
- has_more_events = false;
+ has_more_events = chunk != NULL;
+ if (!chunk)
break;
- }
for (size_t j = 0; j < chunk->size(); ++j) {
- if (i > 0 || j > 0)
- json_events_str_ptr->data().append(",");
+ if (json_events_str_ptr->size())
+ json_events_str_ptr->data().append(",\n");
chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()));
}
}
-
flush_output_callback.Run(json_events_str_ptr, has_more_events);
} while (has_more_events);
}
@@ -1775,11 +1797,21 @@ void TraceLog::FinishFlush(int generation) {
UseNextTraceBuffer();
thread_message_loops_.clear();
- flush_message_loop_proxy_ = NULL;
+ flush_task_runner_ = NULL;
flush_output_callback = flush_output_callback_;
flush_output_callback_.Reset();
}
+ if (use_worker_thread_ &&
+ WorkerPool::PostTask(
+ FROM_HERE,
+ Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+ Passed(&previous_logged_events),
+ flush_output_callback),
+ true)) {
+ return;
+ }
+
ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
flush_output_callback);
}
@@ -1788,7 +1820,7 @@ void TraceLog::FinishFlush(int generation) {
void TraceLog::FlushCurrentThread(int generation) {
{
AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get()) {
+ if (!CheckGeneration(generation) || !flush_task_runner_) {
// This is late. The corresponding flush has finished.
return;
}
@@ -1798,19 +1830,18 @@ void TraceLog::FlushCurrentThread(int generation) {
delete thread_local_event_buffer_.Get();
AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get() ||
+ if (!CheckGeneration(generation) || !flush_task_runner_ ||
thread_message_loops_.size())
return;
- flush_message_loop_proxy_->PostTask(
- FROM_HERE,
- Bind(&TraceLog::FinishFlush, Unretained(this), generation));
+ flush_task_runner_->PostTask(
+ FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
}
void TraceLog::OnFlushTimeout(int generation) {
{
AutoLock lock(lock_);
- if (!CheckGeneration(generation) || !flush_message_loop_proxy_.get()) {
+ if (!CheckGeneration(generation) || !flush_task_runner_) {
// Flush has finished before timeout.
return;
}
@@ -1900,11 +1931,14 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
DCHECK(name);
+ DCHECK(!timestamp.is_null());
if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
- id ^= process_id_hash_;
+ id = MangleEventId(id);
- TimeTicks now = OffsetTimestamp(timestamp);
+ TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+ TimeTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
+ OffsetNow() : offset_event_timestamp;
TimeTicks thread_now = ThreadNow();
ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
@@ -1963,10 +1997,19 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
}
}
+#if defined(OS_WIN)
+ // This is done sooner rather than later, to avoid creating the event and
+ // acquiring the lock, which is not needed for ETW as it's already threadsafe.
+ if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
+ TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
+ num_args, arg_names, arg_types, arg_values,
+ convertable_values);
+#endif // OS_WIN
+
std::string console_message;
if (*category_group_enabled &
(ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
- OptionalAutoLock lock(lock_);
+ OptionalAutoLock lock(&lock_);
TraceEvent* trace_event = NULL;
if (thread_local_event_buffer) {
@@ -1977,8 +2020,8 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
}
if (trace_event) {
- trace_event->Initialize(thread_id, now, thread_now, phase,
- category_group_enabled, name, id,
+ trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
+ phase, category_group_enabled, name, id,
num_args, arg_names, arg_types, arg_values,
convertable_values, flags);
@@ -2016,7 +2059,7 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
EventCallback event_callback = reinterpret_cast<EventCallback>(
subtle::NoBarrier_Load(&event_callback_));
if (event_callback) {
- event_callback(now,
+ event_callback(offset_event_timestamp,
phase == TRACE_EVENT_PHASE_COMPLETE ?
TRACE_EVENT_PHASE_BEGIN : phase,
category_group_enabled, name, id,
@@ -2119,7 +2162,7 @@ void TraceLog::UpdateTraceEventDuration(
std::string console_message;
if (*category_group_enabled & ENABLED_FOR_RECORDING) {
- OptionalAutoLock lock(lock_);
+ OptionalAutoLock lock(&lock_);
TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
if (trace_event) {
@@ -2169,6 +2212,10 @@ void TraceLog::CancelWatchEvent() {
watch_event_callback_.Reset();
}
+uint64 TraceLog::MangleEventId(uint64 id) {
+ return id ^ process_id_hash_;
+}
+
void TraceLog::AddMetadataEventsWhileLocked() {
lock_.AssertAcquired();
@@ -2350,24 +2397,6 @@ bool CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
str.at(str.length() - 1) == ' ';
}
-bool CategoryFilter::DoesCategoryGroupContainCategory(
- const char* category_group,
- const char* category) const {
- DCHECK(category);
- CStringTokenizer category_group_tokens(category_group,
- category_group + strlen(category_group), ",");
- while (category_group_tokens.GetNext()) {
- std::string category_group_token = category_group_tokens.token();
- // Don't allow empty tokens, nor tokens with leading or trailing space.
- DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
- category_group_token))
- << "Disallowed category string";
- if (MatchPattern(category_group_token.c_str(), category))
- return true;
- }
- return false;
-}
-
CategoryFilter::CategoryFilter(const std::string& filter_string) {
if (!filter_string.empty())
Initialize(filter_string);
@@ -2475,30 +2504,78 @@ bool CategoryFilter::IsCategoryGroupEnabled(
const char* category_group_name) const {
// TraceLog should call this method only as part of enabling/disabling
// categories.
+
+ bool had_enabled_by_default = false;
+ DCHECK(category_group_name);
+ CStringTokenizer category_group_tokens(
+ category_group_name, category_group_name + strlen(category_group_name),
+ ",");
+ while (category_group_tokens.GetNext()) {
+ std::string category_group_token = category_group_tokens.token();
+ // Don't allow empty tokens, nor tokens with leading or trailing space.
+ DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+ category_group_token))
+ << "Disallowed category string";
+ if (IsCategoryEnabled(category_group_token.c_str())) {
+ return true;
+ }
+ if (!MatchPattern(category_group_token.c_str(),
+ TRACE_DISABLED_BY_DEFAULT("*")))
+ had_enabled_by_default = true;
+ }
+ // Do a second pass to check for explicitly disabled categories
+ // (those explicitly enabled have priority due to first pass).
+ category_group_tokens.Reset();
+ bool category_group_disabled = false;
+ while (category_group_tokens.GetNext()) {
+ std::string category_group_token = category_group_tokens.token();
+ for (StringList::const_iterator ci = excluded_.begin();
+ ci != excluded_.end(); ++ci) {
+ if (MatchPattern(category_group_token.c_str(), ci->c_str())) {
+ // Current token of category_group_name is present in excluded_list.
+ // Flag the exclusion and proceed further to check if any of the
+ // remaining categories of category_group_name is not present in the
+ // excluded_ list.
+ category_group_disabled = true;
+ break;
+ }
+ // One of the category of category_group_name is not present in
+ // excluded_ list. So, it has to be included_ list. Enable the
+ // category_group_name for recording.
+ category_group_disabled = false;
+ }
+ // One of the categories present in category_group_name is not present in
+ // excluded_ list. Implies this category_group_name group can be enabled
+ // for recording, since one of its groups is enabled for recording.
+ if (!category_group_disabled)
+ break;
+ }
+ // If the category group is not excluded, and there are no included patterns
+ // we consider this category group enabled, as long as it had categories
+ // other than disabled-by-default.
+ return !category_group_disabled &&
+ included_.empty() && had_enabled_by_default;
+}
+
+bool CategoryFilter::IsCategoryEnabled(const char* category_name) const {
StringList::const_iterator ci;
// Check the disabled- filters and the disabled-* wildcard first so that a
// "*" filter does not include the disabled.
for (ci = disabled_.begin(); ci != disabled_.end(); ++ci) {
- if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str()))
+ if (MatchPattern(category_name, ci->c_str()))
return true;
}
- if (DoesCategoryGroupContainCategory(category_group_name,
- TRACE_DISABLED_BY_DEFAULT("*")))
+
+ if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
return false;
for (ci = included_.begin(); ci != included_.end(); ++ci) {
- if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str()))
+ if (MatchPattern(category_name, ci->c_str()))
return true;
}
- for (ci = excluded_.begin(); ci != excluded_.end(); ++ci) {
- if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str()))
- return false;
- }
- // If the category group is not excluded, and there are no included patterns
- // we consider this pattern enabled.
- return included_.empty();
+ return false;
}
bool CategoryFilter::HasIncludedPatterns() const {
@@ -2539,7 +2616,7 @@ const CategoryFilter::StringList&
return delays_;
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
namespace trace_event_internal {
@@ -2547,7 +2624,7 @@ namespace trace_event_internal {
ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
const char* category_group, const char* name) {
// The single atom works because for now the category_group can only be "gpu".
- DCHECK(strcmp(category_group, "gpu") == 0);
+ DCHECK_EQ(strcmp(category_group, "gpu"), 0);
static TRACE_EVENT_API_ATOMIC_WORD atomic = 0;
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(
category_group, atomic, category_group_enabled_);
diff --git a/chromium/base/debug/trace_event_impl.h b/chromium/base/trace_event/trace_event_impl.h
index 6075e2dee78..50d33ca7da9 100644
--- a/chromium/base/debug/trace_event_impl.h
+++ b/chromium/base/trace_event/trace_event_impl.h
@@ -3,8 +3,8 @@
// found in the LICENSE file.
-#ifndef BASE_DEBUG_TRACE_EVENT_IMPL_H_
-#define BASE_DEBUG_TRACE_EVENT_IMPL_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
#include <stack>
#include <string>
@@ -18,6 +18,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -26,18 +27,19 @@
// Older style trace macros with explicit id and extra data
// Only these macros result in publishing data to ETW as currently implemented.
+// TODO(georgesak): Update/replace these with new ETW macros.
#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
- base::debug::TraceLog::AddTraceEventEtw( \
+ base::trace_event::TraceLog::AddTraceEventEtw( \
TRACE_EVENT_PHASE_BEGIN, \
name, reinterpret_cast<const void*>(id), extra)
#define TRACE_EVENT_END_ETW(name, id, extra) \
- base::debug::TraceLog::AddTraceEventEtw( \
+ base::trace_event::TraceLog::AddTraceEventEtw( \
TRACE_EVENT_PHASE_END, \
name, reinterpret_cast<const void*>(id), extra)
#define TRACE_EVENT_INSTANT_ETW(name, id, extra) \
- base::debug::TraceLog::AddTraceEventEtw( \
+ base::trace_event::TraceLog::AddTraceEventEtw( \
TRACE_EVENT_PHASE_INSTANT, \
name, reinterpret_cast<const void*>(id), extra)
@@ -49,7 +51,7 @@ namespace base {
class WaitableEvent;
class MessageLoop;
-namespace debug {
+namespace trace_event {
// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
// class must implement this interface.
@@ -320,8 +322,8 @@ class BASE_EXPORT CategoryFilter {
// categories are distinguished from included categories by the prefix '-'.
std::string ToString() const;
- // Determines whether category group would be enabled or
- // disabled by this category filter.
+ // Returns true if at least one category in the list is enabled by this
+ // category filter.
bool IsCategoryGroupEnabled(const char* category_group) const;
// Return a list of the synthetic delays specified in this category filter.
@@ -341,6 +343,9 @@ class BASE_EXPORT CategoryFilter {
private:
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, CategoryFilter);
+ // Returns true if category is enable according to this filter.
+ bool IsCategoryEnabled(const char* category_name) const;
+
static bool IsEmptyOrContainsLeadingOrTrailingWhitespace(
const std::string& str);
@@ -351,9 +356,6 @@ class BASE_EXPORT CategoryFilter {
void WriteString(const StringList& delays, std::string* out) const;
bool HasIncludedPatterns() const;
- bool DoesCategoryGroupContainCategory(const char* category_group,
- const char* category) const;
-
StringList included_;
StringList disabled_;
StringList excluded_;
@@ -420,6 +422,13 @@ struct BASE_EXPORT TraceOptions {
bool enable_systrace;
};
+struct BASE_EXPORT TraceLogStatus {
+ TraceLogStatus();
+ ~TraceLogStatus();
+ size_t event_capacity;
+ size_t event_count;
+};
+
class BASE_EXPORT TraceLog {
public:
enum Mode {
@@ -439,6 +448,8 @@ class BASE_EXPORT TraceLog {
ENABLED_FOR_MONITORING = 1 << 1,
// Category group enabled by SetEventCallbackEnabled().
ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+ // Category group enabled to export events to ETW.
+ ENABLED_FOR_ETW_EXPORT = 1 << 3
};
static TraceLog* GetInstance();
@@ -495,7 +506,7 @@ class BASE_EXPORT TraceLog {
void RemoveEnabledStateObserver(EnabledStateObserver* listener);
bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
- float GetBufferPercentFull() const;
+ TraceLogStatus GetStatus() const;
bool BufferIsFull() const;
// Not using base::Callback because of its limited by 7 parameters.
@@ -531,10 +542,11 @@ class BASE_EXPORT TraceLog {
// Due to the implementation of thread-local buffers, flush can't be
// done when tracing is enabled. If called when tracing is enabled, the
// callback will be called directly with (empty_string, false) to indicate
- // the end of this unsuccessful flush.
+ // the end of this unsuccessful flush. Flush does the serialization
+ // on the same thread if the caller doesn't set use_worker_thread explicitly.
typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
bool has_more_events)> OutputCallback;
- void Flush(const OutputCallback& cb);
+ void Flush(const OutputCallback& cb, bool use_worker_thread = false);
void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
// Called by TRACE_EVENT* macros, don't call this directly.
@@ -595,6 +607,8 @@ class BASE_EXPORT TraceLog {
int process_id() const { return process_id_; }
+ uint64 MangleEventId(uint64 id);
+
// Exposed for unittesting:
void WaitSamplingEventForTesting();
@@ -603,7 +617,6 @@ class BASE_EXPORT TraceLog {
static void DeleteForTesting();
// Allow tests to inspect TraceEvents.
- size_t GetEventsSize() const { return logged_events_->Size(); }
TraceEvent* GetEventByHandle(TraceEventHandle handle);
void SetProcessID(int process_id);
@@ -704,7 +717,9 @@ class BASE_EXPORT TraceLog {
// |generation| is used in the following callbacks to check if the callback
// is called for the flush of the current |logged_events_|.
void FlushCurrentThread(int generation);
- void ConvertTraceEventsToTraceFormat(scoped_ptr<TraceBuffer> logged_events,
+ // Usually it runs on a different thread.
+ static void ConvertTraceEventsToTraceFormat(
+ scoped_ptr<TraceBuffer> logged_events,
const TraceLog::OutputCallback& flush_output_callback);
void FinishFlush(int generation);
void OnFlushTimeout(int generation);
@@ -739,7 +754,6 @@ class BASE_EXPORT TraceLog {
// This lock protects accesses to thread_names_, thread_event_start_times_
// and thread_colors_.
Lock thread_info_lock_;
- int locked_line_;
Mode mode_;
int num_traces_recorded_;
scoped_ptr<TraceBuffer> logged_events_;
@@ -785,8 +799,8 @@ class BASE_EXPORT TraceLog {
ThreadLocalBoolean thread_is_in_trace_event_;
// Contains the message loops of threads that have had at least one event
- // added into the local event buffer. Not using MessageLoopProxy because we
- // need to know the life time of the message loops.
+ // added into the local event buffer. Not using SingleThreadTaskRunner
+ // because we need to know the life time of the message loops.
hash_set<MessageLoop*> thread_message_loops_;
// For events which can't be added into the thread local buffer, e.g. events
@@ -796,13 +810,14 @@ class BASE_EXPORT TraceLog {
// Set when asynchronous Flush is in progress.
OutputCallback flush_output_callback_;
- scoped_refptr<MessageLoopProxy> flush_message_loop_proxy_;
+ scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
subtle::AtomicWord generation_;
+ bool use_worker_thread_;
DISALLOW_COPY_AND_ASSIGN(TraceLog);
};
-} // namespace debug
+} // namespace trace_event
} // namespace base
-#endif // BASE_DEBUG_TRACE_EVENT_IMPL_H_
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
diff --git a/chromium/base/debug/trace_event_impl_constants.cc b/chromium/base/trace_event/trace_event_impl_constants.cc
index 8e014110b82..ffeacff3831 100644
--- a/chromium/base/debug/trace_event_impl_constants.cc
+++ b/chromium/base/trace_event/trace_event_impl_constants.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_impl.h"
+#include "base/trace_event/trace_event_impl.h"
namespace base {
-namespace debug {
+namespace trace_event {
// Enable everything but debug and test categories by default.
const char CategoryFilter::kDefaultCategoryFilterString[] = "-*Debug,-*Test";
@@ -24,5 +24,5 @@ const TraceLog::InternalTraceOptions
const TraceLog::InternalTraceOptions
TraceLog::kInternalRecordAsMuchAsPossible = 1 << 4;
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_memory.cc b/chromium/base/trace_event/trace_event_memory.cc
index 28318654750..89595890aec 100644
--- a/chromium/base/debug/trace_event_memory.cc
+++ b/chromium/base/trace_event/trace_event_memory.cc
@@ -2,20 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_memory.h"
+#include "base/trace_event/trace_event_memory.h"
#include "base/debug/leak_annotations.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
namespace base {
-namespace debug {
+namespace trace_event {
namespace {
@@ -26,13 +27,13 @@ const size_t kMaxScopeDepth = 16;
/////////////////////////////////////////////////////////////////////////////
// Holds a memory dump until the tracing system needs to serialize it.
-class MemoryDumpHolder : public base::debug::ConvertableToTraceFormat {
+class MemoryDumpHolder : public base::trace_event::ConvertableToTraceFormat {
public:
// Takes ownership of dump, which must be a JSON string, allocated with
// malloc() and NULL terminated.
explicit MemoryDumpHolder(char* dump) : dump_(dump) {}
- // base::debug::ConvertableToTraceFormat overrides:
+ // base::trace_event::ConvertableToTraceFormat overrides:
void AppendAsTraceFormat(std::string* out) const override {
AppendHeapProfileAsTraceFormat(dump_, out);
}
@@ -70,13 +71,12 @@ void DeleteStackOnThreadCleanup(void* value) {
delete stack;
}
-// Initializes the thread-local TraceMemoryStack pointer. Returns true on
-// success or if it is already initialized.
-bool InitThreadLocalStorage() {
+// Initializes the thread-local TraceMemoryStack pointer.
+void InitThreadLocalStorage() {
if (tls_trace_memory_stack.initialized())
- return true;
- // Initialize the thread-local storage key, returning true on success.
- return tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup);
+ return;
+ // Initialize the thread-local storage key.
+ tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup);
}
// Clean up thread-local-storage in the main thread.
@@ -144,11 +144,11 @@ int GetPseudoStack(int skip_count_ignored, void** stack_out) {
//////////////////////////////////////////////////////////////////////////////
TraceMemoryController::TraceMemoryController(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ scoped_refptr<SingleThreadTaskRunner> task_runner,
HeapProfilerStartFunction heap_profiler_start_function,
HeapProfilerStopFunction heap_profiler_stop_function,
GetHeapProfileFunction get_heap_profile_function)
- : message_loop_proxy_(message_loop_proxy),
+ : task_runner_(task_runner.Pass()),
heap_profiler_start_function_(heap_profiler_start_function),
heap_profiler_stop_function_(heap_profiler_stop_function),
get_heap_profile_function_(get_heap_profile_function),
@@ -165,7 +165,7 @@ TraceMemoryController::~TraceMemoryController() {
TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
}
- // base::debug::TraceLog::EnabledStateChangedObserver overrides:
+// base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
void TraceMemoryController::OnTraceLogEnabled() {
// Check to see if tracing is enabled for the memory category.
bool enabled;
@@ -174,10 +174,9 @@ void TraceMemoryController::OnTraceLogEnabled() {
if (!enabled)
return;
DVLOG(1) << "OnTraceLogEnabled";
- message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&TraceMemoryController::StartProfiling,
- weak_factory_.GetWeakPtr()));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&TraceMemoryController::StartProfiling,
+ weak_factory_.GetWeakPtr()));
}
void TraceMemoryController::OnTraceLogDisabled() {
@@ -185,10 +184,9 @@ void TraceMemoryController::OnTraceLogDisabled() {
// called, so we cannot tell if it was enabled before. Always try to turn
// off profiling.
DVLOG(1) << "OnTraceLogDisabled";
- message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&TraceMemoryController::StopProfiling,
- weak_factory_.GetWeakPtr()));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&TraceMemoryController::StopProfiling,
+ weak_factory_.GetWeakPtr()));
}
void TraceMemoryController::StartProfiling() {
@@ -196,8 +194,7 @@ void TraceMemoryController::StartProfiling() {
if (dump_timer_.IsRunning())
return;
DVLOG(1) << "Starting trace memory";
- if (!InitThreadLocalStorage())
- return;
+ InitThreadLocalStorage();
ScopedTraceMemory::set_enabled(true);
// Call ::HeapProfilerWithPseudoStackStart().
heap_profiler_start_function_(&GetPseudoStack);
@@ -436,5 +433,5 @@ const char* StringFromHexAddress(const std::string& hex_address) {
return reinterpret_cast<const char*>(address);
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_memory.h b/chromium/base/trace_event/trace_event_memory.h
index 94c3f91cd27..e2b3ae93060 100644
--- a/chromium/base/debug/trace_event_memory.h
+++ b/chromium/base/trace_event/trace_event_memory.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEBUG_TRACE_EVENT_MEMORY_H_
-#define BASE_DEBUG_TRACE_EVENT_MEMORY_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
#include "base/base_export.h"
-#include "base/debug/trace_event_impl.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
+#include "base/trace_event/trace_event_impl.h"
// TODO(jamescook): Windows support for memory tracing.
#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \
@@ -20,9 +20,9 @@
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
-namespace debug {
+namespace trace_event {
// Watches for chrome://tracing to be enabled or disabled. When tracing is
// enabled, also enables tcmalloc heap profiling. This class is the preferred
@@ -35,18 +35,17 @@ class BASE_EXPORT TraceMemoryController
typedef void (*HeapProfilerStopFunction)();
typedef char* (*GetHeapProfileFunction)();
- // |message_loop_proxy| must be a proxy to the primary thread for the client
+ // |task_runner| must be a task runner for the primary thread for the client
// process, e.g. the UI thread in a browser. The function pointers must be
// pointers to tcmalloc heap profiling functions; by avoiding direct calls to
// these functions we avoid a dependency on third_party/tcmalloc from base.
- TraceMemoryController(
- scoped_refptr<MessageLoopProxy> message_loop_proxy,
- HeapProfilerStartFunction heap_profiler_start_function,
- HeapProfilerStopFunction heap_profiler_stop_function,
- GetHeapProfileFunction get_heap_profile_function);
+ TraceMemoryController(scoped_refptr<SingleThreadTaskRunner> task_runner,
+ HeapProfilerStartFunction heap_profiler_start_function,
+ HeapProfilerStopFunction heap_profiler_stop_function,
+ GetHeapProfileFunction get_heap_profile_function);
virtual ~TraceMemoryController();
- // base::debug::TraceLog::EnabledStateChangedObserver overrides:
+ // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
void OnTraceLogEnabled() override;
void OnTraceLogDisabled() override;
@@ -65,7 +64,7 @@ class BASE_EXPORT TraceMemoryController
bool IsTimerRunningForTest() const;
// Ensures the observer starts and stops tracing on the primary thread.
- scoped_refptr<MessageLoopProxy> message_loop_proxy_;
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
// Pointers to tcmalloc heap profiling functions. Allows this class to use
// tcmalloc functions without introducing a dependency from base to tcmalloc.
@@ -146,7 +145,7 @@ BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
// and "error" if |address| could not be parsed. Visible for testing.
BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
-} // namespace debug
+} // namespace trace_event
} // namespace base
// Make local variables with unique names based on the line number. Note that
@@ -159,7 +158,7 @@ BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
// It generates a unique local variable name using the macros above.
#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
#define INTERNAL_TRACE_MEMORY(category, name) \
- base::debug::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
+ base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
#else
#define INTERNAL_TRACE_MEMORY(category, name)
#endif // defined(TRACE_MEMORY_SUPPORTED)
@@ -169,4 +168,4 @@ BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
// visualizer skips them. Must match the value in heap.js.
#define TRACE_MEMORY_IGNORE "trace-memory-ignore"
-#endif // BASE_DEBUG_TRACE_EVENT_MEMORY_H_
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
diff --git a/chromium/base/debug/trace_event_memory_unittest.cc b/chromium/base/trace_event/trace_event_memory_unittest.cc
index 3f5cad3ede2..781a0544c45 100644
--- a/chromium/base/debug/trace_event_memory_unittest.cc
+++ b/chromium/base/trace_event/trace_event_memory_unittest.cc
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_memory.h"
+#include "base/trace_event/trace_event_memory.h"
#include <sstream>
#include <string>
-#include "base/debug/trace_event_impl.h"
-#include "base/message_loop/message_loop.h"
+#include "base/trace_event/trace_event_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
@@ -16,14 +15,14 @@
#endif
namespace base {
-namespace debug {
+namespace trace_event {
// Tests for the trace event memory tracking system. Exists as a class so it
// can be a friend of TraceMemoryController.
class TraceMemoryTest : public testing::Test {
public:
TraceMemoryTest() {}
- virtual ~TraceMemoryTest() {}
+ ~TraceMemoryTest() override {}
private:
DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest);
@@ -40,12 +39,9 @@ TEST_F(TraceMemoryTest, TraceMemoryController) {
EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
// Creating a controller adds it to the TraceLog observer list.
- scoped_ptr<TraceMemoryController> controller(
- new TraceMemoryController(
- message_loop.message_loop_proxy(),
- ::HeapProfilerWithPseudoStackStart,
- ::HeapProfilerStop,
- ::GetHeapProfile));
+ scoped_ptr<TraceMemoryController> controller(new TraceMemoryController(
+ message_loop.task_runner(), ::HeapProfilerWithPseudoStackStart,
+ ::HeapProfilerStop, ::GetHeapProfile));
EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
EXPECT_TRUE(
TraceLog::GetInstance()->HasEnabledStateObserver(controller.get()));
@@ -236,5 +232,5 @@ TEST_F(TraceMemoryTest, StringFromHexAddress) {
EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str()));
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_synthetic_delay.cc b/chromium/base/trace_event/trace_event_synthetic_delay.cc
index 6abfe183572..bad79ccbc8c 100644
--- a/chromium/base/debug/trace_event_synthetic_delay.cc
+++ b/chromium/base/trace_event/trace_event_synthetic_delay.cc
@@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_synthetic_delay.h"
#include "base/memory/singleton.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
namespace {
const int kMaxSyntheticDelays = 32;
} // namespace
namespace base {
-namespace debug {
+namespace trace_event {
TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
@@ -184,7 +185,7 @@ TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
}
base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
- return base::TimeTicks::HighResNow();
+ return base::TimeTicks::Now();
}
void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
@@ -200,7 +201,7 @@ void ResetTraceEventSyntheticDelays() {
TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
namespace trace_event_internal {
@@ -215,15 +216,16 @@ ScopedSyntheticDelay::~ScopedSyntheticDelay() {
delay_impl_->EndParallel(end_time_);
}
-base::debug::TraceEventSyntheticDelay* GetOrCreateDelay(
+base::trace_event::TraceEventSyntheticDelay* GetOrCreateDelay(
const char* name,
base::subtle::AtomicWord* impl_ptr) {
- base::debug::TraceEventSyntheticDelay* delay_impl =
- reinterpret_cast<base::debug::TraceEventSyntheticDelay*>(
+ base::trace_event::TraceEventSyntheticDelay* delay_impl =
+ reinterpret_cast<base::trace_event::TraceEventSyntheticDelay*>(
base::subtle::Acquire_Load(impl_ptr));
if (!delay_impl) {
- delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance()
- ->GetOrCreateDelay(name);
+ delay_impl =
+ base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
+ ->GetOrCreateDelay(name);
base::subtle::Release_Store(
impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
}
diff --git a/chromium/base/debug/trace_event_synthetic_delay.h b/chromium/base/trace_event/trace_event_synthetic_delay.h
index 06d6cdea1f9..0df794b46c2 100644
--- a/chromium/base/debug/trace_event_synthetic_delay.h
+++ b/chromium/base/trace_event/trace_event_synthetic_delay.h
@@ -29,13 +29,13 @@
// Note that a single delay may begin on one thread and end on another. This
// implies that a single delay cannot not be applied in several threads at once.
-#ifndef BASE_DEBUG_TRACE_EVENT_SYNTHETIC_DELAY_H_
-#define BASE_DEBUG_TRACE_EVENT_SYNTHETIC_DELAY_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
#include "base/atomicops.h"
-#include "base/debug/trace_event.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
// Apply a named delay in the current scope.
#define TRACE_EVENT_SYNTHETIC_DELAY(name) \
@@ -65,7 +65,7 @@ template <typename Type>
struct DefaultSingletonTraits;
namespace base {
-namespace debug {
+namespace trace_event {
// Time source for computing delay durations. Used for testing.
class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelayClock {
@@ -138,7 +138,7 @@ class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelay {
// Set the target durations of all registered synthetic delay points to zero.
TRACE_EVENT_API_CLASS_EXPORT void ResetTraceEventSyntheticDelays();
-} // namespace debug
+} // namespace trace_event
} // namespace base
namespace trace_event_internal {
@@ -151,16 +151,16 @@ class TRACE_EVENT_API_CLASS_EXPORT ScopedSyntheticDelay {
~ScopedSyntheticDelay();
private:
- base::debug::TraceEventSyntheticDelay* delay_impl_;
+ base::trace_event::TraceEventSyntheticDelay* delay_impl_;
base::TimeTicks end_time_;
DISALLOW_COPY_AND_ASSIGN(ScopedSyntheticDelay);
};
// Helper for registering delays. Do not use directly.
-TRACE_EVENT_API_CLASS_EXPORT base::debug::TraceEventSyntheticDelay*
+TRACE_EVENT_API_CLASS_EXPORT base::trace_event::TraceEventSyntheticDelay*
GetOrCreateDelay(const char* name, base::subtle::AtomicWord* impl_ptr);
} // namespace trace_event_internal
-#endif /* BASE_DEBUG_TRACE_EVENT_SYNTHETIC_DELAY_H_ */
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
diff --git a/chromium/base/debug/trace_event_synthetic_delay_unittest.cc b/chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc
index 60e4d20368e..1dc0fc26f5c 100644
--- a/chromium/base/debug/trace_event_synthetic_delay_unittest.cc
+++ b/chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_synthetic_delay.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
-namespace debug {
+namespace trace_event {
namespace {
const int kTargetDurationMs = 100;
@@ -21,9 +21,7 @@ class TraceEventSyntheticDelayTest : public testing::Test,
public TraceEventSyntheticDelayClock {
public:
TraceEventSyntheticDelayTest() {}
- virtual ~TraceEventSyntheticDelayTest() {
- ResetTraceEventSyntheticDelays();
- }
+ ~TraceEventSyntheticDelayTest() override { ResetTraceEventSyntheticDelays(); }
// TraceEventSyntheticDelayClock implementation.
base::TimeTicks Now() override {
@@ -152,5 +150,5 @@ TEST_F(TraceEventSyntheticDelayTest, BeginParallel) {
EXPECT_LT((Now() - start_time).InMilliseconds(), kShortDurationMs);
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_system_stats_monitor.cc b/chromium/base/trace_event/trace_event_system_stats_monitor.cc
index 9cbefd8d6cc..98f361a9d9b 100644
--- a/chromium/base/debug/trace_event_system_stats_monitor.cc
+++ b/chromium/base/trace_event/trace_event_system_stats_monitor.cc
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_system_stats_monitor.h"
+#include "base/trace_event/trace_event_system_stats_monitor.h"
#include "base/debug/leak_annotations.h"
-#include "base/debug/trace_event.h"
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -14,15 +13,16 @@
#include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
namespace base {
-namespace debug {
+namespace trace_event {
namespace {
/////////////////////////////////////////////////////////////////////////////
// Holds profiled system stats until the tracing system needs to serialize it.
-class SystemStatsHolder : public base::debug::ConvertableToTraceFormat {
+class SystemStatsHolder : public base::trace_event::ConvertableToTraceFormat {
public:
SystemStatsHolder() { }
@@ -30,7 +30,7 @@ class SystemStatsHolder : public base::debug::ConvertableToTraceFormat {
// Uses the previous stats to compute rates if this is not the first profile.
void GetSystemProfilingStats();
- // base::debug::ConvertableToTraceFormat overrides:
+ // base::trace_event::ConvertableToTraceFormat overrides:
void AppendAsTraceFormat(std::string* out) const override {
AppendSystemProfileAsTraceFormat(system_stats_, out);
}
@@ -129,5 +129,5 @@ void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics,
*output += tmp;
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_system_stats_monitor.h b/chromium/base/trace_event/trace_event_system_stats_monitor.h
index 143f1875db8..051669a35f5 100644
--- a/chromium/base/debug/trace_event_system_stats_monitor.h
+++ b/chromium/base/trace_event/trace_event_system_stats_monitor.h
@@ -2,22 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef BASE_DEBUG_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
-#define BASE_DEBUG_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
#include "base/base_export.h"
-#include "base/debug/trace_event_impl.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_metrics.h"
#include "base/timer/timer.h"
+#include "base/trace_event/trace_event_impl.h"
namespace base {
class SingleThreadTaskRunner;
-namespace debug {
+namespace trace_event {
// Watches for chrome://tracing to be enabled or disabled. When tracing is
// enabled, also enables system events profiling. This class is the preferred
@@ -35,7 +35,7 @@ class BASE_EXPORT TraceEventSystemStatsMonitor
virtual ~TraceEventSystemStatsMonitor();
- // base::debug::TraceLog::EnabledStateChangedObserver overrides:
+ // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
void OnTraceLogEnabled() override;
void OnTraceLogDisabled() override;
@@ -69,7 +69,7 @@ BASE_EXPORT void AppendSystemProfileAsTraceFormat(const SystemMetrics&
system_stats,
std::string* output);
-} // namespace debug
+} // namespace trace_event
} // namespace base
-#endif // BASE_DEBUG_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
diff --git a/chromium/base/debug/trace_event_system_stats_monitor_unittest.cc b/chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc
index 5cc2a0fd383..03dff591cfa 100644
--- a/chromium/base/debug/trace_event_system_stats_monitor_unittest.cc
+++ b/chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_system_stats_monitor.h"
+#include "base/trace_event/trace_event_system_stats_monitor.h"
#include <sstream>
#include <string>
-#include "base/debug/trace_event_impl.h"
-#include "base/message_loop/message_loop.h"
+#include "base/trace_event/trace_event_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
-namespace debug {
+namespace trace_event {
#if !defined(OS_IOS)
// Tests for the system stats monitor.
@@ -20,7 +19,7 @@ namespace debug {
class TraceSystemStatsMonitorTest : public testing::Test {
public:
TraceSystemStatsMonitorTest() {}
- virtual ~TraceSystemStatsMonitorTest() {}
+ ~TraceSystemStatsMonitorTest() override {}
private:
DISALLOW_COPY_AND_ASSIGN(TraceSystemStatsMonitorTest);
@@ -36,8 +35,7 @@ TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) {
// Creating a system stats monitor adds it to the TraceLog observer list.
scoped_ptr<TraceEventSystemStatsMonitor> system_stats_monitor(
- new TraceEventSystemStatsMonitor(
- message_loop.message_loop_proxy()));
+ new TraceEventSystemStatsMonitor(message_loop.task_runner()));
EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
EXPECT_TRUE(
TraceLog::GetInstance()->HasEnabledStateObserver(
@@ -62,5 +60,5 @@ TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) {
}
#endif // !defined(OS_IOS)
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_unittest.cc b/chromium/base/trace_event/trace_event_unittest.cc
index 69b574305e2..d03224301cd 100644
--- a/chromium/base/debug/trace_event_unittest.cc
+++ b/chromium/base/trace_event/trace_event_unittest.cc
@@ -2,32 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_unittest.h"
-
#include <math.h>
#include <cstdlib>
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_synthetic_delay.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/location.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
#include "base/values.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
-namespace debug {
+namespace trace_event {
namespace {
@@ -97,10 +97,9 @@ class TraceEventTestFixture : public testing::Test {
WaitableEvent flush_complete_event(false, false);
Thread flush_thread("flush");
flush_thread.Start();
- flush_thread.message_loop()->PostTask(FROM_HERE,
- base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
- base::Unretained(this),
- &flush_complete_event));
+ flush_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
+ base::Unretained(this), &flush_complete_event));
flush_complete_event.Wait();
}
@@ -125,7 +124,7 @@ class TraceEventTestFixture : public testing::Test {
base::Unretained(flush_complete_event)));
}
- virtual void SetUp() override {
+ void SetUp() override {
const char* name = PlatformThread::GetName();
old_thread_name_ = name ? strdup(name) : NULL;
@@ -136,7 +135,7 @@ class TraceEventTestFixture : public testing::Test {
trace_buffer_.SetOutputCallback(json_output_.GetCallback());
event_watch_notification_ = 0;
}
- virtual void TearDown() override {
+ void TearDown() override {
if (TraceLog::GetInstance())
EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : "");
@@ -871,13 +870,6 @@ void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
} // namespace
-void HighResSleepForTraceTest(base::TimeDelta elapsed) {
- base::TimeTicks end_time = base::TimeTicks::HighResNow() + elapsed;
- do {
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
- } while (base::TimeTicks::HighResNow() < end_time);
-}
-
// Simple Test for emitting data and validating it was received.
TEST_F(TraceEventTestFixture, DataCaptured) {
TraceLog::GetInstance()->SetEnabled(
@@ -1214,8 +1206,8 @@ TEST_F(TraceEventTestFixture, Categories) {
EndTraceAndFlush();
EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
EXPECT_FALSE(FindMatchingValue("cat", "inc"));
- EXPECT_FALSE(FindMatchingValue("cat", "inc2,inc"));
- EXPECT_FALSE(FindMatchingValue("cat", "inc,inc2"));
+ EXPECT_TRUE(FindMatchingValue("cat", "inc2,inc"));
+ EXPECT_TRUE(FindMatchingValue("cat", "inc,inc2"));
// Exclude existent wildcard -> all categories not matching wildcard
Clear();
@@ -1366,8 +1358,7 @@ TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) {
TEST_F(TraceEventTestFixture, StaticStringVsString) {
TraceLog* tracer = TraceLog::GetInstance();
// Make sure old events are flushed:
- EndTraceAndFlush();
- EXPECT_EQ(0u, tracer->GetEventsSize());
+ EXPECT_EQ(0u, tracer->GetStatus().event_count);
const unsigned char* category_group_enabled =
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat");
@@ -1384,8 +1375,7 @@ TEST_F(TraceEventTestFixture, StaticStringVsString) {
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
"arg1", TRACE_STR_COPY("argval"),
"arg2", TRACE_STR_COPY("argval"));
- size_t num_events = tracer->GetEventsSize();
- EXPECT_GT(num_events, 1u);
+ EXPECT_GT(tracer->GetStatus().event_count, 1u);
const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
ASSERT_TRUE(event1);
@@ -1414,8 +1404,7 @@ TEST_F(TraceEventTestFixture, StaticStringVsString) {
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
"arg1", TRACE_STR_COPY(str1),
"arg2", TRACE_STR_COPY(str2));
- size_t num_events = tracer->GetEventsSize();
- EXPECT_GT(num_events, 1u);
+ EXPECT_GT(tracer->GetStatus().event_count, 1u);
const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
ASSERT_TRUE(event1);
@@ -1436,7 +1425,7 @@ TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
thread.Stop();
@@ -1457,9 +1446,9 @@ TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
threads[i] = new Thread(StringPrintf("Thread %d", i));
task_complete_events[i] = new WaitableEvent(false, false);
threads[i]->Start();
- threads[i]->message_loop()->PostTask(
- FROM_HERE, base::Bind(&TraceManyInstantEvents,
- i, num_events, task_complete_events[i]));
+ threads[i]->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TraceManyInstantEvents, i, num_events,
+ task_complete_events[i]));
}
for (int i = 0; i < num_threads; i++) {
@@ -1505,9 +1494,9 @@ TEST_F(TraceEventTestFixture, ThreadNames) {
task_complete_events[i] = new WaitableEvent(false, false);
threads[i]->Start();
thread_ids[i] = threads[i]->thread_id();
- threads[i]->message_loop()->PostTask(
- FROM_HERE, base::Bind(&TraceManyInstantEvents,
- i, kNumEvents, task_complete_events[i]));
+ threads[i]->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
+ task_complete_events[i]));
}
for (int i = 0; i < kNumThreads; i++) {
task_complete_events[i]->Wait();
@@ -1538,7 +1527,7 @@ TEST_F(TraceEventTestFixture, ThreadNames) {
// See if this thread name is one of the threads we just created
for (int j = 0; j < kNumThreads; j++) {
- if(static_cast<int>(thread_ids[j]) != tmp_int)
+ if (static_cast<int>(thread_ids[j]) != tmp_int)
continue;
std::string expected_name = StringPrintf("Thread %d", j);
@@ -1618,6 +1607,22 @@ TEST_F(TraceEventTestFixture, DisabledCategories) {
EXPECT_FIND_("disabled-by-default-cc");
EXPECT_FIND_("other_included");
}
+
+ Clear();
+
+ BeginSpecificTrace("other_included");
+ TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc") ",other_included",
+ "first", TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_INSTANT0("other_included," TRACE_DISABLED_BY_DEFAULT("cc"),
+ "second", TRACE_EVENT_SCOPE_THREAD);
+ EndTraceAndFlush();
+
+ {
+ const DictionaryValue* item = NULL;
+ ListValue& trace_parsed = trace_parsed_;
+ EXPECT_FIND_("disabled-by-default-cc,other_included");
+ EXPECT_FIND_("other_included,disabled-by-default-cc");
+ }
}
TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
@@ -2202,14 +2207,14 @@ TEST_F(TraceEventTestFixture, PrimitiveArgs) {
class TraceEventCallbackTest : public TraceEventTestFixture {
public:
- virtual void SetUp() override {
+ void SetUp() override {
TraceEventTestFixture::SetUp();
ASSERT_EQ(NULL, s_instance);
s_instance = this;
}
- virtual void TearDown() override {
+ void TearDown() override {
TraceLog::GetInstance()->SetDisabled();
- ASSERT_TRUE(!!s_instance);
+ ASSERT_TRUE(s_instance);
s_instance = NULL;
TraceEventTestFixture::TearDown();
}
@@ -2620,18 +2625,18 @@ TEST_F(TraceEventTestFixture, CategoryFilter) {
EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("not-excluded-category"));
EXPECT_FALSE(
default_cf.IsCategoryGroupEnabled("disabled-by-default-category"));
- EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
- EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
- EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
+ EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+ EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+ EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
// Make sure that upon an empty string, we fall back to the default filter.
default_cf = CategoryFilter();
category_filter_str = default_cf.ToString();
EXPECT_STREQ("-*Debug,-*Test", category_filter_str.c_str());
EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("not-excluded-category"));
- EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
- EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
- EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
+ EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+ EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+ EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
// Using an arbitrary non-empty filter.
CategoryFilter cf("included,-excluded,inc_pattern*,-exc_pattern*");
@@ -2721,17 +2726,17 @@ TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopBeforeTracing) {
Thread thread("1");
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceLog::SetCurrentThreadBlocksMessageLoop,
Unretained(TraceLog::GetInstance())));
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
WaitableEvent task_start_event(false, false);
WaitableEvent task_stop_event(false, false);
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
task_start_event.Wait();
@@ -2792,15 +2797,15 @@ TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopAfterTracing) {
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
WaitableEvent task_start_event(false, false);
WaitableEvent task_stop_event(false, false);
- thread.message_loop()->PostTask(
- FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped,
- &task_start_event, &task_stop_event));
+ thread.task_runner()->PostTask(
+ FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped, &task_start_event,
+ &task_stop_event));
task_start_event.Wait();
EndTraceAndFlush();
@@ -2817,14 +2822,14 @@ TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
WaitableEvent task_complete_event(false, false);
thread.Start();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
task_complete_event.Reset();
WaitableEvent task_start_event(false, false);
WaitableEvent task_stop_event(false, false);
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
task_start_event.Wait();
@@ -2839,7 +2844,7 @@ TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
// executed in the thread before continuing.
task_start_event.Reset();
task_stop_event.Reset();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
task_start_event.Wait();
task_stop_event.Signal();
@@ -2848,7 +2853,7 @@ TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
// TraceLog should discover the generation mismatch and recover the thread
// local buffer for the thread without any error.
BeginTrace();
- thread.message_loop()->PostTask(
+ thread.task_runner()->PostTask(
FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
task_complete_event.Wait();
task_complete_event.Reset();
@@ -3075,6 +3080,5 @@ TEST(TraceOptionsTest, TraceOptionsToString) {
}
}
-
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_win.cc b/chromium/base/trace_event/trace_event_win.cc
index 99dd242fad6..ebb55c84492 100644
--- a/chromium/base/debug/trace_event_win.cc
+++ b/chromium/base/trace_event/trace_event_win.cc
@@ -1,14 +1,15 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event_win.h"
+
+#include "base/trace_event/trace_event_win.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include <initguid.h> // NOLINT
namespace base {
-namespace debug {
+namespace trace_event {
using base::win::EtwEventType;
using base::win::EtwMofEvent;
@@ -119,5 +120,5 @@ void TraceEventETWProvider::Resurrect() {
StaticMemorySingletonTraits<TraceEventETWProvider>::Resurrect();
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/debug/trace_event_win.h b/chromium/base/trace_event/trace_event_win.h
index c85ca9217cf..41613615549 100644
--- a/chromium/base/debug/trace_event_win.h
+++ b/chromium/base/trace_event/trace_event_win.h
@@ -3,13 +3,13 @@
// found in the LICENSE file.
// This file contains the Windows-specific declarations for trace_event.h.
-#ifndef BASE_DEBUG_TRACE_EVENT_WIN_H_
-#define BASE_DEBUG_TRACE_EVENT_WIN_H_
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
#include <string>
#include "base/base_export.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/event_trace_provider.h"
// Fwd.
@@ -17,7 +17,7 @@ template <typename Type>
struct StaticMemorySingletonTraits;
namespace base {
-namespace debug {
+namespace trace_event {
// This EtwTraceProvider subclass implements ETW logging
// for the macros above on Windows.
@@ -119,7 +119,7 @@ enum TraceEventETWFlags {
// Optionally the stack trace, consisting of a DWORD "depth", followed
// by an array of void* (machine bitness) of length "depth".
-} // namespace debug
+} // namespace trace_event
} // namespace base
-#endif // BASE_DEBUG_TRACE_EVENT_WIN_H_
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
diff --git a/chromium/base/debug/trace_event_win_unittest.cc b/chromium/base/trace_event/trace_event_win_unittest.cc
index 378264511a2..d4dc8542c30 100644
--- a/chromium/base/debug/trace_event_win_unittest.cc
+++ b/chromium/base/trace_event/trace_event_win_unittest.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include <strstream>
#include "base/at_exit.h"
#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_win.h"
#include "base/files/file_util.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_win.h"
#include "base/win/event_trace_consumer.h"
#include "base/win/event_trace_controller.h"
#include "base/win/event_trace_provider.h"
@@ -20,7 +20,7 @@
#include <initguid.h> // NOLINT - must be last include.
namespace base {
-namespace debug {
+namespace trace_event {
namespace {
@@ -92,7 +92,7 @@ class TraceEventWinTest: public testing::Test {
TraceEventWinTest() {
}
- void SetUp() {
+ void SetUp() override {
bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
if (is_xp) {
@@ -151,7 +151,7 @@ class TraceEventWinTest: public testing::Test {
EXPECT_TRUE(tracelog->IsTracing());
}
- void TearDown() {
+ void TearDown() override {
EtwTraceProperties prop;
if (controller_.session() != 0)
EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
@@ -315,5 +315,5 @@ TEST_F(TraceEventWinTest, Macros) {
PlayLog();
}
-} // namespace debug
+} // namespace trace_event
} // namespace base
diff --git a/chromium/base/trace_event/winheap_dump_provider_win.cc b/chromium/base/trace_event/winheap_dump_provider_win.cc
new file mode 100644
index 00000000000..e1e9bcf4a7c
--- /dev/null
+++ b/chromium/base/trace_event/winheap_dump_provider_win.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Report a heap dump to a process memory dump. The |heap_info| structure
+// contains the information about this heap, and |dump_absolute_name| will be
+// used to represent it in the report.
+bool ReportHeapDump(ProcessMemoryDump* pmd,
+ const WinHeapInfo& heap_info,
+ const std::string& dump_absolute_name) {
+ MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_absolute_name);
+ if (!dump)
+ return false;
+ dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+ MemoryAllocatorDump::kUnitsBytes, heap_info.committed_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+ MemoryAllocatorDump::kUnitsBytes, heap_info.allocated_size);
+ dump->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+ MemoryAllocatorDump::kUnitsObjects, heap_info.block_count);
+ return true;
+}
+
+} // namespace
+
+WinHeapDumpProvider* WinHeapDumpProvider::GetInstance() {
+ return Singleton<WinHeapDumpProvider,
+ LeakySingletonTraits<WinHeapDumpProvider>>::get();
+}
+
+bool WinHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+ // Retrieves the number of heaps in the current process.
+ DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
+ WinHeapInfo all_heap_info = {0};
+
+ // Try to retrieve a handle to all the heaps owned by this process. Returns
+ // false if the number of heaps has changed.
+ //
+ // This is inherently racy as is, but it's not something that we observe a lot
+ // in Chrome, the heaps tend to be created at startup only.
+ scoped_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]);
+ if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps)
+ return false;
+
+ // Skip the pointer to the heap array to avoid accounting the memory used by
+ // this dump provider.
+ std::set<void*> block_to_skip;
+ block_to_skip.insert(all_heaps.get());
+
+ // Retrieves some metrics about each heap.
+ for (size_t i = 0; i < number_of_heaps; ++i) {
+ WinHeapInfo heap_info = {0};
+ heap_info.heap_id = all_heaps[i];
+ GetHeapInformation(&heap_info, block_to_skip);
+
+ all_heap_info.allocated_size += heap_info.allocated_size;
+ all_heap_info.committed_size += heap_info.committed_size;
+ all_heap_info.block_count += heap_info.block_count;
+ }
+ // Report the heap dump.
+ if (!ReportHeapDump(pmd, all_heap_info, "winheap"))
+ return false;
+
+ return true;
+}
+
+bool WinHeapDumpProvider::GetHeapInformation(
+ WinHeapInfo* heap_info,
+ const std::set<void*>& block_to_skip) {
+ CHECK(::HeapLock(heap_info->heap_id) == TRUE);
+ PROCESS_HEAP_ENTRY heap_entry;
+ heap_entry.lpData = nullptr;
+ // Walk over all the entries in this heap.
+ while (::HeapWalk(heap_info->heap_id, &heap_entry) != FALSE) {
+ if (block_to_skip.count(heap_entry.lpData) == 1)
+ continue;
+ if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
+ heap_info->allocated_size += heap_entry.cbData;
+ heap_info->block_count++;
+ } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) {
+ heap_info->committed_size += heap_entry.Region.dwCommittedSize;
+ }
+ }
+ CHECK(::HeapUnlock(heap_info->heap_id) == TRUE);
+ return true;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/winheap_dump_provider_win.h b/chromium/base/trace_event/winheap_dump_provider_win.h
new file mode 100644
index 00000000000..99239a066ef
--- /dev/null
+++ b/chromium/base/trace_event/winheap_dump_provider_win.h
@@ -0,0 +1,52 @@
+// Copyright 2015 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_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+#define BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+
+#include <set>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// A structure containing some information about a given heap.
+struct WinHeapInfo {
+ HANDLE heap_id;
+ size_t committed_size;
+ size_t allocated_size;
+ size_t block_count;
+};
+
+// Dump provider which collects process-wide heap memory stats. This provider
+// iterates over all the heaps of the current process to gather some metrics
+// about them.
+class BASE_EXPORT WinHeapDumpProvider : public MemoryDumpProvider {
+ public:
+ static WinHeapDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
+
+ // Retrieves the information about given heap. The |heap_info| should contain
+ // a valid handle to an existing heap. The blocks contained in the
+ // |block_to_skip| set will be ignored.
+ bool GetHeapInformation(WinHeapInfo* heap_info,
+ const std::set<void*>& block_to_skip);
+
+ WinHeapDumpProvider() {}
+ ~WinHeapDumpProvider() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(WinHeapDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
diff --git a/chromium/base/trace_event/winheap_dump_provider_win_unittest.cc b/chromium/base/trace_event/winheap_dump_provider_win_unittest.cc
new file mode 100644
index 00000000000..2309802fe79
--- /dev/null
+++ b/chromium/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(WinHeapDumpProviderTest, OnMemoryDump) {
+ ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+ WinHeapDumpProvider* winheap_dump_provider =
+ WinHeapDumpProvider::GetInstance();
+ ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
+
+ ASSERT_TRUE(winheap_dump_provider->OnMemoryDump(&pmd));
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/tracked_objects.cc b/chromium/base/tracked_objects.cc
index c69fada531c..9db05c0d3fd 100644
--- a/chromium/base/tracked_objects.cc
+++ b/chromium/base/tracked_objects.cc
@@ -28,22 +28,13 @@ class TimeDelta;
namespace tracked_objects {
namespace {
-// Flag to compile out almost all of the task tracking code.
-const bool kTrackAllTaskObjects = true;
-
-// TODO(jar): Evaluate the perf impact of enabling this. If the perf impact is
-// negligible, enable by default.
-// Flag to compile out parent-child link recording.
-const bool kTrackParentChildLinks = false;
-
// When ThreadData is first initialized, should we start in an ACTIVE state to
// record all of the startup-time tasks, or should we start up DEACTIVATED, so
// that we only record after parsing the command line flag --enable-tracking.
// Note that the flag may force either state, so this really controls only the
-// period of time up until that flag is parsed. If there is no flag seen, then
+// period of time up until that flag is parsed. If there is no flag seen, then
// this state may prevail for much or all of the process lifetime.
-const ThreadData::Status kInitialStartupState =
- ThreadData::PROFILING_CHILDREN_ACTIVE;
+const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE;
// Control whether an alternate time source (Now() function) is supported by
// the ThreadData class. This compile time flag should be set to true if we
@@ -64,9 +55,10 @@ enum {
// State of the profiler timing enabledness.
base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING;
-// Returns whether profiler timing is enabled. The default is true, but this may
-// be overridden by a command-line flag. Some platforms may programmatically set
-// this command-line flag to the "off" value if it's not specified.
+// Returns whether profiler timing is enabled. The default is true, but this
+// may be overridden by a command-line flag. Some platforms may
+// programmatically set this command-line flag to the "off" value if it's not
+// specified.
// This in turn can be overridden by explicitly calling
// ThreadData::EnableProfilerTiming, say, based on a field trial.
inline bool IsProfilerTimingEnabled() {
@@ -76,10 +68,10 @@ inline bool IsProfilerTimingEnabled() {
base::subtle::Atomic32 current_timing_enabled =
base::subtle::NoBarrier_Load(&g_profiler_timing_enabled);
if (current_timing_enabled == UNDEFINED_TIMING) {
- if (!CommandLine::InitializedForCurrentProcess())
+ if (!base::CommandLine::InitializedForCurrentProcess())
return true;
current_timing_enabled =
- (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProfilerTiming) ==
switches::kProfilerTimingDisabledValue)
? DISABLED_TIMING
@@ -95,13 +87,40 @@ inline bool IsProfilerTimingEnabled() {
//------------------------------------------------------------------------------
// DeathData tallies durations when a death takes place.
-DeathData::DeathData() {
- Clear();
-}
-
-DeathData::DeathData(int count) {
- Clear();
- count_ = count;
+DeathData::DeathData()
+ : count_(0),
+ sample_probability_count_(0),
+ run_duration_sum_(0),
+ queue_duration_sum_(0),
+ run_duration_max_(0),
+ queue_duration_max_(0),
+ run_duration_sample_(0),
+ queue_duration_sample_(0),
+ last_phase_snapshot_(nullptr) {
+}
+
+DeathData::DeathData(const DeathData& other)
+ : count_(other.count_),
+ sample_probability_count_(other.sample_probability_count_),
+ run_duration_sum_(other.run_duration_sum_),
+ queue_duration_sum_(other.queue_duration_sum_),
+ run_duration_max_(other.run_duration_max_),
+ queue_duration_max_(other.queue_duration_max_),
+ run_duration_sample_(other.run_duration_sample_),
+ queue_duration_sample_(other.queue_duration_sample_),
+ last_phase_snapshot_(nullptr) {
+ // This constructor will be used by std::map when adding new DeathData values
+ // to the map. At that point, last_phase_snapshot_ is still NULL, so we don't
+ // need to worry about ownership transfer.
+ DCHECK(other.last_phase_snapshot_ == nullptr);
+}
+
+DeathData::~DeathData() {
+ while (last_phase_snapshot_) {
+ const DeathDataPhaseSnapshot* snapshot = last_phase_snapshot_;
+ last_phase_snapshot_ = snapshot->prev;
+ delete snapshot;
+ }
}
// TODO(jar): I need to see if this macro to optimize branching is worth using.
@@ -116,10 +135,16 @@ DeathData::DeathData(int count) {
void DeathData::RecordDeath(const int32 queue_duration,
const int32 run_duration,
- int32 random_number) {
+ const uint32 random_number) {
// We'll just clamp at INT_MAX, but we should note this in the UI as such.
if (count_ < INT_MAX)
++count_;
+
+ int sample_probability_count = sample_probability_count_;
+ if (sample_probability_count < INT_MAX)
+ ++sample_probability_count;
+ sample_probability_count_ = sample_probability_count;
+
queue_duration_sum_ += queue_duration;
run_duration_sum_ += run_duration;
@@ -128,54 +153,54 @@ void DeathData::RecordDeath(const int32 queue_duration,
if (run_duration_max_ < run_duration)
run_duration_max_ = run_duration;
- // Take a uniformly distributed sample over all durations ever supplied.
- // The probability that we (instead) use this new sample is 1/count_. This
- // results in a completely uniform selection of the sample (at least when we
- // don't clamp count_... but that should be inconsequentially likely).
- // We ignore the fact that we correlated our selection of a sample to the run
- // and queue times (i.e., we used them to generate random_number).
- CHECK_GT(count_, 0);
- if (0 == (random_number % count_)) {
+ // Take a uniformly distributed sample over all durations ever supplied during
+ // the current profiling phase.
+ // The probability that we (instead) use this new sample is
+ // 1/sample_probability_count_. This results in a completely uniform selection
+ // of the sample (at least when we don't clamp sample_probability_count_...
+ // but that should be inconsequentially likely). We ignore the fact that we
+ // correlated our selection of a sample to the run and queue times (i.e., we
+ // used them to generate random_number).
+ CHECK_GT(sample_probability_count, 0);
+ if (0 == (random_number % sample_probability_count)) {
queue_duration_sample_ = queue_duration;
run_duration_sample_ = run_duration;
}
}
-int DeathData::count() const { return count_; }
-
-int32 DeathData::run_duration_sum() const { return run_duration_sum_; }
-
-int32 DeathData::run_duration_max() const { return run_duration_max_; }
-
-int32 DeathData::run_duration_sample() const {
- return run_duration_sample_;
-}
-
-int32 DeathData::queue_duration_sum() const {
- return queue_duration_sum_;
-}
-
-int32 DeathData::queue_duration_max() const {
- return queue_duration_max_;
-}
-
-int32 DeathData::queue_duration_sample() const {
- return queue_duration_sample_;
-}
-
-void DeathData::ResetMax() {
- run_duration_max_ = 0;
- queue_duration_max_ = 0;
-}
-
-void DeathData::Clear() {
- count_ = 0;
- run_duration_sum_ = 0;
+void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
+ // Snapshotting and storing current state.
+ last_phase_snapshot_ = new DeathDataPhaseSnapshot(
+ profiling_phase, count_, run_duration_sum_, run_duration_max_,
+ run_duration_sample_, queue_duration_sum_, queue_duration_max_,
+ queue_duration_sample_, last_phase_snapshot_);
+
+ // Not touching fields for which a delta can be computed by comparing with a
+ // snapshot from the previous phase. Resetting other fields. Sample values
+ // will be reset upon next death recording because sample_probability_count_
+ // is set to 0.
+ // We avoid resetting to 0 in favor of deltas whenever possible. The reason
+ // is that for incrementable fields, resetting to 0 from the snapshot thread
+ // potentially in parallel with incrementing in the death thread may result in
+ // significant data corruption that has a potential to grow with time. Not
+ // resetting incrementable fields and using deltas will cause any
+ // off-by-little corruptions to be likely fixed at the next snapshot.
+ // The max values are not incrementable, and cannot be deduced using deltas
+ // for a given phase. Hence, we have to reset them to 0. But the potential
+ // damage is limited to getting the previous phase's max to apply for the next
+ // phase, and the error doesn't have a potential to keep growing with new
+ // resets.
+ // sample_probability_count_ is incrementable, but must be reset to 0 at the
+ // phase end, so that we start a new uniformly randomized sample selection
+ // after the reset. Corruptions due to race conditions are possible, but the
+ // damage is limited to selecting a wrong sample, which is not something that
+ // can cause accumulating or cascading effects.
+ // If there were no corruptions caused by race conditions, we never send a
+ // sample for the previous phase in the next phase's snapshot because
+ // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count.
+ sample_probability_count_ = 0;
run_duration_max_ = 0;
- run_duration_sample_ = 0;
- queue_duration_sum_ = 0;
queue_duration_max_ = 0;
- queue_duration_sample_ = 0;
}
//------------------------------------------------------------------------------
@@ -189,20 +214,34 @@ DeathDataSnapshot::DeathDataSnapshot()
queue_duration_sample(-1) {
}
-DeathDataSnapshot::DeathDataSnapshot(
- const tracked_objects::DeathData& death_data)
- : count(death_data.count()),
- run_duration_sum(death_data.run_duration_sum()),
- run_duration_max(death_data.run_duration_max()),
- run_duration_sample(death_data.run_duration_sample()),
- queue_duration_sum(death_data.queue_duration_sum()),
- queue_duration_max(death_data.queue_duration_max()),
- queue_duration_sample(death_data.queue_duration_sample()) {
+DeathDataSnapshot::DeathDataSnapshot(int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample)
+ : count(count),
+ run_duration_sum(run_duration_sum),
+ run_duration_max(run_duration_max),
+ run_duration_sample(run_duration_sample),
+ queue_duration_sum(queue_duration_sum),
+ queue_duration_max(queue_duration_max),
+ queue_duration_sample(queue_duration_sample) {
}
DeathDataSnapshot::~DeathDataSnapshot() {
}
+DeathDataSnapshot DeathDataSnapshot::Delta(
+ const DeathDataSnapshot& older) const {
+ return DeathDataSnapshot(count - older.count,
+ run_duration_sum - older.run_duration_sum,
+ run_duration_max, run_duration_sample,
+ queue_duration_sum - older.queue_duration_sum,
+ queue_duration_max, queue_duration_sample);
+}
+
//------------------------------------------------------------------------------
BirthOnThread::BirthOnThread(const Location& location,
const ThreadData& current)
@@ -214,8 +253,7 @@ BirthOnThread::BirthOnThread(const Location& location,
BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
}
-BirthOnThreadSnapshot::BirthOnThreadSnapshot(
- const tracked_objects::BirthOnThread& birth)
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth)
: location(birth.location()),
thread_name(birth.birth_thread()->thread_name()) {
}
@@ -232,10 +270,6 @@ int Births::birth_count() const { return birth_count_; }
void Births::RecordBirth() { ++birth_count_; }
-void Births::ForgetBirth() { --birth_count_; }
-
-void Births::Clear() { birth_count_ = 0; }
-
//------------------------------------------------------------------------------
// ThreadData maintains the central data for all births and deaths on a single
// thread.
@@ -250,9 +284,9 @@ NowFunction* ThreadData::now_function_ = NULL;
// static
bool ThreadData::now_function_is_time_ = false;
-// A TLS slot which points to the ThreadData instance for the current thread. We
-// do a fake initialization here (zeroing out data), and then the real in-place
-// construction happens when we call tls_index_.Initialize().
+// A TLS slot which points to the ThreadData instance for the current thread.
+// We do a fake initialization here (zeroing out data), and then the real
+// in-place construction happens when we call tls_index_.Initialize().
// static
base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
@@ -300,14 +334,15 @@ ThreadData::ThreadData(int thread_number)
PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
}
-ThreadData::~ThreadData() {}
+ThreadData::~ThreadData() {
+}
void ThreadData::PushToHeadOfList() {
// Toss in a hint of randomness (atop the uniniitalized value).
(void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
sizeof(random_number_));
MSAN_UNPOISON(&random_number_, sizeof(random_number_));
- random_number_ += static_cast<int32>(this - static_cast<ThreadData*>(0));
+ random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
DCHECK(!next_);
@@ -327,8 +362,7 @@ ThreadData* ThreadData::next() const { return next_; }
// static
void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
- if (!Initialize()) // Always initialize if needed.
- return;
+ Initialize();
ThreadData* current_thread_data =
reinterpret_cast<ThreadData*>(tls_index_.Get());
if (current_thread_data)
@@ -373,10 +407,8 @@ ThreadData* ThreadData::Get() {
// static
void ThreadData::OnThreadTermination(void* thread_data) {
DCHECK(thread_data); // TLS should *never* call us with a NULL.
- // We must NOT do any allocations during this callback. There is a chance
+ // We must NOT do any allocations during this callback. There is a chance
// that the allocator is no longer active on this thread.
- if (!kTrackAllTaskObjects)
- return; // Not compiled in.
reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
}
@@ -399,25 +431,56 @@ void ThreadData::OnThreadTerminationCleanup() {
}
// static
-void ThreadData::Snapshot(bool reset_max, ProcessDataSnapshot* process_data) {
- // Add births that have run to completion to |collected_data|.
- // |birth_counts| tracks the total number of births recorded at each location
- // for which we have not seen a death count.
+void ThreadData::Snapshot(int current_profiling_phase,
+ ProcessDataSnapshot* process_data_snapshot) {
+ // Get an unchanging copy of a ThreadData list.
+ ThreadData* my_list = ThreadData::first();
+
+ // Gather data serially.
+ // This hackish approach *can* get some slightly corrupt tallies, as we are
+ // grabbing values without the protection of a lock, but it has the advantage
+ // of working even with threads that don't have message loops. If a user
+ // sees any strangeness, they can always just run their stats gathering a
+ // second time.
BirthCountMap birth_counts;
- ThreadData::SnapshotAllExecutedTasks(reset_max, process_data, &birth_counts);
+ for (ThreadData* thread_data = my_list; thread_data;
+ thread_data = thread_data->next()) {
+ thread_data->SnapshotExecutedTasks(current_profiling_phase,
+ &process_data_snapshot->phased_snapshots,
+ &birth_counts);
+ }
// Add births that are still active -- i.e. objects that have tallied a birth,
// but have not yet tallied a matching death, and hence must be either
// running, queued up, or being held in limbo for future posting.
- for (BirthCountMap::const_iterator it = birth_counts.begin();
- it != birth_counts.end(); ++it) {
- if (it->second > 0) {
- process_data->tasks.push_back(
- TaskSnapshot(*it->first, DeathData(it->second), "Still_Alive"));
+ auto* current_phase_tasks =
+ &process_data_snapshot->phased_snapshots[current_profiling_phase].tasks;
+ for (const auto& birth_count : birth_counts) {
+ if (birth_count.second > 0) {
+ current_phase_tasks->push_back(
+ TaskSnapshot(BirthOnThreadSnapshot(*birth_count.first),
+ DeathDataSnapshot(birth_count.second, 0, 0, 0, 0, 0, 0),
+ "Still_Alive"));
}
}
}
+// static
+void ThreadData::OnProfilingPhaseCompleted(int profiling_phase) {
+ // Get an unchanging copy of a ThreadData list.
+ ThreadData* my_list = ThreadData::first();
+
+ // Add snapshots for all instances of death data in all threads serially.
+ // This hackish approach *can* get some slightly corrupt tallies, as we are
+ // grabbing values without the protection of a lock, but it has the advantage
+ // of working even with threads that don't have message loops. Any corruption
+ // shouldn't cause "cascading damage" to anything else (in later phases).
+ for (ThreadData* thread_data = my_list; thread_data;
+ thread_data = thread_data->next()) {
+ thread_data->OnProfilingPhaseCompletedOnThread(profiling_phase);
+ }
+}
+
Births* ThreadData::TallyABirth(const Location& location) {
BirthMap::iterator it = birth_map_.find(location);
Births* child;
@@ -432,33 +495,21 @@ Births* ThreadData::TallyABirth(const Location& location) {
birth_map_[location] = child;
}
- if (kTrackParentChildLinks && status_ > PROFILING_ACTIVE &&
- !parent_stack_.empty()) {
- const Births* parent = parent_stack_.top();
- ParentChildPair pair(parent, child);
- if (parent_child_set_.find(pair) == parent_child_set_.end()) {
- // Lock since the map may get relocated now, and other threads sometimes
- // snapshot it (but they lock before copying it).
- base::AutoLock lock(map_lock_);
- parent_child_set_.insert(pair);
- }
- }
-
return child;
}
-void ThreadData::TallyADeath(const Births& birth,
+void ThreadData::TallyADeath(const Births& births,
int32 queue_duration,
const TaskStopwatch& stopwatch) {
int32 run_duration = stopwatch.RunDurationMs();
// Stir in some randomness, plus add constant in case durations are zero.
- const int32 kSomePrimeNumber = 2147483647;
+ const uint32 kSomePrimeNumber = 2147483647;
random_number_ += queue_duration + run_duration + kSomePrimeNumber;
// An address is going to have some randomness to it as well ;-).
- random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
+ random_number_ ^= static_cast<uint32>(&births - reinterpret_cast<Births*>(0));
- // We don't have queue durations without OS timer. OS timer is automatically
+ // We don't have queue durations without OS timer. OS timer is automatically
// used for task-post-timing, so the use of an alternate timer implies all
// queue times are invalid, unless it was explicitly said that we can trust
// the alternate timer.
@@ -468,29 +519,19 @@ void ThreadData::TallyADeath(const Births& birth,
queue_duration = 0;
}
- DeathMap::iterator it = death_map_.find(&birth);
+ DeathMap::iterator it = death_map_.find(&births);
DeathData* death_data;
if (it != death_map_.end()) {
death_data = &it->second;
} else {
base::AutoLock lock(map_lock_); // Lock as the map may get relocated now.
- death_data = &death_map_[&birth];
+ death_data = &death_map_[&births];
} // Release lock ASAP.
death_data->RecordDeath(queue_duration, run_duration, random_number_);
-
- if (!kTrackParentChildLinks)
- return;
- if (!parent_stack_.empty()) { // We might get turned off.
- DCHECK_EQ(parent_stack_.top(), &birth);
- parent_stack_.pop();
- }
}
// static
Births* ThreadData::TallyABirthIfActive(const Location& location) {
- if (!kTrackAllTaskObjects)
- return NULL; // Not compiled in.
-
if (!TrackingStatus())
return NULL;
ThreadData* current_thread_data = Get();
@@ -503,14 +544,11 @@ Births* ThreadData::TallyABirthIfActive(const Location& location) {
void ThreadData::TallyRunOnNamedThreadIfTracking(
const base::TrackingInfo& completed_task,
const TaskStopwatch& stopwatch) {
- if (!kTrackAllTaskObjects)
- return; // Not compiled in.
-
// Even if we have been DEACTIVATED, we will process any pending births so
// that our data structures (which counted the outstanding births) remain
// consistent.
- const Births* birth = completed_task.birth_tally;
- if (!birth)
+ const Births* births = completed_task.birth_tally;
+ if (!births)
return;
ThreadData* current_thread_data = stopwatch.GetThreadData();
if (!current_thread_data)
@@ -519,7 +557,7 @@ void ThreadData::TallyRunOnNamedThreadIfTracking(
// Watch out for a race where status_ is changing, and hence one or both
// of start_of_run or end_of_run is zero. In that case, we didn't bother to
// get a time value since we "weren't tracking" and we were trying to be
- // efficient by not calling for a genuine time value. For simplicity, we'll
+ // efficient by not calling for a genuine time value. For simplicity, we'll
// use a default zero duration when we can't calculate a true value.
TrackedTime start_of_run = stopwatch.StartTime();
int32 queue_duration = 0;
@@ -527,21 +565,18 @@ void ThreadData::TallyRunOnNamedThreadIfTracking(
queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
.InMilliseconds();
}
- current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+ current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
// static
void ThreadData::TallyRunOnWorkerThreadIfTracking(
- const Births* birth,
+ const Births* births,
const TrackedTime& time_posted,
const TaskStopwatch& stopwatch) {
- if (!kTrackAllTaskObjects)
- return; // Not compiled in.
-
// Even if we have been DEACTIVATED, we will process any pending births so
// that our data structures (which counted the outstanding births) remain
// consistent.
- if (!birth)
+ if (!births)
return;
// TODO(jar): Support the option to coalesce all worker-thread activity under
@@ -549,7 +584,7 @@ void ThreadData::TallyRunOnWorkerThreadIfTracking(
// reduce memory (making it provably bounded), but run incrementally slower
// (since we'll use locks on TallyABirth and TallyADeath). The good news is
// that the locks on TallyADeath will be *after* the worker thread has run,
- // and hence nothing will be waiting for the completion (... besides some
+ // and hence nothing will be waiting for the completion (... besides some
// other thread that might like to run). Also, the worker threads tasks are
// generally longer, and hence the cost of the lock may perchance be amortized
// over the long task's lifetime.
@@ -562,20 +597,17 @@ void ThreadData::TallyRunOnWorkerThreadIfTracking(
if (!start_of_run.is_null()) {
queue_duration = (start_of_run - time_posted).InMilliseconds();
}
- current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+ current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
// static
void ThreadData::TallyRunInAScopedRegionIfTracking(
- const Births* birth,
+ const Births* births,
const TaskStopwatch& stopwatch) {
- if (!kTrackAllTaskObjects)
- return; // Not compiled in.
-
// Even if we have been DEACTIVATED, we will process any pending births so
// that our data structures (which counted the outstanding births) remain
// consistent.
- if (!birth)
+ if (!births)
return;
ThreadData* current_thread_data = stopwatch.GetThreadData();
@@ -583,105 +615,74 @@ void ThreadData::TallyRunInAScopedRegionIfTracking(
return;
int32 queue_duration = 0;
- current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
+ current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
-// static
-void ThreadData::SnapshotAllExecutedTasks(bool reset_max,
- ProcessDataSnapshot* process_data,
- BirthCountMap* birth_counts) {
- if (!kTrackAllTaskObjects)
- return; // Not compiled in.
-
- // Get an unchanging copy of a ThreadData list.
- ThreadData* my_list = ThreadData::first();
-
- // Gather data serially.
- // This hackish approach *can* get some slighly corrupt tallies, as we are
- // grabbing values without the protection of a lock, but it has the advantage
- // of working even with threads that don't have message loops. If a user
- // sees any strangeness, they can always just run their stats gathering a
- // second time.
- for (ThreadData* thread_data = my_list;
- thread_data;
- thread_data = thread_data->next()) {
- thread_data->SnapshotExecutedTasks(reset_max, process_data, birth_counts);
- }
-}
-
-void ThreadData::SnapshotExecutedTasks(bool reset_max,
- ProcessDataSnapshot* process_data,
- BirthCountMap* birth_counts) {
+void ThreadData::SnapshotExecutedTasks(
+ int current_profiling_phase,
+ PhasedProcessDataSnapshotMap* phased_snapshots,
+ BirthCountMap* birth_counts) {
// Get copy of data, so that the data will not change during the iterations
// and processing.
- ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- SnapshotMaps(reset_max, &birth_map, &death_map, &parent_child_set);
-
- for (ThreadData::DeathMap::const_iterator it = death_map.begin();
- it != death_map.end(); ++it) {
- process_data->tasks.push_back(
- TaskSnapshot(*it->first, it->second, thread_name()));
- (*birth_counts)[it->first] -= it->first->birth_count();
- }
+ BirthMap birth_map;
+ DeathsSnapshot deaths;
+ SnapshotMaps(current_profiling_phase, &birth_map, &deaths);
- for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
- it != birth_map.end(); ++it) {
- (*birth_counts)[it->second] += it->second->birth_count();
+ for (const auto& birth : birth_map) {
+ (*birth_counts)[birth.second] += birth.second->birth_count();
}
- if (!kTrackParentChildLinks)
- return;
-
- for (ThreadData::ParentChildSet::const_iterator it = parent_child_set.begin();
- it != parent_child_set.end(); ++it) {
- process_data->descendants.push_back(ParentChildPairSnapshot(*it));
+ for (const auto& death : deaths) {
+ (*birth_counts)[death.first] -= death.first->birth_count();
+
+ // For the current death data, walk through all its snapshots, starting from
+ // the current one, then from the previous profiling phase etc., and for
+ // each snapshot calculate the delta between the snapshot and the previous
+ // phase, if any. Store the deltas in the result.
+ for (const DeathDataPhaseSnapshot* phase = &death.second; phase;
+ phase = phase->prev) {
+ const DeathDataSnapshot& death_data =
+ phase->prev ? phase->death_data.Delta(phase->prev->death_data)
+ : phase->death_data;
+
+ if (death_data.count > 0) {
+ (*phased_snapshots)[phase->profiling_phase].tasks.push_back(
+ TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data,
+ thread_name()));
+ }
+ }
}
}
// This may be called from another thread.
-void ThreadData::SnapshotMaps(bool reset_max,
+void ThreadData::SnapshotMaps(int profiling_phase,
BirthMap* birth_map,
- DeathMap* death_map,
- ParentChildSet* parent_child_set) {
+ DeathsSnapshot* deaths) {
base::AutoLock lock(map_lock_);
- for (BirthMap::const_iterator it = birth_map_.begin();
- it != birth_map_.end(); ++it)
- (*birth_map)[it->first] = it->second;
- for (DeathMap::iterator it = death_map_.begin();
- it != death_map_.end(); ++it) {
- (*death_map)[it->first] = it->second;
- if (reset_max)
- it->second.ResetMax();
- }
-
- if (!kTrackParentChildLinks)
- return;
-
- for (ParentChildSet::iterator it = parent_child_set_.begin();
- it != parent_child_set_.end(); ++it)
- parent_child_set->insert(*it);
-}
-
-// static
-void ThreadData::ResetAllThreadData() {
- ThreadData* my_list = first();
- for (ThreadData* thread_data = my_list;
- thread_data;
- thread_data = thread_data->next())
- thread_data->Reset();
+ for (const auto& birth : birth_map_)
+ (*birth_map)[birth.first] = birth.second;
+
+ for (const auto& death : death_map_) {
+ deaths->push_back(std::make_pair(
+ death.first,
+ DeathDataPhaseSnapshot(profiling_phase, death.second.count(),
+ death.second.run_duration_sum(),
+ death.second.run_duration_max(),
+ death.second.run_duration_sample(),
+ death.second.queue_duration_sum(),
+ death.second.queue_duration_max(),
+ death.second.queue_duration_sample(),
+ death.second.last_phase_snapshot())));
+ }
}
-void ThreadData::Reset() {
+void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) {
base::AutoLock lock(map_lock_);
- for (DeathMap::iterator it = death_map_.begin();
- it != death_map_.end(); ++it)
- it->second.Clear();
- for (BirthMap::iterator it = birth_map_.begin();
- it != birth_map_.end(); ++it)
- it->second->Clear();
+
+ for (auto& death : death_map_) {
+ death.second.OnProfilingPhaseCompleted(profiling_phase);
+ }
}
static void OptionallyInitializeAlternateTimer() {
@@ -690,11 +691,9 @@ static void OptionallyInitializeAlternateTimer() {
ThreadData::SetAlternateTimeSource(alternate_time_source);
}
-bool ThreadData::Initialize() {
- if (!kTrackAllTaskObjects)
- return false; // Not compiled in.
+void ThreadData::Initialize() {
if (status_ >= DEACTIVATED)
- return true; // Someone else did the initialization.
+ return; // Someone else did the initialization.
// Due to racy lazy initialization in tests, we'll need to recheck status_
// after we acquire the lock.
@@ -703,7 +702,7 @@ bool ThreadData::Initialize() {
// initialization.
base::AutoLock lock(*list_lock_.Pointer());
if (status_ >= DEACTIVATED)
- return true; // Someone raced in here and beat us.
+ return; // Someone raced in here and beat us.
// Put an alternate timer in place if the environment calls for it, such as
// for tracking TCMalloc allocations. This insertion is idempotent, so we
@@ -717,8 +716,7 @@ bool ThreadData::Initialize() {
if (!tls_index_.initialized()) { // Testing may have initialized this.
DCHECK_EQ(status_, UNINITIALIZED);
tls_index_.Initialize(&ThreadData::OnThreadTermination);
- if (!tls_index_.initialized())
- return false;
+ DCHECK(tls_index_.initialized());
} else {
// TLS was initialzed for us earlier.
DCHECK_EQ(status_, DORMANT_DURING_TESTS);
@@ -728,29 +726,23 @@ bool ThreadData::Initialize() {
// never again change in this process.
++incarnation_counter_;
- // The lock is not critical for setting status_, but it doesn't hurt. It also
+ // The lock is not critical for setting status_, but it doesn't hurt. It also
// ensures that if we have a racy initialization, that we'll bail as soon as
// we get the lock earlier in this method.
status_ = kInitialStartupState;
- if (!kTrackParentChildLinks &&
- kInitialStartupState == PROFILING_CHILDREN_ACTIVE)
- status_ = PROFILING_ACTIVE;
DCHECK(status_ != UNINITIALIZED);
- return true;
}
// static
-bool ThreadData::InitializeAndSetTrackingStatus(Status status) {
+void ThreadData::InitializeAndSetTrackingStatus(Status status) {
DCHECK_GE(status, DEACTIVATED);
- DCHECK_LE(status, PROFILING_CHILDREN_ACTIVE);
+ DCHECK_LE(status, PROFILING_ACTIVE);
- if (!Initialize()) // No-op if already initialized.
- return false; // Not compiled in.
+ Initialize(); // No-op if already initialized.
- if (!kTrackParentChildLinks && status > DEACTIVATED)
+ if (status > DEACTIVATED)
status = PROFILING_ACTIVE;
status_ = status;
- return true;
}
// static
@@ -764,20 +756,6 @@ bool ThreadData::TrackingStatus() {
}
// static
-bool ThreadData::TrackingParentChildStatus() {
- return status_ >= PROFILING_CHILDREN_ACTIVE;
-}
-
-// static
-void ThreadData::PrepareForStartOfRun(const Births* parent) {
- if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) {
- ThreadData* current_thread_data = Get();
- if (current_thread_data)
- current_thread_data->parent_stack_.push(parent);
- }
-}
-
-// static
void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
DCHECK(now_function);
if (kAllowAlternateTimeSourceHandling)
@@ -793,7 +771,7 @@ void ThreadData::EnableProfilerTiming() {
TrackedTime ThreadData::Now() {
if (kAllowAlternateTimeSourceHandling && now_function_)
return TrackedTime::FromMilliseconds((*now_function_)());
- if (kTrackAllTaskObjects && IsProfilerTimingEnabled() && TrackingStatus())
+ if (IsProfilerTimingEnabled() && TrackingStatus())
return TrackedTime::Now();
return TrackedTime(); // Super fast when disabled, or not compiled.
}
@@ -818,8 +796,8 @@ void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
// This is only called from test code, where we need to cleanup so that
// additional tests can be run.
// We must be single threaded... but be careful anyway.
- if (!InitializeAndSetTrackingStatus(DEACTIVATED))
- return;
+ InitializeAndSetTrackingStatus(DEACTIVATED);
+
ThreadData* thread_data_list;
{
base::AutoLock lock(*list_lock_.Pointer());
@@ -873,21 +851,21 @@ TaskStopwatch::TaskStopwatch()
current_thread_data_(NULL),
excluded_duration_ms_(0),
parent_(NULL) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
state_ = CREATED;
child_ = NULL;
#endif
}
TaskStopwatch::~TaskStopwatch() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(state_ != RUNNING);
DCHECK(child_ == NULL);
#endif
}
void TaskStopwatch::Start() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(state_ == CREATED);
state_ = RUNNING;
#endif
@@ -899,7 +877,7 @@ void TaskStopwatch::Start() {
return;
parent_ = current_thread_data_->current_stopwatch_;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
if (parent_) {
DCHECK(parent_->state_ == RUNNING);
DCHECK(parent_->child_ == NULL);
@@ -911,7 +889,7 @@ void TaskStopwatch::Start() {
void TaskStopwatch::Stop() {
const TrackedTime end_time = ThreadData::Now();
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(state_ == RUNNING);
state_ = STOPPED;
DCHECK(child_ == NULL);
@@ -929,7 +907,7 @@ void TaskStopwatch::Stop() {
if (!parent_)
return;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(parent_->state_ == RUNNING);
DCHECK(parent_->child_ == this);
parent_->child_ = NULL;
@@ -939,7 +917,7 @@ void TaskStopwatch::Stop() {
}
TrackedTime TaskStopwatch::StartTime() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(state_ != CREATED);
#endif
@@ -947,7 +925,7 @@ TrackedTime TaskStopwatch::StartTime() const {
}
int32 TaskStopwatch::RunDurationMs() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(state_ == STOPPED);
#endif
@@ -955,7 +933,7 @@ int32 TaskStopwatch::RunDurationMs() const {
}
ThreadData* TaskStopwatch::GetThreadData() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(state_ != CREATED);
#endif
@@ -963,11 +941,37 @@ ThreadData* TaskStopwatch::GetThreadData() const {
}
//------------------------------------------------------------------------------
+// DeathDataPhaseSnapshot
+
+DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
+ int profiling_phase,
+ int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample,
+ const DeathDataPhaseSnapshot* prev)
+ : profiling_phase(profiling_phase),
+ death_data(count,
+ run_duration_sum,
+ run_duration_max,
+ run_duration_sample,
+ queue_duration_sum,
+ queue_duration_max,
+ queue_duration_sample),
+ prev(prev) {
+}
+
+//------------------------------------------------------------------------------
+// TaskSnapshot
+
TaskSnapshot::TaskSnapshot() {
}
-TaskSnapshot::TaskSnapshot(const BirthOnThread& birth,
- const DeathData& death_data,
+TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth,
+ const DeathDataSnapshot& death_data,
const std::string& death_thread_name)
: birth(birth),
death_data(death_data),
@@ -978,28 +982,22 @@ TaskSnapshot::~TaskSnapshot() {
}
//------------------------------------------------------------------------------
-// ParentChildPairSnapshot
-
-ParentChildPairSnapshot::ParentChildPairSnapshot() {
-}
+// ProcessDataPhaseSnapshot
-ParentChildPairSnapshot::ParentChildPairSnapshot(
- const ThreadData::ParentChildPair& parent_child)
- : parent(*parent_child.first),
- child(*parent_child.second) {
+ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
}
-ParentChildPairSnapshot::~ParentChildPairSnapshot() {
+ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() {
}
//------------------------------------------------------------------------------
-// ProcessDataSnapshot
+// ProcessDataPhaseSnapshot
ProcessDataSnapshot::ProcessDataSnapshot()
#if !defined(OS_NACL)
: process_id(base::GetCurrentProcId()) {
#else
- : process_id(0) {
+ : process_id(base::kNullProcessId) {
#endif
}
diff --git a/chromium/base/tracked_objects.h b/chromium/base/tracked_objects.h
index 50bea47987f..8f8379409db 100644
--- a/chromium/base/tracked_objects.h
+++ b/chromium/base/tracked_objects.h
@@ -14,12 +14,15 @@
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
#include "base/location.h"
+#include "base/process/process_handle.h"
#include "base/profiler/alternate_timer.h"
#include "base/profiler/tracked_time.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
#include "base/threading/thread_local_storage.h"
namespace base {
@@ -43,7 +46,7 @@ struct TrackingInfo;
// computational cost is associated with obtaining start and stop times for
// instances as they are created and destroyed.
//
-// The following describes the lifecycle of tracking an instance.
+// The following describes the life cycle of tracking an instance.
//
// First off, when the instance is created, the FROM_HERE macro is expanded
// to specify the birth place (file, line, function) where the instance was
@@ -83,7 +86,7 @@ struct TrackingInfo;
// threads there are, and how many Locations of construction there are.
// Fortunately, we don't use memory that is the product of those two counts, but
// rather we only need one Births instance for each thread that constructs an
-// instance at a Location. In many cases, instances are only created on one
+// instance at a Location. In many cases, instances are only created on one
// thread, so the memory utilization is actually fairly restrained.
//
// Lastly, when an instance is deleted, the final tallies of statistics are
@@ -96,22 +99,22 @@ struct TrackingInfo;
// lock such DeathData instances. (i.e., these accumulated stats in a DeathData
// instance are exclusively updated by the singular owning thread).
//
-// With the above lifecycle description complete, the major remaining detail is
-// explaining how each thread maintains a list of DeathData instances, and of
-// Births instances, and is able to avoid additional (redundant/unnecessary)
+// With the above life cycle description complete, the major remaining detail
+// is explaining how each thread maintains a list of DeathData instances, and
+// of Births instances, and is able to avoid additional (redundant/unnecessary)
// allocations.
//
// Each thread maintains a list of data items specific to that thread in a
// ThreadData instance (for that specific thread only). The two critical items
// are lists of DeathData and Births instances. These lists are maintained in
-// STL maps, which are indexed by Location. As noted earlier, we can compare
+// STL maps, which are indexed by Location. As noted earlier, we can compare
// locations very efficiently as we consider the underlying data (file,
// function, line) to be atoms, and hence pointer comparison is used rather than
// (slow) string comparisons.
//
// To provide a mechanism for iterating over all "known threads," which means
// threads that have recorded a birth or a death, we create a singly linked list
-// of ThreadData instances. Each such instance maintains a pointer to the next
+// of ThreadData instances. Each such instance maintains a pointer to the next
// one. A static member of ThreadData provides a pointer to the first item on
// this global list, and access via that all_thread_data_list_head_ item
// requires the use of the list_lock_.
@@ -119,7 +122,7 @@ struct TrackingInfo;
// which ensures that any prior acquisition of the list is valid (i.e., the
// holder can iterate over it without fear of it changing, or the necessity of
// using an additional lock. Iterations are actually pretty rare (used
-// primarilly for cleanup, or snapshotting data for display), so this lock has
+// primarily for cleanup, or snapshotting data for display), so this lock has
// very little global performance impact.
//
// The above description tries to define the high performance (run time)
@@ -146,17 +149,20 @@ struct TrackingInfo;
// TaskSnapshot instances, so that such instances can be sorted and
// aggregated (and remain frozen during our processing).
//
-// The ProcessDataSnapshot struct is a serialized representation of the list
-// of ThreadData objects for a process. It holds a set of TaskSnapshots
-// and tracks parent/child relationships for the executed tasks. The statistics
-// in a snapshot are gathered asynhcronously relative to their ongoing updates.
+// Profiling consists of phases. The concrete phase in the sequence of phases
+// is identified by its 0-based index.
+//
+// The ProcessDataPhaseSnapshot struct is a serialized representation of the
+// list of ThreadData objects for a process for a concrete profiling phase. It
+// holds a set of TaskSnapshots. The statistics in a snapshot are gathered
+// asynhcronously relative to their ongoing updates.
// It is possible, though highly unlikely, that stats could be incorrectly
// recorded by this process (all data is held in 32 bit ints, but we are not
// atomically collecting all data, so we could have count that does not, for
// example, match with the number of durations we accumulated). The advantage
// to having fast (non-atomic) updates of the data outweighs the minimal risk of
// a singular corrupt statistic snapshot (only the snapshot could be corrupt,
-// not the underlying and ongoing statistic). In constrast, pointer data that
+// not the underlying and ongoing statistic). In contrast, pointer data that
// is accessed during snapshotting is completely invariant, and hence is
// perfectly acquired (i.e., no potential corruption, and no risk of a bad
// memory reference).
@@ -167,21 +173,14 @@ struct TrackingInfo;
// them will continue to be asynchronous). We had an implementation of this in
// the past, but the difficulty is dealing with message loops being terminated.
// We can *try* to spam the available threads via some message loop proxy to
-// achieve this feat, and it *might* be valuable when we are colecting data for
-// upload via UMA (where correctness of data may be more significant than for a
-// single screen of about:profiler).
-//
-// TODO(jar): We should support (optionally) the recording of parent-child
-// relationships for tasks. This should be done by detecting what tasks are
-// Born during the running of a parent task. The resulting data can be used by
-// a smarter profiler to aggregate the cost of a series of child tasks into
-// the ancestor task. It can also be used to illuminate what child or parent is
-// related to each task.
+// achieve this feat, and it *might* be valuable when we are collecting data
+// for upload via UMA (where correctness of data may be more significant than
+// for a single screen of about:profiler).
//
// TODO(jar): We need to store DataCollections, and provide facilities for
// taking the difference between two gathered DataCollections. For now, we're
// just adding a hack that Reset()s to zero all counts and stats. This is also
-// done in a slighly thread-unsafe fashion, as the resetting is done
+// done in a slightly thread-unsafe fashion, as the resetting is done
// asynchronously relative to ongoing updates (but all data is 32 bit in size).
// For basic profiling, this will work "most of the time," and should be
// sufficient... but storing away DataCollections is the "right way" to do this.
@@ -240,13 +239,6 @@ class BASE_EXPORT Births: public BirthOnThread {
// When we have a birth we update the count for this birthplace.
void RecordBirth();
- // When a birthplace is changed (updated), we need to decrement the counter
- // for the old instance.
- void ForgetBirth();
-
- // Hack to quickly reset all counts to zero.
- void Clear();
-
private:
// The number of births on this thread for our location_.
int birth_count_;
@@ -255,74 +247,139 @@ class BASE_EXPORT Births: public BirthOnThread {
};
//------------------------------------------------------------------------------
-// Basic info summarizing multiple destructions of a tracked object with a
-// single birthplace (fixed Location). Used both on specific threads, and also
-// in snapshots when integrating assembled data.
+// A "snapshotted" representation of the DeathData class.
+
+struct BASE_EXPORT DeathDataSnapshot {
+ DeathDataSnapshot();
+
+ // Constructs the snapshot from individual values.
+ // The alternative would be taking a DeathData parameter, but this would
+ // create a loop since DeathData indirectly refers DeathDataSnapshot. Passing
+ // a wrapper structure as a param or using an empty constructor for
+ // snapshotting DeathData would be less efficient.
+ DeathDataSnapshot(int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample);
+ ~DeathDataSnapshot();
+
+ // Calculates and returns the delta between this snapshot and an earlier
+ // snapshot of the same task |older|.
+ DeathDataSnapshot Delta(const DeathDataSnapshot& older) const;
+
+ int count;
+ int32 run_duration_sum;
+ int32 run_duration_max;
+ int32 run_duration_sample;
+ int32 queue_duration_sum;
+ int32 queue_duration_max;
+ int32 queue_duration_sample;
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData for a particular profiling
+// phase. Used as an element of the list of phase snapshots owned by DeathData.
+
+struct DeathDataPhaseSnapshot {
+ DeathDataPhaseSnapshot(int profiling_phase,
+ int count,
+ int32 run_duration_sum,
+ int32 run_duration_max,
+ int32 run_duration_sample,
+ int32 queue_duration_sum,
+ int32 queue_duration_max,
+ int32 queue_duration_sample,
+ const DeathDataPhaseSnapshot* prev);
+
+ // Profiling phase at which completion this snapshot was taken.
+ int profiling_phase;
+
+ // Death data snapshot.
+ DeathDataSnapshot death_data;
+
+ // Pointer to a snapshot from the previous phase.
+ const DeathDataPhaseSnapshot* prev;
+};
+
+//------------------------------------------------------------------------------
+// Information about deaths of a task on a given thread, called "death thread".
+// Access to members of this class is never protected by a lock. The fields
+// are accessed in such a way that corruptions resulting from race conditions
+// are not significant, and don't accumulate as a result of multiple accesses.
+// All invocations of DeathData::OnProfilingPhaseCompleted and
+// ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process
+// must be called from the same thread. It doesn't matter what thread it is, but
+// it's important the same thread is used as a snapshot thread during the whole
+// process lifetime. All fields except sample_probability_count_ can be
+// snapshotted.
class BASE_EXPORT DeathData {
public:
- // Default initializer.
DeathData();
-
- // When deaths have not yet taken place, and we gather data from all the
- // threads, we create DeathData stats that tally the number of births without
- // a corresponding death.
- explicit DeathData(int count);
+ DeathData(const DeathData& other);
+ ~DeathData();
// Update stats for a task destruction (death) that had a Run() time of
// |duration|, and has had a queueing delay of |queue_duration|.
void RecordDeath(const int32 queue_duration,
const int32 run_duration,
- int random_number);
-
- // Metrics accessors, used only for serialization and in tests.
- int count() const;
- int32 run_duration_sum() const;
- int32 run_duration_max() const;
- int32 run_duration_sample() const;
- int32 queue_duration_sum() const;
- int32 queue_duration_max() const;
- int32 queue_duration_sample() const;
-
- // Reset the max values to zero.
- void ResetMax();
-
- // Reset all tallies to zero. This is used as a hack on realtime data.
- void Clear();
+ const uint32 random_number);
+
+ // Metrics and past snapshots accessors, used only for serialization and in
+ // tests.
+ int count() const { return count_; }
+ int32 run_duration_sum() const { return run_duration_sum_; }
+ int32 run_duration_max() const { return run_duration_max_; }
+ int32 run_duration_sample() const { return run_duration_sample_; }
+ int32 queue_duration_sum() const { return queue_duration_sum_; }
+ int32 queue_duration_max() const { return queue_duration_max_; }
+ int32 queue_duration_sample() const { return queue_duration_sample_; }
+ const DeathDataPhaseSnapshot* last_phase_snapshot() const {
+ return last_phase_snapshot_;
+ }
+
+ // Called when the current profiling phase, identified by |profiling_phase|,
+ // ends.
+ // Must be called only on the snapshot thread.
+ void OnProfilingPhaseCompleted(int profiling_phase);
private:
// Members are ordered from most regularly read and updated, to least
// frequently used. This might help a bit with cache lines.
// Number of runs seen (divisor for calculating averages).
+ // Can be incremented only on the death thread.
int count_;
- // Basic tallies, used to compute averages.
+
+ // Count used in determining probability of selecting exec/queue times from a
+ // recorded death as samples.
+ // Gets incremented only on the death thread, but can be set to 0 by
+ // OnProfilingPhaseCompleted() on the snapshot thread.
+ int sample_probability_count_;
+
+ // Basic tallies, used to compute averages. Can be incremented only on the
+ // death thread.
int32 run_duration_sum_;
int32 queue_duration_sum_;
// Max values, used by local visualization routines. These are often read,
- // but rarely updated.
+ // but rarely updated. The max values get assigned only on the death thread,
+ // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the
+ // snapshot thread.
int32 run_duration_max_;
int32 queue_duration_max_;
// Samples, used by crowd sourcing gatherers. These are almost never read,
- // and rarely updated.
+ // and rarely updated. They can be modified only on the death thread.
int32 run_duration_sample_;
int32 queue_duration_sample_;
-};
-//------------------------------------------------------------------------------
-// A "snapshotted" representation of the DeathData class.
+ // Snapshot of this death data made at the last profiling phase completion, if
+ // any. DeathData owns the whole list starting with this pointer.
+ // Can be accessed only on the snapshot thread.
+ const DeathDataPhaseSnapshot* last_phase_snapshot_;
-struct BASE_EXPORT DeathDataSnapshot {
- DeathDataSnapshot();
- explicit DeathDataSnapshot(const DeathData& death_data);
- ~DeathDataSnapshot();
-
- int count;
- int32 run_duration_sum;
- int32 run_duration_max;
- int32 run_duration_sample;
- int32 queue_duration_sum;
- int32 queue_duration_max;
- int32 queue_duration_sample;
+ DISALLOW_ASSIGN(DeathData);
};
//------------------------------------------------------------------------------
@@ -334,12 +391,14 @@ struct BASE_EXPORT DeathDataSnapshot {
struct BASE_EXPORT TaskSnapshot {
TaskSnapshot();
- TaskSnapshot(const BirthOnThread& birth,
- const DeathData& death_data,
+ TaskSnapshot(const BirthOnThreadSnapshot& birth,
+ const DeathDataSnapshot& death_data,
const std::string& death_thread_name);
~TaskSnapshot();
BirthOnThreadSnapshot birth;
+ // Delta between death data for a thread for a certain profiling phase and the
+ // snapshot for the pervious phase, if any. Otherwise, just a snapshot.
DeathDataSnapshot death_data;
std::string death_thread_name;
};
@@ -351,27 +410,29 @@ struct BASE_EXPORT TaskSnapshot {
// We also have a linked list of ThreadData instances, and that list is used to
// harvest data from all existing instances.
+struct ProcessDataPhaseSnapshot;
struct ProcessDataSnapshot;
class BASE_EXPORT TaskStopwatch;
+// Map from profiling phase number to the process-wide snapshotted
+// representation of the list of ThreadData objects that died during the given
+// phase.
+typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap;
+
class BASE_EXPORT ThreadData {
public:
// Current allowable states of the tracking system. The states can vary
// between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
enum Status {
- UNINITIALIZED, // PRistine, link-time state before running.
- DORMANT_DURING_TESTS, // Only used during testing.
- DEACTIVATED, // No longer recording profling.
- PROFILING_ACTIVE, // Recording profiles (no parent-child links).
- PROFILING_CHILDREN_ACTIVE, // Fully active, recording parent-child links.
- STATUS_LAST = PROFILING_CHILDREN_ACTIVE
+ UNINITIALIZED, // Pristine, link-time state before running.
+ DORMANT_DURING_TESTS, // Only used during testing.
+ DEACTIVATED, // No longer recording profiling.
+ PROFILING_ACTIVE, // Recording profiles.
+ STATUS_LAST = PROFILING_ACTIVE
};
- typedef std::map<Location, Births*> BirthMap;
+ typedef base::hash_map<Location, Births*, Location::Hash> BirthMap;
typedef std::map<const Births*, DeathData> DeathMap;
- typedef std::pair<const Births*, const Births*> ParentChildPair;
- typedef std::set<ParentChildPair> ParentChildSet;
- typedef std::stack<const Births*> ParentStack;
// Initialize the current thread context with a new instance of ThreadData.
// This is used by all threads that have names, and should be explicitly
@@ -385,10 +446,22 @@ class BASE_EXPORT ThreadData {
// This may return NULL if the system is disabled for any reason.
static ThreadData* Get();
- // Fills |process_data| with all the recursive results in our process.
- // During the scavenging, if |reset_max| is true, then the DeathData instances
- // max-values are reset to zero during this scan.
- static void Snapshot(bool reset_max, ProcessDataSnapshot* process_data);
+ // Fills |process_data_snapshot| with phased snapshots of all profiling
+ // phases, including the current one, identified by |current_profiling_phase|.
+ // |current_profiling_phase| is necessary because a child process can start
+ // after several phase-changing events, so it needs to receive the current
+ // phase number from the browser process to fill the correct entry for the
+ // current phase in the |process_data_snapshot| map.
+ static void Snapshot(int current_profiling_phase,
+ ProcessDataSnapshot* process_data_snapshot);
+
+ // Called when the current profiling phase, identified by |profiling_phase|,
+ // ends.
+ // |profiling_phase| is necessary because a child process can start after
+ // several phase-changing events, so it needs to receive the phase number from
+ // the browser process to fill the correct entry in the
+ // completed_phases_snapshots_ map.
+ static void OnProfilingPhaseCompleted(int profiling_phase);
// Finds (or creates) a place to count births from the given location in this
// thread, and increment that tally.
@@ -402,7 +475,7 @@ class BASE_EXPORT ThreadData {
// delayed tasks, and it indicates when the task should have run (i.e., when
// it should have posted out of the timer queue, and into the work queue.
// The |end_of_run| was just obtained by a call to Now() (just after the task
- // finished). It is provided as an argument to help with testing.
+ // finished). It is provided as an argument to help with testing.
static void TallyRunOnNamedThreadIfTracking(
const base::TrackingInfo& completed_task,
const TaskStopwatch& stopwatch);
@@ -414,40 +487,25 @@ class BASE_EXPORT ThreadData {
// the task.
// The |end_of_run| was just obtained by a call to Now() (just after the task
// finished).
- static void TallyRunOnWorkerThreadIfTracking(
- const Births* birth,
- const TrackedTime& time_posted,
- const TaskStopwatch& stopwatch);
+ static void TallyRunOnWorkerThreadIfTracking(const Births* births,
+ const TrackedTime& time_posted,
+ const TaskStopwatch& stopwatch);
// Record the end of execution in region, generally corresponding to a scope
// being exited.
- static void TallyRunInAScopedRegionIfTracking(
- const Births* birth,
- const TaskStopwatch& stopwatch);
+ static void TallyRunInAScopedRegionIfTracking(const Births* births,
+ const TaskStopwatch& stopwatch);
const std::string& thread_name() const { return thread_name_; }
- // Hack: asynchronously clear all birth counts and death tallies data values
- // in all ThreadData instances. The numerical (zeroing) part is done without
- // use of a locks or atomics exchanges, and may (for int64 values) produce
- // bogus counts VERY rarely.
- static void ResetAllThreadData();
-
// Initializes all statics if needed (this initialization call should be made
- // while we are single threaded). Returns false if unable to initialize.
- static bool Initialize();
+ // while we are single threaded).
+ static void Initialize();
// Sets internal status_.
// If |status| is false, then status_ is set to DEACTIVATED.
- // If |status| is true, then status_ is set to, PROFILING_ACTIVE, or
- // PROFILING_CHILDREN_ACTIVE.
- // If tracking is not compiled in, this function will return false.
- // If parent-child tracking is not compiled in, then an attempt to set the
- // status to PROFILING_CHILDREN_ACTIVE will only result in a status of
- // PROFILING_ACTIVE (i.e., it can't be set to a higher level than what is
- // compiled into the binary, and parent-child tracking at the
- // PROFILING_CHILDREN_ACTIVE level might not be compiled in).
- static bool InitializeAndSetTrackingStatus(Status status);
+ // If |status| is true, then status_ is set to PROFILING_ACTIVE.
+ static void InitializeAndSetTrackingStatus(Status status);
static Status status();
@@ -455,17 +513,6 @@ class BASE_EXPORT ThreadData {
// DEACTIVATED).
static bool TrackingStatus();
- // For testing only, indicate if the status of parent-child tracking is turned
- // on. This is currently a compiled option, atop TrackingStatus().
- static bool TrackingParentChildStatus();
-
- // Marks a start of a tracked run. It's super fast when tracking is disabled,
- // and has some internal side effects when we are tracking, so that we can
- // deduce the amount of time accumulated outside of execution of tracked runs.
- // The task that will be tracked is passed in as |parent| so that parent-child
- // relationships can be (optionally) calculated.
- static void PrepareForStartOfRun(const Births* parent);
-
// Enables profiler timing.
static void EnableProfilerTiming();
@@ -496,10 +543,12 @@ class BASE_EXPORT ThreadData {
friend class TrackedObjectsTest;
FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown);
FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown);
- FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest);
typedef std::map<const BirthOnThread*, int> BirthCountMap;
+ typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>>
+ DeathsSnapshot;
+
// Worker thread construction creates a name since there is none.
explicit ThreadData(int thread_number);
@@ -524,43 +573,31 @@ class BASE_EXPORT ThreadData {
Births* TallyABirth(const Location& location);
// Find a place to record a death on this thread.
- void TallyADeath(const Births& birth,
+ void TallyADeath(const Births& births,
int32 queue_duration,
const TaskStopwatch& stopwatch);
- // Snapshot (under a lock) the profiled data for the tasks in each ThreadData
- // instance. Also updates the |birth_counts| tally for each task to keep
- // track of the number of living instances of the task. If |reset_max| is
- // true, then the max values in each DeathData instance are reset during the
- // scan.
- static void SnapshotAllExecutedTasks(bool reset_max,
- ProcessDataSnapshot* process_data,
- BirthCountMap* birth_counts);
-
// Snapshots (under a lock) the profiled data for the tasks for this thread
- // and writes all of the executed tasks' data -- i.e. the data for the tasks
- // with with entries in the death_map_ -- into |process_data|. Also updates
- // the |birth_counts| tally for each task to keep track of the number of
- // living instances of the task -- that is, each task maps to the number of
- // births for the task that have not yet been balanced by a death. If
- // |reset_max| is true, then the max values in each DeathData instance are
- // reset during the scan.
- void SnapshotExecutedTasks(bool reset_max,
- ProcessDataSnapshot* process_data,
+ // and writes all of the executed tasks' data -- i.e. the data for all
+ // profiling phases (including the current one: |current_profiling_phase|) for
+ // the tasks with with entries in the death_map_ -- into |phased_snapshots|.
+ // Also updates the |birth_counts| tally for each task to keep track of the
+ // number of living instances of the task -- that is, each task maps to the
+ // number of births for the task that have not yet been balanced by a death.
+ void SnapshotExecutedTasks(int current_profiling_phase,
+ PhasedProcessDataSnapshotMap* phased_snapshots,
BirthCountMap* birth_counts);
// Using our lock, make a copy of the specified maps. This call may be made
// on non-local threads, which necessitate the use of the lock to prevent
- // the map(s) from being reallocaed while they are copied. If |reset_max| is
- // true, then, just after we copy the DeathMap, we will set the max values to
- // zero in the active DeathMap (not the snapshot).
- void SnapshotMaps(bool reset_max,
+ // the map(s) from being reallocated while they are copied.
+ void SnapshotMaps(int profiling_phase,
BirthMap* birth_map,
- DeathMap* death_map,
- ParentChildSet* parent_child_set);
+ DeathsSnapshot* deaths);
- // Using our lock to protect the iteration, Clear all birth and death data.
- void Reset();
+ // Called for this thread when the current profiling phase, identified by
+ // |profiling_phase|, ends.
+ void OnProfilingPhaseCompletedOnThread(int profiling_phase);
// This method is called by the TLS system when a thread terminates.
// The argument may be NULL if this thread has never tracked a birth or death.
@@ -592,8 +629,8 @@ class BASE_EXPORT ThreadData {
// We use thread local store to identify which ThreadData to interact with.
static base::ThreadLocalStorage::StaticSlot tls_index_;
- // List of ThreadData instances for use with worker threads. When a worker
- // thread is done (terminated), we push it onto this llist. When a new worker
+ // List of ThreadData instances for use with worker threads. When a worker
+ // thread is done (terminated), we push it onto this list. When a new worker
// thread is created, we first try to re-use a ThreadData instance from the
// list, and if none are available, construct a new one.
// This is only accessed while list_lock_ is held.
@@ -609,7 +646,7 @@ class BASE_EXPORT ThreadData {
static int worker_thread_data_creation_count_;
// The number of times TLS has called us back to cleanup a ThreadData
- // instance. This is only accessed while list_lock_ is held.
+ // instance. This is only accessed while list_lock_ is held.
static int cleanup_count_;
// Incarnation sequence number, indicating how many times (during unittests)
@@ -626,7 +663,7 @@ class BASE_EXPORT ThreadData {
// We set status_ to SHUTDOWN when we shut down the tracking service.
static Status status_;
- // Link to next instance (null terminated list). Used to globally track all
+ // Link to next instance (null terminated list). Used to globally track all
// registered instances (corresponds to all registered threads where we keep
// data).
ThreadData* next_;
@@ -658,11 +695,6 @@ class BASE_EXPORT ThreadData {
// locking before reading it.
DeathMap death_map_;
- // A set of parents that created children tasks on this thread. Each pair
- // corresponds to potentially non-local Births (location and thread), and a
- // local Births (that took place on this thread).
- ParentChildSet parent_child_set_;
-
// Lock to protect *some* access to BirthMap and DeathMap. The maps are
// regularly read and written on this thread, but may only be read from other
// threads. To support this, we acquire this lock if we are writing from this
@@ -671,21 +703,11 @@ class BASE_EXPORT ThreadData {
// writing is only done from this thread.
mutable base::Lock map_lock_;
- // The stack of parents that are currently being profiled. This includes only
- // tasks that have started a timer recently via PrepareForStartOfRun(), but
- // not yet concluded with a NowForEndOfRun(). Usually this stack is one deep,
- // but if a scoped region is profiled, or <sigh> a task runs a nested-message
- // loop, then the stack can grow larger. Note that we don't try to deduct
- // time in nested porfiles, as our current timer is based on wall-clock time,
- // and not CPU time (and we're hopeful that nested timing won't be a
- // significant additional cost).
- ParentStack parent_stack_;
-
// A random number that we used to select decide which sample to keep as a
// representative sample in each DeathData instance. We can't start off with
// much randomness (because we can't call RandInt() on all our threads), so
// we stir in more and more as we go.
- int32 random_number_;
+ uint32 random_number_;
// Record of what the incarnation_counter_ was when this instance was created.
// If the incarnation_counter_ has changed, then we avoid pushing into the
@@ -702,7 +724,7 @@ class BASE_EXPORT ThreadData {
//------------------------------------------------------------------------------
// Stopwatch to measure task run time or simply create a time interval that will
-// be subtracted from the current most nested task's run time. Stopwatches
+// be subtracted from the current most nested task's run time. Stopwatches
// coordinate with the stopwatches in which they are nested to avoid
// double-counting nested tasks run times.
@@ -749,43 +771,40 @@ class BASE_EXPORT TaskStopwatch {
// duration of this stopwatch.
TaskStopwatch* parent_;
-#if DCHECK_IS_ON
- // State of the stopwatch. Stopwatch is first constructed in a created state
+#if DCHECK_IS_ON()
+ // State of the stopwatch. Stopwatch is first constructed in a created state
// state, then is optionally started/stopped, then destructed.
enum { CREATED, RUNNING, STOPPED } state_;
// Currently running stopwatch that is directly nested in this one, if such
- // stopwatch exists. NULL otherwise.
+ // stopwatch exists. NULL otherwise.
TaskStopwatch* child_;
#endif
};
//------------------------------------------------------------------------------
-// A snapshotted representation of a (parent, child) task pair, for tracking
-// hierarchical profiles.
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for a single profiling phase.
-struct BASE_EXPORT ParentChildPairSnapshot {
+struct BASE_EXPORT ProcessDataPhaseSnapshot {
public:
- ParentChildPairSnapshot();
- explicit ParentChildPairSnapshot(
- const ThreadData::ParentChildPair& parent_child);
- ~ParentChildPairSnapshot();
+ ProcessDataPhaseSnapshot();
+ ~ProcessDataPhaseSnapshot();
- BirthOnThreadSnapshot parent;
- BirthOnThreadSnapshot child;
+ std::vector<TaskSnapshot> tasks;
};
//------------------------------------------------------------------------------
-// A snapshotted representation of the list of ThreadData objects for a process.
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for all profiling phases, including the current one.
struct BASE_EXPORT ProcessDataSnapshot {
public:
ProcessDataSnapshot();
~ProcessDataSnapshot();
- std::vector<TaskSnapshot> tasks;
- std::vector<ParentChildPairSnapshot> descendants;
- int process_id;
+ PhasedProcessDataSnapshotMap phased_snapshots;
+ base::ProcessId process_id;
};
} // namespace tracked_objects
diff --git a/chromium/base/tracked_objects_unittest.cc b/chromium/base/tracked_objects_unittest.cc
index f19ba7b2c63..cdbf9ac7a6c 100644
--- a/chromium/base/tracked_objects_unittest.cc
+++ b/chromium/base/tracked_objects_unittest.cc
@@ -34,7 +34,7 @@ class TrackedObjectsTest : public testing::Test {
ThreadData::now_function_is_time_ = true;
}
- virtual ~TrackedObjectsTest() {
+ ~TrackedObjectsTest() override {
// We should not need to leak any structures we create, since we are
// single threaded, and carefully accounting for items.
ThreadData::ShutdownSingleThreadedCleanup(false);
@@ -71,28 +71,35 @@ class TrackedObjectsTest : public testing::Test {
int count,
int run_ms,
int queue_ms) {
- ASSERT_EQ(1u, process_data.tasks.size());
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
- EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
+ ASSERT_EQ(1u, process_data_phase.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
EXPECT_EQ(function_name,
- process_data.tasks[0].birth.location.function_name);
- EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
+ process_data_phase.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase.tasks[0].birth.location.line_number);
- EXPECT_EQ(birth_thread, process_data.tasks[0].birth.thread_name);
+ EXPECT_EQ(birth_thread, process_data_phase.tasks[0].birth.thread_name);
- EXPECT_EQ(count, process_data.tasks[0].death_data.count);
+ EXPECT_EQ(count, process_data_phase.tasks[0].death_data.count);
EXPECT_EQ(count * run_ms,
- process_data.tasks[0].death_data.run_duration_sum);
- EXPECT_EQ(run_ms, process_data.tasks[0].death_data.run_duration_max);
- EXPECT_EQ(run_ms, process_data.tasks[0].death_data.run_duration_sample);
+ process_data_phase.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(run_ms, process_data_phase.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(run_ms,
+ process_data_phase.tasks[0].death_data.run_duration_sample);
EXPECT_EQ(count * queue_ms,
- process_data.tasks[0].death_data.queue_duration_sum);
- EXPECT_EQ(queue_ms, process_data.tasks[0].death_data.queue_duration_max);
- EXPECT_EQ(queue_ms, process_data.tasks[0].death_data.queue_duration_sample);
+ process_data_phase.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(queue_ms,
+ process_data_phase.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(queue_ms,
+ process_data_phase.tasks[0].death_data.queue_duration_sample);
- EXPECT_EQ(death_thread, process_data.tasks[0].death_thread_name);
-
- EXPECT_EQ(0u, process_data.descendants.size());
+ EXPECT_EQ(death_thread, process_data_phase.tasks[0].death_thread_name);
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
@@ -112,10 +119,7 @@ class TrackedObjectsTest : public testing::Test {
unsigned int TrackedObjectsTest::test_time_;
TEST_F(TrackedObjectsTest, TaskStopwatchNoStartStop) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
// Check that creating and destroying a stopwatch without starting it doesn't
// crash.
@@ -124,10 +128,7 @@ TEST_F(TrackedObjectsTest, TaskStopwatchNoStartStop) {
TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
// Minimal test doesn't even create any tasks.
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
EXPECT_FALSE(ThreadData::first()); // No activity even on this thread.
ThreadData* data = ThreadData::Get();
@@ -136,19 +137,16 @@ TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
EXPECT_FALSE(data->next());
EXPECT_EQ(data, ThreadData::Get());
ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+ ThreadData::DeathsSnapshot deaths;
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(0u, birth_map.size());
- EXPECT_EQ(0u, death_map.size());
- EXPECT_EQ(0u, parent_child_set.size());
+ EXPECT_EQ(0u, deaths.size());
// Clean up with no leaking.
Reset();
// Do it again, just to be sure we reset state completely.
- EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE));
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
EXPECT_FALSE(ThreadData::first()); // No activity even on this thread.
data = ThreadData::Get();
EXPECT_TRUE(ThreadData::first()); // Now class was constructed.
@@ -156,42 +154,34 @@ TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
EXPECT_FALSE(data->next());
EXPECT_EQ(data, ThreadData::Get());
birth_map.clear();
- death_map.clear();
- parent_child_set.clear();
- data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+ deaths.clear();
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(0u, birth_map.size());
- EXPECT_EQ(0u, death_map.size());
- EXPECT_EQ(0u, parent_child_set.size());
+ EXPECT_EQ(0u, deaths.size());
}
TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
// Instigate tracking on a single tracked object, on our thread.
const char kFunction[] = "TinyStartupShutdown";
Location location(kFunction, kFile, kLineNumber, NULL);
- Births* first_birth = ThreadData::TallyABirthIfActive(location);
+ ThreadData::TallyABirthIfActive(location);
ThreadData* data = ThreadData::first();
ASSERT_TRUE(data);
EXPECT_FALSE(data->next());
EXPECT_EQ(data, ThreadData::Get());
ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+ ThreadData::DeathsSnapshot deaths;
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(1u, birth_map.size()); // 1 birth location.
EXPECT_EQ(1, birth_map.begin()->second->birth_count()); // 1 birth.
- EXPECT_EQ(0u, death_map.size()); // No deaths.
- EXPECT_EQ(0u, parent_child_set.size()); // No children.
+ EXPECT_EQ(0u, deaths.size()); // No deaths.
// Now instigate another birth, while we are timing the run of the first
// execution.
- ThreadData::PrepareForStartOfRun(first_birth);
// Create a child (using the same birth location).
// TrackingInfo will call TallyABirth() during construction.
const int32 start_time = 1;
@@ -209,74 +199,56 @@ TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
birth_map.clear();
- death_map.clear();
- parent_child_set.clear();
- data->SnapshotMaps(false, &birth_map, &death_map, &parent_child_set);
+ deaths.clear();
+ data->SnapshotMaps(0, &birth_map, &deaths);
EXPECT_EQ(1u, birth_map.size()); // 1 birth location.
EXPECT_EQ(2, birth_map.begin()->second->birth_count()); // 2 births.
- EXPECT_EQ(1u, death_map.size()); // 1 location.
- EXPECT_EQ(1, death_map.begin()->second.count()); // 1 death.
- if (ThreadData::TrackingParentChildStatus()) {
- EXPECT_EQ(1u, parent_child_set.size()); // 1 child.
- EXPECT_EQ(parent_child_set.begin()->first,
- parent_child_set.begin()->second);
- } else {
- EXPECT_EQ(0u, parent_child_set.size()); // no stats.
- }
+ EXPECT_EQ(1u, deaths.size()); // 1 location.
+ EXPECT_EQ(1, deaths.begin()->second.death_data.count); // 1 death.
// The births were at the same location as the one known death.
- EXPECT_EQ(birth_map.begin()->second, death_map.begin()->first);
+ EXPECT_EQ(birth_map.begin()->second, deaths.begin()->first);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
-
- ASSERT_EQ(1u, process_data.tasks.size());
- EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
- EXPECT_EQ(kFunction, process_data.tasks[0].birth.location.function_name);
- EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
- EXPECT_EQ(kWorkerThreadName, process_data.tasks[0].birth.thread_name);
- EXPECT_EQ(1, process_data.tasks[0].death_data.count);
- EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_sum);
- EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_max);
- EXPECT_EQ(time_elapsed, process_data.tasks[0].death_data.run_duration_sample);
- EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_sum);
- EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_max);
- EXPECT_EQ(0, process_data.tasks[0].death_data.queue_duration_sample);
- EXPECT_EQ(kWorkerThreadName, process_data.tasks[0].death_thread_name);
-
- if (ThreadData::TrackingParentChildStatus()) {
- ASSERT_EQ(1u, process_data.descendants.size());
- EXPECT_EQ(kFile, process_data.descendants[0].parent.location.file_name);
- EXPECT_EQ(kFunction,
- process_data.descendants[0].parent.location.function_name);
- EXPECT_EQ(kLineNumber,
- process_data.descendants[0].parent.location.line_number);
- EXPECT_EQ(kWorkerThreadName,
- process_data.descendants[0].parent.thread_name);
- EXPECT_EQ(kFile, process_data.descendants[0].child.location.file_name);
- EXPECT_EQ(kFunction,
- process_data.descendants[0].child.location.function_name);
- EXPECT_EQ(kLineNumber,
- process_data.descendants[0].child.location.line_number);
- EXPECT_EQ(kWorkerThreadName, process_data.descendants[0].child.thread_name);
- } else {
- EXPECT_EQ(0u, process_data.descendants.size());
- }
+ ThreadData::Snapshot(0, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+ ASSERT_EQ(1u, process_data_phase.tasks.size());
+ EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase.tasks[0].birth.location.line_number);
+ EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].birth.thread_name);
+ EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+ EXPECT_EQ(time_elapsed,
+ process_data_phase.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(time_elapsed,
+ process_data_phase.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(time_elapsed,
+ process_data_phase.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sample);
+ EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].death_thread_name);
}
-TEST_F(TrackedObjectsTest, DeathDataTest) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
scoped_ptr<DeathData> data(new DeathData());
ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
EXPECT_EQ(data->run_duration_sum(), 0);
+ EXPECT_EQ(data->run_duration_max(), 0);
EXPECT_EQ(data->run_duration_sample(), 0);
EXPECT_EQ(data->queue_duration_sum(), 0);
+ EXPECT_EQ(data->queue_duration_max(), 0);
EXPECT_EQ(data->queue_duration_sample(), 0);
EXPECT_EQ(data->count(), 0);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot());
int32 run_ms = 42;
int32 queue_ms = 8;
@@ -284,106 +256,199 @@ TEST_F(TrackedObjectsTest, DeathDataTest) {
const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
EXPECT_EQ(data->run_duration_sum(), run_ms);
+ EXPECT_EQ(data->run_duration_max(), run_ms);
EXPECT_EQ(data->run_duration_sample(), run_ms);
EXPECT_EQ(data->queue_duration_sum(), queue_ms);
+ EXPECT_EQ(data->queue_duration_max(), queue_ms);
EXPECT_EQ(data->queue_duration_sample(), queue_ms);
EXPECT_EQ(data->count(), 1);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot());
+
+ data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+ EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+ EXPECT_EQ(data->run_duration_max(), run_ms);
+ EXPECT_EQ(data->run_duration_sample(), run_ms);
+ EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+ EXPECT_EQ(data->queue_duration_max(), queue_ms);
+ EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+ EXPECT_EQ(data->count(), 2);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot());
+}
+
+TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+ scoped_ptr<DeathData> data(new DeathData());
+ ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+
+ int32 run_ms = 42;
+ int32 queue_ms = 8;
+ const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
+ data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+
+ data->OnProfilingPhaseCompleted(123);
EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+ EXPECT_EQ(data->run_duration_max(), 0);
EXPECT_EQ(data->run_duration_sample(), run_ms);
EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+ EXPECT_EQ(data->queue_duration_max(), 0);
EXPECT_EQ(data->queue_duration_sample(), queue_ms);
EXPECT_EQ(data->count(), 2);
+ ASSERT_NE(nullptr, data->last_phase_snapshot());
+ EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+ EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+ EXPECT_EQ(2 * run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sum);
+ EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+ EXPECT_EQ(run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sample);
+ EXPECT_EQ(2 * queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sum);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_max);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sample);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+
+ int32 run_ms1 = 21;
+ int32 queue_ms1 = 4;
+
+ data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
+ EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
+ EXPECT_EQ(data->run_duration_max(), run_ms1);
+ EXPECT_EQ(data->run_duration_sample(), run_ms1);
+ EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms + queue_ms1);
+ EXPECT_EQ(data->queue_duration_max(), queue_ms1);
+ EXPECT_EQ(data->queue_duration_sample(), queue_ms1);
+ EXPECT_EQ(data->count(), 3);
+ ASSERT_NE(nullptr, data->last_phase_snapshot());
+ EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+ EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+ EXPECT_EQ(2 * run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sum);
+ EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+ EXPECT_EQ(run_ms,
+ data->last_phase_snapshot()->death_data.run_duration_sample);
+ EXPECT_EQ(2 * queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sum);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_max);
+ EXPECT_EQ(queue_ms,
+ data->last_phase_snapshot()->death_data.queue_duration_sample);
+ EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+}
- DeathDataSnapshot snapshot(*data);
- EXPECT_EQ(2, snapshot.count);
- EXPECT_EQ(2 * run_ms, snapshot.run_duration_sum);
- EXPECT_EQ(run_ms, snapshot.run_duration_max);
- EXPECT_EQ(run_ms, snapshot.run_duration_sample);
- EXPECT_EQ(2 * queue_ms, snapshot.queue_duration_sum);
- EXPECT_EQ(queue_ms, snapshot.queue_duration_max);
- EXPECT_EQ(queue_ms, snapshot.queue_duration_sample);
+TEST_F(TrackedObjectsTest, Delta) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+ DeathDataSnapshot snapshot;
+ snapshot.count = 10;
+ snapshot.run_duration_sum = 100;
+ snapshot.run_duration_max = 50;
+ snapshot.run_duration_sample = 25;
+ snapshot.queue_duration_sum = 200;
+ snapshot.queue_duration_max = 101;
+ snapshot.queue_duration_sample = 26;
+
+ DeathDataSnapshot older_snapshot;
+ older_snapshot.count = 2;
+ older_snapshot.run_duration_sum = 95;
+ older_snapshot.run_duration_max = 48;
+ older_snapshot.run_duration_sample = 22;
+ older_snapshot.queue_duration_sum = 190;
+ older_snapshot.queue_duration_max = 99;
+ older_snapshot.queue_duration_sample = 21;
+
+ const DeathDataSnapshot& delta = snapshot.Delta(older_snapshot);
+ EXPECT_EQ(8, delta.count);
+ EXPECT_EQ(5, delta.run_duration_sum);
+ EXPECT_EQ(50, delta.run_duration_max);
+ EXPECT_EQ(25, delta.run_duration_sample);
+ EXPECT_EQ(10, delta.queue_duration_sum);
+ EXPECT_EQ(101, delta.queue_duration_max);
+ EXPECT_EQ(26, delta.queue_duration_sample);
}
TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotWorkerThread) {
// Start in the deactivated state.
- if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
const char kFunction[] = "DeactivatedBirthOnlyToSnapshotWorkerThread";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, std::string());
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
- EXPECT_EQ(0u, process_data.tasks.size());
- EXPECT_EQ(0u, process_data.descendants.size());
+ ThreadData::Snapshot(0, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+ ASSERT_EQ(0u, process_data_phase.tasks.size());
+
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotMainThread) {
// Start in the deactivated state.
- if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
const char kFunction[] = "DeactivatedBirthOnlyToSnapshotMainThread";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
- EXPECT_EQ(0u, process_data.tasks.size());
- EXPECT_EQ(0u, process_data.descendants.size());
+ ThreadData::Snapshot(0, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+ ASSERT_EQ(0u, process_data_phase.tasks.size());
+
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotWorkerThread) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "BirthOnlyToSnapshotWorkerThread";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, std::string());
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
kStillAlive, 1, 0, 0);
}
TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotMainThread) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "BirthOnlyToSnapshotMainThread";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName, kStillAlive,
1, 0, 0);
}
TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "LifeCycleToSnapshotMainThread";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -400,36 +465,24 @@ TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 2, 4);
}
-// We will deactivate tracking after the birth, and before the death, and
-// demonstrate that the lifecycle is completely tallied. This ensures that
-// our tallied births are matched by tallied deaths (except for when the
-// task is still running, or is queued).
-TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+TEST_F(TrackedObjectsTest, TwoPhases) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
- const char kFunction[] = "LifeCycleMidDeactivatedToSnapshotMainThread";
+ const char kFunction[] = "TwoPhases";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
pending_task.time_posted = kTimePosted; // Overwrite implied Now().
- // Turn off tracking now that we have births.
- EXPECT_TRUE(ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::DEACTIVATED));
-
const unsigned int kStartOfRun = 5;
const unsigned int kEndOfRun = 7;
SetTestTime(kStartOfRun);
@@ -440,26 +493,231 @@ TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ ThreadData::OnProfilingPhaseCompleted(0);
+
+ TallyABirth(location, kMainThreadName);
+
+ const TrackedTime kTimePosted1 = TrackedTime::FromMilliseconds(9);
+ const base::TimeTicks kDelayedStartTime1 = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task1(location, kDelayedStartTime1);
+ pending_task1.time_posted = kTimePosted1; // Overwrite implied Now().
+
+ const unsigned int kStartOfRun1 = 11;
+ const unsigned int kEndOfRun1 = 21;
+ SetTestTime(kStartOfRun1);
+ TaskStopwatch stopwatch1;
+ stopwatch1.Start();
+ SetTestTime(kEndOfRun1);
+ stopwatch1.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task1, stopwatch1);
+
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
- ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
- kMainThreadName, 1, 2, 4);
+ ThreadData::Snapshot(1, &process_data);
+
+ ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+ auto it0 = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+ ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase0.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase0.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase1.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase1.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+ EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
-// We will deactivate tracking before starting a life cycle, and neither
-// the birth nor the death will be recorded.
-TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
- // Start in the deactivated state.
- if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) {
- return;
+TEST_F(TrackedObjectsTest, ThreePhases) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+ const char kFunction[] = "ThreePhases";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+
+ // Phase 0
+ {
+ TallyABirth(location, kMainThreadName);
+
+ // TrackingInfo will call TallyABirth() during construction.
+ SetTestTime(10);
+ base::TrackingInfo pending_task(location, base::TimeTicks());
+
+ SetTestTime(17);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(23);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
}
- const char kFunction[] = "LifeCyclePreDeactivatedToSnapshotMainThread";
+ ThreadData::OnProfilingPhaseCompleted(0);
+
+ // Phase 1
+ {
+ TallyABirth(location, kMainThreadName);
+
+ SetTestTime(30);
+ base::TrackingInfo pending_task(location, base::TimeTicks());
+
+ SetTestTime(35);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(39);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ }
+
+ ThreadData::OnProfilingPhaseCompleted(1);
+
+ // Phase 2
+ {
+ TallyABirth(location, kMainThreadName);
+
+ // TrackingInfo will call TallyABirth() during construction.
+ SetTestTime(40);
+ base::TrackingInfo pending_task(location, base::TimeTicks());
+
+ SetTestTime(43);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(45);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ }
+
+ // Snapshot and check results.
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(2, &process_data);
+
+ ASSERT_EQ(3u, process_data.phased_snapshots.size());
+
+ auto it0 = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+ ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase0.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase0.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+ EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase1.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase1.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+ auto it2 = process_data.phased_snapshots.find(2);
+ ASSERT_TRUE(it2 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase2 = it2->second;
+
+ ASSERT_EQ(1u, process_data_phase2.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase2.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase2.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase2.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase2.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].death_thread_name);
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesSecondEmpty) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+ const char kFunction[] = "TwoPhasesSecondEmpty";
Location location(kFunction, kFile, kLineNumber, NULL);
- TallyABirth(location, kMainThreadName);
+ ThreadData::InitializeThreadContext(kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -475,26 +733,61 @@ TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+ ThreadData::OnProfilingPhaseCompleted(0);
+
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
- EXPECT_EQ(0u, process_data.tasks.size());
- EXPECT_EQ(0u, process_data.descendants.size());
+ ThreadData::Snapshot(1, &process_data);
+
+ ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+ auto it0 = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+ ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase0.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase0.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(0u, process_data_phase1.tasks.size());
+
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
-TEST_F(TrackedObjectsTest, LifeCycleToSnapshotWorkerThread) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+TEST_F(TrackedObjectsTest, TwoPhasesFirstEmpty) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+ ThreadData::OnProfilingPhaseCompleted(0);
- const char kFunction[] = "LifeCycleToSnapshotWorkerThread";
+ const char kFunction[] = "TwoPhasesSecondEmpty";
Location location(kFunction, kFile, kLineNumber, NULL);
- // Do not delete |birth|. We don't own it.
- Births* birth = ThreadData::TallyABirthIfActive(location);
- EXPECT_NE(reinterpret_cast<Births*>(NULL), birth);
+ ThreadData::InitializeThreadContext(kMainThreadName);
+
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+ const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task(location, kDelayedStartTime);
+ pending_task.time_posted = kTimePosted; // Overwrite implied Now().
- const unsigned int kTimePosted = 1;
const unsigned int kStartOfRun = 5;
const unsigned int kEndOfRun = 7;
SetTestTime(kStartOfRun);
@@ -503,61 +796,124 @@ TEST_F(TrackedObjectsTest, LifeCycleToSnapshotWorkerThread) {
SetTestTime(kEndOfRun);
stopwatch.Stop();
- ThreadData::TallyRunOnWorkerThreadIfTracking(
- birth, TrackedTime() + Duration::FromMilliseconds(kTimePosted), stopwatch);
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
- // Call for the ToSnapshot, but tell it to not reset the maxes after scanning.
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
- ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
- kWorkerThreadName, 1, 2, 4);
+ ThreadData::Snapshot(1, &process_data);
- // Call for the ToSnapshot, but tell it to reset the maxes after scanning.
- // We'll still get the same values, but the data will be reset (which we'll
- // see in a moment).
- ProcessDataSnapshot process_data_pre_reset;
- ThreadData::Snapshot(true, &process_data_pre_reset);
- ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
- kWorkerThreadName, 1, 2, 4);
-
- // Call for the ToSnapshot, and now we'll see the result of the last
- // translation, as the max will have been pushed back to zero.
- ProcessDataSnapshot process_data_post_reset;
- ThreadData::Snapshot(true, &process_data_post_reset);
- ASSERT_EQ(1u, process_data_post_reset.tasks.size());
- EXPECT_EQ(kFile, process_data_post_reset.tasks[0].birth.location.file_name);
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it1 = process_data.phased_snapshots.find(1);
+ ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+ ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
EXPECT_EQ(kFunction,
- process_data_post_reset.tasks[0].birth.location.function_name);
+ process_data_phase1.tasks[0].birth.location.function_name);
EXPECT_EQ(kLineNumber,
- process_data_post_reset.tasks[0].birth.location.line_number);
- EXPECT_EQ(kWorkerThreadName,
- process_data_post_reset.tasks[0].birth.thread_name);
- EXPECT_EQ(1, process_data_post_reset.tasks[0].death_data.count);
- EXPECT_EQ(2, process_data_post_reset.tasks[0].death_data.run_duration_sum);
- EXPECT_EQ(0, process_data_post_reset.tasks[0].death_data.run_duration_max);
- EXPECT_EQ(2, process_data_post_reset.tasks[0].death_data.run_duration_sample);
- EXPECT_EQ(4, process_data_post_reset.tasks[0].death_data.queue_duration_sum);
- EXPECT_EQ(0, process_data_post_reset.tasks[0].death_data.queue_duration_max);
- EXPECT_EQ(4,
- process_data_post_reset.tasks[0].death_data.queue_duration_sample);
- EXPECT_EQ(kWorkerThreadName,
- process_data_post_reset.tasks[0].death_thread_name);
- EXPECT_EQ(0u, process_data_post_reset.descendants.size());
- EXPECT_EQ(base::GetCurrentProcId(), process_data_post_reset.process_id);
+ process_data_phase1.tasks[0].birth.location.line_number);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+ EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+ EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+// We will deactivate tracking after the birth, and before the death, and
+// demonstrate that the lifecycle is completely tallied. This ensures that
+// our tallied births are matched by tallied deaths (except for when the
+// task is still running, or is queued).
+TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+ const char kFunction[] = "LifeCycleMidDeactivatedToSnapshotMainThread";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+ TallyABirth(location, kMainThreadName);
+
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+ const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task(location, kDelayedStartTime);
+ pending_task.time_posted = kTimePosted; // Overwrite implied Now().
+
+ // Turn off tracking now that we have births.
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+ const unsigned int kStartOfRun = 5;
+ const unsigned int kEndOfRun = 7;
+ SetTestTime(kStartOfRun);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(kEndOfRun);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(0, &process_data);
+ ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+ kMainThreadName, 1, 2, 4);
+}
+
+// We will deactivate tracking before starting a life cycle, and neither
+// the birth nor the death will be recorded.
+TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
+ // Start in the deactivated state.
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+ const char kFunction[] = "LifeCyclePreDeactivatedToSnapshotMainThread";
+ Location location(kFunction, kFile, kLineNumber, NULL);
+ TallyABirth(location, kMainThreadName);
+
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+ const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+ // TrackingInfo will call TallyABirth() during construction.
+ base::TrackingInfo pending_task(location, kDelayedStartTime);
+ pending_task.time_posted = kTimePosted; // Overwrite implied Now().
+
+ const unsigned int kStartOfRun = 5;
+ const unsigned int kEndOfRun = 7;
+ SetTestTime(kStartOfRun);
+ TaskStopwatch stopwatch;
+ stopwatch.Start();
+ SetTestTime(kEndOfRun);
+ stopwatch.Stop();
+
+ ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+ ProcessDataSnapshot process_data;
+ ThreadData::Snapshot(0, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+ ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+ EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, TwoLives) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "TwoLives";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -585,24 +941,20 @@ TEST_F(TrackedObjectsTest, TwoLives) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task2, stopwatch2);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 2, 2, 4);
}
TEST_F(TrackedObjectsTest, DifferentLives) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
// Use a well named thread.
ThreadData::InitializeThreadContext(kMainThreadName);
const char kFunction[] = "DifferentLives";
Location location(kFunction, kFile, kLineNumber, NULL);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -626,50 +978,54 @@ TEST_F(TrackedObjectsTest, DifferentLives) {
pending_task2.time_posted = kTimePosted; // Overwrite implied Now().
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
- ASSERT_EQ(2u, process_data.tasks.size());
-
- EXPECT_EQ(kFile, process_data.tasks[0].birth.location.file_name);
- EXPECT_EQ(kFunction, process_data.tasks[0].birth.location.function_name);
- EXPECT_EQ(kLineNumber, process_data.tasks[0].birth.location.line_number);
- EXPECT_EQ(kMainThreadName, process_data.tasks[0].birth.thread_name);
- EXPECT_EQ(1, process_data.tasks[0].death_data.count);
- EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_sum);
- EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_max);
- EXPECT_EQ(2, process_data.tasks[0].death_data.run_duration_sample);
- EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_sum);
- EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_max);
- EXPECT_EQ(4, process_data.tasks[0].death_data.queue_duration_sample);
- EXPECT_EQ(kMainThreadName, process_data.tasks[0].death_thread_name);
- EXPECT_EQ(kFile, process_data.tasks[1].birth.location.file_name);
- EXPECT_EQ(kFunction, process_data.tasks[1].birth.location.function_name);
+ ThreadData::Snapshot(0, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+ ASSERT_EQ(2u, process_data_phase.tasks.size());
+
+ EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase.tasks[0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase.tasks[0].birth.location.line_number);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].birth.thread_name);
+ EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+ EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sample);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].death_thread_name);
+ EXPECT_EQ(kFile, process_data_phase.tasks[1].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase.tasks[1].birth.location.function_name);
EXPECT_EQ(kSecondFakeLineNumber,
- process_data.tasks[1].birth.location.line_number);
- EXPECT_EQ(kMainThreadName, process_data.tasks[1].birth.thread_name);
- EXPECT_EQ(1, process_data.tasks[1].death_data.count);
- EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_sum);
- EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_max);
- EXPECT_EQ(0, process_data.tasks[1].death_data.run_duration_sample);
- EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_sum);
- EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_max);
- EXPECT_EQ(0, process_data.tasks[1].death_data.queue_duration_sample);
- EXPECT_EQ(kStillAlive, process_data.tasks[1].death_thread_name);
- EXPECT_EQ(0u, process_data.descendants.size());
+ process_data_phase.tasks[1].birth.location.line_number);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[1].birth.thread_name);
+ EXPECT_EQ(1, process_data_phase.tasks[1].death_data.count);
+ EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sum);
+ EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_max);
+ EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sample);
+ EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sum);
+ EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_max);
+ EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sample);
+ EXPECT_EQ(kStillAlive, process_data_phase.tasks[1].death_thread_name);
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
TEST_F(TrackedObjectsTest, TaskWithNestedExclusion) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "TaskWithNestedExclusion";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -691,23 +1047,19 @@ TEST_F(TrackedObjectsTest, TaskWithNestedExclusion) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 6, 4);
}
TEST_F(TrackedObjectsTest, TaskWith2NestedExclusions) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "TaskWith2NestedExclusions";
Location location(kFunction, kFile, kLineNumber, NULL);
TallyABirth(location, kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -735,16 +1087,13 @@ TEST_F(TrackedObjectsTest, TaskWith2NestedExclusions) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
kMainThreadName, 1, 13, 4);
}
TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
- if (!ThreadData::InitializeAndSetTrackingStatus(
- ThreadData::PROFILING_CHILDREN_ACTIVE)) {
- return;
- }
+ ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
const char kFunction[] = "TaskWithNestedExclusionWithNestedTask";
Location location(kFunction, kFile, kLineNumber, NULL);
@@ -753,8 +1102,7 @@ TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
TallyABirth(location, kMainThreadName);
- const base::TimeTicks kTimePosted = base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1);
+ const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
const base::TimeTicks kDelayedStartTime = base::TimeTicks();
// TrackingInfo will call TallyABirth() during construction.
base::TrackingInfo pending_task(location, kDelayedStartTime);
@@ -771,8 +1119,7 @@ TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
Location second_location(kFunction, kFile, kSecondFakeLineNumber, NULL);
base::TrackingInfo nested_task(second_location, kDelayedStartTime);
// Overwrite implied Now().
- nested_task.time_posted =
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(8);
+ nested_task.time_posted = TrackedTime::FromMilliseconds(8);
SetTestTime(9);
TaskStopwatch nested_task_stopwatch;
nested_task_stopwatch.Start();
@@ -790,40 +1137,49 @@ TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
ProcessDataSnapshot process_data;
- ThreadData::Snapshot(false, &process_data);
+ ThreadData::Snapshot(0, &process_data);
+
+ ASSERT_EQ(1u, process_data.phased_snapshots.size());
+ auto it = process_data.phased_snapshots.find(0);
+ ASSERT_TRUE(it != process_data.phased_snapshots.end());
+ const ProcessDataPhaseSnapshot& process_data_phase = it->second;
// The order in which the two task follow is platform-dependent.
- int t0 = (process_data.tasks[0].birth.location.line_number == kLineNumber) ?
- 0 : 1;
+ int t0 =
+ (process_data_phase.tasks[0].birth.location.line_number == kLineNumber)
+ ? 0
+ : 1;
int t1 = 1 - t0;
- ASSERT_EQ(2u, process_data.tasks.size());
- EXPECT_EQ(kFile, process_data.tasks[t0].birth.location.file_name);
- EXPECT_EQ(kFunction, process_data.tasks[t0].birth.location.function_name);
- EXPECT_EQ(kLineNumber, process_data.tasks[t0].birth.location.line_number);
- EXPECT_EQ(kMainThreadName, process_data.tasks[t0].birth.thread_name);
- EXPECT_EQ(1, process_data.tasks[t0].death_data.count);
- EXPECT_EQ(6, process_data.tasks[t0].death_data.run_duration_sum);
- EXPECT_EQ(6, process_data.tasks[t0].death_data.run_duration_max);
- EXPECT_EQ(6, process_data.tasks[t0].death_data.run_duration_sample);
- EXPECT_EQ(4, process_data.tasks[t0].death_data.queue_duration_sum);
- EXPECT_EQ(4, process_data.tasks[t0].death_data.queue_duration_max);
- EXPECT_EQ(4, process_data.tasks[t0].death_data.queue_duration_sample);
- EXPECT_EQ(kMainThreadName, process_data.tasks[t0].death_thread_name);
- EXPECT_EQ(kFile, process_data.tasks[t1].birth.location.file_name);
- EXPECT_EQ(kFunction, process_data.tasks[t1].birth.location.function_name);
+ ASSERT_EQ(2u, process_data_phase.tasks.size());
+ EXPECT_EQ(kFile, process_data_phase.tasks[t0].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase.tasks[t0].birth.location.function_name);
+ EXPECT_EQ(kLineNumber,
+ process_data_phase.tasks[t0].birth.location.line_number);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].birth.thread_name);
+ EXPECT_EQ(1, process_data_phase.tasks[t0].death_data.count);
+ EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sum);
+ EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_max);
+ EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sample);
+ EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sum);
+ EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_max);
+ EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sample);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].death_thread_name);
+ EXPECT_EQ(kFile, process_data_phase.tasks[t1].birth.location.file_name);
+ EXPECT_EQ(kFunction,
+ process_data_phase.tasks[t1].birth.location.function_name);
EXPECT_EQ(kSecondFakeLineNumber,
- process_data.tasks[t1].birth.location.line_number);
- EXPECT_EQ(kMainThreadName, process_data.tasks[t1].birth.thread_name);
- EXPECT_EQ(1, process_data.tasks[t1].death_data.count);
- EXPECT_EQ(2, process_data.tasks[t1].death_data.run_duration_sum);
- EXPECT_EQ(2, process_data.tasks[t1].death_data.run_duration_max);
- EXPECT_EQ(2, process_data.tasks[t1].death_data.run_duration_sample);
- EXPECT_EQ(1, process_data.tasks[t1].death_data.queue_duration_sum);
- EXPECT_EQ(1, process_data.tasks[t1].death_data.queue_duration_max);
- EXPECT_EQ(1, process_data.tasks[t1].death_data.queue_duration_sample);
- EXPECT_EQ(kMainThreadName, process_data.tasks[t1].death_thread_name);
- EXPECT_EQ(0u, process_data.descendants.size());
+ process_data_phase.tasks[t1].birth.location.line_number);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].birth.thread_name);
+ EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.count);
+ EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sum);
+ EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_max);
+ EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sample);
+ EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sum);
+ EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_max);
+ EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sample);
+ EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].death_thread_name);
EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
}
diff --git a/chromium/base/tracking_info.cc b/chromium/base/tracking_info.cc
index 0b091f8b68b..c02b2f47585 100644
--- a/chromium/base/tracking_info.cc
+++ b/chromium/base/tracking_info.cc
@@ -18,7 +18,7 @@ TrackingInfo::TrackingInfo(
base::TimeTicks delayed_run_time)
: birth_tally(
tracked_objects::ThreadData::TallyABirthIfActive(posted_from)),
- time_posted(TimeTicks::Now()),
+ time_posted(tracked_objects::ThreadData::Now()),
delayed_run_time(delayed_run_time) {
}
diff --git a/chromium/base/tracking_info.h b/chromium/base/tracking_info.h
index a1c6392d2ea..6c3bcd1a514 100644
--- a/chromium/base/tracking_info.h
+++ b/chromium/base/tracking_info.h
@@ -36,15 +36,18 @@ struct BASE_EXPORT TrackingInfo {
// unserviced, after they *could* be serviced. This is the same stat as we
// have for non-delayed tasks, and we consistently call it queuing delay.
tracked_objects::TrackedTime EffectiveTimePosted() const {
- return tracked_objects::TrackedTime(
- delayed_run_time.is_null() ? time_posted : delayed_run_time);
+ return delayed_run_time.is_null()
+ ? time_posted
+ : tracked_objects::TrackedTime(delayed_run_time);
}
// Record of location and thread that the task came from.
tracked_objects::Births* birth_tally;
- // Time when the related task was posted.
- base::TimeTicks time_posted;
+ // Time when the related task was posted. Note that this value may be empty
+ // if task profiling is disabled, and should only be used in conjunction with
+ // profiling-related reporting.
+ tracked_objects::TrackedTime time_posted;
// The time when the task should be run.
base::TimeTicks delayed_run_time;
diff --git a/chromium/base/tuple.h b/chromium/base/tuple.h
index 12f7f84ea50..4628aa9417c 100644
--- a/chromium/base/tuple.h
+++ b/chromium/base/tuple.h
@@ -2,20 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// A Tuple is a generic templatized container, similar in concept to std::pair.
-// There are classes Tuple0 to Tuple6, cooresponding to the number of elements
-// it contains. The convenient MakeTuple() function takes 0 to 6 arguments,
-// and will construct and return the appropriate Tuple object. The functions
-// DispatchToMethod and DispatchToFunction take a function pointer or instance
-// and method pointer, and unpack a tuple into arguments to the call.
+// A Tuple is a generic templatized container, similar in concept to std::pair
+// and std::tuple. The convenient MakeTuple() function takes any number of
+// arguments and will construct and return the appropriate Tuple object. The
+// functions DispatchToMethod and DispatchToFunction take a function pointer or
+// instance and method pointer, and unpack a tuple into arguments to the call.
//
// Tuple elements are copied by value, and stored in the tuple. See the unit
// tests for more details of how/when the values are copied.
//
// Example usage:
// // These two methods of creating a Tuple are identical.
-// Tuple2<int, const char*> tuple_a(1, "wee");
-// Tuple2<int, const char*> tuple_b = MakeTuple(1, "wee");
+// Tuple<int, const char*> tuple_a(1, "wee");
+// Tuple<int, const char*> tuple_b = MakeTuple(1, "wee");
//
// void SomeFunc(int a, const char* b) { }
// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee")
@@ -26,11 +25,85 @@
// DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
// // foo->SomeMeth(1, 2, 3);
-#ifndef BASE_TUPLE_H__
-#define BASE_TUPLE_H__
+#ifndef BASE_TUPLE_H_
+#define BASE_TUPLE_H_
#include "base/bind_helpers.h"
+// Index sequences
+//
+// Minimal clone of the similarly-named C++14 functionality.
+
+template <size_t...>
+struct IndexSequence {};
+
+template <size_t... Ns>
+struct MakeIndexSequenceImpl;
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+
+// Work around VC++ 2013 /analyze internal compiler error:
+// https://connect.microsoft.com/VisualStudio/feedback/details/1053626
+
+template <> struct MakeIndexSequenceImpl<0> {
+ using Type = IndexSequence<>;
+};
+template <> struct MakeIndexSequenceImpl<1> {
+ using Type = IndexSequence<0>;
+};
+template <> struct MakeIndexSequenceImpl<2> {
+ using Type = IndexSequence<0,1>;
+};
+template <> struct MakeIndexSequenceImpl<3> {
+ using Type = IndexSequence<0,1,2>;
+};
+template <> struct MakeIndexSequenceImpl<4> {
+ using Type = IndexSequence<0,1,2,3>;
+};
+template <> struct MakeIndexSequenceImpl<5> {
+ using Type = IndexSequence<0,1,2,3,4>;
+};
+template <> struct MakeIndexSequenceImpl<6> {
+ using Type = IndexSequence<0,1,2,3,4,5>;
+};
+template <> struct MakeIndexSequenceImpl<7> {
+ using Type = IndexSequence<0,1,2,3,4,5,6>;
+};
+template <> struct MakeIndexSequenceImpl<8> {
+ using Type = IndexSequence<0,1,2,3,4,5,6,7>;
+};
+template <> struct MakeIndexSequenceImpl<9> {
+ using Type = IndexSequence<0,1,2,3,4,5,6,7,8>;
+};
+template <> struct MakeIndexSequenceImpl<10> {
+ using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9>;
+};
+template <> struct MakeIndexSequenceImpl<11> {
+ using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10>;
+};
+template <> struct MakeIndexSequenceImpl<12> {
+ using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11>;
+};
+template <> struct MakeIndexSequenceImpl<13> {
+ using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11,12>;
+};
+
+#else // defined(WIN) && defined(_PREFAST_)
+
+template <size_t... Ns>
+struct MakeIndexSequenceImpl<0, Ns...> {
+ using Type = IndexSequence<Ns...>;
+};
+
+template <size_t N, size_t... Ns>
+struct MakeIndexSequenceImpl<N, Ns...>
+ : MakeIndexSequenceImpl<N - 1, N - 1, Ns...> {};
+
+#endif // defined(WIN) && defined(_PREFAST_)
+
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
+
// Traits ----------------------------------------------------------------------
//
// A simple traits class for tuple arguments.
@@ -53,9 +126,6 @@ struct TupleTraits<P&> {
typedef P& ParamType;
};
-template <class P>
-struct TupleTypes { };
-
// Tuple -----------------------------------------------------------------------
//
// This set of classes is useful for bundling 0 or more heterogeneous data types
@@ -63,357 +133,81 @@ struct TupleTypes { };
// function objects that need to take an arbitrary number of parameters; see
// RunnableMethod and IPC::MessageWithTuple.
//
-// Tuple0 is supplied to act as a 'void' type. It can be used, for example,
+// Tuple<> is supplied to act as a 'void' type. It can be used, for example,
// when dispatching to a function that accepts no arguments (see the
// Dispatchers below).
-// Tuple1<A> is rarely useful. One such use is when A is non-const ref that you
+// Tuple<A> is rarely useful. One such use is when A is non-const ref that you
// want filled by the dispatchee, and the tuple is merely a container for that
// output (a "tier"). See MakeRefTuple and its usages.
-struct Tuple0 {
- typedef Tuple0 ValueTuple;
- typedef Tuple0 RefTuple;
- typedef Tuple0 ParamTuple;
+template <typename IxSeq, typename... Ts>
+struct TupleBaseImpl;
+template <typename... Ts>
+using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>;
+template <size_t N, typename T>
+struct TupleLeaf;
+
+template <typename... Ts>
+struct Tuple : TupleBase<Ts...> {
+ Tuple() : TupleBase<Ts...>() {}
+ explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
+ : TupleBase<Ts...>(args...) {}
};
-template <class A>
-struct Tuple1 {
- public:
- typedef A TypeA;
-
- Tuple1() {}
- explicit Tuple1(typename TupleTraits<A>::ParamType a) : a(a) {}
-
- A a;
-};
-
-template <class A, class B>
-struct Tuple2 {
- public:
- typedef A TypeA;
- typedef B TypeB;
-
- Tuple2() {}
- Tuple2(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b)
- : a(a), b(b) {
- }
-
- A a;
- B b;
-};
-
-template <class A, class B, class C>
-struct Tuple3 {
- public:
- typedef A TypeA;
- typedef B TypeB;
- typedef C TypeC;
-
- Tuple3() {}
- Tuple3(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b,
- typename TupleTraits<C>::ParamType c)
- : a(a), b(b), c(c){
- }
-
- A a;
- B b;
- C c;
-};
-
-template <class A, class B, class C, class D>
-struct Tuple4 {
- public:
- typedef A TypeA;
- typedef B TypeB;
- typedef C TypeC;
- typedef D TypeD;
-
- Tuple4() {}
- Tuple4(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b,
- typename TupleTraits<C>::ParamType c,
- typename TupleTraits<D>::ParamType d)
- : a(a), b(b), c(c), d(d) {
- }
-
- A a;
- B b;
- C c;
- D d;
-};
-
-template <class A, class B, class C, class D, class E>
-struct Tuple5 {
- public:
- typedef A TypeA;
- typedef B TypeB;
- typedef C TypeC;
- typedef D TypeD;
- typedef E TypeE;
-
- Tuple5() {}
- Tuple5(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b,
- typename TupleTraits<C>::ParamType c,
- typename TupleTraits<D>::ParamType d,
- typename TupleTraits<E>::ParamType e)
- : a(a), b(b), c(c), d(d), e(e) {
- }
-
- A a;
- B b;
- C c;
- D d;
- E e;
-};
-
-template <class A, class B, class C, class D, class E, class F>
-struct Tuple6 {
- public:
- typedef A TypeA;
- typedef B TypeB;
- typedef C TypeC;
- typedef D TypeD;
- typedef E TypeE;
- typedef F TypeF;
-
- Tuple6() {}
- Tuple6(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b,
- typename TupleTraits<C>::ParamType c,
- typename TupleTraits<D>::ParamType d,
- typename TupleTraits<E>::ParamType e,
- typename TupleTraits<F>::ParamType f)
- : a(a), b(b), c(c), d(d), e(e), f(f) {
- }
+// Avoids ambiguity between Tuple's two constructors.
+template <>
+struct Tuple<> {};
- A a;
- B b;
- C c;
- D d;
- E e;
- F f;
+template <size_t... Ns, typename... Ts>
+struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
+ TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {}
+ explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args)
+ : TupleLeaf<Ns, Ts>(args)... {}
};
-template <class A, class B, class C, class D, class E, class F, class G>
-struct Tuple7 {
- public:
- typedef A TypeA;
- typedef B TypeB;
- typedef C TypeC;
- typedef D TypeD;
- typedef E TypeE;
- typedef F TypeF;
- typedef G TypeG;
+template <size_t N, typename T>
+struct TupleLeaf {
+ TupleLeaf() {}
+ explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {}
- Tuple7() {}
- Tuple7(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b,
- typename TupleTraits<C>::ParamType c,
- typename TupleTraits<D>::ParamType d,
- typename TupleTraits<E>::ParamType e,
- typename TupleTraits<F>::ParamType f,
- typename TupleTraits<G>::ParamType g)
- : a(a), b(b), c(c), d(d), e(e), f(f), g(g) {
- }
+ T& get() { return x; }
+ const T& get() const { return x; }
- A a;
- B b;
- C c;
- D d;
- E e;
- F f;
- G g;
+ T x;
};
-template <class A, class B, class C, class D, class E, class F, class G,
- class H>
-struct Tuple8 {
- public:
- typedef A TypeA;
- typedef B TypeB;
- typedef C TypeC;
- typedef D TypeD;
- typedef E TypeE;
- typedef F TypeF;
- typedef G TypeG;
- typedef H TypeH;
+// Tuple getters --------------------------------------------------------------
+//
+// Allows accessing an arbitrary tuple element by index.
+//
+// Example usage:
+// Tuple<int, double> t2;
+// get<0>(t2) = 42;
+// get<1>(t2) = 3.14;
- Tuple8() {}
- Tuple8(typename TupleTraits<A>::ParamType a,
- typename TupleTraits<B>::ParamType b,
- typename TupleTraits<C>::ParamType c,
- typename TupleTraits<D>::ParamType d,
- typename TupleTraits<E>::ParamType e,
- typename TupleTraits<F>::ParamType f,
- typename TupleTraits<G>::ParamType g,
- typename TupleTraits<H>::ParamType h)
- : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {
- }
+template <size_t I, typename T>
+T& get(TupleLeaf<I, T>& leaf) {
+ return leaf.get();
+}
- A a;
- B b;
- C c;
- D d;
- E e;
- F f;
- G g;
- H h;
-};
+template <size_t I, typename T>
+const T& get(const TupleLeaf<I, T>& leaf) {
+ return leaf.get();
+}
// Tuple types ----------------------------------------------------------------
//
// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
// definitions of class types the tuple takes as parameters.
-template <>
-struct TupleTypes< Tuple0 > {
- typedef Tuple0 ValueTuple;
- typedef Tuple0 RefTuple;
- typedef Tuple0 ParamTuple;
-};
-
-template <class A>
-struct TupleTypes< Tuple1<A> > {
- typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
- typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
- typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple;
-};
-
-template <class A, class B>
-struct TupleTypes< Tuple2<A, B> > {
- typedef Tuple2<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType> ValueTuple;
-typedef Tuple2<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType> RefTuple;
- typedef Tuple2<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType> ParamTuple;
-};
-
-template <class A, class B, class C>
-struct TupleTypes< Tuple3<A, B, C> > {
- typedef Tuple3<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType> ValueTuple;
-typedef Tuple3<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType> RefTuple;
- typedef Tuple3<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType> ParamTuple;
-};
-
-template <class A, class B, class C, class D>
-struct TupleTypes< Tuple4<A, B, C, D> > {
- typedef Tuple4<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType> ValueTuple;
-typedef Tuple4<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType> RefTuple;
- typedef Tuple4<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType> ParamTuple;
-};
-
-template <class A, class B, class C, class D, class E>
-struct TupleTypes< Tuple5<A, B, C, D, E> > {
- typedef Tuple5<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType> ValueTuple;
-typedef Tuple5<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType> RefTuple;
- typedef Tuple5<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType> ParamTuple;
-};
-
-template <class A, class B, class C, class D, class E, class F>
-struct TupleTypes< Tuple6<A, B, C, D, E, F> > {
- typedef Tuple6<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType,
- typename TupleTraits<F>::ValueType> ValueTuple;
-typedef Tuple6<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType,
- typename TupleTraits<F>::RefType> RefTuple;
- typedef Tuple6<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType,
- typename TupleTraits<F>::ParamType> ParamTuple;
-};
-
-template <class A, class B, class C, class D, class E, class F, class G>
-struct TupleTypes< Tuple7<A, B, C, D, E, F, G> > {
- typedef Tuple7<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType,
- typename TupleTraits<F>::ValueType,
- typename TupleTraits<G>::ValueType> ValueTuple;
-typedef Tuple7<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType,
- typename TupleTraits<F>::RefType,
- typename TupleTraits<G>::RefType> RefTuple;
- typedef Tuple7<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType,
- typename TupleTraits<F>::ParamType,
- typename TupleTraits<G>::ParamType> ParamTuple;
-};
+template <typename T>
+struct TupleTypes;
-template <class A, class B, class C, class D, class E, class F, class G,
- class H>
-struct TupleTypes< Tuple8<A, B, C, D, E, F, G, H> > {
- typedef Tuple8<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType,
- typename TupleTraits<F>::ValueType,
- typename TupleTraits<G>::ValueType,
- typename TupleTraits<H>::ValueType> ValueTuple;
-typedef Tuple8<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType,
- typename TupleTraits<F>::RefType,
- typename TupleTraits<G>::RefType,
- typename TupleTraits<H>::RefType> RefTuple;
- typedef Tuple8<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType,
- typename TupleTraits<F>::ParamType,
- typename TupleTraits<G>::ParamType,
- typename TupleTraits<H>::ParamType> ParamTuple;
+template <typename... Ts>
+struct TupleTypes<Tuple<Ts...>> {
+ using ValueTuple = Tuple<typename TupleTraits<Ts>::ValueType...>;
+ using RefTuple = Tuple<typename TupleTraits<Ts>::RefType...>;
+ using ParamTuple = Tuple<typename TupleTraits<Ts>::ParamType...>;
};
// Tuple creators -------------------------------------------------------------
@@ -421,105 +215,17 @@ typedef Tuple8<typename TupleTraits<A>::RefType,
// Helper functions for constructing tuples while inferring the template
// argument types.
-inline Tuple0 MakeTuple() {
- return Tuple0();
-}
-
-template <class A>
-inline Tuple1<A> MakeTuple(const A& a) {
- return Tuple1<A>(a);
-}
-
-template <class A, class B>
-inline Tuple2<A, B> MakeTuple(const A& a, const B& b) {
- return Tuple2<A, B>(a, b);
-}
-
-template <class A, class B, class C>
-inline Tuple3<A, B, C> MakeTuple(const A& a, const B& b, const C& c) {
- return Tuple3<A, B, C>(a, b, c);
-}
-
-template <class A, class B, class C, class D>
-inline Tuple4<A, B, C, D> MakeTuple(const A& a, const B& b, const C& c,
- const D& d) {
- return Tuple4<A, B, C, D>(a, b, c, d);
-}
-
-template <class A, class B, class C, class D, class E>
-inline Tuple5<A, B, C, D, E> MakeTuple(const A& a, const B& b, const C& c,
- const D& d, const E& e) {
- return Tuple5<A, B, C, D, E>(a, b, c, d, e);
-}
-
-template <class A, class B, class C, class D, class E, class F>
-inline Tuple6<A, B, C, D, E, F> MakeTuple(const A& a, const B& b, const C& c,
- const D& d, const E& e, const F& f) {
- return Tuple6<A, B, C, D, E, F>(a, b, c, d, e, f);
-}
-
-template <class A, class B, class C, class D, class E, class F, class G>
-inline Tuple7<A, B, C, D, E, F, G> MakeTuple(const A& a, const B& b, const C& c,
- const D& d, const E& e, const F& f,
- const G& g) {
- return Tuple7<A, B, C, D, E, F, G>(a, b, c, d, e, f, g);
-}
-
-template <class A, class B, class C, class D, class E, class F, class G,
- class H>
-inline Tuple8<A, B, C, D, E, F, G, H> MakeTuple(const A& a, const B& b,
- const C& c, const D& d,
- const E& e, const F& f,
- const G& g, const H& h) {
- return Tuple8<A, B, C, D, E, F, G, H>(a, b, c, d, e, f, g, h);
+template <typename... Ts>
+inline Tuple<Ts...> MakeTuple(const Ts&... arg) {
+ return Tuple<Ts...>(arg...);
}
// The following set of helpers make what Boost refers to as "Tiers" - a tuple
// of references.
-template <class A>
-inline Tuple1<A&> MakeRefTuple(A& a) {
- return Tuple1<A&>(a);
-}
-
-template <class A, class B>
-inline Tuple2<A&, B&> MakeRefTuple(A& a, B& b) {
- return Tuple2<A&, B&>(a, b);
-}
-
-template <class A, class B, class C>
-inline Tuple3<A&, B&, C&> MakeRefTuple(A& a, B& b, C& c) {
- return Tuple3<A&, B&, C&>(a, b, c);
-}
-
-template <class A, class B, class C, class D>
-inline Tuple4<A&, B&, C&, D&> MakeRefTuple(A& a, B& b, C& c, D& d) {
- return Tuple4<A&, B&, C&, D&>(a, b, c, d);
-}
-
-template <class A, class B, class C, class D, class E>
-inline Tuple5<A&, B&, C&, D&, E&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e) {
- return Tuple5<A&, B&, C&, D&, E&>(a, b, c, d, e);
-}
-
-template <class A, class B, class C, class D, class E, class F>
-inline Tuple6<A&, B&, C&, D&, E&, F&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e,
- F& f) {
- return Tuple6<A&, B&, C&, D&, E&, F&>(a, b, c, d, e, f);
-}
-
-template <class A, class B, class C, class D, class E, class F, class G>
-inline Tuple7<A&, B&, C&, D&, E&, F&, G&> MakeRefTuple(A& a, B& b, C& c, D& d,
- E& e, F& f, G& g) {
- return Tuple7<A&, B&, C&, D&, E&, F&, G&>(a, b, c, d, e, f, g);
-}
-
-template <class A, class B, class C, class D, class E, class F, class G,
- class H>
-inline Tuple8<A&, B&, C&, D&, E&, F&, G&, H&> MakeRefTuple(A& a, B& b, C& c,
- D& d, E& e, F& f,
- G& g, H& h) {
- return Tuple8<A&, B&, C&, D&, E&, F&, G&, H&>(a, b, c, d, e, f, g, h);
+template <typename... Ts>
+inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) {
+ return Tuple<Ts&...>(arg...);
}
// Dispatchers ----------------------------------------------------------------
@@ -533,759 +239,94 @@ inline Tuple8<A&, B&, C&, D&, E&, F&, G&, H&> MakeRefTuple(A& a, B& b, C& c,
// Non-Static Dispatchers with no out params.
-template <class ObjT, class Method>
-inline void DispatchToMethod(ObjT* obj, Method method, const Tuple0& arg) {
- (obj->*method)();
-}
-
-template <class ObjT, class Method, class A>
+template <typename ObjT, typename Method, typename A>
inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
(obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg));
}
-template <class ObjT, class Method, class A>
-inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a));
+template <typename ObjT, typename Method, typename... Ts, size_t... Ns>
+inline void DispatchToMethodImpl(ObjT* obj,
+ Method method,
+ const Tuple<Ts...>& arg,
+ IndexSequence<Ns...>) {
+ (obj->*method)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
}
-template<class ObjT, class Method, class A, class B>
+template <typename ObjT, typename Method, typename... Ts>
inline void DispatchToMethod(ObjT* obj,
Method method,
- const Tuple2<A, B>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b));
-}
-
-template<class ObjT, class Method, class A, class B, class C>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<A, B, C>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<A, B, C, D>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D, class E>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<A, B, C, D, E>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D, class E,
- class F>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<A, B, C, D, E, F>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D, class E,
- class F, class G>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple7<A, B, C, D, E, F, G>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f),
- base::internal::UnwrapTraits<G>::Unwrap(arg.g));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D, class E,
- class F, class G, class H>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple8<A, B, C, D, E, F, G, H>& arg) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f),
- base::internal::UnwrapTraits<G>::Unwrap(arg.g),
- base::internal::UnwrapTraits<H>::Unwrap(arg.h));
+ const Tuple<Ts...>& arg) {
+ DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>());
}
// Static Dispatchers with no out params.
-template <class Function>
-inline void DispatchToFunction(Function function, const Tuple0& arg) {
- (*function)();
-}
-
-template <class Function, class A>
-inline void DispatchToFunction(Function function, const A& arg) {
- (*function)(arg);
-}
-
-template <class Function, class A>
-inline void DispatchToFunction(Function function, const Tuple1<A>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a));
-}
-
-template<class Function, class A, class B>
-inline void DispatchToFunction(Function function, const Tuple2<A, B>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b));
+template <typename Function, typename A>
+inline void DispatchToMethod(Function function, const A& arg) {
+ (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg));
}
-template<class Function, class A, class B, class C>
-inline void DispatchToFunction(Function function, const Tuple3<A, B, C>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c));
+template <typename Function, typename... Ts, size_t... Ns>
+inline void DispatchToFunctionImpl(Function function,
+ const Tuple<Ts...>& arg,
+ IndexSequence<Ns...>) {
+ (*function)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
}
-template<class Function, class A, class B, class C, class D>
-inline void DispatchToFunction(Function function,
- const Tuple4<A, B, C, D>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d));
+template <typename Function, typename... Ts>
+inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) {
+ DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>());
}
-template<class Function, class A, class B, class C, class D, class E>
-inline void DispatchToFunction(Function function,
- const Tuple5<A, B, C, D, E>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e));
-}
+// Dispatchers with out parameters.
-template<class Function, class A, class B, class C, class D, class E, class F>
-inline void DispatchToFunction(Function function,
- const Tuple6<A, B, C, D, E, F>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f));
+template <typename ObjT,
+ typename Method,
+ typename In,
+ typename... OutTs,
+ size_t... OutNs>
+inline void DispatchToMethodImpl(ObjT* obj,
+ Method method,
+ const In& in,
+ Tuple<OutTs...>* out,
+ IndexSequence<OutNs...>) {
+ (obj->*method)(base::internal::UnwrapTraits<In>::Unwrap(in),
+ &get<OutNs>(*out)...);
}
-template<class Function, class A, class B, class C, class D, class E, class F,
- class G>
-inline void DispatchToFunction(Function function,
- const Tuple7<A, B, C, D, E, F, G>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f),
- base::internal::UnwrapTraits<G>::Unwrap(arg.g));
-}
-
-template<class Function, class A, class B, class C, class D, class E, class F,
- class G, class H>
-inline void DispatchToFunction(Function function,
- const Tuple8<A, B, C, D, E, F, G, H>& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f),
- base::internal::UnwrapTraits<G>::Unwrap(arg.g),
- base::internal::UnwrapTraits<H>::Unwrap(arg.h));
-}
-
-// Dispatchers with 0 out param (as a Tuple0).
-
-template <class ObjT, class Method>
+template <typename ObjT, typename Method, typename In, typename... OutTs>
inline void DispatchToMethod(ObjT* obj,
Method method,
- const Tuple0& arg, Tuple0*) {
- (obj->*method)();
-}
-
-template <class ObjT, class Method, class A>
-inline void DispatchToMethod(ObjT* obj, Method method, const A& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg));
-}
-
-template <class ObjT, class Method, class A>
-inline void DispatchToMethod(ObjT* obj,
- Method method,
- const Tuple1<A>& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a));
-}
-
-template<class ObjT, class Method, class A, class B>
+ const In& in,
+ Tuple<OutTs...>* out) {
+ DispatchToMethodImpl(obj, method, in, out,
+ MakeIndexSequence<sizeof...(OutTs)>());
+}
+
+template <typename ObjT,
+ typename Method,
+ typename... InTs,
+ typename... OutTs,
+ size_t... InNs,
+ size_t... OutNs>
+inline void DispatchToMethodImpl(ObjT* obj,
+ Method method,
+ const Tuple<InTs...>& in,
+ Tuple<OutTs...>* out,
+ IndexSequence<InNs...>,
+ IndexSequence<OutNs...>) {
+ (obj->*method)(base::internal::UnwrapTraits<InTs>::Unwrap(get<InNs>(in))...,
+ &get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename... InTs, typename... OutTs>
inline void DispatchToMethod(ObjT* obj,
Method method,
- const Tuple2<A, B>& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b));
-}
-
-template<class ObjT, class Method, class A, class B, class C>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<A, B, C>& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<A, B, C, D>& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D, class E>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<A, B, C, D, E>& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e));
-}
-
-template<class ObjT, class Method, class A, class B, class C, class D, class E,
- class F>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<A, B, C, D, E, F>& arg, Tuple0*) {
- (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg.a),
- base::internal::UnwrapTraits<B>::Unwrap(arg.b),
- base::internal::UnwrapTraits<C>::Unwrap(arg.c),
- base::internal::UnwrapTraits<D>::Unwrap(arg.d),
- base::internal::UnwrapTraits<E>::Unwrap(arg.e),
- base::internal::UnwrapTraits<F>::Unwrap(arg.f));
-}
-
-// Dispatchers with 1 out param.
-
-template<class ObjT, class Method,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple0& in,
- Tuple1<OutA>* out) {
- (obj->*method)(&out->a);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const InA& in,
- Tuple1<OutA>* out) {
- (obj->*method)(in, &out->a);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple1<InA>& in,
- Tuple1<OutA>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a), &out->a);
-}
-
-template<class ObjT, class Method, class InA, class InB,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple2<InA, InB>& in,
- Tuple1<OutA>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- &out->a);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<InA, InB, InC>& in,
- Tuple1<OutA>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- &out->a);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC, class InD,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<InA, InB, InC, InD>& in,
- Tuple1<OutA>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- &out->a);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC, class InD,
- class InE, class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<InA, InB, InC, InD, InE>& in,
- Tuple1<OutA>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- &out->a);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE, class InF,
- class OutA>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<InA, InB, InC, InD, InE, InF>& in,
- Tuple1<OutA>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- base::internal::UnwrapTraits<InF>::Unwrap(in.f),
- &out->a);
-}
-
-// Dispatchers with 2 out params.
-
-template<class ObjT, class Method,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple0& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(&out->a, &out->b);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const InA& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(in, &out->a, &out->b);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple1<InA>& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(
- base::internal::UnwrapTraits<InA>::Unwrap(in.a), &out->a, &out->b);
-}
-
-template<class ObjT, class Method, class InA, class InB,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple2<InA, InB>& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- &out->a,
- &out->b);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<InA, InB, InC>& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- &out->a,
- &out->b);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC, class InD,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<InA, InB, InC, InD>& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- &out->a,
- &out->b);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<InA, InB, InC, InD, InE>& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- &out->a,
- &out->b);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE, class InF,
- class OutA, class OutB>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<InA, InB, InC, InD, InE, InF>& in,
- Tuple2<OutA, OutB>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- base::internal::UnwrapTraits<InF>::Unwrap(in.f),
- &out->a,
- &out->b);
-}
-
-// Dispatchers with 3 out params.
-
-template<class ObjT, class Method,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple0& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(&out->a, &out->b, &out->c);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const InA& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(in, &out->a, &out->b, &out->c);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple1<InA>& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- &out->a,
- &out->b,
- &out->c);
-}
-
-template<class ObjT, class Method, class InA, class InB,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple2<InA, InB>& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- &out->a,
- &out->b,
- &out->c);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<InA, InB, InC>& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- &out->a,
- &out->b,
- &out->c);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC, class InD,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<InA, InB, InC, InD>& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- &out->a,
- &out->b,
- &out->c);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<InA, InB, InC, InD, InE>& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- &out->a,
- &out->b,
- &out->c);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE, class InF,
- class OutA, class OutB, class OutC>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<InA, InB, InC, InD, InE, InF>& in,
- Tuple3<OutA, OutB, OutC>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- base::internal::UnwrapTraits<InF>::Unwrap(in.f),
- &out->a,
- &out->b,
- &out->c);
-}
-
-// Dispatchers with 4 out params.
-
-template<class ObjT, class Method,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple0& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(&out->a, &out->b, &out->c, &out->d);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const InA& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple1<InA>& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-template<class ObjT, class Method, class InA, class InB,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple2<InA, InB>& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<InA, InB, InC>& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC, class InD,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<InA, InB, InC, InD>& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<InA, InB, InC, InD, InE>& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE, class InF,
- class OutA, class OutB, class OutC, class OutD>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<InA, InB, InC, InD, InE, InF>& in,
- Tuple4<OutA, OutB, OutC, OutD>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- base::internal::UnwrapTraits<InF>::Unwrap(in.f),
- &out->a,
- &out->b,
- &out->c,
- &out->d);
-}
-
-// Dispatchers with 5 out params.
-
-template<class ObjT, class Method,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple0& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(&out->a, &out->b, &out->c, &out->d, &out->e);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const InA& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
-}
-
-template<class ObjT, class Method, class InA,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple1<InA>& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
-}
-
-template<class ObjT, class Method, class InA, class InB,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple2<InA, InB>& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple3<InA, InB, InC>& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
-}
-
-template<class ObjT, class Method, class InA, class InB, class InC, class InD,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple4<InA, InB, InC, InD>& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple5<InA, InB, InC, InD, InE>& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
-}
-
-template<class ObjT, class Method,
- class InA, class InB, class InC, class InD, class InE, class InF,
- class OutA, class OutB, class OutC, class OutD, class OutE>
-inline void DispatchToMethod(ObjT* obj, Method method,
- const Tuple6<InA, InB, InC, InD, InE, InF>& in,
- Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
- (obj->*method)(base::internal::UnwrapTraits<InA>::Unwrap(in.a),
- base::internal::UnwrapTraits<InB>::Unwrap(in.b),
- base::internal::UnwrapTraits<InC>::Unwrap(in.c),
- base::internal::UnwrapTraits<InD>::Unwrap(in.d),
- base::internal::UnwrapTraits<InE>::Unwrap(in.e),
- base::internal::UnwrapTraits<InF>::Unwrap(in.f),
- &out->a,
- &out->b,
- &out->c,
- &out->d,
- &out->e);
+ const Tuple<InTs...>& in,
+ Tuple<OutTs...>* out) {
+ DispatchToMethodImpl(obj, method, in, out,
+ MakeIndexSequence<sizeof...(InTs)>(),
+ MakeIndexSequence<sizeof...(OutTs)>());
}
-#endif // BASE_TUPLE_H__
+#endif // BASE_TUPLE_H_
diff --git a/chromium/base/tuple_unittest.cc b/chromium/base/tuple_unittest.cc
index 8d620deb639..5b43affc600 100644
--- a/chromium/base/tuple_unittest.cc
+++ b/chromium/base/tuple_unittest.cc
@@ -30,50 +30,50 @@ struct Addz {
} // namespace
TEST(TupleTest, Basic) {
- Tuple0 t0 = MakeTuple();
+ Tuple<> t0 = MakeTuple();
ALLOW_UNUSED_LOCAL(t0);
- Tuple1<int> t1(1);
- Tuple2<int, const char*> t2 = MakeTuple(1, static_cast<const char*>("wee"));
- Tuple3<int, int, int> t3(1, 2, 3);
- Tuple4<int, int, int, int*> t4(1, 2, 3, &t1.a);
- Tuple5<int, int, int, int, int*> t5(1, 2, 3, 4, &t4.a);
- Tuple6<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &t4.a);
-
- EXPECT_EQ(1, t1.a);
- EXPECT_EQ(1, t2.a);
- EXPECT_EQ(1, t3.a);
- EXPECT_EQ(2, t3.b);
- EXPECT_EQ(3, t3.c);
- EXPECT_EQ(1, t4.a);
- EXPECT_EQ(2, t4.b);
- EXPECT_EQ(3, t4.c);
- EXPECT_EQ(1, t5.a);
- EXPECT_EQ(2, t5.b);
- EXPECT_EQ(3, t5.c);
- EXPECT_EQ(4, t5.d);
- EXPECT_EQ(1, t6.a);
- EXPECT_EQ(2, t6.b);
- EXPECT_EQ(3, t6.c);
- EXPECT_EQ(4, t6.d);
- EXPECT_EQ(5, t6.e);
-
- EXPECT_EQ(1, t1.a);
+ Tuple<int> t1(1);
+ Tuple<int, const char*> t2 = MakeTuple(1, static_cast<const char*>("wee"));
+ Tuple<int, int, int> t3(1, 2, 3);
+ Tuple<int, int, int, int*> t4(1, 2, 3, &get<0>(t1));
+ Tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &get<0>(t4));
+ Tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &get<0>(t4));
+
+ EXPECT_EQ(1, get<0>(t1));
+ EXPECT_EQ(1, get<0>(t2));
+ EXPECT_EQ(1, get<0>(t3));
+ EXPECT_EQ(2, get<1>(t3));
+ EXPECT_EQ(3, get<2>(t3));
+ EXPECT_EQ(1, get<0>(t4));
+ EXPECT_EQ(2, get<1>(t4));
+ EXPECT_EQ(3, get<2>(t4));
+ EXPECT_EQ(1, get<0>(t5));
+ EXPECT_EQ(2, get<1>(t5));
+ EXPECT_EQ(3, get<2>(t5));
+ EXPECT_EQ(4, get<3>(t5));
+ EXPECT_EQ(1, get<0>(t6));
+ EXPECT_EQ(2, get<1>(t6));
+ EXPECT_EQ(3, get<2>(t6));
+ EXPECT_EQ(4, get<3>(t6));
+ EXPECT_EQ(5, get<4>(t6));
+
+ EXPECT_EQ(1, get<0>(t1));
DispatchToFunction(&DoAdd, t4);
- EXPECT_EQ(6, t1.a);
+ EXPECT_EQ(6, get<0>(t1));
int res = 0;
DispatchToFunction(&DoAdd, MakeTuple(9, 8, 7, &res));
EXPECT_EQ(24, res);
Addy addy;
- EXPECT_EQ(1, t4.a);
+ EXPECT_EQ(1, get<0>(t4));
DispatchToMethod(&addy, &Addy::DoAdd, t5);
- EXPECT_EQ(10, t4.a);
+ EXPECT_EQ(10, get<0>(t4));
Addz addz;
- EXPECT_EQ(10, t4.a);
+ EXPECT_EQ(10, get<0>(t4));
DispatchToMethod(&addz, &Addz::DoAdd, t6);
- EXPECT_EQ(15, t4.a);
+ EXPECT_EQ(15, get<0>(t4));
}
namespace {
@@ -108,8 +108,8 @@ TEST(TupleTest, Copying) {
bool res = false;
// Creating the tuple should copy the class to store internally in the tuple.
- Tuple3<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
- tuple.b = &tuple.a;
+ Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
+ get<1>(tuple) = &get<0>(tuple);
EXPECT_EQ(2, CopyLogger::TimesConstructed);
EXPECT_EQ(1, CopyLogger::TimesCopied);
diff --git a/chromium/base/value_conversions.h b/chromium/base/value_conversions.h
index fde9a269299..452c587cb84 100644
--- a/chromium/base/value_conversions.h
+++ b/chromium/base/value_conversions.h
@@ -24,6 +24,6 @@ BASE_EXPORT bool GetValueAsFilePath(const Value& value, FilePath* file_path);
BASE_EXPORT StringValue* CreateTimeDeltaValue(const TimeDelta& time);
BASE_EXPORT bool GetValueAsTimeDelta(const Value& value, TimeDelta* time);
-} // namespace
+} // namespace base
#endif // BASE_VALUE_CONVERSIONS_H_
diff --git a/chromium/base/values.cc b/chromium/base/values.cc
index 5d45ec36c55..4093eba67aa 100644
--- a/chromium/base/values.cc
+++ b/chromium/base/values.cc
@@ -7,9 +7,9 @@
#include <string.h>
#include <algorithm>
+#include <cmath>
#include <ostream>
-#include "base/float_util.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/move.h"
@@ -85,8 +85,12 @@ Value::~Value() {
}
// static
-Value* Value::CreateNullValue() {
- return new Value(TYPE_NULL);
+scoped_ptr<Value> Value::CreateNullValue() {
+ return make_scoped_ptr(new Value(TYPE_NULL));
+}
+
+bool Value::GetAsBinary(const BinaryValue** out_value) const {
+ return false;
}
bool Value::GetAsBoolean(bool* out_value) const {
@@ -133,7 +137,11 @@ Value* Value::DeepCopy() const {
// This method should only be getting called for null Values--all subclasses
// need to provide their own implementation;.
DCHECK(IsType(TYPE_NULL));
- return CreateNullValue();
+ return CreateNullValue().release();
+}
+
+scoped_ptr<Value> Value::CreateDeepCopy() const {
+ return make_scoped_ptr(DeepCopy());
}
bool Value::Equals(const Value* other) const {
@@ -171,7 +179,7 @@ FundamentalValue::FundamentalValue(int in_value)
FundamentalValue::FundamentalValue(double in_value)
: Value(TYPE_DOUBLE), double_value_(in_value) {
- if (!IsFinite(double_value_)) {
+ if (!std::isfinite(double_value_)) {
NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
<< "values cannot be represented in JSON";
double_value_ = 0.0;
@@ -319,6 +327,12 @@ BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
return new BinaryValue(scoped_buffer_copy.Pass(), size);
}
+bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const {
+ if (out_value)
+ *out_value = this;
+ return true;
+}
+
BinaryValue* BinaryValue::DeepCopy() const {
return CreateWithCopiedBuffer(buffer_.get(), size_);
}
@@ -371,7 +385,7 @@ void DictionaryValue::Clear() {
dictionary_.clear();
}
-void DictionaryValue::Set(const std::string& path, Value* in_value) {
+void DictionaryValue::Set(const std::string& path, scoped_ptr<Value> in_value) {
DCHECK(IsStringUTF8(path));
DCHECK(in_value);
@@ -392,7 +406,11 @@ void DictionaryValue::Set(const std::string& path, Value* in_value) {
current_path.erase(0, delimiter_position + 1);
}
- current_dictionary->SetWithoutPathExpansion(current_path, in_value);
+ current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass());
+}
+
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+ Set(path, make_scoped_ptr(in_value));
}
void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
@@ -418,18 +436,24 @@ void DictionaryValue::SetString(const std::string& path,
}
void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
- Value* in_value) {
+ scoped_ptr<Value> in_value) {
+ Value* bare_ptr = in_value.release();
// If there's an existing value here, we need to delete it, because
// we own all our children.
std::pair<ValueMap::iterator, bool> ins_res =
- dictionary_.insert(std::make_pair(key, in_value));
+ dictionary_.insert(std::make_pair(key, bare_ptr));
if (!ins_res.second) {
- DCHECK_NE(ins_res.first->second, in_value); // This would be bogus
+ DCHECK_NE(ins_res.first->second, bare_ptr); // This would be bogus
delete ins_res.first->second;
- ins_res.first->second = in_value;
+ ins_res.first->second = bare_ptr;
}
}
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+ Value* in_value) {
+ SetWithoutPathExpansion(key, make_scoped_ptr(in_value));
+}
+
void DictionaryValue::SetBooleanWithoutPathExpansion(
const std::string& path, bool in_value) {
SetWithoutPathExpansion(path, new FundamentalValue(in_value));
@@ -809,6 +833,10 @@ DictionaryValue* DictionaryValue::DeepCopy() const {
return result;
}
+scoped_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
+ return make_scoped_ptr(DeepCopy());
+}
+
bool DictionaryValue::Equals(const Value* other) const {
if (other->GetType() != GetType())
return false;
@@ -863,6 +891,10 @@ bool ListValue::Set(size_t index, Value* in_value) {
return true;
}
+bool ListValue::Set(size_t index, scoped_ptr<Value> in_value) {
+ return Set(index, in_value.release());
+}
+
bool ListValue::Get(size_t index, const Value** out_value) const {
if (index >= list_.size())
return false;
@@ -1012,6 +1044,10 @@ ListValue::iterator ListValue::Erase(iterator iter,
return list_.erase(iter);
}
+void ListValue::Append(scoped_ptr<Value> in_value) {
+ Append(in_value.release());
+}
+
void ListValue::Append(Value* in_value) {
DCHECK(in_value);
list_.push_back(in_value);
@@ -1101,6 +1137,10 @@ ListValue* ListValue::DeepCopy() const {
return result;
}
+scoped_ptr<ListValue> ListValue::CreateDeepCopy() const {
+ return make_scoped_ptr(DeepCopy());
+}
+
bool ListValue::Equals(const Value* other) const {
if (other->GetType() != GetType())
return false;
@@ -1123,6 +1163,9 @@ bool ListValue::Equals(const Value* other) const {
ValueSerializer::~ValueSerializer() {
}
+ValueDeserializer::~ValueDeserializer() {
+}
+
std::ostream& operator<<(std::ostream& out, const Value& value) {
std::string json;
JSONWriter::WriteWithOptions(&value,
diff --git a/chromium/base/values.h b/chromium/base/values.h
index 04b2d26eac6..e32edecf2ec 100644
--- a/chromium/base/values.h
+++ b/chromium/base/values.h
@@ -33,6 +33,7 @@
namespace base {
+class BinaryValue;
class DictionaryValue;
class FundamentalValue;
class ListValue;
@@ -63,7 +64,7 @@ class BASE_EXPORT Value {
virtual ~Value();
- static Value* CreateNullValue();
+ static scoped_ptr<Value> CreateNullValue();
// Returns the type of the value stored by the current Value object.
// Each type will be implemented by only one subclass of Value, so it's
@@ -85,6 +86,7 @@ class BASE_EXPORT Value {
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
virtual bool GetAsString(const StringValue** out_value) const;
+ virtual bool GetAsBinary(const BinaryValue** out_value) const;
virtual bool GetAsList(ListValue** out_value);
virtual bool GetAsList(const ListValue** out_value) const;
virtual bool GetAsDictionary(DictionaryValue** out_value);
@@ -97,6 +99,8 @@ class BASE_EXPORT Value {
// Subclasses return their own type directly in their overrides;
// this works because C++ supports covariant return types.
virtual Value* DeepCopy() const;
+ // Preferred version of DeepCopy. TODO(estade): remove the above.
+ scoped_ptr<Value> CreateDeepCopy() const;
// Compares if two Value objects have equal contents.
virtual bool Equals(const Value* other) const;
@@ -188,6 +192,7 @@ class BASE_EXPORT BinaryValue: public Value {
const char* GetBuffer() const { return buffer_.get(); }
// Overridden from Value:
+ bool GetAsBinary(const BinaryValue** out_value) const override;
BinaryValue* DeepCopy() const override;
bool Equals(const Value* other) const override;
@@ -228,9 +233,9 @@ class BASE_EXPORT DictionaryValue : public Value {
// within a key, but there are no other restrictions on keys.
// If the key at any step of the way doesn't exist, or exists but isn't
// a DictionaryValue, a new DictionaryValue will be created and attached
- // to the path in that location.
- // Note that the dictionary takes ownership of the value referenced by
- // |in_value|, and therefore |in_value| must be non-NULL.
+ // to the path in that location. |in_value| must be non-null.
+ void Set(const std::string& path, scoped_ptr<Value> in_value);
+ // Deprecated version of the above. TODO(estade): remove.
void Set(const std::string& path, Value* in_value);
// Convenience forms of Set(). These methods will replace any existing
@@ -243,6 +248,9 @@ class BASE_EXPORT DictionaryValue : public Value {
// Like Set(), but without special treatment of '.'. This allows e.g. URLs to
// be used as paths.
+ void SetWithoutPathExpansion(const std::string& key,
+ scoped_ptr<Value> in_value);
+ // Deprecated version of the above. TODO(estade): remove.
void SetWithoutPathExpansion(const std::string& key, Value* in_value);
// Convenience forms of SetWithoutPathExpansion().
@@ -362,6 +370,8 @@ class BASE_EXPORT DictionaryValue : public Value {
// Overridden from Value:
DictionaryValue* DeepCopy() const override;
+ // Preferred version of DeepCopy. TODO(estade): remove the above.
+ scoped_ptr<DictionaryValue> CreateDeepCopy() const;
bool Equals(const Value* other) const override;
private:
@@ -394,6 +404,8 @@ class BASE_EXPORT ListValue : public Value {
// Returns true if successful, or false if the index was negative or
// the value is a null pointer.
bool Set(size_t index, Value* in_value);
+ // Preferred version of the above. TODO(estade): remove the above.
+ bool Set(size_t index, scoped_ptr<Value> in_value);
// Gets the Value at the given index. Modifies |out_value| (and returns true)
// only if the index falls within the current list range.
@@ -439,6 +451,8 @@ class BASE_EXPORT ListValue : public Value {
iterator Erase(iterator iter, scoped_ptr<Value>* out_value);
// Appends a Value to the end of the list.
+ void Append(scoped_ptr<Value> in_value);
+ // Deprecated version of the above. TODO(estade): remove.
void Append(Value* in_value);
// Convenience forms of Append.
@@ -480,19 +494,29 @@ class BASE_EXPORT ListValue : public Value {
ListValue* DeepCopy() const override;
bool Equals(const Value* other) const override;
+ // Preferred version of DeepCopy. TODO(estade): remove DeepCopy.
+ scoped_ptr<ListValue> CreateDeepCopy() const;
+
private:
ValueVector list_;
DISALLOW_COPY_AND_ASSIGN(ListValue);
};
-// This interface is implemented by classes that know how to serialize and
-// deserialize Value objects.
+// This interface is implemented by classes that know how to serialize
+// Value objects.
class BASE_EXPORT ValueSerializer {
public:
virtual ~ValueSerializer();
virtual bool Serialize(const Value& root) = 0;
+};
+
+// This interface is implemented by classes that know how to deserialize Value
+// objects.
+class BASE_EXPORT ValueDeserializer {
+ public:
+ virtual ~ValueDeserializer();
// This method deserializes the subclass-specific format into a Value object.
// If the return value is non-NULL, the caller takes ownership of returned
diff --git a/chromium/base/values_unittest.cc b/chromium/base/values_unittest.cc
index cbb07f3199d..6466a962554 100644
--- a/chromium/base/values_unittest.cc
+++ b/chromium/base/values_unittest.cc
@@ -20,7 +20,7 @@ TEST(ValuesTest, Basic) {
ASSERT_EQ(std::string("http://google.com"), homepage);
ASSERT_FALSE(settings.Get("global", NULL));
- settings.Set("global", new FundamentalValue(true));
+ settings.SetBoolean("global", true);
ASSERT_TRUE(settings.Get("global", NULL));
settings.SetString("global.homepage", "http://scurvy.com");
ASSERT_TRUE(settings.Get("global", NULL));
@@ -33,14 +33,14 @@ TEST(ValuesTest, Basic) {
ASSERT_FALSE(
settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
- toolbar_bookmarks = new ListValue;
- settings.Set("global.toolbar.bookmarks", toolbar_bookmarks);
+ scoped_ptr<ListValue> new_toolbar_bookmarks(new ListValue);
+ settings.Set("global.toolbar.bookmarks", new_toolbar_bookmarks.Pass());
ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
- DictionaryValue* new_bookmark = new DictionaryValue;
+ scoped_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
new_bookmark->SetString("name", "Froogle");
new_bookmark->SetString("url", "http://froogle.com");
- toolbar_bookmarks->Append(new_bookmark);
+ toolbar_bookmarks->Append(new_bookmark.Pass());
ListValue* bookmark_list;
ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
@@ -57,10 +57,10 @@ TEST(ValuesTest, Basic) {
TEST(ValuesTest, List) {
scoped_ptr<ListValue> mixed_list(new ListValue());
- mixed_list->Set(0, new FundamentalValue(true));
- mixed_list->Set(1, new FundamentalValue(42));
- mixed_list->Set(2, new FundamentalValue(88.8));
- mixed_list->Set(3, new StringValue("foo"));
+ mixed_list->Set(0, make_scoped_ptr(new FundamentalValue(true)));
+ mixed_list->Set(1, make_scoped_ptr(new FundamentalValue(42)));
+ mixed_list->Set(2, make_scoped_ptr(new FundamentalValue(88.8)));
+ mixed_list->Set(3, make_scoped_ptr(new StringValue("foo")));
ASSERT_EQ(4u, mixed_list->GetSize());
Value *value = NULL;
@@ -112,11 +112,12 @@ TEST(ValuesTest, BinaryValue) {
ASSERT_EQ(0U, binary->GetSize());
// Test the common case of a non-empty buffer
- char* buffer = new char[15];
- binary.reset(new BinaryValue(scoped_ptr<char[]>(buffer), 15));
+ scoped_ptr<char[]> buffer(new char[15]);
+ char* original_buffer = buffer.get();
+ binary.reset(new BinaryValue(buffer.Pass(), 15));
ASSERT_TRUE(binary.get());
ASSERT_TRUE(binary->GetBuffer());
- ASSERT_EQ(buffer, binary->GetBuffer());
+ ASSERT_EQ(original_buffer, binary->GetBuffer());
ASSERT_EQ(15U, binary->GetSize());
char stack_buffer[42];
@@ -127,6 +128,12 @@ TEST(ValuesTest, BinaryValue) {
ASSERT_NE(stack_buffer, binary->GetBuffer());
ASSERT_EQ(42U, binary->GetSize());
ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize()));
+
+ // Test overloaded GetAsBinary.
+ Value* narrow_value = binary.get();
+ const BinaryValue* narrow_binary = NULL;
+ ASSERT_TRUE(narrow_value->GetAsBinary(&narrow_binary));
+ EXPECT_EQ(binary.get(), narrow_binary);
}
TEST(ValuesTest, StringValue) {
@@ -188,14 +195,14 @@ TEST(ValuesTest, ListDeletion) {
{
ListValue list;
- list.Append(new DeletionTestValue(&deletion_flag));
+ list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
}
EXPECT_TRUE(deletion_flag);
{
ListValue list;
- list.Append(new DeletionTestValue(&deletion_flag));
+ list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
list.Clear();
EXPECT_TRUE(deletion_flag);
@@ -203,7 +210,7 @@ TEST(ValuesTest, ListDeletion) {
{
ListValue list;
- list.Append(new DeletionTestValue(&deletion_flag));
+ list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
EXPECT_TRUE(list.Set(0, Value::CreateNullValue()));
EXPECT_TRUE(deletion_flag);
@@ -216,7 +223,7 @@ TEST(ValuesTest, ListRemoval) {
{
ListValue list;
- list.Append(new DeletionTestValue(&deletion_flag));
+ list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
EXPECT_EQ(1U, list.GetSize());
EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(),
@@ -232,7 +239,7 @@ TEST(ValuesTest, ListRemoval) {
{
ListValue list;
- list.Append(new DeletionTestValue(&deletion_flag));
+ list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
EXPECT_TRUE(list.Remove(0, NULL));
EXPECT_TRUE(deletion_flag);
@@ -241,11 +248,12 @@ TEST(ValuesTest, ListRemoval) {
{
ListValue list;
- DeletionTestValue* value = new DeletionTestValue(&deletion_flag);
- list.Append(value);
+ scoped_ptr<DeletionTestValue> value(new DeletionTestValue(&deletion_flag));
+ DeletionTestValue* original_value = value.get();
+ list.Append(value.Pass());
EXPECT_FALSE(deletion_flag);
size_t index = 0;
- list.Remove(*value, &index);
+ list.Remove(*original_value, &index);
EXPECT_EQ(0U, index);
EXPECT_TRUE(deletion_flag);
EXPECT_EQ(0U, list.GetSize());
@@ -258,14 +266,14 @@ TEST(ValuesTest, DictionaryDeletion) {
{
DictionaryValue dict;
- dict.Set(key, new DeletionTestValue(&deletion_flag));
+ dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
}
EXPECT_TRUE(deletion_flag);
{
DictionaryValue dict;
- dict.Set(key, new DeletionTestValue(&deletion_flag));
+ dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
dict.Clear();
EXPECT_TRUE(deletion_flag);
@@ -273,7 +281,7 @@ TEST(ValuesTest, DictionaryDeletion) {
{
DictionaryValue dict;
- dict.Set(key, new DeletionTestValue(&deletion_flag));
+ dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
dict.Set(key, Value::CreateNullValue());
EXPECT_TRUE(deletion_flag);
@@ -287,7 +295,7 @@ TEST(ValuesTest, DictionaryRemoval) {
{
DictionaryValue dict;
- dict.Set(key, new DeletionTestValue(&deletion_flag));
+ dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
EXPECT_TRUE(dict.HasKey(key));
EXPECT_FALSE(dict.Remove("absent key", &removed_item));
@@ -301,7 +309,7 @@ TEST(ValuesTest, DictionaryRemoval) {
{
DictionaryValue dict;
- dict.Set(key, new DeletionTestValue(&deletion_flag));
+ dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
EXPECT_FALSE(deletion_flag);
EXPECT_TRUE(dict.HasKey(key));
EXPECT_TRUE(dict.Remove(key, NULL));
@@ -332,10 +340,34 @@ TEST(ValuesTest, DictionaryWithoutPathExpansion) {
EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
}
+// Tests the deprecated version of SetWithoutPathExpansion.
+// TODO(estade): remove.
+TEST(ValuesTest, DictionaryWithoutPathExpansionDeprecated) {
+ DictionaryValue dict;
+ dict.Set("this.is.expanded", Value::CreateNullValue());
+ dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue());
+
+ EXPECT_FALSE(dict.HasKey("this.is.expanded"));
+ EXPECT_TRUE(dict.HasKey("this"));
+ Value* value1;
+ EXPECT_TRUE(dict.Get("this", &value1));
+ DictionaryValue* value2;
+ ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2));
+ EXPECT_EQ(value1, value2);
+ EXPECT_EQ(1U, value2->size());
+
+ EXPECT_TRUE(dict.HasKey("this.isnt.expanded"));
+ Value* value3;
+ EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3));
+ Value* value4;
+ ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4));
+ EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
+}
+
TEST(ValuesTest, DictionaryRemovePath) {
DictionaryValue dict;
- dict.Set("a.long.way.down", new FundamentalValue(1));
- dict.Set("a.long.key.path", new FundamentalValue(true));
+ dict.SetInteger("a.long.way.down", 1);
+ dict.SetBoolean("a.long.key.path", true);
scoped_ptr<Value> removed_item;
EXPECT_TRUE(dict.RemovePath("a.long.way.down", &removed_item));
@@ -359,36 +391,49 @@ TEST(ValuesTest, DictionaryRemovePath) {
TEST(ValuesTest, DeepCopy) {
DictionaryValue original_dict;
- Value* original_null = Value::CreateNullValue();
- original_dict.Set("null", original_null);
- FundamentalValue* original_bool = new FundamentalValue(true);
- original_dict.Set("bool", original_bool);
- FundamentalValue* original_int = new FundamentalValue(42);
- original_dict.Set("int", original_int);
- FundamentalValue* original_double = new FundamentalValue(3.14);
- original_dict.Set("double", original_double);
- StringValue* original_string = new StringValue("hello");
- original_dict.Set("string", original_string);
- StringValue* original_string16 = new StringValue(ASCIIToUTF16("hello16"));
- original_dict.Set("string16", original_string16);
+ scoped_ptr<Value> scoped_null = Value::CreateNullValue();
+ Value* original_null = scoped_null.get();
+ original_dict.Set("null", scoped_null.Pass());
+ scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
+ FundamentalValue* original_bool = scoped_bool.get();
+ original_dict.Set("bool", scoped_bool.Pass());
+ scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
+ FundamentalValue* original_int = scoped_int.get();
+ original_dict.Set("int", scoped_int.Pass());
+ scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
+ FundamentalValue* original_double = scoped_double.get();
+ original_dict.Set("double", scoped_double.Pass());
+ scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
+ StringValue* original_string = scoped_string.get();
+ original_dict.Set("string", scoped_string.Pass());
+ scoped_ptr<StringValue> scoped_string16(
+ new StringValue(ASCIIToUTF16("hello16")));
+ StringValue* original_string16 = scoped_string16.get();
+ original_dict.Set("string16", scoped_string16.Pass());
scoped_ptr<char[]> original_buffer(new char[42]);
memset(original_buffer.get(), '!', 42);
- BinaryValue* original_binary = new BinaryValue(original_buffer.Pass(), 42);
- original_dict.Set("binary", original_binary);
-
- ListValue* original_list = new ListValue();
- FundamentalValue* original_list_element_0 = new FundamentalValue(0);
- original_list->Append(original_list_element_0);
- FundamentalValue* original_list_element_1 = new FundamentalValue(1);
- original_list->Append(original_list_element_1);
- original_dict.Set("list", original_list);
-
- DictionaryValue* original_nested_dictionary = new DictionaryValue();
- original_nested_dictionary->Set("key", new StringValue("value"));
- original_dict.Set("dictionary", original_nested_dictionary);
-
- scoped_ptr<DictionaryValue> copy_dict(original_dict.DeepCopy());
+ scoped_ptr<BinaryValue> scoped_binary(
+ new BinaryValue(original_buffer.Pass(), 42));
+ BinaryValue* original_binary = scoped_binary.get();
+ original_dict.Set("binary", scoped_binary.Pass());
+
+ scoped_ptr<ListValue> scoped_list(new ListValue());
+ Value* original_list = scoped_list.get();
+ scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
+ Value* original_list_element_0 = scoped_list_element_0.get();
+ scoped_list->Append(scoped_list_element_0.Pass());
+ scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
+ Value* original_list_element_1 = scoped_list_element_1.get();
+ scoped_list->Append(scoped_list_element_1.Pass());
+ original_dict.Set("list", scoped_list.Pass());
+
+ scoped_ptr<DictionaryValue> scoped_nested_dictionary(new DictionaryValue());
+ Value* original_nested_dictionary = scoped_nested_dictionary.get();
+ scoped_nested_dictionary->SetString("key", "value");
+ original_dict.Set("dictionary", scoped_nested_dictionary.Pass());
+
+ scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy();
ASSERT_TRUE(copy_dict.get());
ASSERT_NE(copy_dict.get(), &original_dict);
@@ -498,16 +543,13 @@ TEST(ValuesTest, DeepCopy) {
}
TEST(ValuesTest, Equals) {
- Value* null1 = Value::CreateNullValue();
- Value* null2 = Value::CreateNullValue();
- EXPECT_NE(null1, null2);
- EXPECT_TRUE(null1->Equals(null2));
+ scoped_ptr<Value> null1(Value::CreateNullValue());
+ scoped_ptr<Value> null2(Value::CreateNullValue());
+ EXPECT_NE(null1.get(), null2.get());
+ EXPECT_TRUE(null1->Equals(null2.get()));
- Value* boolean = new FundamentalValue(false);
- EXPECT_FALSE(null1->Equals(boolean));
- delete null1;
- delete null2;
- delete boolean;
+ FundamentalValue boolean(false);
+ EXPECT_FALSE(null1->Equals(&boolean));
DictionaryValue dv;
dv.SetBoolean("a", false);
@@ -517,24 +559,25 @@ TEST(ValuesTest, Equals) {
dv.SetString("d2", ASCIIToUTF16("http://google.com"));
dv.Set("e", Value::CreateNullValue());
- scoped_ptr<DictionaryValue> copy;
- copy.reset(dv.DeepCopy());
+ scoped_ptr<DictionaryValue> copy = dv.CreateDeepCopy();
EXPECT_TRUE(dv.Equals(copy.get()));
- ListValue* list = new ListValue;
+ scoped_ptr<ListValue> list(new ListValue);
+ ListValue* original_list = list.get();
list->Append(Value::CreateNullValue());
- list->Append(new DictionaryValue);
- dv.Set("f", list);
+ list->Append(make_scoped_ptr(new DictionaryValue));
+ scoped_ptr<Value> list_copy(list->CreateDeepCopy());
+ dv.Set("f", list.Pass());
EXPECT_FALSE(dv.Equals(copy.get()));
- copy->Set("f", list->DeepCopy());
+ copy->Set("f", list_copy.Pass());
EXPECT_TRUE(dv.Equals(copy.get()));
- list->Append(new FundamentalValue(true));
+ original_list->Append(make_scoped_ptr(new FundamentalValue(true)));
EXPECT_FALSE(dv.Equals(copy.get()));
// Check if Equals detects differences in only the keys.
- copy.reset(dv.DeepCopy());
+ copy = dv.CreateDeepCopy();
EXPECT_TRUE(dv.Equals(copy.get()));
copy->Remove("a", NULL);
copy->SetBoolean("aa", false);
@@ -566,71 +609,75 @@ TEST(ValuesTest, StaticEquals) {
TEST(ValuesTest, DeepCopyCovariantReturnTypes) {
DictionaryValue original_dict;
- Value* original_null = Value::CreateNullValue();
- original_dict.Set("null", original_null);
- FundamentalValue* original_bool = new FundamentalValue(true);
- original_dict.Set("bool", original_bool);
- FundamentalValue* original_int = new FundamentalValue(42);
- original_dict.Set("int", original_int);
- FundamentalValue* original_double = new FundamentalValue(3.14);
- original_dict.Set("double", original_double);
- StringValue* original_string = new StringValue("hello");
- original_dict.Set("string", original_string);
- StringValue* original_string16 = new StringValue(ASCIIToUTF16("hello16"));
- original_dict.Set("string16", original_string16);
+ scoped_ptr<Value> scoped_null(Value::CreateNullValue());
+ Value* original_null = scoped_null.get();
+ original_dict.Set("null", scoped_null.Pass());
+ scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
+ Value* original_bool = scoped_bool.get();
+ original_dict.Set("bool", scoped_bool.Pass());
+ scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
+ Value* original_int = scoped_int.get();
+ original_dict.Set("int", scoped_int.Pass());
+ scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
+ Value* original_double = scoped_double.get();
+ original_dict.Set("double", scoped_double.Pass());
+ scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
+ Value* original_string = scoped_string.get();
+ original_dict.Set("string", scoped_string.Pass());
+ scoped_ptr<StringValue> scoped_string16(
+ new StringValue(ASCIIToUTF16("hello16")));
+ Value* original_string16 = scoped_string16.get();
+ original_dict.Set("string16", scoped_string16.Pass());
scoped_ptr<char[]> original_buffer(new char[42]);
memset(original_buffer.get(), '!', 42);
- BinaryValue* original_binary = new BinaryValue(original_buffer.Pass(), 42);
- original_dict.Set("binary", original_binary);
-
- ListValue* original_list = new ListValue();
- FundamentalValue* original_list_element_0 = new FundamentalValue(0);
- original_list->Append(original_list_element_0);
- FundamentalValue* original_list_element_1 = new FundamentalValue(1);
- original_list->Append(original_list_element_1);
- original_dict.Set("list", original_list);
-
- Value* original_dict_value = &original_dict;
- Value* original_bool_value = original_bool;
- Value* original_int_value = original_int;
- Value* original_double_value = original_double;
- Value* original_string_value = original_string;
- Value* original_string16_value = original_string16;
- Value* original_binary_value = original_binary;
- Value* original_list_value = original_list;
-
- scoped_ptr<Value> copy_dict_value(original_dict_value->DeepCopy());
- scoped_ptr<Value> copy_bool_value(original_bool_value->DeepCopy());
- scoped_ptr<Value> copy_int_value(original_int_value->DeepCopy());
- scoped_ptr<Value> copy_double_value(original_double_value->DeepCopy());
- scoped_ptr<Value> copy_string_value(original_string_value->DeepCopy());
- scoped_ptr<Value> copy_string16_value(original_string16_value->DeepCopy());
- scoped_ptr<Value> copy_binary_value(original_binary_value->DeepCopy());
- scoped_ptr<Value> copy_list_value(original_list_value->DeepCopy());
-
- EXPECT_TRUE(original_dict_value->Equals(copy_dict_value.get()));
- EXPECT_TRUE(original_bool_value->Equals(copy_bool_value.get()));
- EXPECT_TRUE(original_int_value->Equals(copy_int_value.get()));
- EXPECT_TRUE(original_double_value->Equals(copy_double_value.get()));
- EXPECT_TRUE(original_string_value->Equals(copy_string_value.get()));
- EXPECT_TRUE(original_string16_value->Equals(copy_string16_value.get()));
- EXPECT_TRUE(original_binary_value->Equals(copy_binary_value.get()));
- EXPECT_TRUE(original_list_value->Equals(copy_list_value.get()));
+ scoped_ptr<BinaryValue> scoped_binary(
+ new BinaryValue(original_buffer.Pass(), 42));
+ Value* original_binary = scoped_binary.get();
+ original_dict.Set("binary", scoped_binary.Pass());
+
+ scoped_ptr<ListValue> scoped_list(new ListValue());
+ Value* original_list = scoped_list.get();
+ scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
+ scoped_list->Append(scoped_list_element_0.Pass());
+ scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
+ scoped_list->Append(scoped_list_element_1.Pass());
+ original_dict.Set("list", scoped_list.Pass());
+
+ scoped_ptr<Value> copy_dict = original_dict.CreateDeepCopy();
+ scoped_ptr<Value> copy_null = original_null->CreateDeepCopy();
+ scoped_ptr<Value> copy_bool = original_bool->CreateDeepCopy();
+ scoped_ptr<Value> copy_int = original_int->CreateDeepCopy();
+ scoped_ptr<Value> copy_double = original_double->CreateDeepCopy();
+ scoped_ptr<Value> copy_string = original_string->CreateDeepCopy();
+ scoped_ptr<Value> copy_string16 = original_string16->CreateDeepCopy();
+ scoped_ptr<Value> copy_binary = original_binary->CreateDeepCopy();
+ scoped_ptr<Value> copy_list = original_list->CreateDeepCopy();
+
+ EXPECT_TRUE(original_dict.Equals(copy_dict.get()));
+ EXPECT_TRUE(original_null->Equals(copy_null.get()));
+ EXPECT_TRUE(original_bool->Equals(copy_bool.get()));
+ EXPECT_TRUE(original_int->Equals(copy_int.get()));
+ EXPECT_TRUE(original_double->Equals(copy_double.get()));
+ EXPECT_TRUE(original_string->Equals(copy_string.get()));
+ EXPECT_TRUE(original_string16->Equals(copy_string16.get()));
+ EXPECT_TRUE(original_binary->Equals(copy_binary.get()));
+ EXPECT_TRUE(original_list->Equals(copy_list.get()));
}
TEST(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<DictionaryValue> root(new DictionaryValue);
// Remove empty lists and dictionaries.
- root->Set("empty_dict", new DictionaryValue);
- root->Set("empty_list", new ListValue);
- root->SetWithoutPathExpansion("a.b.c.d.e", new DictionaryValue);
+ root->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+ root->Set("empty_list", make_scoped_ptr(new ListValue));
+ root->SetWithoutPathExpansion("a.b.c.d.e",
+ make_scoped_ptr(new DictionaryValue));
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_TRUE(root->empty());
// Make sure we don't prune too much.
root->SetBoolean("bool", true);
- root->Set("empty_dict", new DictionaryValue);
+ root->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
root->SetString("empty_string", std::string());
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
@@ -642,55 +689,57 @@ TEST(ValuesTest, RemoveEmptyChildren) {
// Nested test cases. These should all reduce back to the bool and string
// set above.
{
- root->Set("a.b.c.d.e", new DictionaryValue);
+ root->Set("a.b.c.d.e", make_scoped_ptr(new DictionaryValue));
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
{
- DictionaryValue* inner = new DictionaryValue;
- root->Set("dict_with_emtpy_children", inner);
- inner->Set("empty_dict", new DictionaryValue);
- inner->Set("empty_list", new ListValue);
+ scoped_ptr<DictionaryValue> inner(new DictionaryValue);
+ inner->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+ inner->Set("empty_list", make_scoped_ptr(new ListValue));
+ root->Set("dict_with_empty_children", inner.Pass());
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
{
- ListValue* inner = new ListValue;
- root->Set("list_with_empty_children", inner);
- inner->Append(new DictionaryValue);
- inner->Append(new ListValue);
+ scoped_ptr<ListValue> inner(new ListValue);
+ inner->Append(make_scoped_ptr(new DictionaryValue));
+ inner->Append(make_scoped_ptr(new ListValue));
+ root->Set("list_with_empty_children", inner.Pass());
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
// Nested with siblings.
{
- ListValue* inner = new ListValue;
- root->Set("list_with_empty_children", inner);
- inner->Append(new DictionaryValue);
- inner->Append(new ListValue);
- DictionaryValue* inner2 = new DictionaryValue;
- root->Set("dict_with_empty_children", inner2);
- inner2->Set("empty_dict", new DictionaryValue);
- inner2->Set("empty_list", new ListValue);
+ scoped_ptr<ListValue> inner(new ListValue());
+ inner->Append(make_scoped_ptr(new DictionaryValue));
+ inner->Append(make_scoped_ptr(new ListValue));
+ root->Set("list_with_empty_children", inner.Pass());
+ scoped_ptr<DictionaryValue> inner2(new DictionaryValue);
+ inner2->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+ inner2->Set("empty_list", make_scoped_ptr(new ListValue));
+ root->Set("dict_with_empty_children", inner2.Pass());
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
// Make sure nested values don't get pruned.
{
- ListValue* inner = new ListValue;
- root->Set("list_with_empty_children", inner);
- ListValue* inner2 = new ListValue;
- inner->Append(new DictionaryValue);
- inner->Append(inner2);
- inner2->Append(new StringValue("hello"));
+ scoped_ptr<ListValue> inner(new ListValue);
+ scoped_ptr<ListValue> inner2(new ListValue);
+ inner2->Append(make_scoped_ptr(new StringValue("hello")));
+ inner->Append(make_scoped_ptr(new DictionaryValue));
+ inner->Append(inner2.Pass());
+ root->Set("list_with_empty_children", inner.Pass());
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(3U, root->size());
- EXPECT_TRUE(root->GetList("list_with_empty_children", &inner));
- EXPECT_EQ(1U, inner->GetSize()); // Dictionary was pruned.
- EXPECT_TRUE(inner->GetList(0, &inner2));
- EXPECT_EQ(1U, inner2->GetSize());
+
+ ListValue* inner_value, *inner_value2;
+ EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value));
+ EXPECT_EQ(1U, inner_value->GetSize()); // Dictionary was pruned.
+ EXPECT_TRUE(inner_value->GetList(0, &inner_value2));
+ EXPECT_EQ(1U, inner_value2->GetSize());
}
}
@@ -698,18 +747,18 @@ TEST(ValuesTest, MergeDictionary) {
scoped_ptr<DictionaryValue> base(new DictionaryValue);
base->SetString("base_key", "base_key_value_base");
base->SetString("collide_key", "collide_key_value_base");
- DictionaryValue* base_sub_dict = new DictionaryValue;
+ scoped_ptr<DictionaryValue> base_sub_dict(new DictionaryValue);
base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
- base->Set("sub_dict_key", base_sub_dict);
+ base->Set("sub_dict_key", base_sub_dict.Pass());
scoped_ptr<DictionaryValue> merge(new DictionaryValue);
merge->SetString("merge_key", "merge_key_value_merge");
merge->SetString("collide_key", "collide_key_value_merge");
- DictionaryValue* merge_sub_dict = new DictionaryValue;
+ scoped_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue);
merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
- merge->Set("sub_dict_key", merge_sub_dict);
+ merge->Set("sub_dict_key", merge_sub_dict.Pass());
base->MergeDictionary(merge.get());
@@ -740,7 +789,8 @@ TEST(ValuesTest, MergeDictionary) {
}
TEST(ValuesTest, MergeDictionaryDeepCopy) {
- DictionaryValue* child = new DictionaryValue;
+ scoped_ptr<DictionaryValue> child(new DictionaryValue);
+ DictionaryValue* original_child = child.get();
child->SetString("test", "value");
EXPECT_EQ(1U, child->size());
@@ -749,22 +799,22 @@ TEST(ValuesTest, MergeDictionaryDeepCopy) {
EXPECT_EQ("value", value);
scoped_ptr<DictionaryValue> base(new DictionaryValue);
- base->Set("dict", child);
+ base->Set("dict", child.Pass());
EXPECT_EQ(1U, base->size());
DictionaryValue* ptr;
EXPECT_TRUE(base->GetDictionary("dict", &ptr));
- EXPECT_EQ(child, ptr);
+ EXPECT_EQ(original_child, ptr);
scoped_ptr<DictionaryValue> merged(new DictionaryValue);
merged->MergeDictionary(base.get());
EXPECT_EQ(1U, merged->size());
EXPECT_TRUE(merged->GetDictionary("dict", &ptr));
- EXPECT_NE(child, ptr);
+ EXPECT_NE(original_child, ptr);
EXPECT_TRUE(ptr->GetString("test", &value));
EXPECT_EQ("value", value);
- child->SetString("test", "overwrite");
+ original_child->SetString("test", "overwrite");
base.reset();
EXPECT_TRUE(ptr->GetString("test", &value));
EXPECT_EQ("value", value);
@@ -777,7 +827,7 @@ TEST(ValuesTest, DictionaryIterator) {
}
StringValue value1("value1");
- dict.Set("key1", value1.DeepCopy());
+ dict.Set("key1", value1.CreateDeepCopy());
bool seen1 = false;
for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
EXPECT_FALSE(seen1);
@@ -788,7 +838,7 @@ TEST(ValuesTest, DictionaryIterator) {
EXPECT_TRUE(seen1);
StringValue value2("value2");
- dict.Set("key2", value2.DeepCopy());
+ dict.Set("key2", value2.CreateDeepCopy());
bool seen2 = seen1 = false;
for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
if (it.key() == "key1") {
@@ -821,21 +871,21 @@ TEST(ValuesTest, GetWithNullOutValue) {
DictionaryValue dict_value;
ListValue list_value;
- main_dict.Set("bool", bool_value.DeepCopy());
- main_dict.Set("int", int_value.DeepCopy());
- main_dict.Set("double", double_value.DeepCopy());
- main_dict.Set("string", string_value.DeepCopy());
- main_dict.Set("binary", binary_value.DeepCopy());
- main_dict.Set("dict", dict_value.DeepCopy());
- main_dict.Set("list", list_value.DeepCopy());
-
- main_list.Append(bool_value.DeepCopy());
- main_list.Append(int_value.DeepCopy());
- main_list.Append(double_value.DeepCopy());
- main_list.Append(string_value.DeepCopy());
- main_list.Append(binary_value.DeepCopy());
- main_list.Append(dict_value.DeepCopy());
- main_list.Append(list_value.DeepCopy());
+ main_dict.Set("bool", bool_value.CreateDeepCopy());
+ main_dict.Set("int", int_value.CreateDeepCopy());
+ main_dict.Set("double", double_value.CreateDeepCopy());
+ main_dict.Set("string", string_value.CreateDeepCopy());
+ main_dict.Set("binary", binary_value.CreateDeepCopy());
+ main_dict.Set("dict", dict_value.CreateDeepCopy());
+ main_dict.Set("list", list_value.CreateDeepCopy());
+
+ main_list.Append(bool_value.CreateDeepCopy());
+ main_list.Append(int_value.CreateDeepCopy());
+ main_list.Append(double_value.CreateDeepCopy());
+ main_list.Append(string_value.CreateDeepCopy());
+ main_list.Append(binary_value.CreateDeepCopy());
+ main_list.Append(dict_value.CreateDeepCopy());
+ main_list.Append(list_value.CreateDeepCopy());
EXPECT_TRUE(main_dict.Get("bool", NULL));
EXPECT_TRUE(main_dict.Get("int", NULL));
diff --git a/chromium/base/version.cc b/chromium/base/version.cc
index 6318b350edc..ede8a4586eb 100644
--- a/chromium/base/version.cc
+++ b/chromium/base/version.cc
@@ -23,7 +23,7 @@ namespace {
// is the resulting integer vector. Function returns true if all numbers were
// parsed successfully, false otherwise.
bool ParseVersionNumbers(const std::string& version_str,
- std::vector<uint16>* parsed) {
+ std::vector<uint32_t>* parsed) {
std::vector<std::string> numbers;
SplitString(version_str, '.', &numbers);
if (numbers.empty())
@@ -31,22 +31,20 @@ bool ParseVersionNumbers(const std::string& version_str,
for (std::vector<std::string>::const_iterator it = numbers.begin();
it != numbers.end(); ++it) {
- int num;
- if (!StringToInt(*it, &num))
+ if (StartsWithASCII(*it, "+", false))
return false;
-
- if (num < 0)
- return false;
-
- const uint16 max = 0xFFFF;
- if (num > max)
+ unsigned int num;
+ if (!StringToUint(*it, &num))
return false;
- // This throws out things like +3, or 032.
- if (IntToString(num) != *it)
+ // This throws out leading zeros for the first item only.
+ if (it == numbers.begin() && UintToString(num) != *it)
return false;
- parsed->push_back(static_cast<uint16>(num));
+ // StringToUint returns unsigned int but Version fields are uint32_t.
+ static_assert(sizeof (uint32_t) == sizeof (unsigned int),
+ "uint32_t must be same as unsigned int");
+ parsed->push_back(num);
}
return true;
}
@@ -54,8 +52,8 @@ bool ParseVersionNumbers(const std::string& version_str,
// Compares version components in |components1| with components in
// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to,
// or greater than |components2|, respectively.
-int CompareVersionComponents(const std::vector<uint16>& components1,
- const std::vector<uint16>& components2) {
+int CompareVersionComponents(const std::vector<uint32_t>& components1,
+ const std::vector<uint32_t>& components2) {
const size_t count = std::min(components1.size(), components2.size());
for (size_t i = 0; i < count; ++i) {
if (components1[i] > components2[i])
@@ -86,7 +84,7 @@ Version::~Version() {
}
Version::Version(const std::string& version_str) {
- std::vector<uint16> parsed;
+ std::vector<uint32_t> parsed;
if (!ParseVersionNumbers(version_str, &parsed))
return;
@@ -125,7 +123,7 @@ int Version::CompareToWildcardString(const std::string& wildcard_string) const {
return CompareTo(version);
}
- std::vector<uint16> parsed;
+ std::vector<uint32_t> parsed;
const bool success = ParseVersionNumbers(
wildcard_string.substr(0, wildcard_string.length() - 2), &parsed);
DCHECK(success);
diff --git a/chromium/base/version.h b/chromium/base/version.h
index b3012eb921b..814acaa2b4e 100644
--- a/chromium/base/version.h
+++ b/chromium/base/version.h
@@ -5,6 +5,7 @@
#ifndef BASE_VERSION_H_
#define BASE_VERSION_H_
+#include <stdint.h>
#include <string>
#include <vector>
@@ -57,10 +58,10 @@ class BASE_EXPORT Version {
// Return the string representation of this version.
const std::string GetString() const;
- const std::vector<uint16>& components() const { return components_; }
+ const std::vector<uint32_t>& components() const { return components_; }
private:
- std::vector<uint16> components_;
+ std::vector<uint32_t> components_;
};
} // namespace base
diff --git a/chromium/base/version_unittest.cc b/chromium/base/version_unittest.cc
index 3119c3972a7..f40ed27d881 100644
--- a/chromium/base/version_unittest.cc
+++ b/chromium/base/version_unittest.cc
@@ -31,33 +31,44 @@ TEST(VersionTest, GetVersionFromString) {
static const struct version_string {
const char* input;
size_t parts;
+ uint32_t firstpart;
bool success;
} cases[] = {
- {"", 0, false},
- {" ", 0, false},
- {"\t", 0, false},
- {"\n", 0, false},
- {" ", 0, false},
- {".", 0, false},
- {" . ", 0, false},
- {"0", 1, true},
- {"0.0", 2, true},
- {"65537.0", 0, false},
- {"-1.0", 0, false},
- {"1.-1.0", 0, false},
- {"+1.0", 0, false},
- {"1.+1.0", 0, false},
- {"1.0a", 0, false},
- {"1.2.3.4.5.6.7.8.9.0", 10, true},
- {"02.1", 0, false},
- {"f.1", 0, false},
+ {"", 0, 0, false},
+ {" ", 0, 0, false},
+ {"\t", 0, 0, false},
+ {"\n", 0, 0, false},
+ {" ", 0, 0, false},
+ {".", 0, 0, false},
+ {" . ", 0, 0, false},
+ {"0", 1, 0, true},
+ {"0.", 0, 0, false},
+ {"0.0", 2, 0, true},
+ {"4294967295.0", 2, 4294967295, true},
+ {"4294967296.0", 0, 0, false},
+ {"-1.0", 0, 0, false},
+ {"1.-1.0", 0, 0, false},
+ {"1,--1.0", 0, 0, false},
+ {"+1.0", 0, 0, false},
+ {"1.+1.0", 0, 0, false},
+ {"1+1.0", 0, 0, false},
+ {"++1.0", 0, 0, false},
+ {"1.0a", 0, 0, false},
+ {"1.2.3.4.5.6.7.8.9.0", 10, 1, true},
+ {"02.1", 0, 0, false},
+ {"0.01", 2, 0, true},
+ {"f.1", 0, 0, false},
+ {"15.007.20011", 3, 15, true},
+ {"15.5.28.130162", 4, 15, true},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
Version version(cases[i].input);
EXPECT_EQ(cases[i].success, version.IsValid());
- if (cases[i].success)
+ if (cases[i].success) {
EXPECT_EQ(cases[i].parts, version.components().size());
+ EXPECT_EQ(cases[i].firstpart, version.components()[0]);
+ }
}
}
@@ -77,6 +88,8 @@ TEST(VersionTest, Compare) {
{"1.1", "1.0.1", 1},
{"1.0.0", "1.0", 0},
{"1.0.3", "1.0.20", -1},
+ {"11.0.10", "15.007.20011", -1},
+ {"11.0.10", "15.5.28.130162", -1},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
Version lhs(cases[i].lhs);
diff --git a/chromium/base/vlog.cc b/chromium/base/vlog.cc
index 434a70e0917..519ceff10c0 100644
--- a/chromium/base/vlog.cc
+++ b/chromium/base/vlog.cc
@@ -50,7 +50,6 @@ VlogInfo::VlogInfo(const std::string& v_switch,
: min_log_level_(min_log_level) {
DCHECK(min_log_level != NULL);
- typedef std::pair<std::string, std::string> KVPair;
int vlog_level = 0;
if (!v_switch.empty()) {
if (base::StringToInt(v_switch, &vlog_level)) {
@@ -60,13 +59,13 @@ VlogInfo::VlogInfo(const std::string& v_switch,
}
}
- std::vector<KVPair> kv_pairs;
+ base::StringPairs kv_pairs;
if (!base::SplitStringIntoKeyValuePairs(
vmodule_switch, '=', ',', &kv_pairs)) {
DLOG(WARNING) << "Could not fully parse vmodule switch \""
<< vmodule_switch << "\"";
}
- for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
+ for (base::StringPairs::const_iterator it = kv_pairs.begin();
it != kv_pairs.end(); ++it) {
VmodulePattern pattern(it->first);
if (!base::StringToInt(it->second, &pattern.vlog_level)) {
@@ -178,4 +177,4 @@ bool MatchVlogPattern(const base::StringPiece& string,
return false;
}
-} // namespace
+} // namespace logging
diff --git a/chromium/base/win/enum_variant.h b/chromium/base/win/enum_variant.h
index d978eaa7dda..2caaccded9f 100644
--- a/chromium/base/win/enum_variant.h
+++ b/chromium/base/win/enum_variant.h
@@ -39,7 +39,7 @@ class BASE_EXPORT EnumVariant
STDMETHODIMP Clone(IEnumVARIANT** out_cloned_object) override;
private:
- ~EnumVariant();
+ ~EnumVariant() override;
scoped_ptr<VARIANT[]> items_;
unsigned long count_;
diff --git a/chromium/base/win/event_trace_consumer.h b/chromium/base/win/event_trace_consumer.h
index 9322e1e9b4f..fd44894993f 100644
--- a/chromium/base/win/event_trace_consumer.h
+++ b/chromium/base/win/event_trace_consumer.h
@@ -119,7 +119,7 @@ HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
template <class ImplClass> inline
HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
ULONG err = ::ProcessTrace(&trace_handles_[0],
- trace_handles_.size(),
+ static_cast<ULONG>(trace_handles_.size()),
NULL,
NULL);
return HRESULT_FROM_WIN32(err);
diff --git a/chromium/base/win/event_trace_consumer_unittest.cc b/chromium/base/win/event_trace_consumer_unittest.cc
index 3043152af0c..ecbf238bea4 100644
--- a/chromium/base/win/event_trace_consumer_unittest.cc
+++ b/chromium/base/win/event_trace_consumer_unittest.cc
@@ -82,7 +82,7 @@ class EtwTraceConsumerBaseTest: public testing::Test {
: session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
}
- virtual void SetUp() {
+ void SetUp() override {
// Cleanup any potentially dangling sessions.
EtwTraceProperties ignore;
EtwTraceController::Stop(session_name_.c_str(), &ignore);
@@ -91,7 +91,7 @@ class EtwTraceConsumerBaseTest: public testing::Test {
ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
}
- virtual void TearDown() {
+ void TearDown() override {
// Cleanup any potentially dangling sessions.
EtwTraceProperties ignore;
EtwTraceController::Stop(session_name_.c_str(), &ignore);
@@ -125,13 +125,13 @@ namespace {
class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
public:
- virtual void SetUp() {
+ void SetUp() override {
EtwTraceConsumerBaseTest::SetUp();
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
}
- virtual void TearDown() {
+ void TearDown() override {
consumer_.Close();
EtwTraceConsumerBaseTest::TearDown();
}
@@ -261,7 +261,7 @@ class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
EtwTraceConsumerDataTest() {
}
- virtual void SetUp() {
+ void SetUp() override {
EtwTraceConsumerBaseTest::SetUp();
EtwTraceProperties prop;
@@ -273,7 +273,7 @@ class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
temp_file_ = temp_dir_.path().Append(L"test.etl");
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_TRUE(base::DeleteFile(temp_file_, false));
EtwTraceConsumerBaseTest::TearDown();
diff --git a/chromium/base/win/event_trace_controller_unittest.cc b/chromium/base/win/event_trace_controller_unittest.cc
index be11128d009..a2cd81cf709 100644
--- a/chromium/base/win/event_trace_controller_unittest.cc
+++ b/chromium/base/win/event_trace_controller_unittest.cc
@@ -42,12 +42,8 @@ class TestingProvider: public EtwTraceProvider {
}
private:
- virtual void OnEventsEnabled() {
- ::SetEvent(callback_event_.Get());
- }
- virtual void PostEventsDisabled() {
- ::SetEvent(callback_event_.Get());
- }
+ void OnEventsEnabled() override { ::SetEvent(callback_event_.Get()); }
+ void PostEventsDisabled() override { ::SetEvent(callback_event_.Get()); }
ScopedHandle callback_event_;
@@ -113,7 +109,7 @@ class EtwTraceControllerTest : public testing::Test {
: session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
}
- virtual void SetUp() {
+ void SetUp() override {
EtwTraceProperties ignore;
EtwTraceController::Stop(session_name_.c_str(), &ignore);
@@ -121,7 +117,7 @@ class EtwTraceControllerTest : public testing::Test {
ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
}
- virtual void TearDown() {
+ void TearDown() override {
EtwTraceProperties prop;
EtwTraceController::Stop(session_name_.c_str(), &prop);
}
diff --git a/chromium/base/win/iunknown_impl.h b/chromium/base/win/iunknown_impl.h
index 4283d020c43..b7de205ac6c 100644
--- a/chromium/base/win/iunknown_impl.h
+++ b/chromium/base/win/iunknown_impl.h
@@ -19,11 +19,11 @@ class BASE_EXPORT IUnknownImpl : public IUnknown {
public:
IUnknownImpl();
- virtual ULONG STDMETHODCALLTYPE AddRef() override;
- virtual ULONG STDMETHODCALLTYPE Release() override;
+ ULONG STDMETHODCALLTYPE AddRef() override;
+ ULONG STDMETHODCALLTYPE Release() override;
// Subclasses should extend this to return any interfaces they provide.
- virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
protected:
virtual ~IUnknownImpl();
diff --git a/chromium/base/win/iunknown_impl_unittest.cc b/chromium/base/win/iunknown_impl_unittest.cc
index db86214daf5..874a43a39a9 100644
--- a/chromium/base/win/iunknown_impl_unittest.cc
+++ b/chromium/base/win/iunknown_impl_unittest.cc
@@ -15,9 +15,7 @@ class TestIUnknownImplSubclass : public IUnknownImpl {
TestIUnknownImplSubclass() {
++instance_count;
}
- virtual ~TestIUnknownImplSubclass() {
- --instance_count;
- }
+ ~TestIUnknownImplSubclass() override { --instance_count; }
static int instance_count;
};
diff --git a/chromium/base/win/memory_pressure_monitor.cc b/chromium/base/win/memory_pressure_monitor.cc
new file mode 100644
index 00000000000..ed49a40a816
--- /dev/null
+++ b/chromium/base/win/memory_pressure_monitor.cc
@@ -0,0 +1,254 @@
+// Copyright 2015 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/win/memory_pressure_monitor.h"
+
+#include <windows.h>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const DWORDLONG kMBBytes = 1024 * 1024;
+
+// Enumeration of UMA memory pressure levels. This needs to be kept in sync with
+// histograms.xml and the memory pressure levels defined in
+// MemoryPressureListener.
+enum MemoryPressureLevelUMA {
+ UMA_MEMORY_PRESSURE_LEVEL_NONE = 0,
+ UMA_MEMORY_PRESSURE_LEVEL_MODERATE = 1,
+ UMA_MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
+ // This must be the last value in the enum.
+ UMA_MEMORY_PRESSURE_LEVEL_COUNT,
+};
+
+// Converts a memory pressure level to an UMA enumeration value.
+MemoryPressureLevelUMA MemoryPressureLevelToUmaEnumValue(
+ MemoryPressureListener::MemoryPressureLevel level) {
+ switch (level) {
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ return UMA_MEMORY_PRESSURE_LEVEL_NONE;
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ return UMA_MEMORY_PRESSURE_LEVEL_MODERATE;
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ return UMA_MEMORY_PRESSURE_LEVEL_CRITICAL;
+ }
+ NOTREACHED();
+ return UMA_MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+} // namespace
+
+// The following constants have been lifted from similar values in the ChromeOS
+// memory pressure monitor. The values were determined experimentally to ensure
+// sufficient responsiveness of the memory pressure subsystem, and minimal
+// overhead.
+const int MemoryPressureMonitor::kPollingIntervalMs = 5000;
+const int MemoryPressureMonitor::kModeratePressureCooldownMs = 10000;
+const int MemoryPressureMonitor::kModeratePressureCooldownCycles =
+ kModeratePressureCooldownMs / kPollingIntervalMs;
+
+// TODO(chrisha): Explore the following constants further with an experiment.
+
+// A system is considered 'high memory' if it has more than 1.5GB of system
+// memory available for use by the memory manager (not reserved for hardware
+// and drivers). This is a fuzzy version of the ~2GB discussed below.
+const int MemoryPressureMonitor::kLargeMemoryThresholdMb = 1536;
+
+// These are the default thresholds used for systems with < ~2GB of physical
+// memory. Such systems have been observed to always maintain ~100MB of
+// available memory, paging until that is the case. To try to avoid paging a
+// threshold slightly above this is chosen. The moderate threshold is slightly
+// less grounded in reality and chosen as 2.5x critical.
+const int MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb = 500;
+const int MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb = 200;
+
+// These are the default thresholds used for systems with >= ~2GB of physical
+// memory. Such systems have been observed to always maintain ~300MB of
+// available memory, paging until that is the case.
+const int MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb = 1000;
+const int MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb = 400;
+
+MemoryPressureMonitor::MemoryPressureMonitor()
+ : moderate_threshold_mb_(0),
+ critical_threshold_mb_(0),
+ current_memory_pressure_level_(
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+ moderate_pressure_repeat_count_(0),
+ weak_ptr_factory_(this) {
+ InferThresholds();
+ StartObserving();
+}
+
+MemoryPressureMonitor::MemoryPressureMonitor(int moderate_threshold_mb,
+ int critical_threshold_mb)
+ : moderate_threshold_mb_(moderate_threshold_mb),
+ critical_threshold_mb_(critical_threshold_mb),
+ current_memory_pressure_level_(
+ MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+ moderate_pressure_repeat_count_(0),
+ weak_ptr_factory_(this) {
+ DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
+ DCHECK_LE(0, critical_threshold_mb_);
+ StartObserving();
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+ StopObserving();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureSoon() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+ return current_memory_pressure_level_;
+}
+
+void MemoryPressureMonitor::InferThresholds() {
+ // Default to a 'high' memory situation, which uses more conservative
+ // thresholds.
+ bool high_memory = true;
+ MEMORYSTATUSEX mem_status = {};
+ if (GetSystemMemoryStatus(&mem_status)) {
+ static const DWORDLONG kLargeMemoryThresholdBytes =
+ static_cast<DWORDLONG>(kLargeMemoryThresholdMb) * kMBBytes;
+ high_memory = mem_status.ullTotalPhys >= kLargeMemoryThresholdBytes;
+ }
+
+ if (high_memory) {
+ moderate_threshold_mb_ = kLargeMemoryDefaultModerateThresholdMb;
+ critical_threshold_mb_ = kLargeMemoryDefaultCriticalThresholdMb;
+ } else {
+ moderate_threshold_mb_ = kSmallMemoryDefaultModerateThresholdMb;
+ critical_threshold_mb_ = kSmallMemoryDefaultCriticalThresholdMb;
+ }
+}
+
+void MemoryPressureMonitor::StartObserving() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ timer_.Start(FROM_HERE,
+ TimeDelta::FromMilliseconds(kPollingIntervalMs),
+ Bind(&MemoryPressureMonitor::
+ CheckMemoryPressureAndRecordStatistics,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MemoryPressureMonitor::StopObserving() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // If StartObserving failed, StopObserving will still get called.
+ timer_.Stop();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressure() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Get the previous pressure level and update the current one.
+ MemoryPressureLevel old_pressure = current_memory_pressure_level_;
+ current_memory_pressure_level_ = CalculateCurrentPressureLevel();
+
+ // |notify| will be set to true if MemoryPressureListeners need to be
+ // notified of a memory pressure level state change.
+ bool notify = false;
+ switch (current_memory_pressure_level_) {
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ break;
+
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ if (old_pressure != current_memory_pressure_level_) {
+ // This is a new transition to moderate pressure so notify.
+ moderate_pressure_repeat_count_ = 0;
+ notify = true;
+ } else {
+ // Already in moderate pressure, only notify if sustained over the
+ // cooldown period.
+ if (++moderate_pressure_repeat_count_ ==
+ kModeratePressureCooldownCycles) {
+ moderate_pressure_repeat_count_ = 0;
+ notify = true;
+ }
+ }
+ break;
+
+ case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ // Always notify of critical pressure levels.
+ notify = true;
+ break;
+ }
+
+ if (!notify)
+ return;
+
+ // Emit a notification of the current memory pressure level. This can only
+ // happen for moderate and critical pressure levels.
+ DCHECK_NE(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ current_memory_pressure_level_);
+ MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ CheckMemoryPressure();
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "Memory.PressureLevel",
+ MemoryPressureLevelToUmaEnumValue(current_memory_pressure_level_),
+ UMA_MEMORY_PRESSURE_LEVEL_COUNT);
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::CalculateCurrentPressureLevel() {
+ MEMORYSTATUSEX mem_status = {};
+ if (!GetSystemMemoryStatus(&mem_status))
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+ // How much system memory is actively available for use right now, in MBs.
+ int phys_free = static_cast<int>(mem_status.ullAvailPhys / kMBBytes);
+
+ // TODO(chrisha): This should eventually care about address space pressure,
+ // but the browser process (where this is running) effectively never runs out
+ // of address space. Renderers occasionally do, but it does them no good to
+ // have the browser process monitor address space pressure. Long term,
+ // renderers should run their own address space pressure monitors and act
+ // accordingly, with the browser making cross-process decisions based on
+ // system memory pressure.
+
+ // Determine if the physical memory is under critical memory pressure.
+ if (phys_free <= critical_threshold_mb_)
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+
+ // Determine if the physical memory is under moderate memory pressure.
+ if (phys_free <= moderate_threshold_mb_)
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+
+ // No memory pressure was detected.
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+bool MemoryPressureMonitor::GetSystemMemoryStatus(
+ MEMORYSTATUSEX* mem_status) {
+ DCHECK(mem_status != nullptr);
+ mem_status->dwLength = sizeof(*mem_status);
+ if (!::GlobalMemoryStatusEx(mem_status))
+ return false;
+ return true;
+}
+
+} // namespace win
+} // namespace base
diff --git a/chromium/base/win/memory_pressure_monitor.h b/chromium/base/win/memory_pressure_monitor.h
new file mode 100644
index 00000000000..933d91290f1
--- /dev/null
+++ b/chromium/base/win/memory_pressure_monitor.h
@@ -0,0 +1,144 @@
+// Copyright 2015 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_WIN_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_WIN_MEMORY_PRESSURE_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+
+// To not pull in windows.h.
+typedef struct _MEMORYSTATUSEX MEMORYSTATUSEX;
+
+namespace base {
+namespace win {
+
+// Windows memory pressure monitor. Because there is no OS provided signal this
+// polls at a low frequency (once per second), and applies internal hysteresis.
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+ // Constants governing the polling and hysteresis behaviour of the observer.
+
+ // The polling interval, in milliseconds. While under critical pressure, this
+ // is also the timer to repeat cleanup attempts.
+ static const int kPollingIntervalMs;
+ // The time which should pass between 2 successive moderate memory pressure
+ // signals, in milliseconds.
+ static const int kModeratePressureCooldownMs;
+ // The number of cycles that should pass between 2 successive moderate memory
+ // pressure signals.
+ static const int kModeratePressureCooldownCycles;
+
+ // Constants governing the memory pressure level detection.
+
+ // The amount of total system memory beyond which a system is considered to be
+ // a large-memory system.
+ static const int kLargeMemoryThresholdMb;
+ // Default minimum free memory thresholds for small-memory systems, in MB.
+ static const int kSmallMemoryDefaultModerateThresholdMb;
+ static const int kSmallMemoryDefaultCriticalThresholdMb;
+ // Default minimum free memory thresholds for large-memory systems, in MB.
+ static const int kLargeMemoryDefaultModerateThresholdMb;
+ static const int kLargeMemoryDefaultCriticalThresholdMb;
+
+ // Default constructor. Will choose thresholds automatically basd on the
+ // actual amount of system memory.
+ MemoryPressureMonitor();
+
+ // Constructor with explicit memory thresholds. These represent the amount of
+ // free memory below which the applicable memory pressure state engages.
+ MemoryPressureMonitor(int moderate_threshold_mb, int critical_threshold_mb);
+
+ ~MemoryPressureMonitor() override;
+
+ // Schedules a memory pressure check to run soon. This must be called on the
+ // same thread where the monitor was instantiated.
+ void CheckMemoryPressureSoon();
+
+ // Get the current memory pressure level. This can be called from any thread.
+ MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+ // Returns the moderate pressure level free memory threshold, in MB.
+ int moderate_threshold_mb() const { return moderate_threshold_mb_; }
+
+ // Returns the critical pressure level free memory threshold, in MB.
+ int critical_threshold_mb() const { return critical_threshold_mb_; }
+
+ protected:
+ // Internals are exposed for unittests.
+
+ // Automatically infers threshold values based on system memory. This invokes
+ // GetMemoryStatus so it can be mocked in unittests.
+ void InferThresholds();
+
+ // Starts observing the memory fill level. Calls to StartObserving should
+ // always be matched with calls to StopObserving.
+ void StartObserving();
+
+ // Stop observing the memory fill level. May be safely called if
+ // StartObserving has not been called. Must be called from the same thread on
+ // which the monitor was instantiated.
+ void StopObserving();
+
+ // Checks memory pressure, storing the current level, applying any hysteresis
+ // and emitting memory pressure level change signals as necessary. This
+ // function is called periodically while the monitor is observing memory
+ // pressure. This is split out from CheckMemoryPressureAndRecordStatistics so
+ // that it may be called by CheckMemoryPressureSoon and not invoke UMA
+ // logging. Must be called from the same thread on which the monitor was
+ // instantiated.
+ void CheckMemoryPressure();
+
+ // Wrapper to CheckMemoryPressure that also records the observed memory
+ // pressure level via an UMA enumeration. This is the function that is called
+ // periodically by the timer. Must be called from the same thread on which the
+ // monitor was instantiated.
+ void CheckMemoryPressureAndRecordStatistics();
+
+ // Calculates the current instantaneous memory pressure level. This does not
+ // use any hysteresis and simply returns the result at the current moment. Can
+ // be called on any thread.
+ MemoryPressureLevel CalculateCurrentPressureLevel();
+
+ // Gets system memory status. This is virtual as a unittesting hook. Returns
+ // true if the system call succeeds, false otherwise. Can be called on any
+ // thread.
+ virtual bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status);
+
+ private:
+ // Threshold amounts of available memory that trigger pressure levels. See
+ // memory_pressure_monitor.cc for a discussion of reasonable values for these.
+ int moderate_threshold_mb_;
+ int critical_threshold_mb_;
+
+ // A periodic timer to check for memory pressure changes.
+ base::RepeatingTimer<MemoryPressureMonitor> timer_;
+
+ // The current memory pressure.
+ MemoryPressureLevel current_memory_pressure_level_;
+
+ // To slow down the amount of moderate pressure event calls, this gets used to
+ // count the number of events since the last event occured. This is used by
+ // |CheckMemoryPressure| to apply hysteresis on the raw results of
+ // |CalculateCurrentPressureLevel|.
+ int moderate_pressure_repeat_count_;
+
+ // Ensures that this object is used from a single thread.
+ base::ThreadChecker thread_checker_;
+
+ // Weak pointer factory to ourself used for scheduling calls to
+ // CheckMemoryPressure/CheckMemoryPressureAndRecordStatistics via |timer_|.
+ base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_MEMORY_PRESSURE_MONITOR_H_
diff --git a/chromium/base/win/memory_pressure_monitor_unittest.cc b/chromium/base/win/memory_pressure_monitor_unittest.cc
new file mode 100644
index 00000000000..40a25a79dd8
--- /dev/null
+++ b/chromium/base/win/memory_pressure_monitor_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2015 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/win/memory_pressure_monitor.h"
+
+#include "base/basictypes.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct PressureSettings {
+ int phys_left_mb;
+ MemoryPressureListener::MemoryPressureLevel level;
+};
+
+} // namespace
+
+// This is outside of the anonymous namespace so that it can be seen as a friend
+// to the monitor class.
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+ using MemoryPressureMonitor::CalculateCurrentPressureLevel;
+ using MemoryPressureMonitor::CheckMemoryPressure;
+
+ static const DWORDLONG kMBBytes = 1024 * 1024;
+
+ explicit TestMemoryPressureMonitor(bool large_memory)
+ : mem_status_() {
+ // Generate a plausible amount of memory.
+ mem_status_.ullTotalPhys =
+ static_cast<DWORDLONG>(GenerateTotalMemoryMb(large_memory)) * kMBBytes;
+
+ // Rerun InferThresholds using the test fixture's GetSystemMemoryStatus.
+ InferThresholds();
+ // Stop the timer.
+ StopObserving();
+ }
+
+ TestMemoryPressureMonitor(int system_memory_mb,
+ int moderate_threshold_mb,
+ int critical_threshold_mb)
+ : MemoryPressureMonitor(moderate_threshold_mb, critical_threshold_mb),
+ mem_status_() {
+ // Set the amount of system memory.
+ mem_status_.ullTotalPhys = static_cast<DWORDLONG>(
+ system_memory_mb * kMBBytes);
+
+ // Stop the timer.
+ StopObserving();
+ }
+
+ virtual ~TestMemoryPressureMonitor() {}
+
+ MOCK_METHOD1(OnMemoryPressure,
+ void(MemoryPressureListener::MemoryPressureLevel level));
+
+ // Generates an amount of total memory that is consistent with the requested
+ // memory model.
+ int GenerateTotalMemoryMb(bool large_memory) {
+ int total_mb = 64;
+ while (total_mb < MemoryPressureMonitor::kLargeMemoryThresholdMb)
+ total_mb *= 2;
+ if (large_memory)
+ return total_mb * 2;
+ return total_mb / 2;
+ }
+
+ // Sets up the memory status to reflect the provided absolute memory left.
+ void SetMemoryFree(int phys_left_mb) {
+ // ullTotalPhys is set in the constructor and not modified.
+
+ // Set the amount of available memory.
+ mem_status_.ullAvailPhys =
+ static_cast<DWORDLONG>(phys_left_mb) * kMBBytes;
+ DCHECK_LT(mem_status_.ullAvailPhys, mem_status_.ullTotalPhys);
+
+ // These fields are unused.
+ mem_status_.dwMemoryLoad = 0;
+ mem_status_.ullTotalPageFile = 0;
+ mem_status_.ullAvailPageFile = 0;
+ mem_status_.ullTotalVirtual = 0;
+ mem_status_.ullAvailVirtual = 0;
+ }
+
+ void SetNone() {
+ SetMemoryFree(moderate_threshold_mb() + 1);
+ }
+
+ void SetModerate() {
+ SetMemoryFree(moderate_threshold_mb() - 1);
+ }
+
+ void SetCritical() {
+ SetMemoryFree(critical_threshold_mb() - 1);
+ }
+
+ private:
+ bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status) override {
+ // Simply copy the memory status set by the test fixture.
+ *mem_status = mem_status_;
+ return true;
+ }
+
+ MEMORYSTATUSEX mem_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+class WinMemoryPressureMonitorTest : public testing::Test {
+ protected:
+ void CalculateCurrentMemoryPressureLevelTest(
+ TestMemoryPressureMonitor* monitor) {
+
+ int mod = monitor->moderate_threshold_mb();
+ monitor->SetMemoryFree(mod + 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(mod);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(mod - 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->CalculateCurrentPressureLevel());
+
+ int crit = monitor->critical_threshold_mb();
+ monitor->SetMemoryFree(crit + 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(crit);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(crit - 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor->CalculateCurrentPressureLevel());
+ }
+
+ base::MessageLoopForUI message_loop_;
+};
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// small-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelSmall) {
+ static const int kModerateMb =
+ MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb;
+ static const int kCriticalMb =
+ MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb;
+
+ TestMemoryPressureMonitor monitor(false); // Small-memory model.
+
+ EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+ EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+ ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// large-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLarge) {
+ static const int kModerateMb =
+ MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb;
+ static const int kCriticalMb =
+ MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb;
+
+ TestMemoryPressureMonitor monitor(true); // Large-memory model.
+
+ EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+ EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+ ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with manually
+// specified threshold levels.
+TEST_F(WinMemoryPressureMonitorTest,
+ CalculateCurrentMemoryPressureLevelCustom) {
+ static const int kSystemMb = 512;
+ static const int kModerateMb = 256;
+ static const int kCriticalMb = 128;
+
+ TestMemoryPressureMonitor monitor(kSystemMb, kModerateMb, kCriticalMb);
+
+ EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+ EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+ ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST_F(WinMemoryPressureMonitorTest, CheckMemoryPressure) {
+ // Large-memory.
+ testing::StrictMock<TestMemoryPressureMonitor> monitor(true);
+ MemoryPressureListener listener(
+ base::Bind(&TestMemoryPressureMonitor::OnMemoryPressure,
+ base::Unretained(&monitor)));
+
+ // Checking the memory pressure at 0% load should not produce any
+ // events.
+ monitor.SetNone();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor.GetCurrentPressureLevel());
+
+ // Setting the memory level to 80% should produce a moderate pressure level.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ monitor.SetModerate();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // Check that the event gets reposted after a while.
+ for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+ if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ }
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+ }
+
+ // Setting the memory usage to 99% should produce critical levels.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_CRITICAL));
+ monitor.SetCritical();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // Calling it again should immediately produce a second call.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_CRITICAL));
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // When lowering the pressure again there should be a notification and the
+ // pressure should go back to moderate.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ monitor.SetModerate();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // Check that the event gets reposted after a while.
+ for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+ if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ }
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+ }
+
+ // Going down to no pressure should not produce an notification.
+ monitor.SetNone();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+}
+
+} // namespace win
+} // namespace base
diff --git a/chromium/base/win/message_window.cc b/chromium/base/win/message_window.cc
index 57fe64c7981..0b4b29f5aa6 100644
--- a/chromium/base/win/message_window.cc
+++ b/chromium/base/win/message_window.cc
@@ -7,6 +7,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/win/wrapped_window_proc.h"
const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow";
@@ -120,6 +121,10 @@ LRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 MessageWindow::WindowProc"));
+
MessageWindow* self = reinterpret_cast<MessageWindow*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
diff --git a/chromium/base/win/metro.cc b/chromium/base/win/metro.cc
index 6e443ba66b6..794669803ca 100644
--- a/chromium/base/win/metro.cc
+++ b/chromium/base/win/metro.cc
@@ -4,10 +4,7 @@
#include "base/win/metro.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
-#include "base/win/scoped_comptr.h"
-#include "base/win/windows_version.h"
namespace base {
namespace win {
@@ -73,38 +70,6 @@ wchar_t* LocalAllocAndCopyString(const string16& src) {
return dest;
}
-bool IsParentalControlActivityLoggingOn() {
- // Query this info on Windows 7 and above.
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return false;
-
- static bool parental_control_logging_required = false;
- static bool parental_control_status_determined = false;
-
- if (parental_control_status_determined)
- return parental_control_logging_required;
-
- parental_control_status_determined = true;
-
- ScopedComPtr<IWindowsParentalControlsCore> parent_controls;
- HRESULT hr = parent_controls.CreateInstance(
- __uuidof(WindowsParentalControls));
- if (FAILED(hr))
- return false;
-
- ScopedComPtr<IWPCSettings> settings;
- hr = parent_controls->GetUserSettings(NULL, settings.Receive());
- if (FAILED(hr))
- return false;
-
- unsigned long restrictions = 0;
- settings->GetRestrictions(&restrictions);
-
- parental_control_logging_required =
- (restrictions & WPCFLAG_LOGGING_REQUIRED) == WPCFLAG_LOGGING_REQUIRED;
- return parental_control_logging_required;
-}
-
// Metro driver exports for getting the launch type, initial url, initial
// search term, etc.
extern "C" {
diff --git a/chromium/base/win/metro.h b/chromium/base/win/metro.h
index 5894ef06dae..06960067519 100644
--- a/chromium/base/win/metro.h
+++ b/chromium/base/win/metro.h
@@ -6,7 +6,6 @@
#define BASE_WIN_METRO_H_
#include <windows.h>
-#include <wpcapi.h>
#include "base/base_export.h"
#include "base/callback.h"
@@ -80,11 +79,6 @@ BASE_EXPORT bool IsProcessImmersive(HANDLE process);
// copying the src to it.
BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src);
-// Returns true if Windows Parental control activity logging is enabled. This
-// feature is available on Windows Vista and beyond.
-// This function should ideally be called on the UI thread.
-BASE_EXPORT bool IsParentalControlActivityLoggingOn();
-
// Returns the type of launch and the activation params. For example if the
// the launch is for METRO_PROTOCOL then the params is a url.
BASE_EXPORT MetroLaunchType GetMetroLaunchParams(string16* params);
diff --git a/chromium/base/win/object_watcher.cc b/chromium/base/win/object_watcher.cc
index fe209f5e338..5ebe1856d31 100644
--- a/chromium/base/win/object_watcher.cc
+++ b/chromium/base/win/object_watcher.cc
@@ -77,7 +77,11 @@ bool ObjectWatcher::StopWatching() {
return true;
}
-HANDLE ObjectWatcher::GetWatchedObject() {
+bool ObjectWatcher::IsWatching() const {
+ return object_ != NULL;
+}
+
+HANDLE ObjectWatcher::GetWatchedObject() const {
return object_;
}
@@ -88,7 +92,7 @@ void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
// The destructor blocks on any callbacks that are in flight, so we know that
// that is always a pointer to a valid ObjectWater.
ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
- that->origin_loop_->PostTask(FROM_HERE, that->callback_);
+ that->origin_loop_->task_runner()->PostTask(FROM_HERE, that->callback_);
that->callback_.Reset();
}
diff --git a/chromium/base/win/object_watcher.h b/chromium/base/win/object_watcher.h
index bf7f8b3e92c..d68d9350b38 100644
--- a/chromium/base/win/object_watcher.h
+++ b/chromium/base/win/object_watcher.h
@@ -56,7 +56,7 @@ class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
};
ObjectWatcher();
- ~ObjectWatcher();
+ ~ObjectWatcher() override;
// When the object is signaled, the given delegate is notified on the thread
// where StartWatching is called. The ObjectWatcher is not responsible for
@@ -74,9 +74,11 @@ class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
//
bool StopWatching();
- // Returns the handle of the object being watched, or NULL if the object
- // watcher is stopped.
- HANDLE GetWatchedObject();
+ // Returns true if currently watching an object.
+ bool IsWatching() const;
+
+ // Returns the handle of the object being watched.
+ HANDLE GetWatchedObject() const;
private:
// Called on a background thread when done waiting.
@@ -85,7 +87,7 @@ class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
void Signal(Delegate* delegate);
// MessageLoop::DestructionObserver implementation:
- virtual void WillDestroyCurrentMessageLoop();
+ void WillDestroyCurrentMessageLoop() override;
// Internal state.
Closure callback_;
@@ -101,4 +103,4 @@ class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
} // namespace win
} // namespace base
-#endif // BASE_OBJECT_WATCHER_H_
+#endif // BASE_WIN_OBJECT_WATCHER_H_
diff --git a/chromium/base/win/object_watcher_unittest.cc b/chromium/base/win/object_watcher_unittest.cc
index 46b98de524d..b30ca41a4fe 100644
--- a/chromium/base/win/object_watcher_unittest.cc
+++ b/chromium/base/win/object_watcher_unittest.cc
@@ -17,7 +17,7 @@ namespace {
class QuitDelegate : public ObjectWatcher::Delegate {
public:
- virtual void OnObjectSignaled(HANDLE object) {
+ void OnObjectSignaled(HANDLE object) override {
MessageLoop::current()->QuitWhenIdle();
}
};
@@ -26,9 +26,8 @@ class DecrementCountDelegate : public ObjectWatcher::Delegate {
public:
explicit DecrementCountDelegate(int* counter) : counter_(counter) {
}
- virtual void OnObjectSignaled(HANDLE object) {
- --(*counter_);
- }
+ void OnObjectSignaled(HANDLE object) override { --(*counter_); }
+
private:
int* counter_;
};
@@ -37,7 +36,7 @@ void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
MessageLoop message_loop(message_loop_type);
ObjectWatcher watcher;
- EXPECT_EQ(NULL, watcher.GetWatchedObject());
+ EXPECT_FALSE(watcher.IsWatching());
// A manual-reset event that is not yet signaled.
HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -45,13 +44,14 @@ void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
QuitDelegate delegate;
bool ok = watcher.StartWatching(event, &delegate);
EXPECT_TRUE(ok);
+ EXPECT_TRUE(watcher.IsWatching());
EXPECT_EQ(event, watcher.GetWatchedObject());
SetEvent(event);
MessageLoop::current()->Run();
- EXPECT_EQ(NULL, watcher.GetWatchedObject());
+ EXPECT_FALSE(watcher.IsWatching());
CloseHandle(event);
}
@@ -115,7 +115,7 @@ void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) {
MessageLoop::current()->Run();
- EXPECT_EQ(NULL, watcher.GetWatchedObject());
+ EXPECT_FALSE(watcher.IsWatching());
CloseHandle(event);
}
diff --git a/chromium/base/win/pe_image.cc b/chromium/base/win/pe_image.cc
index db28699b734..692b7b66507 100644
--- a/chromium/base/win/pe_image.cc
+++ b/chromium/base/win/pe_image.cc
@@ -10,14 +10,7 @@
namespace base {
namespace win {
-#if defined(_WIN64) && !defined(NACL_WIN64)
-// TODO(jschuh): crbug.com/167707 Make sure this is ok.
-#pragma message ("Warning: \
- This code is not tested on x64. Please make sure all the base unit tests\
- pass before doing any real work. The current unit tests don't test the\
- differences between 32- and 64-bits implementations. Bugs may slip through.\
- You need to improve the coverage before continuing.")
-#endif
+// TODO(jschuh): crbug.com/167707 Make sure this code works on 64-bit.
// Structure to perform imports enumerations.
struct EnumAllImportsStorage {
@@ -27,6 +20,9 @@ struct EnumAllImportsStorage {
namespace {
+ // PdbInfo Signature
+ const DWORD kPdbInfoSignature = 'SDSR';
+
// Compare two strings byte by byte on an unsigned basis.
// if s1 == s2, return 0
// if s1 < s2, return negative
@@ -42,6 +38,12 @@ namespace {
*reinterpret_cast<const unsigned char*>(s2));
}
+ struct PdbInfo {
+ DWORD Signature;
+ GUID Guid;
+ DWORD Age;
+ char PdbFileName[1];
+ };
} // namespace
// Callback used to enumerate imports. See EnumImportChunksFunction.
@@ -149,6 +151,36 @@ PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
return ret;
}
+bool PEImage::GetDebugId(LPGUID guid, LPDWORD age) const {
+ if (NULL == guid || NULL == age) {
+ return false;
+ }
+
+ DWORD debug_directory_size =
+ GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
+ PIMAGE_DEBUG_DIRECTORY debug_directory =
+ reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
+
+ size_t directory_count =
+ debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
+
+ for (size_t index = 0; index < directory_count; ++index) {
+ if (debug_directory[index].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
+ PdbInfo* pdb_info = reinterpret_cast<PdbInfo*>(
+ RVAToAddr(debug_directory[index].AddressOfRawData));
+ if (pdb_info->Signature != kPdbInfoSignature) {
+ // Unsupported PdbInfo signature
+ return false;
+ }
+ *guid = pdb_info->Guid;
+ *age = pdb_info->Age;
+ return true;
+ }
+ }
+ return false;
+}
+
PDWORD PEImage::GetExportEntry(LPCSTR name) const {
PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
@@ -536,14 +568,11 @@ bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
if (NULL == section_header)
return false;
-#pragma warning(push)
-#pragma warning(disable: 4311)
- // These casts generate warnings because they are 32 bit specific.
// Don't follow the virtual RVAToAddr, use the one on the base.
- DWORD offset_within_section = reinterpret_cast<DWORD>(address) -
- reinterpret_cast<DWORD>(PEImage::RVAToAddr(
- section_header->VirtualAddress));
-#pragma warning(pop)
+ DWORD offset_within_section =
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(
+ PEImage::RVAToAddr(section_header->VirtualAddress)));
*on_disk_offset = section_header->PointerToRawData + offset_within_section;
return true;
diff --git a/chromium/base/win/pe_image.h b/chromium/base/win/pe_image.h
index d93e99dc143..343d2866436 100644
--- a/chromium/base/win/pe_image.h
+++ b/chromium/base/win/pe_image.h
@@ -132,6 +132,9 @@ class PEImage {
// Returns the exports directory.
PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
+ // Returns the debug id (guid+age).
+ bool GetDebugId(LPGUID guid, LPDWORD age) const;
+
// Returns a given export entry.
// Use: e = image.GetExportEntry(f);
// Pre: 'f' is either a zero terminated string or ordinal
@@ -235,19 +238,15 @@ class PEImageAsData : public PEImage {
public:
explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
- virtual PVOID RVAToAddr(DWORD rva) const;
+ PVOID RVAToAddr(DWORD rva) const override;
};
inline bool PEImage::IsOrdinal(LPCSTR name) {
-#pragma warning(push)
-#pragma warning(disable: 4311)
- // This cast generates a warning because it is 32 bit specific.
- return reinterpret_cast<DWORD>(name) <= 0xFFFF;
-#pragma warning(pop)
+ return reinterpret_cast<uintptr_t>(name) <= 0xFFFF;
}
inline WORD PEImage::ToOrdinal(LPCSTR name) {
- return reinterpret_cast<WORD>(name);
+ return static_cast<WORD>(reinterpret_cast<intptr_t>(name));
}
inline HMODULE PEImage::module() const {
diff --git a/chromium/base/win/pe_image_test.cc b/chromium/base/win/pe_image_test.cc
new file mode 100644
index 00000000000..e374598ada7
--- /dev/null
+++ b/chromium/base/win/pe_image_test.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 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 <cfgmgr32.h>
+#include <shellapi.h>
+
+extern "C" {
+
+__declspec(dllexport) void ExportFunc1() {
+ // Call into user32.dll.
+ HWND dummy = GetDesktopWindow();
+ SetWindowTextA(dummy, "dummy");
+}
+
+__declspec(dllexport) void ExportFunc2() {
+ // Call into cfgmgr32.dll.
+ CM_MapCrToWin32Err(CR_SUCCESS, ERROR_SUCCESS);
+
+ // Call into shell32.dll.
+ SHFILEOPSTRUCT file_operation = {0};
+ SHFileOperation(&file_operation);
+
+ // Call into kernel32.dll.
+ HANDLE h = CreateEvent(NULL, FALSE, FALSE, NULL);
+ CloseHandle(h);
+}
+
+} // extern "C"
diff --git a/chromium/base/win/pe_image_unittest.cc b/chromium/base/win/pe_image_unittest.cc
index 238c924f62c..28b65a4e0ba 100644
--- a/chromium/base/win/pe_image_unittest.cc
+++ b/chromium/base/win/pe_image_unittest.cc
@@ -3,29 +3,21 @@
// found in the LICENSE file.
// This file contains unit tests for PEImage.
+#include <algorithm>
+#include <vector>
-#include "testing/gtest/include/gtest/gtest.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
#include "base/win/pe_image.h"
-#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace win {
-// Just counts the number of invocations.
-bool ExportsCallback(const PEImage &image,
- DWORD ordinal,
- DWORD hint,
- LPCSTR name,
- PVOID function,
- LPCSTR forward,
- PVOID cookie) {
- int* count = reinterpret_cast<int*>(cookie);
- (*count)++;
- return true;
-}
+namespace {
// Just counts the number of invocations.
-bool ImportsCallback(const PEImage &image,
+bool ImportsCallback(const PEImage& image,
LPCSTR module,
DWORD ordinal,
LPCSTR name,
@@ -38,18 +30,18 @@ bool ImportsCallback(const PEImage &image,
}
// Just counts the number of invocations.
-bool SectionsCallback(const PEImage &image,
- PIMAGE_SECTION_HEADER header,
- PVOID section_start,
- DWORD section_size,
- PVOID cookie) {
+bool SectionsCallback(const PEImage& image,
+ PIMAGE_SECTION_HEADER header,
+ PVOID section_start,
+ DWORD section_size,
+ PVOID cookie) {
int* count = reinterpret_cast<int*>(cookie);
(*count)++;
return true;
}
// Just counts the number of invocations.
-bool RelocsCallback(const PEImage &image,
+bool RelocsCallback(const PEImage& image,
WORD type,
PVOID address,
PVOID cookie) {
@@ -59,7 +51,7 @@ bool RelocsCallback(const PEImage &image,
}
// Just counts the number of invocations.
-bool ImportChunksCallback(const PEImage &image,
+bool ImportChunksCallback(const PEImage& image,
LPCSTR module,
PIMAGE_THUNK_DATA name_table,
PIMAGE_THUNK_DATA iat,
@@ -70,7 +62,7 @@ bool ImportChunksCallback(const PEImage &image,
}
// Just counts the number of invocations.
-bool DelayImportChunksCallback(const PEImage &image,
+bool DelayImportChunksCallback(const PEImage& image,
PImgDelayDescr delay_descriptor,
LPCSTR module,
PIMAGE_THUNK_DATA name_table,
@@ -83,167 +75,83 @@ bool DelayImportChunksCallback(const PEImage &image,
return true;
}
-// Identifiers for the set of supported expectations.
-enum ExpectationSet {
- WIN_2K_SET,
- WIN_XP_SET,
- WIN_VISTA_SET,
- WIN_7_SET,
- WIN_8_SET,
- UNSUPPORTED_SET,
-};
-
-// We'll be using some known values for the tests.
-enum Value {
- sections = 0,
- imports_dlls,
- delay_dlls,
- exports,
- imports,
- delay_imports,
- relocs
-};
-
-ExpectationSet GetExpectationSet(DWORD os) {
- if (os == 50)
- return WIN_2K_SET;
- if (os == 51)
- return WIN_XP_SET;
- if (os == 60)
- return WIN_VISTA_SET;
- if (os == 61)
- return WIN_7_SET;
- if (os >= 62)
- return WIN_8_SET;
- return UNSUPPORTED_SET;
-}
-
-// Retrieves the expected value from advapi32.dll based on the OS.
-int GetExpectedValue(Value value, DWORD os) {
- const int xp_delay_dlls = 2;
- const int xp_exports = 675;
- const int xp_imports = 422;
- const int xp_delay_imports = 8;
- const int xp_relocs = 9180;
- const int vista_delay_dlls = 4;
- const int vista_exports = 799;
- const int vista_imports = 476;
- const int vista_delay_imports = 24;
- const int vista_relocs = 10188;
- const int w2k_delay_dlls = 0;
- const int w2k_exports = 566;
- const int w2k_imports = 357;
- const int w2k_delay_imports = 0;
- const int w2k_relocs = 7388;
- const int win7_delay_dlls = 7;
- const int win7_exports = 806;
- const int win7_imports = 568;
- const int win7_delay_imports = 71;
- int win7_relocs = 7812;
- int win7_sections = 4;
- const int win8_delay_dlls = 9;
- const int win8_exports = 806;
- const int win8_imports = 568;
- const int win8_delay_imports = 113;
- const int win8_relocs = 9478;
- int win8_sections = 4;
- int win8_import_dlls = 17;
-
- base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
- // 32-bit process on a 32-bit system.
- if (os_info->architecture() == base::win::OSInfo::X86_ARCHITECTURE) {
- win8_sections = 5;
- win8_import_dlls = 19;
-
- // 64-bit process on a 64-bit system.
- } else if (os_info->wow64_status() == base::win::OSInfo::WOW64_DISABLED) {
- win7_sections = 6;
- win7_relocs = 2712;
- }
-
- // Contains the expected value, for each enumerated property (Value), and the
- // OS version: [Value][os_version]
- const int expected[][5] = {
- {4, 4, 4, win7_sections, win8_sections},
- {3, 3, 3, 13, win8_import_dlls},
- {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls,
- win8_delay_dlls},
- {w2k_exports, xp_exports, vista_exports, win7_exports, win8_exports},
- {w2k_imports, xp_imports, vista_imports, win7_imports, win8_imports},
- {w2k_delay_imports, xp_delay_imports,
- vista_delay_imports, win7_delay_imports, win8_delay_imports},
- {w2k_relocs, xp_relocs, vista_relocs, win7_relocs, win8_relocs}
- };
- COMPILE_ASSERT(arraysize(expected[0]) == UNSUPPORTED_SET,
- expected_value_set_mismatch);
-
- if (value > relocs)
- return 0;
- ExpectationSet expected_set = GetExpectationSet(os);
- if (expected_set >= arraysize(expected)) {
- // This should never happen. Log a failure if it does.
- EXPECT_NE(UNSUPPORTED_SET, expected_set);
- expected_set = WIN_2K_SET;
- }
-
- return expected[value][expected_set];
+// Just counts the number of invocations.
+bool ExportsCallback(const PEImage& image,
+ DWORD ordinal,
+ DWORD hint,
+ LPCSTR name,
+ PVOID function,
+ LPCSTR forward,
+ PVOID cookie) {
+ int* count = reinterpret_cast<int*>(cookie);
+ (*count)++;
+ return true;
}
+} // namespace
-// TODO(jschuh): crbug.com/167707 Need to fix test on Win64 bots
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
-#define MAYBE_EnumeratesPE DISABLED_EnumeratesPE
+// Tests that we are able to enumerate stuff from a PE file, and that
+// the actual number of items found matches an expected value.
+TEST(PEImageTest, EnumeratesPE) {
+ base::FilePath pe_image_test_path;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &pe_image_test_path));
+ pe_image_test_path = pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image"));
+
+#if defined(ARCH_CPU_64_BITS)
+ pe_image_test_path =
+ pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_64.dll"));
+ const int sections = 6;
+ const int imports_dlls = 2;
+ const int delay_dlls = 2;
+ const int exports = 2;
+ const int imports = 69;
+ const int delay_imports = 2;
+ const int relocs = 632;
#else
-#define MAYBE_EnumeratesPE EnumeratesPE
+ pe_image_test_path =
+ pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll"));
+ const int sections = 5;
+ const int imports_dlls = 2;
+ const int delay_dlls = 2;
+ const int exports = 2;
+ const int imports = 66;
+ const int delay_imports = 2;
+ const int relocs = 1586;
#endif
-// Tests that we are able to enumerate stuff from a PE file, and that
-// the actual number of items found is within the expected range.
-TEST(PEImageTest, MAYBE_EnumeratesPE) {
- HMODULE module = LoadLibrary(L"advapi32.dll");
+ HMODULE module = LoadLibrary(pe_image_test_path.value().c_str());
ASSERT_TRUE(NULL != module);
PEImage pe(module);
int count = 0;
EXPECT_TRUE(pe.VerifyMagic());
- DWORD os = pe.GetNTHeaders()->OptionalHeader.MajorOperatingSystemVersion;
- os = os * 10 + pe.GetNTHeaders()->OptionalHeader.MinorOperatingSystemVersion;
-
- // Skip this test for unsupported OS versions.
- if (GetExpectationSet(os) == UNSUPPORTED_SET)
- return;
-
pe.EnumSections(SectionsCallback, &count);
- EXPECT_EQ(GetExpectedValue(sections, os), count);
+ EXPECT_EQ(sections, count);
count = 0;
pe.EnumImportChunks(ImportChunksCallback, &count);
- EXPECT_EQ(GetExpectedValue(imports_dlls, os), count);
+ EXPECT_EQ(imports_dlls, count);
count = 0;
pe.EnumDelayImportChunks(DelayImportChunksCallback, &count);
- EXPECT_EQ(GetExpectedValue(delay_dlls, os), count);
+ EXPECT_EQ(delay_dlls, count);
count = 0;
pe.EnumExports(ExportsCallback, &count);
- EXPECT_GT(count, GetExpectedValue(exports, os) - 20);
- EXPECT_LT(count, GetExpectedValue(exports, os) + 100);
+ EXPECT_EQ(exports, count);
count = 0;
pe.EnumAllImports(ImportsCallback, &count);
- EXPECT_GT(count, GetExpectedValue(imports, os) - 20);
- EXPECT_LT(count, GetExpectedValue(imports, os) + 100);
+ EXPECT_EQ(imports, count);
count = 0;
pe.EnumAllDelayImports(ImportsCallback, &count);
- EXPECT_GT(count, GetExpectedValue(delay_imports, os) - 2);
- EXPECT_LT(count, GetExpectedValue(delay_imports, os) + 8);
+ EXPECT_EQ(delay_imports, count);
count = 0;
pe.EnumRelocs(RelocsCallback, &count);
- EXPECT_GT(count, GetExpectedValue(relocs, os) - 150);
- EXPECT_LT(count, GetExpectedValue(relocs, os) + 1500);
+ EXPECT_EQ(relocs, count);
FreeLibrary(module);
}
@@ -267,5 +175,21 @@ TEST(PEImageTest, RetrievesExports) {
FreeLibrary(module);
}
+// Test that we can get debug id out of a module.
+TEST(PEImageTest, GetDebugId) {
+ HMODULE module = LoadLibrary(L"advapi32.dll");
+ ASSERT_TRUE(NULL != module);
+
+ PEImage pe(module);
+ GUID guid = {0};
+ DWORD age = 0;
+ EXPECT_TRUE(pe.GetDebugId(&guid, &age));
+
+ GUID empty_guid = {0};
+ EXPECT_TRUE(!IsEqualGUID(empty_guid, guid));
+ EXPECT_NE(0U, age);
+ FreeLibrary(module);
+}
+
} // namespace win
} // namespace base
diff --git a/chromium/base/win/registry.cc b/chromium/base/win/registry.cc
index 23ad12cad64..47afcbfb77b 100644
--- a/chromium/base/win/registry.cc
+++ b/chromium/base/win/registry.cc
@@ -38,7 +38,7 @@ const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
class RegKey::Watcher : public ObjectWatcher::Delegate {
public:
explicit Watcher(RegKey* owner) : owner_(owner) {}
- ~Watcher() {}
+ ~Watcher() override {}
bool StartWatching(HKEY key, const ChangeCallback& callback);
@@ -210,7 +210,7 @@ void RegKey::Set(HKEY key) {
}
HKEY RegKey::Take() {
- DCHECK(wow64access_ == 0);
+ DCHECK_EQ(wow64access_, 0u);
HKEY key = key_;
key_ = NULL;
return key;
@@ -662,8 +662,8 @@ void RegistryKeyIterator::Initialize(HKEY root_key,
key_ = NULL;
} else {
DWORD count = 0;
- LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL);
+ result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS) {
::RegCloseKey(key_);
diff --git a/chromium/base/win/registry_unittest.cc b/chromium/base/win/registry_unittest.cc
index 6548474c4fa..22576634f9a 100644
--- a/chromium/base/win/registry_unittest.cc
+++ b/chromium/base/win/registry_unittest.cc
@@ -31,7 +31,7 @@ class RegistryTest : public testing::Test {
#endif // _WIN64
RegistryTest() {}
- virtual void SetUp() override {
+ void SetUp() override {
// Create a temporary key.
RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
key.DeleteKey(kRootKey);
@@ -42,7 +42,7 @@ class RegistryTest : public testing::Test {
foo_software_key_ += L"\\Foo";
}
- virtual void TearDown() override {
+ void TearDown() override {
// Clean up the temporary key.
RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
diff --git a/chromium/base/win/resource_util.h b/chromium/base/win/resource_util.h
index f3444ae79f5..8a8baa0f532 100644
--- a/chromium/base/win/resource_util.h
+++ b/chromium/base/win/resource_util.h
@@ -5,8 +5,8 @@
// This file contains utility functions for accessing resources in external
// files (DLLs) or embedded in the executable itself.
-#ifndef BASE_WIN_RESOURCE_UTIL_H__
-#define BASE_WIN_RESOURCE_UTIL_H__
+#ifndef BASE_WIN_RESOURCE_UTIL_H_
+#define BASE_WIN_RESOURCE_UTIL_H_
#include <windows.h>
@@ -36,4 +36,4 @@ bool BASE_EXPORT GetDataResourceFromModule(HMODULE module,
} // namespace win
} // namespace base
-#endif // BASE_WIN_RESOURCE_UTIL_H__
+#endif // BASE_WIN_RESOURCE_UTIL_H_
diff --git a/chromium/base/win/scoped_bstr.h b/chromium/base/win/scoped_bstr.h
index d703f62dac8..7c9f5df0868 100644
--- a/chromium/base/win/scoped_bstr.h
+++ b/chromium/base/win/scoped_bstr.h
@@ -94,4 +94,4 @@ class BASE_EXPORT ScopedBstr {
} // namespace win
} // namespace base
-#endif // BASE_SCOPED_BSTR_H_
+#endif // BASE_WIN_SCOPED_BSTR_H_
diff --git a/chromium/base/win/scoped_comptr.h b/chromium/base/win/scoped_comptr.h
index 98cea0ff4c8..373c0c3ba50 100644
--- a/chromium/base/win/scoped_comptr.h
+++ b/chromium/base/win/scoped_comptr.h
@@ -133,8 +133,7 @@ class ScopedComPtr : public scoped_refptr<Interface> {
ScopedComPtr<IUnknown> other_identity;
other->QueryInterface(other_identity.Receive());
- return static_cast<IUnknown*>(my_identity) ==
- static_cast<IUnknown*>(other_identity);
+ return my_identity == other_identity;
}
// Provides direct access to the interface.
diff --git a/chromium/base/win/scoped_comptr_unittest.cc b/chromium/base/win/scoped_comptr_unittest.cc
index d8d12be87df..d38752dfb9f 100644
--- a/chromium/base/win/scoped_comptr_unittest.cc
+++ b/chromium/base/win/scoped_comptr_unittest.cc
@@ -31,8 +31,8 @@ const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
} // namespace
TEST(ScopedComPtrTest, ScopedComPtr) {
- EXPECT_TRUE(memcmp(&ScopedComPtr<IUnknown>::iid(), &IID_IUnknown,
- sizeof(IID)) == 0);
+ EXPECT_EQ(memcmp(&ScopedComPtr<IUnknown>::iid(), &IID_IUnknown, sizeof(IID)),
+ 0);
base::win::ScopedCOMInitializer com_initializer;
EXPECT_TRUE(com_initializer.succeeded());
@@ -41,8 +41,8 @@ TEST(ScopedComPtrTest, ScopedComPtr) {
EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
ScopedComPtr<IUnknown> unk2;
unk2.Attach(unk.Detach());
- EXPECT_TRUE(unk == NULL);
- EXPECT_TRUE(unk2 != NULL);
+ EXPECT_TRUE(unk.get() == NULL);
+ EXPECT_TRUE(unk2.get() != NULL);
ScopedComPtr<IMalloc> mem_alloc;
EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
@@ -55,26 +55,26 @@ TEST(ScopedComPtrTest, ScopedComPtr) {
// test ScopedComPtr& constructor
ScopedComPtr<IMalloc> copy1(mem_alloc);
- EXPECT_TRUE(copy1.IsSameObject(mem_alloc));
- EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid but different
- EXPECT_FALSE(copy1.IsSameObject(unk)); // unk is NULL
+ EXPECT_TRUE(copy1.IsSameObject(mem_alloc.get()));
+ EXPECT_FALSE(copy1.IsSameObject(unk2.get())); // unk2 is valid but different
+ EXPECT_FALSE(copy1.IsSameObject(unk.get())); // unk is NULL
IMalloc* naked_copy = copy1.Detach();
copy1 = naked_copy; // Test the =(T*) operator.
naked_copy->Release();
copy1.Release();
- EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid, copy1 is not
+ EXPECT_FALSE(copy1.IsSameObject(unk2.get())); // unk2 is valid, copy1 is not
// test Interface* constructor
- ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc));
- EXPECT_TRUE(copy2.IsSameObject(mem_alloc));
+ ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc.get()));
+ EXPECT_TRUE(copy2.IsSameObject(mem_alloc.get()));
- EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc)));
- EXPECT_TRUE(unk != NULL);
+ EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc.get())));
+ EXPECT_TRUE(unk.get() != NULL);
unk.Release();
- EXPECT_TRUE(unk == NULL);
- EXPECT_TRUE(unk.IsSameObject(copy1)); // both are NULL
+ EXPECT_TRUE(unk.get() == NULL);
+ EXPECT_TRUE(unk.IsSameObject(copy1.get())); // both are NULL
}
TEST(ScopedComPtrTest, ScopedComPtrVector) {
@@ -98,7 +98,7 @@ TEST(ScopedComPtrTest, ScopedComPtrVector) {
bleh.push_back(p2);
EXPECT_EQ(p->adds, 4);
EXPECT_EQ(p->releases, 1);
- EXPECT_EQ(bleh[0], p.get());
+ EXPECT_EQ(bleh[0].get(), p.get());
bleh.pop_back();
EXPECT_EQ(p->adds, 4);
EXPECT_EQ(p->releases, 2);
diff --git a/chromium/base/win/scoped_handle.cc b/chromium/base/win/scoped_handle.cc
index 28030216920..ce944e43b9f 100644
--- a/chromium/base/win/scoped_handle.cc
+++ b/chromium/base/win/scoped_handle.cc
@@ -12,6 +12,11 @@
#include "base/logging.h"
#include "base/synchronization/lock_impl.h"
+extern "C" {
+__declspec(dllexport) void* GetHandleVerifier();
+typedef void* (*GetHandleVerifierFn)();
+}
+
namespace {
struct HandleHash {
@@ -30,20 +35,9 @@ struct Info {
};
typedef std::unordered_map<HANDLE, Info, HandleHash> HandleMap;
-// g_lock protects g_handle_map and g_closing.
+// g_lock protects the handle map and setting g_active_verifier.
typedef base::internal::LockImpl NativeLock;
base::LazyInstance<NativeLock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<HandleMap>::Leaky g_handle_map = LAZY_INSTANCE_INITIALIZER;
-bool g_closing = false;
-
-// g_verifier_enabled is not protected by g_lock because that would require
-// using the lock (hence, synchornizing multiple threads) even when the
-// verifier is not in use. Note that this variable is initialized to track all
-// handles, and it should only move to the disabled state, and never back to
-// enabled, because that would crash when seeing handles created while the
-// verifier was disabled. This also implies that it is OK if the value change is
-// not propagated immediately to all CPUs (as would happen with a lock).
-bool g_verifier_enabled = true;
bool CloseHandleWrapper(HANDLE handle) {
if (!::CloseHandle(handle))
@@ -68,82 +62,196 @@ class AutoNativeLock {
DISALLOW_COPY_AND_ASSIGN(AutoNativeLock);
};
-} // namespace
+// Implements the actual object that is verifying handles for this process.
+// The active instance is shared across the module boundary but there is no
+// way to delete this object from the wrong side of it (or any side, actually).
+class ActiveVerifier {
+ public:
+ explicit ActiveVerifier(bool enabled)
+ : enabled_(enabled), closing_(false), lock_(g_lock.Pointer()) {
+ }
-namespace base {
-namespace win {
+ // Retrieves the current verifier.
+ static ActiveVerifier* Get();
-// Static.
-bool HandleTraits::CloseHandle(HANDLE handle) {
- if (!g_verifier_enabled)
- return CloseHandleWrapper(handle);
+ // The methods required by HandleTraits. They are virtual because we need to
+ // forward the call execution to another module, instead of letting the
+ // compiler call the version that is linked in the current module.
+ virtual bool CloseHandle(HANDLE handle);
+ virtual void StartTracking(HANDLE handle, const void* owner,
+ const void* pc1, const void* pc2);
+ virtual void StopTracking(HANDLE handle, const void* owner,
+ const void* pc1, const void* pc2);
+ virtual void Disable();
+ virtual void OnHandleBeingClosed(HANDLE handle);
+
+ private:
+ ~ActiveVerifier(); // Not implemented.
+
+ static void InstallVerifier();
+
+ bool enabled_;
+ bool closing_;
+ NativeLock* lock_;
+ HandleMap map_;
+ DISALLOW_COPY_AND_ASSIGN(ActiveVerifier);
+};
+ActiveVerifier* g_active_verifier = NULL;
+
+// static
+ActiveVerifier* ActiveVerifier::Get() {
+ if (!g_active_verifier)
+ ActiveVerifier::InstallVerifier();
+
+ return g_active_verifier;
+}
+// static
+void ActiveVerifier::InstallVerifier() {
+#if defined(COMPONENT_BUILD)
AutoNativeLock lock(g_lock.Get());
- g_closing = true;
+ g_active_verifier = new ActiveVerifier(true);
+#else
+ // If you are reading this, wondering why your process seems deadlocked, take
+ // a look at your DllMain code and remove things that should not be done
+ // there, like doing whatever gave you that nice windows handle you are trying
+ // to store in a ScopedHandle.
+ HMODULE main_module = ::GetModuleHandle(NULL);
+ GetHandleVerifierFn get_handle_verifier =
+ reinterpret_cast<GetHandleVerifierFn>(::GetProcAddress(
+ main_module, "GetHandleVerifier"));
+
+ if (!get_handle_verifier) {
+ g_active_verifier = new ActiveVerifier(false);
+ return;
+ }
+
+ ActiveVerifier* verifier =
+ reinterpret_cast<ActiveVerifier*>(get_handle_verifier());
+
+ // This lock only protects against races in this module, which is fine.
+ AutoNativeLock lock(g_lock.Get());
+ g_active_verifier = verifier ? verifier : new ActiveVerifier(true);
+#endif
+}
+
+bool ActiveVerifier::CloseHandle(HANDLE handle) {
+ if (!enabled_)
+ return CloseHandleWrapper(handle);
+
+ AutoNativeLock lock(*lock_);
+ closing_ = true;
CloseHandleWrapper(handle);
- g_closing = false;
+ closing_ = false;
return true;
}
-// Static.
-void VerifierTraits::StartTracking(HANDLE handle, const void* owner,
+void ActiveVerifier::StartTracking(HANDLE handle, const void* owner,
const void* pc1, const void* pc2) {
- if (!g_verifier_enabled)
+ if (!enabled_)
return;
+ // Idea here is to make our handles non-closable until we close it ourselves.
+ // Handles provided could be totally fabricated especially through our
+ // unittest, we are ignoring that for now by not checking return value.
+ ::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE,
+ HANDLE_FLAG_PROTECT_FROM_CLOSE);
+
// Grab the thread id before the lock.
DWORD thread_id = GetCurrentThreadId();
- AutoNativeLock lock(g_lock.Get());
+ AutoNativeLock lock(*lock_);
Info handle_info = { owner, pc1, pc2, thread_id };
std::pair<HANDLE, Info> item(handle, handle_info);
- std::pair<HandleMap::iterator, bool> result = g_handle_map.Get().insert(item);
+ std::pair<HandleMap::iterator, bool> result = map_.insert(item);
if (!result.second) {
Info other = result.first->second;
- debug::Alias(&other);
+ base::debug::Alias(&other);
CHECK(false);
}
}
-// Static.
-void VerifierTraits::StopTracking(HANDLE handle, const void* owner,
+void ActiveVerifier::StopTracking(HANDLE handle, const void* owner,
const void* pc1, const void* pc2) {
- if (!g_verifier_enabled)
+ if (!enabled_)
return;
- AutoNativeLock lock(g_lock.Get());
- HandleMap::iterator i = g_handle_map.Get().find(handle);
- if (i == g_handle_map.Get().end())
+ // We expect handle to be protected till this point.
+ DWORD flags = 0;
+ if (::GetHandleInformation(handle, &flags)) {
+ CHECK_NE(0U, (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE));
+
+ // Unprotect handle so that it could be closed.
+ ::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
+ }
+
+ AutoNativeLock lock(*lock_);
+ HandleMap::iterator i = map_.find(handle);
+ if (i == map_.end())
CHECK(false);
Info other = i->second;
if (other.owner != owner) {
- debug::Alias(&other);
+ base::debug::Alias(&other);
CHECK(false);
}
- g_handle_map.Get().erase(i);
+ map_.erase(i);
}
-void DisableHandleVerifier() {
- g_verifier_enabled = false;
+void ActiveVerifier::Disable() {
+ enabled_ = false;
}
-void OnHandleBeingClosed(HANDLE handle) {
- AutoNativeLock lock(g_lock.Get());
- if (g_closing)
+void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) {
+ AutoNativeLock lock(*lock_);
+ if (closing_)
return;
- HandleMap::iterator i = g_handle_map.Get().find(handle);
- if (i == g_handle_map.Get().end())
+ HandleMap::iterator i = map_.find(handle);
+ if (i == map_.end())
return;
Info other = i->second;
- debug::Alias(&other);
+ base::debug::Alias(&other);
CHECK(false);
}
+} // namespace
+
+void* GetHandleVerifier() {
+ return g_active_verifier;
+}
+
+namespace base {
+namespace win {
+
+// Static.
+bool HandleTraits::CloseHandle(HANDLE handle) {
+ return ActiveVerifier::Get()->CloseHandle(handle);
+}
+
+// Static.
+void VerifierTraits::StartTracking(HANDLE handle, const void* owner,
+ const void* pc1, const void* pc2) {
+ return ActiveVerifier::Get()->StartTracking(handle, owner, pc1, pc2);
+}
+
+// Static.
+void VerifierTraits::StopTracking(HANDLE handle, const void* owner,
+ const void* pc1, const void* pc2) {
+ return ActiveVerifier::Get()->StopTracking(handle, owner, pc1, pc2);
+}
+
+void DisableHandleVerifier() {
+ return ActiveVerifier::Get()->Disable();
+}
+
+void OnHandleBeingClosed(HANDLE handle) {
+ return ActiveVerifier::Get()->OnHandleBeingClosed(handle);
+}
+
} // namespace win
} // namespace base
diff --git a/chromium/base/win/scoped_handle.h b/chromium/base/win/scoped_handle.h
index db24f4bb362..97fd7a5c79a 100644
--- a/chromium/base/win/scoped_handle.h
+++ b/chromium/base/win/scoped_handle.h
@@ -174,4 +174,4 @@ void BASE_EXPORT OnHandleBeingClosed(HANDLE handle);
} // namespace win
} // namespace base
-#endif // BASE_SCOPED_HANDLE_WIN_H_
+#endif // BASE_WIN_SCOPED_HANDLE_H_
diff --git a/chromium/base/win/scoped_hdc.h b/chromium/base/win/scoped_hdc.h
index 9aead967929..2452067dfb3 100644
--- a/chromium/base/win/scoped_hdc.h
+++ b/chromium/base/win/scoped_hdc.h
@@ -68,7 +68,7 @@ class CreateDCTraits {
DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits);
};
-typedef GenericScopedHandle<CreateDCTraits, VerifierTraits> ScopedCreateDC;
+typedef GenericScopedHandle<CreateDCTraits, DummyVerifierTraits> ScopedCreateDC;
} // namespace win
} // namespace base
diff --git a/chromium/base/win/scoped_process_information.cc b/chromium/base/win/scoped_process_information.cc
index bb2463774a8..634a538eece 100644
--- a/chromium/base/win/scoped_process_information.cc
+++ b/chromium/base/win/scoped_process_information.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
namespace base {
namespace win {
@@ -20,11 +21,49 @@ bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) {
return true;
HANDLE temp = NULL;
- if (!::DuplicateHandle(::GetCurrentProcess(), source,
- ::GetCurrentProcess(), &temp, 0, FALSE,
- DUPLICATE_SAME_ACCESS)) {
- DPLOG(ERROR) << "Failed to duplicate a handle.";
- return false;
+
+ // TODO(shrikant): Remove following code as soon as we gather some
+ // information regarding AppContainer related DuplicateHandle failures that
+ // only seem to happen on certain machine and only random launches (normally
+ // renderer launches seem to succeed even on those machines.)
+ if (base::win::GetVersion() == base::win::VERSION_WIN8 ||
+ base::win::GetVersion() == base::win::VERSION_WIN8_1) {
+ typedef LONG (WINAPI *NtDuplicateObject)(
+ IN HANDLE SourceProcess,
+ IN HANDLE SourceHandle,
+ IN HANDLE TargetProcess,
+ OUT PHANDLE TargetHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN ULONG Attributes,
+ IN ULONG Options);
+
+ typedef ULONG (WINAPI *RtlNtStatusToDosError)(IN LONG Status);
+
+ NtDuplicateObject nt_duplicate_object =
+ reinterpret_cast<NtDuplicateObject>(::GetProcAddress(
+ GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"));
+ if (nt_duplicate_object != NULL) {
+ LONG status = nt_duplicate_object(::GetCurrentProcess(), source,
+ ::GetCurrentProcess(), &temp,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (status < 0) {
+ DPLOG(ERROR) << "Failed to duplicate a handle.";
+ RtlNtStatusToDosError ntstatus_to_doserror =
+ reinterpret_cast<RtlNtStatusToDosError>(::GetProcAddress(
+ GetModuleHandle(L"ntdll.dll"), "RtlNtStatusToDosError"));
+ if (ntstatus_to_doserror != NULL) {
+ ::SetLastError(ntstatus_to_doserror(status));
+ }
+ return false;
+ }
+ }
+ } else {
+ if (!::DuplicateHandle(::GetCurrentProcess(), source,
+ ::GetCurrentProcess(), &temp, 0, FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ DPLOG(ERROR) << "Failed to duplicate a handle.";
+ return false;
+ }
}
target->Set(temp);
return true;
diff --git a/chromium/base/win/scoped_process_information_unittest.cc b/chromium/base/win/scoped_process_information_unittest.cc
index ccfa7290a97..614504d414e 100644
--- a/chromium/base/win/scoped_process_information_unittest.cc
+++ b/chromium/base/win/scoped_process_information_unittest.cc
@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "base/process/kill.h"
+#include "base/process/process.h"
#include "base/test/multiprocess_test.h"
#include "base/win/scoped_process_information.h"
#include "testing/multiprocess_func_list.h"
@@ -135,13 +136,13 @@ TEST_F(ScopedProcessInformationTest, Duplicate) {
// Validate that we have separate handles that are good.
int exit_code = 0;
- ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(),
- &exit_code));
+ base::Process process(process_info.TakeProcessHandle());
+ ASSERT_TRUE(process.WaitForExit(&exit_code));
ASSERT_EQ(7, exit_code);
exit_code = 0;
- ASSERT_TRUE(base::WaitForExitCode(duplicate.TakeProcessHandle(),
- &exit_code));
+ base::Process dup_process(duplicate.TakeProcessHandle());
+ ASSERT_TRUE(dup_process.WaitForExit(&exit_code));
ASSERT_EQ(7, exit_code);
ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
diff --git a/chromium/base/win/scoped_propvariant.h b/chromium/base/win/scoped_propvariant.h
index 711d51adb40..62cc6a6d152 100644
--- a/chromium/base/win/scoped_propvariant.h
+++ b/chromium/base/win/scoped_propvariant.h
@@ -41,8 +41,7 @@ class ScopedPropVariant {
}
const PROPVARIANT& get() const { return pv_; }
-
- const PROPVARIANT* operator&() const { return &pv_; }
+ const PROPVARIANT* ptr() const { return &pv_; }
private:
PROPVARIANT pv_;
diff --git a/chromium/base/win/scoped_variant.h b/chromium/base/win/scoped_variant.h
index b6e65798fbd..322fcf71e55 100644
--- a/chromium/base/win/scoped_variant.h
+++ b/chromium/base/win/scoped_variant.h
@@ -122,9 +122,7 @@ class BASE_EXPORT ScopedVariant {
// This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to
// work properly but still doesn't allow modifications since we want control
// over that.
- const VARIANT* operator&() const {
- return &var_;
- }
+ const VARIANT* ptr() const { return &var_; }
// Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr)
// we support the assignment operator for the type we wrap.
@@ -161,6 +159,6 @@ class BASE_EXPORT ScopedVariant {
};
} // namespace win
-} // namesoace base
+} // namespace base
#endif // BASE_WIN_SCOPED_VARIANT_H_
diff --git a/chromium/base/win/scoped_variant_unittest.cc b/chromium/base/win/scoped_variant_unittest.cc
index 1f017cf94ab..d530d5bcd91 100644
--- a/chromium/base/win/scoped_variant_unittest.cc
+++ b/chromium/base/win/scoped_variant_unittest.cc
@@ -27,34 +27,34 @@ class FakeComObject : public IDispatch {
FakeComObject() : ref_(0) {
}
- STDMETHOD_(DWORD, AddRef)() {
+ STDMETHOD_(DWORD, AddRef)() override {
ref_++;
return ref_;
}
- STDMETHOD_(DWORD, Release)() {
+ STDMETHOD_(DWORD, Release)() override {
ref_--;
return ref_;
}
- STDMETHOD(QueryInterface)(REFIID, void**) {
- return E_NOTIMPL;
- }
+ STDMETHOD(QueryInterface)(REFIID, void**) override { return E_NOTIMPL; }
- STDMETHOD(GetTypeInfoCount)(UINT*) {
- return E_NOTIMPL;
- }
+ STDMETHOD(GetTypeInfoCount)(UINT*) override { return E_NOTIMPL; }
- STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) {
- return E_NOTIMPL;
- }
+ STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
- STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) {
+ STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) override {
return E_NOTIMPL;
}
- STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*,
- EXCEPINFO*, UINT*) {
+ STDMETHOD(Invoke)(DISPID,
+ REFIID,
+ LCID,
+ WORD,
+ DISPPARAMS*,
+ VARIANT*,
+ EXCEPINFO*,
+ UINT*) override {
return E_NOTIMPL;
}
@@ -72,41 +72,41 @@ class FakeComObject : public IDispatch {
TEST(ScopedVariantTest, ScopedVariant) {
ScopedVariant var;
EXPECT_TRUE(var.type() == VT_EMPTY);
- // V_BSTR(&var) = NULL; <- NOTE: Assignment like that is not supported
+ // V_BSTR(var.ptr()) = NULL; <- NOTE: Assignment like that is not supported.
ScopedVariant var_bstr(L"VT_BSTR");
- EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
- EXPECT_TRUE(V_BSTR(&var_bstr) != NULL); // can't use EXPECT_NE for BSTR
+ EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+ EXPECT_TRUE(V_BSTR(var_bstr.ptr()) != NULL); // can't use EXPECT_NE for BSTR
var_bstr.Reset();
- EXPECT_NE(VT_BSTR, V_VT(&var_bstr));
+ EXPECT_NE(VT_BSTR, V_VT(var_bstr.ptr()));
var_bstr.Set(kTestString2);
- EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+ EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
VARIANT tmp = var_bstr.Release();
- EXPECT_EQ(VT_EMPTY, V_VT(&var_bstr));
+ EXPECT_EQ(VT_EMPTY, V_VT(var_bstr.ptr()));
EXPECT_EQ(VT_BSTR, V_VT(&tmp));
EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2));
var.Reset(tmp);
- EXPECT_EQ(VT_BSTR, V_VT(&var));
- EXPECT_EQ(0, lstrcmpW(V_BSTR(&var), kTestString2));
+ EXPECT_EQ(VT_BSTR, V_VT(var.ptr()));
+ EXPECT_EQ(0, lstrcmpW(V_BSTR(var.ptr()), kTestString2));
var_bstr.Swap(var);
- EXPECT_EQ(VT_EMPTY, V_VT(&var));
- EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
- EXPECT_EQ(0, lstrcmpW(V_BSTR(&var_bstr), kTestString2));
+ EXPECT_EQ(VT_EMPTY, V_VT(var.ptr()));
+ EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+ EXPECT_EQ(0, lstrcmpW(V_BSTR(var_bstr.ptr()), kTestString2));
var_bstr.Reset();
// Test the Compare and Copy routines.
GiveMeAVariant(var_bstr.Receive());
- ScopedVariant var_bstr2(V_BSTR(&var_bstr));
+ ScopedVariant var_bstr2(V_BSTR(var_bstr.ptr()));
EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
var_bstr2.Reset();
EXPECT_NE(0, var_bstr.Compare(var_bstr2));
var_bstr2.Reset(var_bstr.Copy());
EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
var_bstr2.Reset();
- var_bstr2.Set(V_BSTR(&var_bstr));
+ var_bstr2.Set(V_BSTR(var_bstr.ptr()));
EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
var_bstr2.Reset();
var_bstr.Reset();
@@ -119,7 +119,7 @@ TEST(ScopedVariantTest, ScopedVariant) {
var.Reset();
var.SetDate(date);
EXPECT_EQ(VT_DATE, var.type());
- EXPECT_EQ(date, V_DATE(&var));
+ EXPECT_EQ(date, V_DATE(var.ptr()));
// Simple setter tests. These do not require resetting the variant
// after each test since the variant type is not "leakable" (i.e. doesn't
@@ -128,75 +128,75 @@ TEST(ScopedVariantTest, ScopedVariant) {
// We need static cast here since char defaults to int (!?).
var.Set(static_cast<int8>('v'));
EXPECT_EQ(VT_I1, var.type());
- EXPECT_EQ('v', V_I1(&var));
+ EXPECT_EQ('v', V_I1(var.ptr()));
var.Set(static_cast<short>(123));
EXPECT_EQ(VT_I2, var.type());
- EXPECT_EQ(123, V_I2(&var));
+ EXPECT_EQ(123, V_I2(var.ptr()));
var.Set(static_cast<int32>(123));
EXPECT_EQ(VT_I4, var.type());
- EXPECT_EQ(123, V_I4(&var));
+ EXPECT_EQ(123, V_I4(var.ptr()));
var.Set(static_cast<int64>(123));
EXPECT_EQ(VT_I8, var.type());
- EXPECT_EQ(123, V_I8(&var));
+ EXPECT_EQ(123, V_I8(var.ptr()));
var.Set(static_cast<uint8>(123));
EXPECT_EQ(VT_UI1, var.type());
- EXPECT_EQ(123, V_UI1(&var));
+ EXPECT_EQ(123, V_UI1(var.ptr()));
var.Set(static_cast<unsigned short>(123));
EXPECT_EQ(VT_UI2, var.type());
- EXPECT_EQ(123, V_UI2(&var));
+ EXPECT_EQ(123, V_UI2(var.ptr()));
var.Set(static_cast<uint32>(123));
EXPECT_EQ(VT_UI4, var.type());
- EXPECT_EQ(123, V_UI4(&var));
+ EXPECT_EQ(123, V_UI4(var.ptr()));
var.Set(static_cast<uint64>(123));
EXPECT_EQ(VT_UI8, var.type());
- EXPECT_EQ(123, V_UI8(&var));
+ EXPECT_EQ(123, V_UI8(var.ptr()));
var.Set(123.123f);
EXPECT_EQ(VT_R4, var.type());
- EXPECT_EQ(123.123f, V_R4(&var));
+ EXPECT_EQ(123.123f, V_R4(var.ptr()));
var.Set(static_cast<double>(123.123));
EXPECT_EQ(VT_R8, var.type());
- EXPECT_EQ(123.123, V_R8(&var));
+ EXPECT_EQ(123.123, V_R8(var.ptr()));
var.Set(true);
EXPECT_EQ(VT_BOOL, var.type());
- EXPECT_EQ(VARIANT_TRUE, V_BOOL(&var));
+ EXPECT_EQ(VARIANT_TRUE, V_BOOL(var.ptr()));
var.Set(false);
EXPECT_EQ(VT_BOOL, var.type());
- EXPECT_EQ(VARIANT_FALSE, V_BOOL(&var));
+ EXPECT_EQ(VARIANT_FALSE, V_BOOL(var.ptr()));
// Com interface tests
var.Set(static_cast<IDispatch*>(NULL));
EXPECT_EQ(VT_DISPATCH, var.type());
- EXPECT_EQ(NULL, V_DISPATCH(&var));
+ EXPECT_EQ(NULL, V_DISPATCH(var.ptr()));
var.Reset();
var.Set(static_cast<IUnknown*>(NULL));
EXPECT_EQ(VT_UNKNOWN, var.type());
- EXPECT_EQ(NULL, V_UNKNOWN(&var));
+ EXPECT_EQ(NULL, V_UNKNOWN(var.ptr()));
var.Reset();
FakeComObject faker;
EXPECT_EQ(0, faker.ref_count());
var.Set(static_cast<IDispatch*>(&faker));
EXPECT_EQ(VT_DISPATCH, var.type());
- EXPECT_EQ(&faker, V_DISPATCH(&var));
+ EXPECT_EQ(&faker, V_DISPATCH(var.ptr()));
EXPECT_EQ(1, faker.ref_count());
var.Reset();
EXPECT_EQ(0, faker.ref_count());
var.Set(static_cast<IUnknown*>(&faker));
EXPECT_EQ(VT_UNKNOWN, var.type());
- EXPECT_EQ(&faker, V_UNKNOWN(&var));
+ EXPECT_EQ(&faker, V_UNKNOWN(var.ptr()));
EXPECT_EQ(1, faker.ref_count());
var.Reset();
EXPECT_EQ(0, faker.ref_count());
@@ -204,7 +204,7 @@ TEST(ScopedVariantTest, ScopedVariant) {
{
ScopedVariant disp_var(&faker);
EXPECT_EQ(VT_DISPATCH, disp_var.type());
- EXPECT_EQ(&faker, V_DISPATCH(&disp_var));
+ EXPECT_EQ(&faker, V_DISPATCH(disp_var.ptr()));
EXPECT_EQ(1, faker.ref_count());
}
EXPECT_EQ(0, faker.ref_count());
@@ -223,7 +223,7 @@ TEST(ScopedVariantTest, ScopedVariant) {
{
ScopedVariant unk_var(static_cast<IUnknown*>(&faker));
EXPECT_EQ(VT_UNKNOWN, unk_var.type());
- EXPECT_EQ(&faker, V_UNKNOWN(&unk_var));
+ EXPECT_EQ(&faker, V_UNKNOWN(unk_var.ptr()));
EXPECT_EQ(1, faker.ref_count());
}
EXPECT_EQ(0, faker.ref_count());
@@ -240,7 +240,7 @@ TEST(ScopedVariantTest, ScopedVariant) {
{
ScopedVariant number(123);
EXPECT_EQ(VT_I4, number.type());
- EXPECT_EQ(123, V_I4(&number));
+ EXPECT_EQ(123, V_I4(number.ptr()));
}
// SAFEARRAY tests
@@ -253,7 +253,7 @@ TEST(ScopedVariantTest, ScopedVariant) {
var.Set(sa);
EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type()));
EXPECT_EQ(VT_ARRAY | VT_UI1, var.type());
- EXPECT_EQ(sa, V_ARRAY(&var));
+ EXPECT_EQ(sa, V_ARRAY(var.ptr()));
// The array is destroyed in the destructor of var.
}
diff --git a/chromium/base/win/shortcut.cc b/chromium/base/win/shortcut.cc
index eef299b9440..f8b2182b286 100644
--- a/chromium/base/win/shortcut.cc
+++ b/chromium/base/win/shortcut.cc
@@ -33,7 +33,7 @@ void InitializeShortcutInterfaces(
i_persist_file->Release();
if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER)) ||
- FAILED(i_persist_file->QueryFrom(*i_shell_link)) ||
+ FAILED(i_persist_file->QueryFrom(i_shell_link->get())) ||
(shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) {
i_shell_link->Release();
i_persist_file->Release();
@@ -42,6 +42,13 @@ void InitializeShortcutInterfaces(
} // namespace
+ShortcutProperties::ShortcutProperties()
+ : icon_index(-1), dual_mode(false), options(0U) {
+}
+
+ShortcutProperties::~ShortcutProperties() {
+}
+
bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
const ShortcutProperties& properties,
ShortcutOperation operation) {
@@ -129,15 +136,17 @@ bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
if ((has_app_id || has_dual_mode) &&
GetVersion() >= VERSION_WIN7) {
ScopedComPtr<IPropertyStore> property_store;
- if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get())
+ if (FAILED(property_store.QueryFrom(i_shell_link.get())) ||
+ !property_store.get())
return false;
if (has_app_id &&
- !SetAppIdForPropertyStore(property_store, properties.app_id.c_str())) {
+ !SetAppIdForPropertyStore(property_store.get(),
+ properties.app_id.c_str())) {
return false;
}
if (has_dual_mode &&
- !SetBooleanValueForPropertyStore(property_store,
+ !SetBooleanValueForPropertyStore(property_store.get(),
PKEY_AppUserModel_IsDualMode,
properties.dual_mode)) {
return false;
@@ -192,7 +201,7 @@ bool ResolveShortcutProperties(const FilePath& shortcut_path,
ScopedComPtr<IPersistFile> persist;
// Query IShellLink for the IPersistFile interface.
- if (FAILED(persist.QueryFrom(i_shell_link)))
+ if (FAILED(persist.QueryFrom(i_shell_link.get())))
return false;
// Load the shell link.
@@ -239,7 +248,7 @@ bool ResolveShortcutProperties(const FilePath& shortcut_path,
if ((options & ShortcutProperties::PROPERTIES_WIN7) &&
GetVersion() >= VERSION_WIN7) {
ScopedComPtr<IPropertyStore> property_store;
- if (FAILED(property_store.QueryFrom(i_shell_link)))
+ if (FAILED(property_store.QueryFrom(i_shell_link.get())))
return false;
if (options & ShortcutProperties::PROPERTIES_APP_ID) {
@@ -312,8 +321,8 @@ bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
if (GetVersion() < VERSION_WIN7)
return false;
- int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut,
- NULL, NULL, 0));
+ intptr_t result = reinterpret_cast<intptr_t>(
+ ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
return result > 32;
}
@@ -324,8 +333,8 @@ bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
if (GetVersion() < VERSION_WIN7)
return false;
- int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
- shortcut, NULL, NULL, 0));
+ intptr_t result = reinterpret_cast<intptr_t>(
+ ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
return result > 32;
}
diff --git a/chromium/base/win/shortcut.h b/chromium/base/win/shortcut.h
index 2feb4c3aa9e..6f7d10c8ee7 100644
--- a/chromium/base/win/shortcut.h
+++ b/chromium/base/win/shortcut.h
@@ -7,6 +7,7 @@
#include <windows.h>
+#include "base/base_export.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/string16.h"
@@ -29,7 +30,7 @@ enum ShortcutOperation {
// creation/update, others will be ignored.
// Callers are encouraged to use the setters provided which take care of
// setting |options| as desired.
-struct ShortcutProperties {
+struct BASE_EXPORT ShortcutProperties {
enum IndividualProperties {
PROPERTIES_TARGET = 1U << 0,
PROPERTIES_WORKING_DIR = 1U << 1,
@@ -48,7 +49,8 @@ struct ShortcutProperties {
PROPERTIES_ALL = PROPERTIES_BASIC | PROPERTIES_WIN7
};
- ShortcutProperties() : icon_index(-1), dual_mode(false), options(0U) {}
+ ShortcutProperties();
+ ~ShortcutProperties();
void set_target(const FilePath& target_in) {
target = target_in;
diff --git a/chromium/base/win/shortcut_unittest.cc b/chromium/base/win/shortcut_unittest.cc
index 4bb227a4701..794be2364f4 100644
--- a/chromium/base/win/shortcut_unittest.cc
+++ b/chromium/base/win/shortcut_unittest.cc
@@ -25,7 +25,7 @@ static const char kFileContents2[] = "This is another target.";
class ShortcutTest : public testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
diff --git a/chromium/base/win/startup_information.h b/chromium/base/win/startup_information.h
index 7cef81f2c8f..3f18ee58efb 100644
--- a/chromium/base/win/startup_information.h
+++ b/chromium/base/win/startup_information.h
@@ -24,6 +24,8 @@ class BASE_EXPORT StartupInformation {
bool InitializeProcThreadAttributeList(DWORD attribute_count);
// Sets one entry in the initialized attribute list.
+ // |value| needs to live at least as long as the StartupInformation object
+ // this is called on.
bool UpdateProcThreadAttribute(DWORD_PTR attribute,
void* value,
size_t size);
@@ -45,5 +47,4 @@ class BASE_EXPORT StartupInformation {
} // namespace win
} // namespace base
-#endif // BASE_WIN_SCOPED_STARTUP_INFO_EX_H_
-
+#endif // BASE_WIN_STARTUP_INFORMATION_H_
diff --git a/chromium/base/win/win_util.cc b/chromium/base/win/win_util.cc
index f46242d3d25..c5b06c48f8a 100644
--- a/chromium/base/win/win_util.cc
+++ b/chromium/base/win/win_util.cc
@@ -57,7 +57,7 @@ const wchar_t kWindows8OSKRegPath[] =
// Returns true if a physical keyboard is detected on Windows 8 and up.
// Uses the Setup APIs to enumerate the attached keyboards and returns true
-// if the keyboard count is more than 1. While this will work in most cases
+// if the keyboard count is 1 or more.. While this will work in most cases
// it won't work if there are devices which expose keyboard interfaces which
// are attached to the machine.
bool IsKeyboardPresentOnSlate() {
@@ -70,6 +70,53 @@ bool IsKeyboardPresentOnSlate() {
return true;
}
+ // If the device is docked, the user is treating the device as a PC.
+ if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
+ return true;
+
+ // To determine whether a keyboard is present on the device, we do the
+ // following:-
+ // 1. Check whether the device supports auto rotation. If it does then
+ // it possibly supports flipping from laptop to slate mode. If it
+ // does not support auto rotation, then we assume it is a desktop
+ // or a normal laptop and assume that there is a keyboard.
+
+ // 2. If the device supports auto rotation, then we get its platform role
+ // and check the system metric SM_CONVERTIBLESLATEMODE to see if it is
+ // being used in slate mode. If yes then we return false here to ensure
+ // that the OSK is displayed.
+
+ // 3. If step 1 and 2 fail then we check attached keyboards and return true
+ // if we find ACPI\* or HID\VID* keyboards.
+
+ typedef BOOL (WINAPI* GetAutoRotationState)(PAR_STATE state);
+
+ GetAutoRotationState get_rotation_state =
+ reinterpret_cast<GetAutoRotationState>(::GetProcAddress(
+ GetModuleHandle(L"user32.dll"), "GetAutoRotationState"));
+
+ if (get_rotation_state) {
+ AR_STATE auto_rotation_state = AR_ENABLED;
+ get_rotation_state(&auto_rotation_state);
+ if ((auto_rotation_state & AR_NOSENSOR) ||
+ (auto_rotation_state & AR_NOT_SUPPORTED)) {
+ // If there is no auto rotation sensor or rotation is not supported in
+ // the current configuration, then we can assume that this is a desktop
+ // or a traditional laptop.
+ return true;
+ }
+ }
+
+ // Check if the device is being used as a laptop or a tablet. This can be
+ // checked by first checking the role of the device and then the
+ // corresponding system metric (SM_CONVERTIBLESLATEMODE). If it is being used
+ // as a tablet then we want the OSK to show up.
+ POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+
+ if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
+ (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0))
+ return false;
+
const GUID KEYBOARD_CLASS_GUID =
{ 0x4D36E96B, 0xE325, 0x11CE,
{ 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
@@ -89,6 +136,7 @@ bool IsKeyboardPresentOnSlate() {
device_info_data.cbSize = sizeof(device_info_data);
if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data))
break;
+
// Get the device ID.
wchar_t device_id[MAX_DEVICE_ID_LEN];
CONFIGRET status = CM_Get_Device_ID(device_info_data.DevInst,
@@ -96,20 +144,18 @@ bool IsKeyboardPresentOnSlate() {
MAX_DEVICE_ID_LEN,
0);
if (status == CR_SUCCESS) {
- // To reduce the scope of the hack we only look for PNP and HID
- // keyboards.
- if (StartsWith(L"ACPI\\PNP", device_id, false) ||
- StartsWith(L"HID\\VID", device_id, false)) {
+ // To reduce the scope of the hack we only look for ACPI and HID\\VID
+ // prefixes in the keyboard device ids.
+ if (StartsWith(device_id, L"ACPI", false) ||
+ StartsWith(device_id, L"HID\\VID", false)) {
keyboard_count++;
}
}
}
- // On a Windows machine, the API's always report 1 keyboard at least
- // regardless of whether the machine has a keyboard attached or not.
- // The heuristic we are using is to check the count and return true
- // if the API's report more than one keyboard. Please note that this
+ // The heuristic we are using is to check the count of keyboards and return
+ // true if the API's report one or more keyboards. Please note that this
// will break for non keyboard devices which expose a keyboard PDO.
- return keyboard_count > 1;
+ return keyboard_count >= 1;
}
} // namespace
@@ -382,7 +428,7 @@ bool DisplayVirtualKeyboard() {
NULL,
NULL,
SW_SHOW);
- return reinterpret_cast<int>(ret) > 32;
+ return reinterpret_cast<intptr_t>(ret) > 32;
}
bool DismissVirtualKeyboard() {
@@ -448,29 +494,3 @@ bool MaybeHasSHA256Support() {
} // namespace win
} // namespace base
-
-#ifdef _MSC_VER
-
-// There are optimizer bugs in x86 VS2012 pre-Update 1.
-#if _MSC_VER == 1700 && defined _M_IX86 && _MSC_FULL_VER < 170051106
-
-#pragma message("Relevant defines:")
-#define __STR2__(x) #x
-#define __STR1__(x) __STR2__(x)
-#define __PPOUT__(x) "#define " #x " " __STR1__(x)
-#if defined(_M_IX86)
- #pragma message(__PPOUT__(_M_IX86))
-#endif
-#if defined(_M_X64)
- #pragma message(__PPOUT__(_M_X64))
-#endif
-#if defined(_MSC_FULL_VER)
- #pragma message(__PPOUT__(_MSC_FULL_VER))
-#endif
-
-#pragma message("Visual Studio 2012 x86 must be updated to at least Update 1")
-#error Must install Update 1 to Visual Studio 2012.
-#endif
-
-#endif // _MSC_VER
-
diff --git a/chromium/base/win/win_util_unittest.cc b/chromium/base/win/win_util_unittest.cc
index 8300c1623b0..24141cd68a0 100644
--- a/chromium/base/win/win_util_unittest.cc
+++ b/chromium/base/win/win_util_unittest.cc
@@ -49,9 +49,9 @@ TEST(BaseWinUtilTest, TestGetUserSidString) {
TEST(BaseWinUtilTest, TestGetNonClientMetrics) {
NONCLIENTMETRICS_XP metrics = {0};
GetNonClientMetrics(&metrics);
- EXPECT_TRUE(metrics.cbSize > 0);
- EXPECT_TRUE(metrics.iScrollWidth > 0);
- EXPECT_TRUE(metrics.iScrollHeight > 0);
+ EXPECT_GT(metrics.cbSize, 0u);
+ EXPECT_GT(metrics.iScrollWidth, 0);
+ EXPECT_GT(metrics.iScrollHeight, 0);
}
} // namespace win
diff --git a/chromium/base/win/windows_version.cc b/chromium/base/win/windows_version.cc
index a99cd1840ac..fc2def39194 100644
--- a/chromium/base/win/windows_version.cc
+++ b/chromium/base/win/windows_version.cc
@@ -64,6 +64,8 @@ OSInfo::OSInfo()
version_ = VERSION_WIN8_1;
break;
}
+ } else if (version_number_.major == 10) {
+ version_ = VERSION_WIN10;
} else if (version_number_.major > 6) {
NOTREACHED();
version_ = VERSION_WIN_LAST;
@@ -84,7 +86,7 @@ OSInfo::OSInfo()
GetProductInfoPtr get_product_info;
DWORD os_type;
- if (version_info.dwMajorVersion == 6) {
+ if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
// Only present on Vista+.
get_product_info = reinterpret_cast<GetProductInfoPtr>(
::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetProductInfo"));
diff --git a/chromium/base/win/windows_version.h b/chromium/base/win/windows_version.h
index e51840b0db8..a52e64e0742 100644
--- a/chromium/base/win/windows_version.h
+++ b/chromium/base/win/windows_version.h
@@ -26,7 +26,8 @@ enum Version {
VERSION_VISTA, // Also includes Windows Server 2008.
VERSION_WIN7, // Also includes Windows Server 2008 R2.
VERSION_WIN8, // Also includes Windows Server 2012.
- VERSION_WIN8_1, // Code named Windows Blue
+ VERSION_WIN8_1, // Also includes Windows Server 2012 R2.
+ VERSION_WIN10, // Also includes Windows 10 Server.
VERSION_WIN_LAST, // Indicates error condition.
};